From f4e883d24f50c775034d8ee10b7a72bd37d3cddd Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Tue, 10 Oct 2017 16:42:24 +0200 Subject: [PATCH 01/42] Divided phch_recv in subclasses --- lib/include/srslte/phy/utils/ringbuffer.h | 4 +- lib/include/srslte/srslte.h | 1 + lib/src/phy/utils/ringbuffer.c | 8 +- srsue/hdr/phy/phch_recv.h | 182 +++-- srsue/src/phy/phch_recv.cc | 895 +++++++++++++++------- 5 files changed, 746 insertions(+), 344 deletions(-) diff --git a/lib/include/srslte/phy/utils/ringbuffer.h b/lib/include/srslte/phy/utils/ringbuffer.h index 9cbe0ddd6..c9276d5a9 100644 --- a/lib/include/srslte/phy/utils/ringbuffer.h +++ b/lib/include/srslte/phy/utils/ringbuffer.h @@ -24,11 +24,11 @@ SRSLTE_API void srslte_ringbuffer_free(srslte_ringbuffer_t *q, int capacity); SRSLTE_API int srslte_ringbuffer_write(srslte_ringbuffer_t *q, - uint8_t *ptr, + void *ptr, int nof_bytes); SRSLTE_API int srslte_ringbuffer_read(srslte_ringbuffer_t *q, - uint8_t *ptr, + void *ptr, int nof_bytes); diff --git a/lib/include/srslte/srslte.h b/lib/include/srslte/srslte.h index f44f5325d..f4806b36d 100644 --- a/lib/include/srslte/srslte.h +++ b/lib/include/srslte/srslte.h @@ -39,6 +39,7 @@ #include "srslte/version.h" #include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/ringbuffer.h" #include "srslte/phy/utils/convolution.h" #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/cexptab.h" diff --git a/lib/src/phy/utils/ringbuffer.c b/lib/src/phy/utils/ringbuffer.c index 86578b3ea..02faaeb9a 100644 --- a/lib/src/phy/utils/ringbuffer.c +++ b/lib/src/phy/utils/ringbuffer.c @@ -34,8 +34,9 @@ void srslte_ringbuffer_free(srslte_ringbuffer_t *q, int capacity) } } -int srslte_ringbuffer_write(srslte_ringbuffer_t *q, uint8_t *ptr, int nof_bytes) -{ +int srslte_ringbuffer_write(srslte_ringbuffer_t *q, void *p, int nof_bytes) +{ + uint8_t *ptr = (uint8_t*) p; int w_bytes = nof_bytes; pthread_mutex_lock(&q->mutex); if (q->count + w_bytes >= q->capacity) { @@ -59,8 +60,9 @@ int srslte_ringbuffer_write(srslte_ringbuffer_t *q, uint8_t *ptr, int nof_bytes) return w_bytes; } -int srslte_ringbuffer_read(srslte_ringbuffer_t *q, uint8_t *ptr, int nof_bytes) +int srslte_ringbuffer_read(srslte_ringbuffer_t *q, void *p, int nof_bytes) { + uint8_t *ptr = (uint8_t*) p; pthread_mutex_lock(&q->mutex); while(q->count < nof_bytes) { pthread_cond_wait(&q->cvar, &q->mutex); diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/phch_recv.h index c51622e53..781603be1 100644 --- a/srsue/hdr/phy/phch_recv.h +++ b/srsue/hdr/phy/phch_recv.h @@ -70,11 +70,8 @@ public: const static int MUTEX_X_WORKER = 4; - // public variables needed by callback function - uint32_t current_sflen; - srslte::radio_multi *radio_h; - int next_offset; - + int radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); + int scell_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); private: @@ -83,49 +80,156 @@ private: void reset(); void radio_error(); bool wait_radio_reset(); - void set_ue_sync_opts(srslte_ue_sync_t *q); + void set_ue_sync_opts(srslte_ue_sync_t *q); void run_thread(); void set_sampling_rate(); bool set_frequency(); - void resync_sfn(bool is_connected = false); - bool stop_sync(); + bool set_cell(); void cell_search_inc(); - - bool init_cell(); - void free_cell(); + void resync_sfn(bool is_connected = false); + bool stop_sync(); void stop_rx(); void start_rx(); bool radio_is_rx; bool radio_is_resetting; + bool running; + + // Class to run cell search + class search { + public: + typedef enum {CELL_NOT_FOUND, CELL_FOUND, ERROR, TIMEOUT} ret_code; + + ~search(); + void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, phch_recv *parent); + void reset(); + float get_last_gain(); + float get_last_cfo(); + void set_N_id_2(int N_id_2); + ret_code run(srslte_cell_t *cell); + + private: + phch_recv *p; + srslte::log *log_h; + cf_t *buffer[SRSLTE_MAX_PORTS]; + srslte_ue_cellsearch_t cs; + srslte_ue_mib_sync_t ue_mib_sync; + int force_N_id_2; + }; + + // Class to synchronize system frame number + class sfn_sync { + public: + typedef enum {IDLE, SFN_FOUND, ERROR, TIMEOUT} ret_code; + + ~sfn_sync(); + void init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t timeout = SYNC_SFN_TIMEOUT); + void reset(); + bool set_cell(srslte_cell_t cell); + ret_code run_subframe(srslte_cell_t *cell, uint32_t *tti_cnt); + + private: + srslte::log *log_h; + srslte_ue_sync_t *ue_sync; + cf_t *buffer[SRSLTE_MAX_PORTS]; + srslte_ue_mib_t ue_mib; + uint32_t cnt; + uint32_t timeout; + const static uint32_t SYNC_SFN_TIMEOUT = 200; + }; + + // Class to perform cell measurements + class measure { + public: + typedef enum {IDLE, MEASURE_OK, ERROR} ret_code; + + ~measure(); + void init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, + uint32_t nof_rx_antennas, uint32_t nof_subframes = RSRP_MEASURE_NOF_FRAMES); + void reset(); + void set_cell(srslte_cell_t cell); + ret_code run_subframe(uint32_t sf_idx); + float rsrp(); + float rsrq(); + float snr(); + private: + srslte::log *log_h; + srslte_ue_dl_t ue_dl; + srslte_ue_sync_t *ue_sync; + cf_t *buffer[SRSLTE_MAX_PORTS]; + uint32_t cnt; + uint32_t nof_subframes; + float mean_rsrp, mean_rsrq, mean_snr; + const static int RSRP_MEASURE_NOF_FRAMES = 5; + }; + + + // Class to receive secondary cell + class scell_recv : public thread { + public: + void init(phch_recv *parent, srslte::log *log_h, uint32_t nof_rx_antennas, uint32_t prio, int cpu_affinity = -1); + void stop(); + int recv(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); + void write(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); + bool is_enabled(); + private: + void run_thread(); + + enum { + IDLE = 0, + SCELL_SELECT, + SCELL_MEASURE, + SCELL_CAMPING + } scell_state; + + srslte::log *log_h; + phch_recv *p; + bool running; + srslte_ringbuffer_t ring_buffer[SRSLTE_MAX_PORTS]; + cf_t *sf_buffer[SRSLTE_MAX_PORTS]; + srslte_ue_sync_t ue_sync; + srslte_cell_t cell; + + measure measure_p; + sfn_sync sfn_p; + uint32_t tti; + }; + + + + + // Objects for internal use + scell_recv scell; + measure measure_p; + search search_p; + sfn_sync sfn_p; - bool running; - + uint32_t current_sflen; + int next_offset; + uint32_t nof_rx_antennas; + + // Pointers to other classes mac_interface_phy *mac; rrc_interface_phy *rrc; srslte::log *log_h; srslte::thread_pool *workers_pool; + srslte::radio_multi *radio_h; phch_common *worker_com; prach *prach_buffer; - // Structures for Cell Camp - srslte_ue_sync_t ue_sync; - srslte_ue_mib_t ue_mib; - - // Structures for Cell Search - srslte_ue_cellsearch_t cs; - srslte_ue_mib_sync_t ue_mib_sync; + // Object for synchronization of the primary cell + srslte_ue_sync_t ue_sync; - uint32_t nof_rx_antennas; - - cf_t *sf_buffer[SRSLTE_MAX_PORTS]; + // Buffer for primary cell samples + cf_t *sf_buffer[SRSLTE_MAX_PORTS]; // Sync metrics - sync_metrics_t metrics; + sync_metrics_t metrics; + // State for primary cell enum { IDLE = 0, CELL_SEARCH, @@ -137,44 +241,30 @@ private: bool is_in_idle; + // Sampling rate mode (find is 1.96 MHz, camp is the full cell BW) enum { SRATE_NONE=0, SRATE_FIND, SRATE_CAMP } srate_mode; float current_srate; + // This is the primary cell srslte_cell_t cell; bool cell_is_set; - bool is_sfn_synched; - bool started; + bool started; float time_adv_sec; uint32_t tti; bool do_agc; - float last_gain; - float cellsearch_cfo; uint32_t nof_tx_mutex; uint32_t tx_mutex_cnt; + float ul_dl_factor; uint32_t current_earfcn; + int cur_earfcn_index; + bool cell_search_in_progress; - uint32_t sync_sfn_cnt; - const static uint32_t SYNC_SFN_TIMEOUT = 200; - float ul_dl_factor; - int cur_earfcn_index; - bool cell_search_in_progress; - uint32_t measure_cnt; - float measure_rsrp; - srslte_ue_dl_t ue_dl_measure; - - const static int RSRP_MEASURE_NOF_FRAMES = 5; - - int cell_sync_sfn(); - int cell_meas_rsrp(); - int cell_search(int force_N_id_2 = -1); - bool set_cell(); - - float dl_freq; - float ul_freq; + float dl_freq; + float ul_freq; }; diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 8642460aa..2249a0913 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -39,23 +39,15 @@ namespace srsue { -int radio_recv_wrapper_cs(void *obj, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) { - phch_recv *h = (phch_recv*) obj; - srslte::radio_multi *radio_h = h->radio_h; +int radio_recv_callback(void *obj, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) { + return ((phch_recv*) obj)->radio_recv_fnc(data, nsamples, rx_time); - if (radio_h->rx_now(data, nsamples, rx_time)) { - int offset = nsamples - h->current_sflen; - if (abs(offset) < 10 && offset != 0) { - h->next_offset = offset; - } else if (nsamples < 10) { - h->next_offset = nsamples; - } - return nsamples; - } else { - return -1; - } } +int scell_recv_callback(void *obj, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) { + return ((phch_recv*) obj)->scell_recv_fnc(data, nsamples, rx_time); +} + double callback_set_rx_gain(void *h, double gain) { srslte::radio_multi *radio_handler = (srslte::radio_multi *) h; return radio_handler->set_rx_gain_th(gain); @@ -69,68 +61,52 @@ phch_recv::phch_recv() { running = false; } -void phch_recv:: init(srslte::radio_multi *_radio_handler, mac_interface_phy *_mac, rrc_interface_phy *_rrc, +void phch_recv::init(srslte::radio_multi *_radio_handler, mac_interface_phy *_mac, rrc_interface_phy *_rrc, prach *_prach_buffer, srslte::thread_pool *_workers_pool, phch_common *_worker_com, srslte::log *_log_h, uint32_t nof_rx_antennas_, uint32_t prio, int sync_cpu_affinity) { radio_h = _radio_handler; - log_h = _log_h; - mac = _mac; - rrc = _rrc; - workers_pool = _workers_pool; - worker_com = _worker_com; - prach_buffer = _prach_buffer; + log_h = _log_h; + mac = _mac; + rrc = _rrc; + workers_pool = _workers_pool; + worker_com = _worker_com; + prach_buffer = _prach_buffer; nof_rx_antennas = nof_rx_antennas_; - reset(); - for (uint32_t i = 0; i < nof_rx_antennas; i++) { sf_buffer[i] = (cf_t *) srslte_vec_malloc(sizeof(cf_t) * 3 * SRSLTE_SF_LEN_PRB(100)); } - - if (srslte_ue_cellsearch_init_multi(&cs, 5, radio_recv_wrapper_cs, nof_rx_antennas, - this)) { - Error("SYNC: Initiating UE cell search\n"); + if (srslte_ue_sync_init_multi(&ue_sync, SRSLTE_MAX_PRB, false, radio_recv_callback, nof_rx_antennas, this)) { + Error("SYNC: Initiating ue_sync\n"); return; } - srslte_ue_cellsearch_set_nof_valid_frames(&cs, 2); - - // Set options defined in expert section - set_ue_sync_opts(&cs.ue_sync); + nof_tx_mutex = MUTEX_X_WORKER * workers_pool->get_nof_workers(); + worker_com->set_nof_mutex(nof_tx_mutex); - if (do_agc) { - srslte_ue_sync_start_agc(&cs.ue_sync, callback_set_rx_gain, last_gain); - } + // Initialize cell searcher + search_p.init(sf_buffer, log_h, nof_rx_antennas, this); - if (srslte_ue_dl_init(&ue_dl_measure, SRSLTE_MAX_PRB, nof_rx_antennas)) { - Error("SYNC: Initiating ue_dl_measure\n"); - return; - } + // Initialize SFN synchronizer + sfn_p.init(&ue_sync, sf_buffer, log_h); - if (srslte_ue_mib_init(&ue_mib, SRSLTE_MAX_PRB)) { - Error("SYNC: Initiating UE MIB decoder\n"); - return; - } + // Initialize measurement class for the primary cell + measure_p.init(&ue_sync, sf_buffer, log_h, nof_rx_antennas); - if (srslte_ue_sync_init_multi(&ue_sync, SRSLTE_MAX_PRB, false, radio_recv_wrapper_cs, nof_rx_antennas, this)) { - Error("SYNC: Initiating ue_sync\n"); - return; - } + // Start scell + scell.init(this, log_h, nof_rx_antennas_, prio, sync_cpu_affinity); - if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, radio_recv_wrapper_cs, nof_rx_antennas, this)) { - Error("SYNC: Initiating UE MIB synchronization\n"); - return; - } + reset(); - nof_tx_mutex = MUTEX_X_WORKER * workers_pool->get_nof_workers(); - worker_com->set_nof_mutex(nof_tx_mutex); + // Start main thread if (sync_cpu_affinity < 0) { start(prio); } else { start_cpu(prio, sync_cpu_affinity); } + } phch_recv::~phch_recv() { @@ -140,10 +116,6 @@ phch_recv::~phch_recv() { } } srslte_ue_sync_free(&ue_sync); - srslte_ue_dl_free(&ue_dl_measure); - srslte_ue_mib_free(&ue_mib); - srslte_ue_mib_sync_free(&ue_mib_sync); - srslte_ue_cellsearch_free(&cs); } void phch_recv::stop() { @@ -159,11 +131,14 @@ void phch_recv::reset() { time_adv_sec = 0; next_offset = 0; cell_is_set = false; - sync_sfn_cnt = 0; srate_mode = SRATE_NONE; cell_search_in_progress = false; current_earfcn = 0; radio_is_resetting = false; + sfn_p.reset(); + measure_p.reset(); + search_p.reset(); + } void phch_recv::radio_error() { @@ -232,23 +207,14 @@ void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) { bool phch_recv::set_cell() { cell_is_set = false; - if (srslte_ue_mib_set_cell(&ue_mib, cell)) { - Error("SYNC: Setting cell: initiating ue_mib\n"); - return false; - } + + // Set cell in all objects if (srslte_ue_sync_set_cell(&ue_sync, cell)) { Error("SYNC: Setting cell: initiating ue_sync"); return false; } - - // Set options defined in expert section - set_ue_sync_opts(&ue_sync); - - if (srslte_ue_dl_set_cell(&ue_dl_measure, cell)) { - Error("SYNC: Setting cell: initiating ue_dl_measure\n"); - return false; - } - + measure_p.set_cell(cell); + sfn_p.set_cell(cell); worker_com->set_cell(cell); for (uint32_t i = 0; i < workers_pool->get_nof_workers(); i++) { @@ -257,178 +223,20 @@ bool phch_recv::set_cell() { return false; } } - if (do_agc) { - srslte_ue_sync_start_agc(&ue_sync, callback_set_rx_gain, last_gain); - } - cell_is_set = true; - - return cell_is_set; -} - -int phch_recv::cell_search(int force_N_id_2) { - uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; - - srslte_ue_cellsearch_result_t found_cells[3]; - - bzero(&cell, sizeof(srslte_cell_t)); - bzero(found_cells, 3 * sizeof(srslte_ue_cellsearch_result_t)); - - if (srate_mode != SRATE_FIND) { - srate_mode = SRATE_FIND; - radio_h->set_rx_srate(1.92e6); - } - start_rx(); - - /* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */ - uint32_t max_peak_cell = 0; - int ret = SRSLTE_ERROR; - - Info("SYNC: Searching for cell...\n"); - printf("."); fflush(stdout); - - if (force_N_id_2 >= 0 && force_N_id_2 < 3) { - ret = srslte_ue_cellsearch_scan_N_id_2(&cs, force_N_id_2, &found_cells[force_N_id_2]); - max_peak_cell = force_N_id_2; - } else { - ret = srslte_ue_cellsearch_scan(&cs, found_cells, &max_peak_cell); - } - - last_gain = srslte_agc_get_gain(&cs.ue_sync.agc); - - if (ret < 0) { - Error("SYNC: Error decoding MIB: Error searching PSS\n"); - return -1; - } else if (ret == 0) { - stop_rx(); - Info("SYNC: Could not find any cell in this frequency\n"); - return 0; - } - // Save result - cell.id = found_cells[max_peak_cell].cell_id; - cell.cp = found_cells[max_peak_cell].cp; - cellsearch_cfo = found_cells[max_peak_cell].cfo; - - printf("\n"); - Info("SYNC: PSS/SSS detected: PCI=%d, CFO=%.1f KHz, CP=%s\n", - cell.id, cellsearch_cfo/1000, srslte_cp_string(cell.cp)); - - if (srslte_ue_mib_sync_set_cell(&ue_mib_sync, cell.id, cell.cp)) { - Error("SYNC: Setting UE MIB cell\n"); - return false; - } // Set options defined in expert section - set_ue_sync_opts(&ue_mib_sync.ue_sync); - - if (do_agc) { - srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, callback_set_rx_gain, last_gain); - } - - srslte_ue_sync_reset(&ue_mib_sync.ue_sync); - srslte_ue_sync_set_cfo(&ue_mib_sync.ue_sync, cellsearch_cfo); - - /* Find and decode MIB */ - int sfn_offset; - ret = srslte_ue_mib_sync_decode(&ue_mib_sync, - 40, - bch_payload, &cell.nof_ports, &sfn_offset); - stop_rx(); - last_gain = srslte_agc_get_gain(&ue_mib_sync.ue_sync.agc); - cellsearch_cfo = srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync); + set_ue_sync_opts(&ue_sync); + // Reset ue_sync and set CFO/gain from search procedure srslte_ue_sync_reset(&ue_sync); - srslte_ue_sync_set_cfo(&ue_sync, cellsearch_cfo); - - if (ret == 1) { - srslte_pbch_mib_unpack(bch_payload, &cell, NULL); - - fprintf(stdout, "Found Cell: PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", - cell.id, cell.nof_prb, cell.nof_ports, cellsearch_cfo/1000); - - Info("SYNC: MIB Decoded: PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", - cell.id, cell.nof_prb, cell.nof_ports, cellsearch_cfo/1000); - - return true; - } else if (ret == 0) { - Warning("SYNC: Found PSS but could not decode PBCH\n"); - return 0; - } else { - Error("SYNC: Receiving MIB\n"); - return -1; - } -} - - -int phch_recv::cell_sync_sfn(void) { - - int ret = SRSLTE_ERROR; - uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; - - srslte_ue_sync_decode_sss_on_track(&ue_sync, true); - ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer); - if (ret < 0) { - Error("SYNC: Error calling ue_sync_get_buffer"); - return -1; - } - - if (ret == 1) { - if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) { - int sfn_offset = 0; - Info("SYNC: Trying to decode MIB... SNR=%.1f dB\n", - 10*log10(srslte_chest_dl_get_snr(&ue_mib.chest))); - int n = srslte_ue_mib_decode(&ue_mib, sf_buffer[0], bch_payload, NULL, &sfn_offset); - if (n < 0) { - Error("SYNC: Error decoding MIB while synchronising SFN"); - return -1; - } else if (n == SRSLTE_UE_MIB_FOUND) { - uint32_t sfn; - srslte_pbch_mib_unpack(bch_payload, &cell, &sfn); - - sfn = (sfn+sfn_offset)%1024; - tti = sfn * 10; - - srslte_ue_sync_decode_sss_on_track(&ue_sync, true); - Info("SYNC: DONE, TTI=%d, sfn_offset=%d\n", tti, sfn_offset); - srslte_ue_mib_reset(&ue_mib); - return 1; - } - } - } else { - Debug("SYNC: PSS/SSS not found...\n"); + srslte_ue_sync_set_cfo(&ue_sync, search_p.get_last_cfo()); + if (do_agc) { + srslte_ue_sync_start_agc(&ue_sync, callback_set_rx_gain, search_p.get_last_gain()); } - return 0; -} - -int phch_recv::cell_meas_rsrp() { - - uint32_t cfi = 0; - tti = (tti+1) % 10240; - log_h->step(tti); - - uint32_t sf_idx = tti%10; - - int sync_res = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer); - if (sync_res == 1) { - if (srslte_ue_dl_decode_fft_estimate(&ue_dl_measure, sf_buffer, sf_idx, &cfi)) { - log_h->error("SYNC: Measuring RSRP: Estimating channel\n"); - return -1; - } - float rsrp = srslte_chest_dl_get_rsrp(&ue_dl_measure.chest); - float snr = srslte_chest_dl_get_snr(&ue_dl_measure.chest); - measure_rsrp = SRSLTE_VEC_CMA(rsrp, measure_rsrp, measure_cnt); - measure_cnt++; - log_h->info("SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n", - measure_cnt, RSRP_MEASURE_NOF_FRAMES, sf_idx, 10 * log10(rsrp / 1000), 10*log10(snr)); - if (measure_cnt >= RSRP_MEASURE_NOF_FRAMES) { - return 1; - } - } else { - log_h->error("SYNC: Measuring RSRP: Sync error\n"); - return -1; - } + cell_is_set = true; - return 0; + return cell_is_set; } void phch_recv::resync_sfn(bool is_connected) { @@ -437,9 +245,9 @@ void phch_recv::resync_sfn(bool is_connected) { stop_rx(); start_rx(); - srslte_ue_mib_reset(&ue_mib); + sfn_p.reset(); Info("SYNC: Starting SFN synchronization\n"); - sync_sfn_cnt = 0; + phy_state = is_connected?CELL_RESELECT:CELL_SELECT; } @@ -475,7 +283,7 @@ void phch_recv::reset_sync() { wait_radio_reset(); Warning("SYNC: Resetting sync, cell_search_in_progress=%s\n", cell_search_in_progress?"yes":"no"); - srslte_ue_sync_reset(&ue_mib_sync.ue_sync); + search_p.reset(); srslte_ue_sync_reset(&ue_sync); resync_sfn(true); } @@ -625,22 +433,96 @@ void phch_recv::set_sampling_rate() } } -void phch_recv::run_thread() { +void phch_recv::stop_rx() { + if (radio_is_rx) { + Info("SYNC: Stopping RX streaming\n"); + radio_h->stop_rx(); + } + radio_is_rx = false; +} + +void phch_recv::start_rx() { + if (!radio_is_rx) { + Info("SYNC: Starting RX streaming\n"); + radio_h->start_rx(); + } + radio_is_rx = true; +} + +uint32_t phch_recv::get_current_tti() { + return tti; +} + +bool phch_recv::status_is_sync() { + return phy_state == CELL_CAMP; +} + +void phch_recv::get_current_cell(srslte_cell_t *cell_) { + if (cell_) { + memcpy(cell_, &cell, sizeof(srslte_cell_t)); + } +} + +int phch_recv::radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) +{ + if (radio_h->rx_now(data, nsamples, rx_time)) { + int offset = nsamples - current_sflen; + if (abs(offset) < 10 && offset != 0) { + next_offset = offset; + } else if (nsamples < 10) { + next_offset = nsamples; + } + + if (offset == 0) { + scell.write(data, nsamples, rx_time); + } + return nsamples; + } else { + return -1; + } +} + +int phch_recv::scell_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) +{ + return scell.recv(data, nsamples, rx_time); +} + + + + + + + +/** + * MAIN THREAD + */ + +void phch_recv::run_thread() +{ phch_worker *worker = NULL; - cf_t *buffer[SRSLTE_MAX_PORTS]; + cf_t *buffer[SRSLTE_MAX_PORTS] = {NULL}; + uint32_t sf_idx = 0; phy_state = IDLE; is_in_idle = true; - while (running) { + while (running) + { if (phy_state != IDLE) { is_in_idle = false; Debug("SYNC: state=%d\n", phy_state); } + + tti = (tti+1) % 10240; + log_h->step(tti); + sf_idx = tti%10; + switch (phy_state) { case CELL_SEARCH: - if (cell_search_in_progress) { - switch(cell_search()) { - case 1: + if (cell_search_in_progress) + { + switch(search_p.run(&cell)) + { + case search::CELL_FOUND: if (!srslte_cell_isvalid(&cell)) { Error("SYNC: Detected invalid cell\n"); phy_state = IDLE; @@ -651,7 +533,7 @@ void phch_recv::run_thread() { resync_sfn(); } break; - case 0: + case search::CELL_NOT_FOUND: if (cell_search_in_progress) { cell_search_inc(); } @@ -664,46 +546,40 @@ void phch_recv::run_thread() { break; case CELL_RESELECT: case CELL_SELECT: - - srslte_ue_sync_decode_sss_on_track(&ue_sync, true); - - switch (cell_sync_sfn()) { - case 1: - srslte_ue_sync_set_agc_period(&ue_sync, 20); + switch (sfn_p.run_subframe(&cell, &tti)) + { + case sfn_sync::SFN_FOUND: if (!cell_search_in_progress) { - phy_state = CELL_CAMP; log_h->info("Sync OK. Camping on cell PCI=%d...\n", cell.id); + phy_state = CELL_CAMP; + } else { + measure_p.reset(); + phy_state = CELL_MEASURE; + } + break; + case sfn_sync::TIMEOUT: + if (phy_state == CELL_SELECT) { + phy_state = CELL_SEARCH; } else { - measure_cnt = 0; - measure_rsrp = 0; - phy_state = CELL_MEASURE; + phy_state = IDLE; } break; - case 0: + case sfn_sync::IDLE: break; default: radio_error(); break; } - sync_sfn_cnt++; - if (sync_sfn_cnt >= SYNC_SFN_TIMEOUT) { - sync_sfn_cnt = 0; - log_h->warning("SYNC: Timeout while synchronizing SFN\n"); - if (phy_state == CELL_SELECT) { - phy_state = CELL_SEARCH; - } else { - phy_state = IDLE; - } - } break; case CELL_MEASURE: - switch(cell_meas_rsrp()) { - case 1: + switch(measure_p.run_subframe(sf_idx)) + { + case measure::MEASURE_OK: log_h->info("SYNC: Measured OK. Camping on cell PCI=%d...\n", cell.id); phy_state = CELL_CAMP; - rrc->cell_found(earfcn[cur_earfcn_index], cell, 10*log10(measure_rsrp/1000)); + rrc->cell_found(earfcn[cur_earfcn_index], cell, measure_p.rsrp()); break; - case 0: + case measure::IDLE: break; default: radio_error(); @@ -711,7 +587,7 @@ void phch_recv::run_thread() { } break; case CELL_CAMP: - tti = (tti+1) % 10240; + worker = (phch_worker *) workers_pool->wait_worker(tti); if (worker) { for (uint32_t i = 0; i < nof_rx_antennas; i++) { @@ -721,8 +597,6 @@ void phch_recv::run_thread() { switch(srslte_ue_sync_zerocopy_multi(&ue_sync, buffer)) { case 1: - log_h->step(tti); - Debug("SYNC: Worker %d synchronized\n", worker->get_id()); metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync); @@ -786,33 +660,468 @@ void phch_recv::run_thread() { } } -void phch_recv::stop_rx() { - if (radio_is_rx) { - Info("SYNC: Stopping RX streaming\n"); - radio_h->stop_rx(); - } - radio_is_rx = false; -} -void phch_recv::start_rx() { - if (!radio_is_rx) { - Info("SYNC: Starting RX streaming\n"); - radio_h->start_rx(); - } - radio_is_rx = true; + + + + + + + + + + + + + +/********* + * Cell search class + */ +phch_recv::search::~search() +{ + srslte_ue_mib_sync_free(&ue_mib_sync); + srslte_ue_cellsearch_free(&cs); } -uint32_t phch_recv::get_current_tti() { - return tti; +void phch_recv::search::init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, phch_recv *parent) +{ + this->log_h = log_h; + this->p = parent; + + for (int i=0;ibuffer[i] = buffer[i]; + } + + if (srslte_ue_cellsearch_init_multi(&cs, 5, radio_recv_callback, nof_rx_antennas, parent)) { + Error("SYNC: Initiating UE cell search\n"); + } + + if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, radio_recv_callback, nof_rx_antennas, parent)) { + Error("SYNC: Initiating UE MIB synchronization\n"); + } + + srslte_ue_cellsearch_set_nof_valid_frames(&cs, 2); + + // Set options defined in expert section + p->set_ue_sync_opts(&cs.ue_sync); + + if (p->do_agc) { + srslte_ue_sync_start_agc(&cs.ue_sync, callback_set_rx_gain, 40); + } + + force_N_id_2 = -1; } -bool phch_recv::status_is_sync() { - return phy_state == CELL_CAMP; +void phch_recv::search::set_N_id_2(int N_id_2) { + force_N_id_2 = N_id_2; } -void phch_recv::get_current_cell(srslte_cell_t *cell_) { - if (cell_) { - memcpy(cell_, &cell, sizeof(srslte_cell_t)); +void phch_recv::search::reset() +{ + srslte_ue_sync_reset(&ue_mib_sync.ue_sync); +} + +float phch_recv::search::get_last_gain() +{ + return srslte_agc_get_gain(&ue_mib_sync.ue_sync.agc); +} + +float phch_recv::search::get_last_cfo() +{ + return srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync); +} + +phch_recv::search::ret_code phch_recv::search::run(srslte_cell_t *cell) +{ + + if (!cell) { + return ERROR; + } + + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; + + srslte_ue_cellsearch_result_t found_cells[3]; + + bzero(cell, sizeof(srslte_cell_t)); + bzero(found_cells, 3 * sizeof(srslte_ue_cellsearch_result_t)); + + if (p->srate_mode != SRATE_FIND) { + p->srate_mode = SRATE_FIND; + p->radio_h->set_rx_srate(1.92e6); + } + p->start_rx(); + + /* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */ + uint32_t max_peak_cell = 0; + int ret = SRSLTE_ERROR; + + Info("SYNC: Searching for cell...\n"); + printf("."); fflush(stdout); + + if (force_N_id_2 >= 0 && force_N_id_2 < 3) { + ret = srslte_ue_cellsearch_scan_N_id_2(&cs, force_N_id_2, &found_cells[force_N_id_2]); + max_peak_cell = force_N_id_2; + } else { + ret = srslte_ue_cellsearch_scan(&cs, found_cells, &max_peak_cell); + } + + if (ret < 0) { + Error("SYNC: Error decoding MIB: Error searching PSS\n"); + return ERROR; + } else if (ret == 0) { + p->stop_rx(); + Info("SYNC: Could not find any cell in this frequency\n"); + return CELL_NOT_FOUND; + } + // Save result + cell->id = found_cells[max_peak_cell].cell_id; + cell->cp = found_cells[max_peak_cell].cp; + float cfo = found_cells[max_peak_cell].cfo; + + printf("\n"); + Info("SYNC: PSS/SSS detected: PCI=%d, CFO=%.1f KHz, CP=%s\n", + cell->id, cfo/1000, srslte_cp_string(cell->cp)); + + if (srslte_ue_mib_sync_set_cell(&ue_mib_sync, cell->id, cell->cp)) { + Error("SYNC: Setting UE MIB cell\n"); + return ERROR; + } + + // Set options defined in expert section + p->set_ue_sync_opts(&ue_mib_sync.ue_sync); + + if (p->do_agc) { + srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, callback_set_rx_gain, srslte_agc_get_gain(&cs.ue_sync.agc)); + } + + srslte_ue_sync_reset(&ue_mib_sync.ue_sync); + srslte_ue_sync_set_cfo(&ue_mib_sync.ue_sync, cfo); + + /* Find and decode MIB */ + int sfn_offset; + ret = srslte_ue_mib_sync_decode(&ue_mib_sync, + 40, + bch_payload, &cell->nof_ports, &sfn_offset); + p->stop_rx(); + + if (ret == 1) { + srslte_pbch_mib_unpack(bch_payload, cell, NULL); + + fprintf(stdout, "Found Cell: PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", + cell->id, cell->nof_prb, cell->nof_ports, cfo/1000); + + Info("SYNC: MIB Decoded: PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", + cell->id, cell->nof_prb, cell->nof_ports, cfo/1000); + + return CELL_FOUND; + } else if (ret == 0) { + Warning("SYNC: Found PSS but could not decode PBCH\n"); + return CELL_NOT_FOUND; + } else { + Error("SYNC: Receiving MIB\n"); + return ERROR; + } +} + + + + + + + + +/********* + * SFN synchronizer class + */ + +phch_recv::sfn_sync::~sfn_sync() +{ + srslte_ue_mib_free(&ue_mib); +} + +void phch_recv::sfn_sync::init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t timeout) +{ + this->log_h = log_h; + this->ue_sync = ue_sync; + this->timeout = timeout; + + for (int i=0;ibuffer[i] = buffer[i]; + } + + if (srslte_ue_mib_init(&ue_mib, SRSLTE_MAX_PRB)) { + Error("SYNC: Initiating UE MIB decoder\n"); + } +} + +bool phch_recv::sfn_sync::set_cell(srslte_cell_t cell) +{ + if (srslte_ue_mib_set_cell(&ue_mib, cell)) { + Error("SYNC: Setting cell: initiating ue_mib\n"); + return false; } + return true; } + +void phch_recv::sfn_sync::reset() +{ + srslte_ue_mib_reset(&ue_mib); + cnt = 0; +} + +phch_recv::sfn_sync::ret_code phch_recv::sfn_sync::run_subframe(srslte_cell_t *cell, uint32_t *tti_cnt) +{ + + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; + + srslte_ue_sync_decode_sss_on_track(ue_sync, true); + int ret = srslte_ue_sync_zerocopy_multi(ue_sync, buffer); + if (ret < 0) { + Error("SYNC: Error calling ue_sync_get_buffer"); + return ERROR; + } + + if (ret == 1) { + if (srslte_ue_sync_get_sfidx(ue_sync) == 0) { + int sfn_offset = 0; + Info("SYNC: Trying to decode MIB... SNR=%.1f dB\n", 10*log10(srslte_chest_dl_get_snr(&ue_mib.chest))); + + int n = srslte_ue_mib_decode(&ue_mib, buffer[0], bch_payload, NULL, &sfn_offset); + if (n < 0) { + Error("SYNC: Error decoding MIB while synchronising SFN"); + return ERROR; + } else if (n == SRSLTE_UE_MIB_FOUND) { + uint32_t sfn; + srslte_pbch_mib_unpack(bch_payload, cell, &sfn); + + sfn = (sfn+sfn_offset)%1024; + if (tti_cnt) { + *tti_cnt = 10*sfn; + Info("SYNC: DONE, TTI=%d, sfn_offset=%d\n", *tti_cnt, sfn_offset); + } + + srslte_ue_sync_set_agc_period(ue_sync, 20); + srslte_ue_sync_decode_sss_on_track(ue_sync, true); + reset(); + return SFN_FOUND; + } + } + } else { + Debug("SYNC: PSS/SSS not found...\n"); + } + + cnt++; + if (cnt >= timeout) { + cnt = 0; + log_h->warning("SYNC: Timeout while synchronizing SFN\n"); + return TIMEOUT; + } + + return IDLE; +} + + + + + + +/********* + * Measurement class + */ +void phch_recv::measure::init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, uint32_t nof_subrames) +{ + this->log_h = log_h; + this->nof_subframes = nof_subrames; + this->ue_sync = ue_sync; + for (int i=0;ibuffer[i] = buffer[i]; + } + + if (srslte_ue_dl_init(&ue_dl, SRSLTE_MAX_PRB, nof_rx_antennas)) { + Error("SYNC: Initiating ue_dl_measure\n"); + return; + } + reset(); +} + +phch_recv::measure::~measure() { + srslte_ue_dl_free(&ue_dl); +} + +void phch_recv::measure::reset() { + cnt = 0; + mean_rsrp = 0; + mean_rsrq = 0; + mean_snr = 0; +} + +void phch_recv::measure::set_cell(srslte_cell_t cell) +{ + if (srslte_ue_dl_set_cell(&ue_dl, cell)) { + Error("SYNC: Setting cell: initiating ue_dl_measure\n"); + } +} + +float phch_recv::measure::rsrp() { + return 10*log10(mean_rsrp/1000); +} + +float phch_recv::measure::rsrq() { + return 10*log10(mean_rsrq); +} + +float phch_recv::measure::snr() { + return 10*log10(mean_snr); +} + +phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx) +{ + int sync_res = srslte_ue_sync_zerocopy_multi(ue_sync, buffer); + if (sync_res == 1) { + uint32_t cfi = 0; + + if (srslte_ue_dl_decode_fft_estimate(&ue_dl, buffer, sf_idx, &cfi)) { + log_h->error("SYNC: Measuring RSRP: Estimating channel\n"); + return ERROR; + } + + float rsrp = srslte_chest_dl_get_rsrp(&ue_dl.chest); + float rsrq = srslte_chest_dl_get_rsrq(&ue_dl.chest); + float snr = srslte_chest_dl_get_snr(&ue_dl.chest); + + mean_rsrp = SRSLTE_VEC_CMA(rsrp, mean_rsrp, cnt); + mean_rsrq = SRSLTE_VEC_CMA(rsrq, mean_rsrq, cnt); + mean_snr = SRSLTE_VEC_CMA(rsrq, mean_snr, cnt); + cnt++; + + log_h->info("SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n", + cnt, RSRP_MEASURE_NOF_FRAMES, sf_idx, + 10*log10(rsrp/1000), 10*log10(snr)); + + if (cnt >= nof_subframes) { + return MEASURE_OK; + } + } else { + log_h->error("SYNC: Measuring RSRP: Sync error\n"); + return ERROR; + } + + return IDLE; +} + + + + + + + + +/********** + * Secondary cell receiver + */ + +void phch_recv::scell_recv::init(phch_recv *parent, srslte::log *log_h, uint32_t nof_rx_antennas, uint32_t prio, int cpu_affinity) +{ + this->p = parent; + this->log_h = log_h; + + // Create the ringbuffer for secondary cell reception + for (int i=0;iinfo("SFN Sync OK. Camping on cell PCI=%d...\n", cell.id); + break; + case sfn_sync::TIMEOUT: + log_h->info("SFN sync timeout\n"); + break; + case sfn_sync::IDLE: + break; + default: + p->radio_error(); + break; + } + break; + case SCELL_MEASURE: + switch (measure_p.run_subframe(tti%10)) { + case measure::MEASURE_OK: + log_h->info("SYNC: Measured OK\n"); + break; + case measure::IDLE: + break; + default: + p->radio_error(); + break; + } + break; + } + } +} + } From c4c1c62360ccbede6bb85dbfd7575e545d1aa96e Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 13 Oct 2017 17:59:12 +0200 Subject: [PATCH 02/42] stable connection. Runs out of samples in ringbuffer if clock differences --- lib/include/srslte/phy/utils/ringbuffer.h | 8 +- lib/src/phy/utils/ringbuffer.c | 5 + srsue/hdr/phy/phch_recv.h | 11 +- srsue/hdr/phy/phy.h | 2 + srsue/hdr/ue.h | 1 + srsue/src/main.cc | 6 + srsue/src/phy/phch_recv.cc | 147 +++++++++++++++++----- srsue/src/phy/phy.cc | 5 + srsue/src/ue.cc | 5 + 9 files changed, 152 insertions(+), 38 deletions(-) diff --git a/lib/include/srslte/phy/utils/ringbuffer.h b/lib/include/srslte/phy/utils/ringbuffer.h index c9276d5a9..acd2ae5e6 100644 --- a/lib/include/srslte/phy/utils/ringbuffer.h +++ b/lib/include/srslte/phy/utils/ringbuffer.h @@ -17,17 +17,19 @@ typedef struct { } srslte_ringbuffer_t; -SRSLTE_API int srslte_ringbuffer_init(srslte_ringbuffer_t *q, +SRSLTE_API int srslte_ringbuffer_init(srslte_ringbuffer_t *q, int capacity); SRSLTE_API void srslte_ringbuffer_free(srslte_ringbuffer_t *q, int capacity); -SRSLTE_API int srslte_ringbuffer_write(srslte_ringbuffer_t *q, +SRSLTE_API int srslte_ringbuffer_status(srslte_ringbuffer_t *q); + +SRSLTE_API int srslte_ringbuffer_write(srslte_ringbuffer_t *q, void *ptr, int nof_bytes); -SRSLTE_API int srslte_ringbuffer_read(srslte_ringbuffer_t *q, +SRSLTE_API int srslte_ringbuffer_read(srslte_ringbuffer_t *q, void *ptr, int nof_bytes); diff --git a/lib/src/phy/utils/ringbuffer.c b/lib/src/phy/utils/ringbuffer.c index 02faaeb9a..f7a10e2c5 100644 --- a/lib/src/phy/utils/ringbuffer.c +++ b/lib/src/phy/utils/ringbuffer.c @@ -34,6 +34,11 @@ void srslte_ringbuffer_free(srslte_ringbuffer_t *q, int capacity) } } +int srslte_ringbuffer_status(srslte_ringbuffer_t *q) +{ + return q->count; +} + int srslte_ringbuffer_write(srslte_ringbuffer_t *q, void *p, int nof_bytes) { uint8_t *ptr = (uint8_t*) p; diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/phch_recv.h index 781603be1..bb23bb5b5 100644 --- a/srsue/hdr/phy/phch_recv.h +++ b/srsue/hdr/phy/phch_recv.h @@ -67,7 +67,9 @@ public: void set_time_adv_sec(float time_adv_sec); void get_current_cell(srslte_cell_t *cell); - + + void scell_enable(bool enable); + const static int MUTEX_X_WORKER = 4; int radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); @@ -155,6 +157,7 @@ private: float rsrp(); float rsrq(); float snr(); + float cfo(); private: srslte::log *log_h; srslte_ue_dl_t ue_dl; @@ -162,7 +165,7 @@ private: cf_t *buffer[SRSLTE_MAX_PORTS]; uint32_t cnt; uint32_t nof_subframes; - float mean_rsrp, mean_rsrq, mean_snr; + float mean_rsrp, mean_rsrq, mean_snr, mean_cfo; const static int RSRP_MEASURE_NOF_FRAMES = 5; }; @@ -172,9 +175,11 @@ private: public: void init(phch_recv *parent, srslte::log *log_h, uint32_t nof_rx_antennas, uint32_t prio, int cpu_affinity = -1); void stop(); + void reset(); int recv(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); void write(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); bool is_enabled(); + void set_cell(srslte_cell_t scell); private: void run_thread(); @@ -192,6 +197,8 @@ private: cf_t *sf_buffer[SRSLTE_MAX_PORTS]; srslte_ue_sync_t ue_sync; srslte_cell_t cell; + uint32_t nof_rx_antennas; + uint32_t current_sflen; measure measure_p; sfn_sync sfn_p; diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index 07a2713fa..c75fbb90d 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -78,6 +78,8 @@ public: void set_earfcn(std::vector earfcns); void force_freq(float dl_freq, float ul_freq); + void scell_enable(bool enable); + /********** RRC INTERFACE ********************/ void reset(); void sync_reset(); diff --git a/srsue/hdr/ue.h b/srsue/hdr/ue.h index 4e48f6b6d..fa461d1c9 100644 --- a/srsue/hdr/ue.h +++ b/srsue/hdr/ue.h @@ -80,6 +80,7 @@ public: void pregenerate_signals(bool enable); + void test_scell(); private: virtual ~ue(); diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 47d5f807e..0b67cecc1 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -387,14 +387,20 @@ int main(int argc, char *argv[]) pthread_t input; pthread_create(&input, NULL, &input_loop, &args); + bool scell_done = false; bool plot_started = false; bool signals_pregenerated = false; + while (running) { if (ue->is_attached()) { if (!signals_pregenerated && args.expert.pregenerate_signals) { ue->pregenerate_signals(true); signals_pregenerated = true; } + if (!scell_done) { + ((srsue::ue*) ue)->test_scell(); + scell_done = true; + } if (!plot_started && args.gui.enable) { ue->start_plot(); plot_started = true; diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 2249a0913..91d2cd482 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -64,7 +64,8 @@ phch_recv::phch_recv() { void phch_recv::init(srslte::radio_multi *_radio_handler, mac_interface_phy *_mac, rrc_interface_phy *_rrc, prach *_prach_buffer, srslte::thread_pool *_workers_pool, phch_common *_worker_com, srslte::log *_log_h, uint32_t nof_rx_antennas_, uint32_t prio, - int sync_cpu_affinity) { + int sync_cpu_affinity) +{ radio_h = _radio_handler; log_h = _log_h; mac = _mac; @@ -96,7 +97,7 @@ void phch_recv::init(srslte::radio_multi *_radio_handler, mac_interface_phy *_ma measure_p.init(&ue_sync, sf_buffer, log_h, nof_rx_antennas); // Start scell - scell.init(this, log_h, nof_rx_antennas_, prio, sync_cpu_affinity); + scell.init(this, log_h, nof_rx_antennas_, prio-1, sync_cpu_affinity); reset(); @@ -106,7 +107,6 @@ void phch_recv::init(srslte::radio_multi *_radio_handler, mac_interface_phy *_ma } else { start_cpu(prio, sync_cpu_affinity); } - } phch_recv::~phch_recv() { @@ -118,13 +118,15 @@ phch_recv::~phch_recv() { srslte_ue_sync_free(&ue_sync); } -void phch_recv::stop() { +void phch_recv::stop() +{ running = false; wait_thread_finish(); } -void phch_recv::reset() { +void phch_recv::reset() +{ tx_mutex_cnt = 0; running = true; phy_state = IDLE; @@ -141,7 +143,8 @@ void phch_recv::reset() { } -void phch_recv::radio_error() { +void phch_recv::radio_error() +{ log_h->error("SYNC: Receiving from radio.\n"); phy_state = IDLE; radio_is_resetting=true; @@ -157,7 +160,8 @@ void phch_recv::radio_error() { radio_is_resetting=false; } -bool phch_recv::wait_radio_reset() { +bool phch_recv::wait_radio_reset() +{ int cnt=0; while(cnt < 20 && radio_is_resetting) { sleep(1); @@ -166,11 +170,13 @@ bool phch_recv::wait_radio_reset() { return radio_is_resetting; } -void phch_recv::set_agc_enable(bool enable) { +void phch_recv::set_agc_enable(bool enable) +{ do_agc = enable; } -void phch_recv::set_time_adv_sec(float _time_adv_sec) { +void phch_recv::set_time_adv_sec(float _time_adv_sec) +{ if (TX_MODE_CONTINUOUS && !radio_h->is_first_of_burst()) { int nsamples = ceil(current_srate*_time_adv_sec); next_offset = -nsamples; @@ -179,7 +185,8 @@ void phch_recv::set_time_adv_sec(float _time_adv_sec) { } } -void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) { +void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) +{ if (worker_com->args->cfo_integer_enabled) { srslte_ue_sync_cfo_i_detec_en(q, true); } @@ -473,9 +480,12 @@ int phch_recv::radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, s next_offset = nsamples; } - if (offset == 0) { + if (offset <= 0) { scell.write(data, nsamples, rx_time); } + + log_h->debug("SYNC: received %d samples from radio\n", nsamples); + return nsamples; } else { return -1; @@ -487,7 +497,13 @@ int phch_recv::scell_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, s return scell.recv(data, nsamples, rx_time); } - +void phch_recv::scell_enable(bool enable) +{ + srslte_cell_t target_cell; + memcpy(&target_cell, &cell, sizeof(srslte_cell_t)); + target_cell.id++; + scell.set_cell(target_cell); +} @@ -512,7 +528,6 @@ void phch_recv::run_thread() Debug("SYNC: state=%d\n", phy_state); } - tti = (tti+1) % 10240; log_h->step(tti); sf_idx = tti%10; @@ -635,7 +650,6 @@ void phch_recv::run_thread() rrc->out_of_sync(); worker->release(); worker_com->reset_ul(); - mac->tti_clock(tti); break; default: radio_error(); @@ -652,11 +666,12 @@ void phch_recv::run_thread() } is_in_idle = true; usleep(1000); - // Keep running MAC timer from system clock - tti = (tti+1) % 10240; - mac->tti_clock(tti); break; } + + // Increase TTI counter and trigger MAC clock (lower priority) + tti = (tti+1) % 10240; + mac->tti_clock(tti); } } @@ -860,6 +875,7 @@ bool phch_recv::sfn_sync::set_cell(srslte_cell_t cell) Error("SYNC: Setting cell: initiating ue_mib\n"); return false; } + reset(); return true; } @@ -952,7 +968,8 @@ void phch_recv::measure::reset() { cnt = 0; mean_rsrp = 0; mean_rsrq = 0; - mean_snr = 0; + mean_snr = 0; + mean_cfo = 0; } void phch_recv::measure::set_cell(srslte_cell_t cell) @@ -960,6 +977,7 @@ void phch_recv::measure::set_cell(srslte_cell_t cell) if (srslte_ue_dl_set_cell(&ue_dl, cell)) { Error("SYNC: Setting cell: initiating ue_dl_measure\n"); } + reset(); } float phch_recv::measure::rsrp() { @@ -974,6 +992,10 @@ float phch_recv::measure::snr() { return 10*log10(mean_snr); } +float phch_recv::measure::cfo() { + return mean_cfo; +} + phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx) { int sync_res = srslte_ue_sync_zerocopy_multi(ue_sync, buffer); @@ -988,10 +1010,12 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx) float rsrp = srslte_chest_dl_get_rsrp(&ue_dl.chest); float rsrq = srslte_chest_dl_get_rsrq(&ue_dl.chest); float snr = srslte_chest_dl_get_snr(&ue_dl.chest); + float cfo = srslte_ue_sync_get_cfo(ue_sync); mean_rsrp = SRSLTE_VEC_CMA(rsrp, mean_rsrp, cnt); mean_rsrq = SRSLTE_VEC_CMA(rsrq, mean_rsrq, cnt); - mean_snr = SRSLTE_VEC_CMA(rsrq, mean_snr, cnt); + mean_snr = SRSLTE_VEC_CMA(snr, mean_snr, cnt); + mean_cfo = SRSLTE_VEC_CMA(cfo, mean_cfo, cnt); cnt++; log_h->info("SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n", @@ -1022,19 +1046,20 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx) void phch_recv::scell_recv::init(phch_recv *parent, srslte::log *log_h, uint32_t nof_rx_antennas, uint32_t prio, int cpu_affinity) { - this->p = parent; - this->log_h = log_h; + this->p = parent; + this->log_h = log_h; + this->nof_rx_antennas = nof_rx_antennas; // Create the ringbuffer for secondary cell reception for (int i=0;i current_sflen) { + read_samples = current_sflen; + } + if (nsamples < 10) { + read_samples = 0; + } + int n = 0; + for (uint32_t i=0;idebug("SCELL: tti=%d, read %d/%d samples from buffer, buffer size=%d\n", + tti, read_samples,nsamples, srslte_ringbuffer_status(&ring_buffer[0])); + return nsamples; } else { - Error("SYNC: SCell reception not enabled\n"); + Error("SCELL: Reception not enabled\n"); return -1; } } @@ -1079,7 +1151,7 @@ int phch_recv::scell_recv::recv(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, void phch_recv::scell_recv::write(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) { if (is_enabled()) { - for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (uint32_t i = 0; i < nof_rx_antennas; i++) { srslte_ringbuffer_write(&ring_buffer[i], data[i], sizeof(cf_t) * nsamples); } } @@ -1090,16 +1162,19 @@ void phch_recv::scell_recv::run_thread() while(running) { switch(scell_state) { case IDLE: + usleep(1000); break; case SCELL_SELECT: switch (sfn_p.run_subframe(&cell, &tti)) { case sfn_sync::SFN_FOUND: - log_h->info("SFN Sync OK. Camping on cell PCI=%d...\n", cell.id); + log_h->info("SCELL: SFN Sync OK. Camping on cell PCI=%d...\n", cell.id); + sfn_p.reset(); + scell_state = SCELL_MEASURE; break; case sfn_sync::TIMEOUT: - log_h->info("SFN sync timeout\n"); + log_h->info("SCELL: SFN sync timeout\n"); break; case sfn_sync::IDLE: break; @@ -1107,11 +1182,15 @@ void phch_recv::scell_recv::run_thread() p->radio_error(); break; } + break; case SCELL_MEASURE: switch (measure_p.run_subframe(tti%10)) { case measure::MEASURE_OK: - log_h->info("SYNC: Measured OK\n"); + log_h->info("SCELL: Measured OK TTI=%5d, RSRP=%.1f dBm, RSRQ=%.1f dB, SNR=%3.1f dB, CFO=%.1f KHz, Buff=%d\n", + tti, measure_p.rsrp(), measure_p.rsrq(), measure_p.snr(), measure_p.cfo()/1000, + srslte_ringbuffer_status(&ring_buffer[0])); + measure_p.reset(); break; case measure::IDLE: break; @@ -1121,6 +1200,8 @@ void phch_recv::scell_recv::run_thread() } break; } + // Increase TTI counter + tti = (tti+1) % 10240; } } diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index df29726d5..0e4bcdc5f 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -243,6 +243,11 @@ void phy::cell_search_next() sf_recv.cell_search_next(); } +void phy::scell_enable(bool enable) +{ + sf_recv.scell_enable(enable); +} + void phy::sync_reset() { sf_recv.reset_sync(); } diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 3560a78fe..ee00d8876 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -213,6 +213,11 @@ void ue::pregenerate_signals(bool enable) phy.enable_pregen_signals(enable); } +void ue::test_scell() +{ + phy.scell_enable(true); +}; + void ue::stop() { if(started) From 15e75b2c65b35c573bab2fd68c7fb1d553741307 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 23 Oct 2017 14:23:03 +0200 Subject: [PATCH 03/42] Created Bit interleaver object and SSE optimised interleaver --- lib/include/srslte/phy/fec/rm_turbo.h | 2 + lib/include/srslte/phy/utils/bit.h | 19 +++ lib/src/phy/fec/rm_turbo.c | 19 ++- lib/src/phy/fec/test/rm_turbo_test.c | 1 + lib/src/phy/fec/turbocoder.c | 10 +- lib/src/phy/phch/sch.c | 2 + lib/src/phy/utils/bit.c | 173 +++++++++++++++++++++++++- 7 files changed, 221 insertions(+), 5 deletions(-) diff --git a/lib/include/srslte/phy/fec/rm_turbo.h b/lib/include/srslte/phy/fec/rm_turbo.h index df0720b95..182b49fb8 100644 --- a/lib/include/srslte/phy/fec/rm_turbo.h +++ b/lib/include/srslte/phy/fec/rm_turbo.h @@ -58,6 +58,8 @@ SRSLTE_API int srslte_rm_turbo_tx(uint8_t *w_buff, SRSLTE_API void srslte_rm_turbo_gentables(); +SRSLTE_API void srslte_rm_turbo_free_tables(); + SRSLTE_API int srslte_rm_turbo_tx_lut(uint8_t *w_buff, uint8_t *systematic, uint8_t *parity, diff --git a/lib/include/srslte/phy/utils/bit.h b/lib/include/srslte/phy/utils/bit.h index c02ecd6bb..e4289b790 100644 --- a/lib/include/srslte/phy/utils/bit.h +++ b/lib/include/srslte/phy/utils/bit.h @@ -40,6 +40,25 @@ #include "srslte/config.h" +typedef struct { + uint32_t nof_bits; + uint16_t *interleaver; + uint16_t *byte_idx; + uint8_t *bit_mask; + uint8_t n_128; +} srslte_bit_interleaver_t; + +SRSLTE_API void srslte_bit_interleaver_init(srslte_bit_interleaver_t *q, + uint16_t *interleaver, + uint32_t nof_bits); + +SRSLTE_API void srslte_bit_interleaver_free(srslte_bit_interleaver_t *q); + +SRSLTE_API void srslte_bit_interleaver_run(srslte_bit_interleaver_t *q, + uint8_t *input, + uint8_t *output, + uint16_t w_offset); + SRSLTE_API void srslte_bit_interleave(uint8_t *input, uint8_t *output, uint16_t *interleaver, diff --git a/lib/src/phy/fec/rm_turbo.c b/lib/src/phy/fec/rm_turbo.c index cdc8ac88d..b1cc95a8c 100644 --- a/lib/src/phy/fec/rm_turbo.c +++ b/lib/src/phy/fec/rm_turbo.c @@ -61,7 +61,9 @@ static uint8_t RM_PERM_TC[NCOLS] = { 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, /* Align tables to 16-byte boundary */ static uint16_t interleaver_systematic_bits[192][6160]; // 4 tail bits +static srslte_bit_interleaver_t bit_interleavers_systematic_bits[192]; static uint16_t interleaver_parity_bits[192][2*6160]; +static srslte_bit_interleaver_t bit_interleavers_parity_bits[192]; static uint16_t deinterleaver[192][4][18448]; static int k0_vec[SRSLTE_NOF_TC_CB_SIZES][4][2]; static bool rm_turbo_tables_generated = false; @@ -235,7 +237,12 @@ void srslte_rm_turbo_gentables() { k0_vec[cb_idx][i][1] = -1; } srslte_rm_turbo_gentable_systematic(interleaver_systematic_bits[cb_idx], k0_vec[cb_idx], nrows, ndummy); + srslte_bit_interleaver_init(&bit_interleavers_systematic_bits[cb_idx], interleaver_systematic_bits[cb_idx], + (uint32_t) srslte_cbsegm_cbsize(cb_idx)+4); + srslte_rm_turbo_gentable_parity(interleaver_parity_bits[cb_idx], k0_vec[cb_idx], in_len/3, nrows, ndummy); + srslte_bit_interleaver_init(&bit_interleavers_parity_bits[cb_idx], interleaver_parity_bits[cb_idx], + (uint32_t) (srslte_cbsegm_cbsize(cb_idx)+4)*2); for (int i=0;i<4;i++) { srslte_rm_turbo_gentable_receive(deinterleaver[cb_idx][i], in_len, i); @@ -244,6 +251,12 @@ void srslte_rm_turbo_gentables() { } } +void srslte_rm_turbo_free_tables () { + for (int i = 0; i < SRSLTE_NOF_TC_CB_SIZES; i++) { + srslte_bit_interleaver_free(&bit_interleavers_systematic_bits[i]); + srslte_bit_interleaver_free(&bit_interleavers_parity_bits[i]); + } +} /** * Rate matching for LTE Turbo Coder @@ -274,11 +287,13 @@ int srslte_rm_turbo_tx_lut(uint8_t *w_buff, uint8_t *systematic, uint8_t *parity if (rv_idx == 0) { // Systematic bits - srslte_bit_interleave(systematic, w_buff, interleaver_systematic_bits[cb_idx], in_len/3); + //srslte_bit_interleave(systematic, w_buff, interleaver_systematic_bits[cb_idx], in_len/3); + srslte_bit_interleaver_run(&bit_interleavers_systematic_bits[cb_idx], systematic, w_buff, 0); // Parity bits - srslte_bit_interleave_w_offset(parity, &w_buff[in_len/24], interleaver_parity_bits[cb_idx], 2*in_len/3, 4); + //srslte_bit_interleave_w_offset(parity, &w_buff[in_len/24], interleaver_parity_bits[cb_idx], 2*in_len/3, 4); + srslte_bit_interleaver_run(&bit_interleavers_parity_bits[cb_idx], parity, &w_buff[in_len/24], 4); } /* Bit selection and transmission 5.1.4.1.2 */ diff --git a/lib/src/phy/fec/test/rm_turbo_test.c b/lib/src/phy/fec/test/rm_turbo_test.c index 6943c72d1..1c5b2abf5 100644 --- a/lib/src/phy/fec/test/rm_turbo_test.c +++ b/lib/src/phy/fec/test/rm_turbo_test.c @@ -197,6 +197,7 @@ int main(int argc, char **argv) { } } + srslte_rm_turbo_free_tables(); free(rm_bits); free(rm_bits2); free(rm_bits2_bytes); diff --git a/lib/src/phy/fec/turbocoder.c b/lib/src/phy/fec/turbocoder.c index b7785980c..64f05b5e8 100644 --- a/lib/src/phy/fec/turbocoder.c +++ b/lib/src/phy/fec/turbocoder.c @@ -43,6 +43,7 @@ uint8_t tcod_lut_next_state[188][8][256]; uint8_t tcod_lut_output[188][8][256]; uint16_t tcod_per_fw[188][6144]; +static srslte_bit_interleaver_t tcod_interleavers[188]; static bool table_initiated = false; @@ -63,6 +64,9 @@ void srslte_tcod_free(srslte_tcod_t *h) { if (h->temp) { free(h->temp); } + for (int i = 0; i < 188; i++) { + srslte_bit_interleaver_free(&tcod_interleavers[i]); + } } /* Expects bits (1 byte = 1 bit) and produces bits. The systematic and parity bits are interlaced in the output */ @@ -198,8 +202,9 @@ int srslte_tcod_encode_lut(srslte_tcod_t *h, uint8_t *input, uint8_t *parity, ui } parity[long_cb/8] = 0; // will put tail here later - /* Interleave input */ - srslte_bit_interleave(input, h->temp, tcod_per_fw[cblen_idx], long_cb); + /* Interleave input */ + srslte_bit_interleaver_run(&tcod_interleavers[cblen_idx], input, h->temp, 0); + //srslte_bit_interleave(input, h->temp, tcod_per_fw[cblen_idx], long_cb); /* Parity bits for the 2nd constituent encoders */ uint8_t state1 = 0; @@ -297,6 +302,7 @@ void srslte_tcod_gentable() { for (uint32_t i=0;icb_in) { free(q->cb_in); } diff --git a/lib/src/phy/utils/bit.c b/lib/src/phy/utils/bit.c index b1ae383a6..809d4c392 100644 --- a/lib/src/phy/utils/bit.c +++ b/lib/src/phy/utils/bit.c @@ -30,6 +30,7 @@ #include #include #include +#include #ifdef LV_HAVE_SSE @@ -38,6 +39,172 @@ #endif /* LV_HAVE_SSE */ #include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/vector.h" + +void srslte_bit_interleaver_init(srslte_bit_interleaver_t *q, + uint16_t *interleaver, + uint32_t nof_bits) { + static const uint8_t mask[] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 }; + + bzero(q, sizeof(srslte_bit_interleaver_t)); + + q->interleaver = srslte_vec_malloc(sizeof(uint16_t)*nof_bits); + q->byte_idx = srslte_vec_malloc(sizeof(uint16_t)*nof_bits); + q->bit_mask = srslte_vec_malloc(sizeof(uint8_t)*nof_bits); + q->nof_bits = nof_bits; + + for (int i = 0; i < nof_bits; i++) { + uint16_t i_px = interleaver[i]; + q->interleaver[i] = i_px; + q->byte_idx[i] = (uint16_t) (interleaver[i] / 8); + q->bit_mask[i] = (uint8_t) (mask[i_px%8]); + } +} + +void srslte_bit_interleaver_free(srslte_bit_interleaver_t *q) { + if (q->interleaver) { + free(q->interleaver); + } + + if (q->byte_idx) { + free(q->byte_idx); + } + + if (q->bit_mask) { + free(q->bit_mask); + } + + bzero(q, sizeof(srslte_bit_interleaver_t)); +} + +void srslte_bit_interleaver_run(srslte_bit_interleaver_t *q, uint8_t *input, uint8_t *output, uint16_t w_offset) { + static const uint8_t mask[] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 }; + uint16_t *byte_idx = q->byte_idx; + uint8_t *bit_mask = q->bit_mask; + uint8_t *output_ptr = output; + + uint32_t st=0, w_offset_p=0; + + if (w_offset < 8 && w_offset > 0) { + st=1; + for (uint32_t j=0;j<8-w_offset;j++) { + uint16_t i_p = q->interleaver[j]; + if (input[i_p/8] & mask[i_p%8]) { + output[0] |= mask[j+w_offset]; + } else { + output[0] &= ~(mask[j+w_offset]); + } + } + w_offset_p=8-w_offset; + } + + uint32_t i = st * 8; + + byte_idx += i - w_offset_p; + bit_mask += i - w_offset_p; + output_ptr += st; + +#ifdef LV_HAVE_SSE + for(; i < q->nof_bits - 15; i += 16) { + __m128i in128; + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x7); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x6); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x5); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x4); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x3); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x2); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x1); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x0); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xF); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xE); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xD); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xC); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xB); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xA); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x9); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x8); + + __m128i mask128 = _mm_loadu_si128((__m128i *) bit_mask); + mask128 = _mm_shuffle_epi8(mask128, _mm_set_epi8(0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7)); + + __m128i cmp128 = _mm_cmpeq_epi8(_mm_and_si128(in128, mask128), mask128); + *((uint16_t *) (output_ptr)) = (uint16_t) _mm_movemask_epi8(cmp128); + + bit_mask += 16; + output_ptr += 2; + } + +#endif /* LV_HAVE_SSE */ + + for(; i < q->nof_bits; i += 8) { + uint8_t out0 = (input[*(byte_idx++)] & *(bit_mask++))?mask[0]:(uint8_t)0; + uint8_t out1 = (input[*(byte_idx++)] & *(bit_mask++))?mask[1]:(uint8_t)0; + uint8_t out2 = (input[*(byte_idx++)] & *(bit_mask++))?mask[2]:(uint8_t)0; + uint8_t out3 = (input[*(byte_idx++)] & *(bit_mask++))?mask[3]:(uint8_t)0; + uint8_t out4 = (input[*(byte_idx++)] & *(bit_mask++))?mask[4]:(uint8_t)0; + uint8_t out5 = (input[*(byte_idx++)] & *(bit_mask++))?mask[5]:(uint8_t)0; + uint8_t out6 = (input[*(byte_idx++)] & *(bit_mask++))?mask[6]:(uint8_t)0; + uint8_t out7 = (input[*(byte_idx++)] & *(bit_mask++))?mask[7]:(uint8_t)0; + + *output_ptr = out0 | out1 | out2 | out3 | out4 | out5 | out6 | out7; + output_ptr++; + } + + for (uint32_t j=0;jnof_bits%8;j++) { + uint16_t i_p = q->interleaver[(q->nof_bits/8)*8+j-w_offset]; + if (input[i_p/8] & mask[i_p%8]) { + output[q->nof_bits/8] |= mask[j]; + } else { + output[q->nof_bits/8] &= ~(mask[j]); + } + } + for (uint32_t j=0;jinterleaver[(q->nof_bits/8)*8+j-w_offset]; + if (input[i_p/8] & (1<<(7-i_p%8))) { + output[q->nof_bits/8] |= mask[j]; + } else { + output[q->nof_bits/8] &= ~(mask[j]); + } + } + +#if 0 + /* THIS PIECE OF CODE IS FOR CHECKING SIMD BEHAVIOUR. DO NOT ENABLE. */ + uint8_t *output2 = malloc(q->nof_bits/8); + for (i=st;inof_bits/8;i++) { + + uint16_t i_p0 = q->interleaver[i*8+0-w_offset_p]; + uint16_t i_p1 = q->interleaver[i*8+1-w_offset_p]; + uint16_t i_p2 = q->interleaver[i*8+2-w_offset_p]; + uint16_t i_p3 = q->interleaver[i*8+3-w_offset_p]; + uint16_t i_p4 = q->interleaver[i*8+4-w_offset_p]; + uint16_t i_p5 = q->interleaver[i*8+5-w_offset_p]; + uint16_t i_p6 = q->interleaver[i*8+6-w_offset_p]; + uint16_t i_p7 = q->interleaver[i*8+7-w_offset_p]; + + uint8_t out0 = (input[i_p0/8] & mask[i_p0%8])?mask[0]:(uint8_t)0; + uint8_t out1 = (input[i_p1/8] & mask[i_p1%8])?mask[1]:(uint8_t)0; + uint8_t out2 = (input[i_p2/8] & mask[i_p2%8])?mask[2]:(uint8_t)0; + uint8_t out3 = (input[i_p3/8] & mask[i_p3%8])?mask[3]:(uint8_t)0; + uint8_t out4 = (input[i_p4/8] & mask[i_p4%8])?mask[4]:(uint8_t)0; + uint8_t out5 = (input[i_p5/8] & mask[i_p5%8])?mask[5]:(uint8_t)0; + uint8_t out6 = (input[i_p6/8] & mask[i_p6%8])?mask[6]:(uint8_t)0; + uint8_t out7 = (input[i_p7/8] & mask[i_p7%8])?mask[7]:(uint8_t)0; + + output2[i] = out0 | out1 | out2 | out3 | out4 | out5 | out6 | out7; + } + + for(i = st; i < q->nof_bits/8; i++) { + if (true || output[i] != output2[i]) { + printf("%05d/%05d %02X %02X\n", i, q->nof_bits/8, output[i], output2[i]); + } + //output[i] = output2[i]; + } + free(output2); +#endif +} + + void srslte_bit_interleave(uint8_t *input, uint8_t *output, uint16_t *interleaver, uint32_t nof_bits) { srslte_bit_interleave_w_offset(input, output, interleaver, nof_bits, 0); @@ -90,7 +257,11 @@ void srslte_bit_interleave_w_offset(uint8_t *input, uint8_t *output, uint16_t *i epx2.m128 = _mm_shuffle_epi8(ipx2.m128, _mm_set_epi8(0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E)); - epx.m64.reg_b = epx2.m64.reg_a; + epx.m128 = _mm_blendv_epi8(epx.m128, epx2.m128, _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, + (uint8_t) 0xFF, (uint8_t) 0xFF, + (uint8_t) 0xFF, (uint8_t) 0xFF, + (uint8_t) 0xFF, (uint8_t) 0xFF, + (uint8_t) 0xFF, (uint8_t) 0xFF)); b128.m128 = _mm_and_si128(epx.m128, _mm_set1_epi8(0x7)); b128.m128 = _mm_shuffle_epi8(m128mask, b128.m128); From 344ace8f52289c50caf61459cb5ff6ddec891fe4 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Sun, 12 Nov 2017 11:43:56 +0100 Subject: [PATCH 04/42] Fix issue #120 --- lib/src/phy/phch/ra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/phy/phch/ra.c b/lib/src/phy/phch/ra.c index be10c304c..19b78c60a 100644 --- a/lib/src/phy/phch/ra.c +++ b/lib/src/phy/phch/ra.c @@ -663,7 +663,7 @@ uint32_t srslte_ra_type1_N_rb(uint32_t nof_prb) { /* Convert Type2 scheduling L_crb and RB_start to RIV value */ uint32_t srslte_ra_type2_to_riv(uint32_t L_crb, uint32_t RB_start, uint32_t nof_prb) { uint32_t riv; - if (L_crb <= nof_prb / 2) { + if ((L_crb - 1) <= nof_prb / 2) { riv = nof_prb * (L_crb - 1) + RB_start; } else { riv = nof_prb * (nof_prb - L_crb + 1) + nof_prb - 1 - RB_start; @@ -907,4 +907,4 @@ void srslte_ra_prb_fprint(FILE *f, srslte_ra_dl_grant_t *grant) { } } -} \ No newline at end of file +} From 12d8b373c7e5f7a2c15e9ef3216c5d87c6e51e79 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Mon, 20 Nov 2017 10:02:39 +0100 Subject: [PATCH 05/42] srsUE takes and reports intra-frequency measurements correctly --- CMakeLists.txt | 16 - lib/include/srslte/asn1/liblte_rrc.h | 3 + lib/include/srslte/common/threads.h | 14 +- lib/include/srslte/interfaces/ue_interfaces.h | 9 +- lib/include/srslte/phy/common/phy_common.h | 3 +- lib/include/srslte/phy/utils/ringbuffer.h | 5 +- lib/src/phy/CMakeLists.txt | 4 - lib/src/phy/sync/sync.c | 1 - lib/src/phy/utils/ringbuffer.c | 20 +- srsue/hdr/phy/phch_common.h | 4 +- srsue/hdr/phy/phch_recv.h | 109 ++- srsue/hdr/phy/phy.h | 11 +- srsue/hdr/ue.h | 2 - srsue/hdr/upper/rrc.h | 172 ++++- srsue/src/mac/mac.cc | 2 + srsue/src/main.cc | 5 - srsue/src/phy/phch_common.cc | 3 + srsue/src/phy/phch_recv.cc | 470 +++++++----- srsue/src/phy/phch_worker.cc | 15 +- srsue/src/phy/phy.cc | 21 +- srsue/src/ue.cc | 5 - srsue/src/upper/rrc.cc | 714 ++++++++++++++++-- 22 files changed, 1198 insertions(+), 410 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index efaa1973a..73b38ceb1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,7 +61,6 @@ set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") option(ENABLE_SRSUE "Build srsUE application" ON) option(ENABLE_SRSENB "Build srsENB application" ON) -option(ENABLE_VOLK "Enable use of VOLK SIMD library" OFF) option(ENABLE_GUI "Enable GUI (using srsGUI)" ON) option(ENABLE_BLADERF "Enable BladeRF" ON) @@ -189,21 +188,6 @@ if(ENABLE_GUI) endif(SRSGUI_FOUND) endif(ENABLE_GUI) -# VOLK -include(CheckFunctionExistsMath) -if(ENABLE_VOLK) - find_package(Volk) - if(VOLK_FOUND) - include_directories(${VOLK_INCLUDE_DIRS}) - link_directories(${VOLK_LIBRARY_DIRS}) - message(STATUS "Compiling with VOLK SIMD library.") - else(VOLK_FOUND) - message(STATUS "VOLK SIMD library NOT found. Using generic implementation.") - endif(VOLK_FOUND) -else(ENABLE_VOLK) - message(STATUS "VOLK library disabled") -endif(ENABLE_VOLK) - ######################################################################## # Install Dirs ######################################################################## diff --git a/lib/include/srslte/asn1/liblte_rrc.h b/lib/include/srslte/asn1/liblte_rrc.h index c5c3b60e2..46f725ec3 100644 --- a/lib/include/srslte/asn1/liblte_rrc.h +++ b/lib/include/srslte/asn1/liblte_rrc.h @@ -1218,6 +1218,9 @@ typedef enum{ }LIBLTE_RRC_REPORT_AMOUNT_ENUM; static const char liblte_rrc_report_amount_text[LIBLTE_RRC_REPORT_AMOUNT_N_ITEMS][20] = { "r1", "r2", "r4", "r8", "r16", "r32", "r64", "INFINITY"}; + +static const int8 liblte_rrc_report_amount_num[LIBLTE_RRC_REPORT_AMOUNT_N_ITEMS] = {1, 2, 4, 8, 16, 32, 64, -1}; + typedef enum{ LIBLTE_RRC_THRESHOLD_UTRA_TYPE_RSCP = 0, LIBLTE_RRC_THRESHOLD_UTRA_TYPE_ECNO, diff --git a/lib/include/srslte/common/threads.h b/lib/include/srslte/common/threads.h index a8807ba9b..077dda72b 100644 --- a/lib/include/srslte/common/threads.h +++ b/lib/include/srslte/common/threads.h @@ -78,22 +78,30 @@ class periodic_thread : public thread { public: void start_periodic(int period_us_, int priority = -1) { + run_enable = true; period_us = period_us_; start(priority); } + void stop() { + run_enable = false; + wait_thread_finish(); + } protected: virtual void run_period() = 0; private: int wakeups_missed; int timer_fd; - int period_us; + int period_us; + bool run_enable; void run_thread() { if (make_periodic()) { return; } - while(1) { + while(run_enable) { run_period(); - wait_period(); + if (run_enable) { + wait_period(); + } } } int make_periodic() { diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 88dfd285c..a4ecf1345 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -134,6 +134,7 @@ class rrc_interface_mac : public rrc_interface_mac_common { public: virtual void release_pucch_srs() = 0; + virtual void run_tti(uint32_t tti) = 0; }; // RRC interface for PHY @@ -144,6 +145,7 @@ public: 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 new_phy_meas(float rsrp, float rsrq, uint32_t tti, uint32_t earfcn = 0, uint32_t pci = 0) = 0; }; // RRC interface for NAS @@ -521,7 +523,7 @@ public: bool enable_64qam; } phy_cfg_t; - virtual void get_current_cell(srslte_cell_t *cell) = 0; + virtual void get_current_cell(srslte_cell_t *cell, uint32_t *current_earfcn = NULL) = 0; virtual void get_config(phy_cfg_t *phy_cfg) = 0; virtual void set_config(phy_cfg_t *phy_cfg) = 0; virtual void set_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated) = 0; @@ -529,6 +531,11 @@ public: virtual void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd) = 0; virtual void set_config_64qam_en(bool enable) = 0; + /* Measurements interface */ + virtual void meas_reset() = 0; + virtual int meas_start(uint32_t earfcn, int pci = -1) = 0; + virtual int meas_stop(uint32_t earfcn, int pci = -1) = 0; + /* Cell search and selection procedures */ virtual void cell_search_start() = 0; virtual void cell_search_stop() = 0; diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index 4a1eeb27d..c55713cfc 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -301,7 +301,8 @@ SRSLTE_API int srslte_str2mimotype(char *mimo_type_str, SRSLTE_API char *srslte_mimotype2str(srslte_mimo_type_t mimo_type); -SRSLTE_API uint32_t srslte_tti_interval(uint32_t tti1, +/* Returns the interval tti1-tti2 mod 10240 */ +SRSLTE_API uint32_t srslte_tti_interval(uint32_t tti1, uint32_t tti2); #endif diff --git a/lib/include/srslte/phy/utils/ringbuffer.h b/lib/include/srslte/phy/utils/ringbuffer.h index acd2ae5e6..e590131ff 100644 --- a/lib/include/srslte/phy/utils/ringbuffer.h +++ b/lib/include/srslte/phy/utils/ringbuffer.h @@ -20,8 +20,9 @@ typedef struct { SRSLTE_API int srslte_ringbuffer_init(srslte_ringbuffer_t *q, int capacity); -SRSLTE_API void srslte_ringbuffer_free(srslte_ringbuffer_t *q, - int capacity); +SRSLTE_API void srslte_ringbuffer_free(srslte_ringbuffer_t *q); + +SRSLTE_API void srslte_ringbuffer_reset(srslte_ringbuffer_t *q); SRSLTE_API int srslte_ringbuffer_status(srslte_ringbuffer_t *q); diff --git a/lib/src/phy/CMakeLists.txt b/lib/src/phy/CMakeLists.txt index 572ff19c3..b52af7b1d 100644 --- a/lib/src/phy/CMakeLists.txt +++ b/lib/src/phy/CMakeLists.txt @@ -57,9 +57,5 @@ set(srslte_srcs $ add_library(srslte_phy STATIC ${srslte_srcs}) target_link_libraries(srslte_phy ${FFT_LIBRARIES}) -if(VOLK_FOUND) - target_link_libraries(srslte_phy ${VOLK_LIBRARIES}) -endif(VOLK_FOUND) - target_link_libraries(srslte_phy pthread m) install(TARGETS srslte_phy DESTINATION ${LIBRARY_DIR}) diff --git a/lib/src/phy/sync/sync.c b/lib/src/phy/sync/sync.c index ee2ba76d1..0fb1b819d 100644 --- a/lib/src/phy/sync/sync.c +++ b/lib/src/phy/sync/sync.c @@ -62,7 +62,6 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && - frame_size <= 307200 && fft_size_isvalid(fft_size)) { ret = SRSLTE_ERROR; diff --git a/lib/src/phy/utils/ringbuffer.c b/lib/src/phy/utils/ringbuffer.c index f7a10e2c5..400f80360 100644 --- a/lib/src/phy/utils/ringbuffer.c +++ b/lib/src/phy/utils/ringbuffer.c @@ -11,10 +11,9 @@ int srslte_ringbuffer_init(srslte_ringbuffer_t *q, int capacity) if (!q->buffer) { return -1; } - q->capacity = capacity; - q->count = 0; - q->wpm = 0; - q->rpm = 0; + + q->capacity = capacity; + srslte_ringbuffer_reset(q); pthread_mutex_init(&q->mutex, NULL); pthread_cond_init(&q->cvar, NULL); @@ -22,7 +21,7 @@ int srslte_ringbuffer_init(srslte_ringbuffer_t *q, int capacity) return 0; } -void srslte_ringbuffer_free(srslte_ringbuffer_t *q, int capacity) +void srslte_ringbuffer_free(srslte_ringbuffer_t *q) { if (q) { if (q->buffer) { @@ -34,6 +33,15 @@ void srslte_ringbuffer_free(srslte_ringbuffer_t *q, int capacity) } } +void srslte_ringbuffer_reset(srslte_ringbuffer_t *q) +{ + pthread_mutex_lock(&q->mutex); + q->count = 0; + q->wpm = 0; + q->rpm = 0; + pthread_mutex_unlock(&q->mutex); +} + int srslte_ringbuffer_status(srslte_ringbuffer_t *q) { return q->count; @@ -44,7 +52,7 @@ int srslte_ringbuffer_write(srslte_ringbuffer_t *q, void *p, int nof_bytes) uint8_t *ptr = (uint8_t*) p; int w_bytes = nof_bytes; pthread_mutex_lock(&q->mutex); - if (q->count + w_bytes >= q->capacity) { + if (q->count + w_bytes > q->capacity) { w_bytes = q->capacity - q->count; fprintf(stderr, "Buffer overrun: lost %d bytes\n", nof_bytes - w_bytes); } diff --git a/srsue/hdr/phy/phch_common.h b/srsue/hdr/phy/phch_common.h index 39e9e9685..f3c36d994 100644 --- a/srsue/hdr/phy/phch_common.h +++ b/srsue/hdr/phy/phch_common.h @@ -65,7 +65,9 @@ namespace srsue { float avg_snr_db; float avg_noise; float avg_rsrp; - + + uint32_t serving_cell_report_period; + phch_common(uint32_t max_mutex = 3); void init(phy_interface_rrc::phy_cfg_t *config, phy_args_t *args, diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/phch_recv.h index bb23bb5b5..e35610c0b 100644 --- a/srsue/hdr/phy/phch_recv.h +++ b/srsue/hdr/phy/phch_recv.h @@ -27,10 +27,13 @@ #ifndef UEPHYRECV_H #define UEPHYRECV_H +#include + #include "srslte/srslte.h" #include "srslte/common/log.h" #include "srslte/common/threads.h" #include "srslte/common/thread_pool.h" +#include "srslte/common/tti_sync_cv.h" #include "srslte/radio/radio_multi.h" #include "phy/prach.h" #include "phy/phch_worker.h" @@ -39,7 +42,8 @@ namespace srsue { -typedef _Complex float cf_t; +typedef _Complex float cf_t; + class phch_recv : public thread { @@ -61,14 +65,17 @@ public: void cell_search_next(bool reset = false); bool cell_select(uint32_t earfcn, srslte_cell_t cell); + void meas_reset(); + int meas_start(uint32_t earfcn, int pci); + int meas_stop(uint32_t earfcn, int pci); + uint32_t get_current_tti(); bool status_is_sync(); void set_time_adv_sec(float time_adv_sec); - void get_current_cell(srslte_cell_t *cell); + void get_current_cell(srslte_cell_t *cell, uint32_t *earfcn = NULL); - void scell_enable(bool enable); const static int MUTEX_X_WORKER = 4; @@ -125,13 +132,13 @@ private: // Class to synchronize system frame number class sfn_sync { public: - typedef enum {IDLE, SFN_FOUND, ERROR, TIMEOUT} ret_code; + typedef enum {IDLE, SFN_FOUND, SFX0_FOUND, ERROR, TIMEOUT} ret_code; ~sfn_sync(); void init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t timeout = SYNC_SFN_TIMEOUT); void reset(); bool set_cell(srslte_cell_t cell); - ret_code run_subframe(srslte_cell_t *cell, uint32_t *tti_cnt); + ret_code run_subframe(srslte_cell_t *cell, uint32_t *tti_cnt, bool sfidx_only = false); private: srslte::log *log_h; @@ -145,74 +152,106 @@ private: // Class to perform cell measurements class measure { + + // TODO: This class could early stop once the variance between the last N measurements is below 3GPP requirements + public: typedef enum {IDLE, MEASURE_OK, ERROR} ret_code; ~measure(); - void init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, + void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, uint32_t nof_subframes = RSRP_MEASURE_NOF_FRAMES); void reset(); void set_cell(srslte_cell_t cell); ret_code run_subframe(uint32_t sf_idx); + ret_code run_subframe_sync(srslte_ue_sync_t *ue_sync, uint32_t sf_idx); + ret_code run_multiple_subframes(cf_t *buffer, uint32_t sf_idx, uint32_t nof_sf); float rsrp(); float rsrq(); float snr(); - float cfo(); private: srslte::log *log_h; srslte_ue_dl_t ue_dl; - srslte_ue_sync_t *ue_sync; cf_t *buffer[SRSLTE_MAX_PORTS]; uint32_t cnt; uint32_t nof_subframes; - float mean_rsrp, mean_rsrq, mean_snr, mean_cfo; + uint32_t current_prb; + float mean_rsrp, mean_rsrq, mean_snr; const static int RSRP_MEASURE_NOF_FRAMES = 5; }; - // Class to receive secondary cell - class scell_recv : public thread { + class scell_recv { public: - void init(phch_recv *parent, srslte::log *log_h, uint32_t nof_rx_antennas, uint32_t prio, int cpu_affinity = -1); - void stop(); + const static int MAX_CELLS = 8; + typedef struct { + uint32_t pci; + float rsrp; + float rsrq; + uint32_t offset; + } cell_info_t; + void init(srslte::log *log_h); void reset(); - int recv(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); - void write(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); - bool is_enabled(); - void set_cell(srslte_cell_t scell); + int find_cells(cf_t *input_buffer, srslte_cell_t current_cell, uint32_t nof_sf, cell_info_t found_cells[MAX_CELLS]); private: - void run_thread(); - enum { - IDLE = 0, - SCELL_SELECT, - SCELL_MEASURE, - SCELL_CAMPING - } scell_state; + const static int DEFAULT_MEASUREMENT_LEN = 10; - srslte::log *log_h; - phch_recv *p; - bool running; - srslte_ringbuffer_t ring_buffer[SRSLTE_MAX_PORTS]; cf_t *sf_buffer[SRSLTE_MAX_PORTS]; - srslte_ue_sync_t ue_sync; - srslte_cell_t cell; - uint32_t nof_rx_antennas; - uint32_t current_sflen; + srslte::log *log_h; + srslte_sync_t sync_find; measure measure_p; - sfn_sync sfn_p; - uint32_t tti; }; + /* TODO: Intra-freq measurements can be improved by capturing 200 ms length signal and run cell search + + * measurements offline using sync object and finding multiple cells for each N_id_2 + */ + + // Class to perform intra-frequency measurements + class intra_measure : public thread { + public: + void init(phch_common *common, rrc_interface_phy *rrc, srslte::log *log_h); + void stop(); + void add_cell(int pci); + void rem_cell(int pci); + void set_primay_cell(uint32_t earfcn, srslte_cell_t cell); + void clear_cells(); + void write(uint32_t tti, cf_t *data, uint32_t nsamples); + private: + void run_thread(); + const static int CAPTURE_LEN_SF = 15; + const static int INTRA_FREQ_MEAS_PERIOD_MS = 200; + scell_recv scell; + rrc_interface_phy *rrc; + srslte::log *log_h; + phch_common *common; + uint32_t current_earfcn; + uint32_t current_sflen; + srslte_cell_t primary_cell; + std::vector active_pci; + + srslte::tti_sync_cv tti_sync; + + cf_t *search_buffer; + + scell_recv::cell_info_t info[scell_recv::MAX_CELLS]; + + bool running; + bool receive_enabled; + bool receiving; + uint32_t measure_tti; + uint32_t receive_cnt; + srslte_ringbuffer_t ring_buffer; + }; // Objects for internal use - scell_recv scell; measure measure_p; search search_p; sfn_sync sfn_p; + intra_measure intra_freq_meas; uint32_t current_sflen; int next_offset; diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index c75fbb90d..6a0e8891e 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -40,8 +40,8 @@ #include "srslte/interfaces/ue_interfaces.h" namespace srsue { - -typedef _Complex float cf_t; + +typedef _Complex float cf_t; class phy : public phy_interface_mac @@ -78,7 +78,6 @@ public: void set_earfcn(std::vector earfcns); void force_freq(float dl_freq, float ul_freq); - void scell_enable(bool enable); /********** RRC INTERFACE ********************/ void reset(); @@ -89,6 +88,10 @@ public: void cell_search_next(); bool cell_select(uint32_t earfcn, srslte_cell_t phy_cell); + void meas_reset(); + int meas_start(uint32_t earfcn, int pci); + int meas_stop(uint32_t earfcn, int pci); + /********** MAC INTERFACE ********************/ /* Functions to synchronize with a cell */ bool sync_status(); // this is also RRC interface @@ -133,7 +136,7 @@ public: float get_pathloss_db(); uint32_t get_current_tti(); - void get_current_cell(srslte_cell_t *cell); + void get_current_cell(srslte_cell_t *cell, uint32_t *current_earfcn = NULL); void start_plot(); diff --git a/srsue/hdr/ue.h b/srsue/hdr/ue.h index fa461d1c9..bfb38f14d 100644 --- a/srsue/hdr/ue.h +++ b/srsue/hdr/ue.h @@ -80,8 +80,6 @@ public: void pregenerate_signals(bool enable); - void test_scell(); - private: virtual ~ue(); diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index 3e2fb70dd..5ec484251 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -38,6 +38,7 @@ #include "srslte/common/threads.h" #include +#include using srslte::byte_buffer_t; @@ -80,6 +81,46 @@ public: void liblte_rrc_log(char *str); + + // NAS interface + void write_sdu(uint32_t lcid, byte_buffer_t *sdu); + + uint16_t get_mcc(); + + uint16_t get_mnc(); + + void enable_capabilities(); + void plmn_search(); + void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id); + + // 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); + void new_phy_meas(float rsrp, float rsrq, uint32_t tti, uint32_t earfcn, uint32_t pci); + + // MAC interface + void release_pucch_srs(); + void run_tti(uint32_t tti); + + void ra_problem(); + + // GW interface + bool is_connected(); + + bool have_drb(); + + // PDCP interface + void write_pdu(uint32_t lcid, byte_buffer_t *pdu); + + void write_pdu_bcch_bch(byte_buffer_t *pdu); + + void write_pdu_bcch_dlsch(byte_buffer_t *pdu); + + void write_pdu_pcch(byte_buffer_t *pdu); + + private: srslte::byte_buffer_pool *pool; srslte::log *rrc_log; @@ -90,7 +131,9 @@ private: nas_interface_rrc *nas; usim_interface_rrc *usim; - srslte::bit_buffer_t bit_buf; + void send_ul_dcch_msg(byte_buffer_t *pdu = NULL); + LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + srslte::bit_buffer_t bit_buf; pthread_mutex_t mutex; @@ -166,42 +209,6 @@ private: bool thread_running; void run_thread(); - // NAS interface - void write_sdu(uint32_t lcid, byte_buffer_t *sdu); - - uint16_t get_mcc(); - - uint16_t get_mnc(); - - void enable_capabilities(); - void plmn_search(); - void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id); - - // 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 - void release_pucch_srs(); - - void ra_problem(); - - // GW interface - bool is_connected(); - - bool have_drb(); - - // PDCP interface - void write_pdu(uint32_t lcid, byte_buffer_t *pdu); - - void write_pdu_bcch_bch(byte_buffer_t *pdu); - - void write_pdu_bcch_dlsch(byte_buffer_t *pdu); - - void write_pdu_pcch(byte_buffer_t *pdu); - // Radio bearers typedef enum{ RB_ID_SRB0 = 0, @@ -226,6 +233,97 @@ private: } } + // Measurements sub-class + class rrc_meas { + public: + void init(rrc *parent); + void reset(); + void parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *meas_config); + void new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, float rsrq, uint32_t tti); + void run_tti(uint32_t tti); + bool timer_expired(uint32_t timer_id); + private: + + const static int NOF_MEASUREMENTS = 3; + + typedef enum {RSRP = 0, RSRQ = 1, BOTH = 2} quantity_t; + + typedef struct { + uint32_t pci; + float q_offset; + } meas_cell_t; + + typedef struct { + uint32_t earfcn; + float q_offset; + std::map cells; + } meas_obj_t; + + typedef struct { + uint32_t interval; + uint32_t max_cell; + uint32_t amount; + quantity_t trigger_quantity; + quantity_t report_quantity; + LIBLTE_RRC_EVENT_EUTRA_STRUCT event; + enum {EVENT, PERIODIC} trigger_type; + } report_cfg_t; + + typedef struct { + float ms[NOF_MEASUREMENTS]; + bool triggered; + bool timer_enter_triggered; + bool timer_exit_triggered; + uint32_t enter_tti; + uint32_t exit_tti; + } meas_value_t; + + typedef struct { + uint32_t nof_reports_sent; + uint32_t report_id; + uint32_t object_id; + bool triggered; + uint32_t periodic_timer; + std::map cell_values; // Value for each PCI in this object + } meas_t; + + std::map objects; + std::map reports_cfg; + std::map active; + + rrc *parent; + srslte::log *log_h; + phy_interface_rrc *phy; + srslte::mac_interface_timers *mac_timers; + + uint32_t filter_k_rsrp, filter_k_rsrq; + float filter_a[NOF_MEASUREMENTS]; + + meas_value_t pcell_measurement; + + bool s_measure_enabled; + float s_measure_value; + + void stop_reports_object(uint32_t object_id); + void remove_meas_object(uint32_t object_id); + void remove_meas_report(uint32_t report_id); + void remove_meas_id(uint32_t meas_id); + void calculate_triggers(uint32_t tti); + void update_phy(); + void L3_filter(meas_value_t *value, float rsrp[NOF_MEASUREMENTS]); + bool find_earfcn_cell(uint32_t earfcn, uint32_t pci, meas_obj_t **object, int *cell_idx); + float range_to_value(quantity_t quant, uint8_t range); + uint8_t value_to_range(quantity_t quant, float value); + bool process_event(LIBLTE_RRC_EVENT_EUTRA_STRUCT *event, uint32_t tti, + bool enter_condition, bool exit_condition, + meas_t *m, meas_value_t *cell); + + void generate_report(uint32_t meas_id); + }; + + rrc_meas measurements; + + // RLC interface void max_retx_attempted(); diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc index f8d10bb34..66adb5b0b 100644 --- a/srsue/src/mac/mac.cc +++ b/srsue/src/mac/mac.cc @@ -180,6 +180,8 @@ void mac::run_thread() { ra_procedure.start_mac_order(); } ra_procedure.step(tti); + + rrc_h->run_tti(tti); } } diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 92745edb8..0cd31a3d6 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -398,7 +398,6 @@ int main(int argc, char *argv[]) pthread_t input; pthread_create(&input, NULL, &input_loop, &args); - bool scell_done = false; bool plot_started = false; bool signals_pregenerated = false; @@ -408,10 +407,6 @@ int main(int argc, char *argv[]) ue->pregenerate_signals(true); signals_pregenerated = true; } - if (!scell_done) { - ((srsue::ue*) ue)->test_scell(); - scell_done = true; - } if (!plot_started && args.gui.enable) { ue->start_plot(); plot_started = true; diff --git a/srsue/src/phy/phch_common.cc b/srsue/src/phy/phch_common.cc index d956ddd15..416f146ac 100644 --- a/srsue/src/phy/phch_common.cc +++ b/srsue/src/phy/phch_common.cc @@ -59,6 +59,9 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) rx_gain_offset = 0; sr_last_tx_tti = -1; cur_pusch_power = 0; + + serving_cell_report_period = 20; + bzero(zeros, 50000*sizeof(cf_t)); // FIXME: This is an ungly fix to avoid the TX filters to empty diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 91d2cd482..126c4a2f6 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -25,11 +25,10 @@ */ #include -#include +#include #include "srslte/srslte.h" #include "srslte/common/log.h" #include "phy/phch_worker.h" -#include "phy/phch_common.h" #include "phy/phch_recv.h" #define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) @@ -41,13 +40,8 @@ namespace srsue { int radio_recv_callback(void *obj, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) { return ((phch_recv*) obj)->radio_recv_fnc(data, nsamples, rx_time); - } -int scell_recv_callback(void *obj, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) { - return ((phch_recv*) obj)->scell_recv_fnc(data, nsamples, rx_time); -} - double callback_set_rx_gain(void *h, double gain) { srslte::radio_multi *radio_handler = (srslte::radio_multi *) h; return radio_handler->set_rx_gain_th(gain); @@ -94,10 +88,10 @@ void phch_recv::init(srslte::radio_multi *_radio_handler, mac_interface_phy *_ma sfn_p.init(&ue_sync, sf_buffer, log_h); // Initialize measurement class for the primary cell - measure_p.init(&ue_sync, sf_buffer, log_h, nof_rx_antennas); + measure_p.init(sf_buffer, log_h, nof_rx_antennas); - // Start scell - scell.init(this, log_h, nof_rx_antennas_, prio-1, sync_cpu_affinity); + // Start intra-frequency measurement + intra_freq_meas.init(worker_com, rrc, log_h); reset(); @@ -120,7 +114,7 @@ phch_recv::~phch_recv() { void phch_recv::stop() { - + intra_freq_meas.stop(); running = false; wait_thread_finish(); } @@ -223,6 +217,7 @@ bool phch_recv::set_cell() { measure_p.set_cell(cell); sfn_p.set_cell(cell); worker_com->set_cell(cell); + intra_freq_meas.set_primay_cell(current_earfcn, cell); for (uint32_t i = 0; i < workers_pool->get_nof_workers(); i++) { if (!((phch_worker *) workers_pool->get_worker(i))->set_cell(cell)) { @@ -464,10 +459,13 @@ bool phch_recv::status_is_sync() { return phy_state == CELL_CAMP; } -void phch_recv::get_current_cell(srslte_cell_t *cell_) { +void phch_recv::get_current_cell(srslte_cell_t *cell_, uint32_t *earfcn) { if (cell_) { memcpy(cell_, &cell, sizeof(srslte_cell_t)); } + if (earfcn) { + *earfcn = current_earfcn; + } } int phch_recv::radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) @@ -480,10 +478,6 @@ int phch_recv::radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, s next_offset = nsamples; } - if (offset <= 0) { - scell.write(data, nsamples, rx_time); - } - log_h->debug("SYNC: received %d samples from radio\n", nsamples); return nsamples; @@ -492,19 +486,6 @@ int phch_recv::radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, s } } -int phch_recv::scell_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) -{ - return scell.recv(data, nsamples, rx_time); -} - -void phch_recv::scell_enable(bool enable) -{ - srslte_cell_t target_cell; - memcpy(&target_cell, &cell, sizeof(srslte_cell_t)); - target_cell.id++; - scell.set_cell(target_cell); -} - @@ -587,7 +568,7 @@ void phch_recv::run_thread() } break; case CELL_MEASURE: - switch(measure_p.run_subframe(sf_idx)) + switch(measure_p.run_subframe_sync(&ue_sync, sf_idx)) { case measure::MEASURE_OK: log_h->info("SYNC: Measured OK. Camping on cell PCI=%d...\n", cell.id); @@ -643,6 +624,9 @@ void phch_recv::run_thread() worker_com->cur_radio_power = SRSLTE_MIN(SRSLTE_PC_MAX, worker_com->pathloss+worker_com->p0_preamble); } workers_pool->start_worker(worker); + + intra_freq_meas.write(tti, buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb)); + break; case 0: log_h->error("SYNC: Sync error. Sending out-of-sync to RRC\n"); @@ -789,8 +773,8 @@ phch_recv::search::ret_code phch_recv::search::run(srslte_cell_t *cell) return CELL_NOT_FOUND; } // Save result - cell->id = found_cells[max_peak_cell].cell_id; - cell->cp = found_cells[max_peak_cell].cp; + cell->id = found_cells[max_peak_cell].cell_id; + cell->cp = found_cells[max_peak_cell].cp; float cfo = found_cells[max_peak_cell].cfo; printf("\n"); @@ -864,7 +848,7 @@ void phch_recv::sfn_sync::init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MA this->buffer[i] = buffer[i]; } - if (srslte_ue_mib_init(&ue_mib, SRSLTE_MAX_PRB)) { + if (srslte_ue_mib_init(&ue_mib, this->buffer, SRSLTE_MAX_PRB)) { Error("SYNC: Initiating UE MIB decoder\n"); } } @@ -885,7 +869,7 @@ void phch_recv::sfn_sync::reset() cnt = 0; } -phch_recv::sfn_sync::ret_code phch_recv::sfn_sync::run_subframe(srslte_cell_t *cell, uint32_t *tti_cnt) +phch_recv::sfn_sync::ret_code phch_recv::sfn_sync::run_subframe(srslte_cell_t *cell, uint32_t *tti_cnt, bool sfidx_only) { uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; @@ -899,10 +883,19 @@ phch_recv::sfn_sync::ret_code phch_recv::sfn_sync::run_subframe(srslte_cell_t *c if (ret == 1) { if (srslte_ue_sync_get_sfidx(ue_sync) == 0) { + + // Skip MIB decoding if we are only interested in subframe 0 + if (sfidx_only) { + if (tti_cnt) { + *tti_cnt = 0; + } + return SFX0_FOUND; + } + int sfn_offset = 0; Info("SYNC: Trying to decode MIB... SNR=%.1f dB\n", 10*log10(srslte_chest_dl_get_snr(&ue_mib.chest))); - int n = srslte_ue_mib_decode(&ue_mib, buffer[0], bch_payload, NULL, &sfn_offset); + int n = srslte_ue_mib_decode(&ue_mib, bch_payload, NULL, &sfn_offset); if (n < 0) { Error("SYNC: Error decoding MIB while synchronising SFN"); return ERROR; @@ -944,16 +937,15 @@ phch_recv::sfn_sync::ret_code phch_recv::sfn_sync::run_subframe(srslte_cell_t *c /********* * Measurement class */ -void phch_recv::measure::init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, uint32_t nof_subrames) +void phch_recv::measure::init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, uint32_t nof_subframes) { this->log_h = log_h; - this->nof_subframes = nof_subrames; - this->ue_sync = ue_sync; + this->nof_subframes = nof_subframes; for (int i=0;ibuffer[i] = buffer[i]; } - if (srslte_ue_dl_init(&ue_dl, SRSLTE_MAX_PRB, nof_rx_antennas)) { + if (srslte_ue_dl_init(&ue_dl, this->buffer, SRSLTE_MAX_PRB, nof_rx_antennas)) { Error("SYNC: Initiating ue_dl_measure\n"); return; } @@ -969,11 +961,11 @@ void phch_recv::measure::reset() { mean_rsrp = 0; mean_rsrq = 0; mean_snr = 0; - mean_cfo = 0; } void phch_recv::measure::set_cell(srslte_cell_t cell) { + current_prb = cell.nof_prb; if (srslte_ue_dl_set_cell(&ue_dl, cell)) { Error("SYNC: Setting cell: initiating ue_dl_measure\n"); } @@ -981,59 +973,75 @@ void phch_recv::measure::set_cell(srslte_cell_t cell) } float phch_recv::measure::rsrp() { - return 10*log10(mean_rsrp/1000); + return mean_rsrp; } float phch_recv::measure::rsrq() { - return 10*log10(mean_rsrq); + return mean_rsrq; } float phch_recv::measure::snr() { - return 10*log10(mean_snr); -} - -float phch_recv::measure::cfo() { - return mean_cfo; + return mean_snr; } -phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx) +phch_recv::measure::ret_code phch_recv::measure::run_subframe_sync(srslte_ue_sync_t *ue_sync, uint32_t sf_idx) { int sync_res = srslte_ue_sync_zerocopy_multi(ue_sync, buffer); if (sync_res == 1) { - uint32_t cfi = 0; - - if (srslte_ue_dl_decode_fft_estimate(&ue_dl, buffer, sf_idx, &cfi)) { - log_h->error("SYNC: Measuring RSRP: Estimating channel\n"); - return ERROR; - } + return run_subframe(sf_idx); + } else { + log_h->error("SYNC: Measuring RSRP: Sync error\n"); + return ERROR; + } - float rsrp = srslte_chest_dl_get_rsrp(&ue_dl.chest); - float rsrq = srslte_chest_dl_get_rsrq(&ue_dl.chest); - float snr = srslte_chest_dl_get_snr(&ue_dl.chest); - float cfo = srslte_ue_sync_get_cfo(ue_sync); + return IDLE; +} - mean_rsrp = SRSLTE_VEC_CMA(rsrp, mean_rsrp, cnt); - mean_rsrq = SRSLTE_VEC_CMA(rsrq, mean_rsrq, cnt); - mean_snr = SRSLTE_VEC_CMA(snr, mean_snr, cnt); - mean_cfo = SRSLTE_VEC_CMA(cfo, mean_cfo, cnt); - cnt++; +phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *input_buffer, + uint32_t sf_idx, + uint32_t nof_sf) +{ + uint32_t sf_len = SRSLTE_SF_LEN_PRB(current_prb); - log_h->info("SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n", - cnt, RSRP_MEASURE_NOF_FRAMES, sf_idx, - 10*log10(rsrp/1000), 10*log10(snr)); + ret_code ret = IDLE; - if (cnt >= nof_subframes) { - return MEASURE_OK; + for (uint32_t i=0;ierror("SYNC: Measuring RSRP: Sync error\n"); + } + return ret; +} + +phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx) +{ + uint32_t cfi = 0; + if (srslte_ue_dl_decode_fft_estimate(&ue_dl, buffer, sf_idx, &cfi)) { + log_h->error("SYNC: Measuring RSRP: Estimating channel\n"); return ERROR; } - return IDLE; -} + float rsrp = 10*log10(srslte_chest_dl_get_rsrp(&ue_dl.chest)) + 30; + float rsrq = 10*log10(srslte_chest_dl_get_rsrq(&ue_dl.chest)); + float snr = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)); + + mean_rsrp = SRSLTE_VEC_CMA(rsrp, mean_rsrp, cnt); + mean_rsrq = SRSLTE_VEC_CMA(rsrq, mean_rsrq, cnt); + mean_snr = SRSLTE_VEC_CMA(snr, mean_snr, cnt); + cnt++; + log_h->info("SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n", + cnt, nof_subframes, sf_idx, + rsrp, snr); + if (cnt >= nof_subframes) { + return MEASURE_OK; + } else { + return IDLE; + } +} @@ -1044,164 +1052,246 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx) * Secondary cell receiver */ -void phch_recv::scell_recv::init(phch_recv *parent, srslte::log *log_h, uint32_t nof_rx_antennas, uint32_t prio, int cpu_affinity) +void phch_recv::scell_recv::init(srslte::log *log_h) { - this->p = parent; this->log_h = log_h; - this->nof_rx_antennas = nof_rx_antennas; - // Create the ringbuffer for secondary cell reception - for (int i=0;irrc = rrc; + this->log_h = log_h; + this->common = common; + receive_enabled = false; + + // Start scell + scell.init(log_h); + + search_buffer = (cf_t*) srslte_vec_malloc(CAPTURE_LEN_SF*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB)*sizeof(cf_t)); + + if (srslte_ringbuffer_init(&ring_buffer, sizeof(cf_t)*50*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB))) { + return; + } + + running = true; + start(); } -void phch_recv::scell_recv::set_cell(srslte_cell_t scell) { - printf("SCELL: set scell to select, id=%d, prb=%d\n", scell.id, scell.nof_prb); +void phch_recv::intra_measure::stop() { + running = false; + tti_sync.increase(); + wait_thread_finish(); +} - memcpy(&cell, &scell, sizeof(srslte_cell_t)); +void phch_recv::intra_measure::set_primay_cell(uint32_t earfcn, srslte_cell_t cell) { + this->current_earfcn = earfcn; current_sflen = SRSLTE_SF_LEN_PRB(cell.nof_prb); - srslte_ue_sync_set_cell(&ue_sync, scell); - measure_p.set_cell(scell); - sfn_p.set_cell(scell); + memcpy(&this->primary_cell, &cell, sizeof(srslte_cell_t)); +} - scell_state = SCELL_SELECT; +void phch_recv::intra_measure::clear_cells() { + active_pci.clear(); + receive_enabled = false; } -bool phch_recv::scell_recv::is_enabled() -{ - return scell_state != IDLE; +void phch_recv::intra_measure::add_cell(int pci) { + if (std::find(active_pci.begin(), active_pci.end(), pci) == active_pci.end()) { + active_pci.push_back(pci); + receive_enabled = true; + Info("INTRA: Starting intra-frequency measurement for pci=%d\n", pci); + } else { + Warning("INTRA: Requested to start already existing intra-frequency measurement for PCI=%d\n", pci); + } } -int phch_recv::scell_recv::recv(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) -{ - if (is_enabled()) - { - uint32_t read_samples = nsamples; - if (read_samples > current_sflen) { - read_samples = current_sflen; - } - if (nsamples < 10) { - read_samples = 0; - } - int n = 0; - for (uint32_t i=0;idebug("SCELL: tti=%d, read %d/%d samples from buffer, buffer size=%d\n", - tti, read_samples,nsamples, srslte_ringbuffer_status(&ring_buffer[0])); +void phch_recv::intra_measure::rem_cell(int pci) { + std::vector::iterator newEnd = std::remove(active_pci.begin(), active_pci.end(), pci); - return nsamples; + if (newEnd != active_pci.end()) { + active_pci.erase(newEnd, active_pci.end()); + if (active_pci.size() == 0) { + receive_enabled = false; + } + Info("INTRA: Stopping intra-frequency measurement for pci=%d. Number of cells: %d\n", pci, active_pci.size()); } else { - Error("SCELL: Reception not enabled\n"); - return -1; + Warning("INTRA: Requested to stop non-existing intra-frequency measurement for PCI=%d\n", pci); } } -void phch_recv::scell_recv::write(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) -{ - if (is_enabled()) { - for (uint32_t i = 0; i < nof_rx_antennas; i++) { - srslte_ringbuffer_write(&ring_buffer[i], data[i], sizeof(cf_t) * nsamples); +void phch_recv::intra_measure::write(uint32_t tti, cf_t *data, uint32_t nsamples) { + if (receive_enabled) { + if ((tti%INTRA_FREQ_MEAS_PERIOD_MS) == 0) { + receiving = true; + receive_cnt = 0; + measure_tti = tti; + } + if (receiving == true) { + if (srslte_ringbuffer_write(&ring_buffer, data, nsamples*sizeof(cf_t)) < (int) (nsamples*sizeof(cf_t))) { + receiving = false; + srslte_ringbuffer_reset(&ring_buffer); + } else { + receive_cnt++; + if (receive_cnt == CAPTURE_LEN_SF) { + tti_sync.increase(); + } + } } + } } -void phch_recv::scell_recv::run_thread() +void phch_recv::intra_measure::run_thread() { while(running) { - switch(scell_state) { - case IDLE: - usleep(1000); - break; - case SCELL_SELECT: + if (running) { + tti_sync.wait(); + } - switch (sfn_p.run_subframe(&cell, &tti)) - { - case sfn_sync::SFN_FOUND: - log_h->info("SCELL: SFN Sync OK. Camping on cell PCI=%d...\n", cell.id); - sfn_p.reset(); - scell_state = SCELL_MEASURE; - break; - case sfn_sync::TIMEOUT: - log_h->info("SCELL: SFN sync timeout\n"); - break; - case sfn_sync::IDLE: - break; - default: - p->radio_error(); - break; - } + if (running) { + Info("INTRA: Running intra-frequency measurement for %d cells\n", active_pci.size()); - break; - case SCELL_MEASURE: - switch (measure_p.run_subframe(tti%10)) { - case measure::MEASURE_OK: - log_h->info("SCELL: Measured OK TTI=%5d, RSRP=%.1f dBm, RSRQ=%.1f dB, SNR=%3.1f dB, CFO=%.1f KHz, Buff=%d\n", - tti, measure_p.rsrp(), measure_p.rsrq(), measure_p.snr(), measure_p.cfo()/1000, - srslte_ringbuffer_status(&ring_buffer[0])); - measure_p.reset(); - break; - case measure::IDLE: - break; - default: - p->radio_error(); - break; - } - break; + // Read 5 ms data from buffer + srslte_ringbuffer_read(&ring_buffer, search_buffer, CAPTURE_LEN_SF*current_sflen*sizeof(cf_t)); + int found_cells = scell.find_cells(search_buffer, primary_cell, CAPTURE_LEN_SF, info); + receiving = false; + srslte_ringbuffer_reset(&ring_buffer); + + for (int i=0;irx_gain_offset; + rrc->new_phy_meas(info[i].rsrp, info[i].rsrq, measure_tti, current_earfcn, info[i].pci); + } + // Look for other cells not found automatically } - // Increase TTI counter - tti = (tti+1) % 10240; } } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index cf0eab94c..5d93d94a4 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -1210,8 +1210,8 @@ void phch_worker::update_measurements() { float snr_ema_coeff = phy->args->snr_ema_coeff; if (chest_done) { - /* Compute ADC/RX gain offset every 20 ms */ - if ((tti%20) == 0 || phy->rx_gain_offset == 0) { + /* Compute ADC/RX gain offset every ~10s */ + if (tti== 0 || phy->rx_gain_offset == 0) { float rx_gain_offset = 0; if (phy->get_radio()->has_rssi() && phy->args->rssi_sensor_enabled) { float rssi_all_signal = srslte_chest_dl_get_rssi(&ue_dl.chest); @@ -1224,7 +1224,7 @@ void phch_worker::update_measurements() rx_gain_offset = phy->get_radio()->get_rx_gain(); } if (phy->rx_gain_offset) { - phy->rx_gain_offset = SRSLTE_VEC_EMA(phy->rx_gain_offset, rx_gain_offset, 0.1); + phy->rx_gain_offset = SRSLTE_VEC_EMA(phy->rx_gain_offset, rx_gain_offset, 0.5); } else { phy->rx_gain_offset = rx_gain_offset; } @@ -1246,15 +1246,16 @@ void phch_worker::update_measurements() float rsrp = 10*log10(srslte_chest_dl_get_rsrp(&ue_dl.chest)) + 30 - phy->rx_gain_offset; float rssi = 10*log10(srslte_chest_dl_get_rssi(&ue_dl.chest)) + 30 - phy->rx_gain_offset; - // TODO: Send UE measurements to RRC where filtering is done. Now do filtering here + // Serving cell measurements are averaged over DEFAULT_MEAS_PERIOD_MS then sent to RRC if (isnormal(rsrp)) { if (!phy->avg_rsrp_db) { phy->avg_rsrp_db = rsrp; } else { - uint32_t k = 4; // Set by RRC reconfiguration message - float coeff = pow(0.5,(float) k/4); - phy->avg_rsrp_db = SRSLTE_VEC_EMA(phy->avg_rsrp_db, rsrp, coeff); + phy->avg_rsrp_db = SRSLTE_VEC_EMA(phy->avg_rsrp_db, rsrp, 0.8); } + if ((tti%phy->serving_cell_report_period) == 0) { + phy->rrc->new_phy_meas(phy->avg_rsrp_db, phy->avg_rsrq_db, tti); + } } // Compute PL float tx_crs_power = phy->config->common.pdsch_cnfg.rs_power; diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index 2c140c191..7d3b8f311 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -243,15 +243,22 @@ void phy::cell_search_next() sf_recv.cell_search_next(); } -void phy::scell_enable(bool enable) -{ - sf_recv.scell_enable(enable); -} - void phy::sync_reset() { sf_recv.reset_sync(); } +void phy::meas_reset() { + sf_recv.meas_reset(); +} + +int phy::meas_start(uint32_t earfcn, int pci) { + return sf_recv.meas_start(earfcn, pci); +} + +int phy::meas_stop(uint32_t earfcn, int pci) { + return sf_recv.meas_stop(earfcn, pci); +} + bool phy::cell_select(uint32_t earfcn, srslte_cell_t phy_cell) { return sf_recv.cell_select(earfcn, phy_cell); @@ -288,9 +295,9 @@ void phy::pdcch_ul_search_reset() workers_common.set_ul_rnti(SRSLTE_RNTI_USER, 0); } -void phy::get_current_cell(srslte_cell_t *cell) +void phy::get_current_cell(srslte_cell_t *cell, uint32_t *current_earfcn) { - sf_recv.get_current_cell(cell); + sf_recv.get_current_cell(cell, current_earfcn); } void phy::prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm) diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index c97958316..a99281e6f 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -215,11 +215,6 @@ void ue::pregenerate_signals(bool enable) phy.enable_pregen_signals(enable); } -void ue::test_scell() -{ - phy.scell_enable(true); -}; - void ue::stop() { if(started) diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 10373dcf2..434f931f3 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -109,6 +109,8 @@ void rrc::init(phy_interface_rrc *phy_, set_rrc_default(); set_phy_default(); set_mac_default(); + + measurements.init(this); } void rrc::stop() { @@ -116,6 +118,10 @@ void rrc::stop() { wait_thread_finish(); } +void rrc::run_tti(uint32_t tti) { + measurements.run_tti(tti); +} + rrc_state_t rrc::get_state() { return state; } @@ -418,6 +424,10 @@ void rrc::select_next_cell_in_plmn() { rrc_log->info("No more known cells...\n"); } +void rrc::new_phy_meas(float rsrp, float rsrq, uint32_t tti, uint32_t earfcn, uint32_t pci) { + measurements.new_phy_meas(earfcn, pci, rsrp, rsrq, tti); +} + void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { // find if cell_id-earfcn combination already exists @@ -562,7 +572,8 @@ void rrc::timer_expired(uint32_t timeout_id) { } else if (timeout_id == t301) { rrc_log->info("Timer T301 expired: Going to RRC IDLE\n"); state = RRC_STATE_LEAVE_CONNECTED; - } else { + // fw to measurement + } else if (!measurements.timer_expired(timeout_id)) { rrc_log->error("Timeout from unknown timer id %d\n", timeout_id); } } @@ -717,32 +728,22 @@ void rrc::con_restablish_cell_reselected() void rrc::send_con_restablish_complete() { rrc_log->debug("Preparing RRC Connection Reestablishment Complete\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + + rrc_log->console("RRC Connected\n"); + state = RRC_STATE_CONNECTED; // Prepare ConnectionSetupComplete packet ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_REEST_COMPLETE; ul_dcch_msg.msg.rrc_con_reest_complete.rrc_transaction_id = transaction_id; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - byte_buffer_t *pdcp_buf = pool_allocate;; - srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); - pdcp_buf->N_bytes = bit_buf.N_bits / 8; - - state = RRC_STATE_CONNECTED; - rrc_log->console("RRC Connected\n"); - rrc_log->info("Sending RRC Connection Reestablishment Complete\n"); - pdcp->write_sdu(RB_ID_SRB1, pdcp_buf); + send_ul_dcch_msg(); } void rrc::send_con_setup_complete(byte_buffer_t *nas_msg) { rrc_log->debug("Preparing RRC Connection Setup Complete\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + + state = RRC_STATE_CONNECTED; + rrc_log->console("RRC Connected\n"); // Prepare ConnectionSetupComplete packet ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_SETUP_COMPLETE; @@ -751,96 +752,38 @@ void rrc::send_con_setup_complete(byte_buffer_t *nas_msg) { ul_dcch_msg.msg.rrc_con_setup_complete.selected_plmn_id = 1; memcpy(ul_dcch_msg.msg.rrc_con_setup_complete.dedicated_info_nas.msg, nas_msg->msg, nas_msg->N_bytes); ul_dcch_msg.msg.rrc_con_setup_complete.dedicated_info_nas.N_bytes = nas_msg->N_bytes; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - byte_buffer_t *pdcp_buf = pool_allocate;; - srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); - pdcp_buf->N_bytes = bit_buf.N_bits / 8; - pdcp_buf->set_timestamp(); - - state = RRC_STATE_CONNECTED; - rrc_log->console("RRC Connected\n"); - rrc_log->info("Sending RRC Connection Setup Complete\n"); - pdcp->write_sdu(RB_ID_SRB1, pdcp_buf); + send_ul_dcch_msg(); } void rrc::send_ul_info_transfer(uint32_t lcid, byte_buffer_t *sdu) { rrc_log->debug("Preparing RX Info Transfer\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; // Prepare RX INFO packet ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_UL_INFO_TRANSFER; ul_dcch_msg.msg.ul_info_transfer.dedicated_info_type = LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_NAS; memcpy(ul_dcch_msg.msg.ul_info_transfer.dedicated_info.msg, sdu->msg, sdu->N_bytes); ul_dcch_msg.msg.ul_info_transfer.dedicated_info.N_bytes = sdu->N_bytes; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - - // Reset and reuse sdu buffer - byte_buffer_t *pdu = sdu; - pdu->reset(); - - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); - pdu->N_bytes = bit_buf.N_bits / 8; - pdu->set_timestamp(); - pdu->set_timestamp(); - rrc_log->info("Sending RX Info Transfer\n"); - pdcp->write_sdu(lcid, pdu); + send_ul_dcch_msg(sdu); } void rrc::send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu) { rrc_log->debug("Preparing Security Mode Complete\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_SECURITY_MODE_COMPLETE; ul_dcch_msg.msg.security_mode_complete.rrc_transaction_id = transaction_id; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); - pdu->N_bytes = bit_buf.N_bits / 8; - pdu->set_timestamp(); - - rrc_log->info("Sending Security Mode Complete\n"); - pdcp->write_sdu(lcid, pdu); + send_ul_dcch_msg(pdu); } void rrc::send_rrc_con_reconfig_complete(uint32_t lcid, byte_buffer_t *pdu) { rrc_log->debug("Preparing RRC Connection Reconfig Complete\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_RECONFIG_COMPLETE; ul_dcch_msg.msg.rrc_con_reconfig_complete.rrc_transaction_id = transaction_id; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); - pdu->N_bytes = bit_buf.N_bits / 8; - pdu->set_timestamp(); - - rrc_log->info("Sending RRC Connection Reconfig Complete\n"); - pdcp->write_sdu(lcid, pdu); + send_ul_dcch_msg(); } @@ -854,7 +797,7 @@ void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGU printf("received con reconfig no rr confg present\n"); } if (reconfig->meas_cnfg_present) { - //TODO: handle meas_cnfg + measurements.parse_meas_config(&reconfig->meas_cnfg); } if (reconfig->mob_ctrl_info_present) { //TODO: handle mob_ctrl_info @@ -864,7 +807,7 @@ void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGU byte_buffer_t *nas_sdu; for (i = 0; i < reconfig->N_ded_info_nas; i++) { - nas_sdu = pool_allocate;; + nas_sdu = pool_allocate; memcpy(nas_sdu->msg, &reconfig->ded_info_nas_list[i].msg, reconfig->ded_info_nas_list[i].N_bytes); nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes; nas->write_pdu(lcid, nas_sdu); @@ -1051,6 +994,33 @@ void rrc::write_pdu_pcch(byte_buffer_t *pdu) { * * *******************************************************************************/ +void rrc::send_ul_dcch_msg(byte_buffer_t *pdu) +{ + liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); + + // Byte align and pack the message bits for PDCP + if ((bit_buf.N_bits % 8) != 0) { + for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) + bit_buf.msg[bit_buf.N_bits + i] = 0; + bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); + } + // Reset and reuse sdu buffer if provided + byte_buffer_t *pdcp_buf = pdu; + + if (pdcp_buf) { + pdcp_buf->reset(); + } else { + pdcp_buf = pool_allocate; + } + + srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); + pdcp_buf->N_bytes = bit_buf.N_bits / 8; + pdcp_buf->set_timestamp(); + + rrc_log->info("Sending %s\n", liblte_rrc_ul_dcch_msg_type_text[ul_dcch_msg.msg_type]); + pdcp->write_sdu(RB_ID_SRB1, pdcp_buf); +} + void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { rrc_log->info_hex(sdu->msg, sdu->N_bytes, "RX %s SDU", get_rb_name(lcid).c_str()); switch (state) { @@ -1764,4 +1734,582 @@ void rrc::set_rrc_default() { } + + + + + + + + + + + + + + + + + +/************************************************************************ + * + * + * RRC Measurements + * + * + ************************************************************************/ + +void rrc::rrc_meas::init(rrc *parent) { + this->parent = parent; + this->log_h = parent->rrc_log; + this->phy = parent->phy; + this->mac_timers = parent->mac_timers; + s_measure_enabled = false; + reset(); +} + +void rrc::rrc_meas::reset() +{ + bzero(&pcell_measurement, sizeof(meas_value_t)); + filter_k_rsrp = liblte_rrc_filter_coefficient_num[LIBLTE_RRC_FILTER_COEFFICIENT_FC4]; + filter_k_rsrq = liblte_rrc_filter_coefficient_num[LIBLTE_RRC_FILTER_COEFFICIENT_FC4]; + objects.clear(); + active.clear(); + reports_cfg.clear(); + phy->meas_reset(); +} + +/* L3 filtering 5.5.3.2 */ +void rrc::rrc_meas::L3_filter(meas_value_t *value, float values[NOF_MEASUREMENTS]) +{ + for (int i=0;ims[i]) { + value->ms[i] = SRSLTE_VEC_EMA(values[i], value->ms[i], filter_a[i]); + } else { + value->ms[i] = values[i]; + } + } +} + +void rrc::rrc_meas::new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, float rsrq, uint32_t tti) +{ + log_h->info("MEAS: New measurement earfcn=%d, pci=%d, rsrp=%f, rsrq=%f, tti=%d\n", earfcn, pci, rsrp, rsrq, tti); + + float values[NOF_MEASUREMENTS] = {rsrp, rsrq}; + // This indicates serving cell + if (earfcn == 0) { + L3_filter(&pcell_measurement, values); + } else { + // Save PHY measurement for all active measurements whose earfcn/pci matches + for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { + meas_t *m = &iter->second; + if (objects[m->object_id].earfcn == earfcn) { + // If it's a newly discovered cell, add it to objects + if (!m->cell_values.count(pci)) { + uint32_t cell_idx = objects[m->object_id].cells.size(); + objects[m->object_id].cells[cell_idx].pci = pci; + objects[m->object_id].cells[cell_idx].q_offset = 0; + } + // Update or add cell + L3_filter(&m->cell_values[pci], values); + return; + } + } + parent->rrc_log->warning("MEAS: Received measurement from unknown EARFCN=%d\n", earfcn); + } +} + +void rrc::rrc_meas::run_tti(uint32_t tti) { + // Measurement Report Triggering Section 5.5.4 + calculate_triggers(tti); +} + +bool rrc::rrc_meas::find_earfcn_cell(uint32_t earfcn, uint32_t pci, meas_obj_t **object, int *cell_idx) { + if (object) { + *object = NULL; + } + for (std::map::iterator obj = objects.begin(); obj != objects.end(); ++obj) { + if (obj->second.earfcn == earfcn) { + if (object) { + *object = &obj->second; + } + for (std::map::iterator c = obj->second.cells.begin(); c != obj->second.cells.end(); ++c) { + if (c->second.pci == pci) { + if (cell_idx) { + *cell_idx = c->first; + return true; + } + } + } + // return true if cell idx not found but frequency is found + if (cell_idx) { + *cell_idx = -1; + } + return true; + } + } + return false; +} + +/* Generate report procedure 5.5.5 */ +void rrc::rrc_meas::generate_report(uint32_t meas_id) +{ + parent->ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_MEASUREMENT_REPORT; + LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *report = &parent->ul_dcch_msg.msg.measurement_report; + + bzero(report, sizeof(LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT)); + + meas_t *m = &active[meas_id]; + report_cfg_t *cfg = &reports_cfg[m->report_id]; + + report->meas_id = meas_id; + report->pcell_rsrp_result = value_to_range(RSRP, pcell_measurement.ms[RSRP]); + report->pcell_rsrq_result = value_to_range(RSRQ, pcell_measurement.ms[RSRQ]); + + log_h->console("MEAS: Generate report MeasId=%d, rsrp=%f rsrq=%f\n", + report->meas_id, pcell_measurement.ms[RSRP], pcell_measurement.ms[RSRQ]); + + // TODO: report up to 8 best cells + for (std::map::iterator cell = m->cell_values.begin(); cell != m->cell_values.end(); ++cell) + { + if (cell->second.triggered && report->meas_result_neigh_cells.eutra.n_result < 8) + { + LIBLTE_RRC_MEAS_RESULT_EUTRA_STRUCT *rc = &report->meas_result_neigh_cells.eutra.result_eutra_list[report->meas_result_neigh_cells.eutra.n_result]; + + rc->phys_cell_id = cell->first; + rc->meas_result.have_rsrp = cfg->report_quantity==RSRP || cfg->report_quantity==BOTH; + rc->meas_result.have_rsrq = cfg->report_quantity==RSRQ || cfg->report_quantity==BOTH; + rc->meas_result.rsrp_result = value_to_range(RSRP, cell->second.ms[RSRP]); + rc->meas_result.rsrq_result = value_to_range(RSRQ, cell->second.ms[RSRQ]); + + log_h->console("MEAS: Add neigh=%d, pci=%d, rsrp=%f, rsrq=%f\n", + report->meas_result_neigh_cells.eutra.n_result, rc->phys_cell_id, + cell->second.ms[RSRP], cell->second.ms[RSRQ]); + + report->meas_result_neigh_cells.eutra.n_result++; + } + } + report->have_meas_result_neigh_cells = report->meas_result_neigh_cells.eutra.n_result > 0; + + m->nof_reports_sent++; + mac_timers->timer_get(m->periodic_timer)->stop(); + + if (m->nof_reports_sent < cfg->amount) { + mac_timers->timer_get(m->periodic_timer)->reset(); + mac_timers->timer_get(m->periodic_timer)->run(); + } else { + if (cfg->trigger_type == report_cfg_t::PERIODIC) { + m->triggered = false; + } + } + + // Send to lower layers + parent->send_ul_dcch_msg(); +} + +/* Handle entering/leaving event conditions 5.5.4.1 */ +bool rrc::rrc_meas::process_event(LIBLTE_RRC_EVENT_EUTRA_STRUCT *event, uint32_t tti, + bool enter_condition, bool exit_condition, + meas_t *m, meas_value_t *cell) +{ + bool generate_report = false; + if (enter_condition && (!m->triggered || !cell->triggered)) { + if (!cell->timer_enter_triggered) { + cell->timer_enter_triggered = true; + cell->enter_tti = tti; + } else if (srslte_tti_interval(tti, cell->enter_tti) >= event->time_to_trigger) { + m->triggered = true; + cell->triggered = true; + m->nof_reports_sent = 0; + generate_report = true; + } + } else if (exit_condition) { + if (!cell->timer_exit_triggered) { + cell->timer_exit_triggered = true; + cell->exit_tti = tti; + } else if (srslte_tti_interval(tti, cell->exit_tti) >= event->time_to_trigger) { + m->triggered = false; + cell->triggered = false; + mac_timers->timer_get(m->periodic_timer)->stop(); + if (event) { + if (event->event_id == LIBLTE_RRC_EVENT_ID_EUTRA_A3 && event->event_a3.report_on_leave) { + generate_report = true; + } + } + } + } + if (!enter_condition) { + cell->timer_enter_triggered = false; + } + if (!enter_condition) { + cell->timer_exit_triggered = false; + } + return generate_report; +} + +/* Calculate trigger conditions for each cell 5.5.4 */ +void rrc::rrc_meas::calculate_triggers(uint32_t tti) +{ + float Ofp = 0, Ocp = 0; + meas_obj_t *serving_object = NULL; + int serving_cell_idx = 0; + + // Get serving cell + if (active.size()) { + uint32_t current_earfcn = 0; + srslte_cell_t current_cell; + phy->get_current_cell(¤t_cell, ¤t_earfcn); + if (find_earfcn_cell(current_earfcn, current_cell.id, &serving_object, &serving_cell_idx)) { + Ofp = serving_object->q_offset; + if (serving_cell_idx >= 0) { + Ocp = serving_object->cells[serving_cell_idx].q_offset; + } + } else { + log_h->warning("Can't find current eafcn=%d, pci=%d in objects list. Using Ofp=0, Ocp=0\n", current_earfcn, current_cell.id); + } + } + + for (std::map::iterator m = active.begin(); m != active.end(); ++m) { + report_cfg_t *cfg = &reports_cfg[m->second.report_id]; + float hyst = 0.5*cfg->event.hysteresis; + float Mp = pcell_measurement.ms[cfg->trigger_quantity]; + + LIBLTE_RRC_EVENT_ID_EUTRA_ENUM event_id = cfg->event.event_id; + const char *event_str = liblte_rrc_event_id_eutra_text[event_id]; + + bool gen_report = false; + + if (cfg->trigger_type == report_cfg_t::EVENT) { + + // A1 & A2 are for serving cell only + if (event_id < LIBLTE_RRC_EVENT_ID_EUTRA_A3) { + + bool enter_condition; + bool exit_condition; + if (event_id == LIBLTE_RRC_EVENT_ID_EUTRA_A1) { + enter_condition = Mp - hyst > range_to_value(cfg->trigger_quantity, cfg->event.event_a1.eutra.range); + exit_condition = Mp + hyst < range_to_value(cfg->trigger_quantity, cfg->event.event_a1.eutra.range); + } else { + enter_condition = Mp + hyst < range_to_value(cfg->trigger_quantity, cfg->event.event_a1.eutra.range); + exit_condition = Mp - hyst > range_to_value(cfg->trigger_quantity, cfg->event.event_a1.eutra.range); + } + gen_report |= process_event(&cfg->event, tti, enter_condition, exit_condition, + &m->second, &m->second.cell_values[serving_cell_idx]); + + // Rest are evaluated for every cell in frequency + } else { + meas_obj_t *obj = &objects[m->second.object_id]; + for (std::map::iterator cell = obj->cells.begin(); cell != obj->cells.end(); ++cell) { + float Ofn = obj->q_offset; + float Ocn = cell->second.q_offset; + float Mn = m->second.cell_values[cell->second.pci].ms[cfg->trigger_quantity]; + float Off=0, th=0, th1=0, th2=0; + bool enter_condition = false; + bool exit_condition = false; + switch (event_id) { + case LIBLTE_RRC_EVENT_ID_EUTRA_A3: + Off = 0.5*cfg->event.event_a3.offset; + enter_condition = Mn + Ofn + Ocn - hyst > Mp + Ofp + Ocp + Off; + exit_condition = Mn + Ofn + Ocn + hyst < Mp + Ofp + Ocp + Off; + break; + case LIBLTE_RRC_EVENT_ID_EUTRA_A4: + th = range_to_value(cfg->trigger_quantity, cfg->event.event_a4.eutra.range); + enter_condition = Mn + Ofn + Ocn - hyst > th; + exit_condition = Mn + Ofn + Ocn + hyst < th; + break; + case LIBLTE_RRC_EVENT_ID_EUTRA_A5: + th1 = range_to_value(cfg->trigger_quantity, cfg->event.event_a5.eutra1.range); + th2 = range_to_value(cfg->trigger_quantity, cfg->event.event_a5.eutra2.range); + enter_condition = (Mp + hyst < th1) && (Mn + Ofn + Ocn - hyst > th2); + exit_condition = (Mp - hyst > th1) && (Mn + Ofn + Ocn + hyst < th2); + break; + default: + log_h->error("Error event %s not implemented\n", event_str); + } + gen_report |= process_event(&cfg->event, tti, enter_condition, exit_condition, + &m->second, &m->second.cell_values[cell->second.pci]); + } + } + } + if (gen_report) { + generate_report(m->first); + } + } +} + +// 5.5.4.1 expiry of periodical reporting timer +bool rrc::rrc_meas::timer_expired(uint32_t timer_id) { + for (std::map::iterator iter = active.begin(); iter != active.end(); ++iter) { + if (iter->second.periodic_timer == timer_id) { + generate_report(iter->first); + return true; + } + } + return false; +} + +void rrc::rrc_meas::stop_reports_object(uint32_t object_id) { + for (std::map::iterator iter = active.begin(); iter != active.end(); ++iter) { + meas_t *m = &iter->second; + if (m->object_id == object_id) { + mac_timers->timer_get(m->periodic_timer)->stop(); + m->triggered = false; + } + } +} + +void rrc::rrc_meas::remove_meas_object(uint32_t object_id) { + // CHECKME: Is the delete from the map correct? + for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { + meas_t m = iter->second; + if (m.object_id == object_id) { + remove_meas_id(iter->first); + } + } +} + +void rrc::rrc_meas::remove_meas_report(uint32_t report_id) { + // CHECKME: Is the delete from the map correct? + for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { + meas_t m = iter->second; + if (m.report_id == report_id) { + remove_meas_id(iter->first); + } + } +} + +void rrc::rrc_meas::remove_meas_id(uint32_t meas_id) { + mac_timers->timer_get(active[meas_id].periodic_timer)->stop(); + mac_timers->timer_release_id(active[meas_id].periodic_timer); + active.erase(meas_id); + log_h->info("MEAS: Removed measId=%d\n", meas_id); +} + +/* Parses MeasConfig object from RRCConnectionReconfiguration message and applies configuration + * as per section 5.5.2 + */ +void rrc::rrc_meas::parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *cfg) +{ + + // Measurement identity removal 5.5.2.2 + for (uint32_t i=0;iN_meas_id_to_remove;i++) { + remove_meas_id(cfg->meas_id_to_remove_list[i]); + } + + // Measurement identity addition/modification 5.5.2.3 + if (cfg->meas_id_to_add_mod_list_present) { + for (uint32_t i=0;imeas_id_to_add_mod_list.N_meas_id;i++) { + LIBLTE_RRC_MEAS_ID_TO_ADD_MOD_STRUCT *measId = &cfg->meas_id_to_add_mod_list.meas_id_list[i]; + // Stop the timer if the entry exists or create the timer if not + if (active.count(measId->meas_id)) { + mac_timers->timer_get(active[measId->meas_id].periodic_timer)->stop(); + } else { + active[measId->meas_id].periodic_timer = mac_timers->timer_get_unique_id(); + } + active[measId->meas_id].object_id = measId->meas_obj_id; + active[measId->meas_id].report_id = measId->rep_cnfg_id; + log_h->info("MEAS: Added measId=%d, measObjectId=%d, reportConfigId=%d\n", + measId->meas_id, measId->meas_obj_id, measId->rep_cnfg_id); + } + } + + // Measurement object removal 5.5.2.4 + for (uint32_t i=0;iN_meas_obj_to_remove;i++) { + objects.erase(cfg->meas_obj_to_remove_list[i]); + remove_meas_object(cfg->meas_obj_to_remove_list[i]); + log_h->info("MEAS: Removed measObjectId=%d\n", cfg->meas_obj_to_remove_list[i]); + } + + // Measurement object addition/modification Section 5.5.2.5 + if (cfg->meas_obj_to_add_mod_list_present) { + for (uint32_t i=0;imeas_obj_to_add_mod_list.N_meas_obj;i++) { + if (cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_type == LIBLTE_RRC_MEAS_OBJECT_TYPE_EUTRA) { + LIBLTE_RRC_MEAS_OBJECT_EUTRA_STRUCT *src_obj = &cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_eutra; + + // Access the object if exists or create it + meas_obj_t *dst_obj = &objects[cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_id]; + + dst_obj->earfcn = src_obj->carrier_freq;; + if (src_obj->offset_freq_not_default) { + dst_obj->q_offset = liblte_rrc_q_offset_range_num[src_obj->offset_freq]; + } else { + dst_obj->q_offset = 0; + } + + if (src_obj->black_cells_to_remove_list_present) { + for (uint32_t j=0;jblack_cells_to_remove_list.N_cell_idx;j++) { + dst_obj->cells.erase(src_obj->black_cells_to_remove_list.cell_idx[j]); + } + } + + for (uint32_t j=0;jN_cells_to_add_mod;j++) { + dst_obj->cells[src_obj->cells_to_add_mod_list[j].cell_idx].q_offset = liblte_rrc_q_offset_range_num[src_obj->cells_to_add_mod_list[j].cell_offset]; + dst_obj->cells[src_obj->cells_to_add_mod_list[j].cell_idx].pci = src_obj->cells_to_add_mod_list[j].pci; + + log_h->info("MEAS: Added measObjectId=%d, earfcn=%d, q_offset=%f, pci=%d, offset_cell=%f\n", + cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_id, dst_obj->earfcn, dst_obj->q_offset, + dst_obj->cells[src_obj->cells_to_add_mod_list[j].cell_idx].q_offset, + dst_obj->cells[src_obj->cells_to_add_mod_list[j].cell_idx].pci); + + } + + // Untrigger reports and stop timers + stop_reports_object(cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_id); + + // TODO: Blackcells + // TODO: meassubframepattern + + } else { + log_h->warning("MEAS: Unsupported MeasObject type %s\n", + liblte_rrc_meas_object_type_text[cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_type]); + } + } + } + + // Reporting configuration removal 5.5.2.6 + for (uint32_t i=0;iN_rep_cnfg_to_remove;i++) { + reports_cfg.erase(cfg->rep_cnfg_to_remove_list[i]); + remove_meas_report(cfg->rep_cnfg_to_remove_list[i]); + log_h->info("MEAS: Removed reportConfigId=%d\n", cfg->rep_cnfg_to_remove_list[i]); + } + + // Reporting configuration addition/modification 5.5.2.7 + if (cfg->rep_cnfg_to_add_mod_list_present) { + for (uint32_t i=0;irep_cnfg_to_add_mod_list.N_rep_cnfg;i++) { + if (cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_type == LIBLTE_RRC_REPORT_CONFIG_TYPE_EUTRA) { + LIBLTE_RRC_REPORT_CONFIG_EUTRA_STRUCT *src_rep = &cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_eutra; + // Access the object if exists or create it + report_cfg_t *dst_rep = &reports_cfg[cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_id]; + + dst_rep->trigger_type = src_rep->trigger_type==LIBLTE_RRC_TRIGGER_TYPE_EUTRA_EVENT?report_cfg_t::EVENT:report_cfg_t::PERIODIC; + dst_rep->event = src_rep->event; + dst_rep->amount = liblte_rrc_report_amount_num[src_rep->report_amount]; + dst_rep->interval = liblte_rrc_report_interval_num[src_rep->report_interval]; + dst_rep->max_cell = src_rep->max_report_cells; + dst_rep->trigger_quantity = (quantity_t) src_rep->trigger_quantity; + dst_rep->report_quantity = src_rep->report_quantity==LIBLTE_RRC_REPORT_QUANTITY_SAME_AS_TRIGGER_QUANTITY?dst_rep->trigger_quantity:BOTH; + + log_h->info("MEAS: Added reportConfigId=%d, event=%s, amount=%d, interval=%d\n", + cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_id, + liblte_rrc_event_id_eutra_text[dst_rep->event.event_id], + dst_rep->amount, dst_rep->interval); + + // Reset reports counter + for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { + meas_t m = iter->second; + if (m.report_id == cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_id) { + iter->second.nof_reports_sent = 0; + m.triggered = false; + mac_timers->timer_get(m.periodic_timer)->stop(); + } + } + } else { + log_h->warning("MEAS: Unsupported reportConfigType %s\n", liblte_rrc_report_config_type_text[cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_type]); + } + } + } + + // Quantity configuration 5.5.2.8 + if (cfg->quantity_cnfg_present && cfg->quantity_cnfg.qc_eutra_present) { + if (cfg->quantity_cnfg.qc_eutra.fc_rsrp_not_default) { + filter_k_rsrp = liblte_rrc_filter_coefficient_num[cfg->quantity_cnfg.qc_eutra.fc_rsrp]; + } else { + filter_k_rsrp = liblte_rrc_filter_coefficient_num[LIBLTE_RRC_FILTER_COEFFICIENT_FC4]; + } + if (cfg->quantity_cnfg.qc_eutra.fc_rsrq_not_default) { + filter_k_rsrq = liblte_rrc_filter_coefficient_num[cfg->quantity_cnfg.qc_eutra.fc_rsrq]; + } else { + filter_k_rsrq = liblte_rrc_filter_coefficient_num[LIBLTE_RRC_FILTER_COEFFICIENT_FC4]; + } + filter_a[RSRP] = pow(0.5, (float) filter_k_rsrp/4); + filter_a[RSRQ] = pow(0.5, (float) filter_k_rsrq/4); + + log_h->info("MEAS: Quantity configuration k_rsrp=%d, k_rsrq=%d\n", filter_k_rsrp, filter_k_rsrq); + } + + // S-Measure + if (cfg->s_meas_present) { + if (cfg->s_meas) { + s_measure_enabled = true; + s_measure_value = range_to_value(RSRP, cfg->s_meas); + } else { + s_measure_enabled = false; + } + } + + update_phy(); +} + +/* Instruct PHY to start measurement */ +void rrc::rrc_meas::update_phy() +{ + phy->meas_reset(); + if (pcell_measurement.ms[RSRP] < s_measure_value || !s_measure_enabled) { + for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { + meas_t m = iter->second; + meas_obj_t o = objects[m.object_id]; + // Instruct PHY to look for neighbour cells on this frequency + phy->meas_start(o.earfcn); + for(std::map::iterator iter=o.cells.begin(); iter!=o.cells.end(); ++iter) { + // Instruct PHY to look for cells IDs on this frequency + phy->meas_start(o.earfcn, iter->second.pci); + } + } + } +} + + +uint8_t rrc::rrc_meas::value_to_range(quantity_t quant, float value) { + uint8_t range = 0; + switch(quant) { + case RSRP: + if (value < -140) { + range = 0; + } else if (-140 <= value && value < -44) { + range = 1 + (uint8_t) (value + 140); + } else { + range = 97; + } + break; + case RSRQ: + if (value < -19.5) { + range = 0; + } else if (-19.5 <= value && value < -3) { + range = 1 + (uint8_t) (2*(value + 19.5)); + } else { + range = 34; + } + break; + case BOTH: + printf("Error quantity both not supported in value_to_range\n"); + break; + } + return range; +} + +float rrc::rrc_meas::range_to_value(quantity_t quant, uint8_t range) { + float val = 0; + switch(quant) { + case RSRP: + val = -140+(float) range; + break; + case RSRQ: + val = -19.5+(float) range/2; + break; + case BOTH: + printf("Error quantity both not supported in range_to_value\n"); + break; + } + return val; +} + + + + + + + + + + } // namespace srsue From 408545dab85a7089199fd6ca09c59d232cb318b4 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Thu, 23 Nov 2017 19:46:34 +0100 Subject: [PATCH 06/42] X2 (constant NCC) working --- lib/examples/cell_measurement.c | 2 +- lib/examples/cell_search.c | 2 +- lib/examples/pdsch_ue.c | 2 +- lib/examples/usrp_capture.c | 2 +- lib/examples/usrp_capture_sync.c | 2 +- lib/examples/usrp_txrx.c | 2 +- lib/include/srslte/asn1/liblte_rrc.h | 1 + lib/include/srslte/common/liblte_security.h | 5 + lib/include/srslte/common/mac_pcap.h | 11 +- lib/include/srslte/common/security.h | 5 + .../srslte/interfaces/enb_interfaces.h | 1 + lib/include/srslte/interfaces/ue_interfaces.h | 25 +- lib/include/srslte/phy/rf/rf.h | 2 +- lib/include/srslte/radio/radio.h | 2 +- lib/include/srslte/upper/pdcp.h | 1 + lib/include/srslte/upper/pdcp_entity.h | 3 +- lib/include/srslte/upper/rlc.h | 2 + lib/include/srslte/upper/rlc_am.h | 1 + lib/include/srslte/upper/rlc_entity.h | 1 + lib/src/common/liblte_security.cc | 37 ++ lib/src/common/mac_pcap.cc | 8 +- lib/src/common/security.cc | 11 + lib/src/phy/phch/test/prach_test_usrp.c | 2 +- lib/src/phy/rf/rf_blade_imp.c | 2 +- lib/src/phy/rf/rf_blade_imp.h | 2 +- lib/src/phy/rf/rf_dev.h | 2 +- lib/src/phy/rf/rf_imp.c | 4 +- lib/src/phy/rf/rf_soapy_imp.c | 2 +- lib/src/phy/rf/rf_soapy_imp.h | 2 +- lib/src/phy/rf/rf_uhd_imp.c | 18 +- lib/src/phy/rf/rf_uhd_imp.h | 3 +- lib/src/phy/rf/rf_utils.c | 6 +- lib/src/phy/sync/test/pss_usrp.c | 2 +- lib/src/radio/radio.cc | 4 +- lib/src/upper/pdcp.cc | 8 + lib/src/upper/pdcp_entity.cc | 16 +- lib/src/upper/rlc.cc | 12 + lib/src/upper/rlc_entity.cc | 4 + srsenb/hdr/upper/pdcp.h | 5 +- srsenb/hdr/upper/rlc.h | 1 + srsenb/src/upper/pdcp.cc | 4 + srsenb/src/upper/rlc.cc | 8 + srsue/hdr/mac/mac.h | 9 +- srsue/hdr/mac/proc_ra.h | 325 ++++++++-------- srsue/hdr/phy/phch_common.h | 9 +- srsue/hdr/phy/phch_recv.h | 10 +- srsue/hdr/phy/phch_worker.h | 3 +- srsue/hdr/phy/phy.h | 1 + srsue/hdr/upper/rrc.h | 18 +- srsue/hdr/upper/rrc_common.h | 2 + srsue/hdr/upper/usim.h | 10 + srsue/src/mac/mac.cc | 29 ++ srsue/src/mac/mux.cc | 79 ++-- srsue/src/mac/proc_ra.cc | 36 +- srsue/src/phy/phch_common.cc | 62 ++- srsue/src/phy/phch_recv.cc | 82 +++- srsue/src/phy/phch_worker.cc | 14 +- srsue/src/phy/phy.cc | 19 +- srsue/src/upper/rrc.cc | 368 ++++++++++++++---- srsue/src/upper/usim.cc | 34 ++ 60 files changed, 956 insertions(+), 389 deletions(-) diff --git a/lib/examples/cell_measurement.c b/lib/examples/cell_measurement.c index bfb8194df..1fc5e1640 100644 --- a/lib/examples/cell_measurement.c +++ b/lib/examples/cell_measurement.c @@ -293,7 +293,7 @@ int main(int argc, char **argv) { return -1; } - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); float rx_gain_offset = 0; diff --git a/lib/examples/cell_search.c b/lib/examples/cell_search.c index 281e3d102..e7740d892 100644 --- a/lib/examples/cell_search.c +++ b/lib/examples/cell_search.c @@ -219,7 +219,7 @@ int main(int argc, char **argv) { INFO("Setting sampling frequency %.2f MHz for PSS search\n", SRSLTE_CS_SAMP_FREQ/1000000); srslte_rf_set_rx_srate(&rf, SRSLTE_CS_SAMP_FREQ); INFO("Starting receiver...\n", 0); - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); n = srslte_ue_cellsearch_scan(&cs, found_cells, NULL); if (n < 0) { diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index bf4414f08..ecff9267f 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -552,7 +552,7 @@ int main(int argc, char **argv) { #ifndef DISABLE_RF if (!prog_args.input_file_name) { - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); } #endif diff --git a/lib/examples/usrp_capture.c b/lib/examples/usrp_capture.c index 02b543c0e..a0136e913 100644 --- a/lib/examples/usrp_capture.c +++ b/lib/examples/usrp_capture.c @@ -153,7 +153,7 @@ int main(int argc, char **argv) { printf("Correctly RX rate: %.2f MHz\n", srate*1e-6); srslte_rf_rx_wait_lo_locked(&rf); - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); while((sample_count < nof_samples || nof_samples == -1) diff --git a/lib/examples/usrp_capture_sync.c b/lib/examples/usrp_capture_sync.c index bac17698a..613f26d84 100644 --- a/lib/examples/usrp_capture_sync.c +++ b/lib/examples/usrp_capture_sync.c @@ -158,7 +158,7 @@ int main(int argc, char **argv) { exit(-1); } srslte_rf_rx_wait_lo_locked(&rf); - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); cell.cp = SRSLTE_CP_NORM; cell.id = N_id_2; diff --git a/lib/examples/usrp_txrx.c b/lib/examples/usrp_txrx.c index 508b4b397..42f610d65 100644 --- a/lib/examples/usrp_txrx.c +++ b/lib/examples/usrp_txrx.c @@ -175,7 +175,7 @@ int main(int argc, char **argv) { srslte_timestamp_t tstamp; - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); uint32_t nframe=0; diff --git a/lib/include/srslte/asn1/liblte_rrc.h b/lib/include/srslte/asn1/liblte_rrc.h index 46f725ec3..cd0c3f087 100644 --- a/lib/include/srslte/asn1/liblte_rrc.h +++ b/lib/include/srslte/asn1/liblte_rrc.h @@ -2684,6 +2684,7 @@ typedef enum{ }LIBLTE_RRC_T304_ENUM; static const char liblte_rrc_t304_text[LIBLTE_RRC_T304_N_ITEMS][20] = { "50", "100", "150", "200", "500", "1000", "2000", "SPARE"}; +static const int32 liblte_rrc_t304_num[LIBLTE_RRC_T304_N_ITEMS] = {50, 100, 150, 200, 500, 1000, 2000, -1}; // Structs typedef struct{ uint8 p_b; diff --git a/lib/include/srslte/common/liblte_security.h b/lib/include/srslte/common/liblte_security.h index b49f7211b..2c6fdc50c 100644 --- a/lib/include/srslte/common/liblte_security.h +++ b/lib/include/srslte/common/liblte_security.h @@ -86,6 +86,11 @@ LIBLTE_ERROR_ENUM liblte_security_generate_k_enb(uint8 *k_asme, uint32 nas_count, uint8 *k_enb); +LIBLTE_ERROR_ENUM liblte_security_generate_k_enb_star(uint8 *k_enb, + uint32 pci, + uint32_t earfcn, + uint8 *k_enb_star); + /********************************************************************* Name: liblte_security_generate_k_nas diff --git a/lib/include/srslte/common/mac_pcap.h b/lib/include/srslte/common/mac_pcap.h index f441e1aed..26a8f20bb 100644 --- a/lib/include/srslte/common/mac_pcap.h +++ b/lib/include/srslte/common/mac_pcap.h @@ -35,10 +35,13 @@ namespace srslte { class mac_pcap { public: - mac_pcap() {enable_write=false; ue_id=0; pcap_file = NULL; }; + mac_pcap() {enable_write=false; ue_id=0; pcap_file = NULL; }; void enable(bool en); void open(const char *filename, uint32_t ue_id = 0); - void close(); + void close(); + + void set_ue_id(uint16_t ue_id); + void write_ul_crnti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint32_t reTX, uint32_t tti); void write_dl_crnti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t crnti, bool crc_ok, uint32_t tti); void write_dl_ranti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t ranti, bool crc_ok, uint32_t tti); @@ -51,8 +54,8 @@ public: private: bool enable_write; FILE *pcap_file; - uint32_t ue_id; - void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti, + uint32_t ue_id; + void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti, uint16_t crnti_, uint8_t direction, uint8_t rnti_type); }; diff --git a/lib/include/srslte/common/security.h b/lib/include/srslte/common/security.h index 080f1848f..fd892e891 100644 --- a/lib/include/srslte/common/security.h +++ b/lib/include/srslte/common/security.h @@ -76,6 +76,11 @@ uint8_t security_generate_k_enb( uint8_t *k_asme, uint32_t nas_count, uint8_t *k_enb); +uint8_t security_generate_k_enb_star( uint8_t *k_enb, + uint32_t pci, + uint32_t earfcn, + uint8_t *k_enb_star); + uint8_t security_generate_k_nas( uint8_t *k_asme, CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index 9c85814f8..eb3eb6c2e 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -147,6 +147,7 @@ public: /* PDCP calls RLC to push an RLC SDU. SDU gets placed into the RLC buffer and MAC pulls * RLC PDUs according to TB size. */ virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; + virtual bool rb_is_um(uint16_t rnti, uint32_t lcid) = 0; }; // RLC interface for RRC diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index a4ecf1345..df2d74c33 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -78,6 +78,14 @@ public: uint8_t *k_up_int, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; + virtual void generate_as_keys_ho(uint32_t pci, + uint32_t earfcn, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int, + uint8_t *k_up_enc, + uint8_t *k_up_int, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; }; // GW interface for NAS @@ -133,6 +141,7 @@ public: class rrc_interface_mac : public rrc_interface_mac_common { public: + virtual void ho_ra_completed(bool ra_successful) = 0; virtual void release_pucch_srs() = 0; virtual void run_tti(uint32_t tti) = 0; }; @@ -192,6 +201,7 @@ public: class pdcp_interface_rrc { public: + virtual void reestablish() = 0; virtual void reset() = 0; virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; virtual void add_bearer(uint32_t lcid, srslte::srslte_pdcp_config_t cnfg = srslte::srslte_pdcp_config_t()) = 0; @@ -218,6 +228,7 @@ class rlc_interface_rrc { public: virtual void reset() = 0; + virtual void reestablish() = 0; virtual void add_bearer(uint32_t lcid) = 0; virtual void add_bearer(uint32_t lcid, srslte::srslte_rlc_config_t cnfg) = 0; }; @@ -229,6 +240,7 @@ public: /* PDCP calls RLC to push an RLC SDU. SDU gets placed into the RLC buffer and MAC pulls * RLC PDUs according to TB size. */ virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; + virtual bool rb_is_um(uint32_t lcid) = 0; }; //RLC interface for MAC @@ -392,8 +404,8 @@ public: LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT rach; LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT sr; ul_harq_params_t ul_harq_params; - uint32_t prach_config_index; - } mac_cfg_t; + uint32_t prach_config_index; + } mac_cfg_t; /* Instructs the MAC to start receiving BCCH */ virtual void bcch_start_rx() = 0; @@ -408,7 +420,7 @@ public: virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0; virtual uint32_t get_current_tti() = 0; - + virtual void set_config(mac_cfg_t *mac_cfg) = 0; virtual void set_config_main(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *main_cfg) = 0; virtual void set_config_rach(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT *rach_cfg, uint32_t prach_config_index) = 0; @@ -417,10 +429,14 @@ public: virtual void get_rntis(ue_rnti_t *rntis) = 0; virtual void set_contention_id(uint64_t uecri) = 0; + virtual void set_ho_rnti(uint16_t crnti, uint16_t target_pci) = 0; + + virtual void start_noncont_ho(uint32_t preamble_index, uint32_t prach_mask) = 0; + virtual void start_cont_ho() = 0; - virtual void reconfiguration() = 0; virtual void reset() = 0; + virtual void wait_uplink() = 0; }; @@ -541,6 +557,7 @@ public: virtual void cell_search_stop() = 0; virtual void cell_search_next() = 0; virtual bool cell_select(uint32_t earfcn, srslte_cell_t cell) = 0; + virtual bool cell_handover(srslte_cell_t cell) = 0; /* Is the PHY downlink synchronized? */ virtual bool sync_status() = 0; diff --git a/lib/include/srslte/phy/rf/rf.h b/lib/include/srslte/phy/rf/rf.h index 860e0a257..afafc5cf2 100644 --- a/lib/include/srslte/phy/rf/rf.h +++ b/lib/include/srslte/phy/rf/rf.h @@ -95,7 +95,7 @@ SRSLTE_API void srslte_rf_set_tx_cal(srslte_rf_t *h, srslte_rf_cal_t *cal); SRSLTE_API void srslte_rf_set_rx_cal(srslte_rf_t *h, srslte_rf_cal_t *cal); -SRSLTE_API int srslte_rf_start_rx_stream(srslte_rf_t *h); +SRSLTE_API int srslte_rf_start_rx_stream(srslte_rf_t *h, bool now); SRSLTE_API int srslte_rf_stop_rx_stream(srslte_rf_t *h); diff --git a/lib/include/srslte/radio/radio.h b/lib/include/srslte/radio/radio.h index 329dd825a..3f961e2aa 100644 --- a/lib/include/srslte/radio/radio.h +++ b/lib/include/srslte/radio/radio.h @@ -117,7 +117,7 @@ namespace srslte { void start_trace(); void write_trace(std::string filename); - void start_rx(); + void start_rx(bool now = false); void stop_rx(); void set_tti(uint32_t tti); diff --git a/lib/include/srslte/upper/pdcp.h b/lib/include/srslte/upper/pdcp.h index ce6ece151..11880c61d 100644 --- a/lib/include/srslte/upper/pdcp.h +++ b/lib/include/srslte/upper/pdcp.h @@ -54,6 +54,7 @@ public: bool is_drb_enabled(uint32_t lcid); // RRC interface + void reestablish(); void reset(); void write_sdu(uint32_t lcid, byte_buffer_t *sdu); void add_bearer(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t()); diff --git a/lib/include/srslte/upper/pdcp_entity.h b/lib/include/srslte/upper/pdcp_entity.h index 0ff005d07..38190a428 100644 --- a/lib/include/srslte/upper/pdcp_entity.h +++ b/lib/include/srslte/upper/pdcp_entity.h @@ -69,6 +69,7 @@ public: uint32_t lcid_, srslte_pdcp_config_t cfg_); void reset(); + void reestablish(); bool is_active(); @@ -94,8 +95,8 @@ private: uint32_t lcid; srslte_pdcp_config_t cfg; - uint32_t rx_count; uint32_t tx_count; + uint32_t tx_sn; uint8_t k_rrc_enc[32]; uint8_t k_rrc_int[32]; diff --git a/lib/include/srslte/upper/rlc.h b/lib/include/srslte/upper/rlc.h index 349a7952d..ed5929542 100644 --- a/lib/include/srslte/upper/rlc.h +++ b/lib/include/srslte/upper/rlc.h @@ -64,6 +64,7 @@ public: // PDCP interface void write_sdu(uint32_t lcid, byte_buffer_t *sdu); + bool rb_is_um(uint32_t lcid); std::string get_rb_name(uint32_t lcid); // MAC interface @@ -76,6 +77,7 @@ public: void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes); // RRC interface + void reestablish(); void reset(); void empty_queue(); void add_bearer(uint32_t lcid); diff --git a/lib/include/srslte/upper/rlc_am.h b/lib/include/srslte/upper/rlc_am.h index cee0d5959..c0289956c 100644 --- a/lib/include/srslte/upper/rlc_am.h +++ b/lib/include/srslte/upper/rlc_am.h @@ -78,6 +78,7 @@ public: mac_interface_timers *mac_timers); void configure(srslte_rlc_config_t cnfg); void reset(); + void reestablish(); void stop(); void empty_queue(); diff --git a/lib/include/srslte/upper/rlc_entity.h b/lib/include/srslte/upper/rlc_entity.h index e9c41fa30..de4a396fe 100644 --- a/lib/include/srslte/upper/rlc_entity.h +++ b/lib/include/srslte/upper/rlc_entity.h @@ -56,6 +56,7 @@ public: void configure(srslte_rlc_config_t cnfg); void reset(); + void reestablish(); void stop(); void empty_queue(); bool active(); diff --git a/lib/src/common/liblte_security.cc b/lib/src/common/liblte_security.cc index 95f9617cd..e0cdd90d8 100644 --- a/lib/src/common/liblte_security.cc +++ b/lib/src/common/liblte_security.cc @@ -298,6 +298,43 @@ LIBLTE_ERROR_ENUM liblte_security_generate_k_enb(uint8 *k_asme, return(err); } +/********************************************************************* + Name: liblte_security_generate_k_enb_star + + Description: Generate the security key Kenb*. + + Document Reference: 33.401 v10.0.0 Annex A.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_generate_k_enb_star(uint8 *k_enb, + uint32 pci, + uint32_t earfcn, + uint8 *k_enb_star) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 s[9]; + + if (k_enb_star != NULL && + k_enb != NULL) { + // Construct S + s[0] = 0x13; // FC + s[1] = (pci >> 8) & 0xFF; // First byte of P0 + s[2] = pci & 0xFF; // Second byte of P0 + s[3] = 0x00; // First byte of L0 + s[4] = 0x02; // Second byte of L0 + s[5] = (earfcn >> 8) & 0xFF; // First byte of P0 + s[6] = earfcn & 0xFF; // Second byte of P0 + s[7] = 0x00; // First byte of L0 + s[8] = 0x02; // Second byte of L0 + + // Derive Kenb + sha256(k_enb, 32, s, 9, k_enb_star, 0); + + err = LIBLTE_SUCCESS; + } + + return (err); +} + /********************************************************************* Name: liblte_security_generate_k_nas diff --git a/lib/src/common/mac_pcap.cc b/lib/src/common/mac_pcap.cc index ff30670ed..c3bf3e1d4 100644 --- a/lib/src/common/mac_pcap.cc +++ b/lib/src/common/mac_pcap.cc @@ -41,8 +41,8 @@ void mac_pcap::enable(bool en) void mac_pcap::open(const char* filename, uint32_t ue_id) { pcap_file = MAC_LTE_PCAP_Open(filename); - ue_id = ue_id; - enable_write = true; + this->ue_id = ue_id; + enable_write = true; } void mac_pcap::close() { @@ -50,6 +50,10 @@ void mac_pcap::close() MAC_LTE_PCAP_Close(pcap_file); } +void mac_pcap::set_ue_id(uint16_t ue_id) { + this->ue_id = ue_id; +} + void mac_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti, uint16_t crnti, uint8_t direction, uint8_t rnti_type) { diff --git a/lib/src/common/security.cc b/lib/src/common/security.cc index f0ad1ce7e..93b197e7c 100644 --- a/lib/src/common/security.cc +++ b/lib/src/common/security.cc @@ -61,6 +61,17 @@ uint8_t security_generate_k_enb( uint8_t *k_asme, k_enb); } +uint8_t security_generate_k_enb_star( uint8_t *k_enb, + uint32_t pci, + uint32_t earfcn, + uint8_t *k_enb_star) +{ + return liblte_security_generate_k_enb_star(k_enb, + pci, + earfcn, + k_enb_star); +} + uint8_t security_generate_k_nas( uint8_t *k_asme, CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, diff --git a/lib/src/phy/phch/test/prach_test_usrp.c b/lib/src/phy/phch/test/prach_test_usrp.c index c0fae365c..c4edc343d 100644 --- a/lib/src/phy/phch/test/prach_test_usrp.c +++ b/lib/src/phy/phch/test/prach_test_usrp.c @@ -199,7 +199,7 @@ int main(int argc, char **argv) { srslte_timestamp_t tstamp; - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); uint32_t nframe=0; while(nframedev)->srslte_rf_rx_wait_lo_locked(rf->handler); } -int srslte_rf_start_rx_stream(srslte_rf_t *rf) +int srslte_rf_start_rx_stream(srslte_rf_t *rf, bool now) { - return ((rf_dev_t*) rf->dev)->srslte_rf_start_rx_stream(rf->handler); + return ((rf_dev_t*) rf->dev)->srslte_rf_start_rx_stream(rf->handler, now); } int srslte_rf_stop_rx_stream(srslte_rf_t *rf) diff --git a/lib/src/phy/rf/rf_soapy_imp.c b/lib/src/phy/rf/rf_soapy_imp.c index 18c5b01cd..3e8d83eb8 100644 --- a/lib/src/phy/rf/rf_soapy_imp.c +++ b/lib/src/phy/rf/rf_soapy_imp.c @@ -114,7 +114,7 @@ void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal) } -int rf_soapy_start_rx_stream(void *h) +int rf_soapy_start_rx_stream(void *h, bool now) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; if(handler->rx_stream_active == false){ diff --git a/lib/src/phy/rf/rf_soapy_imp.h b/lib/src/phy/rf/rf_soapy_imp.h index 19de4536c..18850e520 100644 --- a/lib/src/phy/rf/rf_soapy_imp.h +++ b/lib/src/phy/rf/rf_soapy_imp.h @@ -45,7 +45,7 @@ SRSLTE_API void rf_soapy_set_tx_cal(void *h, srslte_rf_cal_t *cal); SRSLTE_API void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal); -SRSLTE_API int rf_soapy_start_rx_stream(void *h); +SRSLTE_API int rf_soapy_start_rx_stream(void *h, bool now); SRSLTE_API int rf_soapy_stop_rx_stream(void *h); diff --git a/lib/src/phy/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c index 29aec5b44..f5bed7362 100644 --- a/lib/src/phy/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -219,21 +219,23 @@ void rf_uhd_set_rx_cal(void *h, srslte_rf_cal_t *cal) } -int rf_uhd_start_rx_stream(void *h) +int rf_uhd_start_rx_stream(void *h, bool now) { rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; uhd_stream_cmd_t stream_cmd = { .stream_mode = UHD_STREAM_MODE_START_CONTINUOUS, - .stream_now = false + .stream_now = now }; - uhd_usrp_get_time_now(handler->usrp, 0, &stream_cmd.time_spec_full_secs, &stream_cmd.time_spec_frac_secs); - stream_cmd.time_spec_frac_secs += 0.1; - if (stream_cmd.time_spec_frac_secs > 1) { - stream_cmd.time_spec_frac_secs -= 1; - stream_cmd.time_spec_full_secs += 1; + if (!now) { + uhd_usrp_get_time_now(handler->usrp, 0, &stream_cmd.time_spec_full_secs, &stream_cmd.time_spec_frac_secs); + stream_cmd.time_spec_frac_secs += 0.1; + if (stream_cmd.time_spec_frac_secs > 1) { + stream_cmd.time_spec_frac_secs -= 1; + stream_cmd.time_spec_full_secs += 1; + } } - uhd_rx_streamer_issue_stream_cmd(handler->rx_stream, &stream_cmd); + uhd_rx_streamer_issue_stream_cmd(handler->rx_stream, &stream_cmd); return 0; } diff --git a/lib/src/phy/rf/rf_uhd_imp.h b/lib/src/phy/rf/rf_uhd_imp.h index 2be799333..e3555fab3 100644 --- a/lib/src/phy/rf/rf_uhd_imp.h +++ b/lib/src/phy/rf/rf_uhd_imp.h @@ -49,7 +49,8 @@ SRSLTE_API void rf_uhd_set_tx_cal(void *h, srslte_rf_cal_t *cal); SRSLTE_API void rf_uhd_set_rx_cal(void *h, srslte_rf_cal_t *cal); -SRSLTE_API int rf_uhd_start_rx_stream(void *h); +SRSLTE_API int rf_uhd_start_rx_stream(void *h, + bool now); SRSLTE_API int rf_uhd_start_rx_stream_nsamples(void *h, uint32_t nsamples); diff --git a/lib/src/phy/rf/rf_utils.c b/lib/src/phy/rf/rf_utils.c index ce288b5c5..0ef082a23 100644 --- a/lib/src/phy/rf/rf_utils.c +++ b/lib/src/phy/rf/rf_utils.c @@ -60,7 +60,7 @@ int rf_rssi_scan(srslte_rf_t *rf, float *freqs, float *rssi, int nof_bands, doub srslte_rf_set_rx_freq(rf, f); srslte_rf_rx_wait_lo_locked(rf); usleep(10000); - srslte_rf_start_rx_stream(rf); + srslte_rf_start_rx_stream(rf, false); /* discard first samples */ for (j=0;j<2;j++) { @@ -122,7 +122,7 @@ int rf_mib_decoder(srslte_rf_t *rf, uint32_t nof_rx_antennas,cell_search_cfg_t * srslte_rf_set_rx_srate(rf, (float) srate); INFO("Starting receiver...\n", 0); - srslte_rf_start_rx_stream(rf); + srslte_rf_start_rx_stream(rf, false); // Set CFO if available if (cfo) { @@ -184,7 +184,7 @@ int rf_cell_search(srslte_rf_t *rf, uint32_t nof_rx_antennas, srslte_rf_set_rx_srate(rf, SRSLTE_CS_SAMP_FREQ); INFO("Starting receiver...\n", 0); - srslte_rf_start_rx_stream(rf); + srslte_rf_start_rx_stream(rf, false); /* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */ uint32_t max_peak_cell = 0; diff --git a/lib/src/phy/sync/test/pss_usrp.c b/lib/src/phy/sync/test/pss_usrp.c index 8e8377b83..25f8a07b3 100644 --- a/lib/src/phy/sync/test/pss_usrp.c +++ b/lib/src/phy/sync/test/pss_usrp.c @@ -198,7 +198,7 @@ int main(int argc, char **argv) { printf("N_id_2: %d\n", N_id_2); - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); printf("Frame length %d samples\n", flen); printf("PSS detection threshold: %.2f\n", threshold); diff --git a/lib/src/radio/radio.cc b/lib/src/radio/radio.cc index 42d4143f9..66e28b1d3 100644 --- a/lib/src/radio/radio.cc +++ b/lib/src/radio/radio.cc @@ -392,9 +392,9 @@ void radio::set_tx_srate(double srate) tx_adv_sec = nsamples/cur_tx_srate; } -void radio::start_rx() +void radio::start_rx(bool now) { - srslte_rf_start_rx_stream(&rf_device); + srslte_rf_start_rx_stream(&rf_device, now); } void radio::stop_rx() diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc index 0acc7f6bd..7b5de7e67 100644 --- a/lib/src/upper/pdcp.cc +++ b/lib/src/upper/pdcp.cc @@ -53,6 +53,14 @@ void pdcp::init(srsue::rlc_interface_pdcp *rlc_, srsue::rrc_interface_pdcp *rrc_ void pdcp::stop() {} +void pdcp::reestablish() { + for(uint32_t i=0;idebug("Init %s\n", rrc->get_rb_name(lcid).c_str()); } +// Reestablishment procedure: 36.323 5.2 +void pdcp_entity::reestablish() { + // For SRBs + if (cfg.is_control) { + tx_count = 0; + cfg.do_security = false; + } else { + if (rlc->rb_is_um(lcid)) { + tx_count = 0; + } + } +} + void pdcp_entity::reset() { active = false; @@ -80,6 +91,7 @@ void pdcp_entity::write_sdu(byte_buffer_t *sdu) pdcp_pack_control_pdu(tx_count, sdu); if(cfg.do_security) { + log->info("rrc_int[0]=0x%x, tx_count=%d\n", k_rrc_int[0], tx_count); integrity_generate(&k_rrc_int[16], tx_count, lcid-1, diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc index f506ebc63..c86d1d989 100644 --- a/lib/src/upper/rlc.cc +++ b/lib/src/upper/rlc.cc @@ -95,6 +95,14 @@ void rlc::get_metrics(rlc_metrics_t &m) reset_metrics(); } +void rlc::reestablish() { + for(uint32_t i=0; iget_rb_name(lcid); diff --git a/lib/src/upper/rlc_entity.cc b/lib/src/upper/rlc_entity.cc index 5a351162a..81692889c 100644 --- a/lib/src/upper/rlc_entity.cc +++ b/lib/src/upper/rlc_entity.cc @@ -70,6 +70,10 @@ void rlc_entity::configure(srslte_rlc_config_t cnfg) rlc->configure(cnfg); } +void rlc_entity::reestablish() { + rlc->reset(); +} + void rlc_entity::reset() { rlc->reset(); diff --git a/srsenb/hdr/upper/pdcp.h b/srsenb/hdr/upper/pdcp.h index 228490312..8c5b05275 100644 --- a/srsenb/hdr/upper/pdcp.h +++ b/srsenb/hdr/upper/pdcp.h @@ -67,8 +67,9 @@ private: uint16_t rnti; srsenb::rlc_interface_pdcp *rlc; // rlc_interface_pdcp - void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu); - }; + void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu); + bool rb_is_um(uint32_t lcid); + }; class user_interface_gtpu : public srsue::gw_interface_pdcp { diff --git a/srsenb/hdr/upper/rlc.h b/srsenb/hdr/upper/rlc.h index abbf99516..b937cd216 100644 --- a/srsenb/hdr/upper/rlc.h +++ b/srsenb/hdr/upper/rlc.h @@ -54,6 +54,7 @@ public: // rlc_interface_pdcp void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu); + bool rb_is_um(uint16_t rnti, uint32_t lcid); std::string get_rb_name(uint32_t lcid); // rlc_interface_mac diff --git a/srsenb/src/upper/pdcp.cc b/srsenb/src/upper/pdcp.cc index 027f04909..afd41976f 100644 --- a/srsenb/src/upper/pdcp.cc +++ b/srsenb/src/upper/pdcp.cc @@ -124,6 +124,10 @@ void pdcp::user_interface_rlc::write_sdu(uint32_t lcid, srslte::byte_buffer_t* s rlc->write_sdu(rnti, lcid, sdu); } +bool pdcp::user_interface_rlc::rb_is_um(uint32_t lcid) { + return rlc->rb_is_um(rnti, lcid); +} + void pdcp::user_interface_rrc::write_pdu(uint32_t lcid, srslte::byte_buffer_t* pdu) { rrc->write_pdu(rnti, lcid, pdu); diff --git a/srsenb/src/upper/rlc.cc b/srsenb/src/upper/rlc.cc index 6147597e3..fff674112 100644 --- a/srsenb/src/upper/rlc.cc +++ b/srsenb/src/upper/rlc.cc @@ -160,6 +160,14 @@ void rlc::write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu) } } +bool rlc::rb_is_um(uint16_t rnti, uint32_t lcid) { + if (users.count(rnti)) { + return users[rnti].rlc->rb_is_um(lcid); + } else { + return false; + } +} + void rlc::user_interface::max_retx_attempted() { rrc->max_retx_attempted(rnti); diff --git a/srsue/hdr/mac/mac.h b/srsue/hdr/mac/mac.h index d19f668bf..b1b649de7 100644 --- a/srsue/hdr/mac/mac.h +++ b/srsue/hdr/mac/mac.h @@ -79,7 +79,8 @@ public: void pcch_stop_rx(); void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD); void reconfiguration(); - void reset(); + void reset(); + void wait_uplink(); /******** set/get MAC configuration ****************/ void set_config(mac_cfg_t *mac_cfg); @@ -88,8 +89,12 @@ public: void set_config_rach(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT *rach_cfg, uint32_t prach_config_index); void set_config_sr(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT *sr_cfg); void set_contention_id(uint64_t uecri); - + + void start_noncont_ho(uint32_t preamble_index, uint32_t prach_mask); + void start_cont_ho(); + void get_rntis(ue_rnti_t *rntis); + void set_ho_rnti(uint16_t crnti, uint16_t target_pci); void start_pcap(srslte::mac_pcap* pcap); diff --git a/srsue/hdr/mac/proc_ra.h b/srsue/hdr/mac/proc_ra.h index 2bd2dd807..de8a0671d 100644 --- a/srsue/hdr/mac/proc_ra.h +++ b/srsue/hdr/mac/proc_ra.h @@ -43,164 +43,175 @@ namespace srsue { class ra_proc : public srslte::timer_callback { - public: - ra_proc() : rar_pdu_msg(20) { - bzero(&softbuffer_rar, sizeof(srslte_softbuffer_rx_t)); - pcap = NULL; - backoff_interval_start = 0; - backoff_inteval = 0; - received_target_power_dbm = 0; - ra_rnti = 0; - current_ta = 0; - state = IDLE; - last_msg3_group = RA_GROUP_A; - msg3_transmitted = false; - first_rar_received = false; - phy_h = NULL; - log_h = NULL; - mac_cfg = NULL; - mux_unit = NULL; - demux_unit = NULL; - rrc = NULL; - transmitted_contention_id = 0; - transmitted_crnti = 0; - pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED; - started_by_pdcch = false; - rar_grant_nbytes = 0; - rar_grant_tti = 0; - msg3_flushed = false; - - time_alignment_timer = NULL; - contention_resolution_timer = NULL; - }; - - ~ra_proc(); - - void init(phy_interface_mac *phy_h, - rrc_interface_mac *rrc_, - srslte::log *log_h, - mac_interface_rrc::ue_rnti_t *rntis, - mac_interface_rrc::mac_cfg_t *mac_cfg, - srslte::timers::timer* time_alignment_timer_, - srslte::timers::timer* contention_resolution_timer_, - mux *mux_unit, - demux *demux_unit); - void reset(); - void start_pdcch_order(); - void start_mac_order(uint32_t msg_len_bits = 56); - void step(uint32_t tti); - bool is_successful(); - bool is_response_error(); - bool is_contention_resolution(); - void harq_retx(); - bool is_error(); - bool in_progress(); - void pdcch_to_crnti(bool contains_uplink_grant); - void timer_expired(uint32_t timer_id); - - void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action); - void tb_decoded_ok(); - - void start_pcap(srslte::mac_pcap* pcap); +public: + ra_proc() : rar_pdu_msg(20) { + bzero(&softbuffer_rar, sizeof(srslte_softbuffer_rx_t)); + pcap = NULL; + backoff_interval_start = 0; + backoff_inteval = 0; + received_target_power_dbm = 0; + ra_rnti = 0; + current_ta = 0; + state = IDLE; + last_msg3_group = RA_GROUP_A; + msg3_transmitted = false; + first_rar_received = false; + phy_h = NULL; + log_h = NULL; + mac_cfg = NULL; + mux_unit = NULL; + demux_unit = NULL; + rrc = NULL; + transmitted_contention_id = 0; + transmitted_crnti = 0; + pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED; + started_by_pdcch = false; + rar_grant_nbytes = 0; + rar_grant_tti = 0; + msg3_flushed = false; + + noncontention_enabled = false; + next_preamble_idx = 0; + next_prach_mask = 0; + + time_alignment_timer = NULL; + contention_resolution_timer = NULL; + }; + + ~ra_proc(); + + void init(phy_interface_mac *phy_h, + rrc_interface_mac *rrc_, + srslte::log *log_h, + mac_interface_rrc::ue_rnti_t *rntis, + mac_interface_rrc::mac_cfg_t *mac_cfg, + srslte::timers::timer* time_alignment_timer_, + srslte::timers::timer* contention_resolution_timer_, + mux *mux_unit, + demux *demux_unit); + void reset(); + void start_pdcch_order(); + void start_mac_order(uint32_t msg_len_bits = 56, bool is_ho = false); + void step(uint32_t tti); + bool is_successful(); + bool is_response_error(); + bool is_contention_resolution(); + void harq_retx(); + bool is_error(); + bool in_progress(); + void pdcch_to_crnti(bool contains_uplink_grant); + void timer_expired(uint32_t timer_id); + + void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action); + void tb_decoded_ok(); + + void start_noncont(uint32_t preamble_index, uint32_t prach_mask); + + void start_pcap(srslte::mac_pcap* pcap); private: - static bool uecrid_callback(void *arg, uint64_t uecri); - - bool contention_resolution_id_received(uint64_t uecri); - void process_timeadv_cmd(uint32_t ta_cmd); - void step_initialization(); - void step_resource_selection(); - void step_preamble_transmission(); - void step_pdcch_setup(); - void step_response_reception(); - void step_response_error(); - void step_backoff_wait(); - void step_contention_resolution(); - void step_completition(); - - // Buffer to receive RAR PDU - static const uint32_t MAX_RAR_PDU_LEN = 2048; - uint8_t rar_pdu_buffer[MAX_RAR_PDU_LEN]; - srslte::rar_pdu rar_pdu_msg; - - // Random Access parameters provided by higher layers defined in 5.1.1 - uint32_t configIndex; - uint32_t nof_preambles; - uint32_t nof_groupA_preambles; - uint32_t nof_groupB_preambles; - uint32_t messagePowerOffsetGroupB; - uint32_t messageSizeGroupA; - uint32_t responseWindowSize; - uint32_t powerRampingStep; - uint32_t preambleTransMax; - uint32_t iniReceivedTargetPower; - int delta_preamble_db; - uint32_t contentionResolutionTimer; - uint32_t maskIndex; - int preambleIndex; - uint32_t new_ra_msg_len; - - // Internal variables - uint32_t preambleTransmissionCounter; - uint32_t backoff_param_ms; - uint32_t sel_maskIndex; - uint32_t sel_preamble; - uint32_t backoff_interval_start; - uint32_t backoff_inteval; - int received_target_power_dbm; - uint32_t ra_rnti; - uint32_t current_ta; - - srslte_softbuffer_rx_t softbuffer_rar; - - enum { - IDLE = 0, - INITIALIZATION, // Section 5.1.1 - RESOURCE_SELECTION, // Section 5.1.2 - PREAMBLE_TRANSMISSION, // Section 5.1.3 - PDCCH_SETUP, - RESPONSE_RECEPTION, // Section 5.1.4 - RESPONSE_ERROR, - BACKOFF_WAIT, - CONTENTION_RESOLUTION, // Section 5.1.5 - COMPLETION, // Section 5.1.6 - COMPLETION_DONE, - RA_PROBLEM // Section 5.1.5 last part - } state; - - typedef enum {RA_GROUP_A, RA_GROUP_B} ra_group_t; - - ra_group_t last_msg3_group; - bool msg3_transmitted; - bool first_rar_received; - void read_params(); - - phy_interface_mac *phy_h; - srslte::log *log_h; - mux *mux_unit; - demux *demux_unit; - srslte::mac_pcap *pcap; - rrc_interface_mac *rrc; - - srslte::timers::timer *time_alignment_timer; - srslte::timers::timer *contention_resolution_timer; - - mac_interface_rrc::ue_rnti_t *rntis; - mac_interface_rrc::mac_cfg_t *mac_cfg; - - uint64_t transmitted_contention_id; - uint16_t transmitted_crnti; - - enum { - PDCCH_CRNTI_NOT_RECEIVED = 0, - PDCCH_CRNTI_UL_GRANT, - PDCCH_CRNTI_DL_GRANT - } pdcch_to_crnti_received; - - bool started_by_pdcch; - uint32_t rar_grant_nbytes; - uint32_t rar_grant_tti; - bool msg3_flushed; - bool rar_received; + static bool uecrid_callback(void *arg, uint64_t uecri); + + bool contention_resolution_id_received(uint64_t uecri); + void process_timeadv_cmd(uint32_t ta_cmd); + void step_initialization(); + void step_resource_selection(); + void step_preamble_transmission(); + void step_pdcch_setup(); + void step_response_reception(); + void step_response_error(); + void step_backoff_wait(); + void step_contention_resolution(); + void step_completition(); + + // Buffer to receive RAR PDU + static const uint32_t MAX_RAR_PDU_LEN = 2048; + uint8_t rar_pdu_buffer[MAX_RAR_PDU_LEN]; + srslte::rar_pdu rar_pdu_msg; + + // Random Access parameters provided by higher layers defined in 5.1.1 + uint32_t configIndex; + uint32_t nof_preambles; + uint32_t nof_groupA_preambles; + uint32_t nof_groupB_preambles; + uint32_t messagePowerOffsetGroupB; + uint32_t messageSizeGroupA; + uint32_t responseWindowSize; + uint32_t powerRampingStep; + uint32_t preambleTransMax; + uint32_t iniReceivedTargetPower; + int delta_preamble_db; + uint32_t contentionResolutionTimer; + uint32_t maskIndex; + int preambleIndex; + uint32_t new_ra_msg_len; + + bool noncontention_enabled; + uint32_t next_preamble_idx; + uint32_t next_prach_mask; + + // Internal variables + uint32_t preambleTransmissionCounter; + uint32_t backoff_param_ms; + uint32_t sel_maskIndex; + uint32_t sel_preamble; + uint32_t backoff_interval_start; + uint32_t backoff_inteval; + int received_target_power_dbm; + uint32_t ra_rnti; + uint32_t current_ta; + + srslte_softbuffer_rx_t softbuffer_rar; + + enum { + IDLE = 0, + INITIALIZATION, // Section 5.1.1 + RESOURCE_SELECTION, // Section 5.1.2 + PREAMBLE_TRANSMISSION, // Section 5.1.3 + PDCCH_SETUP, + RESPONSE_RECEPTION, // Section 5.1.4 + RESPONSE_ERROR, + BACKOFF_WAIT, + CONTENTION_RESOLUTION, // Section 5.1.5 + COMPLETION, // Section 5.1.6 + COMPLETION_DONE, + RA_PROBLEM // Section 5.1.5 last part + } state; + + typedef enum {RA_GROUP_A, RA_GROUP_B} ra_group_t; + + ra_group_t last_msg3_group; + bool msg3_transmitted; + bool first_rar_received; + void read_params(); + + phy_interface_mac *phy_h; + srslte::log *log_h; + mux *mux_unit; + demux *demux_unit; + srslte::mac_pcap *pcap; + rrc_interface_mac *rrc; + + srslte::timers::timer *time_alignment_timer; + srslte::timers::timer *contention_resolution_timer; + + mac_interface_rrc::ue_rnti_t *rntis; + mac_interface_rrc::mac_cfg_t *mac_cfg; + + uint64_t transmitted_contention_id; + uint16_t transmitted_crnti; + + enum { + PDCCH_CRNTI_NOT_RECEIVED = 0, + PDCCH_CRNTI_UL_GRANT, + PDCCH_CRNTI_DL_GRANT + } pdcch_to_crnti_received; + + bool ra_is_ho; + bool started_by_pdcch; + uint32_t rar_grant_nbytes; + uint32_t rar_grant_tti; + bool msg3_flushed; + bool rar_received; }; } // namespace srsue diff --git a/srsue/hdr/phy/phch_common.h b/srsue/hdr/phy/phch_common.h index f3c36d994..aa7c53ab7 100644 --- a/srsue/hdr/phy/phch_common.h +++ b/srsue/hdr/phy/phch_common.h @@ -64,9 +64,10 @@ namespace srsue { float rx_gain_offset; float avg_snr_db; float avg_noise; - float avg_rsrp; + float avg_rsrp; - uint32_t serving_cell_report_period; + bool pcell_meas_enabled; + uint32_t pcell_report_period; phch_common(uint32_t max_mutex = 3); void init(phy_interface_rrc::phy_cfg_t *config, @@ -92,7 +93,8 @@ namespace srsue { void set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs); bool get_pending_ack(uint32_t tti); bool get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs); - + bool is_any_pending_ack(); + void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); void set_nof_mutex(uint32_t nof_mutex); @@ -112,6 +114,7 @@ namespace srsue { void get_sync_metrics(sync_metrics_t &m); void reset_ul(); + void reset(); private: diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/phch_recv.h index e35610c0b..93ace4d68 100644 --- a/srsue/hdr/phy/phch_recv.h +++ b/srsue/hdr/phy/phch_recv.h @@ -64,6 +64,7 @@ public: void cell_search_stop(); void cell_search_next(bool reset = false); bool cell_select(uint32_t earfcn, srslte_cell_t cell); + bool cell_handover(srslte_cell_t cell); void meas_reset(); int meas_start(uint32_t earfcn, int pci); @@ -97,11 +98,11 @@ private: bool set_cell(); void cell_search_inc(); - void resync_sfn(bool is_connected = false); + void resync_sfn(bool is_connected = false, bool rx_now = false); bool stop_sync(); void stop_rx(); - void start_rx(); + void start_rx(bool now = false); bool radio_is_rx; bool radio_is_resetting; @@ -169,6 +170,7 @@ private: float rsrp(); float rsrq(); float snr(); + void set_rx_gain_offset(float rx_gain_offset); private: srslte::log *log_h; srslte_ue_dl_t ue_dl; @@ -176,6 +178,7 @@ private: uint32_t cnt; uint32_t nof_subframes; uint32_t current_prb; + float rx_gain_offset; float mean_rsrp, mean_rsrq, mean_snr; const static int RSRP_MEASURE_NOF_FRAMES = 5; }; @@ -192,7 +195,7 @@ private: } cell_info_t; void init(srslte::log *log_h); void reset(); - int find_cells(cf_t *input_buffer, srslte_cell_t current_cell, uint32_t nof_sf, cell_info_t found_cells[MAX_CELLS]); + int find_cells(cf_t *input_buffer, float rx_gain_offset, srslte_cell_t current_cell, uint32_t nof_sf, cell_info_t found_cells[MAX_CELLS]); private: const static int DEFAULT_MEASUREMENT_LEN = 10; @@ -217,6 +220,7 @@ private: void rem_cell(int pci); void set_primay_cell(uint32_t earfcn, srslte_cell_t cell); void clear_cells(); + int get_offset(uint32_t pci); void write(uint32_t tti, cf_t *data, uint32_t nsamples); private: void run_thread(); diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index c26966c17..73547a9aa 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -146,7 +146,8 @@ private: srslte_uci_cfg_t uci_cfg; srslte_cqi_periodic_cfg_t period_cqi; srslte_ue_ul_powerctrl_t power_ctrl; - uint32_t I_sr; + uint32_t I_sr; + bool sr_configured; float cfo; bool rar_cqi_request; diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index 6a0e8891e..05edf31f9 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -87,6 +87,7 @@ public: void cell_search_stop(); void cell_search_next(); bool cell_select(uint32_t earfcn, srslte_cell_t phy_cell); + bool cell_handover(srslte_cell_t cell); void meas_reset(); int meas_start(uint32_t earfcn, int pci); diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index 5ec484251..5a49a9275 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -101,6 +101,7 @@ public: void new_phy_meas(float rsrp, float rsrq, uint32_t tti, uint32_t earfcn, uint32_t pci); // MAC interface + void ho_ra_completed(bool ra_successful); void release_pucch_srs(); void run_tti(uint32_t tti); @@ -143,6 +144,9 @@ private: bool reestablishment_in_progress; + bool pending_mob_reconf; + LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT mob_reconf; + // timeouts in ms uint32_t connecting_timeout; @@ -172,7 +176,7 @@ private: srslte::mac_interface_timers *mac_timers; uint32_t n310_cnt, N310; uint32_t n311_cnt, N311; - uint32_t t301, t310, t311; + uint32_t t301, t310, t311, t304; int ue_category; typedef struct { @@ -189,7 +193,6 @@ private: std::vector known_cells; cell_t *current_cell; - typedef enum { SI_ACQUIRE_IDLE = 0, SI_ACQUIRE_SIB1, @@ -242,6 +245,7 @@ private: void new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, float rsrq, uint32_t tti); void run_tti(uint32_t tti); bool timer_expired(uint32_t timer_id); + void ho_finish(); private: const static int NOF_MEASUREMENTS = 3; @@ -304,10 +308,12 @@ private: bool s_measure_enabled; float s_measure_value; + void stop_reports(meas_t *m); void stop_reports_object(uint32_t object_id); void remove_meas_object(uint32_t object_id); void remove_meas_report(uint32_t report_id); - void remove_meas_id(uint32_t meas_id); + void remove_meas_id(uint32_t measId); + void remove_meas_id(std::map::iterator it); void calculate_triggers(uint32_t tti); void update_phy(); void L3_filter(meas_value_t *value, float rsrp[NOF_MEASUREMENTS]); @@ -334,7 +340,7 @@ private: void send_con_setup_complete(byte_buffer_t *nas_msg); void send_ul_info_transfer(uint32_t lcid, byte_buffer_t *sdu); void send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu); - void send_rrc_con_reconfig_complete(uint32_t lcid, byte_buffer_t *pdu); + void send_rrc_con_reconfig_complete(byte_buffer_t *pdu); void send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu); // Parsers @@ -343,11 +349,15 @@ private: void parse_dl_info_transfer(uint32_t lcid, byte_buffer_t *pdu); // Helpers + void ho_prepare(); + void add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp); void rrc_connection_release(); void con_restablish_cell_reselected(); void radio_link_failure(); static void* start_sib_thread(void *rrc_); void sib_search(); + void apply_rr_config_common_dl(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config); + void apply_rr_config_common_ul(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config); void apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2); void handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup); void handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup); diff --git a/srsue/hdr/upper/rrc_common.h b/srsue/hdr/upper/rrc_common.h index 95b909620..6d1186812 100644 --- a/srsue/hdr/upper/rrc_common.h +++ b/srsue/hdr/upper/rrc_common.h @@ -38,6 +38,8 @@ typedef enum { RRC_STATE_CELL_SELECTED, RRC_STATE_CONNECTING, RRC_STATE_CONNECTED, + RRC_STATE_HO_PREPARE, + RRC_STATE_HO_PROCESS, RRC_STATE_LEAVE_CONNECTED, RRC_STATE_N_ITEMS, } rrc_state_t; diff --git a/srsue/hdr/upper/usim.h b/srsue/hdr/upper/usim.h index fea15ba68..3b122d416 100644 --- a/srsue/hdr/upper/usim.h +++ b/srsue/hdr/upper/usim.h @@ -84,6 +84,15 @@ public: srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo); + void generate_as_keys_ho(uint32_t pci, + uint32_t earfcn, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int, + uint8_t *k_up_enc, + uint8_t *k_up_int, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo); + private: void gen_auth_res_milenage( uint8_t *rand, @@ -119,6 +128,7 @@ private: uint8_t autn[16]; uint8_t k_asme[32]; uint8_t k_enb[32]; + uint8_t k_enb_star[32]; bool initiated; diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc index 66adb5b0b..e543c0fd5 100644 --- a/srsue/src/mac/mac.cc +++ b/srsue/src/mac/mac.cc @@ -110,6 +110,15 @@ void mac::reconfiguration() } +void mac::wait_uplink() { + int cnt=0; + Info("Waiting to uplink...\n"); + while(mux_unit.is_pending_any_sdu() && cnt<20) { + usleep(1000); + cnt++; + } +} + // Implement Section 5.9 void mac::reset() { @@ -371,11 +380,31 @@ void mac::get_rntis(ue_rnti_t* rntis) memcpy(rntis, &uernti, sizeof(ue_rnti_t)); } +void mac::set_ho_rnti(uint16_t crnti, uint16_t target_pci) { + phy_h->pdcch_dl_search_reset(); + phy_h->pdcch_ul_search_reset(); + uernti.crnti = crnti; + if (pcap) { + printf("set_ue_id=%d\n", target_pci); + pcap->set_ue_id(target_pci); + } +} + void mac::set_contention_id(uint64_t uecri) { uernti.contention_id = uecri; } +void mac::start_noncont_ho(uint32_t preamble_index, uint32_t prach_mask) +{ + ra_procedure.start_noncont(preamble_index, prach_mask); +} + +void mac::start_cont_ho() +{ + ra_procedure.start_mac_order(56, true); +} + void mac::get_config(mac_cfg_t* mac_cfg) { memcpy(mac_cfg, &config, sizeof(mac_cfg_t)); diff --git a/srsue/src/mac/mux.cc b/srsue/src/mac/mux.cc index e38300b87..2b92061e9 100644 --- a/srsue/src/mac/mux.cc +++ b/srsue/src/mac/mux.cc @@ -62,7 +62,9 @@ void mux::init(rlc_interface_mac *rlc_, srslte::log *log_h_, bsr_interface_mux * void mux::reset() { - lch.clear(); + for (uint32_t i=0;iset_c_rnti(pending_crnti_ce)) { Warning("Pending C-RNTI CE could not be inserted in MAC PDU\n"); } } } + } else { + is_rar = true; } pending_crnti_ce = 0; @@ -200,44 +207,48 @@ uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32 } } - // Update buffer states for all logical channels - int sdu_space = pdu_msg.get_sdu_space(); - for (uint32_t i=0;iget_buffer_state(lch[i].id); - lch[i].sched_len = 0; - } - - // data from any Logical Channel, except data from UL-CCCH; - // first only those with positive Bj - for (uint32_t i=0;i= 0) { - lch[i].Bj -= lch[i].sched_len; + if (!is_rar) { + // Update buffer states for all logical channels + int sdu_space = pdu_msg.get_sdu_space(); + for (uint32_t i=0;iget_buffer_state(lch[i].id); + lch[i].sched_len = 0; + Info("lch[%d].buffer_len=%d\n",i,lch[i].buffer_len); + } + + + // data from any Logical Channel, except data from UL-CCCH; + // first only those with positive Bj + for (uint32_t i=0;i= 0) { + lch[i].Bj -= lch[i].sched_len; + } } } - } - // If resources remain, allocate regardless of their Bj value - for (uint32_t i=0;i 0) { - for (int i=(int)lch.size()-1;i>=0;i--) { - if (lch[i].sched_len > 0) { - lch[i].sched_len = -1; - break; + + // Maximize the grant utilization + if (lch.size() > 0) { + for (int i=(int)lch.size()-1;i>=0;i--) { + if (lch[i].sched_len > 0) { + lch[i].sched_len = -1; + break; + } } } - } - // Now allocate the SDUs from the RLC - for (uint32_t i=0;iinfo("Allocating scheduled lch=%d len=%d\n", lch[i].id, lch[i].sched_len); - allocate_sdu(lch[i].id, &pdu_msg, lch[i].sched_len); + // Now allocate the SDUs from the RLC + for (uint32_t i=0;iinfo("Allocating scheduled lch=%d len=%d\n", lch[i].id, lch[i].sched_len); + allocate_sdu(lch[i].id, &pdu_msg, lch[i].sched_len); + } } } @@ -262,7 +273,7 @@ uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32 } pthread_mutex_unlock(&mutex); - + return ret; } diff --git a/srsue/src/mac/proc_ra.cc b/srsue/src/mac/proc_ra.cc index 4bceef2a5..18548be23 100644 --- a/srsue/src/mac/proc_ra.cc +++ b/srsue/src/mac/proc_ra.cc @@ -96,9 +96,15 @@ void ra_proc::read_params() { // Read initialization parameters configIndex = mac_cfg->prach_config_index; - preambleIndex = 0; // pass when called from higher layers for non-contention based RA - maskIndex = 0; // same - nof_preambles = liblte_rrc_number_of_ra_preambles_num[mac_cfg->rach.num_ra_preambles]; + if (noncontention_enabled) { + preambleIndex = next_preamble_idx; + maskIndex = next_prach_mask; + noncontention_enabled = false; + } else { + preambleIndex = 0; // pass when called from higher layers for non-contention based RA + maskIndex = 0; // same + } + nof_preambles = liblte_rrc_number_of_ra_preambles_num[mac_cfg->rach.num_ra_preambles]; if (mac_cfg->rach.preambles_group_a_cnfg.present) { nof_groupA_preambles = liblte_rrc_size_of_ra_preambles_group_a_num[mac_cfg->rach.preambles_group_a_cnfg.size_of_ra]; } else { @@ -386,8 +392,13 @@ void ra_proc::step_response_reception() { } } -void ra_proc::step_response_error() { - +void ra_proc::step_response_error() +{ + if (ra_is_ho) { + state = RA_PROBLEM; + rrc->ho_ra_completed(false); + return; + } preambleTransmissionCounter++; if (preambleTransmissionCounter >= preambleTransMax + 1) { rError("Maximum number of transmissions reached (%d)\n", preambleTransMax); @@ -495,8 +506,11 @@ void ra_proc::step_completition() { phy_h->set_crnti(rntis->crnti); - msg3_transmitted = false; + msg3_transmitted = false; state = COMPLETION_DONE; + if (ra_is_ho) { + rrc->ho_ra_completed(true); + } } void ra_proc::step(uint32_t tti_) @@ -536,9 +550,17 @@ void ra_proc::step(uint32_t tti_) } } -void ra_proc::start_mac_order(uint32_t msg_len_bits) +void ra_proc::start_noncont(uint32_t preamble_index, uint32_t prach_mask) { + next_preamble_idx = preamble_index; + next_prach_mask = prach_mask; + noncontention_enabled = true; + start_mac_order(56, true); +} + +void ra_proc::start_mac_order(uint32_t msg_len_bits, bool is_ho) { if (state == IDLE || state == COMPLETION_DONE || state == RA_PROBLEM) { + ra_is_ho = is_ho; started_by_pdcch = false; new_ra_msg_len = msg_len_bits; state = INITIALIZATION; diff --git a/srsue/src/phy/phch_common.cc b/srsue/src/phy/phch_common.cc index 416f146ac..961080a56 100644 --- a/srsue/src/phy/phch_common.cc +++ b/srsue/src/phy/phch_common.cc @@ -47,27 +47,7 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) mac = NULL; max_mutex = max_mutex_; nof_mutex = 0; - sr_enabled = false; - is_first_of_burst = true; - is_first_tx = true; - rar_grant_pending = false; - pathloss = 0; - cur_pathloss = 0; - cur_pusch_power = 0; - p0_preamble = 0; - cur_radio_power = 0; - rx_gain_offset = 0; - sr_last_tx_tti = -1; - cur_pusch_power = 0; - - serving_cell_report_period = 20; - bzero(zeros, 50000*sizeof(cf_t)); - - // FIXME: This is an ungly fix to avoid the TX filters to empty - for (int i=0;i<50000;i++) { - zeros[i] = 0.01*cexpf(((float) i/50000)*0.1*_Complex_I); - } bzero(&dl_metrics, sizeof(dl_metrics_t)); dl_metrics_read = true; dl_metrics_count = 0; @@ -77,6 +57,16 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) bzero(&sync_metrics, sizeof(sync_metrics_t)); sync_metrics_read = true; sync_metrics_count = 0; + + bzero(zeros, 50000*sizeof(cf_t)); + + // FIXME: This is an ugly fix to avoid the TX filters to empty + for (int i=0;i<50000;i++) { + zeros[i] = 0.01*cexpf(((float) i/50000)*0.1*_Complex_I); + } + + reset(); + } void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args, srslte::log *_log, srslte::radio *_radio, rrc_interface_phy *_rrc, mac_interface_phy *_mac) @@ -224,6 +214,15 @@ bool phch_common::get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_ return pending_ack[TTIMOD(tti)].enabled; } +bool phch_common::is_any_pending_ack() { + for (int i=0;ierror("Cell HO: Can't find PCI=%d\n", cell.id); + return false; + } + + int cnt = 0; + while(worker_com->is_any_pending_ack() && cnt < 10) { + usleep(1000); + cnt++; + log_h->info("Cell HO: Waiting pending PHICH\n"); + } + + bool ret; + this->cell = cell; + Info("Cell HO: Stopping sync with current cell\n"); + worker_com->reset_ul(); + stop_sync(); + Info("Cell HO: Reconfiguring cell\n"); + if (set_cell()) { + Info("Cell HO: Synchronizing with new cell\n"); + resync_sfn(true, true); + ret = true; + } else { + log_h->error("Cell HO: Configuring cell PCI=%d\n", cell.id); + ret = false; + } + return ret; +} + bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) { // Check if we are already camping in this cell @@ -373,7 +406,7 @@ bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) { resync_sfn(); - usleep(500000); // Time offset we set start_rx to start receveing samples + usleep(500000); // Time offset we set start_rx to start receiving samples return true; } else { log_h->error("Cell Select: Configuring cell in EARFCN=%d, PCI=%d\n", earfcn, cell.id); @@ -443,10 +476,10 @@ void phch_recv::stop_rx() { radio_is_rx = false; } -void phch_recv::start_rx() { +void phch_recv::start_rx(bool now) { if (!radio_is_rx) { Info("SYNC: Starting RX streaming\n"); - radio_h->start_rx(); + radio_h->start_rx(now); } radio_is_rx = true; } @@ -626,7 +659,6 @@ void phch_recv::run_thread() workers_pool->start_worker(worker); intra_freq_meas.write(tti, buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb)); - break; case 0: log_h->error("SYNC: Sync error. Sending out-of-sync to RRC\n"); @@ -984,6 +1016,10 @@ float phch_recv::measure::snr() { return mean_snr; } +void phch_recv::measure::set_rx_gain_offset(float rx_gain_offset) { + this->rx_gain_offset = rx_gain_offset; +} + phch_recv::measure::ret_code phch_recv::measure::run_subframe_sync(srslte_ue_sync_t *ue_sync, uint32_t sf_idx) { int sync_res = srslte_ue_sync_zerocopy_multi(ue_sync, buffer); @@ -1023,7 +1059,7 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx) return ERROR; } - float rsrp = 10*log10(srslte_chest_dl_get_rsrp(&ue_dl.chest)) + 30; + float rsrp = 10*log10(srslte_chest_dl_get_rsrp(&ue_dl.chest)) + 30 - rx_gain_offset; float rsrq = 10*log10(srslte_chest_dl_get_rsrq(&ue_dl.chest)); float snr = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)); @@ -1081,7 +1117,7 @@ void phch_recv::scell_recv::reset() measure_p.reset(); } -int phch_recv::scell_recv::find_cells(cf_t *input_buffer, srslte_cell_t current_cell, uint32_t nof_sf, cell_info_t cells[MAX_CELLS]) +int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, srslte_cell_t current_cell, uint32_t nof_sf, cell_info_t cells[MAX_CELLS]) { uint32_t fft_sz = srslte_symbol_sz(current_cell.nof_prb); uint32_t sf_len = SRSLTE_SF_LEN(fft_sz); @@ -1100,6 +1136,8 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, srslte_cell_t current_ srslte_cell_t found_cell; memcpy(&found_cell, ¤t_cell, sizeof(srslte_cell_t)); + measure_p.set_rx_gain_offset(rx_gain_offset); + for (uint32_t n_id_2=0;n_id_2<3;n_id_2++) { if (current_cell.id%3 != n_id_2) { @@ -1164,10 +1202,12 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, srslte_cell_t current_ void phch_recv::meas_reset() { // Stop all measurements intra_freq_meas.clear_cells(); + worker_com->pcell_meas_enabled = false; } int phch_recv::meas_start(uint32_t earfcn, int pci) { if (earfcn == current_earfcn) { + worker_com->pcell_meas_enabled = true; intra_freq_meas.add_cell(pci); return 0; } else { @@ -1199,7 +1239,7 @@ void phch_recv::intra_measure::init(phch_common *common, rrc_interface_phy *rrc, search_buffer = (cf_t*) srslte_vec_malloc(CAPTURE_LEN_SF*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB)*sizeof(cf_t)); - if (srslte_ringbuffer_init(&ring_buffer, sizeof(cf_t)*50*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB))) { + if (srslte_ringbuffer_init(&ring_buffer, sizeof(cf_t)*100*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB))) { return; } @@ -1222,6 +1262,9 @@ void phch_recv::intra_measure::set_primay_cell(uint32_t earfcn, srslte_cell_t ce void phch_recv::intra_measure::clear_cells() { active_pci.clear(); receive_enabled = false; + receiving = false; + receive_cnt = 0; + srslte_ringbuffer_reset(&ring_buffer); } void phch_recv::intra_measure::add_cell(int pci) { @@ -1234,6 +1277,15 @@ void phch_recv::intra_measure::add_cell(int pci) { } } +int phch_recv::intra_measure::get_offset(uint32_t pci) { + for (int i=0;i::iterator newEnd = std::remove(active_pci.begin(), active_pci.end(), pci); @@ -1257,6 +1309,7 @@ void phch_recv::intra_measure::write(uint32_t tti, cf_t *data, uint32_t nsamples } if (receiving == true) { if (srslte_ringbuffer_write(&ring_buffer, data, nsamples*sizeof(cf_t)) < (int) (nsamples*sizeof(cf_t))) { + Warning("Error writing to ringbuffer\n"); receiving = false; srslte_ringbuffer_reset(&ring_buffer); } else { @@ -1282,12 +1335,11 @@ void phch_recv::intra_measure::run_thread() // Read 5 ms data from buffer srslte_ringbuffer_read(&ring_buffer, search_buffer, CAPTURE_LEN_SF*current_sflen*sizeof(cf_t)); - int found_cells = scell.find_cells(search_buffer, primary_cell, CAPTURE_LEN_SF, info); + int found_cells = scell.find_cells(search_buffer, common->rx_gain_offset, primary_cell, CAPTURE_LEN_SF, info); receiving = false; srslte_ringbuffer_reset(&ring_buffer); for (int i=0;irx_gain_offset; rrc->new_phy_meas(info[i].rsrp, info[i].rsrq, measure_tti, current_earfcn, info[i].pci); } // Look for other cells not found automatically diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 5d93d94a4..e811baefc 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -94,10 +94,11 @@ void phch_worker::reset() bzero(&pucch_sched, sizeof(srslte_pucch_sched_t)); bzero(&srs_cfg, sizeof(srslte_refsignal_srs_cfg_t)); bzero(&period_cqi, sizeof(srslte_cqi_periodic_cfg_t)); - I_sr = 0; + sr_configured = false; rnti_is_set = false; rar_cqi_request = false; - cfi = 0; + I_sr = 0; + cfi = 0; } void phch_worker::set_common(phch_common* phy_) @@ -801,7 +802,7 @@ void phch_worker::set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], bool tb_en[SRSLTE_ void phch_worker::set_uci_sr() { uci_data.scheduling_request = false; - if (phy->sr_enabled) { + if (phy->sr_enabled && sr_configured) { uint32_t sr_tx_tti = TTI_TX(tti); // Get I_sr parameter if (srslte_ue_ul_sr_send_tti(I_sr, sr_tx_tti)) { @@ -944,7 +945,8 @@ void phch_worker::encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, ui snprintf(timestr, 64, ", tot_time=%4d us", (int) logtime_start[0].tv_usec); #endif - Info("PUSCH: tti_tx=%d, alloc=(%d,%d), tbs=%d, mcs=%d, rv=%d, ack=%s, ri=%s, cfo=%.1f KHz%s\n", + uint8_t dummy[2] = {0,0}; + log_h->info_hex(payload?payload:dummy, payload?grant->mcs.tbs/8:1,"PUSCH: tti_tx=%d, alloc=(%d,%d), tbs=%d, mcs=%d, rv=%d, ack=%s, ri=%s, cfo=%.1f KHz%s\n", (tti+HARQ_DELAY_MS)%10240, grant->n_prb[0], grant->n_prb[0]+grant->L_prb, grant->mcs.tbs/8, grant->mcs.idx, rv, @@ -1144,7 +1146,7 @@ void phch_worker::set_ul_params(bool pregen_disabled) /* SR configuration */ I_sr = dedicated->sched_request_cnfg.sr_cnfg_idx; - + sr_configured = true; if (pregen_enabled && !pregen_disabled) { Info("Pre-generating UL signals worker=%d\n", get_id()); @@ -1253,7 +1255,7 @@ void phch_worker::update_measurements() } else { phy->avg_rsrp_db = SRSLTE_VEC_EMA(phy->avg_rsrp_db, rsrp, 0.8); } - if ((tti%phy->serving_cell_report_period) == 0) { + if ((tti%phy->pcell_report_period) == 0 && phy->pcell_meas_enabled) { phy->rrc->new_phy_meas(phy->avg_rsrp_db, phy->avg_rsrq_db, tti); } } diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index 7d3b8f311..880f8e609 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -206,15 +206,11 @@ void phy::set_timeadv(uint32_t ta_cmd) { void phy::configure_prach_params() { - if (sf_recv.status_is_sync()) { - Debug("Configuring PRACH parameters\n"); - srslte_cell_t cell; - sf_recv.get_current_cell(&cell); - if (!prach_buffer.set_cell(cell)) { - Error("Configuring PRACH parameters\n"); - } - } else { - Error("Cell is not synchronized\n"); + Debug("Configuring PRACH parameters\n"); + srslte_cell_t cell; + sf_recv.get_current_cell(&cell); + if (!prach_buffer.set_cell(cell)) { + Error("Configuring PRACH parameters\n"); } } @@ -264,6 +260,10 @@ bool phy::cell_select(uint32_t earfcn, srslte_cell_t phy_cell) return sf_recv.cell_select(earfcn, phy_cell); } +bool phy::cell_handover(srslte_cell_t cell) { + return sf_recv.cell_handover(cell); +} + float phy::get_phr() { float phr = radio_handler->get_max_tx_power() - workers_common.cur_pusch_power; @@ -321,6 +321,7 @@ void phy::reset() for(uint32_t i=0;itimer_get_unique_id(); t310 = mac_timers->timer_get_unique_id(); t311 = mac_timers->timer_get_unique_id(); + t304 = mac_timers->timer_get_unique_id(); transaction_id = 0; @@ -105,6 +106,8 @@ void rrc::init(phy_interface_rrc *phy_, nof_sib1_trials = 0; last_win_start = 0; + pending_mob_reconf = false; + // Set default values for all layers set_rrc_default(); set_phy_default(); @@ -232,6 +235,13 @@ void rrc::run_thread() { case RRC_STATE_CONNECTED: // Take measurements, cell reselection, etc break; + case RRC_STATE_HO_PREPARE: + ho_prepare(); + state = RRC_STATE_HO_PROCESS; + break; + case RRC_STATE_HO_PROCESS: + // wait for HO to finish + break; case RRC_STATE_LEAVE_CONNECTED: usleep(60000); rrc_log->info("Leaving RRC_CONNECTED state\n"); @@ -412,6 +422,9 @@ void rrc::select_next_cell_in_plmn() { { last_selected_cell = i; current_cell = &known_cells[i]; + rrc_log->info("Selected cell PCI=%d, EARFCN=%d, Cell ID=0x%x, addr=0x%x\n", + current_cell->phy_cell.id, current_cell->earfcn, + current_cell->sib1.cell_id, current_cell); return; } else { rrc_log->warning("Selecting cell EARFCN=%d, Cell ID=0x%x.\n", @@ -433,17 +446,17 @@ void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { // find if cell_id-earfcn combination already exists for (uint32_t i = 0; i < known_cells.size(); i++) { if (earfcn == known_cells[i].earfcn && phy_cell.id == known_cells[i].phy_cell.id) { - known_cells[i].rsrp = rsrp; - known_cells[i].in_sync = true; current_cell = &known_cells[i]; - rrc_log->info("Updating cell EARFCN=%d, PCI=%d, RSRP=%.1f dBm\n", known_cells[i].earfcn, - known_cells[i].phy_cell.id, known_cells[i].rsrp); + current_cell->rsrp = rsrp; + current_cell->in_sync = true; + rrc_log->info("Updating cell EARFCN=%d, PCI=%d, RSRP=%.1f dBm\n", current_cell->earfcn, + current_cell->phy_cell.id, current_cell->rsrp); - if (!known_cells[i].has_valid_sib1) { + if (!current_cell->has_valid_sib1) { si_acquire_state = SI_ACQUIRE_SIB1; } 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); + for (uint32_t j = 0; j < current_cell->sib1.N_plmn_ids; j++) { + nas->plmn_found(current_cell->sib1.plmn_id[j].id, current_cell->sib1.tracking_area_code); } usleep(5000); phy->cell_search_next(); @@ -465,9 +478,9 @@ void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { si_acquire_state = SI_ACQUIRE_SIB1; - rrc_log->info("New Cell: PCI=%d, PRB=%d, Ports=%d, EARFCN=%d, RSRP=%.1f dBm\n", - cell.phy_cell.id, cell.phy_cell.nof_prb, cell.phy_cell.nof_ports, - cell.earfcn, cell.rsrp); + rrc_log->info("New Cell: PCI=%d, PRB=%d, Ports=%d, EARFCN=%d, RSRP=%.1f dBm, addr=0x%x\n", + current_cell->phy_cell.id, current_cell->phy_cell.nof_prb, current_cell->phy_cell.nof_ports, + current_cell->earfcn, current_cell->rsrp, current_cell); } // PHY indicates that has gone through all known EARFCN @@ -480,7 +493,22 @@ void rrc::earfcn_end() { } } - +void rrc::add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp) { + for (uint32_t i = 0; i < known_cells.size(); i++) { + if (earfcn == known_cells[i].earfcn && pci == known_cells[i].phy_cell.id) { + known_cells[i].rsrp = rsrp; + return; + } + } + rrc_log->info("Added neighbour cell earfcn=%d, pci=%d, rsrp=%f\n", earfcn, pci, rsrp); + cell_t c; + bzero(&c, sizeof(cell_t)); + c.earfcn = earfcn; + c.rsrp = rsrp; + memcpy(&c.phy_cell, ¤t_cell->phy_cell, sizeof(srslte_cell_t)); + c.phy_cell.id = pci; + known_cells.push_back(c); +} @@ -572,6 +600,8 @@ void rrc::timer_expired(uint32_t timeout_id) { } else if (timeout_id == t301) { rrc_log->info("Timer T301 expired: Going to RRC IDLE\n"); state = RRC_STATE_LEAVE_CONNECTED; + } else if (timeout_id == t304) { + rrc_log->console("Timer T304 expired: Handover failed\n"); // fw to measurement } else if (!measurements.timer_expired(timeout_id)) { rrc_log->error("Timeout from unknown timer id %d\n", timeout_id); @@ -777,40 +807,134 @@ void rrc::send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu) { send_ul_dcch_msg(pdu); } -void rrc::send_rrc_con_reconfig_complete(uint32_t lcid, byte_buffer_t *pdu) { +void rrc::send_rrc_con_reconfig_complete(byte_buffer_t *pdu) { rrc_log->debug("Preparing RRC Connection Reconfig Complete\n"); ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_RECONFIG_COMPLETE; ul_dcch_msg.msg.rrc_con_reconfig_complete.rrc_transaction_id = transaction_id; - send_ul_dcch_msg(); + send_ul_dcch_msg(pdu); +} + +void rrc::ho_prepare() { + if (pending_mob_reconf) { + rrc_log->info("Processing HO command to target PCell=%d\n", mob_reconf.mob_ctrl_info.target_pci); + + // Section 5.3.5.4 + mac_timers->timer_get(t310)->stop(); + mac_timers->timer_get(t304)->set(this, liblte_rrc_t304_num[mob_reconf.mob_ctrl_info.t304]); + if (mob_reconf.mob_ctrl_info.carrier_freq_eutra_present && + mob_reconf.mob_ctrl_info.carrier_freq_eutra.dl_carrier_freq != current_cell->earfcn) { + rrc_log->warning("Received mobilityControlInfo for inter-frequency handover\n"); + } + + phy->meas_reset(); + mac->wait_uplink(); + pdcp->reestablish(); + rlc->reestablish(); + mac->reset(); + phy->reset(); + mac->set_ho_rnti(mob_reconf.mob_ctrl_info.new_ue_id, mob_reconf.mob_ctrl_info.target_pci); + apply_rr_config_common_dl(&mob_reconf.mob_ctrl_info.rr_cnfg_common); + + uint32_t current_earfcn = 0; + phy->get_current_cell(NULL, ¤t_earfcn); + + bool found = false; + for (uint32_t i = 0; i < known_cells.size(); i++) { + rrc_log->info("cell[%d]=%d:%d, cur_earfcn=%d\n", i, known_cells[i].earfcn, known_cells[i].phy_cell.id, + current_cell->earfcn); + if (known_cells[i].earfcn == current_earfcn && + known_cells[i].phy_cell.id == mob_reconf.mob_ctrl_info.target_pci) { + rrc_log->info("Selecting new cell pci=%d\n", known_cells[i].phy_cell.id); + if (!phy->cell_handover(known_cells[i].phy_cell)) { + rrc_log->error("Could not synchronize with target cell pci=%d\n", known_cells[i].phy_cell.id); + } + found = true; + break; + } + } + if (!found) { + rrc_log->error("Could not find target cell pci=%d\n", mob_reconf.mob_ctrl_info.target_pci); + return; + } + + if (mob_reconf.mob_ctrl_info.rach_cnfg_ded_present) { + mac->start_noncont_ho(mob_reconf.mob_ctrl_info.rach_cnfg_ded.preamble_index, + mob_reconf.mob_ctrl_info.rach_cnfg_ded.prach_mask_index); + } else { + mac->start_cont_ho(); + } + + printf("ncc=%d\n", mob_reconf.sec_cnfg_ho.intra_lte.next_hop_chaining_count); + usim->generate_as_keys_ho(mob_reconf.mob_ctrl_info.target_pci, current_earfcn, + k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); + pdcp->config_security(1, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); + send_rrc_con_reconfig_complete(NULL); + } } +void rrc::ho_ra_completed(bool ra_successful) { + if (pending_mob_reconf) { + + measurements.ho_finish(); + + if (mob_reconf.meas_cnfg_present) { + measurements.parse_meas_config(&mob_reconf.meas_cnfg); + } + + if (ra_successful) { + mac_timers->timer_get(t304)->stop(); + + apply_rr_config_common_ul(&mob_reconf.mob_ctrl_info.rr_cnfg_common); + if (mob_reconf.rr_cnfg_ded_present) { + apply_rr_config_dedicated(&mob_reconf.rr_cnfg_ded); + } + } + + rrc_log->info("HO %ssuccessful\n", ra_successful?"":"un"); + rrc_log->console("HO %ssuccessful\n", ra_successful?"":"un"); + + pending_mob_reconf = false; + state = RRC_STATE_CONNECTED; + } else { + rrc_log->error("Received HO random access completed but no pending mobility reconfiguration info\n"); + } +} void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig, byte_buffer_t *pdu) { uint32_t i; - if (reconfig->rr_cnfg_ded_present) { - apply_rr_config_dedicated(&reconfig->rr_cnfg_ded); - } else { - printf("received con reconfig no rr confg present\n"); - } - if (reconfig->meas_cnfg_present) { - measurements.parse_meas_config(&reconfig->meas_cnfg); - } if (reconfig->mob_ctrl_info_present) { - //TODO: handle mob_ctrl_info - } - send_rrc_con_reconfig_complete(lcid, pdu); + rrc_log->info("Received HO command to target PCell=%d\n", reconfig->mob_ctrl_info.target_pci); + rrc_log->console("Received HO command to target PCell=%d\n", reconfig->mob_ctrl_info.target_pci); + + // store mobilityControlInfo + memcpy(&mob_reconf, reconfig, sizeof(LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT)); + pending_mob_reconf = true; + + state = RRC_STATE_HO_PREPARE; + + } else { + // Section 5.3.5.3 + if (reconfig->rr_cnfg_ded_present) { + apply_rr_config_dedicated(&reconfig->rr_cnfg_ded); + } + if (reconfig->meas_cnfg_present) { + measurements.parse_meas_config(&reconfig->meas_cnfg); + } + + send_rrc_con_reconfig_complete(pdu); - byte_buffer_t *nas_sdu; - for (i = 0; i < reconfig->N_ded_info_nas; i++) { - nas_sdu = pool_allocate; - memcpy(nas_sdu->msg, &reconfig->ded_info_nas_list[i].msg, reconfig->ded_info_nas_list[i].N_bytes); - nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes; - nas->write_pdu(lcid, nas_sdu); + byte_buffer_t *nas_sdu; + for (i = 0; i < reconfig->N_ded_info_nas; i++) { + nas_sdu = pool_allocate; + memcpy(nas_sdu->msg, &reconfig->ded_info_nas_list[i].msg, reconfig->ded_info_nas_list[i].N_bytes); + nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes; + nas->write_pdu(lcid, nas_sdu); + } } } @@ -1022,7 +1146,7 @@ void rrc::send_ul_dcch_msg(byte_buffer_t *pdu) } void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { - rrc_log->info_hex(sdu->msg, sdu->N_bytes, "RX %s SDU", get_rb_name(lcid).c_str()); + rrc_log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU", get_rb_name(lcid).c_str()); switch (state) { case RRC_STATE_CONNECTING: send_con_setup_complete(sdu); @@ -1037,8 +1161,8 @@ void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { } void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { - rrc_log->info_hex(pdu->msg, pdu->N_bytes, "TX %s PDU", get_rb_name(lcid).c_str()); - rrc_log->info("TX PDU Stack latency: %ld us\n", pdu->get_latency_us()); + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", get_rb_name(lcid).c_str()); + rrc_log->info("RX PDU Stack latency: %ld us\n", pdu->get_latency_us()); switch (lcid) { case RB_ID_SRB0: @@ -1049,7 +1173,7 @@ void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { parse_dl_dcch(lcid, pdu); break; default: - rrc_log->error("TX PDU with invalid bearer id: %s", lcid); + rrc_log->error("RX PDU with invalid bearer id: %s", lcid); break; } } @@ -1265,6 +1389,54 @@ void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) { * *******************************************************************************/ +void rrc::apply_rr_config_common_dl(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config) { + mac_interface_rrc::mac_cfg_t mac_cfg; + mac->get_config(&mac_cfg); + if (config->rach_cnfg_present) { + memcpy(&mac_cfg.rach, &config->rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT)); + } + mac_cfg.prach_config_index = config->prach_cnfg.root_sequence_index; + mac_cfg.ul_harq_params.max_harq_msg3_tx = config->rach_cnfg.max_harq_msg3_tx; + + mac->set_config(&mac_cfg); + + phy_interface_rrc::phy_cfg_t phy_cfg; + phy->get_config(&phy_cfg); + phy_interface_rrc::phy_cfg_common_t *common = &phy_cfg.common; + + if (config->pdsch_cnfg_present) { + memcpy(&common->pdsch_cnfg, &config->pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT)); + } + common->prach_cnfg.root_sequence_index = config->prach_cnfg.root_sequence_index; + if (config->prach_cnfg.prach_cnfg_info_present) { + memcpy(&common->prach_cnfg.prach_cnfg_info, &config->prach_cnfg.prach_cnfg_info, sizeof(LIBLTE_RRC_PRACH_CONFIG_INFO_STRUCT)); + } + + phy->set_config_common(common); +} + +void rrc::apply_rr_config_common_ul(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config) { + phy_interface_rrc::phy_cfg_t phy_cfg; + phy->get_config(&phy_cfg); + phy_interface_rrc::phy_cfg_common_t *common = &phy_cfg.common; + + memcpy(&common->pusch_cnfg, &config->pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT)); + if (config->pucch_cnfg_present) { + memcpy(&common->pucch_cnfg, &config->pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT)); + } + if (config->ul_pwr_ctrl_present) { + memcpy(&common->ul_pwr_ctrl, &config->ul_pwr_ctrl, sizeof(LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT)); + } + if (config->srs_ul_cnfg.present) { + memcpy(&common->srs_ul_cnfg, &config->srs_ul_cnfg, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT)); + } else { + // default is release + common->srs_ul_cnfg.present = false; + } + phy->set_config_common(common); + phy->configure_ul_params(); +} + void rrc::apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) { // Apply RACH timeAlginmentTimer configuration @@ -1800,6 +1972,9 @@ void rrc::rrc_meas::new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, floa if (earfcn == 0) { L3_filter(&pcell_measurement, values); } else { + // Add to known cells + parent->add_neighbour_cell(earfcn, pci, rsrp); + // Save PHY measurement for all active measurements whose earfcn/pci matches for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { meas_t *m = &iter->second; @@ -1815,6 +1990,7 @@ void rrc::rrc_meas::new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, floa return; } } + parent->rrc_log->warning("MEAS: Received measurement from unknown EARFCN=%d\n", earfcn); } } @@ -1866,7 +2042,7 @@ void rrc::rrc_meas::generate_report(uint32_t meas_id) report->pcell_rsrp_result = value_to_range(RSRP, pcell_measurement.ms[RSRP]); report->pcell_rsrq_result = value_to_range(RSRQ, pcell_measurement.ms[RSRQ]); - log_h->console("MEAS: Generate report MeasId=%d, rsrp=%f rsrq=%f\n", + log_h->info("MEAS: Generate report MeasId=%d, rsrp=%f rsrq=%f\n", report->meas_id, pcell_measurement.ms[RSRP], pcell_measurement.ms[RSRQ]); // TODO: report up to 8 best cells @@ -1882,7 +2058,7 @@ void rrc::rrc_meas::generate_report(uint32_t meas_id) rc->meas_result.rsrp_result = value_to_range(RSRP, cell->second.ms[RSRP]); rc->meas_result.rsrq_result = value_to_range(RSRQ, cell->second.ms[RSRQ]); - log_h->console("MEAS: Add neigh=%d, pci=%d, rsrp=%f, rsrq=%f\n", + log_h->info("MEAS: Add neigh=%d, pci=%d, rsrp=%f, rsrq=%f\n", report->meas_result_neigh_cells.eutra.n_result, rc->phys_cell_id, cell->second.ms[RSRP], cell->second.ms[RSRQ]); @@ -2037,6 +2213,26 @@ void rrc::rrc_meas::calculate_triggers(uint32_t tti) } } +// Procedure upon handover or reestablishment 5.5.6.1 +void rrc::rrc_meas::ho_finish() { + // Remove all measId with trigger periodic + std::map::iterator iter = active.begin(); + while (iter != active.end()) { + if (reports_cfg[iter->second.report_id].trigger_type == report_cfg_t::PERIODIC) { + remove_meas_id(iter++); + } else { + ++iter; + } + } + + //TODO: Inter-frequency handover + + // Stop all reports + for (std::map::iterator iter = active.begin(); iter != active.end(); ++iter) { + stop_reports(&iter->second); + } +} + // 5.5.4.1 expiry of periodical reporting timer bool rrc::rrc_meas::timer_expired(uint32_t timer_id) { for (std::map::iterator iter = active.begin(); iter != active.end(); ++iter) { @@ -2048,41 +2244,53 @@ bool rrc::rrc_meas::timer_expired(uint32_t timer_id) { return false; } +void rrc::rrc_meas::stop_reports(meas_t *m) { + mac_timers->timer_get(m->periodic_timer)->stop(); + m->triggered = false; +} + void rrc::rrc_meas::stop_reports_object(uint32_t object_id) { for (std::map::iterator iter = active.begin(); iter != active.end(); ++iter) { - meas_t *m = &iter->second; - if (m->object_id == object_id) { - mac_timers->timer_get(m->periodic_timer)->stop(); - m->triggered = false; + if (iter->second.object_id == object_id) { + stop_reports(&iter->second); } } } void rrc::rrc_meas::remove_meas_object(uint32_t object_id) { - // CHECKME: Is the delete from the map correct? - for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { - meas_t m = iter->second; - if (m.object_id == object_id) { - remove_meas_id(iter->first); + std::map::iterator iter = active.begin(); + while (iter != active.end()) { + if (iter->second.object_id == object_id) { + remove_meas_id(iter++); + } else { + ++iter; } } } void rrc::rrc_meas::remove_meas_report(uint32_t report_id) { - // CHECKME: Is the delete from the map correct? - for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { - meas_t m = iter->second; - if (m.report_id == report_id) { - remove_meas_id(iter->first); + std::map::iterator iter = active.begin(); + while (iter != active.end()) { + if (iter->second.report_id == report_id) { + remove_meas_id(iter++); + } else { + ++iter; } } } -void rrc::rrc_meas::remove_meas_id(uint32_t meas_id) { - mac_timers->timer_get(active[meas_id].periodic_timer)->stop(); - mac_timers->timer_release_id(active[meas_id].periodic_timer); - active.erase(meas_id); - log_h->info("MEAS: Removed measId=%d\n", meas_id); +void rrc::rrc_meas::remove_meas_id(uint32_t measId) { + mac_timers->timer_get(active[measId].periodic_timer)->stop(); + mac_timers->timer_release_id(active[measId].periodic_timer); + log_h->info("MEAS: Removed measId=%d\n", measId); + active.erase(measId); +} + +void rrc::rrc_meas::remove_meas_id(std::map::iterator it) { + mac_timers->timer_get(it->second.periodic_timer)->stop(); + mac_timers->timer_release_id(it->second.periodic_timer); + log_h->info("MEAS: Removed measId=%d\n", it->first); + active.erase(it); } /* Parses MeasConfig object from RRCConnectionReconfiguration message and applies configuration @@ -2091,28 +2299,6 @@ void rrc::rrc_meas::remove_meas_id(uint32_t meas_id) { void rrc::rrc_meas::parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *cfg) { - // Measurement identity removal 5.5.2.2 - for (uint32_t i=0;iN_meas_id_to_remove;i++) { - remove_meas_id(cfg->meas_id_to_remove_list[i]); - } - - // Measurement identity addition/modification 5.5.2.3 - if (cfg->meas_id_to_add_mod_list_present) { - for (uint32_t i=0;imeas_id_to_add_mod_list.N_meas_id;i++) { - LIBLTE_RRC_MEAS_ID_TO_ADD_MOD_STRUCT *measId = &cfg->meas_id_to_add_mod_list.meas_id_list[i]; - // Stop the timer if the entry exists or create the timer if not - if (active.count(measId->meas_id)) { - mac_timers->timer_get(active[measId->meas_id].periodic_timer)->stop(); - } else { - active[measId->meas_id].periodic_timer = mac_timers->timer_get_unique_id(); - } - active[measId->meas_id].object_id = measId->meas_obj_id; - active[measId->meas_id].report_id = measId->rep_cnfg_id; - log_h->info("MEAS: Added measId=%d, measObjectId=%d, reportConfigId=%d\n", - measId->meas_id, measId->meas_obj_id, measId->rep_cnfg_id); - } - } - // Measurement object removal 5.5.2.4 for (uint32_t i=0;iN_meas_obj_to_remove;i++) { objects.erase(cfg->meas_obj_to_remove_list[i]); @@ -2196,11 +2382,9 @@ void rrc::rrc_meas::parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *cfg) // Reset reports counter for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { - meas_t m = iter->second; - if (m.report_id == cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_id) { + if (iter->second.report_id == cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_id) { iter->second.nof_reports_sent = 0; - m.triggered = false; - mac_timers->timer_get(m.periodic_timer)->stop(); + stop_reports(&iter->second); } } } else { @@ -2227,6 +2411,28 @@ void rrc::rrc_meas::parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *cfg) log_h->info("MEAS: Quantity configuration k_rsrp=%d, k_rsrq=%d\n", filter_k_rsrp, filter_k_rsrq); } + // Measurement identity removal 5.5.2.2 + for (uint32_t i=0;iN_meas_id_to_remove;i++) { + remove_meas_id(cfg->meas_id_to_remove_list[i]); + } + + // Measurement identity addition/modification 5.5.2.3 + if (cfg->meas_id_to_add_mod_list_present) { + for (uint32_t i=0;imeas_id_to_add_mod_list.N_meas_id;i++) { + LIBLTE_RRC_MEAS_ID_TO_ADD_MOD_STRUCT *measId = &cfg->meas_id_to_add_mod_list.meas_id_list[i]; + // Stop the timer if the entry exists or create the timer if not + if (active.count(measId->meas_id)) { + mac_timers->timer_get(active[measId->meas_id].periodic_timer)->stop(); + } else { + active[measId->meas_id].periodic_timer = mac_timers->timer_get_unique_id(); + } + active[measId->meas_id].object_id = measId->meas_obj_id; + active[measId->meas_id].report_id = measId->rep_cnfg_id; + log_h->info("MEAS: Added measId=%d, measObjectId=%d, reportConfigId=%d\n", + measId->meas_id, measId->meas_obj_id, measId->rep_cnfg_id); + } + } + // S-Measure if (cfg->s_meas_present) { if (cfg->s_meas) { diff --git a/srsue/src/upper/usim.cc b/srsue/src/upper/usim.cc index e1d2c204f..842f9b361 100644 --- a/srsue/src/upper/usim.cc +++ b/srsue/src/upper/usim.cc @@ -222,6 +222,7 @@ void usim::generate_as_keys(uint32_t count_ul, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) { + // Generate K_enb security_generate_k_enb( k_asme, count_ul, @@ -242,6 +243,39 @@ void usim::generate_as_keys(uint32_t count_ul, k_up_int); } +void usim::generate_as_keys_ho(uint32_t pci, + uint32_t earfcn, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int, + uint8_t *k_up_enc, + uint8_t *k_up_int, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo) +{ + + // Generate K_enb + security_generate_k_enb_star( k_enb, + pci, + earfcn, + k_enb_star); + + memcpy(k_enb, k_enb_star, 32); + + // Generate K_rrc_enc and K_rrc_int + security_generate_k_rrc( k_enb, + cipher_algo, + integ_algo, + k_rrc_enc, + k_rrc_int); + + // Generate K_up_enc and K_up_int + security_generate_k_up( k_enb, + cipher_algo, + integ_algo, + k_up_enc, + k_up_int); +} + /******************************************************************************* Helpers *******************************************************************************/ From 5b46174b5b01f41cd419870c1243d295c5cdf1d2 Mon Sep 17 00:00:00 2001 From: Paul Sutton Date: Wed, 1 Nov 2017 13:43:49 +0000 Subject: [PATCH 07/42] Adding RRC logic to receive all SIBs --- srsue/hdr/upper/rrc.h | 17 +++- srsue/src/upper/rrc.cc | 191 +++++++++++++++++++++++++---------------- 2 files changed, 133 insertions(+), 75 deletions(-) diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index 0e77e29b0..7b903f0d9 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -196,9 +196,13 @@ private: float rsrp; bool has_valid_sib1; bool has_valid_sib2; + bool has_valid_sib3; + bool has_valid_sib13; bool in_sync; - LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1; - LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT sib3; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT sib13; } cell_t; std::vector known_cells; @@ -212,8 +216,9 @@ private: si_acquire_state_t si_acquire_state; void run_si_acquisition_procedure(); - uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x); + uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t offset, uint32_t sf); uint32_t nof_sib1_trials; + uint16_t sysinfo_index; uint32_t last_win_start; void select_next_cell_in_plmn(); @@ -365,10 +370,16 @@ private: void rrc_connection_release(); void con_restablish_cell_reselected(); void radio_link_failure(); + static void* start_sib_thread(void *rrc_); void sib_search(); void apply_rr_config_common_dl(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config); void apply_rr_config_common_ul(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config); + void handle_sib1(); + void handle_sib2(); + void handle_sib3(); + void handle_sib13(); + void apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2); void handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup); void handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup); diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 39aa8825d..9f2f53f38 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -47,6 +47,7 @@ namespace srsue { rrc::rrc() :state(RRC_STATE_IDLE) ,drb_up(false) + ,sysinfo_index(0) { sync_reset_cnt = 0; n310_cnt = 0; @@ -204,12 +205,7 @@ void rrc::run_thread() { if (phy->sync_status()) { if (!current_cell->has_valid_sib1) { si_acquire_state = SI_ACQUIRE_SIB1; - } else if (!current_cell->has_valid_sib2) { - si_acquire_state = SI_ACQUIRE_SIB2; - } else { - apply_sib2_configs(¤t_cell->sib2); - si_acquire_state = SI_ACQUIRE_IDLE; - state = RRC_STATE_CELL_SELECTED; + sysinfo_index = 0; } } select_cell_timeout++; @@ -289,8 +285,8 @@ void rrc::run_thread() { // Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message -uint32_t rrc::sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) { - return (period * 10 * (1 + tti / (period * 10)) + x) % 10240; // the 1 means next opportunity +uint32_t rrc::sib_start_tti(uint32_t tti, uint32_t period, uint32_t offset, uint32_t sf) { + return (period*10*(1+tti/(period*10))+(offset*10)+sf)%10240; // the 1 means next opportunity } void rrc::run_si_acquisition_procedure() @@ -298,13 +294,14 @@ void rrc::run_si_acquisition_procedure() uint32_t tti; uint32_t si_win_start=0, si_win_len=0; uint16_t period; + uint32_t x, sf, offset; const int SIB1_SEARCH_TIMEOUT = 30; switch (si_acquire_state) { case SI_ACQUIRE_SIB1: // Instruct MAC to look for SIB1 tti = mac->get_current_tti(); - si_win_start = sib_start_tti(tti, 2, 5); + si_win_start = sib_start_tti(tti, 2, 0, 5); if (tti > last_win_start + 10) { last_win_start = si_win_start; mac->bcch_start_rx(si_win_start, 1); @@ -323,17 +320,30 @@ void rrc::run_si_acquisition_procedure() } break; case SI_ACQUIRE_SIB2: - // Instruct MAC to look for SIB2 only when selecting a cell - tti = mac->get_current_tti(); - period = liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[0].si_periodicity]; - si_win_start = sib_start_tti(tti, period, 0); - if (tti > last_win_start + 10) { - last_win_start = si_win_start; - si_win_len = liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length]; + // Instruct MAC to look for next SIB + if(sysinfo_index < current_cell->sib1.N_sched_info) { + si_win_len = liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length]; + x = sysinfo_index*si_win_len; + sf = x%10; + offset = x/10; + + tti = mac->get_current_tti(); + period = liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[sysinfo_index].si_periodicity]; + si_win_start = sib_start_tti(tti, period, offset, sf); + + if (tti > last_win_start + 10) { + last_win_start = si_win_start; + si_win_len = liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length]; + + mac->bcch_start_rx(si_win_start, si_win_len); + rrc_log->debug("Instructed MAC to search for system info, win_start=%d, win_len=%d\n", + si_win_start, si_win_len); + } - mac->bcch_start_rx(si_win_start, si_win_len); - rrc_log->debug("Instructed MAC to search for SIB2, win_start=%d, win_len=%d\n", - si_win_start, si_win_len); + } else { + // We've received all SIBs, move on to connection request + si_acquire_state = SI_ACQUIRE_IDLE; + state = RRC_STATE_CELL_SELECTED; } break; default: @@ -984,6 +994,8 @@ void rrc::write_pdu_bcch_bch(byte_buffer_t *pdu) { } void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu) { + mac->bcch_stop_rx(); + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH DLSCH message received."); rrc_log->info("BCCH DLSCH message Stack latency: %ld us\n", pdu->get_latency_us()); LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg; @@ -992,74 +1004,104 @@ void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu) { pool->deallocate(pdu); liblte_rrc_unpack_bcch_dlsch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &dlsch_msg); - if (dlsch_msg.N_sibs > 0) { - if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[0].sib_type && SI_ACQUIRE_SIB1 == si_acquire_state) { - mac->bcch_stop_rx(); - - // Handle SIB1 - memcpy(¤t_cell->sib1, &dlsch_msg.sibs[0].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT)); + for(uint32_t i=0; iinfo("Processing SIB: %d\n", liblte_rrc_sys_info_block_type_num[dlsch_msg.sibs[i].sib_type]); - rrc_log->info("SIB1 received, CellID=%d, si_window=%d, sib2_period=%d\n", - current_cell->sib1.cell_id & 0xfff, - liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length], - liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[0].si_periodicity]); + if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[i].sib_type && SI_ACQUIRE_SIB1 == si_acquire_state) { + memcpy(¤t_cell->sib1, &dlsch_msg.sibs[i].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT)); + current_cell->has_valid_sib1 = true; + handle_sib1(); + } else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[i].sib_type && !current_cell->has_valid_sib2) { + memcpy(¤t_cell->sib2, &dlsch_msg.sibs[i].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT)); + current_cell->has_valid_sib2 = true; + handle_sib2(); + } else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3 == dlsch_msg.sibs[i].sib_type && !current_cell->has_valid_sib3) { + memcpy(¤t_cell->sib3, &dlsch_msg.sibs[i].sib.sib3, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT)); + current_cell->has_valid_sib3 = true; + handle_sib3(); + }else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13 == dlsch_msg.sibs[i].sib_type && !current_cell->has_valid_sib13) { + memcpy(¤t_cell->sib13, &dlsch_msg.sibs[0].sib.sib13, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT)); + current_cell->has_valid_sib13 = true; + handle_sib13(); + } + } + if(current_cell->has_valid_sib2) { + sysinfo_index++; + } +} +void rrc::handle_sib1() +{ + rrc_log->info("SIB1 received, CellID=%d, si_window=%d, sib2_period=%d\n", + current_cell->sib1.cell_id&0xfff, + liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length], + liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[0].si_periodicity]); + + // Print SIB scheduling info + uint32_t i,j; + for(i=0;isib1.N_sched_info;i++){ + for(j=0;jsib1.sched_info[i].N_sib_mapping_info;j++){ + LIBLTE_RRC_SIB_TYPE_ENUM t = current_cell->sib1.sched_info[i].sib_mapping_info[j].sib_type; + LIBLTE_RRC_SI_PERIODICITY_ENUM p = current_cell->sib1.sched_info[i].si_periodicity; + rrc_log->debug("SIB scheduling info, sib_type=%d, si_periodicity=%d\n", + liblte_rrc_sib_type_num[t], + liblte_rrc_si_periodicity_num[p]); + } + } - // Set TDD Config - if (current_cell->sib1.tdd) { - phy->set_config_tdd(¤t_cell->sib1.tdd_cnfg); - } + // Set TDD Config + if(current_cell->sib1.tdd) { + phy->set_config_tdd(¤t_cell->sib1.tdd_cnfg); + } - current_cell->has_valid_sib1 = true; + current_cell->has_valid_sib1 = true; - // Send PLMN and TAC to NAS - std::stringstream ss; - 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); - } + // Send PLMN and TAC to NAS + std::stringstream ss; + 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); + } - // Jump to next state - switch(state) { - case RRC_STATE_CELL_SELECTING: - si_acquire_state = SI_ACQUIRE_SIB2; - break; - case RRC_STATE_PLMN_SELECTION: - si_acquire_state = SI_ACQUIRE_IDLE; - rrc_log->info("SI Acquisition done. Searching next cell...\n"); - usleep(5000); - phy->cell_search_next(); - break; - default: - si_acquire_state = SI_ACQUIRE_IDLE; - } + // Jump to next state + switch(state) { + case RRC_STATE_CELL_SELECTING: + si_acquire_state = SI_ACQUIRE_SIB2; + break; + case RRC_STATE_PLMN_SELECTION: + si_acquire_state = SI_ACQUIRE_IDLE; + rrc_log->info("SI Acquisition done. Searching next cell...\n"); + usleep(5000); + phy->cell_search_next(); + break; + default: + si_acquire_state = SI_ACQUIRE_IDLE; + } +} - } else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[0].sib_type && - SI_ACQUIRE_SIB2 == si_acquire_state) { - mac->bcch_stop_rx(); +void rrc::handle_sib2() +{ + rrc_log->info("SIB2 received\n"); - // Handle SIB2 - memcpy(¤t_cell->sib2, &dlsch_msg.sibs[0].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT)); - rrc_log->info("SIB2 received\n"); + apply_sib2_configs(¤t_cell->sib2); +} - apply_sib2_configs(¤t_cell->sib2); +void rrc::handle_sib3() +{ + rrc_log->info("SIB3 received\n"); +} - current_cell->has_valid_sib2 = true; +void rrc::handle_sib13() +{ + rrc_log->info("SIB13 received\n"); - // Jump to next state - switch(state) { - case RRC_STATE_CELL_SELECTING: - si_acquire_state = SI_ACQUIRE_IDLE; - state = RRC_STATE_CELL_SELECTED; - break; - default: - si_acquire_state = SI_ACQUIRE_IDLE; - } - } - } +// mac->set_config_mbsfn_sib13(¤t_cell->sib13.mbsfn_area_info_list_r9[0], +// current_cell->sib13.mbsfn_area_info_list_r9_size, +// ¤t_cell->sib13.mbsfn_notification_config); } + /******************************************************************************* * * @@ -1449,6 +1491,11 @@ void rrc::apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) { memcpy(&cfg.rach, &sib2->rr_config_common_sib.rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT)); cfg.prach_config_index = sib2->rr_config_common_sib.prach_cnfg.root_sequence_index; cfg.ul_harq_params.max_harq_msg3_tx = cfg.rach.max_harq_msg3_tx; + // Apply MBSFN configuration +// cfg.mbsfn_subfr_cnfg_list_size = sib2->mbsfn_subfr_cnfg_list_size; +// for(uint8_t i=0;imbsfn_subfr_cnfg_list_size;i++) { +// memcpy(&cfg.mbsfn_subfr_cnfg_list[i], &sib2->mbsfn_subfr_cnfg_list[i], sizeof(LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT)); +// } mac->set_config(&cfg); From a604cfb99bb40365b75dbb4f268bb2898ccce42b Mon Sep 17 00:00:00 2001 From: Paul Sutton Date: Thu, 9 Nov 2017 13:05:50 +0000 Subject: [PATCH 08/42] Fix for RRC reconnection --- srsue/src/upper/rrc.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 9f2f53f38..45e030294 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -206,6 +206,12 @@ void rrc::run_thread() { if (!current_cell->has_valid_sib1) { si_acquire_state = SI_ACQUIRE_SIB1; sysinfo_index = 0; + } else if (!current_cell->has_valid_sib2) { + si_acquire_state = SI_ACQUIRE_SIB2; + } else { + apply_sib2_configs(¤t_cell->sib2); + si_acquire_state = SI_ACQUIRE_IDLE; + state = RRC_STATE_CELL_SELECTED; } } select_cell_timeout++; From 8447c965e3b9b1a940ca353eb46af5aa3b51be32 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Sat, 25 Nov 2017 10:40:53 +0100 Subject: [PATCH 09/42] Fixing RSRP measurements --- lib/include/srslte/interfaces/ue_interfaces.h | 5 +- lib/src/phy/ch_estimation/chest_dl.c | 4 +- srsue/hdr/phy/phy.h | 3 + srsue/hdr/upper/rrc.h | 21 +++++++ srsue/src/mac/mux.cc | 2 - srsue/src/phy/phch_recv.cc | 30 ++++++--- srsue/src/phy/phy.cc | 12 ++++ srsue/src/upper/rrc.cc | 61 ++++++++++++++----- 8 files changed, 110 insertions(+), 28 deletions(-) diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 294606bb5..2713e2a6e 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -546,7 +546,10 @@ public: } phy_cfg_t; virtual void get_current_cell(srslte_cell_t *cell, uint32_t *current_earfcn = NULL) = 0; - virtual void get_config(phy_cfg_t *phy_cfg) = 0; + virtual uint32_t get_current_earfcn() = 0; + virtual uint32_t get_current_pci() = 0; + + virtual void get_config(phy_cfg_t *phy_cfg) = 0; virtual void set_config(phy_cfg_t *phy_cfg) = 0; virtual void set_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated) = 0; virtual void set_config_common(phy_cfg_common_t *common) = 0; diff --git a/lib/src/phy/ch_estimation/chest_dl.c b/lib/src/phy/ch_estimation/chest_dl.c index 0f8ae8074..d76397cf0 100644 --- a/lib/src/phy/ch_estimation/chest_dl.c +++ b/lib/src/phy/ch_estimation/chest_dl.c @@ -435,7 +435,9 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui } /* Compute RSRP for the channel estimates in this port */ - q->rsrp[rxant_id][port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); + uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id); + float energy = cabsf(srslte_vec_acc_cc(q->pilot_estimates, npilots)/npilots); + q->rsrp[rxant_id][port_id] = energy*energy; if (port_id == 0) { /* compute rssi only for port 0 */ q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id); diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index 05edf31f9..adc2abdca 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -137,7 +137,10 @@ public: float get_pathloss_db(); uint32_t get_current_tti(); + void get_current_cell(srslte_cell_t *cell, uint32_t *current_earfcn = NULL); + uint32_t get_current_earfcn(); + uint32_t get_current_pci(); void start_plot(); diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index 7b903f0d9..20b32477f 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -346,6 +346,27 @@ private: rrc_meas measurements; + // Cell selection/reselection functions/variables + typedef struct { + float Qrxlevmin; + float Qrxlevminoffset; + float Qqualmin; + float Qqualminoffset; + float s_intrasearchP; + float s_intrasearchQ; + float q_hyst; + float threshservinglow; + + } cell_resel_cfg_t; + + cell_resel_cfg_t cell_resel_cfg; + + float get_srxlev(float Qrxlevmeas); + float get_squal(float Qqualmeas); + void cell_reselection_eval(float rsrp, float rsrq); + + + // RLC interface void max_retx_attempted(); diff --git a/srsue/src/mac/mux.cc b/srsue/src/mac/mux.cc index d624d2d62..e6e136d2e 100644 --- a/srsue/src/mac/mux.cc +++ b/srsue/src/mac/mux.cc @@ -213,10 +213,8 @@ uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32 for (uint32_t i=0;iget_buffer_state(lch[i].id); lch[i].sched_len = 0; - Info("lch[%d].buffer_len=%d\n",i,lch[i].buffer_len); } - // data from any Logical Channel, except data from UL-CCCH; // first only those with positive Bj for (uint32_t i=0;iinfo("SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n", - cnt, nof_subframes, sf_idx, - rsrp, snr); + cnt, nof_subframes, sf_idx, rsrp, snr); if (cnt >= nof_subframes) { return MEASURE_OK; @@ -1107,7 +1113,7 @@ void phch_recv::scell_recv::init(srslte::log *log_h) } srslte_sync_cp_en(&sync_find, false); srslte_sync_set_cfo_ema_alpha(&sync_find, 0.8); - srslte_sync_set_threshold(&sync_find, 2.0); + srslte_sync_set_threshold(&sync_find, 1.2); reset(); } @@ -1126,6 +1132,7 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, fprintf(stderr, "Error resizing sync\n"); return SRSLTE_ERROR; } + int nof_cells = 0; uint32_t peak_idx = 0; uint32_t sf_idx = 0; @@ -1143,7 +1150,9 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, if (current_cell.id%3 != n_id_2) { srslte_sync_set_N_id_2(&sync_find, n_id_2); - switch(srslte_sync_find(&sync_find, input_buffer, 0, &peak_idx)) { + srslte_sync_find_ret_t sync_res = srslte_sync_find(&sync_find, input_buffer, 0, &peak_idx); + + switch(sync_res) { case SRSLTE_SYNC_ERROR: return SRSLTE_ERROR; fprintf(stderr, "Error finding correlation peak\n"); @@ -1155,6 +1164,7 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, peak_idx, n_id_2, cell_id, sf_idx); found_cell.id = cell_id; + found_cell.nof_ports = 1; // Use port 0 only for measurement measure_p.set_cell(found_cell); offset = peak_idx-sf_len/2; @@ -1208,7 +1218,9 @@ void phch_recv::meas_reset() { int phch_recv::meas_start(uint32_t earfcn, int pci) { if (earfcn == current_earfcn) { worker_com->pcell_meas_enabled = true; - intra_freq_meas.add_cell(pci); + if (pci != (int) cell.id) { + intra_freq_meas.add_cell(pci); + } return 0; } else { Warning("INTRA: Inter-frequency measurements not supported (current EARFCN=%d, requested measurement for %d)\n", @@ -1331,7 +1343,7 @@ void phch_recv::intra_measure::run_thread() } if (running) { - Info("INTRA: Running intra-frequency measurement for %d cells\n", active_pci.size()); + Info("INTRA: Running intra-frequency measurements\n"); // Read 5 ms data from buffer srslte_ringbuffer_read(&ring_buffer, search_buffer, CAPTURE_LEN_SF*current_sflen*sizeof(cf_t)); diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index 96949e94c..917c0b480 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -301,6 +301,18 @@ void phy::get_current_cell(srslte_cell_t *cell, uint32_t *current_earfcn) sf_recv.get_current_cell(cell, current_earfcn); } +uint32_t phy::get_current_pci() { + srslte_cell_t cell; + sf_recv.get_current_cell(&cell); + return cell.id; +} + +uint32_t phy::get_current_earfcn() { + uint32_t earfcn; + sf_recv.get_current_cell(NULL, &earfcn); + return earfcn; +} + void phy::prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm) { diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 45e030294..afa4bca96 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -255,6 +255,7 @@ void rrc::run_thread() { rrc_log->info("Leaving RRC_CONNECTED state\n"); drb_up = false; reestablishment_in_progress = false; + measurements.reset(); pdcp->reset(); rlc->reset(); phy->reset(); @@ -264,6 +265,11 @@ void rrc::run_thread() { mac->pcch_start_rx(); mac_timers->timer_get(t310)->stop(); mac_timers->timer_get(t311)->stop(); + + // Instruct PHY to measure serving cell for cell reselection + phy->meas_start(phy->get_current_earfcn(), phy->get_current_pci()); + + // Move to RRC_IDLE state = RRC_STATE_IDLE; break; default: @@ -460,7 +466,11 @@ void rrc::select_next_cell_in_plmn() { } void rrc::new_phy_meas(float rsrp, float rsrq, uint32_t tti, uint32_t earfcn, uint32_t pci) { - measurements.new_phy_meas(earfcn, pci, rsrp, rsrq, tti); + if (state == RRC_STATE_CONNECTED) { + measurements.new_phy_meas(earfcn, pci, rsrp, rsrq, tti); + } else { + cell_reselection_eval(rsrp, rsrq); + } } void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { @@ -493,6 +503,7 @@ void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { cell.earfcn = earfcn; cell.has_valid_sib1 = false; cell.has_valid_sib2 = false; + cell.has_valid_sib3 = false; known_cells.push_back(cell); // save current cell @@ -532,8 +543,31 @@ void rrc::add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp) { known_cells.push_back(c); } +// Cell reselection in IDLE Section 5.2.4 of 36.304 +void rrc::cell_reselection_eval(float rsrp, float rsrq) +{ + // Intra-frequency cell-reselection criteria + + if (get_srxlev(rsrp) > cell_resel_cfg.s_intrasearchP && get_squal(rsrq) > cell_resel_cfg.s_intrasearchQ) { + // UE may not perform intra-frequency measurements + phy->meas_reset(); + } else { + // UE must start intra-frequency measurements + phy->meas_start(phy->get_current_earfcn(), -1); + } + + // TODO: Inter-frequency cell reselection +} +float rrc::get_srxlev(float Qrxlevmeas) { + // TODO: Do max power limitation + float Pcompensation = 0; + return Qrxlevmeas - (cell_resel_cfg.Qrxlevmin + cell_resel_cfg.Qrxlevminoffset) - Pcompensation; +} +float rrc::get_squal(float Qqualmeas) { + return Qqualmeas - (cell_resel_cfg.Qqualmin + cell_resel_cfg.Qqualminoffset); +} @@ -865,14 +899,11 @@ void rrc::ho_prepare() { mac->set_ho_rnti(mob_reconf.mob_ctrl_info.new_ue_id, mob_reconf.mob_ctrl_info.target_pci); apply_rr_config_common_dl(&mob_reconf.mob_ctrl_info.rr_cnfg_common); - uint32_t current_earfcn = 0; - phy->get_current_cell(NULL, ¤t_earfcn); - bool found = false; for (uint32_t i = 0; i < known_cells.size(); i++) { rrc_log->info("cell[%d]=%d:%d, cur_earfcn=%d\n", i, known_cells[i].earfcn, known_cells[i].phy_cell.id, current_cell->earfcn); - if (known_cells[i].earfcn == current_earfcn && + if (known_cells[i].earfcn == phy->get_current_earfcn() && known_cells[i].phy_cell.id == mob_reconf.mob_ctrl_info.target_pci) { rrc_log->info("Selecting new cell pci=%d\n", known_cells[i].phy_cell.id); if (!phy->cell_handover(known_cells[i].phy_cell)) { @@ -895,7 +926,7 @@ void rrc::ho_prepare() { } printf("ncc=%d\n", mob_reconf.sec_cnfg_ho.intra_lte.next_hop_chaining_count); - usim->generate_as_keys_ho(mob_reconf.mob_ctrl_info.target_pci, current_earfcn, + usim->generate_as_keys_ho(mob_reconf.mob_ctrl_info.target_pci, phy->get_current_earfcn(), k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); pdcp->config_security(1, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); send_rrc_con_reconfig_complete(NULL); @@ -1094,6 +1125,8 @@ void rrc::handle_sib2() void rrc::handle_sib3() { rrc_log->info("SIB3 received\n"); + + } void rrc::handle_sib13() @@ -1591,8 +1624,8 @@ void rrc::apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT sizeof(LIBLTE_RRC_UL_POWER_CONTROL_DEDICATED_STRUCT)); } else if (apply_defaults) { current_cfg->ul_pwr_ctrl_ded.p0_ue_pusch = 0; - current_cfg->ul_pwr_ctrl_ded.delta_mcs_en = LIBLTE_RRC_DELTA_MCS_ENABLED_EN0; - current_cfg->ul_pwr_ctrl_ded.accumulation_en = true; + current_cfg->ul_pwr_ctrl_ded.delta_mcs_en = LIBLTE_RRC_DELTA_MCS_ENABLED_EN0; + current_cfg->ul_pwr_ctrl_ded.accumulation_en = true; current_cfg->ul_pwr_ctrl_ded.p0_ue_pucch = 0; current_cfg->ul_pwr_ctrl_ded.p_srs_offset = 7; } @@ -1741,7 +1774,7 @@ void rrc::apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cnfg default_cfg.time_alignment_timer = mac_cnfg->time_alignment_timer; } - // Setup MAC configuration + // Setup MAC configuration mac->set_config_main(&default_cfg); // Update UL HARQ config @@ -2099,7 +2132,7 @@ void rrc::rrc_meas::generate_report(uint32_t meas_id) report->pcell_rsrp_result = value_to_range(RSRP, pcell_measurement.ms[RSRP]); report->pcell_rsrq_result = value_to_range(RSRQ, pcell_measurement.ms[RSRQ]); - log_h->info("MEAS: Generate report MeasId=%d, rsrp=%f rsrq=%f\n", + log_h->console("MEAS: Generate report MeasId=%d, rsrp=%f rsrq=%f\n", report->meas_id, pcell_measurement.ms[RSRP], pcell_measurement.ms[RSRQ]); // TODO: report up to 8 best cells @@ -2189,16 +2222,14 @@ void rrc::rrc_meas::calculate_triggers(uint32_t tti) // Get serving cell if (active.size()) { - uint32_t current_earfcn = 0; - srslte_cell_t current_cell; - phy->get_current_cell(¤t_cell, ¤t_earfcn); - if (find_earfcn_cell(current_earfcn, current_cell.id, &serving_object, &serving_cell_idx)) { + if (find_earfcn_cell(phy->get_current_earfcn(), phy->get_current_pci(), &serving_object, &serving_cell_idx)) { Ofp = serving_object->q_offset; if (serving_cell_idx >= 0) { Ocp = serving_object->cells[serving_cell_idx].q_offset; } } else { - log_h->warning("Can't find current eafcn=%d, pci=%d in objects list. Using Ofp=0, Ocp=0\n", current_earfcn, current_cell.id); + log_h->warning("Can't find current eafcn=%d, pci=%d in objects list. Using Ofp=0, Ocp=0\n", + phy->get_current_earfcn(), phy->get_current_pci()); } } From cfbea7a6c1f1ad0517e14aa6d595665cabd64572 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Sun, 26 Nov 2017 00:36:06 +0100 Subject: [PATCH 10/42] Restored non-guru DFT interface. Removed input buffer from ue_dl interface --- lib/examples/cell_measurement.c | 2 +- lib/examples/pdsch_ue.c | 9 ++-- lib/include/srslte/phy/dft/ofdm.h | 8 +++ lib/include/srslte/phy/ue/ue_dl.h | 21 ++++---- lib/src/phy/dft/ofdm.c | 35 ++++++++++--- lib/src/phy/phch/test/pdsch_pdcch_file_test.c | 2 +- lib/src/phy/phch/test/pmch_file_test.c | 2 +- lib/src/phy/ue/ue_dl.c | 49 ++++++++++++++----- srsue/src/phy/phch_recv.cc | 2 +- srsue/src/phy/phch_worker.cc | 2 +- 10 files changed, 91 insertions(+), 41 deletions(-) diff --git a/lib/examples/cell_measurement.c b/lib/examples/cell_measurement.c index 333e9aaa4..268e87837 100644 --- a/lib/examples/cell_measurement.c +++ b/lib/examples/cell_measurement.c @@ -332,7 +332,7 @@ int main(int argc, char **argv) { case DECODE_SIB: /* We are looking for SI Blocks, search only in appropiate places */ if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) { - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); + n = srslte_ue_dl_decode(&ue_dl, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); if (n < 0) { fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); return -1; diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index a655e090c..26c681346 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -663,26 +663,25 @@ int main(int argc, char **argv) { if(sfidx != 1 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe if (cell.nof_ports == 1) { /* Transmission mode 1 */ - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); + n = srslte_ue_dl_decode(&ue_dl, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); } else { if (prog_args.rf_nof_rx_ant == 1) { /* Transmission mode 2 */ - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 1, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), + n = srslte_ue_dl_decode(&ue_dl, data, 1, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), acks); } else { /* Transmission mode 3 */ - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), + n = srslte_ue_dl_decode(&ue_dl, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), acks); if (n < 1) { /* Transmission mode 4 */ - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 3, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), + n = srslte_ue_dl_decode(&ue_dl, data, 3, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), acks); } } } }else{ // MBSFN subframe n = srslte_ue_dl_decode_mbsfn(&ue_dl, - sf_buffer, data[0], sfn*10+srslte_ue_sync_get_sfidx(&ue_sync)); if(n>0){ diff --git a/lib/include/srslte/phy/dft/ofdm.h b/lib/include/srslte/phy/dft/ofdm.h index cba963ca4..e48c240b9 100644 --- a/lib/include/srslte/phy/dft/ofdm.h +++ b/lib/include/srslte/phy/dft/ofdm.h @@ -113,8 +113,16 @@ SRSLTE_API void srslte_ofdm_rx_free(srslte_ofdm_t *q); SRSLTE_API void srslte_ofdm_rx_slot(srslte_ofdm_t *q, int slot_in_sf); +SRSLTE_API void srslte_ofdm_rx_slot_ng(srslte_ofdm_t *q, + cf_t *input, + cf_t *output); + SRSLTE_API void srslte_ofdm_rx_sf(srslte_ofdm_t *q); +SRSLTE_API void srslte_ofdm_rx_sf_ng(srslte_ofdm_t *q, + cf_t *input, + cf_t *output); + SRSLTE_API int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp_type, cf_t *in_buffer, diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index a60761a37..02341c08d 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -131,7 +131,7 @@ typedef struct SRSLTE_API { /* This function shall be called just after the initial synchronization */ SRSLTE_API int srslte_ue_dl_init(srslte_ue_dl_t *q, - cf_t *in_buffer[SRSLTE_MAX_PORTS], + cf_t *input[SRSLTE_MAX_PORTS], uint32_t max_prb, uint32_t nof_rx_antennas); @@ -141,20 +141,22 @@ SRSLTE_API int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, srslte_cell_t cell); int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, - cf_t *input[SRSLTE_MAX_PORTS], - uint32_t sf_idx, + uint32_t sf_idx, uint32_t *cfi); SRSLTE_API int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, - cf_t *input[SRSLTE_MAX_PORTS], - uint32_t sf_idx, + uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type); +SRSLTE_API int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t *q, + cf_t *input[SRSLTE_MAX_PORTS], + uint32_t sf_idx, + uint32_t *cfi); -int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, - uint32_t sf_idx, - uint32_t *cfi); +SRSLTE_API int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, + uint32_t sf_idx, + uint32_t *cfi); SRSLTE_API int srslte_ue_dl_decode_estimate_mbsfn(srslte_ue_dl_t *q, uint32_t sf_idx, @@ -195,14 +197,12 @@ SRSLTE_API void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset); SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t *q, - cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]); SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, - cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, @@ -216,7 +216,6 @@ SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, * srslte_pmch_decode_multi */ SRSLTE_API int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q, - cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data, uint32_t tti); diff --git a/lib/src/phy/dft/ofdm.c b/lib/src/phy/dft/ofdm.c index 8ea690bb5..e266023bb 100644 --- a/lib/src/phy/dft/ofdm.c +++ b/lib/src/phy/dft/ofdm.c @@ -380,15 +380,8 @@ void srslte_ofdm_tx_free(srslte_ofdm_t *q) { srslte_ofdm_free_(q); } -/* Transforms input samples into output OFDM symbols. - * Performs FFT on a each symbol and removes CP. - */ -void srslte_ofdm_rx_slot(srslte_ofdm_t *q, int slot_in_sf) { - cf_t *output = q->out_buffer + slot_in_sf * q->nof_re * q->nof_symbols; - -#ifdef AVOID_GURU +void srslte_ofdm_rx_slot_ng(srslte_ofdm_t *q, cf_t *input, cf_t *output) { uint32_t i; - cf_t *input = q->in_buffer + slot_in_sf * q->slot_sz; for (i=0;inof_symbols;i++) { input += SRSLTE_CP_ISNORM(q->cp)?SRSLTE_CP_LEN_NORM(i, q->symbol_sz):SRSLTE_CP_LEN_EXT(q->symbol_sz); srslte_dft_run_c(&q->fft_plan, input, q->tmp); @@ -396,6 +389,16 @@ void srslte_ofdm_rx_slot(srslte_ofdm_t *q, int slot_in_sf) { input += q->symbol_sz; output += q->nof_re; } +} + +/* Transforms input samples into output OFDM symbols. + * Performs FFT on a each symbol and removes CP. + */ +void srslte_ofdm_rx_slot(srslte_ofdm_t *q, int slot_in_sf) { + cf_t *output = q->out_buffer + slot_in_sf * q->nof_re * q->nof_symbols; + +#ifdef AVOID_GURU + srslte_ofdm_rx_slot_ng(q, q->in_buffer + slot_in_sf * q->slot_sz, q->out_buffer + slot_in_sf * q->nof_re * q->nof_symbols); #else float norm = 1.0f/sqrtf(q->fft_plan.size); cf_t *tmp = q->tmp + slot_in_sf * q->symbol_sz * q->nof_symbols; @@ -462,6 +465,22 @@ void srslte_ofdm_rx_sf(srslte_ofdm_t *q) { } } +void srslte_ofdm_rx_sf_ng(srslte_ofdm_t *q, cf_t *input, cf_t *output) { + uint32_t n; + if (q->freq_shift) { + srslte_vec_prod_ccc(q->in_buffer, q->shift_buffer, q->in_buffer, 2*q->slot_sz); + } + if(!q->mbsfn_subframe){ + for (n=0;n<2;n++) { + srslte_ofdm_rx_slot_ng(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]); + } + } + else{ + srslte_ofdm_rx_slot_mbsfn(q, &q->in_buffer[0*q->slot_sz], &q->out_buffer[0*q->nof_re*q->nof_symbols]); + srslte_ofdm_rx_slot(q, 1); + } +} + /* Transforms input OFDM symbols into output samples. * Performs FFT on a each symbol and adds CP. */ diff --git a/lib/src/phy/phch/test/pdsch_pdcch_file_test.c b/lib/src/phy/phch/test/pdsch_pdcch_file_test.c index 0faf7eca1..ba662bc49 100644 --- a/lib/src/phy/phch/test/pdsch_pdcch_file_test.c +++ b/lib/src/phy/phch/test/pdsch_pdcch_file_test.c @@ -182,7 +182,7 @@ int main(int argc, char **argv) { srslte_filesource_read(&fsrc, input_buffer[0], flen); INFO("Reading %d samples sub-frame %d\n", flen, sf_idx); - ret = srslte_ue_dl_decode(&ue_dl, input_buffer, data, 0, sf_idx, acks); + ret = srslte_ue_dl_decode(&ue_dl, data, 0, sf_idx, acks); if(ret > 0) { printf("PDSCH Decoded OK!\n"); } else if (ret == 0) { diff --git a/lib/src/phy/phch/test/pmch_file_test.c b/lib/src/phy/phch/test/pmch_file_test.c index 6586b2ee9..1d0715caa 100644 --- a/lib/src/phy/phch/test/pmch_file_test.c +++ b/lib/src/phy/phch/test/pmch_file_test.c @@ -187,7 +187,7 @@ int main(int argc, char **argv) { srslte_filesource_read(&fsrc, input_buffer[0], flen); INFO("Reading %d samples sub-frame %d\n", flen, sf_idx); - ret = srslte_ue_dl_decode_mbsfn(&ue_dl, input_buffer, data[0], sf_idx); + ret = srslte_ue_dl_decode_mbsfn(&ue_dl, data[0], sf_idx); if(ret > 0) { printf("PMCH Decoded OK!\n"); } else if (ret < 0) { diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 494eecba7..c5431cec9 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -359,20 +359,20 @@ void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) { * - PDCCH decoding: Find DCI for RNTI given by previous call to srslte_ue_dl_set_rnti() * - PDSCH decoding: Decode TB scrambling with RNTI given by srslte_ue_dl_set_rnti() */ -int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], +int srslte_ue_dl_decode(srslte_ue_dl_t *q, uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]) { - return srslte_ue_dl_decode_rnti(q, input, data, tm, tti, q->current_rnti, acks); + return srslte_ue_dl_decode_rnti(q, data, tm, tti, q->current_rnti, acks); } -int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi){ +int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi){ - return srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, cfi, SRSLTE_SF_NORM); + return srslte_ue_dl_decode_fft_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM); } -int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type) +int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type) { - if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { + if (q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { /* Run FFT for all subframe data */ for (int j=0;jnof_rx_antennas;j++) { @@ -398,6 +398,32 @@ int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, cf_t *input[SRSLTE return SRSLTE_ERROR_INVALID_INPUTS; } } + +int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi) +{ + if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { + + /* Run FFT for all subframe data */ + for (int j=0;jnof_rx_antennas;j++) { + srslte_ofdm_rx_sf_ng(&q->fft[j], input[j], q->sf_symbols_m[j]); + + /* Correct SFO multiplying by complex exponential in the time domain */ + if (q->sample_offset) { + int nsym = SRSLTE_CP_NSYMB(q->cell.cp); + for (int i=0;i<2*nsym;i++) { + srslte_cfo_correct(&q->sfo_correct, + &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], + &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], + q->sample_offset / q->fft[j].symbol_sz); + } + } + } + return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM); + } else { + return SRSLTE_ERROR_INVALID_INPUTS; + } +} + int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi) { return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM); @@ -468,7 +494,7 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3 } } -int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], +int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, uint16_t rnti, bool acks[SRSLTE_MAX_CODEWORDS]) { srslte_mimo_type_t mimo_type; @@ -479,7 +505,7 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t cfi; uint32_t sf_idx = tti%10; - if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, &cfi, SRSLTE_SF_NORM)) < 0) { + if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, sf_idx, &cfi, SRSLTE_SF_NORM)) < 0) { return ret; } @@ -621,16 +647,15 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q, - cf_t *input[SRSLTE_MAX_PORTS], - uint8_t *data, - uint32_t tti) + uint8_t *data, + uint32_t tti) { srslte_ra_dl_grant_t grant; int ret = SRSLTE_ERROR; uint32_t cfi; uint32_t sf_idx = tti%10; - if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, &cfi, SRSLTE_SF_MBSFN)) < 0) { + if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, sf_idx, &cfi, SRSLTE_SF_MBSFN)) < 0) { return ret; } diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 8fc026ad9..3f6a2a019 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -1054,7 +1054,7 @@ phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *in phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx) { uint32_t cfi = 0; - if (srslte_ue_dl_decode_fft_estimate(&ue_dl, buffer, sf_idx, &cfi)) { + if (srslte_ue_dl_decode_fft_estimate(&ue_dl, sf_idx, &cfi)) { log_h->error("SYNC: Measuring RSRP: Estimating channel\n"); return ERROR; } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 8c487bc48..ebb234539 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -420,7 +420,7 @@ bool phch_worker::extract_fft_and_pdcch_llr() { srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_PSS); } - if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) { + if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) { Error("Getting PDCCH FFT estimate\n"); return false; } From 3a0ab02264e52e1f6ff7c9ca6fc1d26c0209f2a2 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Mon, 27 Nov 2017 13:57:05 +0100 Subject: [PATCH 11/42] S1/X2 handover tested and working --- lib/examples/cell_measurement.c | 2 +- lib/include/srslte/common/liblte_security.h | 6 + lib/include/srslte/common/security.h | 4 + lib/include/srslte/interfaces/ue_interfaces.h | 1 + lib/include/srslte/phy/sync/sync.h | 1 + lib/src/common/liblte_security.cc | 28 ++++ lib/src/common/security.cc | 9 ++ lib/src/phy/sync/sync.c | 9 +- lib/src/phy/ue/ue_dl.c | 2 +- lib/src/phy/ue/ue_sync.c | 34 ++--- srsue/hdr/phy/phch_common.h | 7 +- srsue/hdr/phy/phch_recv.h | 3 +- srsue/hdr/upper/rrc.h | 5 +- srsue/hdr/upper/usim.h | 5 + srsue/src/mac/mac.cc | 1 - srsue/src/phy/phch_recv.cc | 126 ++++++++++++------ srsue/src/phy/phch_worker.cc | 55 ++++---- srsue/src/upper/rrc.cc | 88 ++++++++---- srsue/src/upper/usim.cc | 33 ++++- 19 files changed, 285 insertions(+), 134 deletions(-) diff --git a/lib/examples/cell_measurement.c b/lib/examples/cell_measurement.c index 268e87837..eec7548e4 100644 --- a/lib/examples/cell_measurement.c +++ b/lib/examples/cell_measurement.c @@ -369,7 +369,7 @@ int main(int argc, char **argv) { if ((nframes%100) == 0 || rx_gain_offset == 0) { if (srslte_rf_has_rssi(&rf)) { - rx_gain_offset = 10*log10(rssi*1000)-srslte_rf_get_rssi(&rf); + rx_gain_offset = 30+10*log10(rssi*1000)-srslte_rf_get_rssi(&rf); } else { rx_gain_offset = srslte_rf_get_rx_gain(&rf); } diff --git a/lib/include/srslte/common/liblte_security.h b/lib/include/srslte/common/liblte_security.h index 2c6fdc50c..79006dca9 100644 --- a/lib/include/srslte/common/liblte_security.h +++ b/lib/include/srslte/common/liblte_security.h @@ -91,6 +91,10 @@ LIBLTE_ERROR_ENUM liblte_security_generate_k_enb_star(uint8 *k_enb, uint32_t earfcn, uint8 *k_enb_star); +LIBLTE_ERROR_ENUM liblte_security_generate_nh( uint8_t *k_asme, + uint8_t *sync, + uint8_t *nh); + /********************************************************************* Name: liblte_security_generate_k_nas @@ -126,6 +130,8 @@ LIBLTE_ERROR_ENUM liblte_security_generate_k_nas(uint8 uint8 *k_nas_enc, uint8 *k_nas_int); + + /********************************************************************* Name: liblte_security_generate_k_rrc diff --git a/lib/include/srslte/common/security.h b/lib/include/srslte/common/security.h index fd892e891..386997326 100644 --- a/lib/include/srslte/common/security.h +++ b/lib/include/srslte/common/security.h @@ -81,6 +81,10 @@ uint8_t security_generate_k_enb_star( uint8_t *k_enb, uint32_t earfcn, uint8_t *k_enb_star); +uint8_t security_generate_nh( uint8_t *k_asme, + uint8_t *sync, + uint8_t *nh); + uint8_t security_generate_k_nas( uint8_t *k_asme, CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 2713e2a6e..94a94dd0d 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -85,6 +85,7 @@ public: srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; virtual void generate_as_keys_ho(uint32_t pci, uint32_t earfcn, + int ncc, uint8_t *k_rrc_enc, uint8_t *k_rrc_int, uint8_t *k_up_enc, diff --git a/lib/include/srslte/phy/sync/sync.h b/lib/include/srslte/phy/sync/sync.h index 135a19160..081b332c7 100644 --- a/lib/include/srslte/phy/sync/sync.h +++ b/lib/include/srslte/phy/sync/sync.h @@ -75,6 +75,7 @@ typedef struct SRSLTE_API { uint32_t frame_size; uint32_t max_offset; bool enable_cfo_corr; + bool enable_cfo_pss; bool mean_cfo2_isunset; bool mean_cfo_isunset; float mean_cfo; diff --git a/lib/src/common/liblte_security.cc b/lib/src/common/liblte_security.cc index e0cdd90d8..0c7626abc 100644 --- a/lib/src/common/liblte_security.cc +++ b/lib/src/common/liblte_security.cc @@ -335,6 +335,34 @@ LIBLTE_ERROR_ENUM liblte_security_generate_k_enb_star(uint8 *k_enb, return (err); } +LIBLTE_ERROR_ENUM liblte_security_generate_nh( uint8_t *k_asme, + uint8_t *sync, + uint8_t *nh) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 s[35]; + + if (k_asme != NULL && + sync != NULL && + nh != NULL) + { + // Construct S + s[0] = 0x12; // FC + for (int i=0;i<32;i++) { + s[1+i] = sync[i]; + } + s[33] = 0x00; // First byte of L0 + s[34] = 0x20, // Second byte of L0 + + // Derive NH + sha256(k_asme, 32, s, 35, nh, 0); + + err = LIBLTE_SUCCESS; + } + + return (err); +} + /********************************************************************* Name: liblte_security_generate_k_nas diff --git a/lib/src/common/security.cc b/lib/src/common/security.cc index 93b197e7c..404e88d34 100644 --- a/lib/src/common/security.cc +++ b/lib/src/common/security.cc @@ -72,6 +72,15 @@ uint8_t security_generate_k_enb_star( uint8_t *k_enb, k_enb_star); } +uint8_t security_generate_nh( uint8_t *k_asme, + uint8_t *sync, + uint8_t *nh) +{ + return liblte_security_generate_nh( k_asme, + sync, + nh); +} + uint8_t security_generate_k_nas( uint8_t *k_asme, CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, diff --git a/lib/src/phy/sync/sync.c b/lib/src/phy/sync/sync.c index 6faebfcad..34009fbad 100644 --- a/lib/src/phy/sync/sync.c +++ b/lib/src/phy/sync/sync.c @@ -554,8 +554,7 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t peak_pos = srslte_pss_synch_find_pss(&q->pss, &input_cfo[find_offset], &q->peak_value); // this compensates for the constant time shift caused by the low pass filter - if(q->decimate && peak_pos < 0) - { + if(q->decimate && peak_pos < 0) { peak_pos = 0 ;//peak_pos + q->decimate*(2);// replace 2 with q->filter_size -2; } if (peak_pos < 0) { @@ -591,17 +590,15 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t } } - if (q->enable_cfo_corr) { + if (q->enable_cfo_pss) { if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { - float cfo2 = srslte_pss_synch_cfo_compute(&q->pss, &input[find_offset + peak_pos - q->fft_size]); + float cfo2 = srslte_pss_synch_cfo_compute(&q->pss, &input[find_offset + peak_pos - q->fft_size]); if (q->mean_cfo2_isunset) { q->mean_cfo2 = cfo2; q->mean_cfo2_isunset = true; } else { q->mean_cfo2 = SRSLTE_VEC_EMA(cfo2, q->mean_cfo2, q->cfo_ema_alpha); } - } else { - ret = SRSLTE_SYNC_FOUND_NOSPACE; } } } else { diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index c5431cec9..a9ecfe40f 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -401,7 +401,7 @@ int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, uint32_t sf_idx, u int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi) { - if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { + if (input && q && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { /* Run FFT for all subframe data */ for (int j=0;jnof_rx_antennas;j++) { diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index d11811cf3..8adf77dd6 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -682,19 +682,21 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE q->sf_idx = (q->sf_idx + q->nof_recv_sf) % 10; #ifndef DO_CFO_IN_SYNC - /* We found that CP-based correction performs better in low SNR than PSS-based. - * - * Estimate, average and correct here instead of inside sync object - */ - q->cfo = srslte_sync_cfo_estimate(&q->strack, input_buffer[0], 0); - if (q->mean_cfo_isunset) { - q->mean_cfo = q->cfo; - q->mean_cfo_isunset = false; - } else { - /* compute exponential moving average CFO */ - q->mean_cfo = SRSLTE_VEC_EMA(q->cfo, q->mean_cfo, q->cfo_ema_alpha); + if (q->correct_cfo) { + /* We found that CP-based correction performs better in low SNR than PSS-based. + * + * Estimate, average and correct here instead of inside sync object + */ + q->cfo = srslte_sync_cfo_estimate(&q->strack, input_buffer[0], 0); + if (q->mean_cfo_isunset) { + q->mean_cfo = q->cfo; + q->mean_cfo_isunset = false; + } else { + /* compute exponential moving average CFO */ + q->mean_cfo = SRSLTE_VEC_EMA(q->cfo, q->mean_cfo, q->cfo_ema_alpha); + } + srslte_cfo_correct(&q->strack.cfocorr2, input_buffer[0], input_buffer[0], -q->mean_cfo / q->fft_size); } - srslte_cfo_correct(&q->strack.cfocorr2, input_buffer[0], input_buffer[0], -q->mean_cfo / q->fft_size); #endif @@ -754,14 +756,6 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE q->frame_total_cnt++; } - if (q->correct_cfo) { - for (int i=0;inof_rx_antennas;i++) { - srslte_cfo_correct(&q->strack.cfocorr, - input_buffer[i], - input_buffer[i], - -srslte_sync_get_cfo(&q->strack) / q->fft_size); - } - } break; } diff --git a/srsue/hdr/phy/phch_common.h b/srsue/hdr/phy/phch_common.h index 39eb594bc..ecdedf63b 100644 --- a/srsue/hdr/phy/phch_common.h +++ b/srsue/hdr/phy/phch_common.h @@ -51,20 +51,19 @@ namespace srsue { phy_args_t *args; rrc_interface_phy *rrc; mac_interface_phy *mac; - srslte_ue_ul_t ue_ul; - + /* Power control variables */ float pathloss; float cur_pathloss; float p0_preamble; float cur_radio_power; float cur_pusch_power; - float avg_rsrp_db; + float avg_rsrp; + float avg_rsrp_dbm; float avg_rsrq_db; float rx_gain_offset; float avg_snr_db; float avg_noise; - float avg_rsrp; bool pcell_meas_enabled; uint32_t pcell_report_period; diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/phch_recv.h index eea156298..4f54580f1 100644 --- a/srsue/hdr/phy/phch_recv.h +++ b/srsue/hdr/phy/phch_recv.h @@ -167,7 +167,7 @@ private: void set_cell(srslte_cell_t cell); ret_code run_subframe(uint32_t sf_idx); ret_code run_subframe_sync(srslte_ue_sync_t *ue_sync, uint32_t sf_idx); - ret_code run_multiple_subframes(cf_t *buffer, uint32_t sf_idx, uint32_t nof_sf); + ret_code run_multiple_subframes(cf_t *buffer, uint32_t offset, uint32_t sf_idx, uint32_t nof_sf); float rsrp(); float rsrq(); float snr(); @@ -205,6 +205,7 @@ private: srslte::log *log_h; srslte_sync_t sync_find; + uint32_t current_fft_sz; measure measure_p; }; diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index 20b32477f..1f28f0000 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -205,8 +205,10 @@ private: LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT sib13; } cell_t; - std::vector known_cells; + const static int MAX_KNOWN_CELLS = 64; + cell_t known_cells[MAX_KNOWN_CELLS]; cell_t *current_cell; + void add_new_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp); typedef enum { SI_ACQUIRE_IDLE = 0, @@ -353,7 +355,6 @@ private: float Qqualmin; float Qqualminoffset; float s_intrasearchP; - float s_intrasearchQ; float q_hyst; float threshservinglow; diff --git a/srsue/hdr/upper/usim.h b/srsue/hdr/upper/usim.h index 6ad3acce5..cf5a4c820 100644 --- a/srsue/hdr/upper/usim.h +++ b/srsue/hdr/upper/usim.h @@ -92,6 +92,7 @@ public: void generate_as_keys_ho(uint32_t pci, uint32_t earfcn, + int ncc, uint8_t *k_rrc_enc, uint8_t *k_rrc_int, uint8_t *k_up_enc, @@ -137,9 +138,13 @@ private: uint8_t ak[6]; uint8_t mac[8]; uint8_t autn[16]; + uint8_t k_asme[32]; + uint8_t nh[32]; uint8_t k_enb[32]; uint8_t k_enb_star[32]; + uint32_t current_ncc; + bool initiated; }; diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc index 368050f7d..42d7c4b96 100644 --- a/srsue/src/mac/mac.cc +++ b/srsue/src/mac/mac.cc @@ -385,7 +385,6 @@ void mac::set_ho_rnti(uint16_t crnti, uint16_t target_pci) { phy_h->pdcch_ul_search_reset(); uernti.crnti = crnti; if (pcap) { - printf("set_ue_id=%d\n", target_pci); pcap->set_ue_id(target_pci); } } diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 3f6a2a019..d9b1b7f72 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -52,6 +52,7 @@ phch_recv::phch_recv() { ul_freq = -1; bzero(&cell, sizeof(srslte_cell_t)); running = false; + worker_com = NULL; } void phch_recv::init(srslte::radio_multi *_radio_handler, mac_interface_phy *_mac, rrc_interface_phy *_rrc, @@ -976,7 +977,7 @@ void phch_recv::measure::init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h for (int i=0;ibuffer[i] = buffer[i]; } - + if (srslte_ue_dl_init(&ue_dl, this->buffer, SRSLTE_MAX_PRB, nof_rx_antennas)) { Error("SYNC: Initiating ue_dl_measure\n"); return; @@ -1024,6 +1025,7 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe_sync(srslte_ue_syn { int sync_res = srslte_ue_sync_zerocopy_multi(ue_sync, buffer); if (sync_res == 1) { + log_h->info("SYNC: CFO=%.1f KHz\n", srslte_ue_sync_get_cfo(ue_sync)); return run_subframe(sf_idx); } else { log_h->error("SYNC: Measuring RSRP: Sync error\n"); @@ -1034,18 +1036,61 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe_sync(srslte_ue_syn } phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *input_buffer, + uint32_t offset, uint32_t sf_idx, - uint32_t nof_sf) + uint32_t max_sf) { uint32_t sf_len = SRSLTE_SF_LEN_PRB(current_prb); ret_code ret = IDLE; - for (uint32_t i=0;i= 0) { + + cf_t *buf_m[SRSLTE_MAX_PORTS]; + buf_m[0] = &input_buffer[test_offset]; + + uint32_t cfi; + if (srslte_ue_dl_decode_fft_estimate_noguru(&ue_dl, buf_m, sf_idx, &cfi)) { + Error("MEAS: Measuring RSRP: Estimating channel\n"); + return ERROR; + } + + float rsrp = srslte_chest_dl_get_rsrp(&ue_dl.chest); + if (rsrp > max_rsrp) { + max_rsrp = rsrp; + best_test_offset = test_offset; + found_best = true; + } + } + } + + offset = found_best?best_test_offset:offset; + if (offset >= 0 && offset < sf_len*max_sf) { + uint32_t nof_sf = (sf_len*max_sf - offset)/sf_len; + + Info("INTRA: fine-tuning offset: %d, found_best=%d, rem_sf=%d\n", offset, found_best, nof_sf); + + for (uint32_t i=0;ipcell_meas_enabled = false; + if (worker_com) { + worker_com->pcell_meas_enabled = false; + } } int phch_recv::meas_start(uint32_t earfcn, int pci) { @@ -1223,7 +1272,7 @@ int phch_recv::meas_start(uint32_t earfcn, int pci) { } return 0; } else { - Warning("INTRA: Inter-frequency measurements not supported (current EARFCN=%d, requested measurement for %d)\n", + Warning("INTRA: Inter-frequency measurements not supported (current EARFCN=%d, requested measurement for %d)\n", current_earfcn, earfcn); return -1; } @@ -1234,7 +1283,7 @@ int phch_recv::meas_stop(uint32_t earfcn, int pci) { intra_freq_meas.rem_cell(pci); return 0; } else { - Warning("INTRA: Inter-frequency measurements not supported (current EARFCN=%d, requested stop measurement for %d)\n", + Warning("INTRA: Inter-frequency measurements not supported (current EARFCN=%d, requested stop measurement for %d)\n", current_earfcn, earfcn); } return -1; @@ -1283,9 +1332,9 @@ void phch_recv::intra_measure::add_cell(int pci) { if (std::find(active_pci.begin(), active_pci.end(), pci) == active_pci.end()) { active_pci.push_back(pci); receive_enabled = true; - Info("INTRA: Starting intra-frequency measurement for pci=%d\n", pci); + Info("INTRA: Starting intra-frequency measurement for pci=%d\n", pci); } else { - Warning("INTRA: Requested to start already existing intra-frequency measurement for PCI=%d\n", pci); + Warning("INTRA: Requested to start already existing intra-frequency measurement for PCI=%d\n", pci); } } @@ -1306,9 +1355,9 @@ void phch_recv::intra_measure::rem_cell(int pci) { if (active_pci.size() == 0) { receive_enabled = false; } - Info("INTRA: Stopping intra-frequency measurement for pci=%d. Number of cells: %d\n", pci, active_pci.size()); + Info("INTRA: Stopping intra-frequency measurement for pci=%d. Number of cells: %d\n", pci, active_pci.size()); } else { - Warning("INTRA: Requested to stop non-existing intra-frequency measurement for PCI=%d\n", pci); + Warning("INTRA: Requested to stop non-existing intra-frequency measurement for PCI=%d\n", pci); } } @@ -1318,12 +1367,12 @@ void phch_recv::intra_measure::write(uint32_t tti, cf_t *data, uint32_t nsamples receiving = true; receive_cnt = 0; measure_tti = tti; + srslte_ringbuffer_reset(&ring_buffer); } if (receiving == true) { if (srslte_ringbuffer_write(&ring_buffer, data, nsamples*sizeof(cf_t)) < (int) (nsamples*sizeof(cf_t))) { Warning("Error writing to ringbuffer\n"); receiving = false; - srslte_ringbuffer_reset(&ring_buffer); } else { receive_cnt++; if (receive_cnt == CAPTURE_LEN_SF) { @@ -1343,13 +1392,12 @@ void phch_recv::intra_measure::run_thread() } if (running) { - Info("INTRA: Running intra-frequency measurements\n"); + Info("INTRA: Running intra-frequency measurements\n"); - // Read 5 ms data from buffer + // Read 15 ms data from buffer srslte_ringbuffer_read(&ring_buffer, search_buffer, CAPTURE_LEN_SF*current_sflen*sizeof(cf_t)); int found_cells = scell.find_cells(search_buffer, common->rx_gain_offset, primary_cell, CAPTURE_LEN_SF, info); receiving = false; - srslte_ringbuffer_reset(&ring_buffer); for (int i=0;inew_phy_meas(info[i].rsrp, info[i].rsrq, measure_tti, current_earfcn, info[i].pci); diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index ebb234539..5ae0b242a 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -221,7 +221,7 @@ void phch_worker::work_imp() /* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */ bool chest_ok = extract_fft_and_pdcch_llr(); - bool snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>1.0; + bool snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>-10.0; if (chest_ok && snr_th_ok) { @@ -381,7 +381,7 @@ void phch_worker::work_imp() log_h->debug("SYNC: Sending in-sync to RRC\n"); } else { phy->rrc->out_of_sync(); - log_h->debug("SNR=%.1f dB under threshold. Sending out-of-sync to RRC\n", + log_h->info("SNR=%.1f dB under threshold. Sending out-of-sync to RRC\n", 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))); } } @@ -974,7 +974,7 @@ void phch_worker::encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, ui #endif uint8_t dummy[2] = {0,0}; - log_h->info_hex(payload?payload:dummy, payload?grant->mcs.tbs/8:1,"PUSCH: tti_tx=%d, alloc=(%d,%d), tbs=%d, mcs=%d, rv=%d, ack=%s, ri=%s, cfo=%.1f KHz%s\n", + log_h->info("PUSCH: tti_tx=%d, alloc=(%d,%d), tbs=%d, mcs=%d, rv=%d, ack=%s, ri=%s, cfo=%.1f KHz%s\n", (tti+HARQ_DELAY_MS)%10240, grant->n_prb[0], grant->n_prb[0]+grant->L_prb, grant->mcs.tbs/8, grant->mcs.idx, rv, @@ -1244,52 +1244,49 @@ void phch_worker::update_measurements() if (tti== 0 || phy->rx_gain_offset == 0) { float rx_gain_offset = 0; if (phy->get_radio()->has_rssi() && phy->args->rssi_sensor_enabled) { - float rssi_all_signal = srslte_chest_dl_get_rssi(&ue_dl.chest); - if (rssi_all_signal) { - rx_gain_offset = 10*log10(rssi_all_signal)-phy->get_radio()->get_rssi(); - } else { - rx_gain_offset = 0; - } + float rssi_all_signal = 30+10*log10(srslte_vec_avg_power_cf(signal_buffer[0],SRSLTE_SF_LEN(srslte_symbol_sz(cell.nof_prb)))); + rx_gain_offset = 30+rssi_all_signal-phy->get_radio()->get_rssi(); } else { rx_gain_offset = phy->get_radio()->get_rx_gain(); } if (phy->rx_gain_offset) { - phy->rx_gain_offset = SRSLTE_VEC_EMA(phy->rx_gain_offset, rx_gain_offset, 0.5); + phy->rx_gain_offset = SRSLTE_VEC_EMA(rx_gain_offset, phy->rx_gain_offset, 0.5); } else { phy->rx_gain_offset = rx_gain_offset; } } // Average RSRQ - float cur_rsrq = 10*log10(srslte_chest_dl_get_rsrq(&ue_dl.chest)); - if (isnormal(cur_rsrq)) { - phy->avg_rsrq_db = SRSLTE_VEC_EMA(phy->avg_rsrq_db, cur_rsrq, snr_ema_coeff); + float rsrq_db = 10*log10(srslte_chest_dl_get_rsrq(&ue_dl.chest)); + if (isnormal(rsrq_db)) { + phy->avg_rsrq_db = SRSLTE_VEC_EMA(rsrq_db, phy->avg_rsrq_db, snr_ema_coeff); } - + // Average RSRP - float cur_rsrp = srslte_chest_dl_get_rsrp(&ue_dl.chest); - if (isnormal(cur_rsrp)) { - phy->avg_rsrp = SRSLTE_VEC_EMA(phy->avg_rsrp, cur_rsrp, snr_ema_coeff); + float rsrp_lin = srslte_chest_dl_get_rsrp(&ue_dl.chest); + if (isnormal(rsrp_lin)) { + phy->avg_rsrp = SRSLTE_VEC_EMA(rsrp_lin, phy->avg_rsrp, snr_ema_coeff); } /* Correct absolute power measurements by RX gain offset */ - float rsrp = 10*log10(srslte_chest_dl_get_rsrp(&ue_dl.chest)) + 30 - phy->rx_gain_offset; - float rssi = 10*log10(srslte_chest_dl_get_rssi(&ue_dl.chest)) + 30 - phy->rx_gain_offset; - + float rsrp_dbm = 10*log10(rsrp_lin) + 30 - phy->rx_gain_offset; + float rssi_db = 10*log10(srslte_chest_dl_get_rssi(&ue_dl.chest)) + 30 - phy->rx_gain_offset; + // Serving cell measurements are averaged over DEFAULT_MEAS_PERIOD_MS then sent to RRC - if (isnormal(rsrp)) { - if (!phy->avg_rsrp_db) { - phy->avg_rsrp_db = rsrp; + if (isnormal(rsrp_dbm)) { + if (!phy->avg_rsrp_dbm) { + phy->avg_rsrp_dbm= rsrp_dbm; } else { - phy->avg_rsrp_db = SRSLTE_VEC_EMA(phy->avg_rsrp_db, rsrp, 0.8); + phy->avg_rsrp_dbm = SRSLTE_VEC_EMA(rsrp_dbm, phy->avg_rsrp_dbm, snr_ema_coeff); } if ((tti%phy->pcell_report_period) == 0 && phy->pcell_meas_enabled) { - phy->rrc->new_phy_meas(phy->avg_rsrp_db, phy->avg_rsrq_db, tti); + phy->rrc->new_phy_meas(phy->avg_rsrp_dbm, phy->avg_rsrq_db, tti); } } + // Compute PL float tx_crs_power = phy->config->common.pdsch_cnfg.rs_power; - phy->pathloss = tx_crs_power - phy->avg_rsrp_db; + phy->pathloss = tx_crs_power - phy->avg_rsrp_dbm; // Average noise float cur_noise = srslte_chest_dl_get_noise_estimate(&ue_dl.chest); @@ -1297,7 +1294,7 @@ void phch_worker::update_measurements() if (!phy->avg_noise) { phy->avg_noise = cur_noise; } else { - phy->avg_noise = SRSLTE_VEC_EMA(phy->avg_noise, cur_noise, snr_ema_coeff); + phy->avg_noise = SRSLTE_VEC_EMA(cur_noise, phy->avg_noise, snr_ema_coeff); } } @@ -1306,9 +1303,9 @@ void phch_worker::update_measurements() // Store metrics dl_metrics.n = phy->avg_noise; - dl_metrics.rsrp = phy->avg_rsrp_db; + dl_metrics.rsrp = phy->avg_rsrp_dbm; dl_metrics.rsrq = phy->avg_rsrq_db; - dl_metrics.rssi = rssi; + dl_metrics.rssi = rssi_db; dl_metrics.pathloss = phy->pathloss; dl_metrics.sinr = phy->avg_snr_db; dl_metrics.turbo_iters = srslte_pdsch_last_noi(&ue_dl.pdsch); diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index afa4bca96..31ed25384 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -89,6 +89,8 @@ void rrc::init(phy_interface_rrc *phy_, state = RRC_STATE_IDLE; si_acquire_state = SI_ACQUIRE_IDLE; + bzero(known_cells, MAX_KNOWN_CELLS*sizeof(cell_t)); + thread_running = true; start(); @@ -433,7 +435,7 @@ void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { } void rrc::select_next_cell_in_plmn() { - for (uint32_t i = last_selected_cell + 1; i < known_cells.size(); i++) { + for (uint32_t i = last_selected_cell + 1; i < MAX_KNOWN_CELLS && known_cells[i].earfcn; i++) { for (uint32_t j = 0; j < known_cells[i].sib1.N_plmn_ids; j++) { if (known_cells[i].sib1.plmn_id[j].id.mcc == selected_plmn_id.mcc || known_cells[i].sib1.plmn_id[j].id.mnc == selected_plmn_id.mnc) { @@ -476,7 +478,7 @@ void rrc::new_phy_meas(float rsrp, float rsrq, uint32_t tti, uint32_t earfcn, ui void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { // find if cell_id-earfcn combination already exists - for (uint32_t i = 0; i < known_cells.size(); i++) { + for (uint32_t i = 0; i < MAX_KNOWN_CELLS && known_cells[i].earfcn; i++) { if (earfcn == known_cells[i].earfcn && phy_cell.id == known_cells[i].phy_cell.id) { current_cell = &known_cells[i]; current_cell->rsrp = rsrp; @@ -497,17 +499,7 @@ void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { } } // add to list of known cells - cell_t cell; - cell.phy_cell = phy_cell; - cell.rsrp = rsrp; - cell.earfcn = earfcn; - cell.has_valid_sib1 = false; - cell.has_valid_sib2 = false; - cell.has_valid_sib3 = false; - known_cells.push_back(cell); - - // save current cell - current_cell = &known_cells.back(); + add_new_cell(earfcn, phy_cell, rsrp); si_acquire_state = SI_ACQUIRE_SIB1; @@ -516,6 +508,24 @@ void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { current_cell->earfcn, current_cell->rsrp, current_cell); } +void rrc::add_new_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { + int i=0; + while(ierror("Can't add more cells\n"); + return; + } + current_cell = &known_cells[i]; + current_cell->phy_cell = phy_cell; + current_cell->rsrp = rsrp; + current_cell->earfcn = earfcn; + current_cell->has_valid_sib1 = false; + current_cell->has_valid_sib2 = false; + current_cell->has_valid_sib3 = false; +} + // 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]); @@ -527,20 +537,18 @@ void rrc::earfcn_end() { } void rrc::add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp) { - for (uint32_t i = 0; i < known_cells.size(); i++) { + for (uint32_t i = 0; i < MAX_KNOWN_CELLS && known_cells[i].earfcn; i++) { if (earfcn == known_cells[i].earfcn && pci == known_cells[i].phy_cell.id) { known_cells[i].rsrp = rsrp; return; } } rrc_log->info("Added neighbour cell earfcn=%d, pci=%d, rsrp=%f\n", earfcn, pci, rsrp); - cell_t c; - bzero(&c, sizeof(cell_t)); - c.earfcn = earfcn; - c.rsrp = rsrp; - memcpy(&c.phy_cell, ¤t_cell->phy_cell, sizeof(srslte_cell_t)); - c.phy_cell.id = pci; - known_cells.push_back(c); + + srslte_cell_t cell; + cell = current_cell->phy_cell; + cell.id = pci; + add_new_cell(earfcn, cell, rsrp); } // Cell reselection in IDLE Section 5.2.4 of 36.304 @@ -548,7 +556,7 @@ void rrc::cell_reselection_eval(float rsrp, float rsrq) { // Intra-frequency cell-reselection criteria - if (get_srxlev(rsrp) > cell_resel_cfg.s_intrasearchP && get_squal(rsrq) > cell_resel_cfg.s_intrasearchQ) { + if (get_srxlev(rsrp) > cell_resel_cfg.s_intrasearchP) { // UE may not perform intra-frequency measurements phy->meas_reset(); } else { @@ -900,9 +908,7 @@ void rrc::ho_prepare() { apply_rr_config_common_dl(&mob_reconf.mob_ctrl_info.rr_cnfg_common); bool found = false; - for (uint32_t i = 0; i < known_cells.size(); i++) { - rrc_log->info("cell[%d]=%d:%d, cur_earfcn=%d\n", i, known_cells[i].earfcn, known_cells[i].phy_cell.id, - current_cell->earfcn); + for (uint32_t i = 0; i < MAX_KNOWN_CELLS && known_cells[i].earfcn; i++) { if (known_cells[i].earfcn == phy->get_current_earfcn() && known_cells[i].phy_cell.id == mob_reconf.mob_ctrl_info.target_pci) { rrc_log->info("Selecting new cell pci=%d\n", known_cells[i].phy_cell.id); @@ -925,8 +931,13 @@ void rrc::ho_prepare() { mac->start_cont_ho(); } - printf("ncc=%d\n", mob_reconf.sec_cnfg_ho.intra_lte.next_hop_chaining_count); + int ncc = -1; + if (mob_reconf.sec_cnfg_ho_present) { + ncc = mob_reconf.sec_cnfg_ho.intra_lte.next_hop_chaining_count; + } + usim->generate_as_keys_ho(mob_reconf.mob_ctrl_info.target_pci, phy->get_current_earfcn(), + ncc, k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); pdcp->config_security(1, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); send_rrc_con_reconfig_complete(NULL); @@ -968,7 +979,8 @@ void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGU if (reconfig->mob_ctrl_info_present) { rrc_log->info("Received HO command to target PCell=%d\n", reconfig->mob_ctrl_info.target_pci); - rrc_log->console("Received HO command to target PCell=%d\n", reconfig->mob_ctrl_info.target_pci); + rrc_log->console("Received HO command to target PCell=%d, NCC=%d\n", + reconfig->mob_ctrl_info.target_pci, reconfig->sec_cnfg_ho.intra_lte.next_hop_chaining_count); // store mobilityControlInfo memcpy(&mob_reconf, reconfig, sizeof(LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT)); @@ -1126,6 +1138,21 @@ void rrc::handle_sib3() { rrc_log->info("SIB3 received\n"); + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3 = ¤t_cell->sib3; + + // cellReselectionInfoCommon + cell_resel_cfg.q_hyst = liblte_rrc_q_hyst_num[sib3->q_hyst]; + + // cellReselectionServingFreqInfo + cell_resel_cfg.threshservinglow = 2*sib3->thresh_serving_low; + + // intraFreqCellReselectionInfo + cell_resel_cfg.Qrxlevmin = 2*sib3->q_rx_lev_min; + if (sib3->s_intra_search_present) { + cell_resel_cfg.s_intrasearchP = 2*sib3->s_intra_search; + } else { + cell_resel_cfg.s_intrasearchP = INFINITY; + } } @@ -2055,16 +2082,19 @@ void rrc::rrc_meas::L3_filter(meas_value_t *value, float values[NOF_MEASUREMENTS void rrc::rrc_meas::new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, float rsrq, uint32_t tti) { - log_h->info("MEAS: New measurement earfcn=%d, pci=%d, rsrp=%f, rsrq=%f, tti=%d\n", earfcn, pci, rsrp, rsrq, tti); - float values[NOF_MEASUREMENTS] = {rsrp, rsrq}; // This indicates serving cell if (earfcn == 0) { + + log_h->info("MEAS: New measurement serving cell, rsrp=%f, rsrq=%f, tti=%d\n", rsrp, rsrq, tti); + L3_filter(&pcell_measurement, values); } else { // Add to known cells parent->add_neighbour_cell(earfcn, pci, rsrp); + log_h->info("MEAS: New measurement earfcn=%d, pci=%d, rsrp=%f, rsrq=%f, tti=%d\n", earfcn, pci, rsrp, rsrq, tti); + // Save PHY measurement for all active measurements whose earfcn/pci matches for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { meas_t *m = &iter->second; diff --git a/srsue/src/upper/usim.cc b/srsue/src/upper/usim.cc index 305da7b25..c460404cc 100644 --- a/srsue/src/upper/usim.cc +++ b/srsue/src/upper/usim.cc @@ -244,6 +244,8 @@ void usim::generate_as_keys(uint8_t *k_asme, count_ul, k_enb); + memcpy(this->k_asme, k_asme, 32); + // Generate K_rrc_enc and K_rrc_int security_generate_k_rrc( k_enb, cipher_algo, @@ -257,10 +259,13 @@ void usim::generate_as_keys(uint8_t *k_asme, integ_algo, k_up_enc, k_up_int); + + current_ncc = 0; } void usim::generate_as_keys_ho(uint32_t pci, uint32_t earfcn, + int ncc, uint8_t *k_rrc_enc, uint8_t *k_rrc_int, uint8_t *k_up_enc, @@ -268,13 +273,39 @@ void usim::generate_as_keys_ho(uint32_t pci, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) { + uint8_t *enb_star_key = k_enb; + + if (ncc < 0) { + ncc = current_ncc; + } + + // Generate successive NH + while(current_ncc != (uint32_t) ncc) { + uint8_t *sync = NULL; + if (current_ncc) { + sync = nh; + } else { + sync = k_enb; + } + // Generate NH + security_generate_nh(k_asme, + sync, + nh); + + current_ncc++; + if (current_ncc == 7) { + current_ncc = 0; + } + enb_star_key = nh; + } // Generate K_enb - security_generate_k_enb_star( k_enb, + security_generate_k_enb_star( enb_star_key, pci, earfcn, k_enb_star); + // K_enb becomes K_enb* memcpy(k_enb, k_enb_star, 32); // Generate K_rrc_enc and K_rrc_int From 84724d2ab122d1d249b50145a1bc746e5be1a327 Mon Sep 17 00:00:00 2001 From: Paul Sutton Date: Thu, 30 Nov 2017 17:09:12 +0000 Subject: [PATCH 12/42] NAS-plane encryption working (thanks to David Rupprecht) --- lib/include/srslte/asn1/liblte_mme.h | 3 + lib/include/srslte/common/common.h | 29 + lib/include/srslte/common/interfaces_common.h | 10 +- lib/include/srslte/common/liblte_security.h | 67 ++ lib/include/srslte/common/liblte_ssl.h | 12 + lib/include/srslte/common/nas_pcap.h | 25 + lib/include/srslte/common/pcap.h | 72 +- lib/include/srslte/common/security.h | 20 + lib/include/srslte/interfaces/ue_interfaces.h | 10 +- lib/include/srslte/upper/pdcp.h | 1 + lib/include/srslte/upper/pdcp_entity.h | 33 +- lib/include/srslte/upper/rlc.h | 1 - lib/src/asn1/liblte_mme.cc | 26 + lib/src/common/liblte_security.cc | 632 ++++++++++++++++++ lib/src/common/mac_pcap.cc | 2 +- lib/src/common/nas_pcap.cc | 35 + lib/src/common/security.cc | 40 ++ lib/src/upper/pdcp.cc | 16 +- lib/src/upper/pdcp_entity.cc | 297 ++++++-- lib/src/upper/rlc.cc | 14 +- lib/src/upper/rlc_am.cc | 76 +-- lib/src/upper/rlc_tm.cc | 8 +- lib/src/upper/rlc_um.cc | 40 +- srsue/hdr/ue.h | 1 + srsue/hdr/ue_base.h | 2 + srsue/hdr/upper/nas.h | 21 +- srsue/hdr/upper/rrc.h | 29 - srsue/src/main.cc | 6 +- srsue/src/ue.cc | 22 +- srsue/src/upper/nas.cc | 223 ++++-- srsue/src/upper/rrc.cc | 11 +- srsue/src/upper/usim.cc | 8 +- srsue/ue.conf.example | 2 + 33 files changed, 1536 insertions(+), 258 deletions(-) create mode 100644 lib/include/srslte/common/nas_pcap.h create mode 100644 lib/src/common/nas_pcap.cc diff --git a/lib/include/srslte/asn1/liblte_mme.h b/lib/include/srslte/asn1/liblte_mme.h index 977f309ce..842fd2e17 100644 --- a/lib/include/srslte/asn1/liblte_mme.h +++ b/lib/include/srslte/asn1/liblte_mme.h @@ -2545,6 +2545,9 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_transaction_identifier_ie(uint8 // Enums // Structs // Functions +LIBLTE_ERROR_ENUM liblte_mme_parse_msg_sec_header(LIBLTE_BYTE_MSG_STRUCT *msg, + uint8 *pd, + uint8 *sec_hdr_type); LIBLTE_ERROR_ENUM liblte_mme_parse_msg_header(LIBLTE_BYTE_MSG_STRUCT *msg, uint8 *pd, uint8 *msg_type); diff --git a/lib/include/srslte/common/common.h b/lib/include/srslte/common/common.h index 41a89fb36..3fd71422b 100644 --- a/lib/include/srslte/common/common.h +++ b/lib/include/srslte/common/common.h @@ -96,6 +96,35 @@ static const char error_text[ERROR_N_ITEMS][20] = { "None", "Can't start", "Already started"}; +// Radio bearers +typedef enum{ + RB_ID_SRB0 = 0, + RB_ID_SRB1, + RB_ID_SRB2, + RB_ID_DRB1, + RB_ID_DRB2, + RB_ID_DRB3, + RB_ID_DRB4, + RB_ID_DRB5, + RB_ID_DRB6, + RB_ID_DRB7, + RB_ID_DRB8, + RB_ID_MAX +} rb_id_t; + +static const char rb_id_str[RB_ID_MAX][8] = {"SRB0", "SRB1", "SRB2", + "DRB1", "DRB2", "DRB3", + "DRB4", "DRB5", "DRB6", + "DRB7", "DRB8"}; + +inline const char* get_rb_name(uint32_t lcid) { + if (lcid < RB_ID_MAX) { + return rb_id_str[lcid]; + } else { + return "INVALID_RB"; + } +} + /****************************************************************************** * Byte and Bit buffers * diff --git a/lib/include/srslte/common/interfaces_common.h b/lib/include/srslte/common/interfaces_common.h index a027b6230..5fe26bc13 100644 --- a/lib/include/srslte/common/interfaces_common.h +++ b/lib/include/srslte/common/interfaces_common.h @@ -52,14 +52,12 @@ public: :direction(direction_) ,is_control(is_control_) ,is_data(is_data_) - ,do_security(false) ,sn_len(12) {} - uint8_t direction; - bool is_control; - bool is_data; - bool do_security; - uint8_t sn_len; + uint8_t direction; + bool is_control; + bool is_data; + uint8_t sn_len; // TODO: Support the following configurations // bool do_rohc; diff --git a/lib/include/srslte/common/liblte_security.h b/lib/include/srslte/common/liblte_security.h index b49f7211b..ebdbddd2f 100644 --- a/lib/include/srslte/common/liblte_security.h +++ b/lib/include/srslte/common/liblte_security.h @@ -185,6 +185,73 @@ LIBLTE_ERROR_ENUM liblte_security_128_eia2(uint8 *key, LIBLTE_BIT_MSG_STRUCT *msg, uint8 *mac); +/********************************************************************* + Name: liblte_security_encryption_eea1 + + Description: 128-bit encryption algorithm EEA1. + + Document Reference: 33.401 v13.1.0 Annex B.1.2 + 35.215 v13.0.0 References + Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D1 v2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_encryption_eea1(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *msg, + uint32 msg_len, + uint8 *out); + +/********************************************************************* + Name: liblte_security_decryption_eea1 + + Description: 128-bit decryption algorithm EEA1. + + Document Reference: 33.401 v13.1.0 Annex B.1.2 + 35.215 v13.0.0 References + Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D1 v2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_decryption_eea1(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *ct, + uint32 ct_len, + uint8 *out); + +/********************************************************************* + Name: liblte_security_encryption_eea2 + + Description: 128-bit encryption algorithm EEA2. + + Document Reference: 33.401 v13.1.0 Annex B.1.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_encryption_eea2(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *msg, + uint32 msg_len, + uint8 *out); + +/********************************************************************* + Name: liblte_security_decryption_eea2 + + Description: 128-bit decryption algorithm EEA2. + + Document Reference: 33.401 v13.1.0 Annex B.1.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_decryption_eea2(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *ct, + uint32 ct_len, + uint8 *out); + + /********************************************************************* Name: liblte_security_milenage_f1 diff --git a/lib/include/srslte/common/liblte_ssl.h b/lib/include/srslte/common/liblte_ssl.h index 886d557b1..d96c728ab 100644 --- a/lib/include/srslte/common/liblte_ssl.h +++ b/lib/include/srslte/common/liblte_ssl.h @@ -38,6 +38,18 @@ int aes_crypt_ecb( aes_context *ctx, return mbedtls_aes_crypt_ecb(ctx, mode, input, output); } +int aes_crypt_ctr(aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + return mbedtls_aes_crypt_ctr(ctx, length, nc_off, nonce_counter, + stream_block, input, output); +} + void sha256(const unsigned char *key, size_t keylen, const unsigned char *input, size_t ilen, unsigned char output[32], int is224 ) diff --git a/lib/include/srslte/common/nas_pcap.h b/lib/include/srslte/common/nas_pcap.h new file mode 100644 index 000000000..68fcabb73 --- /dev/null +++ b/lib/include/srslte/common/nas_pcap.h @@ -0,0 +1,25 @@ +#ifndef NAS_PCAP_H +#define NAS_PCAP_H + +#include "srslte/common/pcap.h" + +namespace srslte { + +class nas_pcap +{ +public: + nas_pcap() {enable_write=false; ue_id=0; pcap_file = NULL; } + void enable(); + void open(const char *filename, uint32_t ue_id=0); + void close(); + void write_nas(uint8_t *pdu, uint32_t pdu_len_bytes); +private: + bool enable_write; + FILE *pcap_file; + uint32_t ue_id; + void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes); +}; + +} //namespace srsue + +#endif // NAS_PCAP_H diff --git a/lib/include/srslte/common/pcap.h b/lib/include/srslte/common/pcap.h index db1dc17d0..611aea72d 100644 --- a/lib/include/srslte/common/pcap.h +++ b/lib/include/srslte/common/pcap.h @@ -33,6 +33,8 @@ #include #define MAC_LTE_DLT 147 +#define RRC_LTE_DLT 148 +#define NAS_LTE_DLT 149 /* This structure gets written to the start of the file */ @@ -113,7 +115,10 @@ typedef struct MAC_Context_Info_t { } MAC_Context_Info_t; - +/* Context information for every NAS PDU that will be logged */ +typedef struct NAS_Context_Info_s { + // No Context yet +} NAS_Context_Info_t; /**************************************************************************/ @@ -218,4 +223,69 @@ inline void MAC_LTE_PCAP_Close(FILE *fd) fclose(fd); } + +/**************************************************************************/ +/* API functions for opening/writing/closing NAS-LTE PCAP files */ + +/* Open the file and write file header */ +inline FILE *NAS_LTE_PCAP_Open(const char *fileName) +{ + pcap_hdr_t file_header = + { + 0xa1b2c3d4, /* magic number */ + 2, 4, /* version number is 2.4 */ + 0, /* timezone */ + 0, /* sigfigs - apparently all tools do this */ + 65535, /* snaplen - this should be long enough */ + NAS_LTE_DLT /* Data Link Type (DLT). Set as unused value 149 for now */ + }; + + FILE *fd = fopen(fileName, "w"); + if (fd == NULL) { + printf("Failed to open file \"%s\" for writing\n", fileName); + return NULL; + } + + /* Write the file header */ + fwrite(&file_header, sizeof(pcap_hdr_t), 1, fd); + + return fd; +} + +/* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */ +inline int NAS_LTE_PCAP_WritePDU(FILE *fd, NAS_Context_Info_t *context, + const unsigned char *PDU, unsigned int length) +{ + pcaprec_hdr_t packet_header; + + /* Can't write if file wasn't successfully opened */ + if (fd == NULL) { + printf("Error: Can't write to empty file handle\n"); + return 0; + } + + /****************************************************************/ + /* PCAP Header */ + struct timeval t; + gettimeofday(&t, NULL); + packet_header.ts_sec = t.tv_sec; + packet_header.ts_usec = t.tv_usec; + packet_header.incl_len = length; + packet_header.orig_len = length; + + /***************************************************************/ + /* Now write everything to the file */ + fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, fd); + fwrite(PDU, 1, length, fd); + + return 1; +} + +/* Close the PCAP file */ +inline void NAS_LTE_PCAP_Close(FILE *fd) +{ + if(fd) + fclose(fd); +} + #endif /* UEPCAP_H */ diff --git a/lib/include/srslte/common/security.h b/lib/include/srslte/common/security.h index 080f1848f..6ef23bafe 100644 --- a/lib/include/srslte/common/security.h +++ b/lib/include/srslte/common/security.h @@ -114,6 +114,26 @@ uint8_t security_128_eia2( uint8_t *key, uint32_t msg_len, uint8_t *mac); +/****************************************************************************** + * Encryption / Decryption + *****************************************************************************/ + +uint8_t security_128_eea1( uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *msg_out); + +uint8_t security_128_eea2(uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *msg_out); + /****************************************************************************** * Authentication *****************************************************************************/ diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index f083c89e2..37d73b910 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -118,15 +118,15 @@ public: class nas_interface_ue { public: - virtual void attach_request() = 0; - virtual void deattach_request() = 0; + virtual void attach_request() = 0; + virtual void deattach_request() = 0; }; // NAS interface for UE class nas_interface_gw { public: - virtual void attach_request() = 0; + virtual void attach_request() = 0; }; // RRC interface for MAC @@ -162,7 +162,6 @@ public: virtual void enable_capabilities() = 0; virtual void plmn_search() = 0; virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) = 0; - virtual std::string get_rb_name(uint32_t lcid) = 0; }; // RRC interface for PDCP @@ -173,7 +172,6 @@ public: virtual void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu_pcch(srslte::byte_buffer_t *pdu) = 0; - virtual std::string get_rb_name(uint32_t lcid) = 0; }; // RRC interface for RLC @@ -181,7 +179,6 @@ class rrc_interface_rlc { public: virtual void max_retx_attempted() = 0; - virtual std::string get_rb_name(uint32_t lcid) = 0; }; // PDCP interface for GW @@ -204,6 +201,7 @@ public: uint8_t *k_rrc_int_, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0; + virtual void enable_encryption(uint32_t lcid) = 0; }; // PDCP interface for RLC diff --git a/lib/include/srslte/upper/pdcp.h b/lib/include/srslte/upper/pdcp.h index ce6ece151..f52fdbe05 100644 --- a/lib/include/srslte/upper/pdcp.h +++ b/lib/include/srslte/upper/pdcp.h @@ -62,6 +62,7 @@ public: uint8_t *k_rrc_int, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo); + void enable_encryption(uint32_t lcid); // RLC interface void write_pdu(uint32_t lcid, byte_buffer_t *sdu); diff --git a/lib/include/srslte/upper/pdcp_entity.h b/lib/include/srslte/upper/pdcp_entity.h index 0ff005d07..bf1e8b5b2 100644 --- a/lib/include/srslte/upper/pdcp_entity.h +++ b/lib/include/srslte/upper/pdcp_entity.h @@ -32,6 +32,8 @@ #include "srslte/common/common.h" #include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/security.h" +#include "srslte/common/msg_queue.h" +#include "srslte/common/threads.h" namespace srslte { @@ -59,6 +61,7 @@ static const char pdcp_d_c_text[PDCP_D_C_N_ITEMS][20] = {"Control PDU", * Common interface for all PDCP entities ***************************************************************************/ class pdcp_entity + :public thread { public: pdcp_entity(); @@ -68,6 +71,7 @@ public: srslte::log *log_, uint32_t lcid_, srslte_pdcp_config_t cfg_); + void stop(); void reset(); bool is_active(); @@ -78,6 +82,7 @@ public: uint8_t *k_rrc_int_, CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, INTEGRITY_ALGORITHM_ID_ENUM integ_algo_); + void enable_encryption(); // RLC interface void write_pdu(byte_buffer_t *pdu); @@ -90,9 +95,15 @@ private: srsue::rrc_interface_pdcp *rrc; srsue::gw_interface_pdcp *gw; + static const int PDCP_THREAD_PRIO = 7; + srslte::msg_queue rx_pdu_queue; + bool running; + bool active; uint32_t lcid; srslte_pdcp_config_t cfg; + bool do_integrity; + bool do_encryption; uint32_t rx_count; uint32_t tx_count; @@ -102,14 +113,26 @@ private: CIPHERING_ALGORITHM_ID_ENUM cipher_algo; INTEGRITY_ALGORITHM_ID_ENUM integ_algo; - void integrity_generate(uint8_t *key_128, - uint32_t count, - uint8_t rb_id, - uint8_t direction, - uint8_t *msg, + void integrity_generate(uint8_t *msg, uint32_t msg_len, uint8_t *mac); + bool integrity_verify(uint8_t *msg, + uint32_t count, + uint32_t msg_len, + uint8_t *mac); + + void cipher_encrypt(uint8_t *msg, + uint32_t msg_len, + uint8_t *ct); + + void cipher_decrypt(uint8_t *ct, + uint32_t count, + uint32_t ct_len, + uint8_t *msg); + + void run_thread(); + }; /**************************************************************************** diff --git a/lib/include/srslte/upper/rlc.h b/lib/include/srslte/upper/rlc.h index 349a7952d..fb0a82587 100644 --- a/lib/include/srslte/upper/rlc.h +++ b/lib/include/srslte/upper/rlc.h @@ -64,7 +64,6 @@ public: // PDCP interface void write_sdu(uint32_t lcid, byte_buffer_t *sdu); - std::string get_rb_name(uint32_t lcid); // MAC interface uint32_t get_buffer_state(uint32_t lcid); diff --git a/lib/src/asn1/liblte_mme.cc b/lib/src/asn1/liblte_mme.cc index 215ffd838..ce3c08987 100644 --- a/lib/src/asn1/liblte_mme.cc +++ b/lib/src/asn1/liblte_mme.cc @@ -4922,6 +4922,32 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_transaction_identifier_ie(uint8 MESSAGE FUNCTIONS *******************************************************************************/ +/********************************************************************* + Message Name: Security Message Header (Plain NAS Message) + + Description: Security header for NAS messages. + + Document Reference: 24.301 v10.2.0 Section 9.1 +*********************************************************************/ + +LIBLTE_ERROR_ENUM liblte_mme_parse_msg_sec_header(LIBLTE_BYTE_MSG_STRUCT *msg, + uint8 *pd, + uint8 *sec_hdr_type) +{ + + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if (msg != NULL && + pd != NULL && + sec_hdr_type != NULL) + { + *sec_hdr_type = (uint8) ((msg->msg[0] & 0xF0) >> 4); + err = LIBLTE_SUCCESS; + } + return(err); +} + + /********************************************************************* Message Name: Message Header (Plain NAS Message) diff --git a/lib/src/common/liblte_security.cc b/lib/src/common/liblte_security.cc index 95f9617cd..4ff35b5e4 100644 --- a/lib/src/common/liblte_security.cc +++ b/lib/src/common/liblte_security.cc @@ -55,6 +55,11 @@ typedef struct{ uint8 state[4][4]; }STATE_STRUCT; +typedef struct{ + uint32 * lfsr; + uint32 * fsm; +}S3G_STATE; + /******************************************************************************* GLOBAL VARIABLES *******************************************************************************/ @@ -76,6 +81,35 @@ static const uint8 S[256] = { 99,124,119,123,242,107,111,197, 48, 1,103, 43,254 225,248,152, 17,105,217,142,148,155, 30,135,233,206, 85, 40,223, 140,161,137, 13,191,230, 66,104, 65,153, 45, 15,176, 84,187, 22}; +/* S-box SQ */ +static const uint8 SQ[256] = { 0x25, 0x24, 0x73, 0x67, 0xD7, 0xAE, + 0x5C, 0x30, 0xA4, 0xEE, 0x6E, 0xCB, 0x7D, 0xB5, 0x82, 0xDB, + 0xE4, 0x8E, 0x48, 0x49, 0x4F, 0x5D, 0x6A, 0x78, 0x70, 0x88, + 0xE8, 0x5F, 0x5E, 0x84, 0x65, 0xE2, 0xD8, 0xE9, 0xCC, 0xED, + 0x40, 0x2F, 0x11, 0x28, 0x57, 0xD2, 0xAC, 0xE3, 0x4A, 0x15, + 0x1B, 0xB9, 0xB2, 0x80, 0x85, 0xA6, 0x2E, 0x02, 0x47, 0x29, + 0x07, 0x4B, 0x0E, 0xC1, 0x51, 0xAA, 0x89, 0xD4, 0xCA, 0x01, + 0x46, 0xB3, 0xEF, 0xDD, 0x44, 0x7B, 0xC2, 0x7F, 0xBE, 0xC3, + 0x9F, 0x20, 0x4C, 0x64, 0x83, 0xA2, 0x68, 0x42, 0x13, 0xB4, + 0x41, 0xCD, 0xBA, 0xC6, 0xBB, 0x6D, 0x4D, 0x71, 0x21, 0xF4, + 0x8D, 0xB0, 0xE5, 0x93, 0xFE, 0x8F, 0xE6, 0xCF, 0x43, 0x45, + 0x31, 0x22, 0x37, 0x36, 0x96, 0xFA, 0xBC, 0x0F, 0x08, 0x52, + 0x1D, 0x55, 0x1A, 0xC5, 0x4E, 0x23, 0x69, 0x7A, 0x92, 0xFF, + 0x5B, 0x5A, 0xEB, 0x9A, 0x1C, 0xA9, 0xD1, 0x7E, 0x0D, 0xFC, + 0x50, 0x8A, 0xB6, 0x62, 0xF5, 0x0A, 0xF8, 0xDC, 0x03, 0x3C, + 0x0C, 0x39, 0xF1, 0xB8, 0xF3, 0x3D, 0xF2, 0xD5, 0x97, 0x66, + 0x81, 0x32, 0xA0, 0x00, 0x06, 0xCE, 0xF6, 0xEA, 0xB7, 0x17, + 0xF7, 0x8C, 0x79, 0xD6, 0xA7, 0xBF, 0x8B, 0x3F, 0x1F, 0x53, + 0x63, 0x75, 0x35, 0x2C, 0x60, 0xFD, 0x27, 0xD3, 0x94, 0xA5, + 0x7C, 0xA1, 0x05, 0x58, 0x2D, 0xBD, 0xD9, 0xC7, 0xAF, 0x6B, + 0x54, 0x0B, 0xE0, 0x38, 0x04, 0xC8, 0x9D, 0xE7, 0x14, 0xB1, + 0x87, 0x9C, 0xDF, 0x6F, 0xF9, 0xDA, 0x2A, 0xC4, 0x59, 0x16, + 0x74, 0x91, 0xAB, 0x26, 0x61, 0x76, 0x34, 0x2B, 0xAD, 0x99, + 0xFB, 0x72, 0xEC, 0x33, 0x12, 0xDE, 0x98, 0x3B, 0xC0, 0x9B, + 0x3E, 0x18, 0x10, 0x3A, 0x56, 0xE1, 0x77, 0xC9, 0x1E, 0x9E, + 0x95, 0xA3, 0x90, 0x19, 0xA8, 0x6C, 0x09, 0xD0, 0xF0, 0x86 }; + + static const uint8 X_TIME[256] = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, @@ -195,6 +229,136 @@ void shift_row(STATE_STRUCT *state); // Functions void mix_column(STATE_STRUCT *state); +/********************************************************************* + Name: zero_tailing_bits + + Description: Fill tailing bits with zeros. + + Document Reference: - +*********************************************************************/ +void zero_tailing_bits(uint8 * data, uint32 length_bits); + +/********************************************************************* + Name: s3g_mul_x + + Description: Multiplication with reduction. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.1.1 +*********************************************************************/ +uint8 s3g_mul_x(uint8 v, uint8 c); + +/********************************************************************* + Name: s3g_mul_x_pow + + Description: Recursive multiplication with reduction. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.1.2 +*********************************************************************/ +uint8 s3g_mul_x_pow(uint8 v, uint8 i, uint8 c); + +/********************************************************************* + Name: s3g_mul_alpha + + Description: Multiplication with alpha. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.2 +*********************************************************************/ +uint32 s3g_mul_alpha(uint8 c); + +/********************************************************************* + Name: s3g_div_alpha + + Description: Division by alpha. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.3 +*********************************************************************/ +uint32 s3g_div_alpha(uint8 c); + +/********************************************************************* + Name: s3g_s1 + + Description: S-Box S1. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.3.1 +*********************************************************************/ +uint32 s3g_s1(uint32 w); + +/********************************************************************* + Name: s3g_s2 + + Description: S-Box S2. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.3.2 +*********************************************************************/ +uint32 s3g_s2(uint32 w); + +/********************************************************************* + Name: s3g_clock_lfsr + + Description: Clocking LFSR. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.4 and Section 3.4.5 +*********************************************************************/ +void s3g_clock_lfsr(S3G_STATE * state, uint32 f); + +/********************************************************************* + Name: s3g_clock_fsm + + Description: Clocking FSM. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.6 +*********************************************************************/ +uint32 s3g_clock_fsm(S3G_STATE * state); + +/********************************************************************* + Name: s3g_initialize + + Description: Initialization. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 4.1 +*********************************************************************/ +void s3g_initialize(S3G_STATE * state, uint32 k[4], uint32 iv[4]); + +/********************************************************************* + Name: s3g_deinitialize + + Description: Deinitialization. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 +*********************************************************************/ +void s3g_deinitialize(S3G_STATE * state); + +/********************************************************************* + Name: s3g_generate_keystream + + Description: Generation of Keystream. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 4.2 +*********************************************************************/ +void s3g_generate_keystream(S3G_STATE * state, uint32 n, uint32 *ks); + + /******************************************************************************* FUNCTIONS *******************************************************************************/ @@ -682,6 +846,184 @@ LIBLTE_ERROR_ENUM liblte_security_128_eia2(uint8 *key, return(err); } +/********************************************************************* + Name: liblte_security_encryption_eea1 + + Description: 128-bit encryption algorithm EEA1. + + Document Reference: 33.401 v13.1.0 Annex B.1.2 + 35.215 v13.0.0 References + Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D1 v2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_encryption_eea1(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *msg, + uint32 msg_len, + uint8 *out) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + S3G_STATE state, *state_ptr; + uint32 k[] = {0,0,0,0}; + uint32 iv[] = {0,0,0,0}; + uint32 *ks; + int32 i; + uint32 msg_len_block_8, msg_len_block_32, m; + + if (key != NULL && + msg != NULL && + out != NULL) + { + state_ptr = &state; + msg_len_block_8 = (msg_len + 7) / 8; + msg_len_block_32 = (msg_len + 31) / 32; + + // Transform key + for (i = 3; i >= 0; i--) { + k[i] = (key[4 * (3 - i) + 0] << 24) | + (key[4 * (3 - i) + 1] << 16) | + (key[4 * (3 - i) + 2] << 8) | + (key[4 * (3 - i) + 3]); + } + + // Construct iv + iv[3] = count; + iv[2] = ((bearer & 0x1F) << 27) | ((direction & 0x01) << 26); + iv[1] = iv[3]; + iv[0] = iv[2]; + + // Initialize keystream + s3g_initialize(state_ptr, k, iv); + + // Generate keystream + + ks = (uint32 *) calloc(msg_len_block_32, sizeof(uint32)); + s3g_generate_keystream(state_ptr, msg_len_block_32, ks); + + // Generate output except last block + for (i = 0; i < msg_len_block_32 - 1; i++) { + out[4 * i + 0] = msg[4 * i + 0] ^ ((ks[i] >> 24) & 0xFF); + out[4 * i + 1] = msg[4 * i + 1] ^ ((ks[i] >> 16) & 0xFF); + out[4 * i + 2] = msg[4 * i + 2] ^ ((ks[i] >> 8) & 0xFF); + out[4 * i + 3] = msg[4 * i + 3] ^ ((ks[i] & 0xFF)); + } + + // Process last bytes + for (i = (msg_len_block_32 - 1) * 4; i < msg_len_block_8; + i++) { + out[i] = msg[i] ^ ((ks[i / 4] >> ((3 - (i % 4)) * 8)) & 0xFF); + } + + // Zero tailing bits + zero_tailing_bits(out, msg_len); + + // Clean up + free(ks); + s3g_deinitialize(state_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Name: liblte_security_decryption_eea1 + + Description: 128-bit decryption algorithm EEA1. + + Document Reference: 33.401 v13.1.0 Annex B.1.2 + 35.215 v13.0.0 References + Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D1 v2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_decryption_eea1(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *ct, + uint32 ct_len, + uint8 *out) { + return liblte_security_encryption_eea1(key, count, bearer, + direction, ct, ct_len, out); +} + +/********************************************************************* + Name: liblte_security_encryption_eea2 + + Description: 128-bit encryption algorithm EEA2. + + Document Reference: 33.401 v13.1.0 Annex B.1.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_encryption_eea2(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *msg, + uint32 msg_len, + uint8 *out) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + aes_context ctx; + unsigned char stream_blk[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + unsigned char nonce_cnt[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + int32 i; + int ret; + size_t nc_off = 0; + + if(key != NULL && + msg != NULL && + out != NULL) + { + ret = aes_setkey_enc(&ctx, key, 128); + + if (ret == 0) { + // Construct nonce + nonce_cnt[0] = (count >> 24) & 0xFF; + nonce_cnt[1] = (count >> 16) & 0xFF; + nonce_cnt[2] = (count >> 8) & 0xFF; + nonce_cnt[3] = (count) & 0xFF; + nonce_cnt[4] = ((bearer & 0x1F) << 3) | + ((direction & 0x01) << 2); + + // Encryption + ret = aes_crypt_ctr(&ctx, (msg_len + 7) / 8, &nc_off, nonce_cnt, + stream_blk, msg, out); + } + + if (ret == 0) { + // Zero tailing bits + zero_tailing_bits(out, msg_len); + err = LIBLTE_SUCCESS; + } + } + + return(err); +} + +/********************************************************************* + Name: liblte_security_decryption_eea2 + + Description: 128-bit decryption algorithm EEA2. + + Document Reference: 33.401 v13.1.0 Annex B.1.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_decryption_eea2(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *ct, + uint32 ct_len, + uint8 *out) +{ + return liblte_security_encryption_eea2(key, count, bearer, + direction, ct, ct_len, out); +} + + + /********************************************************************* Name: liblte_security_milenage_f1 @@ -1243,3 +1585,293 @@ void mix_column(STATE_STRUCT *state) state->state[3][i] ^= temp ^ tmp; } } + +/********************************************************************* + Name: zero_tailing_bits + + Description: Fill tailing bits with zeros. + + Document Reference: - +*********************************************************************/ +void zero_tailing_bits(uint8 * data, uint32 length_bits) { + uint8 bits = (8 - (length_bits & 0x07)) & 0x07; + data[(length_bits + 7) / 8 - 1] &= (uint8) (0xFF << bits); +} + +/********************************************************************* + Name: s3g_mul_x + + Description: Multiplication with reduction. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.1.1 +*********************************************************************/ +uint8 s3g_mul_x(uint8 v, uint8 c) { + if (v & 0x80) + return ((v << 1) ^ c); + else + return (v << 1); +} + +/********************************************************************* + Name: s3g_mul_x_pow + + Description: Recursive multiplication with reduction. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.1.2 +*********************************************************************/ +uint8 s3g_mul_x_pow(uint8 v, uint8 i, uint8 c) { + if (i == 0) + return v; + else + return s3g_mul_x(s3g_mul_x_pow(v, i - 1, c), c); +} + +/********************************************************************* + Name: s3g_mul_alpha + + Description: Multiplication with alpha. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.2 +*********************************************************************/ +uint32 s3g_mul_alpha(uint8 c) { + return ((((uint32) s3g_mul_x_pow(c, 23, 0xa9)) << 24) | + (((uint32) s3g_mul_x_pow(c, 245, 0xa9)) << 16) | + (((uint32) s3g_mul_x_pow(c, 48, 0xa9)) << 8) | + (((uint32) s3g_mul_x_pow(c, 239, 0xa9)))); +} + +/********************************************************************* + Name: s3g_div_alpha + + Description: Division by alpha. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.3 +*********************************************************************/ +uint32 s3g_div_alpha(uint8 c) { + return ((((uint32) s3g_mul_x_pow(c, 16, 0xa9)) << 24) | + (((uint32) s3g_mul_x_pow(c, 39, 0xa9)) << 16) | + (((uint32) s3g_mul_x_pow(c, 6, 0xa9)) << 8) | + (((uint32) s3g_mul_x_pow(c, 64, 0xa9)))); +} + +/********************************************************************* + Name: s3g_s1 + + Description: S-Box S1. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.3.1 +*********************************************************************/ +uint32 s3g_s1(uint32 w) { + uint8 r0 = 0, r1 = 0, r2 = 0, r3 = 0; + uint8 srw0 = S[(uint8) ((w >> 24) & 0xff)]; + uint8 srw1 = S[(uint8) ((w >> 16) & 0xff)]; + uint8 srw2 = S[(uint8) ((w >> 8) & 0xff)]; + uint8 srw3 = S[(uint8) ((w) & 0xff)]; + + r0 = ((s3g_mul_x(srw0, 0x1b)) ^ + (srw1) ^ + (srw2) ^ + ((s3g_mul_x(srw3, 0x1b)) ^ srw3)); + + r1 = (((s3g_mul_x(srw0, 0x1b)) ^ srw0) ^ + (s3g_mul_x(srw1, 0x1b)) ^ + (srw2) ^ + (srw3)); + + r2 = ((srw0) ^ + ((s3g_mul_x(srw1, 0x1b)) ^ srw1) ^ + (s3g_mul_x(srw2, 0x1b)) ^ + (srw3)); + + r3 = ((srw0) ^ + (srw1) ^ + ((s3g_mul_x(srw2, 0x1b)) ^ srw2) ^ + (s3g_mul_x(srw3, 0x1b))); + + return ((((uint32) r0) << 24) | + (((uint32) r1) << 16) | + (((uint32) r2) << 8) | + (((uint32) r3))); +} + +/********************************************************************* + Name: s3g_s2 + + Description: S-Box S2. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.3.2 +*********************************************************************/ +uint32 s3g_s2(uint32 w) { + uint8 r0 = 0, r1 = 0, r2 = 0, r3 = 0; + uint8 sqw0 = SQ[(uint8) ((w >> 24) & 0xff)]; + uint8 sqw1 = SQ[(uint8) ((w >> 16) & 0xff)]; + uint8 sqw2 = SQ[(uint8) ((w >> 8) & 0xff)]; + uint8 sqw3 = SQ[(uint8) ((w) & 0xff)]; + + r0 = ((s3g_mul_x(sqw0, 0x69)) ^ + (sqw1) ^ + (sqw2) ^ + ((s3g_mul_x(sqw3, 0x69)) ^ sqw3)); + + r1 = (((s3g_mul_x(sqw0, 0x69)) ^ sqw0) ^ + (s3g_mul_x(sqw1, 0x69)) ^ + (sqw2) ^ + (sqw3)); + + r2 = ((sqw0) ^ + ((s3g_mul_x(sqw1, 0x69)) ^ sqw1) ^ + (s3g_mul_x(sqw2, 0x69)) ^ + (sqw3)); + + r3 = ((sqw0) ^ + (sqw1) ^ + ((s3g_mul_x(sqw2, 0x69)) ^ sqw2) ^ + (s3g_mul_x(sqw3, 0x69))); + + return ((((uint32) r0) << 24) | + (((uint32) r1) << 16) | + (((uint32) r2) << 8) | + (((uint32) r3))); +} + +/********************************************************************* + Name: s3g_clock_lfsr + + Description: Clocking LFSR. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.4 and Section 3.4.5 +*********************************************************************/ +void s3g_clock_lfsr(S3G_STATE * state, uint32 f) { + uint32 v = ( + ((state->lfsr[0] << 8) & 0xffffff00) ^ + (s3g_mul_alpha((uint8) ((state->lfsr[0] >> 24) & 0xff))) ^ + (state->lfsr[2]) ^ + ((state->lfsr[11] >> 8) & 0x00ffffff) ^ + (s3g_div_alpha((uint8) ((state->lfsr[11]) & 0xff))) ^ + (f) + ); + uint8 i; + + for (i = 0; i < 15; i++) { + state->lfsr[i] = state->lfsr[i + 1]; + } + state->lfsr[15] = v; +} + +/********************************************************************* + Name: s3g_clock_fsm + + Description: Clocking FSM. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.6 +*********************************************************************/ +uint32 s3g_clock_fsm(S3G_STATE * state) { + uint32 f = ((state->lfsr[15] + state->fsm[0]) & 0xffffffff) ^ + state->fsm[1]; + uint32 r = (state->fsm[1] + (state->fsm[2] ^ state->lfsr[5])) & + 0xffffffff; + + state->fsm[2] = s3g_s2(state->fsm[1]); + state->fsm[1] = s3g_s1(state->fsm[0]); + state->fsm[0] = r; + + return f; +} + +/********************************************************************* + Name: s3g_initialize + + Description: Initialization. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 4.1 +*********************************************************************/ +void s3g_initialize(S3G_STATE * state, uint32 k[4], uint32 iv[4]) { + uint8 i = 0; + uint32 f = 0x0; + + state->lfsr = (uint32 *) calloc(16, sizeof(uint32)); + state->fsm = (uint32 *) calloc( 3, sizeof(uint32)); + + state->lfsr[15] = k[3] ^ iv[0]; + state->lfsr[14] = k[2]; + state->lfsr[13] = k[1]; + state->lfsr[12] = k[0] ^ iv[1]; + + state->lfsr[11] = k[3] ^ 0xffffffff; + state->lfsr[10] = k[2] ^ 0xffffffff ^ iv[2]; + state->lfsr[ 9] = k[1] ^ 0xffffffff ^ iv[3]; + state->lfsr[ 8] = k[0] ^ 0xffffffff; + state->lfsr[ 7] = k[3]; + state->lfsr[ 6] = k[2]; + state->lfsr[ 5] = k[1]; + state->lfsr[ 4] = k[0]; + state->lfsr[ 3] = k[3] ^ 0xffffffff; + state->lfsr[ 2] = k[2] ^ 0xffffffff; + state->lfsr[ 1] = k[1] ^ 0xffffffff; + state->lfsr[ 0] = k[0] ^ 0xffffffff; + + state->fsm[0] = 0x0; + state->fsm[1] = 0x0; + state->fsm[2] = 0x0; + for (i = 0; i < 32; i++) { + f = s3g_clock_fsm(state); + s3g_clock_lfsr(state, f); + } +} + +/********************************************************************* + Name: s3g_deinitialize + + Description: Deinitialization. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 +*********************************************************************/ +void s3g_deinitialize(S3G_STATE * state) { + free(state->lfsr); + free(state->fsm); +} + +/********************************************************************* + Name: s3g_generate_keystream + + Description: Generation of Keystream. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 4.2 +*********************************************************************/ +void s3g_generate_keystream(S3G_STATE * state, uint32 n, uint32 *ks) { + uint32 t = 0; + uint32 f = 0x0; + + // Clock FSM once. Discard the output. + s3g_clock_fsm(state); + // Clock LFSR in keystream mode once. + s3g_clock_lfsr(state, 0x0); + + for (t = 0; t < n; t++) { + f = s3g_clock_fsm(state); + // Note that ks[t] corresponds to z_{t+1} in section 4.2 + ks[t] = f ^ state->lfsr[0]; + s3g_clock_lfsr(state, 0x0); + } +} diff --git a/lib/src/common/mac_pcap.cc b/lib/src/common/mac_pcap.cc index ff30670ed..b73181e73 100644 --- a/lib/src/common/mac_pcap.cc +++ b/lib/src/common/mac_pcap.cc @@ -46,7 +46,7 @@ void mac_pcap::open(const char* filename, uint32_t ue_id) } void mac_pcap::close() { - fprintf(stdout, "Saving PCAP file\n"); + fprintf(stdout, "Saving MAC PCAP file\n"); MAC_LTE_PCAP_Close(pcap_file); } diff --git a/lib/src/common/nas_pcap.cc b/lib/src/common/nas_pcap.cc new file mode 100644 index 000000000..80603f8d5 --- /dev/null +++ b/lib/src/common/nas_pcap.cc @@ -0,0 +1,35 @@ +#include +#include "srslte/srslte.h" +#include "srslte/common/pcap.h" +#include "srslte/common/nas_pcap.h" + + +namespace srslte { + +void nas_pcap::enable() +{ + enable_write = true; +} +void nas_pcap::open(const char* filename, uint32_t ue_id) +{ + pcap_file = NAS_LTE_PCAP_Open(filename); + ue_id = ue_id; + enable_write = true; +} +void nas_pcap::close() +{ + fprintf(stdout, "Saving NAS PCAP file\n"); + MAC_LTE_PCAP_Close(pcap_file); +} + +void nas_pcap::write_nas(uint8_t *pdu, uint32_t pdu_len_bytes) +{ + if (enable_write) { + NAS_Context_Info_t context; + if (pdu) { + NAS_LTE_PCAP_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); + } + } +} + +} diff --git a/lib/src/common/security.cc b/lib/src/common/security.cc index f0ad1ce7e..3f2dcff03 100644 --- a/lib/src/common/security.cc +++ b/lib/src/common/security.cc @@ -146,6 +146,46 @@ uint8_t security_128_eia2( uint8_t *key, mac); } +/****************************************************************************** + * Encryption / Decryption + *****************************************************************************/ + +uint8_t security_128_eea1(uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *msg_out){ + + return liblte_security_encryption_eea1(key, + count, + bearer, + direction, + msg, + msg_len * 8, + msg_out); + +} + + +uint8_t security_128_eea2(uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *msg_out){ + + return liblte_security_encryption_eea2(key, + count, + bearer, + direction, + msg, + msg_len * 8, + msg_out); +} + /****************************************************************************** * Authentication *****************************************************************************/ diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc index 0acc7f6bd..ed7e13684 100644 --- a/lib/src/upper/pdcp.cc +++ b/lib/src/upper/pdcp.cc @@ -51,7 +51,11 @@ void pdcp::init(srsue::rlc_interface_pdcp *rlc_, srsue::rrc_interface_pdcp *rrc_ } void pdcp::stop() -{} +{ + for(uint32_t i=0;iinfo("Added bearer %s\n", rrc->get_rb_name(lcid).c_str()); + pdcp_log->info("Added bearer %s\n", get_rb_name(lcid)); } else { - pdcp_log->warning("Bearer %s already configured. Reconfiguration not supported\n", rrc->get_rb_name(lcid).c_str()); + pdcp_log->warning("Bearer %s already configured. Reconfiguration not supported\n", get_rb_name(lcid)); } } @@ -104,6 +108,12 @@ void pdcp::config_security(uint32_t lcid, pdcp_array[lcid].config_security(k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); } +void pdcp::enable_encryption(uint32_t lcid) +{ + if(valid_lcid(lcid)) + pdcp_array[lcid].enable_encryption(); +} + /******************************************************************************* RLC interface *******************************************************************************/ diff --git a/lib/src/upper/pdcp_entity.cc b/lib/src/upper/pdcp_entity.cc index 9f658a577..066bb127f 100644 --- a/lib/src/upper/pdcp_entity.cc +++ b/lib/src/upper/pdcp_entity.cc @@ -45,25 +45,37 @@ void pdcp_entity::init(srsue::rlc_interface_pdcp *rlc_, uint32_t lcid_, srslte_pdcp_config_t cfg_) { - rlc = rlc_; - rrc = rrc_; - gw = gw_; - log = log_; - lcid = lcid_; - cfg = cfg_; - active = true; - - tx_count = 0; - rx_count = 0; + rlc = rlc_; + rrc = rrc_; + gw = gw_; + log = log_; + lcid = lcid_; + cfg = cfg_; + active = true; + tx_count = 0; + rx_count = 0; + do_integrity = false; + do_encryption = false; + + start(PDCP_THREAD_PRIO); + + log->debug("Init %s\n", get_rb_name(lcid)); +} - log->debug("Init %s\n", rrc->get_rb_name(lcid).c_str()); +void pdcp_entity::stop() +{ + if(running) { + running = false; + thread_cancel(); + wait_thread_finish(); + } } void pdcp_entity::reset() { active = false; if(log) - log->debug("Reset %s\n", rrc->get_rb_name(lcid).c_str()); + log->debug("Reset %s\n", get_rb_name(lcid)); } bool pdcp_entity::is_active() @@ -74,17 +86,15 @@ bool pdcp_entity::is_active() // RRC interface void pdcp_entity::write_sdu(byte_buffer_t *sdu) { - log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU, do_security = %s", rrc->get_rb_name(lcid).c_str(), (cfg.do_security)?"true":"false"); + log->info_hex(sdu->msg, sdu->N_bytes, + "TX %s SDU, do_integrity = %s, do_encryption = %s", get_rb_name(lcid), + (do_integrity) ? "true" : "false", (do_encryption) ? "true" : "false"); if (cfg.is_control) { pdcp_pack_control_pdu(tx_count, sdu); - if(cfg.do_security) + if(do_integrity) { - integrity_generate(&k_rrc_int[16], - tx_count, - lcid-1, - cfg.direction, - sdu->msg, + integrity_generate(sdu->msg, sdu->N_bytes-4, &sdu->msg[sdu->N_bytes-4]); } @@ -107,7 +117,7 @@ void pdcp_entity::config_security(uint8_t *k_rrc_enc_, CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) { - cfg.do_security = true; + do_integrity = true; for(int i=0; i<32; i++) { k_rrc_enc[i] = k_rrc_enc_[i]; @@ -117,43 +127,18 @@ void pdcp_entity::config_security(uint8_t *k_rrc_enc_, integ_algo = integ_algo_; } +void pdcp_entity::enable_encryption() +{ + do_encryption = true; +} + // RLC interface void pdcp_entity::write_pdu(byte_buffer_t *pdu) { - - - - - - if (cfg.is_data) { - uint32_t sn; - if(12 == cfg.sn_len) - { - pdcp_unpack_data_pdu_long_sn(pdu, &sn); - } else { - pdcp_unpack_data_pdu_short_sn(pdu, &sn); - } - log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU: %d", rrc->get_rb_name(lcid).c_str(), sn); - gw->write_pdu(lcid, pdu); - } else { - if (cfg.is_control) { - uint32_t sn; - pdcp_unpack_control_pdu(pdu, &sn); - log->info_hex(pdu->msg, pdu->N_bytes, "RX %s SDU SN: %d", - rrc->get_rb_name(lcid).c_str(), sn); - } else { - log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", rrc->get_rb_name(lcid).c_str()); - } - // pass to RRC - rrc->write_pdu(lcid, pdu); - } + rx_pdu_queue.write(pdu); } -void pdcp_entity::integrity_generate( uint8_t *key_128, - uint32_t count, - uint8_t rb_id, - uint8_t direction, - uint8_t *msg, +void pdcp_entity::integrity_generate( uint8_t *msg, uint32_t msg_len, uint8_t *mac) { @@ -162,19 +147,19 @@ void pdcp_entity::integrity_generate( uint8_t *key_128, case INTEGRITY_ALGORITHM_ID_EIA0: break; case INTEGRITY_ALGORITHM_ID_128_EIA1: - security_128_eia1(key_128, - count, - rb_id, - direction, + security_128_eia1(&k_rrc_int[16], + tx_count, + lcid-1, + cfg.direction, msg, msg_len, mac); break; case INTEGRITY_ALGORITHM_ID_128_EIA2: - security_128_eia2(key_128, - count, - rb_id, - direction, + security_128_eia2(&k_rrc_int[16], + tx_count, + lcid-1, + cfg.direction, msg, msg_len, mac); @@ -184,6 +169,198 @@ void pdcp_entity::integrity_generate( uint8_t *key_128, } } +bool pdcp_entity::integrity_verify(uint8_t *msg, + uint32_t count, + uint32_t msg_len, + uint8_t *mac) +{ + uint8_t mac_exp[4] = {0x00}; + uint8_t i = 0; + bool isValid = true; + + switch(integ_algo) + { + case INTEGRITY_ALGORITHM_ID_EIA0: + break; + case INTEGRITY_ALGORITHM_ID_128_EIA1: + security_128_eia1(&k_rrc_int[16], + count, + lcid-1, + ( cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), + msg, + msg_len, + mac_exp); + break; + case INTEGRITY_ALGORITHM_ID_128_EIA2: + security_128_eia2(&k_rrc_int[16], + count, + lcid-1, + ( cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), + msg, + msg_len, + mac_exp); + break; + default: + break; + } + + switch(integ_algo) + { + case INTEGRITY_ALGORITHM_ID_EIA0: + break; + case INTEGRITY_ALGORITHM_ID_128_EIA1: // Intentional fall-through + case INTEGRITY_ALGORITHM_ID_128_EIA2: + for(i=0; i<4; i++){ + if(mac[i] != mac_exp[i]){ + log->error_hex(mac_exp, 4, "MAC mismatch (expected)"); + log->error_hex(mac, 4, "MAC mismatch (found)"); + isValid = false; + break; + } + } + if (isValid){ + log->info_hex(mac_exp, 4, "MAC match (expected)"); + log->info_hex(mac, 4, "MAC match (found)"); + } + break; + default: + break; + } + + return isValid; +} + +void pdcp_entity::cipher_encrypt(uint8_t *msg, + uint32_t msg_len, + uint8_t *ct) +{ + byte_buffer_t ct_tmp; + switch(cipher_algo) + { + case CIPHERING_ALGORITHM_ID_EEA0: + break; + case CIPHERING_ALGORITHM_ID_128_EEA1: + security_128_eea1(&(k_rrc_enc[16]), + tx_count, + lcid - 1, + cfg.direction, + msg, + msg_len, + ct_tmp.msg); + memcpy(ct, ct_tmp.msg, msg_len); + break; + case CIPHERING_ALGORITHM_ID_128_EEA2: + security_128_eea2(&(k_rrc_enc[16]), + tx_count, + lcid - 1, + cfg.direction, + msg, + msg_len, + ct_tmp.msg); + memcpy(ct, ct_tmp.msg, msg_len); + break; + default: + break; + } +} + +void pdcp_entity::cipher_decrypt(uint8_t *ct, + uint32_t count, + uint32_t ct_len, + uint8_t *msg) +{ + byte_buffer_t msg_tmp; + switch(cipher_algo) + { + case CIPHERING_ALGORITHM_ID_EEA0: + break; + case CIPHERING_ALGORITHM_ID_128_EEA1: + security_128_eea1(&(k_rrc_enc[16]), + count, + lcid - 1, + ( cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), + ct, + ct_len, + msg_tmp.msg); + break; + case CIPHERING_ALGORITHM_ID_128_EEA2: + security_128_eea2(&(k_rrc_enc[16]), + count, + lcid - 1, + ( cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), + ct, + ct_len, + msg_tmp.msg); + memcpy(msg, msg_tmp.msg, ct_len); + break; + default: + break; + } +} + + +void pdcp_entity::run_thread() +{ + byte_buffer_t *pdu; + running = true; + + while(running) { + rx_pdu_queue.read(&pdu); + + // Handle SRB messages + switch(lcid) + { + case RB_ID_SRB0: + // Simply pass on to RRC + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", get_rb_name(lcid)); + rrc->write_pdu(RB_ID_SRB0, pdu); + break; + case RB_ID_SRB1: // Intentional fall-through + case RB_ID_SRB2: + uint32_t sn; + + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", get_rb_name(lcid)); + + if (do_encryption) { + cipher_decrypt(&(pdu->msg[1]), + pdu->msg[0], + pdu->N_bytes - 1, + &(pdu->msg[1])); + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU (decrypted)", get_rb_name(lcid)); + } + + if (do_integrity) { + integrity_verify(pdu->msg, + pdu->msg[0], + pdu->N_bytes - 4, + &(pdu->msg[pdu->N_bytes - 4])); + } + + pdcp_unpack_control_pdu(pdu, &sn); + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s SDU SN: %d", + get_rb_name(lcid), sn); + rrc->write_pdu(lcid, pdu); + break; + } + + // Handle DRB messages + if(lcid >= RB_ID_DRB1) + { + uint32_t sn; + if(12 == cfg.sn_len) + { + pdcp_unpack_data_pdu_long_sn(pdu, &sn); + } else { + pdcp_unpack_data_pdu_short_sn(pdu, &sn); + } + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU: %d", get_rb_name(lcid), sn); + gw->write_pdu(lcid, pdu); + } + } +} + + + /**************************************************************************** * Pack/Unpack helper functions * Ref: 3GPP TS 36.323 v10.1.0 diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc index f506ebc63..c16a09cab 100644 --- a/lib/src/upper/rlc.cc +++ b/lib/src/upper/rlc.cc @@ -123,11 +123,6 @@ void rlc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) } } -std::string rlc::get_rb_name(uint32_t lcid) -{ - return rrc->get_rb_name(lcid); -} - /******************************************************************************* MAC interface *******************************************************************************/ @@ -217,11 +212,10 @@ void rlc::add_bearer(uint32_t lcid) cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS0; add_bearer(lcid, srslte_rlc_config_t(&cnfg)); } else { - rlc_log->warning("Bearer %s already configured. Reconfiguration not supported\n", get_rb_name(lcid).c_str()); + rlc_log->warning("Bearer %s already configured. Reconfiguration not supported\n", get_rb_name(lcid)); } }else{ - rlc_log->error("Radio bearer %s does not support default RLC configuration.\n", - get_rb_name(lcid).c_str()); + rlc_log->error("Radio bearer %s does not support default RLC configuration.\n", get_rb_name(lcid)); } } @@ -234,7 +228,7 @@ void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg) if (!rlc_array[lcid].active()) { rlc_log->info("Adding radio bearer %s with mode %s\n", - get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg.rlc_mode]); + get_rb_name(lcid), liblte_rrc_rlc_mode_text[cnfg.rlc_mode]); switch(cnfg.rlc_mode) { case LIBLTE_RRC_RLC_MODE_AM: @@ -254,7 +248,7 @@ void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg) return; } } else { - rlc_log->warning("Bearer %s already created.\n", get_rb_name(lcid).c_str()); + rlc_log->warning("Bearer %s already created.\n", get_rb_name(lcid)); } rlc_array[lcid].configure(cnfg); diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index f8abc0aef..c048133d6 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -79,7 +79,7 @@ void rlc_am::configure(srslte_rlc_config_t cfg_) cfg = cfg_.am; log->info("%s configured: t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, " "t_reordering=%d, t_status_prohibit=%d\n", - rrc->get_rb_name(lcid).c_str(), cfg.t_poll_retx, cfg.poll_pdu, cfg.poll_byte, cfg.max_retx_thresh, + get_rb_name(lcid), cfg.t_poll_retx, cfg.poll_pdu, cfg.poll_byte, cfg.max_retx_thresh, cfg.t_reordering, cfg.t_status_prohibit); } @@ -175,7 +175,7 @@ uint32_t rlc_am::get_bearer() void rlc_am::write_sdu(byte_buffer_t *sdu) { - log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", get_rb_name(lcid)); tx_sdu_queue.write(sdu); } @@ -359,7 +359,7 @@ void rlc_am::check_reordering_timeout() if(reordering_timeout.is_running() && reordering_timeout.expired()) { reordering_timeout.reset(); - log->debug("%s reordering timeout expiry - updating vr_ms\n", rrc->get_rb_name(lcid).c_str()); + log->debug("%s reordering timeout expiry - updating vr_ms\n", get_rb_name(lcid)); // 36.322 v10 Section 5.1.3.2.4 vr_ms = vr_x; @@ -433,7 +433,7 @@ int rlc_am::build_status_pdu(uint8_t *payload, uint32_t nof_bytes) if(pdu_len > 0 && nof_bytes >= (uint32_t)pdu_len) { log->info("%s Tx status PDU - %s\n", - rrc->get_rb_name(lcid).c_str(), rlc_am_to_string(&status).c_str()); + get_rb_name(lcid), rlc_am_to_string(&status).c_str()); do_status = false; poll_received = false; @@ -444,7 +444,7 @@ int rlc_am::build_status_pdu(uint8_t *payload, uint32_t nof_bytes) return rlc_am_write_status_pdu(&status, payload); }else{ log->warning("%s Cannot tx status PDU - %d bytes available, %d bytes required\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, pdu_len); + get_rb_name(lcid), nof_bytes, pdu_len); return 0; } } @@ -478,7 +478,7 @@ int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) return -1; } if(retx.is_segment || req_size > (int)nof_bytes) { - log->debug("%s build_retx_pdu - resegmentation required\n", rrc->get_rb_name(lcid).c_str()); + log->debug("%s build_retx_pdu - resegmentation required\n", get_rb_name(lcid)); return build_segment(payload, nof_bytes, retx); } @@ -503,7 +503,7 @@ int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_window[retx.sn].retx_count >= cfg.max_retx_thresh) rrc->max_retx_attempted(); log->info("%s Retx PDU scheduled for tx. SN: %d, retx count: %d\n", - rrc->get_rb_name(lcid).c_str(), retx.sn, tx_window[retx.sn].retx_count); + get_rb_name(lcid), retx.sn, tx_window[retx.sn].retx_count); debug_state(); return (ptr-payload) + tx_window[retx.sn].buf->N_bytes; @@ -540,7 +540,7 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r if(nof_bytes <= head_len) { log->warning("%s Cannot build a PDU segment - %d bytes available, %d bytes required for header\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len); + get_rb_name(lcid), nof_bytes, head_len); return 0; } pdu_space = nof_bytes-head_len; @@ -606,15 +606,15 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r memcpy(ptr, data, len); log->info("%s Retx PDU segment scheduled for tx. SN: %d, SO: %d\n", - rrc->get_rb_name(lcid).c_str(), retx.sn, retx.so_start); + get_rb_name(lcid), retx.sn, retx.so_start); debug_state(); int pdu_len = (ptr-payload) + len; if(pdu_len > (int)nof_bytes) { log->error("%s Retx PDU segment length error. Available: %d, Used: %d\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, pdu_len); + get_rb_name(lcid), nof_bytes, pdu_len); log->debug("%s Retx PDU segment length error. Header len: %d, Payload len: %d, N_li: %d\n", - rrc->get_rb_name(lcid).c_str(), (ptr-payload), len, new_header.N_li); + get_rb_name(lcid), (ptr-payload), len, new_header.N_li); } return pdu_len; @@ -662,13 +662,13 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) if(pdu_space <= head_len + 1) { log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len); + get_rb_name(lcid), nof_bytes, head_len); pool->deallocate(pdu); return 0; } log->debug("%s Building PDU - pdu_space: %d, head_len: %d \n", - rrc->get_rb_name(lcid).c_str(), pdu_space, head_len); + get_rb_name(lcid), pdu_space, head_len); // Check for SDU segment if(tx_sdu) @@ -683,7 +683,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_sdu->N_bytes == 0) { log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", - rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); + get_rb_name(lcid), tx_sdu->get_latency_us()); pool->deallocate(tx_sdu); tx_sdu = NULL; } @@ -694,7 +694,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n", - rrc->get_rb_name(lcid).c_str(), to_move, pdu_space, head_len); + get_rb_name(lcid), to_move, pdu_space, head_len); } // Pull SDUs from queue @@ -718,7 +718,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_sdu->N_bytes == 0) { log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", - rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); + get_rb_name(lcid), tx_sdu->get_latency_us()); pool->deallocate(tx_sdu); tx_sdu = NULL; } @@ -728,7 +728,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) pdu_space = 0; log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n", - rrc->get_rb_name(lcid).c_str(), to_move, pdu_space, head_len); + get_rb_name(lcid), to_move, pdu_space, head_len); } if(tx_sdu) @@ -737,11 +737,11 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) // Set Poll bit pdu_without_poll++; byte_without_poll += (pdu->N_bytes + head_len); - log->debug("%s pdu_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), pdu_without_poll); - log->debug("%s byte_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), byte_without_poll); + log->debug("%s pdu_without_poll: %d\n", get_rb_name(lcid), pdu_without_poll); + log->debug("%s byte_without_poll: %d\n", get_rb_name(lcid), byte_without_poll); if(poll_required()) { - log->debug("%s setting poll bit to request status\n", rrc->get_rb_name(lcid).c_str()); + log->debug("%s setting poll bit to request status\n", get_rb_name(lcid)); header.p = 1; poll_sn = vt_s; pdu_without_poll = 0; @@ -752,7 +752,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) // Set SN header.sn = vt_s; vt_s = (vt_s + 1)%MOD; - log->info("%s PDU scheduled for tx. SN: %d\n", rrc->get_rb_name(lcid).c_str(), header.sn); + log->info("%s PDU scheduled for tx. SN: %d\n", get_rb_name(lcid), header.sn); // Place PDU in tx_window, write header and TX tx_window[header.sn].buf = pdu; @@ -773,26 +773,26 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h std::map::iterator it; log->info_hex(payload, nof_bytes, "%s Rx data PDU SN: %d", - rrc->get_rb_name(lcid).c_str(), header.sn); + get_rb_name(lcid), header.sn); if(!inside_rx_window(header.sn)) { if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); do_status = true; } log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", - rrc->get_rb_name(lcid).c_str(), header.sn, vr_r, vr_mr); + get_rb_name(lcid), header.sn, vr_r, vr_mr); return; } it = rx_window.find(header.sn); if(rx_window.end() != it) { if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); do_status = true; } log->info("%s Discarding duplicate SN: %d\n", - rrc->get_rb_name(lcid).c_str(), header.sn); + get_rb_name(lcid), header.sn); return; } @@ -825,7 +825,7 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h // Check poll bit if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); poll_received = true; // 36.322 v10 Section 5.2.3 @@ -870,16 +870,16 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a std::map::iterator it; log->info_hex(payload, nof_bytes, "%s Rx data PDU segment. SN: %d, SO: %d", - rrc->get_rb_name(lcid).c_str(), header.sn, header.so); + get_rb_name(lcid), header.sn, header.so); // Check inside rx window if(!inside_rx_window(header.sn)) { if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); do_status = true; } log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", - rrc->get_rb_name(lcid).c_str(), header.sn, vr_r, vr_mr); + get_rb_name(lcid), header.sn, vr_r, vr_mr); return; } @@ -898,7 +898,7 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a if(rx_segments.end() != it) { if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); do_status = true; } @@ -928,7 +928,7 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a // Check poll bit if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); poll_received = true; // 36.322 v10 Section 5.2.3 @@ -946,12 +946,12 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) { - log->info_hex(payload, nof_bytes, "%s Rx control PDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(payload, nof_bytes, "%s Rx control PDU", get_rb_name(lcid)); rlc_status_pdu_t status; rlc_am_read_status_pdu(payload, nof_bytes, &status); - log->info("%s Rx Status PDU: %s\n", rrc->get_rb_name(lcid).c_str(), rlc_am_to_string(&status).c_str()); + log->info("%s Rx Status PDU: %s\n", get_rb_name(lcid), rlc_am_to_string(&status).c_str()); poll_retx_timeout.reset(); @@ -989,7 +989,7 @@ void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) } } else { log->warning("%s invalid segment NACK received for SN %d. so_start: %d, so_end: %d, N_bytes: %d\n", - rrc->get_rb_name(lcid).c_str(), i, status.nacks[j].so_start, status.nacks[j].so_end, it->second.buf->N_bytes); + get_rb_name(lcid), i, status.nacks[j].so_start, status.nacks[j].so_end, it->second.buf->N_bytes); } } @@ -1043,7 +1043,7 @@ void rlc_am::reassemble_rx_sdus() rx_sdu->N_bytes += len; rx_window[vr_r].buf->msg += len; rx_window[vr_r].buf->N_bytes -= len; - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", get_rb_name(lcid)); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -1059,7 +1059,7 @@ void rlc_am::reassemble_rx_sdus() rx_sdu->N_bytes += rx_window[vr_r].buf->N_bytes; if(rlc_am_end_aligned(rx_window[vr_r].header.fi)) { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", get_rb_name(lcid)); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -1103,7 +1103,7 @@ void rlc_am::debug_state() { log->debug("%s vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d " "vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d\n", - rrc->get_rb_name(lcid).c_str(), vt_a, vt_ms, vt_s, poll_sn, + get_rb_name(lcid), vt_a, vt_ms, vt_s, poll_sn, vr_r, vr_mr, vr_x, vr_ms, vr_h); } diff --git a/lib/src/upper/rlc_tm.cc b/lib/src/upper/rlc_tm.cc index 627752494..4559dd07b 100644 --- a/lib/src/upper/rlc_tm.cc +++ b/lib/src/upper/rlc_tm.cc @@ -84,7 +84,7 @@ uint32_t rlc_tm::get_bearer() // PDCP interface void rlc_tm::write_sdu(byte_buffer_t *sdu) { - log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", get_rb_name(lcid)); ul_queue.write(sdu); } @@ -104,7 +104,7 @@ int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes) uint32_t pdu_size = ul_queue.size_tail_bytes(); if(pdu_size > nof_bytes) { - log->error("TX %s PDU size larger than MAC opportunity\n", rrc->get_rb_name(lcid).c_str()); + log->error("TX %s PDU size larger than MAC opportunity\n", get_rb_name(lcid)); return 0; } byte_buffer_t *buf; @@ -112,9 +112,9 @@ int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes) pdu_size = buf->N_bytes; memcpy(payload, buf->msg, buf->N_bytes); log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", - rrc->get_rb_name(lcid).c_str(), buf->get_latency_us()); + get_rb_name(lcid), buf->get_latency_us()); pool->deallocate(buf); - log->info_hex(payload, pdu_size, "TX %s, %s PDU", rrc->get_rb_name(lcid).c_str(), rlc_mode_text[RLC_MODE_TM]); + log->info_hex(payload, pdu_size, "TX %s, %s PDU", get_rb_name(lcid), rlc_mode_text[RLC_MODE_TM]); return pdu_size; } diff --git a/lib/src/upper/rlc_um.cc b/lib/src/upper/rlc_um.cc index 4756e2f7c..5b395228f 100644 --- a/lib/src/upper/rlc_um.cc +++ b/lib/src/upper/rlc_um.cc @@ -75,18 +75,18 @@ void rlc_um::configure(srslte_rlc_config_t cnfg_) case LIBLTE_RRC_RLC_MODE_UM_BI: log->info("%s configured in %s mode: " "t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n", - rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], + get_rb_name(lcid), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length], rlc_umd_sn_size_num[cfg.rx_sn_field_length]); break; case LIBLTE_RRC_RLC_MODE_UM_UNI_UL: log->info("%s configured in %s mode: tx_sn_field_length=%u bits\n", - rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], + get_rb_name(lcid), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], rlc_umd_sn_size_num[cfg.rx_sn_field_length]); break; case LIBLTE_RRC_RLC_MODE_UM_UNI_DL: log->info("%s configured in %s mode: " "t_reordering=%d ms, rx_sn_field_length=%u bits\n", - rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], + get_rb_name(lcid), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length]); break; default: @@ -153,7 +153,7 @@ uint32_t rlc_um::get_bearer() void rlc_um::write_sdu(byte_buffer_t *sdu) { - log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", get_rb_name(lcid)); tx_sdu_queue.write(sdu); } @@ -216,7 +216,7 @@ void rlc_um::timer_expired(uint32_t timeout_id) // 36.322 v10 Section 5.1.2.2.4 log->info("%s reordering timeout expiry - updating vr_ur and reassembling\n", - rrc->get_rb_name(lcid).c_str()); + get_rb_name(lcid)); log->warning("Lost PDU SN: %d\n", vr_ur); pdu_lost = true; @@ -281,7 +281,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) { pool->deallocate(pdu); log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len); + get_rb_name(lcid), nof_bytes, head_len); return 0; } @@ -291,7 +291,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) uint32_t space = pdu_space-head_len; to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n", - rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes); + get_rb_name(lcid), to_move, tx_sdu->N_bytes); memcpy(pdu_ptr, tx_sdu->msg, to_move); last_li = to_move; pdu_ptr += to_move; @@ -301,7 +301,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_sdu->N_bytes == 0) { log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", - rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); + get_rb_name(lcid), tx_sdu->get_latency_us()); pool->deallocate(tx_sdu); tx_sdu = NULL; } @@ -320,7 +320,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) uint32_t space = pdu_space-head_len; to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; log->debug("%s adding new SDU segment - %d bytes of %d remaining\n", - rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes); + get_rb_name(lcid), to_move, tx_sdu->N_bytes); memcpy(pdu_ptr, tx_sdu->msg, to_move); last_li = to_move; pdu_ptr += to_move; @@ -330,7 +330,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_sdu->N_bytes == 0) { log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", - rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); + get_rb_name(lcid), tx_sdu->get_latency_us()); pool->deallocate(tx_sdu); tx_sdu = NULL; } @@ -345,11 +345,11 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) vt_us = (vt_us + 1)%cfg.tx_mod; // Add header and TX - log->debug("%s packing PDU with length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes); + log->debug("%s packing PDU with length %d\n", get_rb_name(lcid), pdu->N_bytes); rlc_um_write_data_pdu_header(&header, pdu); memcpy(payload, pdu->msg, pdu->N_bytes); uint32_t ret = pdu->N_bytes; - log->debug("%s returning length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes); + log->debug("%s returning length %d\n", get_rb_name(lcid), pdu->N_bytes); pool->deallocate(pdu); debug_state(); @@ -363,20 +363,20 @@ void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes) rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.rx_sn_field_length, &header); log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d", - rrc->get_rb_name(lcid).c_str(), header.sn); + get_rb_name(lcid), header.sn); if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) && RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ur)) { log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", - rrc->get_rb_name(lcid).c_str(), header.sn, vr_ur, vr_uh); + get_rb_name(lcid), header.sn, vr_ur, vr_uh); return; } it = rx_window.find(header.sn); if(rx_window.end() != it) { log->info("%s Discarding duplicate SN: %d\n", - rrc->get_rb_name(lcid).c_str(), header.sn); + get_rb_name(lcid), header.sn); return; } @@ -451,7 +451,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (lower edge middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", get_rb_name(lcid), vr_ur, i); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -471,7 +471,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (lower edge last segments)\n"); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (lower edge last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (lower edge last segments)", get_rb_name(lcid), vr_ur); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -505,7 +505,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", get_rb_name(lcid), vr_ur, i); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -534,7 +534,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (update vr_ur last segments)\n"); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", get_rb_name(lcid), vr_ur); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -564,7 +564,7 @@ bool rlc_um::inside_reordering_window(uint16_t sn) void rlc_um::debug_state() { log->debug("%s vt_us = %d, vr_ur = %d, vr_ux = %d, vr_uh = %d \n", - rrc->get_rb_name(lcid).c_str(), vt_us, vr_ur, vr_ux, vr_uh); + get_rb_name(lcid), vt_us, vr_ur, vr_ux, vr_uh); } diff --git a/srsue/hdr/ue.h b/srsue/hdr/ue.h index 4e48f6b6d..b559396be 100644 --- a/srsue/hdr/ue.h +++ b/srsue/hdr/ue.h @@ -88,6 +88,7 @@ private: srsue::phy phy; srsue::mac mac; srslte::mac_pcap mac_pcap; + srslte::nas_pcap nas_pcap; srslte::rlc rlc; srslte::pdcp pdcp; srsue::rrc rrc; diff --git a/srsue/hdr/ue_base.h b/srsue/hdr/ue_base.h index e23adf3d2..8e5ce22a9 100644 --- a/srsue/hdr/ue_base.h +++ b/srsue/hdr/ue_base.h @@ -69,6 +69,8 @@ typedef struct { typedef struct { bool enable; std::string filename; + bool nas_enable; + std::string nas_filename; }pcap_args_t; typedef struct { diff --git a/srsue/hdr/upper/nas.h b/srsue/hdr/upper/nas.h index 2e795098e..5ab77f28c 100644 --- a/srsue/hdr/upper/nas.h +++ b/srsue/hdr/upper/nas.h @@ -33,6 +33,7 @@ #include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/security.h" #include "srslte/asn1/liblte_mme.h" +#include "srslte/common/nas_pcap.h" using srslte::byte_buffer_t; @@ -57,8 +58,8 @@ static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL", "DEREGISTERED INITIATED", "TRACKING AREA UPDATE INITIATED"}; -static const bool eia_caps[8] = {false, true, true, false, false, false, false, false}; -static const bool eea_caps[8] = {true, false, false, false, false, false, false, false}; +static const bool eia_caps[8] = {false, true, true, false, false, false, false, false}; +static const bool eea_caps[8] = {true, true, true, false, false, false, false, false}; typedef enum { PLMN_NOT_SELECTED = 0, @@ -96,6 +97,9 @@ public: void attach_request(); void deattach_request(); + // PCAP + void start_pcap(srslte::nas_pcap *pcap_); + private: srslte::byte_buffer_pool *pool; srslte::log *nas_log; @@ -140,17 +144,20 @@ private: uint8_t k_nas_enc[32]; uint8_t k_nas_int[32]; - void integrity_generate(uint8_t integ_algo, - uint8_t *key_128, + // PCAP + srslte::nas_pcap *pcap = NULL; + + void integrity_generate(uint8_t *key_128, uint32_t count, uint8_t rb_id, uint8_t direction, uint8_t *msg, uint32_t msg_len, uint8_t *mac); - void integrity_check(); - void cipher_encrypt(); - void cipher_decrypt(); + bool integrity_check(uint32 lcid, byte_buffer_t *pdu); + void cipher_encrypt(uint32 lcid, byte_buffer_t *pdu); + void cipher_decrypt(uint32 lcid, byte_buffer_t *pdu); + bool check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *caps); // Parsers diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index d561b0f1c..489e33314 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -50,11 +50,6 @@ using srslte::byte_buffer_t; namespace srsue { -static std::string rb_id_str[] = {"SRB0", "SRB1", "SRB2", - "DRB1","DRB2","DRB3", - "DRB4","DRB5","DRB6", - "DRB7","DRB8"}; - class rrc :public rrc_interface_nas ,public rrc_interface_phy @@ -208,30 +203,6 @@ private: void write_pdu_bcch_dlsch(byte_buffer_t *pdu); void write_pdu_pcch(byte_buffer_t *pdu); - // Radio bearers - typedef enum{ - RB_ID_SRB0 = 0, - RB_ID_SRB1, - RB_ID_SRB2, - RB_ID_DRB1, - RB_ID_DRB2, - RB_ID_DRB3, - RB_ID_DRB4, - RB_ID_DRB5, - RB_ID_DRB6, - RB_ID_DRB7, - RB_ID_DRB8, - RB_ID_MAX - } rb_id_t; - - std::string get_rb_name(uint32_t lcid) { - if (lcid < RB_ID_MAX) { - return rb_id_str[lcid]; - } else { - return std::string("INVALID_RB"); - } - } - // RLC interface void max_retx_attempted(); diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 1c9b6edc6..0f1ffa61c 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -82,9 +82,11 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { ("rrc.ue_category", bpo::value(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)") - ("pcap.enable", bpo::value(&args->pcap.enable)->default_value(false), - "Enable MAC packet captures for wireshark") + ("pcap.enable", bpo::value(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark") ("pcap.filename", bpo::value(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename") + ("pcap.nas_enable", bpo::value(&args->pcap.nas_enable)->default_value(false), "Enable NAS packet captures for wireshark") + ("pcap.nas_filename", bpo::value(&args->pcap.nas_filename)->default_value("ue_nas.pcap"), "NAS layer capture filename (useful when NAS encryption is enabled)") + ("trace.enable", bpo::value(&args->trace.enable)->default_value(false), "Enable PHY and radio timing traces") ("trace.phy_filename", bpo::value(&args->trace.phy_filename)->default_value("ue.phy_trace"), diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index b7e744bd8..2edf0fed5 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -104,13 +104,15 @@ bool ue::init(all_args_t *args_) usim_log.set_hex_limit(args->log.usim_hex_limit); // Set up pcap and trace - if(args->pcap.enable) - { + if(args->pcap.enable) { mac_pcap.open(args->pcap.filename.c_str()); mac.start_pcap(&mac_pcap); } - if(args->trace.enable) - { + if(args->pcap.nas_enable) { + nas_pcap.open(args->pcap.nas_filename.c_str()); + nas.start_pcap(&nas_pcap); + } + if(args->trace.enable) { phy.start_trace(); radio.start_trace(); } @@ -137,8 +139,7 @@ bool ue::init(all_args_t *args_) } printf("Opening RF device with %d RX antennas...\n", args->rf.nof_rx_ant); - if(!radio.init_multi(args->rf.nof_rx_ant, dev_args, dev_name)) - { + if(!radio.init_multi(args->rf.nof_rx_ant, dev_args, dev_name)) { printf("Failed to find device %s with args %s\n", args->rf.device_name.c_str(), args->rf.device_args.c_str()); return false; @@ -244,12 +245,13 @@ void ue::stop() radio.stop(); usleep(1e5); - if(args->pcap.enable) - { + if(args->pcap.enable) { mac_pcap.close(); } - if(args->trace.enable) - { + if(args->pcap.nas_enable) { + nas_pcap.close(); + } + if(args->trace.enable) { phy.write_trace(args->trace.phy_filename); radio.write_trace(args->trace.radio_filename); } diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 62e23d852..99e237ba2 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -32,6 +32,7 @@ #include #include "srslte/asn1/liblte_rrc.h" #include "upper/nas.h" +#include "srslte/common/security.h" #include "srslte/common/bcd_helpers.h" using namespace srslte; @@ -190,11 +191,42 @@ void nas::notify_connection_setup() { void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { uint8 pd; uint8 msg_type; + uint8 sec_hdr_type; + bool mac_valid = false; - nas_log->info_hex(pdu->msg, pdu->N_bytes, "DL %s PDU", rrc->get_rb_name(lcid).c_str()); + nas_log->info_hex(pdu->msg, pdu->N_bytes, "DL %s PDU", get_rb_name(lcid)); - // Parse the message + // Parse the message security header + liblte_mme_parse_msg_sec_header((LIBLTE_BYTE_MSG_STRUCT*)pdu, &pd, &sec_hdr_type); + switch(sec_hdr_type) + { + case LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS: + case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT: + case LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST: + case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY: + break; + case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED: + mac_valid = integrity_check(lcid, pdu); + cipher_decrypt(lcid, pdu); + break; + case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT: + break; + default: + nas_log->error("Not handling NAS message with SEC_HDR_TYPE=%02X\n",msg_type); + pool->deallocate(pdu); + break; + } + + // Write NAS pcap + if(pcap != NULL) { + pcap->write_nas(pdu->msg, pdu->N_bytes); + } + + // Parse the message header liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT *) pdu, &pd, &msg_type); + nas_log->info_hex(pdu->msg, pdu->N_bytes, "DL %s Decrypted PDU", get_rb_name(lcid)); + // TODO: Check if message type requieres specical security header type and if it isvalid + switch (msg_type) { case LIBLTE_MME_MSG_TYPE_ATTACH_ACCEPT: parse_attach_accept(lcid, pdu); @@ -258,19 +290,27 @@ bool nas::get_k_asme(uint8_t *k_asme_, uint32_t n) { return true; } +/******************************************************************************* + PCAP +*******************************************************************************/ + +void nas::start_pcap(srslte::nas_pcap *pcap_) +{ + pcap = pcap_; +} + /******************************************************************************* * Security ******************************************************************************/ -void nas::integrity_generate(uint8_t integ_algo, - uint8_t *key_128, +void nas::integrity_generate(uint8_t *key_128, uint32_t count, uint8_t rb_id, uint8_t direction, uint8_t *msg, uint32_t msg_len, uint8_t *mac) { - switch (integ_algo) { + switch (ctxt.integ_algo) { case INTEGRITY_ALGORITHM_ID_EIA0: break; case INTEGRITY_ALGORITHM_ID_128_EIA1: @@ -296,16 +336,102 @@ void nas::integrity_generate(uint8_t integ_algo, } } -void nas::integrity_check() { - -} +// This function depends to a valid k_nas_int. +// This key is generated in the security mode command. -void nas::cipher_encrypt() { +bool nas::integrity_check(uint32 lcid, + byte_buffer_t *pdu) +{ + uint8_t exp_mac[4]; + uint8_t *mac = &pdu->msg[1]; + int i; + integrity_generate(&k_nas_int[16], + ctxt.rx_count, + lcid-1, + SECURITY_DIRECTION_DOWNLINK, + &pdu->msg[5], + pdu->N_bytes-5, + &exp_mac[0]); + + // Check if expected mac equals the sent mac + for(i=0; i<4; i++){ + if(exp_mac[i] != mac[i]){ + nas_log->warning("Expected MAC [%02x %02x %02x %02x] does not match sent MAC [%02x %02x %02x %02x]\n", exp_mac[0], exp_mac[1], exp_mac[2], exp_mac[3], mac[0], mac[1], mac[2], mac[3]); + return false; + } + } + nas_log->info("Expected MAC [%02x %02x %02x %02x] equals sent MAC [%02x %02x %02x %02x]\n", exp_mac[0], exp_mac[1], exp_mac[2], exp_mac[3], mac[0], mac[1], mac[2], mac[3]); + return true; } -void nas::cipher_decrypt() { +void nas::cipher_encrypt(uint32 lcid, + byte_buffer_t *pdu) +{ + byte_buffer_t pdu_tmp; + switch(ctxt.cipher_algo) + { + case CIPHERING_ALGORITHM_ID_EEA0: + break; + case CIPHERING_ALGORITHM_ID_128_EEA1: + security_128_eea1(&k_nas_enc[16], + pdu->msg[5], + lcid-1, + SECURITY_DIRECTION_UPLINK, + &pdu->msg[6], + pdu->N_bytes-6, + &pdu_tmp.msg[6]); + memcpy(&pdu->msg[6], &pdu_tmp.msg[6], pdu->N_bytes-6); + break; + case CIPHERING_ALGORITHM_ID_128_EEA2: + security_128_eea2(&k_nas_enc[16], + pdu->msg[5], + lcid-1, + SECURITY_DIRECTION_UPLINK, + &pdu->msg[6], + pdu->N_bytes-6, + &pdu_tmp.msg[6]); + memcpy(&pdu->msg[6], &pdu_tmp.msg[6], pdu->N_bytes-6); + break; + default: + nas_log->error("Ciphering algorithmus not known"); + break; + } +} +void nas::cipher_decrypt(uint32 lcid, + byte_buffer_t *pdu) +{ + byte_buffer_t tmp_pdu; + switch(ctxt.cipher_algo) + { + case CIPHERING_ALGORITHM_ID_EEA0: + break; + case CIPHERING_ALGORITHM_ID_128_EEA1: + security_128_eea1(&k_nas_enc[16], + pdu->msg[5], + lcid-1, + SECURITY_DIRECTION_DOWNLINK, + &pdu->msg[6], + pdu->N_bytes-6, + &tmp_pdu.msg[6]); + memcpy(&pdu->msg[6], &tmp_pdu.msg[6], pdu->N_bytes-6); + break; + case CIPHERING_ALGORITHM_ID_128_EEA2: + security_128_eea2(&k_nas_enc[16], + pdu->msg[5], + lcid-1, + SECURITY_DIRECTION_DOWNLINK, + &pdu->msg[6], + pdu->N_bytes-6, + &tmp_pdu.msg[6]); + nas_log->debug_hex(tmp_pdu.msg, pdu->N_bytes, "Decrypted"); + memcpy(&pdu->msg[6], &tmp_pdu.msg[6], pdu->N_bytes-6); + break; + default: + nas_log->error("Ciphering algorithmus not known"); + break; + } } bool nas::check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *caps) @@ -418,8 +544,13 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, ctxt.tx_count, (LIBLTE_BYTE_MSG_STRUCT *) pdu); - integrity_generate(ctxt.integ_algo, - &k_nas_int[16], + // Write NAS pcap + if (pcap != NULL) { + pcap->write_nas(pdu->msg, pdu->N_bytes); + } + + cipher_encrypt(lcid, pdu); + integrity_generate(&k_nas_int[16], ctxt.tx_count, lcid - 1, SECURITY_DIRECTION_UPLINK, @@ -489,6 +620,10 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) { liblte_mme_pack_authentication_response_msg(&auth_res, (LIBLTE_BYTE_MSG_STRUCT *) pdu); nas_log->info("Sending Authentication Response\n"); + // Write NAS pcap + if (pcap != NULL) { + pcap->write_nas(pdu->msg, pdu->N_bytes); + } rrc->write_sdu(lcid, pdu); } else { nas_log->warning("Network authentication failure\n"); @@ -567,7 +702,7 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) return; } - // Reset counterd (as per 24.301 5.4.3.2) + // Reset counters (as per 24.301 5.4.3.2) ctxt.rx_count = 0; ctxt.tx_count = 0; @@ -583,43 +718,23 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) } // Generate NAS keys - usim->generate_nas_keys(ctxt.k_asme, k_nas_enc, k_nas_int, ctxt.cipher_algo, ctxt.integ_algo); + usim->generate_nas_keys(ctxt.k_asme, k_nas_enc, k_nas_int, + ctxt.cipher_algo, ctxt.integ_algo); nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc"); nas_log->debug_hex(k_nas_int, 32, "NAS integrity key - k_nas_int"); nas_log->debug("Generating integrity check. integ_algo:%d, count_dl:%d, lcid:%d\n", ctxt.integ_algo, ctxt.rx_count, lcid); - // Check incoming MAC - uint8_t *inMAC = &pdu->msg[1]; - uint8_t genMAC[4]; - integrity_generate(ctxt.integ_algo, - &k_nas_int[16], - ctxt.rx_count, - lcid - 1, - SECURITY_DIRECTION_DOWNLINK, - &pdu->msg[5], - pdu->N_bytes - 5, - genMAC); - - nas_log->info_hex(inMAC, 4, "Incoming PDU MAC:"); - nas_log->info_hex(genMAC, 4, "Generated PDU MAC:"); - - ctxt.rx_count++; - - bool match = true; - for (int i = 0; i < 4; i++) { - if (inMAC[i] != genMAC[i]) { - match = false; - } - } - if(!match) { + if (integrity_check(lcid, pdu) != true) { nas_log->warning("Sending Security Mode Reject due to integrity check failure\n"); - send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED); + send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_MAC_FAILURE); pool->deallocate(pdu); return; } + ctxt.rx_count++; + // Take security context into use have_ctxt = true; @@ -636,11 +751,14 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) // Send response byte_buffer_t *sdu = pool_allocate; liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp, - LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, + LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT, ctxt.tx_count, (LIBLTE_BYTE_MSG_STRUCT *) sdu); - integrity_generate(ctxt.integ_algo, - &k_nas_int[16], + if(pcap != NULL) { + pcap->write_nas(sdu->msg, sdu->N_bytes); + } + cipher_encrypt(lcid, sdu); + integrity_generate(&k_nas_int[16], ctxt.tx_count, lcid - 1, SECURITY_DIRECTION_UPLINK, @@ -649,7 +767,7 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) &sdu->msg[1]); nas_log->info("Sending Security Mode Complete nas_current_ctxt.tx_count=%d, RB=%s\n", ctxt.tx_count, - rrc->get_rb_name(lcid).c_str()); + get_rb_name(lcid)); rrc->write_sdu(lcid, sdu); ctxt.tx_count++; pool->deallocate(pdu); @@ -726,8 +844,7 @@ void nas::send_attach_request() { (LIBLTE_BYTE_MSG_STRUCT *) msg); // Add MAC - integrity_generate(ctxt.integ_algo, - &k_nas_int[16], + integrity_generate(&k_nas_int[16], ctxt.tx_count, cfg.lcid-1, SECURITY_DIRECTION_UPLINK, @@ -741,6 +858,10 @@ void nas::send_attach_request() { liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT *) msg); } + if(pcap != NULL) { + pcap->write_nas(msg->msg, msg->N_bytes); + } + nas_log->info("Sending attach request\n"); rrc->write_sdu(cfg.lcid, msg); @@ -776,6 +897,10 @@ void nas::send_security_mode_reject(uint8_t cause) { LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej; sec_mode_rej.emm_cause = cause; liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) msg); + if(pcap != NULL) { + pcap->write_nas(msg->msg, msg->N_bytes); + } + nas_log->info("Sending security mode reject\n"); rrc->write_sdu(cfg.lcid, msg); } @@ -792,8 +917,7 @@ void nas::send_service_request() { msg->N_bytes++; uint8_t mac[4]; - integrity_generate(ctxt.integ_algo, - &k_nas_int[16], + integrity_generate(&k_nas_int[16], ctxt.tx_count, cfg.lcid-1, SECURITY_DIRECTION_UPLINK, @@ -805,6 +929,11 @@ void nas::send_service_request() { msg->N_bytes++; msg->msg[3] = mac[3]; msg->N_bytes++; + + if(pcap != NULL) { + pcap->write_nas(msg->msg, msg->N_bytes); + } + nas_log->info("Sending service request\n"); rrc->write_sdu(cfg.lcid, msg); ctxt.tx_count++; diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 665761a04..273a2d84d 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -1067,7 +1067,7 @@ void rrc::write_pdu_pcch(byte_buffer_t *pdu) { * *******************************************************************************/ void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { - rrc_log->info_hex(sdu->msg, sdu->N_bytes, "RX %s SDU", get_rb_name(lcid).c_str()); + rrc_log->info_hex(sdu->msg, sdu->N_bytes, "RX %s SDU", get_rb_name(lcid)); switch (state) { case RRC_STATE_CONNECTING: send_con_setup_complete(sdu); @@ -1082,7 +1082,7 @@ void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { } void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { - rrc_log->info_hex(pdu->msg, pdu->N_bytes, "TX %s PDU", get_rb_name(lcid).c_str()); + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "TX %s PDU", get_rb_name(lcid)); rrc_log->info("TX PDU Stack latency: %ld us\n", pdu->get_latency_us()); switch (lcid) { @@ -1145,7 +1145,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { liblte_rrc_unpack_dl_dcch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &dl_dcch_msg); rrc_log->info("%s - Received %s\n", - get_rb_name(lcid).c_str(), + get_rb_name(lcid), liblte_rrc_dl_dcch_msg_type_text[dl_dcch_msg.msg_type]); // Reset and reuse pdu buffer if possible @@ -1170,6 +1170,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { usim->generate_as_keys(k_asme, nas->get_ul_count()-1, k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); pdcp->config_security(lcid, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); send_security_mode_complete(lcid, pdu); + pdcp->enable_encryption(lcid); break; case LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RECONFIG: transaction_id = dl_dcch_msg.msg.rrc_con_reconfig.rrc_transaction_id; @@ -1663,7 +1664,7 @@ void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg) { } srbs[srb_cnfg->srb_id] = *srb_cnfg; - rrc_log->info("Added radio bearer %s\n", get_rb_name(srb_cnfg->srb_id).c_str()); + rrc_log->info("Added radio bearer %s\n", get_rb_name(srb_cnfg->srb_id)); } void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) { @@ -1721,7 +1722,7 @@ void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) { drbs[lcid] = *drb_cnfg; drb_up = true; - rrc_log->info("Added radio bearer %s\n", get_rb_name(lcid).c_str()); + rrc_log->info("Added radio bearer %s\n", get_rb_name(lcid)); } void rrc::release_drb(uint8_t lcid) { diff --git a/srsue/src/upper/usim.cc b/srsue/src/upper/usim.cc index 7ae53988b..7a524f17a 100644 --- a/srsue/src/upper/usim.cc +++ b/srsue/src/upper/usim.cc @@ -223,6 +223,8 @@ void usim::generate_nas_keys(uint8_t *k_asme, integ_algo, k_nas_enc, k_nas_int); + + } /******************************************************************************* @@ -239,9 +241,9 @@ void usim::generate_as_keys(uint8_t *k_asme, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) { // Generate K_enb - security_generate_k_enb( k_asme, - count_ul, - k_enb); + security_generate_k_enb( k_asme, + count_ul, + k_enb); // Generate K_rrc_enc and K_rrc_int security_generate_k_rrc( k_enb, diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 867221e87..dedd392c1 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -50,6 +50,8 @@ rx_gain = 40 [pcap] enable = false filename = /tmp/ue.pcap +nas_enable = false +nas_filename = /tmp/nas.pcap ##################################################################### # Log configuration From 6b264732d2621353d9c26e9d8ce88430d9edf433 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 1 Dec 2017 11:25:27 +0100 Subject: [PATCH 13/42] Disabled subframe average --- lib/examples/pdsch_ue.c | 8 +-- lib/src/phy/ue/ue_dl.c | 2 +- lib/src/phy/ue/ue_ul.c | 2 +- srsue/hdr/phy/phch_recv.h | 2 + srsue/hdr/upper/rrc.h | 6 +- srsue/src/main.cc | 2 +- srsue/src/phy/phch_recv.cc | 85 ++++++++++++----------- srsue/src/phy/phch_worker.cc | 15 ++-- srsue/src/upper/rrc.cc | 129 ++++++++++++++++++++++++++++------- srsue/ue.conf.example | 2 +- 10 files changed, 171 insertions(+), 82 deletions(-) diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 6608f0817..ae43a5260 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -958,7 +958,7 @@ void *plot_thread_run(void *arg) { plot_real_init(&pce); plot_real_setTitle(&pce, "Channel Response - Magnitude"); plot_real_setLabels(&pce, "Index", "dB"); - plot_real_setYAxisScale(&pce, -M_PI, M_PI); + plot_real_setYAxisScale(&pce, -40, 40); plot_real_init(&p_sync); plot_real_setTitle(&p_sync, "PSS Cross-Corr abs value"); @@ -994,11 +994,7 @@ void *plot_thread_run(void *arg) { tmp_plot2[g+i] = -80; } } - uint32_t nrefs = 2*ue_dl.cell.nof_prb; - for (i=0;i(&args->expert.phy.average_subframe_enabled)->default_value(true), + bpo::value(&args->expert.phy.average_subframe_enabled)->default_value(false), "Averages in the time domain the channel estimates within 1 subframe. Needs accurate CFO correction.") ("expert.time_correct_period", diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index e3ab21c0e..dc056f9c0 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -399,22 +399,24 @@ bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) { log_h->warning("Still not in idle\n"); } - current_earfcn = earfcn; + if (earfcn != current_earfcn) { + if (set_frequency()) { + log_h->error("Cell Select: Configuring cell in EARFCN=%d, PCI=%d\n", earfcn, cell.id); + return false; + } + current_earfcn = earfcn; + } - if (set_frequency()) { - this->cell = cell; - log_h->info("Cell Select: Configuring cell...\n"); + this->cell = cell; + log_h->info("Cell Select: Configuring cell...\n"); - if (set_cell()) { - log_h->info("Cell Select: Synchronizing on cell...\n"); + if (set_cell()) { + log_h->info("Cell Select: Synchronizing on cell...\n"); - resync_sfn(); + resync_sfn(); - usleep(500000); // Time offset we set start_rx to start receiving samples - return true; - } else { - log_h->error("Cell Select: Configuring cell in EARFCN=%d, PCI=%d\n", earfcn, cell.id); - } + usleep(500000); // Time offset we set start_rx to start receiving samples + return true; } return false; } @@ -669,13 +671,21 @@ void phch_recv::run_thread() workers_pool->start_worker(worker); intra_freq_meas.write(tti, buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb)); + out_of_sync_cnt = 0; break; case 0: - log_h->error("SYNC: Sync error. Sending out-of-sync to RRC\n"); - // Notify RRC of out-of-sync frame - rrc->out_of_sync(); + // Signal every 5 errors only (PSS is every 5) + if (out_of_sync_cnt == 0) { + // Notify RRC of out-of-sync frame + log_h->error("SYNC: Sync error. Sending out-of-sync to RRC\n"); + rrc->out_of_sync(); + } worker->release(); worker_com->reset_ul(); + out_of_sync_cnt++; + if (out_of_sync_cnt >= 5) { + out_of_sync_cnt = 0; + } break; default: radio_error(); @@ -1203,7 +1213,7 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, int nof_cells = 0; uint32_t peak_idx = 0; uint32_t sf_idx = 0; - uint32_t cell_id = 0; + int cell_id = 0; srslte_cell_t found_cell; memcpy(&found_cell, &cell, sizeof(srslte_cell_t)); @@ -1226,29 +1236,28 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, sf_idx = srslte_sync_get_sf_idx(&sync_find); cell_id = srslte_sync_get_cell_id(&sync_find); - Info("INTRA: found peak_idx=%d, n_id_2=%d, cell_id=%d, sf=%d\n", + if (cell_id != -1) { + Info("INTRA: found peak_idx=%d, n_id_2=%d, cell_id=%d, sf=%d\n", peak_idx, n_id_2, cell_id, sf_idx); - found_cell.id = cell_id; - found_cell.nof_ports = 1; // Use port 0 only for measurement - measure_p.set_cell(found_cell); - - //printf("cell_id=%d, correcting cfo=%f Hz\n", cell_id, 15000*sync_find.mean_cfo2); - //srslte_cfo_correct(&sync_find.cfocorr, input_buffer, input_buffer, -sync_find.mean_cfo2 / sync_find.fft_size); - - switch(measure_p.run_multiple_subframes(input_buffer, peak_idx, sf_idx, nof_sf)) { - case measure::MEASURE_OK: - cells[nof_cells].pci = found_cell.id; - cells[nof_cells].rsrp = measure_p.rsrp(); - cells[nof_cells].rsrq = measure_p.rsrq(); - cells[nof_cells].offset = peak_idx; - nof_cells++; - break; - case measure::ERROR: - Error("Measuring neighbour cell\n"); - return SRSLTE_ERROR; - default: - break; + found_cell.id = cell_id; + found_cell.nof_ports = 1; // Use port 0 only for measurement + measure_p.set_cell(found_cell); + + switch(measure_p.run_multiple_subframes(input_buffer, peak_idx, sf_idx, nof_sf)) { + case measure::MEASURE_OK: + cells[nof_cells].pci = found_cell.id; + cells[nof_cells].rsrp = measure_p.rsrp(); + cells[nof_cells].rsrq = measure_p.rsrq(); + cells[nof_cells].offset = peak_idx; + nof_cells++; + break; + case measure::ERROR: + Error("Measuring neighbour cell\n"); + return SRSLTE_ERROR; + default: + break; + } } break; case SRSLTE_SYNC_FOUND_NOSPACE: @@ -1347,7 +1356,7 @@ void phch_recv::intra_measure::add_cell(int pci) { receive_enabled = true; Info("INTRA: Starting intra-frequency measurement for pci=%d\n", pci); } else { - Warning("INTRA: Requested to start already existing intra-frequency measurement for PCI=%d\n", pci); + Debug("INTRA: Requested to start already existing intra-frequency measurement for PCI=%d\n", pci); } } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index c56ce9eb8..bf5000ecf 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -230,7 +230,7 @@ void phch_worker::work_imp() /* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */ bool chest_ok = extract_fft_and_pdcch_llr(); - bool snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>-10.0; + bool snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>-20.0; // Call feedback loop for chest if (chest_loop && ((1<<(tti%10)) & phy->args->cfo_ref_mask)) { @@ -1227,18 +1227,13 @@ int phch_worker::read_ce_abs(float *ce_abs) { int sz = srslte_symbol_sz(cell.nof_prb); bzero(ce_abs, sizeof(float)*sz); int g = (sz - 12*cell.nof_prb)/2; -/* for (i = 0; i < 12*cell.nof_prb; i++) { + for (i = 0; i < 12*cell.nof_prb; i++) { ce_abs[g+i] = 20 * log10f(cabsf(ue_dl.ce_m[0][0][i])); if (isinf(ce_abs[g+i])) { ce_abs[g+i] = -80; } } -*/ - uint32_t nrefs = 2*ue_dl.cell.nof_prb; - for (i=0;iavg_rsrp_dbm= rsrp_dbm; } else { phy->avg_rsrp_dbm = SRSLTE_VEC_EMA(rsrp_dbm, phy->avg_rsrp_dbm, snr_ema_coeff); - } + } if ((tti%phy->pcell_report_period) == 0 && phy->pcell_meas_enabled) { phy->rrc->new_phy_meas(phy->avg_rsrp_dbm, phy->avg_rsrq_db, tti); } @@ -1388,7 +1383,7 @@ void *plot_thread_run(void *arg) { plot_real_init(&pce); plot_real_setTitle(&pce, (char*) "Channel Response - Magnitude"); plot_real_setLabels(&pce, (char*) "Index", (char*) "dB"); - plot_real_setYAxisScale(&pce, -1000, 1000); + plot_real_setYAxisScale(&pce, -40, 40); plot_scatter_init(&pconst); plot_scatter_setTitle(&pconst, (char*) "PDSCH - Equalized Symbols"); diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 31ed25384..6e73670f7 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -225,14 +225,22 @@ void rrc::run_thread() { } break; case RRC_STATE_CELL_SELECTED: - rrc_log->info("RRC Cell Selected: Sending connection request...\n"); - if (reestablishment_in_progress) { + if (!nas->is_attached() || paging_received) { + paging_received = false; + rrc_log->info("RRC Cell Selected: Sending connection request...\n"); + send_con_request(); + state = RRC_STATE_CONNECTING; + connecting_timeout = 0; + } else if (reestablishment_in_progress) { + rrc_log->info("RRC Cell Selected: Sending connection reestablishment...\n"); con_restablish_cell_reselected(); + state = RRC_STATE_CONNECTING; + connecting_timeout = 0; } else { - send_con_request(); + rrc_log->console("RRC Cell Selected: New PCI=%d\n", current_cell->phy_cell.id); + mac->pcch_start_rx(); + state = RRC_STATE_IDLE; } - state = RRC_STATE_CONNECTING; - connecting_timeout = 0; break; case RRC_STATE_CONNECTING: connecting_timeout++; @@ -471,7 +479,34 @@ void rrc::new_phy_meas(float rsrp, float rsrq, uint32_t tti, uint32_t earfcn, ui if (state == RRC_STATE_CONNECTED) { measurements.new_phy_meas(earfcn, pci, rsrp, rsrq, tti); } else { - cell_reselection_eval(rsrp, rsrq); + // If measurement is of the serving cell, evaluate cell reselection criteria + if ((earfcn == phy->get_current_earfcn() && pci == phy->get_current_pci()) || (earfcn == 0 && pci == 0)) { + cell_reselection_eval(rsrp, rsrq); + current_cell->rsrp = rsrp; + rrc_log->info("MEAS: New measurement serving cell, rsrp=%f, rsrq=%f, tti=%d\n", rsrp, rsrq, tti); + } else { + // Add/update cell measurement + srslte_cell_t cell; + phy->get_current_cell(&cell, NULL); + cell.id = pci; + add_new_cell(earfcn, cell, rsrp); + + rrc_log->info("MEAS: New measurement PCI=%d, RSRP=%.1f dBm.\n", pci, rsrp); + } + + srslte_cell_t best_cell; + uint32_t best_cell_idx = find_best_cell(phy->get_current_earfcn(), &best_cell); + + // Verify cell selection criteria + if (cell_selection_eval(known_cells[best_cell_idx].rsrp) && + known_cells[best_cell_idx].rsrp > current_cell->rsrp + 5 && + best_cell.id != phy->get_current_pci()) + { + rrc_log->info("Selecting best neighbour cell PCI=%d, rsrp=%.1f dBm\n", best_cell.id, known_cells[best_cell_idx].rsrp); + state = RRC_STATE_CELL_SELECTING; + current_cell = &known_cells[best_cell_idx]; + phy->cell_select(phy->get_current_earfcn(), best_cell); + } } } @@ -498,8 +533,13 @@ void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { return; } } - // add to list of known cells - add_new_cell(earfcn, phy_cell, rsrp); + // add to list of known cells and set current_cell + current_cell = add_new_cell(earfcn, phy_cell, rsrp); + if(!current_cell) { + current_cell = &known_cells[0]; + rrc_log->error("Couldn't add new cell\n"); + return; + } si_acquire_state = SI_ACQUIRE_SIB1; @@ -508,22 +548,52 @@ void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { current_cell->earfcn, current_cell->rsrp, current_cell); } -void rrc::add_new_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { +uint32_t rrc::find_best_cell(uint32_t earfcn, srslte_cell_t *cell) { + float best_rsrp = -INFINITY; + uint32_t best_cell_idx = 0; + for (int i=0;i best_rsrp) { + best_rsrp = known_cells[i].rsrp; + best_cell_idx = i; + } + } + } + if (cell) { + memcpy(cell, &known_cells[best_cell_idx].phy_cell, sizeof(srslte_cell_t)); + } + return best_cell_idx; +} + +rrc::cell_t* rrc::add_new_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { + if (earfcn == 0) { + return NULL; + } + // First check it does not exist already + int j=0; + while(jerror("Can't add more cells\n"); - return; + return NULL; } - current_cell = &known_cells[i]; - current_cell->phy_cell = phy_cell; - current_cell->rsrp = rsrp; - current_cell->earfcn = earfcn; - current_cell->has_valid_sib1 = false; - current_cell->has_valid_sib2 = false; - current_cell->has_valid_sib3 = false; + + known_cells[i].phy_cell = phy_cell; + known_cells[i].rsrp = rsrp; + known_cells[i].earfcn = earfcn; + known_cells[i].has_valid_sib1 = false; + known_cells[i].has_valid_sib2 = false; + known_cells[i].has_valid_sib3 = false; + return &known_cells[i]; } // PHY indicates that has gone through all known EARFCN @@ -551,14 +621,16 @@ void rrc::add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp) { add_new_cell(earfcn, cell, rsrp); } -// Cell reselection in IDLE Section 5.2.4 of 36.304 +// Cell reselction in IDLE Section 5.2.4 of 36.304 void rrc::cell_reselection_eval(float rsrp, float rsrq) { // Intra-frequency cell-reselection criteria - if (get_srxlev(rsrp) > cell_resel_cfg.s_intrasearchP) { - // UE may not perform intra-frequency measurements + if (get_srxlev(rsrp) > cell_resel_cfg.s_intrasearchP && rsrp > -80.0) { + // UE may not perform intra-frequency measurements. phy->meas_reset(); + // keep measuring serving cell + phy->meas_start(phy->get_current_earfcn(), phy->get_current_pci()); } else { // UE must start intra-frequency measurements phy->meas_start(phy->get_current_earfcn(), -1); @@ -567,6 +639,16 @@ void rrc::cell_reselection_eval(float rsrp, float rsrq) // TODO: Inter-frequency cell reselection } +// Cell selection in IDLE Section 5.2.3.2 of 36.304 +bool rrc::cell_selection_eval(float rsrp, float rsrq) +{ + if (get_srxlev(rsrp) > 0) { + return true; + } else { + return false; + } +} + float rrc::get_srxlev(float Qrxlevmeas) { // TODO: Do max power limitation float Pcompensation = 0; @@ -1144,12 +1226,12 @@ void rrc::handle_sib3() cell_resel_cfg.q_hyst = liblte_rrc_q_hyst_num[sib3->q_hyst]; // cellReselectionServingFreqInfo - cell_resel_cfg.threshservinglow = 2*sib3->thresh_serving_low; + cell_resel_cfg.threshservinglow = sib3->thresh_serving_low; // intraFreqCellReselectionInfo - cell_resel_cfg.Qrxlevmin = 2*sib3->q_rx_lev_min; + cell_resel_cfg.Qrxlevmin = sib3->q_rx_lev_min; if (sib3->s_intra_search_present) { - cell_resel_cfg.s_intrasearchP = 2*sib3->s_intra_search; + cell_resel_cfg.s_intrasearchP = sib3->s_intra_search; } else { cell_resel_cfg.s_intrasearchP = INFINITY; } @@ -1214,6 +1296,7 @@ void rrc::write_pdu_pcch(byte_buffer_t *pdu) { mac->pcch_stop_rx(); if (RRC_STATE_IDLE == state) { rrc_log->info("RRC in IDLE state - sending connection request.\n"); + paging_received = true; state = RRC_STATE_CELL_SELECTING; } } diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 7bd6fae18..0b3314e7a 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -188,7 +188,7 @@ enable = false #sfo_correct_disable = false #sss_algorithm = full #estimator_fil_w = 0.1 -#average_subframe_enabled = true +#average_subframe_enabled = false #pregenerate_signals = false #metrics_csv_enable = false #metrics_csv_filename = /tmp/ue_metrics.csv From 516fdc27f19dc4156118021251626ff4f397b71c Mon Sep 17 00:00:00 2001 From: Paul Sutton Date: Fri, 1 Dec 2017 12:38:18 +0000 Subject: [PATCH 14/42] Fix for NAS security bearer id, added encryption test sets, fix for compile warning --- lib/src/common/liblte_security.cc | 5 +- lib/test/common/CMakeLists.txt | 8 + lib/test/common/test_eea1.cc | 569 ++++++++++++++++++++++++++++++ lib/test/common/test_eea2.cc | 567 +++++++++++++++++++++++++++++ srsue/hdr/upper/nas.h | 7 +- srsue/src/upper/nas.cc | 47 ++- 6 files changed, 1170 insertions(+), 33 deletions(-) create mode 100644 lib/test/common/test_eea1.cc create mode 100644 lib/test/common/test_eea2.cc diff --git a/lib/src/common/liblte_security.cc b/lib/src/common/liblte_security.cc index 4ff35b5e4..37df6c7df 100644 --- a/lib/src/common/liblte_security.cc +++ b/lib/src/common/liblte_security.cc @@ -903,7 +903,7 @@ LIBLTE_ERROR_ENUM liblte_security_encryption_eea1(uint8 *key, s3g_generate_keystream(state_ptr, msg_len_block_32, ks); // Generate output except last block - for (i = 0; i < msg_len_block_32 - 1; i++) { + for (i = 0; i < (int32_t)msg_len_block_32 - 1; i++) { out[4 * i + 0] = msg[4 * i + 0] ^ ((ks[i] >> 24) & 0xFF); out[4 * i + 1] = msg[4 * i + 1] ^ ((ks[i] >> 16) & 0xFF); out[4 * i + 2] = msg[4 * i + 2] ^ ((ks[i] >> 8) & 0xFF); @@ -911,8 +911,7 @@ LIBLTE_ERROR_ENUM liblte_security_encryption_eea1(uint8 *key, } // Process last bytes - for (i = (msg_len_block_32 - 1) * 4; i < msg_len_block_8; - i++) { + for (i = (msg_len_block_32 - 1) * 4; i < (int32_t)msg_len_block_8; i++) { out[i] = msg[i] ^ ((ks[i / 4] >> ((3 - (i % 4)) * 8)) & 0xFF); } diff --git a/lib/test/common/CMakeLists.txt b/lib/test/common/CMakeLists.txt index 3faa2ff59..bbdc74613 100644 --- a/lib/test/common/CMakeLists.txt +++ b/lib/test/common/CMakeLists.txt @@ -29,6 +29,14 @@ add_executable(msg_queue_test msg_queue_test.cc) target_link_libraries(msg_queue_test srslte_phy srslte_common ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) add_test(msg_queue_test msg_queue_test) +add_executable(test_eea1 test_eea1.cc) +target_link_libraries(test_eea1 srslte_common ${CMAKE_THREAD_LIBS_INIT}) +add_test(test_eea1 test_eea1) + +add_executable(test_eea2 test_eea2.cc) +target_link_libraries(test_eea2 srslte_common ${CMAKE_THREAD_LIBS_INIT}) +add_test(test_eea2 test_eea2) + add_executable(log_filter_test log_filter_test.cc) target_link_libraries(log_filter_test srslte_phy srslte_common srslte_phy ${SEC_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) diff --git a/lib/test/common/test_eea1.cc b/lib/test/common/test_eea1.cc new file mode 100644 index 000000000..b3c57caa6 --- /dev/null +++ b/lib/test/common/test_eea1.cc @@ -0,0 +1,569 @@ +/* + * Includes + */ + +#include +#include +#include + +#include "srslte/common/liblte_security.h" + +/* + * Prototypes + */ + +int32 arrcmp(uint8_t const * const a, uint8_t const * const b, uint32 len) { + uint32 i = 0; + + for (i = 0; i < len; i++) { + if (a[i] != b[i]) { + return a[i] - b[i]; + } + } + return 0; +} + +/* + * Tests + * + * Document Reference: 33.401 V13.1.0 Annex C.3 + * Specification of the 3GPP Confidentiality and + * Integrity Algorithms UEA2 & UIA2 D4 v1.0 + */ + +void test_set_1() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 253, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0x5d, 0x5b, 0xfe, 0x75, 0xeb, 0x04, 0xf6, + 0x8c, 0xe0, 0xa1, 0x23, 0x77, 0xea, 0x00, 0xb3, 0x7d, + 0x47, 0xc6, 0xa0, 0xba, 0x06, 0x30, 0x91, 0x55, 0x08, + 0x6a, 0x85, 0x9c, 0x43, 0x41, 0xb3, 0x78 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_2() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x2b, 0xd6, 0x45, 0x9f, 0x82, 0xc4, 0x40, + 0xe0, 0x95, 0x2c, 0x49, 0x10, 0x48, 0x05, 0xff, 0x48 }; + uint32_t count = 0xc675a64b; + uint8_t bearer = 0x0c; + uint8_t direction = 1; + uint32_t len_bits = 798, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x7e, 0xc6, 0x12, 0x72, 0x74, 0x3b, 0xf1, + 0x61, 0x47, 0x26, 0x44, 0x6a, 0x6c, 0x38, 0xce, 0xd1, + 0x66, 0xf6, 0xca, 0x76, 0xeb, 0x54, 0x30, 0x04, 0x42, + 0x86, 0x34, 0x6c, 0xef, 0x13, 0x0f, 0x92, 0x92, 0x2b, + 0x03, 0x45, 0x0d, 0x3a, 0x99, 0x75, 0xe5, 0xbd, 0x2e, + 0xa0, 0xeb, 0x55, 0xad, 0x8e, 0x1b, 0x19, 0x9e, 0x3e, + 0xc4, 0x31, 0x60, 0x20, 0xe9, 0xa1, 0xb2, 0x85, 0xe7, + 0x62, 0x79, 0x53, 0x59, 0xb7, 0xbd, 0xfd, 0x39, 0xbe, + 0xf4, 0xb2, 0x48, 0x45, 0x83, 0xd5, 0xaf, 0xe0, 0x82, + 0xae, 0xe6, 0x38, 0xbf, 0x5f, 0xd5, 0xa6, 0x06, 0x19, + 0x39, 0x01, 0xa0, 0x8f, 0x4a, 0xb4, 0x1a, 0xab, 0x9b, + 0x13, 0x48, 0x80 }; + uint8_t ct[] = { 0x3f, 0x67, 0x85, 0x07, 0x14, 0xb8, 0xda, + 0x69, 0xef, 0xb7, 0x27, 0xed, 0x7a, 0x6c, 0x0c, 0x50, + 0x71, 0x4a, 0xd7, 0x36, 0xc4, 0xf5, 0x60, 0x00, 0x06, + 0xe3, 0x52, 0x5b, 0xe8, 0x07, 0xc4, 0x67, 0xc6, 0x77, + 0xff, 0x86, 0x4a, 0xf4, 0x5f, 0xba, 0x09, 0xc2, 0x7c, + 0xde, 0x38, 0xf8, 0x7a, 0x1f, 0x84, 0xd5, 0x9a, 0xb2, + 0x55, 0x40, 0x8f, 0x2c, 0x7b, 0x82, 0xf9, 0xea, 0xd4, + 0x1a, 0x1f, 0xe6, 0x5e, 0xab, 0xeb, 0xfb, 0xc1, 0xf3, + 0xa4, 0xc5, 0x6c, 0x9a, 0x26, 0xfc, 0xf7, 0xb3, 0xd6, + 0x6d, 0x02, 0x20, 0xee, 0x47, 0x75, 0xbc, 0x58, 0x17, + 0x0a, 0x2b, 0x12, 0xf3, 0x43, 0x1d, 0x11, 0xb3, 0x44, + 0xd6, 0xe3, 0x6c }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_3() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x0a, 0x8b, 0x6b, 0xd8, 0xd9, 0xb0, 0x8b, + 0x08, 0xd6, 0x4e, 0x32, 0xd1, 0x81, 0x77, 0x77, 0xfb }; + uint32_t count = 0x544d49cd; + uint8_t bearer = 0x04; + uint8_t direction = 0; + uint32_t len_bits = 310, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0xfd, 0x40, 0xa4, 0x1d, 0x37, 0x0a, 0x1f, + 0x65, 0x74, 0x50, 0x95, 0x68, 0x7d, 0x47, 0xba, 0x1d, + 0x36, 0xd2, 0x34, 0x9e, 0x23, 0xf6, 0x44, 0x39, 0x2c, + 0x8e, 0xa9, 0xc4, 0x9d, 0x40, 0xc1, 0x32, 0x71, 0xaf, + 0xf2, 0x64, 0xd0, 0xf2, 0x48, 0x00 }; + uint8_t ct[] = { 0x48, 0x14, 0x8e, 0x54, 0x52, 0xa2, 0x10, + 0xc0, 0x5f, 0x46, 0xbc, 0x80, 0xdc, 0x6f, 0x73, 0x49, + 0x5b, 0x02, 0x04, 0x8c, 0x1b, 0x95, 0x8b, 0x02, 0x61, + 0x02, 0xca, 0x97, 0x28, 0x02, 0x79, 0xa4, 0xc1, 0x8d, + 0x2e, 0xe3, 0x08, 0x92, 0x1c }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_4() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xaa, 0x1f, 0x95, 0xae, 0xa5, 0x33, 0xbc, + 0xb3, 0x2e, 0xb6, 0x3b, 0xf5, 0x2d, 0x8f, 0x83, 0x1a }; + uint32_t count = 0x72d8c671; + uint8_t bearer = 0x10; + uint8_t direction = 1; + uint32_t len_bits = 1022, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0xfb, 0x1b, 0x96, 0xc5, 0xc8, 0xba, 0xdf, + 0xb2, 0xe8, 0xe8, 0xed, 0xfd, 0xe7, 0x8e, 0x57, 0xf2, + 0xad, 0x81, 0xe7, 0x41, 0x03, 0xfc, 0x43, 0x0a, 0x53, + 0x4d, 0xcc, 0x37, 0xaf, 0xce, 0xc7, 0x0e, 0x15, 0x17, + 0xbb, 0x06, 0xf2, 0x72, 0x19, 0xda, 0xe4, 0x90, 0x22, + 0xdd, 0xc4, 0x7a, 0x06, 0x8d, 0xe4, 0xc9, 0x49, 0x6a, + 0x95, 0x1a, 0x6b, 0x09, 0xed, 0xbd, 0xc8, 0x64, 0xc7, + 0xad, 0xbd, 0x74, 0x0a, 0xc5, 0x0c, 0x02, 0x2f, 0x30, + 0x82, 0xba, 0xfd, 0x22, 0xd7, 0x81, 0x97, 0xc5, 0xd5, + 0x08, 0xb9, 0x77, 0xbc, 0xa1, 0x3f, 0x32, 0xe6, 0x52, + 0xe7, 0x4b, 0xa7, 0x28, 0x57, 0x60, 0x77, 0xce, 0x62, + 0x8c, 0x53, 0x5e, 0x87, 0xdc, 0x60, 0x77, 0xba, 0x07, + 0xd2, 0x90, 0x68, 0x59, 0x0c, 0x8c, 0xb5, 0xf1, 0x08, + 0x8e, 0x08, 0x2c, 0xfa, 0x0e, 0xc9, 0x61, 0x30, 0x2d, + 0x69, 0xcf, 0x3d, 0x44 }; + uint8_t ct[] = { 0xff, 0xcf, 0xc2, 0xfe, 0xad, 0x6c, 0x09, + 0x4e, 0x96, 0xc5, 0x89, 0xd0, 0xf6, 0x77, 0x9b, 0x67, + 0x84, 0x24, 0x6c, 0x3c, 0x4d, 0x1c, 0xea, 0x20, 0x3d, + 0xb3, 0x90, 0x1f, 0x40, 0xad, 0x4f, 0xd7, 0x13, 0x8b, + 0xc6, 0xd7, 0x7e, 0x83, 0x20, 0xcb, 0x10, 0x2f, 0x49, + 0x7f, 0xdd, 0x44, 0xa2, 0x69, 0xa9, 0x6e, 0xcb, 0x28, + 0x61, 0x77, 0x00, 0xe3, 0x32, 0xeb, 0x2f, 0x73, 0x6b, + 0x34, 0xf4, 0xf2, 0x69, 0x30, 0x94, 0xe2, 0x2f, 0xf9, + 0x4f, 0x9b, 0xe4, 0x72, 0x3d, 0xa4, 0x0c, 0x40, 0xdf, + 0xd3, 0x93, 0x1c, 0xc1, 0xac, 0x97, 0x23, 0xf6, 0xb4, + 0xa9, 0x91, 0x3e, 0x96, 0xb6, 0xdb, 0x7a, 0xbc, 0xac, + 0xe4, 0x15, 0x17, 0x7c, 0x1d, 0x01, 0x15, 0xc5, 0xf0, + 0x9b, 0x5f, 0xde, 0xa0, 0xb3, 0xad, 0xb8, 0xf9, 0xda, + 0x6e, 0x9f, 0x9a, 0x04, 0xc5, 0x43, 0x39, 0x7b, 0x9d, + 0x43, 0xf8, 0x73, 0x30 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_5() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x96, 0x18, 0xae, 0x46, 0x89, 0x1f, 0x86, + 0x57, 0x8e, 0xeb, 0xe9, 0x0e, 0xf7, 0xa1, 0x20, 0x2e }; + uint32_t count = 0xc675a64b; + uint8_t bearer = 0x0c; + uint8_t direction = 1; + uint32_t len_bits = 1245, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x8d, 0xaa, 0x17, 0xb1, 0xae, 0x05, 0x05, + 0x29, 0xc6, 0x82, 0x7f, 0x28, 0xc0, 0xef, 0x6a, 0x12, + 0x42, 0xe9, 0x3f, 0x8b, 0x31, 0x4f, 0xb1, 0x8a, 0x77, + 0xf7, 0x90, 0xae, 0x04, 0x9f, 0xed, 0xd6, 0x12, 0x26, + 0x7f, 0xec, 0xae, 0xfc, 0x45, 0x01, 0x74, 0xd7, 0x6d, + 0x9f, 0x9a, 0xa7, 0x75, 0x5a, 0x30, 0xcd, 0x90, 0xa9, + 0xa5, 0x87, 0x4b, 0xf4, 0x8e, 0xaf, 0x70, 0xee, 0xa3, + 0xa6, 0x2a, 0x25, 0x0a, 0x8b, 0x6b, 0xd8, 0xd9, 0xb0, + 0x8b, 0x08, 0xd6, 0x4e, 0x32, 0xd1, 0x81, 0x77, 0x77, + 0xfb, 0x54, 0x4d, 0x49, 0xcd, 0x49, 0x72, 0x0e, 0x21, + 0x9d, 0xbf, 0x8b, 0xbe, 0xd3, 0x39, 0x04, 0xe1, 0xfd, + 0x40, 0xa4, 0x1d, 0x37, 0x0a, 0x1f, 0x65, 0x74, 0x50, + 0x95, 0x68, 0x7d, 0x47, 0xba, 0x1d, 0x36, 0xd2, 0x34, + 0x9e, 0x23, 0xf6, 0x44, 0x39, 0x2c, 0x8e, 0xa9, 0xc4, + 0x9d, 0x40, 0xc1, 0x32, 0x71, 0xaf, 0xf2, 0x64, 0xd0, + 0xf2, 0x48, 0x41, 0xd6, 0x46, 0x5f, 0x09, 0x96, 0xff, + 0x84, 0xe6, 0x5f, 0xc5, 0x17, 0xc5, 0x3e, 0xfc, 0x33, + 0x63, 0xc3, 0x84, 0x92, 0xa8 }; + uint8_t ct[] = { 0x6c, 0xdb, 0x18, 0xa7, 0xca, 0x82, 0x18, + 0xe8, 0x6e, 0x4b, 0x4b, 0x71, 0x6a, 0x4d, 0x04, 0x37, + 0x1f, 0xbe, 0xc2, 0x62, 0xfc, 0x5a, 0xd0, 0xb3, 0x81, + 0x9b, 0x18, 0x7b, 0x97, 0xe5, 0x5b, 0x1a, 0x4d, 0x7c, + 0x19, 0xee, 0x24, 0xc8, 0xb4, 0xd7, 0x72, 0x3c, 0xfe, + 0xdf, 0x04, 0x5b, 0x8a, 0xca, 0xe4, 0x86, 0x95, 0x17, + 0xd8, 0x0e, 0x50, 0x61, 0x5d, 0x90, 0x35, 0xd5, 0xd9, + 0xc5, 0xa4, 0x0a, 0xf6, 0x02, 0x28, 0x0b, 0x54, 0x25, + 0x97, 0xb0, 0xcb, 0x18, 0x61, 0x9e, 0xeb, 0x35, 0x92, + 0x57, 0x59, 0xd1, 0x95, 0xe1, 0x00, 0xe8, 0xe4, 0xaa, + 0x0c, 0x38, 0xa3, 0xc2, 0xab, 0xe0, 0xf3, 0xd8, 0xff, + 0x04, 0xf3, 0xc3, 0x3c, 0x29, 0x50, 0x69, 0xc2, 0x36, + 0x94, 0xb5, 0xbb, 0xea, 0xcd, 0xd5, 0x42, 0xe2, 0x8e, + 0x8a, 0x94, 0xed, 0xb9, 0x11, 0x9f, 0x41, 0x2d, 0x05, + 0x4b, 0xe1, 0xfa, 0x72, 0x72, 0xb5, 0xff, 0xb2, 0xb2, + 0x57, 0x0f, 0x4f, 0x7c, 0xea, 0xf3, 0x83, 0xa8, 0xa9, + 0xd9, 0x35, 0x72, 0xf0, 0x4d, 0x6e, 0x3a, 0x6e, 0x29, + 0x37, 0x26, 0xec, 0x62, 0xc8 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_6() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x54, 0xf4, 0xe2, 0xe0, 0x4c, 0x83, 0x78, + 0x6e, 0xec, 0x8f, 0xb5, 0xab, 0xe8, 0xe3, 0x65, 0x66 }; + uint32_t count = 0xaca4f50f; + uint8_t bearer = 0x0b; + uint8_t direction = 0; + uint32_t len_bits = 3861, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x40, 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, + 0xfb, 0x42, 0x86, 0xb2, 0x99, 0x78, 0x3d, 0xaf, 0x44, + 0x2c, 0x09, 0x9f, 0x7a, 0xb0, 0xf5, 0x8d, 0x5c, 0x8e, + 0x46, 0xb1, 0x04, 0xf0, 0x8f, 0x01, 0xb4, 0x1a, 0xb4, + 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x36, 0xbd, 0x1a, + 0x3d, 0x90, 0xdc, 0x3a, 0x41, 0xb4, 0x6d, 0x51, 0x67, + 0x2a, 0xc4, 0xc9, 0x66, 0x3a, 0x2b, 0xe0, 0x63, 0xda, + 0x4b, 0xc8, 0xd2, 0x80, 0x8c, 0xe3, 0x3e, 0x2c, 0xcc, + 0xbf, 0xc6, 0x34, 0xe1, 0xb2, 0x59, 0x06, 0x08, 0x76, + 0xa0, 0xfb, 0xb5, 0xa4, 0x37, 0xeb, 0xcc, 0x8d, 0x31, + 0xc1, 0x9e, 0x44, 0x54, 0x31, 0x87, 0x45, 0xe3, 0xfa, + 0x16, 0xbb, 0x11, 0xad, 0xae, 0x24, 0x88, 0x79, 0xfe, + 0x52, 0xdb, 0x25, 0x43, 0xe5, 0x3c, 0xf4, 0x45, 0xd3, + 0xd8, 0x28, 0xce, 0x0b, 0xf5, 0xc5, 0x60, 0x59, 0x3d, + 0x97, 0x27, 0x8a, 0x59, 0x76, 0x2d, 0xd0, 0xc2, 0xc9, + 0xcd, 0x68, 0xd4, 0x49, 0x6a, 0x79, 0x25, 0x08, 0x61, + 0x40, 0x14, 0xb1, 0x3b, 0x6a, 0xa5, 0x11, 0x28, 0xc1, + 0x8c, 0xd6, 0xa9, 0x0b, 0x87, 0x97, 0x8c, 0x2f, 0xf1, + 0xca, 0xbe, 0x7d, 0x9f, 0x89, 0x8a, 0x41, 0x1b, 0xfd, + 0xb8, 0x4f, 0x68, 0xf6, 0x72, 0x7b, 0x14, 0x99, 0xcd, + 0xd3, 0x0d, 0xf0, 0x44, 0x3a, 0xb4, 0xa6, 0x66, 0x53, + 0x33, 0x0b, 0xcb, 0xa1, 0x10, 0x5e, 0x4c, 0xec, 0x03, + 0x4c, 0x73, 0xe6, 0x05, 0xb4, 0x31, 0x0e, 0xaa, 0xad, + 0xcf, 0xd5, 0xb0, 0xca, 0x27, 0xff, 0xd8, 0x9d, 0x14, + 0x4d, 0xf4, 0x79, 0x27, 0x59, 0x42, 0x7c, 0x9c, 0xc1, + 0xf8, 0xcd, 0x8c, 0x87, 0x20, 0x23, 0x64, 0xb8, 0xa6, + 0x87, 0x95, 0x4c, 0xb0, 0x5a, 0x8d, 0x4e, 0x2d, 0x99, + 0xe7, 0x3d, 0xb1, 0x60, 0xde, 0xb1, 0x80, 0xad, 0x08, + 0x41, 0xe9, 0x67, 0x41, 0xa5, 0xd5, 0x9f, 0xe4, 0x18, + 0x9f, 0x15, 0x42, 0x00, 0x26, 0xfe, 0x4c, 0xd1, 0x21, + 0x04, 0x93, 0x2f, 0xb3, 0x8f, 0x73, 0x53, 0x40, 0x43, + 0x8a, 0xaf, 0x7e, 0xca, 0x6f, 0xd5, 0xcf, 0xd3, 0xa1, + 0x95, 0xce, 0x5a, 0xbe, 0x65, 0x27, 0x2a, 0xf6, 0x07, + 0xad, 0xa1, 0xbe, 0x65, 0xa6, 0xb4, 0xc9, 0xc0, 0x69, + 0x32, 0x34, 0x09, 0x2c, 0x4d, 0x01, 0x8f, 0x17, 0x56, + 0xc6, 0xdb, 0x9d, 0xc8, 0xa6, 0xd8, 0x0b, 0x88, 0x81, + 0x38, 0x61, 0x6b, 0x68, 0x12, 0x62, 0xf9, 0x54, 0xd0, + 0xe7, 0x71, 0x17, 0x48, 0x78, 0x0d, 0x92, 0x29, 0x1d, + 0x86, 0x29, 0x99, 0x72, 0xdb, 0x74, 0x1c, 0xfa, 0x4f, + 0x37, 0xb8, 0xb5, 0x6c, 0xdb, 0x18, 0xa7, 0xca, 0x82, + 0x18, 0xe8, 0x6e, 0x4b, 0x4b, 0x71, 0x6a, 0x4d, 0x04, + 0x37, 0x1f, 0xbe, 0xc2, 0x62, 0xfc, 0x5a, 0xd0, 0xb3, + 0x81, 0x9b, 0x18, 0x7b, 0x97, 0xe5, 0x5b, 0x1a, 0x4d, + 0x7c, 0x19, 0xee, 0x24, 0xc8, 0xb4, 0xd7, 0x72, 0x3c, + 0xfe, 0xdf, 0x04, 0x5b, 0x8a, 0xca, 0xe4, 0x86, 0x95, + 0x17, 0xd8, 0x0e, 0x50, 0x61, 0x5d, 0x90, 0x35, 0xd5, + 0xd9, 0xc5, 0xa4, 0x0a, 0xf6, 0x02, 0x28, 0x0b, 0x54, + 0x25, 0x97, 0xb0, 0xcb, 0x18, 0x61, 0x9e, 0xeb, 0x35, + 0x92, 0x57, 0x59, 0xd1, 0x95, 0xe1, 0x00, 0xe8, 0xe4, + 0xaa, 0x0c, 0x38, 0xa3, 0xc2, 0xab, 0xe0, 0xf3, 0xd8, + 0xff, 0x04, 0xf3, 0xc3, 0x3c, 0x29, 0x50, 0x69, 0xc2, + 0x36, 0x94, 0xb5, 0xbb, 0xea, 0xcd, 0xd5, 0x42, 0xe2, + 0x8e, 0x8a, 0x94, 0xed, 0xb9, 0x11, 0x9f, 0x41, 0x2d, + 0x05, 0x4b, 0xe1, 0xfa, 0x72, 0xb0, 0x95, 0x50 }; + uint8_t ct[] = { 0x35, 0x1e, 0x30, 0xd4, 0xd9, 0x10, 0xc5, + 0xdd, 0x5a, 0xd7, 0x83, 0x4c, 0x42, 0x6e, 0x6c, 0x0c, + 0xab, 0x64, 0x86, 0xda, 0x7b, 0x0f, 0xda, 0x4c, 0xd8, + 0x3a, 0xf1, 0xb9, 0x64, 0x71, 0x37, 0xf1, 0xac, 0x43, + 0xb4, 0x34, 0x22, 0x3b, 0x19, 0xbe, 0x07, 0xbd, 0x89, + 0xd1, 0xcc, 0x30, 0x69, 0x44, 0xd3, 0x36, 0x1e, 0xa1, + 0xa2, 0xf8, 0xcd, 0xbd, 0x32, 0x16, 0x55, 0x97, 0x63, + 0x50, 0xd0, 0x0b, 0x80, 0xdd, 0x83, 0x81, 0x20, 0xa7, + 0x75, 0x5c, 0x6d, 0xea, 0x2a, 0xb2, 0xb0, 0xc9, 0x9a, + 0x91, 0x3f, 0x47, 0xda, 0xe2, 0xb8, 0xde, 0xb9, 0xa8, + 0x29, 0xe5, 0x46, 0x9f, 0xf2, 0xe1, 0x87, 0x77, 0x6f, + 0x6f, 0xd0, 0x81, 0xe3, 0x87, 0x1d, 0x11, 0x9a, 0x76, + 0xe2, 0x4c, 0x91, 0x7e, 0xa6, 0x26, 0x48, 0xe0, 0x2e, + 0x90, 0x36, 0x75, 0x64, 0xde, 0x72, 0xae, 0x7e, 0x4f, + 0x0a, 0x42, 0x49, 0xa9, 0xa5, 0xb0, 0xe4, 0x65, 0xa2, + 0xd6, 0xd9, 0xdc, 0x87, 0x84, 0x3b, 0x1b, 0x87, 0x5c, + 0xc9, 0xa3, 0xbe, 0x93, 0xd8, 0xda, 0x8f, 0x56, 0xec, + 0xaf, 0x59, 0x81, 0xfe, 0x93, 0xc2, 0x84, 0x31, 0x8b, + 0x0d, 0xec, 0x7a, 0x3b, 0xa1, 0x08, 0xe2, 0xcb, 0x1a, + 0x61, 0xe9, 0x66, 0xfa, 0x7a, 0xfa, 0x7a, 0xc7, 0xf6, + 0x7f, 0x65, 0xbc, 0x4a, 0x2d, 0xf0, 0x70, 0xd4, 0xe4, + 0x34, 0x84, 0x5f, 0x10, 0x9a, 0xb2, 0xb6, 0x8a, 0xde, + 0x3d, 0xc3, 0x16, 0xca, 0x63, 0x32, 0xa6, 0x28, 0x93, + 0xe0, 0xa7, 0xec, 0x0b, 0x4f, 0xc2, 0x51, 0x91, 0xbf, + 0x2f, 0xf1, 0xb9, 0xf9, 0x81, 0x5e, 0x4b, 0xa8, 0xa9, + 0x9c, 0x64, 0x3b, 0x52, 0x18, 0x04, 0xf7, 0xd5, 0x85, + 0x0d, 0xde, 0x39, 0x52, 0x20, 0x6e, 0xc6, 0xcc, 0xf3, + 0x40, 0xf9, 0xb3, 0x22, 0x0b, 0x30, 0x23, 0xbd, 0xd0, + 0x63, 0x95, 0x6e, 0xa8, 0x33, 0x39, 0x20, 0xfd, 0xe9, + 0x9e, 0x06, 0x75, 0x41, 0x0e, 0x49, 0xef, 0x3b, 0x4d, + 0x3f, 0xb3, 0xdf, 0x51, 0x92, 0xf9, 0x9c, 0xa8, 0x3d, + 0x3b, 0x00, 0x32, 0xde, 0x08, 0xc2, 0x20, 0x77, 0x6a, + 0x58, 0x65, 0xb0, 0xe4, 0xb3, 0xb0, 0xc7, 0x5d, 0xef, + 0xe7, 0x76, 0x2d, 0xff, 0x01, 0x8e, 0xa7, 0xf5, 0xbe, + 0x2b, 0x2f, 0x97, 0x2b, 0x2a, 0x8b, 0xa5, 0x97, 0x0e, + 0x43, 0xbd, 0x6f, 0xdd, 0x63, 0xda, 0xe6, 0x29, 0x78, + 0x4e, 0xc4, 0x8d, 0x61, 0x00, 0x54, 0xee, 0x4e, 0x4b, + 0x5d, 0xbb, 0xf1, 0xfc, 0x2f, 0xa0, 0xb8, 0x30, 0xe9, + 0x4d, 0xcb, 0xb7, 0x01, 0x4e, 0x8a, 0xb4, 0x29, 0xab, + 0x10, 0x0f, 0xc4, 0x8f, 0x83, 0x17, 0x1d, 0x99, 0xfc, + 0x25, 0x8b, 0x7c, 0x2b, 0xa7, 0xc1, 0x76, 0xea, 0xea, + 0xad, 0x37, 0xf8, 0x60, 0xd5, 0x97, 0xa3, 0x1c, 0xe7, + 0x9b, 0x59, 0x47, 0x33, 0xc7, 0x14, 0x1d, 0xf7, 0x91, + 0x51, 0xfc, 0xa9, 0x0c, 0x08, 0x47, 0x8a, 0x5c, 0x6c, + 0x2c, 0xc4, 0x81, 0xd5, 0x1f, 0xfe, 0xce, 0x3c, 0xd7, + 0xd2, 0x58, 0x13, 0x48, 0x82, 0x7a, 0x71, 0xf0, 0x91, + 0x42, 0x8e, 0xbe, 0x38, 0xc9, 0x5a, 0x3f, 0x5c, 0x63, + 0xe0, 0x56, 0xdf, 0xb7, 0xcc, 0x45, 0xa9, 0xb7, 0xc0, + 0x7d, 0x83, 0x4e, 0x7b, 0x20, 0xb9, 0x9e, 0xd2, 0x02, + 0x42, 0x9c, 0x14, 0xbb, 0x85, 0xff, 0xa4, 0x3b, 0x7c, + 0xb6, 0x84, 0x95, 0xcd, 0x75, 0xab, 0x66, 0xd9, 0x64, + 0xd4, 0xca, 0xfe, 0x64, 0xdd, 0x94, 0x04, 0xda, 0xe2, + 0xdc, 0x51, 0x10, 0x61, 0x7f, 0x19, 0x4f, 0xc3, 0xc1, + 0x84, 0xf5, 0x83, 0xcd, 0x0d, 0xef, 0x6d, 0x00 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +// set len_bitsgth to multiple of 8 respectively 128 +void test_set_1_block_size() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 256, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0x5d, 0x5b, 0xfe, 0x75, 0xeb, 0x04, 0xf6, + 0x8c, 0xe0, 0xa1, 0x23, 0x77, 0xea, 0x00, 0xb3, 0x7d, + 0x47, 0xc6, 0xa0, 0xba, 0x06, 0x30, 0x91, 0x55, 0x08, + 0x6a, 0x85, 0x9c, 0x43, 0x41, 0xb3, 0x7c }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +// inserted bit flip in msg[0] +void test_set_1_invalid() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 253, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x99, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0x5d, 0x5b, 0xfe, 0x75, 0xeb, 0x04, 0xf6, + 0x8c, 0xe0, 0xa1, 0x23, 0x77, 0xea, 0x00, 0xb3, 0x7d, + 0x47, 0xc6, 0xa0, 0xba, 0x06, 0x30, 0x91, 0x55, 0x08, + 0x6a, 0x85, 0x9c, 0x43, 0x41, 0xb3, 0x78 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp != 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp != 0); + + free(out); +} + +/* + * Functions + */ + +int main(int argc, char * argv[]) { + test_set_1(); + test_set_2(); + test_set_3(); + test_set_4(); + test_set_5(); + test_set_6(); + test_set_1_block_size(); + test_set_1_invalid(); +} diff --git a/lib/test/common/test_eea2.cc b/lib/test/common/test_eea2.cc new file mode 100644 index 000000000..fccaefe70 --- /dev/null +++ b/lib/test/common/test_eea2.cc @@ -0,0 +1,567 @@ +/* + * Includes + */ + +#include +#include +#include + +#include "srslte/common/liblte_security.h" + +/* + * Prototypes + */ + +int32 arrcmp(uint8_t const * const a, uint8_t const * const b, uint32 len) { + uint32 i = 0; + + for (i = 0; i < len; i++) { + if (a[i] != b[i]) { + return a[i] - b[i]; + } + } + return 0; +} + +/* + * Tests + * + * Document Reference: 33.401 V13.1.0 Annex C.1 + */ + +void test_set_1() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 253, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0xe9, 0xfe, 0xd8, 0xa6, 0x3d, 0x15, 0x53, + 0x04, 0xd7, 0x1d, 0xf2, 0x0b, 0xf3, 0xe8, 0x22, 0x14, + 0xb2, 0x0e, 0xd7, 0xda, 0xd2, 0xf2, 0x33, 0xdc, 0x3c, + 0x22, 0xd7, 0xbd, 0xee, 0xed, 0x8e, 0x78 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_2() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x2b, 0xd6, 0x45, 0x9f, 0x82, 0xc4, 0x40, + 0xe0, 0x95, 0x2c, 0x49, 0x10, 0x48, 0x05, 0xff, 0x48 }; + uint32_t count = 0xc675a64b; + uint8_t bearer = 0x0c; + uint8_t direction = 1; + uint32_t len_bits = 798, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x7e, 0xc6, 0x12, 0x72, 0x74, 0x3b, 0xf1, + 0x61, 0x47, 0x26, 0x44, 0x6a, 0x6c, 0x38, 0xce, 0xd1, + 0x66, 0xf6, 0xca, 0x76, 0xeb, 0x54, 0x30, 0x04, 0x42, + 0x86, 0x34, 0x6c, 0xef, 0x13, 0x0f, 0x92, 0x92, 0x2b, + 0x03, 0x45, 0x0d, 0x3a, 0x99, 0x75, 0xe5, 0xbd, 0x2e, + 0xa0, 0xeb, 0x55, 0xad, 0x8e, 0x1b, 0x19, 0x9e, 0x3e, + 0xc4, 0x31, 0x60, 0x20, 0xe9, 0xa1, 0xb2, 0x85, 0xe7, + 0x62, 0x79, 0x53, 0x59, 0xb7, 0xbd, 0xfd, 0x39, 0xbe, + 0xf4, 0xb2, 0x48, 0x45, 0x83, 0xd5, 0xaf, 0xe0, 0x82, + 0xae, 0xe6, 0x38, 0xbf, 0x5f, 0xd5, 0xa6, 0x06, 0x19, + 0x39, 0x01, 0xa0, 0x8f, 0x4a, 0xb4, 0x1a, 0xab, 0x9b, + 0x13, 0x48, 0x80 }; + uint8_t ct[] = { 0x59, 0x61, 0x60, 0x53, 0x53, 0xc6, 0x4b, + 0xdc, 0xa1, 0x5b, 0x19, 0x5e, 0x28, 0x85, 0x53, 0xa9, + 0x10, 0x63, 0x25, 0x06, 0xd6, 0x20, 0x0a, 0xa7, 0x90, + 0xc4, 0xc8, 0x06, 0xc9, 0x99, 0x04, 0xcf, 0x24, 0x45, + 0xcc, 0x50, 0xbb, 0x1c, 0xf1, 0x68, 0xa4, 0x96, 0x73, + 0x73, 0x4e, 0x08, 0x1b, 0x57, 0xe3, 0x24, 0xce, 0x52, + 0x59, 0xc0, 0xe7, 0x8d, 0x4c, 0xd9, 0x7b, 0x87, 0x09, + 0x76, 0x50, 0x3c, 0x09, 0x43, 0xf2, 0xcb, 0x5a, 0xe8, + 0xf0, 0x52, 0xc7, 0xb7, 0xd3, 0x92, 0x23, 0x95, 0x87, + 0xb8, 0x95, 0x60, 0x86, 0xbc, 0xab, 0x18, 0x83, 0x60, + 0x42, 0xe2, 0xe6, 0xce, 0x42, 0x43, 0x2a, 0x17, 0x10, + 0x5c, 0x53, 0xd0 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_3() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x0a, 0x8b, 0x6b, 0xd8, 0xd9, 0xb0, 0x8b, + 0x08, 0xd6, 0x4e, 0x32, 0xd1, 0x81, 0x77, 0x77, 0xfb }; + uint32_t count = 0x544d49cd; + uint8_t bearer = 0x04; + uint8_t direction = 0; + uint32_t len_bits = 310, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0xfd, 0x40, 0xa4, 0x1d, 0x37, 0x0a, 0x1f, + 0x65, 0x74, 0x50, 0x95, 0x68, 0x7d, 0x47, 0xba, 0x1d, + 0x36, 0xd2, 0x34, 0x9e, 0x23, 0xf6, 0x44, 0x39, 0x2c, + 0x8e, 0xa9, 0xc4, 0x9d, 0x40, 0xc1, 0x32, 0x71, 0xaf, + 0xf2, 0x64, 0xd0, 0xf2, 0x48, 0x00 }; + uint8_t ct[] = { 0x75, 0x75, 0x0d, 0x37, 0xb4, 0xbb, 0xa2, + 0xa4, 0xde, 0xdb, 0x34, 0x23, 0x5b, 0xd6, 0x8c, 0x66, + 0x45, 0xac, 0xda, 0xac, 0xa4, 0x81, 0x38, 0xa3, 0xb0, + 0xc4, 0x71, 0xe2, 0xa7, 0x04, 0x1a, 0x57, 0x64, 0x23, + 0xd2, 0x92, 0x72, 0x87, 0xf0, 0x00 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_4() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xaa, 0x1f, 0x95, 0xae, 0xa5, 0x33, 0xbc, + 0xb3, 0x2e, 0xb6, 0x3b, 0xf5, 0x2d, 0x8f, 0x83, 0x1a }; + uint32_t count = 0x72d8c671; + uint8_t bearer = 0x10; + uint8_t direction = 1; + uint32_t len_bits = 1022, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0xfb, 0x1b, 0x96, 0xc5, 0xc8, 0xba, 0xdf, + 0xb2, 0xe8, 0xe8, 0xed, 0xfd, 0xe7, 0x8e, 0x57, 0xf2, + 0xad, 0x81, 0xe7, 0x41, 0x03, 0xfc, 0x43, 0x0a, 0x53, + 0x4d, 0xcc, 0x37, 0xaf, 0xce, 0xc7, 0x0e, 0x15, 0x17, + 0xbb, 0x06, 0xf2, 0x72, 0x19, 0xda, 0xe4, 0x90, 0x22, + 0xdd, 0xc4, 0x7a, 0x06, 0x8d, 0xe4, 0xc9, 0x49, 0x6a, + 0x95, 0x1a, 0x6b, 0x09, 0xed, 0xbd, 0xc8, 0x64, 0xc7, + 0xad, 0xbd, 0x74, 0x0a, 0xc5, 0x0c, 0x02, 0x2f, 0x30, + 0x82, 0xba, 0xfd, 0x22, 0xd7, 0x81, 0x97, 0xc5, 0xd5, + 0x08, 0xb9, 0x77, 0xbc, 0xa1, 0x3f, 0x32, 0xe6, 0x52, + 0xe7, 0x4b, 0xa7, 0x28, 0x57, 0x60, 0x77, 0xce, 0x62, + 0x8c, 0x53, 0x5e, 0x87, 0xdc, 0x60, 0x77, 0xba, 0x07, + 0xd2, 0x90, 0x68, 0x59, 0x0c, 0x8c, 0xb5, 0xf1, 0x08, + 0x8e, 0x08, 0x2c, 0xfa, 0x0e, 0xc9, 0x61, 0x30, 0x2d, + 0x69, 0xcf, 0x3d, 0x44 }; + uint8_t ct[] = { 0xdf, 0xb4, 0x40, 0xac, 0xb3, 0x77, 0x35, + 0x49, 0xef, 0xc0, 0x46, 0x28, 0xae, 0xb8, 0xd8, 0x15, + 0x62, 0x75, 0x23, 0x0b, 0xdc, 0x69, 0x0d, 0x94, 0xb0, + 0x0d, 0x8d, 0x95, 0xf2, 0x8c, 0x4b, 0x56, 0x30, 0x7f, + 0x60, 0xf4, 0xca, 0x55, 0xeb, 0xa6, 0x61, 0xeb, 0xba, + 0x72, 0xac, 0x80, 0x8f, 0xa8, 0xc4, 0x9e, 0x26, 0x78, + 0x8e, 0xd0, 0x4a, 0x5d, 0x60, 0x6c, 0xb4, 0x18, 0xde, + 0x74, 0x87, 0x8b, 0x9a, 0x22, 0xf8, 0xef, 0x29, 0x59, + 0x0b, 0xc4, 0xeb, 0x57, 0xc9, 0xfa, 0xf7, 0xc4, 0x15, + 0x24, 0xa8, 0x85, 0xb8, 0x97, 0x9c, 0x42, 0x3f, 0x2f, + 0x8f, 0x8e, 0x05, 0x92, 0xa9, 0x87, 0x92, 0x01, 0xbe, + 0x7f, 0xf9, 0x77, 0x7a, 0x16, 0x2a, 0xb8, 0x10, 0xfe, + 0xb3, 0x24, 0xba, 0x74, 0xc4, 0xc1, 0x56, 0xe0, 0x4d, + 0x39, 0x09, 0x72, 0x09, 0x65, 0x3a, 0xc3, 0x3e, 0x5a, + 0x5f, 0x2d, 0x88, 0x64 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_5() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x96, 0x18, 0xae, 0x46, 0x89, 0x1f, 0x86, + 0x57, 0x8e, 0xeb, 0xe9, 0x0e, 0xf7, 0xa1, 0x20, 0x2e }; + uint32_t count = 0xc675a64b; + uint8_t bearer = 0x0c; + uint8_t direction = 1; + uint32_t len_bits = 1245, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x8d, 0xaa, 0x17, 0xb1, 0xae, 0x05, 0x05, + 0x29, 0xc6, 0x82, 0x7f, 0x28, 0xc0, 0xef, 0x6a, 0x12, + 0x42, 0xe9, 0x3f, 0x8b, 0x31, 0x4f, 0xb1, 0x8a, 0x77, + 0xf7, 0x90, 0xae, 0x04, 0x9f, 0xed, 0xd6, 0x12, 0x26, + 0x7f, 0xec, 0xae, 0xfc, 0x45, 0x01, 0x74, 0xd7, 0x6d, + 0x9f, 0x9a, 0xa7, 0x75, 0x5a, 0x30, 0xcd, 0x90, 0xa9, + 0xa5, 0x87, 0x4b, 0xf4, 0x8e, 0xaf, 0x70, 0xee, 0xa3, + 0xa6, 0x2a, 0x25, 0x0a, 0x8b, 0x6b, 0xd8, 0xd9, 0xb0, + 0x8b, 0x08, 0xd6, 0x4e, 0x32, 0xd1, 0x81, 0x77, 0x77, + 0xfb, 0x54, 0x4d, 0x49, 0xcd, 0x49, 0x72, 0x0e, 0x21, + 0x9d, 0xbf, 0x8b, 0xbe, 0xd3, 0x39, 0x04, 0xe1, 0xfd, + 0x40, 0xa4, 0x1d, 0x37, 0x0a, 0x1f, 0x65, 0x74, 0x50, + 0x95, 0x68, 0x7d, 0x47, 0xba, 0x1d, 0x36, 0xd2, 0x34, + 0x9e, 0x23, 0xf6, 0x44, 0x39, 0x2c, 0x8e, 0xa9, 0xc4, + 0x9d, 0x40, 0xc1, 0x32, 0x71, 0xaf, 0xf2, 0x64, 0xd0, + 0xf2, 0x48, 0x41, 0xd6, 0x46, 0x5f, 0x09, 0x96, 0xff, + 0x84, 0xe6, 0x5f, 0xc5, 0x17, 0xc5, 0x3e, 0xfc, 0x33, + 0x63, 0xc3, 0x84, 0x92, 0xa8 }; + uint8_t ct[] = { 0x91, 0x9c, 0x8c, 0x33, 0xd6, 0x67, 0x89, + 0x70, 0x3d, 0x05, 0xa0, 0xd7, 0xce, 0x82, 0xa2, 0xae, + 0xac, 0x4e, 0xe7, 0x6c, 0x0f, 0x4d, 0xa0, 0x50, 0x33, + 0x5e, 0x8a, 0x84, 0xe7, 0x89, 0x7b, 0xa5, 0xdf, 0x2f, + 0x36, 0xbd, 0x51, 0x3e, 0x3d, 0x0c, 0x85, 0x78, 0xc7, + 0xa0, 0xfc, 0xf0, 0x43, 0xe0, 0x3a, 0xa3, 0xa3, 0x9f, + 0xba, 0xad, 0x7d, 0x15, 0xbe, 0x07, 0x4f, 0xaa, 0x5d, + 0x90, 0x29, 0xf7, 0x1f, 0xb4, 0x57, 0xb6, 0x47, 0x83, + 0x47, 0x14, 0xb0, 0xe1, 0x8f, 0x11, 0x7f, 0xca, 0x10, + 0x67, 0x79, 0x45, 0x09, 0x6c, 0x8c, 0x5f, 0x32, 0x6b, + 0xa8, 0xd6, 0x09, 0x5e, 0xb2, 0x9c, 0x3e, 0x36, 0xcf, + 0x24, 0x5d, 0x16, 0x22, 0xaa, 0xfe, 0x92, 0x1f, 0x75, + 0x66, 0xc4, 0xf5, 0xd6, 0x44, 0xf2, 0xf1, 0xfc, 0x0e, + 0xc6, 0x84, 0xdd, 0xb2, 0x13, 0x49, 0x74, 0x76, 0x22, + 0xe2, 0x09, 0x29, 0x5d, 0x27, 0xff, 0x3f, 0x95, 0x62, + 0x33, 0x71, 0xd4, 0x9b, 0x14, 0x7c, 0x0a, 0xf4, 0x86, + 0x17, 0x1f, 0x22, 0xcd, 0x04, 0xb1, 0xcb, 0xeb, 0x26, + 0x58, 0x22, 0x3e, 0x69, 0x38 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_6() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x54, 0xf4, 0xe2, 0xe0, 0x4c, 0x83, 0x78, + 0x6e, 0xec, 0x8f, 0xb5, 0xab, 0xe8, 0xe3, 0x65, 0x66 }; + uint32_t count = 0xaca4f50f; + uint8_t bearer = 0x0b; + uint8_t direction = 0; + uint32_t len_bits = 3861, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x40, 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, + 0xfb, 0x42, 0x86, 0xb2, 0x99, 0x78, 0x3d, 0xaf, 0x44, + 0x2c, 0x09, 0x9f, 0x7a, 0xb0, 0xf5, 0x8d, 0x5c, 0x8e, + 0x46, 0xb1, 0x04, 0xf0, 0x8f, 0x01, 0xb4, 0x1a, 0xb4, + 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x36, 0xbd, 0x1a, + 0x3d, 0x90, 0xdc, 0x3a, 0x41, 0xb4, 0x6d, 0x51, 0x67, + 0x2a, 0xc4, 0xc9, 0x66, 0x3a, 0x2b, 0xe0, 0x63, 0xda, + 0x4b, 0xc8, 0xd2, 0x80, 0x8c, 0xe3, 0x3e, 0x2c, 0xcc, + 0xbf, 0xc6, 0x34, 0xe1, 0xb2, 0x59, 0x06, 0x08, 0x76, + 0xa0, 0xfb, 0xb5, 0xa4, 0x37, 0xeb, 0xcc, 0x8d, 0x31, + 0xc1, 0x9e, 0x44, 0x54, 0x31, 0x87, 0x45, 0xe3, 0xfa, + 0x16, 0xbb, 0x11, 0xad, 0xae, 0x24, 0x88, 0x79, 0xfe, + 0x52, 0xdb, 0x25, 0x43, 0xe5, 0x3c, 0xf4, 0x45, 0xd3, + 0xd8, 0x28, 0xce, 0x0b, 0xf5, 0xc5, 0x60, 0x59, 0x3d, + 0x97, 0x27, 0x8a, 0x59, 0x76, 0x2d, 0xd0, 0xc2, 0xc9, + 0xcd, 0x68, 0xd4, 0x49, 0x6a, 0x79, 0x25, 0x08, 0x61, + 0x40, 0x14, 0xb1, 0x3b, 0x6a, 0xa5, 0x11, 0x28, 0xc1, + 0x8c, 0xd6, 0xa9, 0x0b, 0x87, 0x97, 0x8c, 0x2f, 0xf1, + 0xca, 0xbe, 0x7d, 0x9f, 0x89, 0x8a, 0x41, 0x1b, 0xfd, + 0xb8, 0x4f, 0x68, 0xf6, 0x72, 0x7b, 0x14, 0x99, 0xcd, + 0xd3, 0x0d, 0xf0, 0x44, 0x3a, 0xb4, 0xa6, 0x66, 0x53, + 0x33, 0x0b, 0xcb, 0xa1, 0x10, 0x5e, 0x4c, 0xec, 0x03, + 0x4c, 0x73, 0xe6, 0x05, 0xb4, 0x31, 0x0e, 0xaa, 0xad, + 0xcf, 0xd5, 0xb0, 0xca, 0x27, 0xff, 0xd8, 0x9d, 0x14, + 0x4d, 0xf4, 0x79, 0x27, 0x59, 0x42, 0x7c, 0x9c, 0xc1, + 0xf8, 0xcd, 0x8c, 0x87, 0x20, 0x23, 0x64, 0xb8, 0xa6, + 0x87, 0x95, 0x4c, 0xb0, 0x5a, 0x8d, 0x4e, 0x2d, 0x99, + 0xe7, 0x3d, 0xb1, 0x60, 0xde, 0xb1, 0x80, 0xad, 0x08, + 0x41, 0xe9, 0x67, 0x41, 0xa5, 0xd5, 0x9f, 0xe4, 0x18, + 0x9f, 0x15, 0x42, 0x00, 0x26, 0xfe, 0x4c, 0xd1, 0x21, + 0x04, 0x93, 0x2f, 0xb3, 0x8f, 0x73, 0x53, 0x40, 0x43, + 0x8a, 0xaf, 0x7e, 0xca, 0x6f, 0xd5, 0xcf, 0xd3, 0xa1, + 0x95, 0xce, 0x5a, 0xbe, 0x65, 0x27, 0x2a, 0xf6, 0x07, + 0xad, 0xa1, 0xbe, 0x65, 0xa6, 0xb4, 0xc9, 0xc0, 0x69, + 0x32, 0x34, 0x09, 0x2c, 0x4d, 0x01, 0x8f, 0x17, 0x56, + 0xc6, 0xdb, 0x9d, 0xc8, 0xa6, 0xd8, 0x0b, 0x88, 0x81, + 0x38, 0x61, 0x6b, 0x68, 0x12, 0x62, 0xf9, 0x54, 0xd0, + 0xe7, 0x71, 0x17, 0x48, 0x78, 0x0d, 0x92, 0x29, 0x1d, + 0x86, 0x29, 0x99, 0x72, 0xdb, 0x74, 0x1c, 0xfa, 0x4f, + 0x37, 0xb8, 0xb5, 0x6c, 0xdb, 0x18, 0xa7, 0xca, 0x82, + 0x18, 0xe8, 0x6e, 0x4b, 0x4b, 0x71, 0x6a, 0x4d, 0x04, + 0x37, 0x1f, 0xbe, 0xc2, 0x62, 0xfc, 0x5a, 0xd0, 0xb3, + 0x81, 0x9b, 0x18, 0x7b, 0x97, 0xe5, 0x5b, 0x1a, 0x4d, + 0x7c, 0x19, 0xee, 0x24, 0xc8, 0xb4, 0xd7, 0x72, 0x3c, + 0xfe, 0xdf, 0x04, 0x5b, 0x8a, 0xca, 0xe4, 0x86, 0x95, + 0x17, 0xd8, 0x0e, 0x50, 0x61, 0x5d, 0x90, 0x35, 0xd5, + 0xd9, 0xc5, 0xa4, 0x0a, 0xf6, 0x02, 0x28, 0x0b, 0x54, + 0x25, 0x97, 0xb0, 0xcb, 0x18, 0x61, 0x9e, 0xeb, 0x35, + 0x92, 0x57, 0x59, 0xd1, 0x95, 0xe1, 0x00, 0xe8, 0xe4, + 0xaa, 0x0c, 0x38, 0xa3, 0xc2, 0xab, 0xe0, 0xf3, 0xd8, + 0xff, 0x04, 0xf3, 0xc3, 0x3c, 0x29, 0x50, 0x69, 0xc2, + 0x36, 0x94, 0xb5, 0xbb, 0xea, 0xcd, 0xd5, 0x42, 0xe2, + 0x8e, 0x8a, 0x94, 0xed, 0xb9, 0x11, 0x9f, 0x41, 0x2d, + 0x05, 0x4b, 0xe1, 0xfa, 0x72, 0x00, 0xb0, 0x90, 0x00 }; + uint8_t ct[] = { 0x5c, 0xb7, 0x2c, 0x6e, 0xdc, 0x87, 0x8f, + 0x15, 0x66, 0xe1, 0x02, 0x53, 0xaf, 0xc3, 0x64, 0xc9, + 0xfa, 0x54, 0x0d, 0x91, 0x4d, 0xb9, 0x4c, 0xbe, 0xe2, + 0x75, 0xd0, 0x91, 0x7c, 0xa6, 0xaf, 0x0d, 0x77, 0xac, + 0xb4, 0xef, 0x3b, 0xbe, 0x1a, 0x72, 0x2b, 0x2e, 0xf5, + 0xbd, 0x1d, 0x4b, 0x8e, 0x2a, 0xa5, 0x02, 0x4e, 0xc1, + 0x38, 0x8a, 0x20, 0x1e, 0x7b, 0xce, 0x79, 0x20, 0xae, + 0xc6, 0x15, 0x89, 0x5f, 0x76, 0x3a, 0x55, 0x64, 0xdc, + 0xc4, 0xc4, 0x82, 0xa2, 0xee, 0x1d, 0x8b, 0xfe, 0xcc, + 0x44, 0x98, 0xec, 0xa8, 0x3f, 0xbb, 0x75, 0xf9, 0xab, + 0x53, 0x0e, 0x0d, 0xaf, 0xbe, 0xde, 0x2f, 0xa5, 0x89, + 0x5b, 0x82, 0x99, 0x1b, 0x62, 0x77, 0xc5, 0x29, 0xe0, + 0xf2, 0x52, 0x9d, 0x7f, 0x79, 0x60, 0x6b, 0xe9, 0x67, + 0x06, 0x29, 0x6d, 0xed, 0xfa, 0x9d, 0x74, 0x12, 0xb6, + 0x16, 0x95, 0x8c, 0xb5, 0x63, 0xc6, 0x78, 0xc0, 0x28, + 0x25, 0xc3, 0x0d, 0x0a, 0xee, 0x77, 0xc4, 0xc1, 0x46, + 0xd2, 0x76, 0x54, 0x12, 0x42, 0x1a, 0x80, 0x8d, 0x13, + 0xce, 0xc8, 0x19, 0x69, 0x4c, 0x75, 0xad, 0x57, 0x2e, + 0x9b, 0x97, 0x3d, 0x94, 0x8b, 0x81, 0xa9, 0x33, 0x7c, + 0x3b, 0x2a, 0x17, 0x19, 0x2e, 0x22, 0xc2, 0x06, 0x9f, + 0x7e, 0xd1, 0x16, 0x2a, 0xf4, 0x4c, 0xde, 0xa8, 0x17, + 0x60, 0x36, 0x65, 0xe8, 0x07, 0xce, 0x40, 0xc8, 0xe0, + 0xdd, 0x9d, 0x63, 0x94, 0xdc, 0x6e, 0x31, 0x15, 0x3f, + 0xe1, 0x95, 0x5c, 0x47, 0xaf, 0xb5, 0x1f, 0x26, 0x17, + 0xee, 0x0c, 0x5e, 0x3b, 0x8e, 0xf1, 0xad, 0x75, 0x74, + 0xed, 0x34, 0x3e, 0xdc, 0x27, 0x43, 0xcc, 0x94, 0xc9, + 0x90, 0xe1, 0xf1, 0xfd, 0x26, 0x42, 0x53, 0xc1, 0x78, + 0xde, 0xa7, 0x39, 0xc0, 0xbe, 0xfe, 0xeb, 0xcd, 0x9f, + 0x9b, 0x76, 0xd4, 0x9c, 0x10, 0x15, 0xc9, 0xfe, 0xcf, + 0x50, 0xe5, 0x3b, 0x8b, 0x52, 0x04, 0xdb, 0xcd, 0x3e, + 0xed, 0x86, 0x38, 0x55, 0xda, 0xbc, 0xdc, 0xc9, 0x4b, + 0x31, 0xe3, 0x18, 0x02, 0x15, 0x68, 0x85, 0x5c, 0x8b, + 0x9e, 0x52, 0xa9, 0x81, 0x95, 0x7a, 0x11, 0x28, 0x27, + 0xf9, 0x78, 0xba, 0x96, 0x0f, 0x14, 0x47, 0x91, 0x1b, + 0x31, 0x7b, 0x55, 0x11, 0xfb, 0xcc, 0x7f, 0xb1, 0x3a, + 0xc1, 0x53, 0xdb, 0x74, 0x25, 0x11, 0x17, 0xe4, 0x86, + 0x1e, 0xb9, 0xe8, 0x3b, 0xff, 0xff, 0xc4, 0xeb, 0x77, + 0x55, 0x57, 0x90, 0x38, 0xe5, 0x79, 0x24, 0xb1, 0xf7, + 0x8b, 0x3e, 0x1a, 0xd9, 0x0b, 0xab, 0x2a, 0x07, 0x87, + 0x1b, 0x72, 0xdb, 0x5e, 0xef, 0x96, 0xc3, 0x34, 0x04, + 0x49, 0x66, 0xdb, 0x0c, 0x37, 0xca, 0xfd, 0x1a, 0x89, + 0xe5, 0x64, 0x6a, 0x35, 0x80, 0xeb, 0x64, 0x65, 0xf1, + 0x21, 0xdc, 0xe9, 0xcb, 0x88, 0xd8, 0x5b, 0x96, 0xcf, + 0x23, 0xcc, 0xcc, 0xd4, 0x28, 0x07, 0x67, 0xbe, 0xe8, + 0xee, 0xb2, 0x3d, 0x86, 0x52, 0x46, 0x1d, 0xb6, 0x49, + 0x31, 0x03, 0x00, 0x3b, 0xaf, 0x89, 0xf5, 0xe1, 0x82, + 0x61, 0xea, 0x43, 0xc8, 0x4a, 0x92, 0xeb, 0xff, 0xff, + 0xe4, 0x90, 0x9d, 0xc4, 0x6c, 0x51, 0x92, 0xf8, 0x25, + 0xf7, 0x70, 0x60, 0x0b, 0x96, 0x02, 0xc5, 0x57, 0xb5, + 0xf8, 0xb4, 0x31, 0xa7, 0x9d, 0x45, 0x97, 0x7d, 0xd9, + 0xc4, 0x1b, 0x86, 0x3d, 0xa9, 0xe1, 0x42, 0xe9, 0x00, + 0x20, 0xcf, 0xd0, 0x74, 0xd6, 0x92, 0x7b, 0x7a, 0xb3, + 0xb6, 0x72, 0x5d, 0x1a, 0x6f, 0x3f, 0x98, 0xb9, 0xc9, + 0xda, 0xa8, 0x98, 0x2a, 0xff, 0x06, 0x78, 0x28, 0x00 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +// set len_bitsgth to multiple of 8 respectively 128 +void test_set_1_block_size() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 256, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0xe9, 0xfe, 0xd8, 0xa6, 0x3d, 0x15, 0x53, + 0x04, 0xd7, 0x1d, 0xf2, 0x0b, 0xf3, 0xe8, 0x22, 0x14, + 0xb2, 0x0e, 0xd7, 0xda, 0xd2, 0xf2, 0x33, 0xdc, 0x3c, + 0x22, 0xd7, 0xbd, 0xee, 0xed, 0x8e, 0x78 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +// inserted bit flip in msg[0] +void test_set_1_invalid() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 253, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x99, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0xe9, 0xfe, 0xd8, 0xa6, 0x3d, 0x15, 0x53, + 0x04, 0xd7, 0x1d, 0xf2, 0x0b, 0xf3, 0xe8, 0x22, 0x14, + 0xb2, 0x0e, 0xd7, 0xda, 0xd2, 0xf2, 0x33, 0xdc, 0x3c, + 0x22, 0xd7, 0xbd, 0xee, 0xed, 0x8e, 0x78 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp != 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp != 0); + + free(out); +} + +/* + * Functions + */ + +int main(int argc, char * argv[]) { + test_set_1(); + test_set_2(); + test_set_3(); + test_set_4(); + test_set_5(); + test_set_6(); + test_set_1_block_size(); + test_set_1_invalid(); +} diff --git a/srsue/hdr/upper/nas.h b/srsue/hdr/upper/nas.h index 5ab77f28c..6038993e0 100644 --- a/srsue/hdr/upper/nas.h +++ b/srsue/hdr/upper/nas.h @@ -149,14 +149,13 @@ private: void integrity_generate(uint8_t *key_128, uint32_t count, - uint8_t rb_id, uint8_t direction, uint8_t *msg, uint32_t msg_len, uint8_t *mac); - bool integrity_check(uint32 lcid, byte_buffer_t *pdu); - void cipher_encrypt(uint32 lcid, byte_buffer_t *pdu); - void cipher_decrypt(uint32 lcid, byte_buffer_t *pdu); + bool integrity_check(byte_buffer_t *pdu); + void cipher_encrypt(byte_buffer_t *pdu); + void cipher_decrypt(byte_buffer_t *pdu); bool check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *caps); diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 99e237ba2..3886fd5b4 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -206,8 +206,8 @@ void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY: break; case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED: - mac_valid = integrity_check(lcid, pdu); - cipher_decrypt(lcid, pdu); + mac_valid = integrity_check(pdu); + cipher_decrypt(pdu); break; case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT: break; @@ -305,7 +305,6 @@ void nas::start_pcap(srslte::nas_pcap *pcap_) void nas::integrity_generate(uint8_t *key_128, uint32_t count, - uint8_t rb_id, uint8_t direction, uint8_t *msg, uint32_t msg_len, @@ -316,7 +315,7 @@ void nas::integrity_generate(uint8_t *key_128, case INTEGRITY_ALGORITHM_ID_128_EIA1: security_128_eia1(key_128, count, - rb_id, + 0, // Bearer always 0 for NAS direction, msg, msg_len, @@ -325,7 +324,7 @@ void nas::integrity_generate(uint8_t *key_128, case INTEGRITY_ALGORITHM_ID_128_EIA2: security_128_eia2(key_128, count, - rb_id, + 0, // Bearer always 0 for NAS direction, msg, msg_len, @@ -339,16 +338,14 @@ void nas::integrity_generate(uint8_t *key_128, // This function depends to a valid k_nas_int. // This key is generated in the security mode command. -bool nas::integrity_check(uint32 lcid, - byte_buffer_t *pdu) +bool nas::integrity_check(byte_buffer_t *pdu) { - uint8_t exp_mac[4]; uint8_t *mac = &pdu->msg[1]; int i; + integrity_generate(&k_nas_int[16], ctxt.rx_count, - lcid-1, SECURITY_DIRECTION_DOWNLINK, &pdu->msg[5], pdu->N_bytes-5, @@ -357,16 +354,19 @@ bool nas::integrity_check(uint32 lcid, // Check if expected mac equals the sent mac for(i=0; i<4; i++){ if(exp_mac[i] != mac[i]){ - nas_log->warning("Expected MAC [%02x %02x %02x %02x] does not match sent MAC [%02x %02x %02x %02x]\n", exp_mac[0], exp_mac[1], exp_mac[2], exp_mac[3], mac[0], mac[1], mac[2], mac[3]); + nas_log->warning("Integrity check failure. Local: count=%d, [%02x %02x %02x %02x], " + "Received: count=%d, [%02x %02x %02x %02x]\n", + ctxt.rx_count, exp_mac[0], exp_mac[1], exp_mac[2], exp_mac[3], + pdu->msg[5], mac[0], mac[1], mac[2], mac[3]); return false; } } - nas_log->info("Expected MAC [%02x %02x %02x %02x] equals sent MAC [%02x %02x %02x %02x]\n", exp_mac[0], exp_mac[1], exp_mac[2], exp_mac[3], mac[0], mac[1], mac[2], mac[3]); + nas_log->info("Integrity check ok. Local: count=%d, Received: count=%d\n", + ctxt.rx_count, pdu->msg[5]); return true; } -void nas::cipher_encrypt(uint32 lcid, - byte_buffer_t *pdu) +void nas::cipher_encrypt(byte_buffer_t *pdu) { byte_buffer_t pdu_tmp; switch(ctxt.cipher_algo) @@ -376,7 +376,7 @@ void nas::cipher_encrypt(uint32 lcid, case CIPHERING_ALGORITHM_ID_128_EEA1: security_128_eea1(&k_nas_enc[16], pdu->msg[5], - lcid-1, + 0, // Bearer always 0 for NAS SECURITY_DIRECTION_UPLINK, &pdu->msg[6], pdu->N_bytes-6, @@ -386,7 +386,7 @@ void nas::cipher_encrypt(uint32 lcid, case CIPHERING_ALGORITHM_ID_128_EEA2: security_128_eea2(&k_nas_enc[16], pdu->msg[5], - lcid-1, + 0, // Bearer always 0 for NAS SECURITY_DIRECTION_UPLINK, &pdu->msg[6], pdu->N_bytes-6, @@ -399,8 +399,7 @@ void nas::cipher_encrypt(uint32 lcid, } } -void nas::cipher_decrypt(uint32 lcid, - byte_buffer_t *pdu) +void nas::cipher_decrypt(byte_buffer_t *pdu) { byte_buffer_t tmp_pdu; switch(ctxt.cipher_algo) @@ -410,7 +409,7 @@ void nas::cipher_decrypt(uint32 lcid, case CIPHERING_ALGORITHM_ID_128_EEA1: security_128_eea1(&k_nas_enc[16], pdu->msg[5], - lcid-1, + 0, // Bearer always 0 for NAS SECURITY_DIRECTION_DOWNLINK, &pdu->msg[6], pdu->N_bytes-6, @@ -420,7 +419,7 @@ void nas::cipher_decrypt(uint32 lcid, case CIPHERING_ALGORITHM_ID_128_EEA2: security_128_eea2(&k_nas_enc[16], pdu->msg[5], - lcid-1, + 0, // Bearer always 0 for NAS SECURITY_DIRECTION_DOWNLINK, &pdu->msg[6], pdu->N_bytes-6, @@ -549,10 +548,9 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { pcap->write_nas(pdu->msg, pdu->N_bytes); } - cipher_encrypt(lcid, pdu); + cipher_encrypt(pdu); integrity_generate(&k_nas_int[16], ctxt.tx_count, - lcid - 1, SECURITY_DIRECTION_UPLINK, &pdu->msg[5], pdu->N_bytes - 5, @@ -726,7 +724,7 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) nas_log->debug("Generating integrity check. integ_algo:%d, count_dl:%d, lcid:%d\n", ctxt.integ_algo, ctxt.rx_count, lcid); - if (integrity_check(lcid, pdu) != true) { + if (integrity_check(pdu) != true) { nas_log->warning("Sending Security Mode Reject due to integrity check failure\n"); send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_MAC_FAILURE); pool->deallocate(pdu); @@ -757,10 +755,9 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) if(pcap != NULL) { pcap->write_nas(sdu->msg, sdu->N_bytes); } - cipher_encrypt(lcid, sdu); + cipher_encrypt(sdu); integrity_generate(&k_nas_int[16], ctxt.tx_count, - lcid - 1, SECURITY_DIRECTION_UPLINK, &sdu->msg[5], sdu->N_bytes - 5, @@ -846,7 +843,6 @@ void nas::send_attach_request() { // Add MAC integrity_generate(&k_nas_int[16], ctxt.tx_count, - cfg.lcid-1, SECURITY_DIRECTION_UPLINK, &msg->msg[5], msg->N_bytes - 5, @@ -919,7 +915,6 @@ void nas::send_service_request() { uint8_t mac[4]; integrity_generate(&k_nas_int[16], ctxt.tx_count, - cfg.lcid-1, SECURITY_DIRECTION_UPLINK, &msg->msg[0], 2, From c0e79477b59a33151e260145f66611ac8167ea37 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 1 Dec 2017 14:05:54 +0100 Subject: [PATCH 15/42] Fixed cell reselection when radio-link failure --- lib/include/srslte/common/timers.h | 5 ++- lib/include/srslte/common/tti_sync.h | 2 + lib/include/srslte/common/tti_sync_cv.h | 3 +- lib/src/common/tti_sync_cv.cc | 7 +++ srsue/hdr/mac/dl_harq.h | 2 +- srsue/hdr/upper/rrc.h | 5 +-- srsue/src/mac/mac.cc | 5 +-- srsue/src/main.cc | 2 +- srsue/src/phy/phch_common.cc | 3 -- srsue/src/phy/phch_recv.cc | 9 ++-- srsue/src/phy/phch_worker.cc | 9 ++-- srsue/src/upper/rrc.cc | 58 +++++++++++++------------ 12 files changed, 61 insertions(+), 49 deletions(-) diff --git a/lib/include/srslte/common/timers.h b/lib/include/srslte/common/timers.h index a8563af37..d77692d5a 100644 --- a/lib/include/srslte/common/timers.h +++ b/lib/include/srslte/common/timers.h @@ -64,7 +64,7 @@ public: return (counter < timeout) && running; } bool is_expired() { - return callback && (counter >= timeout || !running); + return (timeout > 0) && (counter >= timeout || !running); } uint32_t get_timeout() { return timeout; @@ -72,6 +72,9 @@ public: void reset() { counter = 0; } + uint32_t value() { + return counter; + } void step() { if (running) { counter++; diff --git a/lib/include/srslte/common/tti_sync.h b/lib/include/srslte/common/tti_sync.h index 23061ea2d..fd62f442b 100644 --- a/lib/include/srslte/common/tti_sync.h +++ b/lib/include/srslte/common/tti_sync.h @@ -50,6 +50,7 @@ class tti_sync init_counters(0); } virtual void increase() = 0; + virtual void increase(uint32_t cnt) = 0; virtual void resync() = 0; virtual uint32_t wait() = 0; virtual void set_producer_cntr(uint32_t) = 0; @@ -60,6 +61,7 @@ class tti_sync } protected: void increase_producer() { producer_cntr = (producer_cntr + increment)%modulus; } + void increase_producer(uint32_t cnt) { producer_cntr = cnt%modulus; } void increase_consumer() { consumer_cntr = (consumer_cntr + increment)%modulus; } bool wait_condition() { return producer_cntr == consumer_cntr; } void init_counters(uint32_t val) diff --git a/lib/include/srslte/common/tti_sync_cv.h b/lib/include/srslte/common/tti_sync_cv.h index c04fa71f0..887ac4f04 100644 --- a/lib/include/srslte/common/tti_sync_cv.h +++ b/lib/include/srslte/common/tti_sync_cv.h @@ -44,7 +44,8 @@ class tti_sync_cv : public tti_sync tti_sync_cv(uint32_t modulus = 10240); ~tti_sync_cv(); void increase(); - uint32_t wait(); + void increase(uint32_t cnt); + uint32_t wait(); void resync(); void set_producer_cntr(uint32_t producer_cntr); diff --git a/lib/src/common/tti_sync_cv.cc b/lib/src/common/tti_sync_cv.cc index a3fc7ce4b..c48f0772a 100644 --- a/lib/src/common/tti_sync_cv.cc +++ b/lib/src/common/tti_sync_cv.cc @@ -75,4 +75,11 @@ namespace srslte { pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); } + void tti_sync_cv::increase(uint32_t tti) + { + pthread_mutex_lock(&mutex); + increase_producer(tti); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + } } diff --git a/srsue/hdr/mac/dl_harq.h b/srsue/hdr/mac/dl_harq.h index 521018d73..46c3fb0d0 100644 --- a/srsue/hdr/mac/dl_harq.h +++ b/srsue/hdr/mac/dl_harq.h @@ -259,7 +259,7 @@ private: memcpy(&cur_grant, &grant, sizeof(Tgrant)); // If data has not yet been successfully decoded - if (!ack || (grant.rv[tid]==0 && grant.phy_grant.dl.mcs[tid].idx < 29)) { + if (!ack) { // Instruct the PHY To combine the received data and attempt to decode it if (pid == HARQ_BCCH_PID) { diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index a1e3fbb5f..f587cc0ff 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -149,12 +149,11 @@ private: uint8_t transaction_id; bool drb_up; - bool paging_received; - rrc_args_t args; bool first_stimsi_attempt; bool reestablishment_in_progress; + bool connection_requested; bool pending_mob_reconf; LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT mob_reconf; @@ -186,8 +185,6 @@ private: // RRC constants and timers srslte::mac_interface_timers *mac_timers; - uint32_t sync_reset_cnt; - const static uint32_t SYNC_RESET_TIMEOUT = 10; uint32_t n310_cnt, N310; uint32_t n311_cnt, N311; uint32_t t301, t310, t311, t304; diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc index 42d7c4b96..8813032f5 100644 --- a/srsue/src/mac/mac.cc +++ b/srsue/src/mac/mac.cc @@ -162,8 +162,7 @@ void mac::run_thread() { while(started) { /* Warning: Here order of invocation of procedures is important!! */ - ttisync.wait(); - tti = phy_h->get_current_tti(); + tti = ttisync.wait(); log_h->step(tti); timers.step_all(); @@ -229,7 +228,7 @@ void mac::pcch_stop_rx() void mac::tti_clock(uint32_t tti) { - ttisync.increase(); + ttisync.increase(tti); } void mac::bch_decoded_ok(uint8_t* payload, uint32_t len) diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 9fa5e55ae..978e08dd4 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -233,7 +233,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { ("expert.cfo_loop_pss_conv", - bpo::value(&args->expert.phy.cfo_loop_pss_conv)->default_value(50), + bpo::value(&args->expert.phy.cfo_loop_pss_conv)->default_value(20), "After the PSS estimation is below cfo_loop_pss_tol for cfo_loop_pss_timeout times consecutively, RS adjustments are allowed.") ("expert.average_subframe_enabled", diff --git a/srsue/src/phy/phch_common.cc b/srsue/src/phy/phch_common.cc index 961080a56..39a23e43d 100644 --- a/srsue/src/phy/phch_common.cc +++ b/srsue/src/phy/phch_common.cc @@ -257,9 +257,6 @@ void phch_common::worker_end(uint32_t tti, bool tx_enable, } // Trigger next transmission pthread_mutex_unlock(&tx_mutex[(tti+1)%nof_mutex]); - - // Trigger MAC clock - mac->tti_clock(tti); } diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index dc056f9c0..5fe63ccd4 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -596,10 +596,12 @@ void phch_recv::run_thread() } break; case sfn_sync::TIMEOUT: - if (phy_state == CELL_SELECT) { + if (cell_search_in_progress) { + log_h->warning("SYNC: Timeout while synchronizing SFN. Going back to cell search\n"); phy_state = CELL_SEARCH; } else { - phy_state = IDLE; + log_h->warning("SYNC: Timeout while synchronizing SFN. Reselecting cell\n"); + resync_sfn(true, true); } break; case sfn_sync::IDLE: @@ -706,8 +708,8 @@ void phch_recv::run_thread() } // Increase TTI counter and trigger MAC clock (lower priority) - tti = (tti+1) % 10240; mac->tti_clock(tti); + tti = (tti+1) % 10240; } } @@ -973,7 +975,6 @@ phch_recv::sfn_sync::ret_code phch_recv::sfn_sync::run_subframe(srslte_cell_t *c cnt++; if (cnt >= timeout) { cnt = 0; - log_h->warning("SYNC: Timeout while synchronizing SFN\n"); return TIMEOUT; } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index bf5000ecf..47ca680af 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -230,14 +230,15 @@ void phch_worker::work_imp() /* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */ bool chest_ok = extract_fft_and_pdcch_llr(); - bool snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>-20.0; + bool snr_th_err = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))<-20.0; + bool snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>-15.0; // Call feedback loop for chest if (chest_loop && ((1<<(tti%10)) & phy->args->cfo_ref_mask)) { chest_loop->set_cfo(srslte_chest_dl_get_cfo(&ue_dl.chest)); } - if (chest_ok && snr_th_ok) { + if (chest_ok && !snr_th_err) { /***** Downlink Processing *******/ @@ -267,7 +268,7 @@ void phch_worker::work_imp() } } } - Debug("dl_ack={%d, %d}, generate_ack=%d\n", dl_ack[0], dl_ack[1], dl_action.generate_ack); + Info("dl_ack={%d, %d}, generate_ack=%d\n", dl_ack[0], dl_ack[1], dl_action.generate_ack); if (dl_action.generate_ack) { set_uci_ack(dl_ack, dl_mac_grant.tb_en); } @@ -393,7 +394,7 @@ void phch_worker::work_imp() if (snr_th_ok) { phy->rrc->in_sync(); log_h->debug("SYNC: Sending in-sync to RRC\n"); - } else { + } else if (snr_th_err) { phy->rrc->out_of_sync(); log_h->info("SNR=%.1f dB under threshold. Sending out-of-sync to RRC\n", 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))); diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 6e73670f7..3d46f2fdb 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -49,7 +49,6 @@ rrc::rrc() ,drb_up(false) ,sysinfo_index(0) { - sync_reset_cnt = 0; n310_cnt = 0; n311_cnt = 0; } @@ -98,6 +97,7 @@ void rrc::init(phy_interface_rrc *phy_, first_stimsi_attempt = false; reestablishment_in_progress = false; + connection_requested = false; args.ue_category = SRSLTE_UE_CATEGORY; args.supported_bands[0] = 7; @@ -216,28 +216,31 @@ void rrc::run_thread() { state = RRC_STATE_CELL_SELECTED; } } - select_cell_timeout++; - if (select_cell_timeout >= RRC_SELECT_CELL_TIMEOUT) { - rrc_log->info("RRC Cell Selecting: timeout expired. Starting Cell Search...\n"); - state = RRC_STATE_PLMN_SELECTION; - plmn_select_timeout = 0; - phy->cell_search_start(); + if (!reestablishment_in_progress) { + select_cell_timeout++; + if (select_cell_timeout >= RRC_SELECT_CELL_TIMEOUT) { + rrc_log->info("RRC Cell Selecting: timeout expired. Starting Cell Search...\n"); + state = RRC_STATE_PLMN_SELECTION; + plmn_select_timeout = 0; + phy->cell_search_start(); + } } break; case RRC_STATE_CELL_SELECTED: - if (!nas->is_attached() || paging_received) { - paging_received = false; - rrc_log->info("RRC Cell Selected: Sending connection request...\n"); - send_con_request(); - state = RRC_STATE_CONNECTING; - connecting_timeout = 0; - } else if (reestablishment_in_progress) { + + if (mac_timers->timer_get(t311)->is_running()) { rrc_log->info("RRC Cell Selected: Sending connection reestablishment...\n"); con_restablish_cell_reselected(); state = RRC_STATE_CONNECTING; connecting_timeout = 0; + } else if (connection_requested) { + rrc_log->info("RRC Cell Selected: Sending connection request...\n"); + send_con_request(); + state = RRC_STATE_CONNECTING; + connecting_timeout = 0; + connection_requested = false; } else { - rrc_log->console("RRC Cell Selected: New PCI=%d\n", current_cell->phy_cell.id); + rrc_log->info("RRC Cell Selected: Starting paging and going to IDLE...\n"); mac->pcch_start_rx(); state = RRC_STATE_IDLE; } @@ -426,6 +429,7 @@ void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { rrc_log->info("Already camping on selected PLMN, connecting...\n"); state = RRC_STATE_CELL_SELECTING; select_cell_timeout = 0; + connection_requested = true; } else { rrc_log->info("PLMN Id=%s selected\n", plmn_id_to_string(plmn_id).c_str()); // Sort cells according to RSRP @@ -434,6 +438,7 @@ void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { last_selected_cell = -1; select_cell_timeout = 0; + connection_requested = true; state = RRC_STATE_CELL_SELECTING; select_next_cell_in_plmn(); } @@ -499,7 +504,7 @@ void rrc::new_phy_meas(float rsrp, float rsrq, uint32_t tti, uint32_t earfcn, ui // Verify cell selection criteria if (cell_selection_eval(known_cells[best_cell_idx].rsrp) && - known_cells[best_cell_idx].rsrp > current_cell->rsrp + 5 && + known_cells[best_cell_idx].rsrp > current_cell->rsrp + 5 && best_cell.id != phy->get_current_pci()) { rrc_log->info("Selecting best neighbour cell PCI=%d, rsrp=%.1f dBm\n", best_cell.id, known_cells[best_cell_idx].rsrp); @@ -674,12 +679,6 @@ float rrc::get_squal(float Qqualmeas) { // Detection of physical layer problems (5.3.11.1) void rrc::out_of_sync() { // attempt resync - sync_reset_cnt++; - if (sync_reset_cnt >= SYNC_RESET_TIMEOUT) { - rrc_log->info("Detected %d out-of-sync from PHY. Resynchronizing PHY.\n", sync_reset_cnt); - phy->sync_reset(); - sync_reset_cnt = 0; - } current_cell->in_sync = false; if (!mac_timers->timer_get(t311)->is_running() && !mac_timers->timer_get(t310)->is_running()) { n310_cnt++; @@ -748,8 +747,12 @@ void rrc::timer_expired(uint32_t timeout_id) { rrc_log->info("Timer T311 expired: Going to RRC IDLE\n"); state = RRC_STATE_LEAVE_CONNECTED; } else if (timeout_id == t301) { - rrc_log->info("Timer T301 expired: Going to RRC IDLE\n"); - state = RRC_STATE_LEAVE_CONNECTED; + if (state == RRC_STATE_IDLE) { + rrc_log->info("Timer T301 expired: Already in IDLE.\n"); + } else { + rrc_log->info("Timer T301 expired: Going to RRC IDLE\n"); + state = RRC_STATE_LEAVE_CONNECTED; + } } else if (timeout_id == t304) { rrc_log->console("Timer T304 expired: Handover failed\n"); // fw to measurement @@ -873,6 +876,7 @@ void rrc::send_con_restablish_request() { set_phy_default(); mac->reset(); set_mac_default(); + state = RRC_STATE_CELL_SELECTING; } // Actions following cell reselection 5.3.7.3 @@ -890,7 +894,7 @@ void rrc::con_restablish_cell_reselected() bit_buf.msg[bit_buf.N_bits + i] = 0; bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); } - byte_buffer_t *pdcp_buf = pool_allocate;; + byte_buffer_t *pdcp_buf = pool_allocate; srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); pdcp_buf->N_bytes = bit_buf.N_bits / 8; @@ -1296,8 +1300,8 @@ void rrc::write_pdu_pcch(byte_buffer_t *pdu) { mac->pcch_stop_rx(); if (RRC_STATE_IDLE == state) { rrc_log->info("RRC in IDLE state - sending connection request.\n"); - paging_received = true; - state = RRC_STATE_CELL_SELECTING; + send_con_request(); + state = RRC_STATE_CONNECTING; } } } From c69d4a37e8838913df3bd0c06d19a7f069f033ca Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 1 Dec 2017 17:00:30 +0100 Subject: [PATCH 16/42] Implemented proper cell reselection. Tested reestablishment from one cell to another. --- srsue/hdr/upper/rrc.h | 6 ++-- srsue/src/phy/phch_recv.cc | 27 +++++++++------- srsue/src/phy/phch_worker.cc | 2 +- srsue/src/upper/nas.cc | 6 +++- srsue/src/upper/rrc.cc | 62 ++++++++++++++++++++++++------------ 5 files changed, 66 insertions(+), 37 deletions(-) diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index f587cc0ff..085bf6b88 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -152,9 +152,6 @@ private: rrc_args_t args; bool first_stimsi_attempt; - bool reestablishment_in_progress; - bool connection_requested; - bool pending_mob_reconf; LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT mob_reconf; @@ -367,7 +364,8 @@ private: void cell_reselection_eval(float rsrp, float rsrq); bool cell_selection_eval(float rsrp, float rsrq = 0); - + bool connection_requested; + void plmn_select_rrc(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id); // RLC interface void max_retx_attempted(); diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 5fe63ccd4..941f7d025 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -301,16 +301,17 @@ void phch_recv::cell_search_inc() { cur_earfcn_index++; if (cur_earfcn_index >= 0) { - if (cur_earfcn_index >= (int) earfcn.size() - 1) { + if (cur_earfcn_index >= (int) earfcn.size()) { cur_earfcn_index = 0; rrc->earfcn_end(); + } else { + Info("SYNC: Cell Search idx %d/%d\n", cur_earfcn_index, earfcn.size()); + if (current_earfcn != earfcn[cur_earfcn_index]) { + current_earfcn = earfcn[cur_earfcn_index]; + set_frequency(); + } } } - Info("SYNC: Cell Search idx %d/%d\n", cur_earfcn_index, earfcn.size()); - if (current_earfcn != earfcn[cur_earfcn_index]) { - current_earfcn = earfcn[cur_earfcn_index]; - set_frequency(); - } } void phch_recv::cell_search_next(bool reset) { @@ -329,12 +330,16 @@ void phch_recv::cell_search_next(bool reset) { } void phch_recv::cell_search_start() { - if (earfcn.size() > 0) { - Info("SYNC: Starting Cell Search procedure in %d EARFCNs...\n", earfcn.size()); - cell_search_next(true); + if (phy_state == CELL_CAMP) { + Warning("SYNC: Can't start cell search procedure while camping on cell\n"); } else { - Info("SYNC: Empty EARFCN list. Stopping cell search...\n"); - log_h->console("Empty EARFCN list. Stopping cell search...\n"); + if (earfcn.size() > 0) { + Info("SYNC: Starting Cell Search procedure in %d EARFCNs...\n", earfcn.size()); + cell_search_next(true); + } else { + Info("SYNC: Empty EARFCN list. Stopping cell search...\n"); + log_h->console("Empty EARFCN list. Stopping cell search...\n"); + } } } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 47ca680af..edd5f268c 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -268,7 +268,7 @@ void phch_worker::work_imp() } } } - Info("dl_ack={%d, %d}, generate_ack=%d\n", dl_ack[0], dl_ack[1], dl_action.generate_ack); + Debug("dl_ack={%d, %d}, generate_ack=%d\n", dl_ack[0], dl_ack[1], dl_action.generate_ack); if (dl_action.generate_ack) { set_uci_ack(dl_ack, dl_mac_grant.tb_en); } diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 62e23d852..c53ef35a3 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -108,7 +108,6 @@ void nas::attach_request() { } else if (state == EMM_STATE_REGISTERED) { nas_log->info("NAS state is registered, connecting to same PLMN\n"); rrc->plmn_select(current_plmn); - selecting_plmn = current_plmn; } else { nas_log->info("Attach request ignored. State = %s\n", emm_state_text[state]); } @@ -125,6 +124,11 @@ void nas::deattach_request() { void nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) { + // Do not process new PLMN if already selected + if (plmn_selection == PLMN_SELECTED) { + return; + } + // Check if already registered for (uint32_t i=0;iis_attaching()) { sleep(1); rrc_log->info("RRC IDLE: NAS is attaching and camping on cell, reselecting...\n"); - plmn_select(selected_plmn_id); + plmn_select_rrc(selected_plmn_id); } // If not camping on a cell } else { // If NAS is attached, perform cell reselection on current PLMN if (nas->is_attached()) { rrc_log->info("RRC IDLE: NAS is attached, PHY not synchronized. Re-selecting cell...\n"); - plmn_select(selected_plmn_id); + plmn_select_rrc(selected_plmn_id); } else if (nas->is_attaching()) { sleep(1); rrc_log->info("RRC IDLE: NAS is attaching, searching again PLMN\n"); @@ -204,6 +202,10 @@ void rrc::run_thread() { } break; case RRC_STATE_CELL_SELECTING: + + /* During cell selection, apply SIB configurations if available or receive them if not. + * Cell is selected when all SIBs downloaded or applied. + */ if (phy->sync_status()) { if (!current_cell->has_valid_sib1) { si_acquire_state = SI_ACQUIRE_SIB1; @@ -216,29 +218,36 @@ void rrc::run_thread() { state = RRC_STATE_CELL_SELECTED; } } - if (!reestablishment_in_progress) { + // Don't time out during restablishment (T311 running) + if (!mac_timers->timer_get(t311)->is_running()) { select_cell_timeout++; if (select_cell_timeout >= RRC_SELECT_CELL_TIMEOUT) { rrc_log->info("RRC Cell Selecting: timeout expired. Starting Cell Search...\n"); - state = RRC_STATE_PLMN_SELECTION; plmn_select_timeout = 0; + select_cell_timeout = 0; phy->cell_search_start(); } } break; case RRC_STATE_CELL_SELECTED: + /* The cell is selected when the SIBs are received and applied. + * If we were in RRC_CONNECTED and arrive here it means a RLF occurred and we are in Reestablishment procedure. + * If T311 is running means there is a reestablishment in progress, send ConnectionReestablishmentRequest. + * If not, do a ConnectionRequest if NAS is established or go to IDLE an camp on cell otherwise. + */ if (mac_timers->timer_get(t311)->is_running()) { + // rrc_log->info("RRC Cell Selected: Sending connection reestablishment...\n"); con_restablish_cell_reselected(); state = RRC_STATE_CONNECTING; connecting_timeout = 0; } else if (connection_requested) { + connection_requested = false; rrc_log->info("RRC Cell Selected: Sending connection request...\n"); send_con_request(); state = RRC_STATE_CONNECTING; connecting_timeout = 0; - connection_requested = false; } else { rrc_log->info("RRC Cell Selected: Starting paging and going to IDLE...\n"); mac->pcch_start_rx(); @@ -265,9 +274,9 @@ void rrc::run_thread() { break; case RRC_STATE_LEAVE_CONNECTED: usleep(60000); + rrc_log->console("RRC IDLE\n"); rrc_log->info("Leaving RRC_CONNECTED state\n"); drb_up = false; - reestablishment_in_progress = false; measurements.reset(); pdcp->reset(); rlc->reset(); @@ -275,12 +284,14 @@ void rrc::run_thread() { mac->reset(); set_phy_default(); set_mac_default(); - mac->pcch_start_rx(); mac_timers->timer_get(t310)->stop(); mac_timers->timer_get(t311)->stop(); - - // Instruct PHY to measure serving cell for cell reselection - phy->meas_start(phy->get_current_earfcn(), phy->get_current_pci()); + if (phy->sync_status()) { + // Instruct MAC to look for P-RNTI + mac->pcch_start_rx(); + // Instruct PHY to measure serving cell for cell reselection + phy->meas_start(phy->get_current_earfcn(), phy->get_current_pci()); + } // Move to RRC_IDLE state = RRC_STATE_IDLE; @@ -421,15 +432,24 @@ void rrc::plmn_search() { plmn_select_timeout = 0; } +/* This is the NAS interface. When NAS requests to select a PLMN we have to + * connect to either register or because there is pending higher layer traffic. + */ void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { + connection_requested = true; + plmn_select_rrc(plmn_id); +} +/* This is called by RRC only. In this case, we do not want to connect, just camp on the + * selected PLMN + */ +void rrc::plmn_select_rrc(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { // If already camping on the selected PLMN, select this cell if (state == RRC_STATE_IDLE || state == RRC_STATE_CONNECTED || state == RRC_STATE_PLMN_SELECTION) { if (phy->sync_status() && selected_plmn_id.mcc == plmn_id.mcc && selected_plmn_id.mnc == plmn_id.mnc) { rrc_log->info("Already camping on selected PLMN, connecting...\n"); state = RRC_STATE_CELL_SELECTING; select_cell_timeout = 0; - connection_requested = true; } else { rrc_log->info("PLMN Id=%s selected\n", plmn_id_to_string(plmn_id).c_str()); // Sort cells according to RSRP @@ -438,7 +458,6 @@ void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { last_selected_cell = -1; select_cell_timeout = 0; - connection_requested = true; state = RRC_STATE_CELL_SELECTING; select_next_cell_in_plmn(); } @@ -477,7 +496,8 @@ void rrc::select_next_cell_in_plmn() { } } } - rrc_log->info("No more known cells...\n"); + rrc_log->info("No more known cells. Starting again\n"); + last_selected_cell = -1; } void rrc::new_phy_meas(float rsrp, float rsrq, uint32_t tti, uint32_t earfcn, uint32_t pci) { @@ -603,11 +623,15 @@ rrc::cell_t* rrc::add_new_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rs // 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]); + rrc_log->info("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(); + } else if (state == RRC_STATE_CELL_SELECTING) { + select_cell_timeout = 0; + rrc_log->info("Starting cell search again\n"); + phy->cell_search_start(); } } @@ -631,7 +655,7 @@ void rrc::cell_reselection_eval(float rsrp, float rsrq) { // Intra-frequency cell-reselection criteria - if (get_srxlev(rsrp) > cell_resel_cfg.s_intrasearchP && rsrp > -80.0) { + if (get_srxlev(rsrp) > cell_resel_cfg.s_intrasearchP && rsrp > -70.0) { // UE may not perform intra-frequency measurements. phy->meas_reset(); // keep measuring serving cell @@ -864,8 +888,6 @@ void rrc::send_con_restablish_request() { ul_ccch_msg.msg.rrc_con_reest_req.cause = LIBLTE_RRC_CON_REEST_REQ_CAUSE_OTHER_FAILURE; liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - reestablishment_in_progress = true; - rrc_log->info("Initiating RRC Connection Reestablishment Procedure\n"); rrc_log->console("RRC Connection Reestablishment\n"); mac_timers->timer_get(t310)->stop(); @@ -882,7 +904,6 @@ void rrc::send_con_restablish_request() { // Actions following cell reselection 5.3.7.3 void rrc::con_restablish_cell_reselected() { - reestablishment_in_progress = false; rrc_log->info("Cell Selection finished. Initiating transmission of RRC Connection Reestablishment Request\n"); mac_timers->timer_get(t301)->reset(); mac_timers->timer_get(t301)->run(); @@ -1218,6 +1239,7 @@ void rrc::handle_sib2() rrc_log->info("SIB2 received\n"); apply_sib2_configs(¤t_cell->sib2); + } void rrc::handle_sib3() From 8f39a622fea6414fa3a4d49f60bfc9373f92cbfc Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 1 Dec 2017 19:50:42 +0100 Subject: [PATCH 17/42] Added cancelation of self interference of PSS and SSS signals --- lib/src/phy/ch_estimation/chest_dl.c | 4 +- lib/src/phy/sync/sync.c | 2 +- srsue/hdr/phy/phch_common.h | 1 + srsue/hdr/phy/phch_recv.h | 2 + srsue/src/phy/phch_common.cc | 1 - srsue/src/phy/phch_recv.cc | 60 ++++++++++++++++++++++++---- srsue/src/phy/phch_worker.cc | 1 + srsue/src/phy/phy.cc | 1 + srsue/src/upper/rrc.cc | 6 +-- 9 files changed, 63 insertions(+), 15 deletions(-) diff --git a/lib/src/phy/ch_estimation/chest_dl.c b/lib/src/phy/ch_estimation/chest_dl.c index cdd1af7f8..35122958d 100644 --- a/lib/src/phy/ch_estimation/chest_dl.c +++ b/lib/src/phy/ch_estimation/chest_dl.c @@ -434,10 +434,10 @@ float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id) uint32_t l; float rssi = 0; - uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id); + uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id); for (l=0;lcell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE]; - rssi += srslte_vec_dot_prod_conj_ccc(tmp, tmp, q->cell.nof_prb * SRSLTE_NRE); + rssi += srslte_vec_dot_prod_conj_ccc(tmp, tmp, q->cell.nof_prb * SRSLTE_NRE); } return rssi/nsymbols; } diff --git a/lib/src/phy/sync/sync.c b/lib/src/phy/sync/sync.c index ac29bac21..a74be30d6 100644 --- a/lib/src/phy/sync/sync.c +++ b/lib/src/phy/sync/sync.c @@ -620,7 +620,7 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin } - // If there is enough space for CP and PSS-based CFO estimation + // If there is enough space for CP and SSS estimation if (peak_pos + find_offset >= 2 * (q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { // If SSS search is enabled, correlate SSS sequence diff --git a/srsue/hdr/phy/phch_common.h b/srsue/hdr/phy/phch_common.h index d7b960ea5..fd73d9421 100644 --- a/srsue/hdr/phy/phch_common.h +++ b/srsue/hdr/phy/phch_common.h @@ -46,6 +46,7 @@ namespace srsue { class chest_feedback_itf { public: + virtual void out_of_sync() = 0; virtual void set_cfo(float cfo) = 0; }; diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/phch_recv.h index 8bc310bf5..e6ef981d1 100644 --- a/srsue/hdr/phy/phch_recv.h +++ b/srsue/hdr/phy/phch_recv.h @@ -75,6 +75,7 @@ public: bool status_is_sync(); // from chest_feedback_itf + void out_of_sync(); void set_cfo(float cfo); void set_time_adv_sec(float time_adv_sec); @@ -319,6 +320,7 @@ private: bool cell_search_in_progress; uint32_t out_of_sync_cnt; + uint32_t out_of_sync2_cnt; float dl_freq; float ul_freq; diff --git a/srsue/src/phy/phch_common.cc b/srsue/src/phy/phch_common.cc index 39a23e43d..2a7044acd 100644 --- a/srsue/src/phy/phch_common.cc +++ b/srsue/src/phy/phch_common.cc @@ -257,7 +257,6 @@ void phch_common::worker_end(uint32_t tti, bool tx_enable, } // Trigger next transmission pthread_mutex_unlock(&tx_mutex[(tti+1)%nof_mutex]); - } diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 941f7d025..17ac71c54 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -549,6 +549,9 @@ void phch_recv::run_thread() phy_state = IDLE; is_in_idle = true; + uint32_t hf_len; + uint32_t fft_sz; + while (running) { if (phy_state != IDLE) { @@ -677,6 +680,24 @@ void phch_recv::run_thread() } workers_pool->start_worker(worker); + // Substract PSS/SSS from current cell before computing intrafrequency + hf_len = SRSLTE_SF_LEN_PRB(cell.nof_prb)/2; + fft_sz = srslte_symbol_sz(cell.nof_prb); + + if ((tti%5) == 0) { + srslte_vec_sc_prod_cfc(ue_sync.strack.pss_filt, 1.0/sqrtf(fft_sz), ue_sync.strack.pss_filt, fft_sz); + srslte_vec_sc_prod_cfc(ue_sync.strack.sss_filt, 1.0/sqrtf(fft_sz), ue_sync.strack.pss_filt, fft_sz); + + srslte_vec_sub_ccc(&buffer[0][hf_len-fft_sz], + ue_sync.strack.pss_filt, + &buffer[0][hf_len-fft_sz], + fft_sz); + + srslte_vec_sub_ccc(&buffer[0][hf_len-2*fft_sz-SRSLTE_CP_LEN(fft_sz, SRSLTE_CP_NORM_LEN)], + ue_sync.strack.sss_filt, + &buffer[0][hf_len-2*fft_sz-SRSLTE_CP_LEN(fft_sz, SRSLTE_CP_NORM_LEN)], + fft_sz); + } intra_freq_meas.write(tti, buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb)); out_of_sync_cnt = 0; break; @@ -718,7 +739,15 @@ void phch_recv::run_thread() } } - +void phch_recv::out_of_sync() { + out_of_sync2_cnt++; + Info("SYNC: Received out_of_sync from channel estimator (%d)\n", out_of_sync2_cnt); + if (out_of_sync2_cnt >= 2) { + out_of_sync2_cnt = 0; + Info("SYNC: Trying to resync signal\n"); + resync_sfn(true, true); + } +} @@ -1068,6 +1097,7 @@ phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *in ret_code ret = IDLE; + Info("INTRA: Here offset=%d\n", offset); offset = offset-sf_len/2; if (offset < 0) { offset += sf_len; @@ -1103,6 +1133,10 @@ phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *in } } + if (found_best) { + Info("INTRA: fine-tuned offset=%d\n", best_test_offset); + } + offset = found_best?best_test_offset:offset; if (offset >= 0 && offset < sf_len*max_sf) { uint32_t nof_sf = (sf_len*max_sf - offset)/sf_len; @@ -1116,6 +1150,8 @@ phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *in return ret; } } + } else { + Info("INTRA: not running because offset=%d, sf_len*max_sf=%d*%d\n", offset, sf_len, max_sf); } return ret; } @@ -1176,18 +1212,18 @@ void phch_recv::scell_recv::init(srslte::log *log_h) measure_p.init(sf_buffer, log_h, 1, DEFAULT_MEASUREMENT_LEN); - if(srslte_sync_init(&sync_find, 5*max_sf_size, 5*max_sf_size, max_fft_sz)) { + if(srslte_sync_init(&sync_find, 15*max_sf_size, 5*max_sf_size, max_fft_sz)) { fprintf(stderr, "Error initiating sync_find\n"); return; } srslte_sync_cp_en(&sync_find, false); - srslte_sync_set_threshold(&sync_find, 1.2); + srslte_sync_set_threshold(&sync_find, 1.3); srslte_sync_set_em_alpha(&sync_find, 0.0); // Configure FIND object behaviour (this configuration is always the same) - srslte_sync_set_cfo_ema_alpha(&sync_find, 0.2); + srslte_sync_set_cfo_ema_alpha(&sync_find, 0.5); srslte_sync_set_cfo_i_enable(&sync_find, false); - srslte_sync_set_cfo_cp_enable(&sync_find, true); + srslte_sync_set_cfo_cp_enable(&sync_find, false); srslte_sync_set_cfo_pss_enable(&sync_find, true); srslte_sync_set_pss_filt_enable(&sync_find, true); srslte_sync_set_sss_filt_enable(&sync_find, true); @@ -1208,13 +1244,14 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, if (fft_sz != current_fft_sz) { if (srslte_sync_resize(&sync_find, nof_sf*sf_len, 5*sf_len, fft_sz)) { - fprintf(stderr, "Error resizing sync\n"); + fprintf(stderr, "Error resizing sync nof_sf=%d, sf_len=%d, fft_sz=%d\n", nof_sf, sf_len, fft_sz); return SRSLTE_ERROR; } current_fft_sz = fft_sz; } srslte_sync_reset(&sync_find); + srslte_sync_cfo_reset(&sync_find); int nof_cells = 0; uint32_t peak_idx = 0; @@ -1243,8 +1280,15 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, cell_id = srslte_sync_get_cell_id(&sync_find); if (cell_id != -1) { - Info("INTRA: found peak_idx=%d, n_id_2=%d, cell_id=%d, sf=%d\n", - peak_idx, n_id_2, cell_id, sf_idx); + Info("INTRA: found peak_idx=%d, n_id_2=%d, cell_id=%d, sf=%d, cfo=%.1f Hz, psr=%f\n", + peak_idx, n_id_2, cell_id, sf_idx, 15000*srslte_sync_get_cfo(&sync_find), sync_find.peak_value); + + /* + if (cell_id == 342) { + srslte_vec_save_file("input", input_buffer, 5*sf_len*sizeof(cf_t)); + srslte_vec_save_file("conv", sync_find.pss.conv_output, sync_find.pss.frame_size*sizeof(cf_t)); + exit(-1); + }*/ found_cell.id = cell_id; found_cell.nof_ports = 1; // Use port 0 only for measurement diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index edd5f268c..27503c9f7 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -395,6 +395,7 @@ void phch_worker::work_imp() phy->rrc->in_sync(); log_h->debug("SYNC: Sending in-sync to RRC\n"); } else if (snr_th_err) { + chest_loop->out_of_sync(); phy->rrc->out_of_sync(); log_h->info("SNR=%.1f dB under threshold. Sending out-of-sync to RRC\n", 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))); diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index d871c384e..689426b2a 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -334,6 +334,7 @@ void phy::reset() workers[i].reset(); } workers_common.reset(); + usleep(4000); workers_common.reset_ul(); } diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 1684f3a52..2559d3645 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -1322,8 +1322,8 @@ void rrc::write_pdu_pcch(byte_buffer_t *pdu) { mac->pcch_stop_rx(); if (RRC_STATE_IDLE == state) { rrc_log->info("RRC in IDLE state - sending connection request.\n"); - send_con_request(); - state = RRC_STATE_CONNECTING; + connection_requested = true; + state = RRC_STATE_CELL_SELECTED; } } } @@ -1386,7 +1386,7 @@ void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { send_ul_info_transfer(lcid, sdu); break; default: - rrc_log->error("SDU received from NAS while RRC state = %s", rrc_state_text[state]); + rrc_log->error("SDU received from NAS while RRC state = %s\n", rrc_state_text[state]); break; } } From 1a323770c94a0b2c94fdc239deec23b794a8e166 Mon Sep 17 00:00:00 2001 From: Paul Sutton Date: Fri, 1 Dec 2017 19:19:38 +0000 Subject: [PATCH 18/42] Added support for AS ciphering --- lib/include/srslte/common/pcap.h | 99 ++++---------- lib/include/srslte/interfaces/ue_interfaces.h | 5 +- lib/include/srslte/upper/pdcp.h | 5 +- lib/include/srslte/upper/pdcp_entity.h | 11 +- lib/src/common/mac_pcap.cc | 6 +- lib/src/common/nas_pcap.cc | 6 +- lib/src/upper/pdcp.cc | 12 +- lib/src/upper/pdcp_entity.cc | 124 +++++++++++------- srsue/src/upper/rrc.cc | 17 ++- 9 files changed, 150 insertions(+), 135 deletions(-) diff --git a/lib/include/srslte/common/pcap.h b/lib/include/srslte/common/pcap.h index 611aea72d..ce4fcf541 100644 --- a/lib/include/srslte/common/pcap.h +++ b/lib/include/srslte/common/pcap.h @@ -32,9 +32,8 @@ #include #include -#define MAC_LTE_DLT 147 -#define RRC_LTE_DLT 148 -#define NAS_LTE_DLT 149 +#define MAC_LTE_DLT 147 +#define NAS_LTE_DLT 148 /* This structure gets written to the start of the file */ @@ -74,30 +73,15 @@ typedef struct pcaprec_hdr_s { #define SPS_RNTI 5 #define M_RNTI 6 -#define MAC_LTE_START_STRING "mac-lte" - +#define MAC_LTE_START_STRING "mac-lte" +#define MAC_LTE_PAYLOAD_TAG 0x01 #define MAC_LTE_RNTI_TAG 0x02 -/* 2 bytes, network order */ - #define MAC_LTE_UEID_TAG 0x03 -/* 2 bytes, network order */ - #define MAC_LTE_FRAME_SUBFRAME_TAG 0x04 -/* 2 bytes, network order */ -/* SFN is stored in 12 MSB and SF in 4 LSB */ - #define MAC_LTE_PREDFINED_DATA_TAG 0x05 -/* 1 byte */ - #define MAC_LTE_RETX_TAG 0x06 -/* 1 byte */ - #define MAC_LTE_CRC_STATUS_TAG 0x07 -/* 1 byte */ -/* MAC PDU. Following this tag comes the actual MAC PDU (there is no length, the PDU - continues until the end of the frame) */ -#define MAC_LTE_PAYLOAD_TAG 0x01 /* Context information for every MAC PDU that will be logged */ @@ -112,7 +96,6 @@ typedef struct MAC_Context_Info_t { unsigned short sysFrameNumber; unsigned short subFrameNumber; - } MAC_Context_Info_t; /* Context information for every NAS PDU that will be logged */ @@ -121,11 +104,12 @@ typedef struct NAS_Context_Info_s { } NAS_Context_Info_t; -/**************************************************************************/ -/* API functions for opening/writing/closing MAC-LTE PCAP files */ +/************************************************************************** + * API functions for opening/closing LTE PCAP files * + **************************************************************************/ /* Open the file and write file header */ -inline FILE *MAC_LTE_PCAP_Open(const char *fileName) +inline FILE *LTE_PCAP_Open(uint32_t DLT, const char *fileName) { pcap_hdr_t file_header = { @@ -134,7 +118,7 @@ inline FILE *MAC_LTE_PCAP_Open(const char *fileName) 0, /* timezone */ 0, /* sigfigs - apparently all tools do this */ 65535, /* snaplen - this should be long enough */ - MAC_LTE_DLT /* Data Link Type (DLT). Set as unused value 147 for now */ + DLT /* Data Link Type (DLT). Set as unused value 147 for now */ }; FILE *fd = fopen(fileName, "w"); @@ -149,9 +133,21 @@ inline FILE *MAC_LTE_PCAP_Open(const char *fileName) return fd; } +/* Close the PCAP file */ +inline void LTE_PCAP_Close(FILE *fd) +{ + if(fd) + fclose(fd); +} + + +/************************************************************************** + * API functions for writing MAC-LTE PCAP files * + **************************************************************************/ + /* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */ -inline int MAC_LTE_PCAP_WritePDU(FILE *fd, MAC_Context_Info_t *context, - const unsigned char *PDU, unsigned int length) +inline int LTE_PCAP_MAC_WritePDU(FILE *fd, MAC_Context_Info_t *context, + const unsigned char *PDU, unsigned int length) { pcaprec_hdr_t packet_header; char context_header[256]; @@ -216,45 +212,15 @@ inline int MAC_LTE_PCAP_WritePDU(FILE *fd, MAC_Context_Info_t *context, return 1; } -/* Close the PCAP file */ -inline void MAC_LTE_PCAP_Close(FILE *fd) -{ - if(fd) - fclose(fd); -} - - -/**************************************************************************/ -/* API functions for opening/writing/closing NAS-LTE PCAP files */ - -/* Open the file and write file header */ -inline FILE *NAS_LTE_PCAP_Open(const char *fileName) -{ - pcap_hdr_t file_header = - { - 0xa1b2c3d4, /* magic number */ - 2, 4, /* version number is 2.4 */ - 0, /* timezone */ - 0, /* sigfigs - apparently all tools do this */ - 65535, /* snaplen - this should be long enough */ - NAS_LTE_DLT /* Data Link Type (DLT). Set as unused value 149 for now */ - }; - - FILE *fd = fopen(fileName, "w"); - if (fd == NULL) { - printf("Failed to open file \"%s\" for writing\n", fileName); - return NULL; - } - /* Write the file header */ - fwrite(&file_header, sizeof(pcap_hdr_t), 1, fd); - return fd; -} +/************************************************************************** + * API functions for writing NAS-EPS PCAP files * + **************************************************************************/ -/* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */ -inline int NAS_LTE_PCAP_WritePDU(FILE *fd, NAS_Context_Info_t *context, - const unsigned char *PDU, unsigned int length) +/* Write an individual PDU (PCAP packet header + nas-context + nas-pdu) */ +inline int LTE_PCAP_NAS_WritePDU(FILE *fd, NAS_Context_Info_t *context, + const unsigned char *PDU, unsigned int length) { pcaprec_hdr_t packet_header; @@ -281,11 +247,4 @@ inline int NAS_LTE_PCAP_WritePDU(FILE *fd, NAS_Context_Info_t *context, return 1; } -/* Close the PCAP file */ -inline void NAS_LTE_PCAP_Close(FILE *fd) -{ - if(fd) - fclose(fd); -} - #endif /* UEPCAP_H */ diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 37d73b910..7b15e799d 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -197,10 +197,11 @@ public: virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; virtual void add_bearer(uint32_t lcid, srslte::srslte_pdcp_config_t cnfg = srslte::srslte_pdcp_config_t()) = 0; virtual void config_security(uint32_t lcid, - uint8_t *k_rrc_enc_, - uint8_t *k_rrc_int_, + uint8_t *k_enc_, + uint8_t *k_int_, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0; + virtual void enable_integrity(uint32_t lcid) = 0; virtual void enable_encryption(uint32_t lcid) = 0; }; diff --git a/lib/include/srslte/upper/pdcp.h b/lib/include/srslte/upper/pdcp.h index f52fdbe05..e4547acdf 100644 --- a/lib/include/srslte/upper/pdcp.h +++ b/lib/include/srslte/upper/pdcp.h @@ -58,10 +58,11 @@ public: void write_sdu(uint32_t lcid, byte_buffer_t *sdu); void add_bearer(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t()); void config_security(uint32_t lcid, - uint8_t *k_rrc_enc, - uint8_t *k_rrc_int, + uint8_t *k_enc, + uint8_t *k_int, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo); + void enable_integrity(uint32_t lcid); void enable_encryption(uint32_t lcid); // RLC interface diff --git a/lib/include/srslte/upper/pdcp_entity.h b/lib/include/srslte/upper/pdcp_entity.h index bf1e8b5b2..f59866d5d 100644 --- a/lib/include/srslte/upper/pdcp_entity.h +++ b/lib/include/srslte/upper/pdcp_entity.h @@ -78,10 +78,11 @@ public: // RRC interface void write_sdu(byte_buffer_t *sdu); - void config_security(uint8_t *k_rrc_enc_, - uint8_t *k_rrc_int_, + void config_security(uint8_t *k_enc_, + uint8_t *k_int_, CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, INTEGRITY_ALGORITHM_ID_ENUM integ_algo_); + void enable_integrity(); void enable_encryption(); // RLC interface @@ -102,13 +103,14 @@ private: bool active; uint32_t lcid; srslte_pdcp_config_t cfg; + uint8_t sn_len_bytes; bool do_integrity; bool do_encryption; uint32_t rx_count; uint32_t tx_count; - uint8_t k_rrc_enc[32]; - uint8_t k_rrc_int[32]; + uint8_t k_enc[32]; + uint8_t k_int[32]; CIPHERING_ALGORITHM_ID_ENUM cipher_algo; INTEGRITY_ALGORITHM_ID_ENUM integ_algo; @@ -133,6 +135,7 @@ private: void run_thread(); + uint8_t get_bearer_id(uint8_t lcid); }; /**************************************************************************** diff --git a/lib/src/common/mac_pcap.cc b/lib/src/common/mac_pcap.cc index b73181e73..d73c196fb 100644 --- a/lib/src/common/mac_pcap.cc +++ b/lib/src/common/mac_pcap.cc @@ -40,14 +40,14 @@ void mac_pcap::enable(bool en) } void mac_pcap::open(const char* filename, uint32_t ue_id) { - pcap_file = MAC_LTE_PCAP_Open(filename); + pcap_file = LTE_PCAP_Open(MAC_LTE_DLT, filename); ue_id = ue_id; enable_write = true; } void mac_pcap::close() { fprintf(stdout, "Saving MAC PCAP file\n"); - MAC_LTE_PCAP_Close(pcap_file); + LTE_PCAP_Close(pcap_file); } void mac_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti, @@ -65,7 +65,7 @@ void mac_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reT (uint16_t)(tti%10) /* Subframe number */ }; if (pdu) { - MAC_LTE_PCAP_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); + LTE_PCAP_MAC_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); } } } diff --git a/lib/src/common/nas_pcap.cc b/lib/src/common/nas_pcap.cc index 80603f8d5..94e2cd9b0 100644 --- a/lib/src/common/nas_pcap.cc +++ b/lib/src/common/nas_pcap.cc @@ -12,14 +12,14 @@ void nas_pcap::enable() } void nas_pcap::open(const char* filename, uint32_t ue_id) { - pcap_file = NAS_LTE_PCAP_Open(filename); + pcap_file = LTE_PCAP_Open(NAS_LTE_DLT, filename); ue_id = ue_id; enable_write = true; } void nas_pcap::close() { fprintf(stdout, "Saving NAS PCAP file\n"); - MAC_LTE_PCAP_Close(pcap_file); + LTE_PCAP_Close(pcap_file); } void nas_pcap::write_nas(uint8_t *pdu, uint32_t pdu_len_bytes) @@ -27,7 +27,7 @@ void nas_pcap::write_nas(uint8_t *pdu, uint32_t pdu_len_bytes) if (enable_write) { NAS_Context_Info_t context; if (pdu) { - NAS_LTE_PCAP_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); + LTE_PCAP_NAS_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); } } } diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc index ed7e13684..51d4950a5 100644 --- a/lib/src/upper/pdcp.cc +++ b/lib/src/upper/pdcp.cc @@ -99,13 +99,19 @@ void pdcp::add_bearer(uint32_t lcid, srslte_pdcp_config_t cfg) } void pdcp::config_security(uint32_t lcid, - uint8_t *k_rrc_enc, - uint8_t *k_rrc_int, + uint8_t *k_enc, + uint8_t *k_int, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) { if(valid_lcid(lcid)) - pdcp_array[lcid].config_security(k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); + pdcp_array[lcid].config_security(k_enc, k_int, cipher_algo, integ_algo); +} + +void pdcp::enable_integrity(uint32_t lcid) +{ + if(valid_lcid(lcid)) + pdcp_array[lcid].enable_integrity(); } void pdcp::enable_encryption(uint32_t lcid) diff --git a/lib/src/upper/pdcp_entity.cc b/lib/src/upper/pdcp_entity.cc index 066bb127f..0ac426a6e 100644 --- a/lib/src/upper/pdcp_entity.cc +++ b/lib/src/upper/pdcp_entity.cc @@ -56,6 +56,12 @@ void pdcp_entity::init(srsue::rlc_interface_pdcp *rlc_, rx_count = 0; do_integrity = false; do_encryption = false; + if(cfg.is_control) { + cfg.sn_len = 5; + sn_len_bytes = 1; + } else { + sn_len_bytes = (cfg.sn_len+7)/8; + } start(PDCP_THREAD_PRIO); @@ -87,46 +93,57 @@ bool pdcp_entity::is_active() void pdcp_entity::write_sdu(byte_buffer_t *sdu) { log->info_hex(sdu->msg, sdu->N_bytes, - "TX %s SDU, do_integrity = %s, do_encryption = %s", get_rb_name(lcid), + "TX %s SDU, SN: %d, do_integrity = %s, do_encryption = %s", + get_rb_name(lcid), tx_count, (do_integrity) ? "true" : "false", (do_encryption) ? "true" : "false"); if (cfg.is_control) { pdcp_pack_control_pdu(tx_count, sdu); - if(do_integrity) - { + if(do_integrity) { integrity_generate(sdu->msg, sdu->N_bytes-4, &sdu->msg[sdu->N_bytes-4]); } - tx_count++; } if (cfg.is_data) { if(12 == cfg.sn_len) { - pdcp_pack_data_pdu_long_sn(tx_count++, sdu); + pdcp_pack_data_pdu_long_sn(tx_count, sdu); } else { - pdcp_pack_data_pdu_short_sn(tx_count++, sdu); + pdcp_pack_data_pdu_short_sn(tx_count, sdu); } } + if(do_encryption) { + cipher_encrypt(&sdu->msg[sn_len_bytes], + sdu->N_bytes-sn_len_bytes, + &sdu->msg[sn_len_bytes]); + log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU (encrypted)", get_rb_name(lcid)); + } + tx_count++; + rlc->write_sdu(lcid, sdu); } -void pdcp_entity::config_security(uint8_t *k_rrc_enc_, - uint8_t *k_rrc_int_, +void pdcp_entity::config_security(uint8_t *k_enc_, + uint8_t *k_int_, CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) { - do_integrity = true; for(int i=0; i<32; i++) { - k_rrc_enc[i] = k_rrc_enc_[i]; - k_rrc_int[i] = k_rrc_int_[i]; + k_enc[i] = k_enc_[i]; + k_int[i] = k_int_[i]; } cipher_algo = cipher_algo_; integ_algo = integ_algo_; } +void pdcp_entity::enable_integrity() +{ + do_integrity = true; +} + void pdcp_entity::enable_encryption() { do_encryption = true; @@ -142,24 +159,26 @@ void pdcp_entity::integrity_generate( uint8_t *msg, uint32_t msg_len, uint8_t *mac) { + uint8_t bearer; + switch(integ_algo) { case INTEGRITY_ALGORITHM_ID_EIA0: break; case INTEGRITY_ALGORITHM_ID_128_EIA1: - security_128_eia1(&k_rrc_int[16], + security_128_eia1(&k_int[16], tx_count, - lcid-1, + get_bearer_id(lcid), cfg.direction, msg, msg_len, mac); break; case INTEGRITY_ALGORITHM_ID_128_EIA2: - security_128_eia2(&k_rrc_int[16], + security_128_eia2(&k_int[16], tx_count, - lcid-1, - cfg.direction, + get_bearer_id(lcid), + cfg.direction, msg, msg_len, mac); @@ -183,19 +202,19 @@ bool pdcp_entity::integrity_verify(uint8_t *msg, case INTEGRITY_ALGORITHM_ID_EIA0: break; case INTEGRITY_ALGORITHM_ID_128_EIA1: - security_128_eia1(&k_rrc_int[16], + security_128_eia1(&k_int[16], count, - lcid-1, - ( cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), + get_bearer_id(lcid), + (cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), msg, msg_len, mac_exp); break; case INTEGRITY_ALGORITHM_ID_128_EIA2: - security_128_eia2(&k_rrc_int[16], + security_128_eia2(&k_int[16], count, - lcid-1, - ( cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), + get_bearer_id(lcid), + (cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), msg, msg_len, mac_exp); @@ -240,20 +259,20 @@ void pdcp_entity::cipher_encrypt(uint8_t *msg, case CIPHERING_ALGORITHM_ID_EEA0: break; case CIPHERING_ALGORITHM_ID_128_EEA1: - security_128_eea1(&(k_rrc_enc[16]), + security_128_eea1(&(k_enc[16]), tx_count, - lcid - 1, - cfg.direction, + get_bearer_id(lcid), + cfg.direction, msg, msg_len, ct_tmp.msg); memcpy(ct, ct_tmp.msg, msg_len); break; case CIPHERING_ALGORITHM_ID_128_EEA2: - security_128_eea2(&(k_rrc_enc[16]), + security_128_eea2(&(k_enc[16]), tx_count, - lcid - 1, - cfg.direction, + get_bearer_id(lcid), + cfg.direction, msg, msg_len, ct_tmp.msg); @@ -275,19 +294,19 @@ void pdcp_entity::cipher_decrypt(uint8_t *ct, case CIPHERING_ALGORITHM_ID_EEA0: break; case CIPHERING_ALGORITHM_ID_128_EEA1: - security_128_eea1(&(k_rrc_enc[16]), + security_128_eea1(&(k_enc[16]), count, - lcid - 1, - ( cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), + get_bearer_id(lcid), + (cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), ct, ct_len, msg_tmp.msg); break; case CIPHERING_ALGORITHM_ID_128_EEA2: - security_128_eea2(&(k_rrc_enc[16]), + security_128_eea2(&(k_enc[16]), count, - lcid - 1, - ( cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), + get_bearer_id(lcid), + (cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), ct, ct_len, msg_tmp.msg); @@ -306,39 +325,35 @@ void pdcp_entity::run_thread() while(running) { rx_pdu_queue.read(&pdu); + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", get_rb_name(lcid)); // Handle SRB messages switch(lcid) { case RB_ID_SRB0: // Simply pass on to RRC - log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", get_rb_name(lcid)); rrc->write_pdu(RB_ID_SRB0, pdu); break; case RB_ID_SRB1: // Intentional fall-through case RB_ID_SRB2: uint32_t sn; - - log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", get_rb_name(lcid)); - if (do_encryption) { - cipher_decrypt(&(pdu->msg[1]), - pdu->msg[0], - pdu->N_bytes - 1, - &(pdu->msg[1])); + cipher_decrypt(&(pdu->msg[sn_len_bytes]), + rx_count, + pdu->N_bytes - sn_len_bytes, + &(pdu->msg[sn_len_bytes])); log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU (decrypted)", get_rb_name(lcid)); } if (do_integrity) { integrity_verify(pdu->msg, - pdu->msg[0], + rx_count, pdu->N_bytes - 4, &(pdu->msg[pdu->N_bytes - 4])); } pdcp_unpack_control_pdu(pdu, &sn); - log->info_hex(pdu->msg, pdu->N_bytes, "RX %s SDU SN: %d", - get_rb_name(lcid), sn); + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU SN: %d", get_rb_name(lcid), sn); rrc->write_pdu(lcid, pdu); break; } @@ -347,18 +362,35 @@ void pdcp_entity::run_thread() if(lcid >= RB_ID_DRB1) { uint32_t sn; + if (do_encryption) { + cipher_decrypt(&(pdu->msg[sn_len_bytes]), + rx_count, + pdu->N_bytes - sn_len_bytes, + &(pdu->msg[sn_len_bytes])); + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU (decrypted)", get_rb_name(lcid)); + } if(12 == cfg.sn_len) { pdcp_unpack_data_pdu_long_sn(pdu, &sn); } else { pdcp_unpack_data_pdu_short_sn(pdu, &sn); } - log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU: %d", get_rb_name(lcid), sn); + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU SN: %d", get_rb_name(lcid), sn); gw->write_pdu(lcid, pdu); } + + rx_count++; } } +uint8_t pdcp_entity::get_bearer_id(uint8_t lcid) +{ + if(lcid <= RB_ID_SRB2) { + return lcid - 1; + } else { + return lcid - RB_ID_SRB2 - 1; + } +} /**************************************************************************** diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 273a2d84d..d801d78d6 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -1164,11 +1164,21 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.cipher_alg; integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.int_alg; - // Configure PDCP for security + rrc_log->info("Received Security Mode Command eea: %s, eia: %s\n", + ciphering_algorithm_id_text[cipher_algo], + integrity_algorithm_id_text[integ_algo]); + + // Generate AS security keys uint8_t k_asme[32]; nas->get_k_asme(k_asme, 32); usim->generate_as_keys(k_asme, nas->get_ul_count()-1, k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); + rrc_log->debug_hex(k_rrc_enc, 32, "RRC encryption key - k_rrc_enc"); + rrc_log->debug_hex(k_rrc_int, 32, "RRC integrity key - k_rrc_int"); + rrc_log->debug_hex(k_up_enc, 32, "UP encryption key - k_up_enc"); + + // Configure PDCP for security pdcp->config_security(lcid, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); + pdcp->enable_integrity(lcid); send_security_mode_complete(lcid, pdu); pdcp->enable_encryption(lcid); break; @@ -1626,6 +1636,8 @@ void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg) { pdcp->add_bearer(srb_cnfg->srb_id, srslte_pdcp_config_t(true)); // Set PDCP config control flag if(RB_ID_SRB2 == srb_cnfg->srb_id) { pdcp->config_security(srb_cnfg->srb_id, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); + pdcp->enable_integrity(srb_cnfg->srb_id); + pdcp->enable_encryption(srb_cnfg->srb_id); } // Setup RLC @@ -1692,7 +1704,8 @@ void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) { } } pdcp->add_bearer(lcid, pdcp_cfg); - // TODO: setup PDCP security (using k_up_enc) + pdcp->config_security(lcid, k_up_enc, k_up_int, cipher_algo, integ_algo); + pdcp->enable_encryption(lcid); // Setup RLC rlc->add_bearer(lcid, srslte_rlc_config_t(&drb_cnfg->rlc_cnfg)); From f3b1bc0e2ddc4f200d913074ea7d80e225021b27 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Sat, 2 Dec 2017 12:02:01 +0100 Subject: [PATCH 19/42] Look for multiple cells on each n_id_2 while cancelling the self interference --- srsue/hdr/phy/phch_recv.h | 5 ++ srsue/src/phy/phch_recv.cc | 170 ++++++++++++++++++++----------------- 2 files changed, 99 insertions(+), 76 deletions(-) diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/phch_recv.h index e6ef981d1..667f0a93c 100644 --- a/srsue/hdr/phy/phch_recv.h +++ b/srsue/hdr/phy/phch_recv.h @@ -102,6 +102,8 @@ private: bool set_frequency(); bool set_cell(); + static void substract_sync(cf_t *buffer, uint32_t nof_prb, srslte_sync_t *sync_obj); + void cell_search_inc(); void resync_sfn(bool is_connected = false, bool rx_now = false); bool stop_sync(); @@ -175,6 +177,7 @@ private: float rsrp(); float rsrq(); float snr(); + uint32_t frame_st_idx(); void set_rx_gain_offset(float rx_gain_offset); private: srslte::log *log_h; @@ -185,6 +188,7 @@ private: uint32_t current_prb; float rx_gain_offset; float mean_rsrp, mean_rsrq, mean_snr; + uint32_t final_offset; const static int RSRP_MEASURE_NOF_FRAMES = 5; }; @@ -205,6 +209,7 @@ private: const static int DEFAULT_MEASUREMENT_LEN = 10; + cf_t *input_cfo_corrected; cf_t *sf_buffer[SRSLTE_MAX_PORTS]; srslte::log *log_h; srslte_sync_t sync_find; diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 17ac71c54..95931e600 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -549,9 +549,6 @@ void phch_recv::run_thread() phy_state = IDLE; is_in_idle = true; - uint32_t hf_len; - uint32_t fft_sz; - while (running) { if (phy_state != IDLE) { @@ -680,23 +677,9 @@ void phch_recv::run_thread() } workers_pool->start_worker(worker); - // Substract PSS/SSS from current cell before computing intrafrequency - hf_len = SRSLTE_SF_LEN_PRB(cell.nof_prb)/2; - fft_sz = srslte_symbol_sz(cell.nof_prb); - + // Substract PSS/SSS from current cell before computing intra-frequency if ((tti%5) == 0) { - srslte_vec_sc_prod_cfc(ue_sync.strack.pss_filt, 1.0/sqrtf(fft_sz), ue_sync.strack.pss_filt, fft_sz); - srslte_vec_sc_prod_cfc(ue_sync.strack.sss_filt, 1.0/sqrtf(fft_sz), ue_sync.strack.pss_filt, fft_sz); - - srslte_vec_sub_ccc(&buffer[0][hf_len-fft_sz], - ue_sync.strack.pss_filt, - &buffer[0][hf_len-fft_sz], - fft_sz); - - srslte_vec_sub_ccc(&buffer[0][hf_len-2*fft_sz-SRSLTE_CP_LEN(fft_sz, SRSLTE_CP_NORM_LEN)], - ue_sync.strack.sss_filt, - &buffer[0][hf_len-2*fft_sz-SRSLTE_CP_LEN(fft_sz, SRSLTE_CP_NORM_LEN)], - fft_sz); + substract_sync(buffer[0], cell.nof_prb, &ue_sync.strack); } intra_freq_meas.write(tti, buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb)); out_of_sync_cnt = 0; @@ -749,7 +732,24 @@ void phch_recv::out_of_sync() { } } +void phch_recv::substract_sync(cf_t *buffer, uint32_t nof_prb, srslte_sync_t *sync_obj) +{ + uint32_t hf_len = SRSLTE_SF_LEN_PRB(nof_prb)/2; + uint32_t fft_sz = srslte_symbol_sz(nof_prb); + + srslte_vec_sc_prod_cfc(sync_obj->pss_filt, 1.0/sqrtf(fft_sz), sync_obj->pss_filt, fft_sz); + srslte_vec_sc_prod_cfc(sync_obj->sss_filt, 1.0/sqrtf(fft_sz), sync_obj->sss_filt, fft_sz); + + srslte_vec_sub_ccc(&buffer[hf_len-fft_sz], + sync_obj->pss_filt, + &buffer[hf_len-fft_sz], + fft_sz); + srslte_vec_sub_ccc(&buffer[hf_len-2*fft_sz-SRSLTE_CP_LEN(fft_sz, SRSLTE_CP_NORM_LEN)], + sync_obj->sss_filt, + &buffer[hf_len-2*fft_sz-SRSLTE_CP_LEN(fft_sz, SRSLTE_CP_NORM_LEN)], + fft_sz); +} @@ -1070,6 +1070,10 @@ float phch_recv::measure::snr() { return mean_snr; } +uint32_t phch_recv::measure::frame_st_idx() { + return final_offset; +} + void phch_recv::measure::set_rx_gain_offset(float rx_gain_offset) { this->rx_gain_offset = rx_gain_offset; } @@ -1097,7 +1101,6 @@ phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *in ret_code ret = IDLE; - Info("INTRA: Here offset=%d\n", offset); offset = offset-sf_len/2; if (offset < 0) { offset += sf_len; @@ -1133,15 +1136,13 @@ phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *in } } - if (found_best) { - Info("INTRA: fine-tuned offset=%d\n", best_test_offset); - } - offset = found_best?best_test_offset:offset; if (offset >= 0 && offset < sf_len*max_sf) { uint32_t nof_sf = (sf_len*max_sf - offset)/sf_len; - Info("INTRA: fine-tuning offset: %d, found_best=%d, rem_sf=%d\n", offset, found_best, nof_sf); + Debug("INTRA: fine-tuning offset: %d, found_best=%d, rem_sf=%d\n", offset, found_best, nof_sf); + + final_offset = offset; for (uint32_t i=0;i= 0) { + // We found the same cell as before, look another N_id_2 + if ((uint32_t) cell_id == found_cell.id) { + sync_res = SRSLTE_SYNC_NOFOUND; + } else { + // We found a new cell ID + found_cell.id = cell_id; + found_cell.nof_ports = 1; // Use port 0 only for measurement + measure_p.set_cell(found_cell); + + // Correct CFO + srslte_cfo_correct(&sync_find.cfo_corr_frame, + input_buffer, + input_cfo_corrected, + -srslte_sync_get_cfo(&sync_find)/sync_find.fft_size); + + switch(measure_p.run_multiple_subframes(input_cfo_corrected, peak_idx, sf_idx, nof_sf)) { + case measure::MEASURE_OK: + cells[nof_cells].pci = found_cell.id; + cells[nof_cells].rsrp = measure_p.rsrp(); + cells[nof_cells].rsrq = measure_p.rsrq(); + cells[nof_cells].offset = measure_p.frame_st_idx(); + nof_cells++; + + // Substract interference from input buffer (for the next cell) + substract_sync(&input_buffer[measure_p.frame_st_idx()], cell.nof_prb, &sync_find); + + Info("INTRA: Found neighbour cell: pci=%d, rsrp=%.1f dBm, peak_idx=%d, n_id_2=%d, cfo=%.1f Hz\n", + cell_id, measure_p.rsrq(), peak_idx, n_id_2, 15000*srslte_sync_get_cfo(&sync_find)); + + break; + case measure::ERROR: + Error("Measuring neighbour cell\n"); + return SRSLTE_ERROR; + default: + break; + } + } + } else { + sync_res = SRSLTE_SYNC_NOFOUND; } - } - break; - case SRSLTE_SYNC_FOUND_NOSPACE: - /* If a peak was found but there is not enough space for SSS/CP detection, discard a few samples */ - break; - default: - break; - } + break; + case SRSLTE_SYNC_FOUND_NOSPACE: + /* If a peak was found but there is not enough space for SSS/CP detection, discard a few samples */ + break; + default: + break; + } + } while(sync_res == SRSLTE_SYNC_FOUND); } } return nof_cells; From aa41237961bbfa06a2d7ea7e5dcea9ff7cafd2af Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Sat, 2 Dec 2017 18:37:20 +0100 Subject: [PATCH 20/42] Fix adaptive UL retx. Fixes #99 --- srsue/hdr/mac/ul_harq.h | 82 ++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/srsue/hdr/mac/ul_harq.h b/srsue/hdr/mac/ul_harq.h index 72b691c00..d162d35a2 100644 --- a/srsue/hdr/mac/ul_harq.h +++ b/srsue/hdr/mac/ul_harq.h @@ -205,14 +205,16 @@ private: *ack = false; } } - set_harq_feedback(*ack); + harq_feedback = *ack; } - uint32_t max_retx; - if (is_msg3) { - max_retx = harq_entity->params->max_harq_msg3_tx; - } else { - max_retx = harq_entity->params->max_harq_tx; + // Reset HARQ process if TB has changed + if (harq_feedback && has_grant() && grant) { + if (grant->n_bytes[0] != cur_grant.n_bytes[0] && cur_grant.n_bytes[0] > 0) { + Debug("UL %d: Reset due to change of grant size last_grant=%d, new_grant=%d\n", + pid, cur_grant.n_bytes[0], grant->n_bytes[0]); + reset(); + } } // Receive and route HARQ feedbacks @@ -222,6 +224,7 @@ private: grant->is_from_rar) { // New transmission + reset(); // Uplink grant in a RAR if (grant->is_from_rar) { @@ -245,25 +248,13 @@ private: } } else if (has_grant()) { // Adaptive Re-TX - if (current_tx_nb >= max_retx) { - Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx); - reset(); - action->expect_ack = false; - } else { - generate_retx(tti_tx, grant, action); - } + generate_retx(tti_tx, grant, action); } else { Warning("UL %d: Received retransmission but no previous grant available for this PID.\n", pid); } } else if (has_grant()) { // Non-Adaptive Re-Tx - if (current_tx_nb >= max_retx) { - Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx); - reset(); - action->expect_ack = false; - } else { - generate_retx(tti_tx, action); - } + generate_retx(tti_tx, action); } if (harq_entity->pcap && grant) { if (grant->is_from_rar) { @@ -273,18 +264,6 @@ private: } } - void set_harq_feedback(bool ack) - { - harq_feedback = ack; - // UL packet successfully delivered - if (ack) { - Info("UL %d: HARQ = ACK for UL transmission. Discarting TB.\n", pid); - reset(); - } else { - Info("UL %d: HARQ = NACK for UL transmission\n", pid); - } - } - uint32_t get_rv() { int rv_of_irv[4] = {0, 2, 3, 1}; @@ -326,24 +305,43 @@ private: void generate_retx(uint32_t tti_tx, Tgrant *grant, Taction *action) { + uint32_t max_retx; + if (is_msg3) { + max_retx = harq_entity->params->max_harq_msg3_tx; + } else { + max_retx = harq_entity->params->max_harq_tx; + } + + if (current_tx_nb >= max_retx) { + Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx); + reset(); + action->expect_ack = false; + return; + } + int irv_of_rv[4] = {0, 3, 1, 2}; + + // HARQ entity requests an adaptive transmission if (grant) { - // HARQ entity requests an adaptive transmission if (grant->rv) { current_irv = irv_of_rv[grant->rv[0]%4]; } + memcpy(&cur_grant, grant, sizeof(Tgrant)); harq_feedback = false; - Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d\n", - pid, current_tx_nb, get_rv(), grant->n_bytes[0]); + + Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d, HI=%s\n", + pid, current_tx_nb, get_rv(), grant->n_bytes[0], harq_feedback?"ACK":"NACK"); + + generate_tx(tti_tx, action); + + // HARQ entity requests a non-adaptive transmission + } else if (!harq_feedback) { + // Non-adaptive retx are only sent if HI=NACK. If HI=ACK but no grant was received do not reset PID + Info("UL %d: Non-Adaptive retx=%d, RV=%d, TBS=%d, HI=%s\n", + pid, current_tx_nb, get_rv(), cur_grant.n_bytes[0], harq_feedback?"ACK":"NACK"); + generate_tx(tti_tx, action); - } else { - Info("UL %d: Non-Adaptive retx=%d, RV=%d, TBS=%d\n", - pid, current_tx_nb, get_rv(), cur_grant.n_bytes[0]); - // HARQ entity requests a non-adaptive transmission - if (!harq_feedback) { - generate_tx(tti_tx, action); - } } // On every Msg3 retransmission, restart mac-ContentionResolutionTimer as defined in Section 5.1.5 From c816be525e6baef55894e1d14e77a5e923758d21 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Sat, 2 Dec 2017 20:32:44 +0100 Subject: [PATCH 21/42] Testing Reestablishment --- srsue/hdr/upper/rrc.h | 26 +++- srsue/src/phy/phch_recv.cc | 6 - srsue/src/upper/rrc.cc | 308 ++++++++++++++++++++----------------- 3 files changed, 188 insertions(+), 152 deletions(-) diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index 085bf6b88..55ce12dee 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -139,8 +139,14 @@ private: nas_interface_rrc *nas; usim_interface_rrc *usim; - void send_ul_dcch_msg(byte_buffer_t *pdu = NULL); LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; + LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; + LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; + + byte_buffer_t* byte_align_and_pack(byte_buffer_t *pdu = NULL); + void send_ul_ccch_msg(byte_buffer_t *pdu = NULL); + void send_ul_dcch_msg(byte_buffer_t *pdu = NULL); srslte::bit_buffer_t bit_buf; pthread_mutex_t mutex; @@ -152,6 +158,10 @@ private: rrc_args_t args; bool first_stimsi_attempt; + uint16_t ho_src_rnti; + int ho_src_cell_idx; + phy_interface_rrc::phy_cfg_t ho_src_phy_cfg; + mac_interface_rrc::mac_cfg_t ho_src_mac_cfg; bool pending_mob_reconf; LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT mob_reconf; @@ -177,9 +187,6 @@ private: std::map srbs; std::map drbs; - LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; - LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; - // RRC constants and timers srslte::mac_interface_timers *mac_timers; uint32_t n310_cnt, N310; @@ -204,7 +211,9 @@ private: const static int MAX_KNOWN_CELLS = 64; cell_t known_cells[MAX_KNOWN_CELLS]; cell_t *current_cell; - cell_t* add_new_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp); + + int find_cell_idx(uint32_t earfcn, uint32_t pci); + cell_t* add_new_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp); uint32_t find_best_cell(uint32_t earfcn, srslte_cell_t *cell); typedef enum { @@ -372,13 +381,13 @@ private: // Senders void send_con_request(); - void send_con_restablish_request(); + void send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause, uint16_t crnti); void send_con_restablish_complete(); void send_con_setup_complete(byte_buffer_t *nas_msg); void send_ul_info_transfer(uint32_t lcid, byte_buffer_t *sdu); void send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu); void send_rrc_con_reconfig_complete(byte_buffer_t *pdu); - void send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu); + void send_rrc_ue_cap_info(byte_buffer_t *pdu); // Parsers void parse_dl_ccch(byte_buffer_t *pdu); @@ -386,7 +395,8 @@ private: void parse_dl_info_transfer(uint32_t lcid, byte_buffer_t *pdu); // Helpers - void ho_prepare(); + void ho_failed(); + bool ho_prepare(); void add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp); void rrc_connection_release(); void con_restablish_cell_reselected(); diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 95931e600..cd95f6d98 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -353,12 +353,6 @@ void phch_recv::cell_search_stop() { bool phch_recv::cell_handover(srslte_cell_t cell) { - int offset = intra_freq_meas.get_offset(cell.id); - if (offset < 0) { - log_h->error("Cell HO: Can't find PCI=%d\n", cell.id); - return false; - } - int cnt = 0; while(worker_com->is_any_pending_ack() && cnt < 10) { usleep(1000); diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 2559d3645..99c6894b0 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -159,6 +159,8 @@ void rrc::set_args(rrc_args_t *args) { */ void rrc::run_thread() { + uint32_t failure_test = 0; + while (thread_running) { if (state >= RRC_STATE_IDLE && state < RRC_STATE_CONNECTING) { @@ -263,11 +265,20 @@ void rrc::run_thread() { } break; case RRC_STATE_CONNECTED: + failure_test++; + if (failure_test >= 100) { + mac_interface_rrc::ue_rnti_t ue_rnti; + mac->get_rntis(&ue_rnti); + send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_OTHER_FAILURE, ue_rnti.crnti); + } // Take measurements, cell reselection, etc break; case RRC_STATE_HO_PREPARE: - ho_prepare(); - state = RRC_STATE_HO_PROCESS; + if (ho_prepare()) { + state = RRC_STATE_HO_PROCESS; + } else { + state = RRC_STATE_CONNECTED; + } break; case RRC_STATE_HO_PROCESS: // wait for HO to finish @@ -594,15 +605,13 @@ rrc::cell_t* rrc::add_new_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rs if (earfcn == 0) { return NULL; } - // First check it does not exist already - int j=0; - while(j= 0) { + known_cells[idx].rsrp = rsrp; + return &known_cells[idx]; } + + // if does not exist, find empty slot int i=0; while(i= 0) { + known_cells[idx].rsrp = rsrp; + return; + } + + rrc_log->info("Added neighbour cell earfcn=%d, pci=%d, rsrp=%f\n", earfcn, pci, rsrp); + + srslte_cell_t cell; + cell = current_cell->phy_cell; + cell.id = pci; + add_new_cell(earfcn, cell, rsrp); +} + +int rrc::find_cell_idx(uint32_t earfcn, uint32_t pci) { + for (uint32_t i = 0; i < MAX_KNOWN_CELLS; i++) { + if (earfcn == known_cells[i].earfcn && pci == known_cells[i].phy_cell.id) { + return (int) i; + } + } + return -1; +} + // PHY indicates that has gone through all known EARFCN void rrc::earfcn_end() { rrc_log->info("Finished searching cells in EARFCN set while in state %s\n", rrc_state_text[state]); @@ -635,22 +668,7 @@ void rrc::earfcn_end() { } } -void rrc::add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp) { - for (uint32_t i = 0; i < MAX_KNOWN_CELLS && known_cells[i].earfcn; i++) { - if (earfcn == known_cells[i].earfcn && pci == known_cells[i].phy_cell.id) { - known_cells[i].rsrp = rsrp; - return; - } - } - rrc_log->info("Added neighbour cell earfcn=%d, pci=%d, rsrp=%f\n", earfcn, pci, rsrp); - - srslte_cell_t cell; - cell = current_cell->phy_cell; - cell.id = pci; - add_new_cell(earfcn, cell, rsrp); -} - -// Cell reselction in IDLE Section 5.2.4 of 36.304 +// Cell reselection in IDLE Section 5.2.4 of 36.304 void rrc::cell_reselection_eval(float rsrp, float rsrq) { // Intra-frequency cell-reselection criteria @@ -740,7 +758,9 @@ void rrc::radio_link_failure() { if (state != RRC_STATE_CONNECTED) { state = RRC_STATE_LEAVE_CONNECTED; } else { - send_con_restablish_request(); + mac_interface_rrc::ue_rnti_t uernti; + mac->get_rntis(&uernti); + send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_OTHER_FAILURE, uernti.crnti); } } @@ -779,6 +799,7 @@ void rrc::timer_expired(uint32_t timeout_id) { } } else if (timeout_id == t304) { rrc_log->console("Timer T304 expired: Handover failed\n"); + ho_failed(); // fw to measurement } else if (!measurements.timer_expired(timeout_id)) { rrc_log->error("Timeout from unknown timer id %d\n", timeout_id); @@ -804,7 +825,6 @@ void rrc::timer_expired(uint32_t timeout_id) { void rrc::send_con_request() { rrc_log->debug("Preparing RRC Connection Request\n"); - LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; // Prepare ConnectionRequest packet @@ -819,74 +839,63 @@ void rrc::send_con_request() { } ul_ccch_msg.msg.rrc_con_req.cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING; - liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - byte_buffer_t *pdcp_buf = pool_allocate;; - srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); - pdcp_buf->N_bytes = bit_buf.N_bits / 8; - pdcp_buf->set_timestamp(); - - // Set UE contention resolution ID in MAC - uint64_t uecri = 0; - uint8_t *ue_cri_ptr = (uint8_t *) &uecri; - uint32_t nbytes = 6; - for (uint32_t i = 0; i < nbytes; i++) { - ue_cri_ptr[nbytes - i - 1] = pdcp_buf->msg[i]; - } - rrc_log->debug("Setting UE contention resolution ID: %d\n", uecri); - mac->set_contention_id(uecri); + send_ul_ccch_msg(); - rrc_log->info("Sending RRC Connection Request on SRB0\n"); - pdcp->write_sdu(RB_ID_SRB0, pdcp_buf); } /* RRC connection re-establishment procedure (5.3.7) */ -void rrc::send_con_restablish_request() { - - srslte_cell_t cell; - phy->get_current_cell(&cell); - - LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; - LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; - +void rrc::send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause, uint16_t crnti) +{ // Compute shortMAC-I uint8_t varShortMAC[128], varShortMAC_packed[16]; bzero(varShortMAC, 128); bzero(varShortMAC_packed, 16); uint8_t *msg_ptr = varShortMAC; - liblte_rrc_pack_cell_identity_ie(0x1a2d0, &msg_ptr); - liblte_rrc_pack_phys_cell_id_ie(cell.id, &msg_ptr); - mac_interface_rrc::ue_rnti_t ue_rnti; - mac->get_rntis(&ue_rnti); - liblte_rrc_pack_c_rnti_ie(ue_rnti.crnti, &msg_ptr); - srslte_bit_pack_vector(varShortMAC, varShortMAC_packed, msg_ptr - varShortMAC); - uint8_t mac_key[4]; - security_128_eia2(&k_rrc_int[16], - 1, - 1, - 1, - varShortMAC_packed, - 7, - mac_key); + // ASN.1 encode byte-aligned VarShortMAC-Input + liblte_rrc_pack_cell_identity_ie(current_cell->sib1.cell_id, &msg_ptr); + msg_ptr = &varShortMAC[4]; + liblte_rrc_pack_phys_cell_id_ie(phy->get_current_pci(), &msg_ptr); + msg_ptr = &varShortMAC[4+2]; + liblte_rrc_pack_c_rnti_ie(crnti, &msg_ptr); + srslte_bit_pack_vector(varShortMAC, varShortMAC_packed, (4+2+4)*8); - mac_interface_rrc::ue_rnti_t uernti; - mac->get_rntis(&uernti); + rrc_log->info("Generated varShortMAC: cellId=0x%x, PCI=%d, rnti=%d\n", + current_cell->sib1.cell_id, phy->get_current_pci(), crnti); + + // Compute MAC-I + uint8_t mac_key[4]; + switch(integ_algo) { + case INTEGRITY_ALGORITHM_ID_128_EIA1: + security_128_eia1(&k_rrc_int[16], + 1, + 1, + 1, + varShortMAC_packed, + 10, + mac_key); + break; + case INTEGRITY_ALGORITHM_ID_128_EIA2: + security_128_eia2(&k_rrc_int[16], + 1, + 1, + 1, + varShortMAC_packed, + 10, + mac_key); + break; + default: + rrc_log->info("Unsupported integrity algorithm during reestablishment\n"); + return; + } // Prepare ConnectionRestalishmentRequest packet ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REEST_REQ; - ul_ccch_msg.msg.rrc_con_reest_req.ue_id.c_rnti = uernti.crnti; - ul_ccch_msg.msg.rrc_con_reest_req.ue_id.phys_cell_id = cell.id; - ul_ccch_msg.msg.rrc_con_reest_req.ue_id.short_mac_i = mac_key[2] << 8 | mac_key[3]; - ul_ccch_msg.msg.rrc_con_reest_req.cause = LIBLTE_RRC_CON_REEST_REQ_CAUSE_OTHER_FAILURE; - liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); + ul_ccch_msg.msg.rrc_con_reest_req.ue_id.c_rnti = crnti; + ul_ccch_msg.msg.rrc_con_reest_req.ue_id.phys_cell_id = phy->get_current_pci(); + ul_ccch_msg.msg.rrc_con_reest_req.ue_id.short_mac_i = mac_key[1] << 8 | mac_key[0]; + ul_ccch_msg.msg.rrc_con_reest_req.cause = cause; rrc_log->info("Initiating RRC Connection Reestablishment Procedure\n"); rrc_log->console("RRC Connection Reestablishment\n"); @@ -904,33 +913,15 @@ void rrc::send_con_restablish_request() { // Actions following cell reselection 5.3.7.3 void rrc::con_restablish_cell_reselected() { + liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); + rrc_log->info("Cell Selection finished. Initiating transmission of RRC Connection Reestablishment Request\n"); mac_timers->timer_get(t301)->reset(); mac_timers->timer_get(t301)->run(); mac_timers->timer_get(t311)->stop(); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - byte_buffer_t *pdcp_buf = pool_allocate; - srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); - pdcp_buf->N_bytes = bit_buf.N_bits / 8; - - // Set UE contention resolution ID in MAC - uint64_t uecri = 0; - uint8_t *ue_cri_ptr = (uint8_t *) &uecri; - uint32_t nbytes = 6; - for (uint32_t i = 0; i < nbytes; i++) { - ue_cri_ptr[nbytes - i - 1] = pdcp_buf->msg[i]; - } - rrc_log->debug("Setting UE contention resolution ID: %d\n", uecri); - mac->set_contention_id(uecri); + send_ul_ccch_msg(); - rrc_log->info("Sending RRC Connection Reestablishment Request on SRB0\n"); - pdcp->write_sdu(RB_ID_SRB0, pdcp_buf); } void rrc::send_con_restablish_complete() { @@ -993,10 +984,16 @@ void rrc::send_rrc_con_reconfig_complete(byte_buffer_t *pdu) { send_ul_dcch_msg(pdu); } -void rrc::ho_prepare() { +bool rrc::ho_prepare() { if (pending_mob_reconf) { rrc_log->info("Processing HO command to target PCell=%d\n", mob_reconf.mob_ctrl_info.target_pci); + int cell_idx = find_cell_idx(phy->get_current_earfcn(), mob_reconf.mob_ctrl_info.target_pci); + if (cell_idx < 0) { + rrc_log->error("Could not find target cell pci=%d\n", mob_reconf.mob_ctrl_info.target_pci); + return false; + } + // Section 5.3.5.4 mac_timers->timer_get(t310)->stop(); mac_timers->timer_get(t304)->set(this, liblte_rrc_t304_num[mob_reconf.mob_ctrl_info.t304]); @@ -1005,6 +1002,19 @@ void rrc::ho_prepare() { rrc_log->warning("Received mobilityControlInfo for inter-frequency handover\n"); } + // Save cell and current configuration + ho_src_cell_idx = find_cell_idx(phy->get_current_earfcn(), phy->get_current_pci()); + if (ho_src_cell_idx < 0) { + rrc_log->error("Source cell not found in known cells. Reconnecting to cell 0 in case of failure\n"); + ho_src_cell_idx = 0; + } + phy->get_config(&ho_src_phy_cfg); + mac->get_config(&ho_src_mac_cfg); + mac_interface_rrc::ue_rnti_t uernti; + mac->get_rntis(&uernti); + ho_src_rnti = uernti.crnti; + + // Reset/Reestablish stack phy->meas_reset(); mac->wait_uplink(); pdcp->reestablish(); @@ -1014,21 +1024,10 @@ void rrc::ho_prepare() { mac->set_ho_rnti(mob_reconf.mob_ctrl_info.new_ue_id, mob_reconf.mob_ctrl_info.target_pci); apply_rr_config_common_dl(&mob_reconf.mob_ctrl_info.rr_cnfg_common); - bool found = false; - for (uint32_t i = 0; i < MAX_KNOWN_CELLS && known_cells[i].earfcn; i++) { - if (known_cells[i].earfcn == phy->get_current_earfcn() && - known_cells[i].phy_cell.id == mob_reconf.mob_ctrl_info.target_pci) { - rrc_log->info("Selecting new cell pci=%d\n", known_cells[i].phy_cell.id); - if (!phy->cell_handover(known_cells[i].phy_cell)) { - rrc_log->error("Could not synchronize with target cell pci=%d\n", known_cells[i].phy_cell.id); - } - found = true; - break; - } - } - if (!found) { - rrc_log->error("Could not find target cell pci=%d\n", mob_reconf.mob_ctrl_info.target_pci); - return; + rrc_log->info("Selecting new cell pci=%d\n", known_cells[cell_idx].phy_cell.id); + if (!phy->cell_handover(known_cells[cell_idx].phy_cell)) { + rrc_log->error("Could not synchronize with target cell pci=%d\n", known_cells[cell_idx].phy_cell.id); + return false; } if (mob_reconf.mob_ctrl_info.rach_cnfg_ded_present) { @@ -1049,6 +1048,7 @@ void rrc::ho_prepare() { pdcp->config_security(1, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); send_rrc_con_reconfig_complete(NULL); } + return true; } void rrc::ho_ra_completed(bool ra_successful) { @@ -1079,6 +1079,23 @@ void rrc::ho_ra_completed(bool ra_successful) { } } +// This is T304 expiry 5.3.5.6 +void rrc::ho_failed() { + + // Instruct PHY to resync with source PCI + if (!phy->cell_handover(known_cells[ho_src_cell_idx].phy_cell)) { + rrc_log->error("Could not synchronize with target cell pci=%d\n", known_cells[ho_src_cell_idx].phy_cell.id); + return; + } + + // Set previous PHY/MAC configuration + phy->set_config(&ho_src_phy_cfg); + mac->set_config(&ho_src_mac_cfg); + + // Start the Reestablishment Procedure + send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_HANDOVER_FAILURE, ho_src_rnti); +} + void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig, byte_buffer_t *pdu) { uint32_t i; @@ -1347,18 +1364,16 @@ void rrc::write_pdu_pcch(byte_buffer_t *pdu) { * Packet processing * * -* *******************************************************************************/ -void rrc::send_ul_dcch_msg(byte_buffer_t *pdu) +byte_buffer_t* rrc::byte_align_and_pack(byte_buffer_t *pdu) { - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Byte align and pack the message bits for PDCP if ((bit_buf.N_bits % 8) != 0) { for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) bit_buf.msg[bit_buf.N_bits + i] = 0; bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); } + // Reset and reuse sdu buffer if provided byte_buffer_t *pdcp_buf = pdu; @@ -1372,8 +1387,37 @@ void rrc::send_ul_dcch_msg(byte_buffer_t *pdu) pdcp_buf->N_bytes = bit_buf.N_bits / 8; pdcp_buf->set_timestamp(); + return pdcp_buf; +} + +void rrc::send_ul_ccch_msg(byte_buffer_t *pdu) +{ + liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); + pdu = byte_align_and_pack(pdu); + + // Set UE contention resolution ID in MAC + uint64_t uecri = 0; + uint8_t *ue_cri_ptr = (uint8_t *) &uecri; + uint32_t nbytes = 6; + for (uint32_t i = 0; i < nbytes; i++) { + ue_cri_ptr[nbytes - i - 1] = pdu->msg[i]; + } + + rrc_log->debug("Setting UE contention resolution ID: %d\n", uecri); + mac->set_contention_id(uecri); + + rrc_log->info("Sending %s\n", liblte_rrc_ul_ccch_msg_type_text[ul_ccch_msg.msg_type]); + pdcp->write_sdu(RB_ID_SRB0, pdu); +} + +void rrc::send_ul_dcch_msg(byte_buffer_t *pdu) +{ + liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); + + pdu = byte_align_and_pack(pdu); + rrc_log->info("Sending %s\n", liblte_rrc_ul_dcch_msg_type_text[ul_dcch_msg.msg_type]); - pdcp->write_sdu(RB_ID_SRB1, pdcp_buf); + pdcp->write_sdu(RB_ID_SRB1, pdu); } void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { @@ -1489,7 +1533,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { transaction_id = dl_dcch_msg.msg.ue_cap_enquiry.rrc_transaction_id; for (uint32_t i = 0; i < dl_dcch_msg.msg.ue_cap_enquiry.N_ue_cap_reqs; i++) { if (LIBLTE_RRC_RAT_TYPE_EUTRA == dl_dcch_msg.msg.ue_cap_enquiry.ue_capability_request[i]) { - send_rrc_ue_cap_info(lcid, pdu); + send_rrc_ue_cap_info(pdu); break; } } @@ -1525,9 +1569,8 @@ void rrc::enable_capabilities() { phy->set_config_64qam_en(enable_ul_64); } -void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) { +void rrc::send_rrc_ue_cap_info(byte_buffer_t *pdu) { rrc_log->debug("Preparing UE Capability Info\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_UE_CAPABILITY_INFO; ul_dcch_msg.msg.ue_capability_info.rrc_transaction_id = transaction_id; @@ -1575,18 +1618,7 @@ void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) { liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); - pdu->N_bytes = bit_buf.N_bits / 8; - pdu->set_timestamp(); - - rrc_log->info("Sending UE Capability Info\n"); - pdcp->write_sdu(lcid, pdu); + send_ul_dcch_msg(pdu); } From 997a22a1c6605ed2e33029884436ee0d6027b6c6 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Sat, 2 Dec 2017 20:53:09 +0100 Subject: [PATCH 22/42] Disabled test Restablishment --- srsue/src/upper/rrc.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 6c92a1bda..813ebec91 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -265,12 +265,13 @@ void rrc::run_thread() { } break; case RRC_STATE_CONNECTED: + /* failure_test++; if (failure_test >= 100) { mac_interface_rrc::ue_rnti_t ue_rnti; mac->get_rntis(&ue_rnti); send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_OTHER_FAILURE, ue_rnti.crnti); - } + }*/ // Take measurements, cell reselection, etc break; case RRC_STATE_HO_PREPARE: @@ -2015,7 +2016,7 @@ void rrc::handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup) { void rrc::handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup) { mac_timers->timer_get(t301)->stop(); - // TODO: Restablish DRB1. Not done because never was suspended + // TODO: Reestablish DRB1. Not done because never was suspended // Apply the Radio Resource configuration apply_rr_config_dedicated(&setup->rr_cnfg); From 5c31800ccb3c1c149f90404346f3970625476fe0 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Sat, 2 Dec 2017 22:43:35 +0100 Subject: [PATCH 23/42] Fixed HO with ciphering --- lib/include/srslte/interfaces/ue_interfaces.h | 5 +- lib/include/srslte/upper/pdcp.h | 4 + lib/include/srslte/upper/rlc.h | 1 - lib/src/upper/pdcp.cc | 12 ++ lib/src/upper/pdcp_entity.cc | 1 + lib/src/upper/rlc.cc | 5 - srsue/hdr/upper/rrc.h | 24 --- srsue/src/phy/phch_recv.cc | 146 +++++++++--------- srsue/src/upper/rrc.cc | 23 ++- 9 files changed, 111 insertions(+), 110 deletions(-) diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index f99f10c9a..540ccb715 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -191,7 +191,6 @@ class rrc_interface_rlc { public: virtual void max_retx_attempted() = 0; - virtual std::string get_rb_name(uint32_t lcid) = 0; }; // PDCP interface for GW @@ -215,6 +214,10 @@ public: uint8_t *k_int_, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0; + virtual void config_security_all(uint8_t *k_enc_, + uint8_t *k_int_, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0; virtual void enable_integrity(uint32_t lcid) = 0; virtual void enable_encryption(uint32_t lcid) = 0; }; diff --git a/lib/include/srslte/upper/pdcp.h b/lib/include/srslte/upper/pdcp.h index e6483809d..584b231a3 100644 --- a/lib/include/srslte/upper/pdcp.h +++ b/lib/include/srslte/upper/pdcp.h @@ -63,6 +63,10 @@ public: uint8_t *k_int, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo); + void config_security_all(uint8_t *k_enc, + uint8_t *k_int, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo); void enable_integrity(uint32_t lcid); void enable_encryption(uint32_t lcid); diff --git a/lib/include/srslte/upper/rlc.h b/lib/include/srslte/upper/rlc.h index 8e40f7b6e..17f6bd82c 100644 --- a/lib/include/srslte/upper/rlc.h +++ b/lib/include/srslte/upper/rlc.h @@ -66,7 +66,6 @@ public: void write_sdu(uint32_t lcid, byte_buffer_t *sdu); bool rb_is_um(uint32_t lcid); - std::string get_rb_name(uint32_t lcid); // MAC interface uint32_t get_buffer_state(uint32_t lcid); diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc index b3d86dfff..5d3b4d061 100644 --- a/lib/src/upper/pdcp.cc +++ b/lib/src/upper/pdcp.cc @@ -116,6 +116,18 @@ void pdcp::config_security(uint32_t lcid, pdcp_array[lcid].config_security(k_enc, k_int, cipher_algo, integ_algo); } +void pdcp::config_security_all(uint8_t *k_enc, + uint8_t *k_int, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo) +{ + for(uint32_t i=0;irb_is_um(lcid)) { tx_count = 0; + rx_count = 0; } } } diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc index baf3c6247..16319c268 100644 --- a/lib/src/upper/rlc.cc +++ b/lib/src/upper/rlc.cc @@ -135,11 +135,6 @@ bool rlc::rb_is_um(uint32_t lcid) { return rlc_array[lcid].get_mode()==RLC_MODE_UM; } -std::string rlc::get_rb_name(uint32_t lcid) -{ - return rrc->get_rb_name(lcid); -} - /******************************************************************************* MAC interface *******************************************************************************/ diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index 5499290e8..b5df0900a 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -238,30 +238,6 @@ private: bool thread_running; void run_thread(); - // Radio bearers - typedef enum{ - RB_ID_SRB0 = 0, - RB_ID_SRB1, - RB_ID_SRB2, - RB_ID_DRB1, - RB_ID_DRB2, - RB_ID_DRB3, - RB_ID_DRB4, - RB_ID_DRB5, - RB_ID_DRB6, - RB_ID_DRB7, - RB_ID_DRB8, - RB_ID_MAX - } rb_id_t; - - std::string get_rb_name(uint32_t lcid) { - if (lcid < RB_ID_MAX) { - return rb_id_str[lcid]; - } else { - return std::string("INVALID_RB"); - } - } - // Measurements sub-class class rrc_meas { public: diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index cd95f6d98..7a78fc11c 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -672,9 +672,9 @@ void phch_recv::run_thread() workers_pool->start_worker(worker); // Substract PSS/SSS from current cell before computing intra-frequency - if ((tti%5) == 0) { + /*if ((tti%5) == 0) { substract_sync(buffer[0], cell.nof_prb, &ue_sync.strack); - } + }*/ intra_freq_meas.write(tti, buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb)); out_of_sync_cnt = 0; break; @@ -1164,7 +1164,7 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx) float snr = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)); if (cnt == 0) { - mean_rsrp = rsrp; + mean_rsrp = rsrp; mean_rsrq = rsrq; mean_snr = snr; } else { @@ -1175,7 +1175,7 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx) } cnt++; - log_h->info("SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n", + log_h->debug("SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n", cnt, nof_subframes, sf_idx, rsrp, snr); if (cnt >= nof_subframes) { @@ -1259,76 +1259,76 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, for (uint32_t n_id_2=0;n_id_2<3;n_id_2++) { - if (cell.id%3 != n_id_2) { - srslte_sync_set_N_id_2(&sync_find, n_id_2); - - srslte_sync_find_ret_t sync_res; - do { - - srslte_sync_reset(&sync_find); - srslte_sync_cfo_reset(&sync_find); - - sync_res = srslte_sync_find(&sync_find, input_buffer, 0, &peak_idx); - - switch(sync_res) { - case SRSLTE_SYNC_ERROR: - return SRSLTE_ERROR; - fprintf(stderr, "Error finding correlation peak\n"); - return SRSLTE_ERROR; - case SRSLTE_SYNC_FOUND: - sf_idx = srslte_sync_get_sf_idx(&sync_find); - cell_id = srslte_sync_get_cell_id(&sync_find); - - if (cell_id >= 0) { - // We found the same cell as before, look another N_id_2 - if ((uint32_t) cell_id == found_cell.id) { - sync_res = SRSLTE_SYNC_NOFOUND; - } else { - // We found a new cell ID - found_cell.id = cell_id; - found_cell.nof_ports = 1; // Use port 0 only for measurement - measure_p.set_cell(found_cell); - - // Correct CFO - srslte_cfo_correct(&sync_find.cfo_corr_frame, - input_buffer, - input_cfo_corrected, - -srslte_sync_get_cfo(&sync_find)/sync_find.fft_size); - - switch(measure_p.run_multiple_subframes(input_cfo_corrected, peak_idx, sf_idx, nof_sf)) { - case measure::MEASURE_OK: - cells[nof_cells].pci = found_cell.id; - cells[nof_cells].rsrp = measure_p.rsrp(); - cells[nof_cells].rsrq = measure_p.rsrq(); - cells[nof_cells].offset = measure_p.frame_st_idx(); - nof_cells++; - - // Substract interference from input buffer (for the next cell) - substract_sync(&input_buffer[measure_p.frame_st_idx()], cell.nof_prb, &sync_find); - - Info("INTRA: Found neighbour cell: pci=%d, rsrp=%.1f dBm, peak_idx=%d, n_id_2=%d, cfo=%.1f Hz\n", - cell_id, measure_p.rsrq(), peak_idx, n_id_2, 15000*srslte_sync_get_cfo(&sync_find)); - - break; - case measure::ERROR: - Error("Measuring neighbour cell\n"); - return SRSLTE_ERROR; - default: - break; - } - } - } else { + srslte_sync_set_N_id_2(&sync_find, n_id_2); + + srslte_sync_find_ret_t sync_res; + //do { + + srslte_sync_reset(&sync_find); + srslte_sync_cfo_reset(&sync_find); + + sync_res = srslte_sync_find(&sync_find, input_buffer, 0, &peak_idx); + + switch(sync_res) { + case SRSLTE_SYNC_ERROR: + return SRSLTE_ERROR; + fprintf(stderr, "Error finding correlation peak\n"); + return SRSLTE_ERROR; + case SRSLTE_SYNC_FOUND: + sf_idx = srslte_sync_get_sf_idx(&sync_find); + cell_id = srslte_sync_get_cell_id(&sync_find); + + if (cell_id >= 0) { + // We found the same cell as before, look another N_id_2 + if ((uint32_t) cell_id == found_cell.id || (uint32_t) cell_id == cell.id) { sync_res = SRSLTE_SYNC_NOFOUND; + } else { + // We found a new cell ID + found_cell.id = cell_id; + found_cell.nof_ports = 1; // Use port 0 only for measurement + measure_p.set_cell(found_cell); + + // Correct CFO + /* + srslte_cfo_correct(&sync_find.cfo_corr_frame, + input_buffer, + input_cfo_corrected, + -srslte_sync_get_cfo(&sync_find)/sync_find.fft_size); + */ + + switch(measure_p.run_multiple_subframes(input_buffer, peak_idx, sf_idx, nof_sf)) { + case measure::MEASURE_OK: + cells[nof_cells].pci = found_cell.id; + cells[nof_cells].rsrp = measure_p.rsrp(); + cells[nof_cells].rsrq = measure_p.rsrq(); + cells[nof_cells].offset = measure_p.frame_st_idx(); + nof_cells++; + + // Substract interference from input buffer (for the next cell) + //substract_sync(&input_buffer[measure_p.frame_st_idx()], cell.nof_prb, &sync_find); + + Info("INTRA: Found neighbour cell: PCI=%03d, RSRP=%5.1f dBm, peak_idx=%5d, peak_value=%3.2f n_id_2=%d, CFO=%6.1f Hz\n", + cell_id, measure_p.rsrp(), measure_p.frame_st_idx(), sync_find.peak_value, n_id_2, 15000*srslte_sync_get_cfo(&sync_find)); + + break; + case measure::ERROR: + Error("Measuring neighbour cell\n"); + return SRSLTE_ERROR; + default: + break; + } } - break; - case SRSLTE_SYNC_FOUND_NOSPACE: - /* If a peak was found but there is not enough space for SSS/CP detection, discard a few samples */ - break; - default: - break; - } - } while(sync_res == SRSLTE_SYNC_FOUND); - } + } else { + sync_res = SRSLTE_SYNC_NOFOUND; + } + break; + case SRSLTE_SYNC_FOUND_NOSPACE: + /* If a peak was found but there is not enough space for SSS/CP detection, discard a few samples */ + break; + default: + break; + } + //} while(sync_res == SRSLTE_SYNC_FOUND); } return nof_cells; } @@ -1476,8 +1476,6 @@ void phch_recv::intra_measure::run_thread() } if (running) { - Info("INTRA: Running intra-frequency measurements\n"); - // Read 15 ms data from buffer srslte_ringbuffer_read(&ring_buffer, search_buffer, CAPTURE_LEN_SF*current_sflen*sizeof(cf_t)); int found_cells = scell.find_cells(search_buffer, common->rx_gain_offset, primary_cell, CAPTURE_LEN_SF, info); diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 813ebec91..346a04ac0 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -30,6 +30,7 @@ #include #include #include +#include #include "upper/rrc.h" #include "srslte/asn1/liblte_rrc.h" #include "srslte/common/security.h" @@ -1041,12 +1042,24 @@ bool rrc::ho_prepare() { int ncc = -1; if (mob_reconf.sec_cnfg_ho_present) { ncc = mob_reconf.sec_cnfg_ho.intra_lte.next_hop_chaining_count; + if (mob_reconf.sec_cnfg_ho.intra_lte.key_change_ind) { + rrc_log->console("keyChangeIndicator in securityConfigHO not supported\n"); + return false; + } + if (mob_reconf.sec_cnfg_ho.intra_lte.sec_alg_cnfg_present) { + cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) mob_reconf.sec_cnfg_ho.intra_lte.sec_alg_cnfg.cipher_alg; + integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) mob_reconf.sec_cnfg_ho.intra_lte.sec_alg_cnfg.int_alg; + rrc_log->console("Warning changed Cipering to %s and Integrity to %s\n", + ciphering_algorithm_id_text[cipher_algo], + integrity_algorithm_id_text[integ_algo]); + } } usim->generate_as_keys_ho(mob_reconf.mob_ctrl_info.target_pci, phy->get_current_earfcn(), ncc, k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); - pdcp->config_security(1, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); + + pdcp->config_security_all(k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); send_rrc_con_reconfig_complete(NULL); } return true; @@ -1423,7 +1436,7 @@ void rrc::send_ul_dcch_msg(byte_buffer_t *pdu) void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { - rrc_log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU", get_rb_name(lcid).c_str()); + rrc_log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU", get_rb_name(lcid)); switch (state) { case RRC_STATE_CONNECTING: send_con_setup_complete(sdu); @@ -1438,7 +1451,7 @@ void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { } void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { - rrc_log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", get_rb_name(lcid).c_str()); + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", get_rb_name(lcid)); switch (lcid) { case RB_ID_SRB0: @@ -1528,8 +1541,8 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { nas->get_k_asme(k_asme, 32); usim->generate_as_keys(k_asme, nas->get_ul_count()-1, k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); rrc_log->debug_hex(k_rrc_enc, 32, "RRC encryption key - k_rrc_enc"); - rrc_log->debug_hex(k_rrc_int, 32, "RRC integrity key - k_rrc_int"); - rrc_log->debug_hex(k_up_enc, 32, "UP encryption key - k_up_enc"); + rrc_log->debug_hex(k_rrc_int, 32, "RRC integrity key - k_rrc_int"); + rrc_log->debug_hex(k_up_enc, 32, "UP encryption key - k_up_enc"); // Configure PDCP for security pdcp->config_security(lcid, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); From cfb059f0c2d8657757e834b1ceba6f3b05745d72 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Sat, 2 Dec 2017 22:52:17 +0100 Subject: [PATCH 24/42] Restart rx_counter for SRB in PDCP when restablishing --- lib/src/upper/pdcp_entity.cc | 1 + srsue/src/upper/rrc.cc | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/upper/pdcp_entity.cc b/lib/src/upper/pdcp_entity.cc index ceb89a0bb..b4cc5b9d5 100644 --- a/lib/src/upper/pdcp_entity.cc +++ b/lib/src/upper/pdcp_entity.cc @@ -81,6 +81,7 @@ void pdcp_entity::reestablish() { // For SRBs if (cfg.is_control) { tx_count = 0; + rx_count = 0; } else { if (rlc->rb_is_um(lcid)) { tx_count = 0; diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 346a04ac0..461a4f9ee 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -514,7 +514,7 @@ void rrc::select_next_cell_in_plmn() { } void rrc::new_phy_meas(float rsrp, float rsrq, uint32_t tti, uint32_t earfcn, uint32_t pci) { - if (state == RRC_STATE_CONNECTED) { + if (state != RRC_STATE_IDLE) { measurements.new_phy_meas(earfcn, pci, rsrp, rsrq, tti); } else { // If measurement is of the serving cell, evaluate cell reselection criteria From 324ba02481050a4f36479d50725ff4d346908d6c Mon Sep 17 00:00:00 2001 From: Paul Sutton Date: Sun, 3 Dec 2017 18:16:05 +0000 Subject: [PATCH 25/42] Fix for PDCP EEA1 --- lib/src/upper/pdcp_entity.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/src/upper/pdcp_entity.cc b/lib/src/upper/pdcp_entity.cc index 0ac426a6e..731245e4f 100644 --- a/lib/src/upper/pdcp_entity.cc +++ b/lib/src/upper/pdcp_entity.cc @@ -301,6 +301,7 @@ void pdcp_entity::cipher_decrypt(uint8_t *ct, ct, ct_len, msg_tmp.msg); + memcpy(msg, msg_tmp.msg, ct_len); break; case CIPHERING_ALGORITHM_ID_128_EEA2: security_128_eea2(&(k_enc[16]), @@ -311,9 +312,9 @@ void pdcp_entity::cipher_decrypt(uint8_t *ct, ct_len, msg_tmp.msg); memcpy(msg, msg_tmp.msg, ct_len); - break; - default: - break; + break; + default: + break; } } @@ -325,7 +326,8 @@ void pdcp_entity::run_thread() while(running) { rx_pdu_queue.read(&pdu); - log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", get_rb_name(lcid)); + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU, do_integrity = %s, do_encryption = %s", + get_rb_name(lcid), (do_integrity) ? "true" : "false", (do_encryption) ? "true" : "false"); // Handle SRB messages switch(lcid) From 48dfc08fa3d84e7d58cc2242511b31fdaeea6dc8 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Sun, 3 Dec 2017 22:13:07 -0600 Subject: [PATCH 26/42] Fixed SIC for PSS using channel estimates, added option to disable it (not usable on synchronous same-site cells). Use PSS CE in SSS decoding --- lib/examples/pdsch_ue.c | 2 +- lib/examples/synch_file.c | 28 +-- lib/include/srslte/interfaces/ue_interfaces.h | 1 + lib/include/srslte/phy/sync/pss.h | 44 +++-- lib/include/srslte/phy/sync/sss.h | 28 +-- lib/include/srslte/phy/sync/sync.h | 14 +- lib/src/phy/sync/find_sss.c | 10 +- lib/src/phy/sync/pss.c | 98 ++++++---- lib/src/phy/sync/sss.c | 22 +-- lib/src/phy/sync/sync.c | 72 +++---- lib/src/phy/sync/test/pss_file.c | 42 ++-- lib/src/phy/sync/test/pss_mex.c | 12 +- lib/src/phy/sync/test/pss_usrp.c | 44 ++--- lib/src/phy/sync/test/sss_mex.c | 20 +- lib/src/phy/ue/ue_sync.c | 4 +- srsue/hdr/phy/phch_recv.h | 5 +- srsue/src/mac/proc_ra.cc | 8 +- srsue/src/main.cc | 5 +- srsue/src/phy/phch_recv.cc | 182 +++++++++--------- srsue/src/upper/rrc.cc | 4 +- srsue/ue.conf.example | 5 + 21 files changed, 341 insertions(+), 309 deletions(-) diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index ae43a5260..6293d0e70 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -998,7 +998,7 @@ void *plot_thread_run(void *arg) { if (!prog_args.input_file_name) { if (plot_track) { - srslte_pss_synch_t *pss_obj = srslte_sync_get_cur_pss_obj(&ue_sync.strack); + srslte_pss_t *pss_obj = srslte_sync_get_cur_pss_obj(&ue_sync.strack); int max = srslte_vec_max_fi(pss_obj->conv_output_avg, pss_obj->frame_size+pss_obj->fft_size-1); srslte_vec_sc_prod_fff(pss_obj->conv_output_avg, 1/pss_obj->conv_output_avg[max], diff --git a/lib/examples/synch_file.c b/lib/examples/synch_file.c index 178e56e99..4d553bd38 100644 --- a/lib/examples/synch_file.c +++ b/lib/examples/synch_file.c @@ -102,8 +102,8 @@ void parse_args(int argc, char **argv) { int main(int argc, char **argv) { srslte_filesource_t fsrc; srslte_filesink_t fsink; - srslte_pss_synch_t pss[3]; // One for each N_id_2 - srslte_sss_synch_t sss[3]; // One for each N_id_2 + srslte_pss_t pss[3]; // One for each N_id_2 + srslte_sss_t sss[3]; // One for each N_id_2 srslte_cfo_t cfocorr; int peak_pos[3]; float *cfo; @@ -163,19 +163,19 @@ int main(int argc, char **argv) { * a) requries more memory but has less latency and is paralellizable. */ for (N_id_2=0;N_id_2<3;N_id_2++) { - if (srslte_pss_synch_init(&pss[N_id_2], frame_length)) { + if (srslte_pss_init(&pss[N_id_2], frame_length)) { fprintf(stderr, "Error initializing PSS object\n"); exit(-1); } - if (srslte_pss_synch_set_N_id_2(&pss[N_id_2], N_id_2)) { + if (srslte_pss_set_N_id_2(&pss[N_id_2], N_id_2)) { fprintf(stderr, "Error initializing N_id_2\n"); exit(-1); } - if (srslte_sss_synch_init(&sss[N_id_2], 128)) { + if (srslte_sss_init(&sss[N_id_2], 128)) { fprintf(stderr, "Error initializing SSS object\n"); exit(-1); } - if (srslte_sss_synch_set_N_id_2(&sss[N_id_2], N_id_2)) { + if (srslte_sss_set_N_id_2(&sss[N_id_2], N_id_2)) { fprintf(stderr, "Error initializing N_id_2\n"); exit(-1); } @@ -199,10 +199,10 @@ int main(int argc, char **argv) { if (force_N_id_2 != -1) { N_id_2 = force_N_id_2; - peak_pos[N_id_2] = srslte_pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); + peak_pos[N_id_2] = srslte_pss_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); } else { for (N_id_2=0;N_id_2<3;N_id_2++) { - peak_pos[N_id_2] = srslte_pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); + peak_pos[N_id_2] = srslte_pss_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); } float max_value=-99999; N_id_2=-1; @@ -220,13 +220,13 @@ int main(int argc, char **argv) { sss_idx = peak_pos[N_id_2]-2*(symbol_sz+SRSLTE_CP_LEN(symbol_sz,SRSLTE_CP_NORM_LEN)); if (sss_idx >= 0) { - srslte_sss_synch_m0m1_diff(&sss[N_id_2], &input[sss_idx], + srslte_sss_m0m1_diff(&sss[N_id_2], &input[sss_idx], &m0, &m0_value, &m1, &m1_value); - cfo[frame_cnt] = srslte_pss_synch_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2]-128]); + cfo[frame_cnt] = srslte_pss_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2]-128]); printf("\t%d\t%d\t%d\t%d\t%.3f\t\t%3d\t%d\t%d\t%.3f\n", - frame_cnt,N_id_2, srslte_sss_synch_N_id_1(&sss[N_id_2], m0, m1), - srslte_sss_synch_subframe(m0, m1), peak_value[N_id_2], + frame_cnt,N_id_2, srslte_sss_N_id_1(&sss[N_id_2], m0, m1), + srslte_sss_subframe(m0, m1), peak_value[N_id_2], peak_pos[N_id_2], m0, m1, cfo[frame_cnt]); } @@ -254,8 +254,8 @@ int main(int argc, char **argv) { printf("Average CFO: %.3f\n", cfo_mean); for (N_id_2=0;N_id_2<3;N_id_2++) { - srslte_pss_synch_free(&pss[N_id_2]); - srslte_sss_synch_free(&sss[N_id_2]); + srslte_pss_free(&pss[N_id_2]); + srslte_sss_free(&sss[N_id_2]); } srslte_filesource_free(&fsrc); diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 540ccb715..e8a33c207 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -488,6 +488,7 @@ typedef struct { std::string sss_algorithm; float estimator_fil_w; bool rssi_sensor_enabled; + bool sic_pss_enabled; } phy_args_t; diff --git a/lib/include/srslte/phy/sync/pss.h b/lib/include/srslte/phy/sync/pss.h index aba84f5cd..922bc0286 100644 --- a/lib/include/srslte/phy/sync/pss.h +++ b/lib/include/srslte/phy/sync/pss.h @@ -29,9 +29,9 @@ * * Description: Primary synchronization signal (PSS) generation and detection. * - * The srslte_pss_synch_t object provides functions for fast + * The srslte_pss_t object provides functions for fast * computation of the crosscorrelation between the PSS and received - * signal and CFO estimation. Also, the function srslte_pss_synch_tperiodic() + * signal and CFO estimation. Also, the function srslte_pss_tperiodic() * is designed to be called periodically every subframe, taking * care of the correct data alignment with respect to the PSS sequence. * @@ -61,7 +61,7 @@ /* PSS processing options */ -#define SRSLTE_PSS_ACCUMULATE_ABS // If enabled, accumulates the correlation absolute value on consecutive calls to srslte_pss_synch_find_pss +#define SRSLTE_PSS_ACCUMULATE_ABS // If enabled, accumulates the correlation absolute value on consecutive calls to srslte_pss_find_pss #define SRSLTE_PSS_RETURN_PSR // If enabled returns peak to side-lobe ratio, otherwise returns absolute peak value @@ -85,6 +85,7 @@ typedef struct SRSLTE_API { cf_t *pss_signal_freq_full[3]; cf_t *pss_signal_time[3]; + cf_t *pss_signal_time_scale[3]; cf_t pss_signal_freq[3][SRSLTE_PSS_LEN]; // One sequence for each N_id_2 cf_t *tmp_input; @@ -100,41 +101,48 @@ typedef struct SRSLTE_API { cf_t tmp_fft[SRSLTE_SYMBOL_SZ_MAX]; cf_t tmp_fft2[SRSLTE_SYMBOL_SZ_MAX]; -}srslte_pss_synch_t; + cf_t tmp_ce[SRSLTE_PSS_LEN]; + + bool chest_on_filter; + +}srslte_pss_t; typedef enum { PSS_TX, PSS_RX } pss_direction_t; /* Basic functionality */ -SRSLTE_API int srslte_pss_synch_init_fft(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_init_fft(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size); -SRSLTE_API int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_init_fft_offset(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, int cfo_i); -SRSLTE_API int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_init_fft_offset_decim(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, int cfo_i, int decimate); -SRSLTE_API int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, +SRSLTE_API int srslte_pss_resize(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, int offset); -SRSLTE_API int srslte_pss_synch_init(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_init(srslte_pss_t *q, uint32_t frame_size); -SRSLTE_API void srslte_pss_synch_free(srslte_pss_synch_t *q); +SRSLTE_API void srslte_pss_free(srslte_pss_t *q); -SRSLTE_API void srslte_pss_synch_reset(srslte_pss_synch_t *q); +SRSLTE_API void srslte_pss_reset(srslte_pss_t *q); -SRSLTE_API void srslte_pss_synch_filter_enable(srslte_pss_synch_t *q, +SRSLTE_API void srslte_pss_filter_enable(srslte_pss_t *q, bool enable); -SRSLTE_API void srslte_pss_synch_filter(srslte_pss_synch_t *q, +SRSLTE_API void srslte_pss_sic(srslte_pss_t *q, + cf_t *input); + +SRSLTE_API void srslte_pss_filter(srslte_pss_t *q, const cf_t *input, cf_t *output); @@ -151,21 +159,21 @@ SRSLTE_API void srslte_pss_put_slot(cf_t *pss_signal, uint32_t nof_prb, srslte_cp_t cp); -SRSLTE_API void srslte_pss_synch_set_ema_alpha(srslte_pss_synch_t *q, +SRSLTE_API void srslte_pss_set_ema_alpha(srslte_pss_t *q, float alpha); -SRSLTE_API int srslte_pss_synch_set_N_id_2(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_set_N_id_2(srslte_pss_t *q, uint32_t N_id_2); -SRSLTE_API int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_find_pss(srslte_pss_t *q, const cf_t *input, float *corr_peak_value); -SRSLTE_API int srslte_pss_synch_chest(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_chest(srslte_pss_t *q, const cf_t *input, cf_t ce[SRSLTE_PSS_LEN]); -SRSLTE_API float srslte_pss_synch_cfo_compute(srslte_pss_synch_t* q, +SRSLTE_API float srslte_pss_cfo_compute(srslte_pss_t* q, const cf_t *pss_recv); #endif // PSS_ diff --git a/lib/include/srslte/phy/sync/sss.h b/lib/include/srslte/phy/sync/sss.h index 4a0942d61..9f77d1ce6 100644 --- a/lib/include/srslte/phy/sync/sss.h +++ b/lib/include/srslte/phy/sync/sss.h @@ -83,17 +83,17 @@ typedef struct SRSLTE_API { float corr_output_m0[SRSLTE_SSS_N]; float corr_output_m1[SRSLTE_SSS_N]; -}srslte_sss_synch_t; +}srslte_sss_t; /* Basic functionality */ -SRSLTE_API int srslte_sss_synch_init(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_init(srslte_sss_t *q, uint32_t fft_size); -SRSLTE_API int srslte_sss_synch_resize(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_resize(srslte_sss_t *q, uint32_t fft_size); -SRSLTE_API void srslte_sss_synch_free(srslte_sss_synch_t *q); +SRSLTE_API void srslte_sss_free(srslte_sss_t *q); SRSLTE_API void srslte_sss_generate(float *signal0, float *signal5, @@ -104,10 +104,10 @@ SRSLTE_API void srslte_sss_put_slot(float *sss, uint32_t nof_prb, srslte_cp_t cp); -SRSLTE_API int srslte_sss_synch_set_N_id_2(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_set_N_id_2(srslte_sss_t *q, uint32_t N_id_2); -SRSLTE_API int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_m0m1_partial(srslte_sss_t *q, const cf_t *input, uint32_t M, cf_t ce[2*SRSLTE_SSS_N], @@ -116,7 +116,7 @@ SRSLTE_API int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q, uint32_t *m1, float *m1_value); -SRSLTE_API int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_m0m1_diff_coh(srslte_sss_t *q, const cf_t *input, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, @@ -124,7 +124,7 @@ SRSLTE_API int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, uint32_t *m1, float *m1_value); -SRSLTE_API int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_m0m1_diff(srslte_sss_t *q, const cf_t *input, uint32_t *m0, float *m0_value, @@ -132,25 +132,25 @@ SRSLTE_API int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, float *m1_value); -SRSLTE_API uint32_t srslte_sss_synch_subframe(uint32_t m0, +SRSLTE_API uint32_t srslte_sss_subframe(uint32_t m0, uint32_t m1); -SRSLTE_API int srslte_sss_synch_N_id_1(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_N_id_1(srslte_sss_t *q, uint32_t m0, uint32_t m1); -SRSLTE_API int srslte_sss_synch_frame(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_frame(srslte_sss_t *q, cf_t *input, uint32_t *subframe_idx, uint32_t *N_id_1); -SRSLTE_API void srslte_sss_synch_set_threshold(srslte_sss_synch_t *q, +SRSLTE_API void srslte_sss_set_threshold(srslte_sss_t *q, float threshold); -SRSLTE_API void srslte_sss_synch_set_symbol_sz(srslte_sss_synch_t *q, +SRSLTE_API void srslte_sss_set_symbol_sz(srslte_sss_t *q, uint32_t symbol_sz); -SRSLTE_API void srslte_sss_synch_set_subframe_sz(srslte_sss_synch_t *q, +SRSLTE_API void srslte_sss_set_subframe_sz(srslte_sss_t *q, uint32_t subframe_sz); #endif // SSS_ diff --git a/lib/include/srslte/phy/sync/sync.h b/lib/include/srslte/phy/sync/sync.h index 151c530b1..3146761ce 100644 --- a/lib/include/srslte/phy/sync/sync.h +++ b/lib/include/srslte/phy/sync/sync.h @@ -60,9 +60,9 @@ typedef enum {SSS_DIFF=0, SSS_PARTIAL_3=2, SSS_FULL=1} sss_alg_t; typedef struct SRSLTE_API { - srslte_pss_synch_t pss; - srslte_pss_synch_t pss_i[2]; - srslte_sss_synch_t sss; + srslte_pss_t pss; + srslte_pss_t pss_i[2]; + srslte_sss_t sss; srslte_cp_synch_t cp_synch; cf_t *cfo_i_corr[2]; int decimate; @@ -110,7 +110,7 @@ typedef struct SRSLTE_API { srslte_cfo_t cfo_corr_frame; srslte_cfo_t cfo_corr_symbol; - bool sss_filtering_enabled; + bool sss_channel_equalize; bool pss_filtering_enabled; cf_t sss_filt[SRSLTE_SYMBOL_SZ_MAX]; cf_t pss_filt[SRSLTE_SYMBOL_SZ_MAX]; @@ -186,8 +186,8 @@ SRSLTE_API int srslte_sync_get_cell_id(srslte_sync_t *q); SRSLTE_API void srslte_sync_set_pss_filt_enable(srslte_sync_t *q, bool enable); -SRSLTE_API void srslte_sync_set_sss_filt_enable(srslte_sync_t *q, - bool enable); +SRSLTE_API void srslte_sync_set_sss_eq_enable(srslte_sync_t *q, + bool enable); /* Gets the CFO estimation from the last call to synch_run() */ SRSLTE_API float srslte_sync_get_cfo(srslte_sync_t *q); @@ -227,7 +227,7 @@ SRSLTE_API void srslte_sync_set_cp(srslte_sync_t *q, SRSLTE_API void srslte_sync_sss_en(srslte_sync_t *q, bool enabled); -SRSLTE_API srslte_pss_synch_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q); +SRSLTE_API srslte_pss_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q); SRSLTE_API bool srslte_sync_sss_detected(srslte_sync_t *q); diff --git a/lib/src/phy/sync/find_sss.c b/lib/src/phy/sync/find_sss.c index 70b300bd3..6695d70c2 100644 --- a/lib/src/phy/sync/find_sss.c +++ b/lib/src/phy/sync/find_sss.c @@ -68,7 +68,7 @@ static void corr_all_sz_partial(cf_t z[SRSLTE_SSS_N], float s[SRSLTE_SSS_N][SRSL } } -static void extract_pair_sss(srslte_sss_synch_t *q, const cf_t *input, cf_t *ce, cf_t y[2][SRSLTE_SSS_N]) { +static void extract_pair_sss(srslte_sss_t *q, const cf_t *input, cf_t *ce, cf_t y[2][SRSLTE_SSS_N]) { cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX]; srslte_dft_run_c(&q->dftp_input, input, input_fft); @@ -88,10 +88,10 @@ static void extract_pair_sss(srslte_sss_synch_t *q, const cf_t *input, cf_t *ce, } -int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, const cf_t *input, uint32_t *m0, float *m0_value, +int srslte_sss_m0m1_diff(srslte_sss_t *q, const cf_t *input, uint32_t *m0, float *m0_value, uint32_t *m1, float *m1_value) { - return srslte_sss_synch_m0m1_diff_coh(q, input, NULL, m0, m0_value, m1, m1_value); + return srslte_sss_m0m1_diff_coh(q, input, NULL, m0, m0_value, m1, m1_value); } /* Differential SSS estimation. @@ -102,7 +102,7 @@ int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, const cf_t *input, uint32_ * */ -int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, const cf_t *input, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, +int srslte_sss_m0m1_diff_coh(srslte_sss_t *q, const cf_t *input, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, uint32_t *m1, float *m1_value) { @@ -145,7 +145,7 @@ int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, const cf_t *input, cf_ * Jung-In Kim, Jung-Su Han, Hee-Jin Roh and Hyung-Jin Choi */ -int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q, const cf_t *input, uint32_t M, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, +int srslte_sss_m0m1_partial(srslte_sss_t *q, const cf_t *input, uint32_t M, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, uint32_t *m1, float *m1_value) { diff --git a/lib/src/phy/sync/pss.c b/lib/src/phy/sync/pss.c index d93fe0896..1f56dfda9 100644 --- a/lib/src/phy/sync/pss.c +++ b/lib/src/phy/sync/pss.c @@ -35,7 +35,7 @@ #include "srslte/phy/utils/debug.h" -int srslte_pss_synch_init_N_id_2(cf_t *pss_signal_freq, cf_t *pss_signal_time, +int srslte_pss_init_N_id_2(cf_t *pss_signal_freq, cf_t *pss_signal_time, uint32_t N_id_2, uint32_t fft_size, int cfo_i) { srslte_dft_plan_t plan; cf_t pss_signal_pad[2048]; @@ -73,16 +73,16 @@ int srslte_pss_synch_init_N_id_2(cf_t *pss_signal_freq, cf_t *pss_signal_time, /* Initializes the PSS synchronization object with fft_size=128 */ -int srslte_pss_synch_init(srslte_pss_synch_t *q, uint32_t frame_size) { - return srslte_pss_synch_init_fft(q, frame_size, 128); +int srslte_pss_init(srslte_pss_t *q, uint32_t frame_size) { + return srslte_pss_init_fft(q, frame_size, 128); } -int srslte_pss_synch_init_fft(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size) { - return srslte_pss_synch_init_fft_offset(q, frame_size, fft_size, 0); +int srslte_pss_init_fft(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size) { + return srslte_pss_init_fft_offset(q, frame_size, fft_size, 0); } -int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { - return srslte_pss_synch_init_fft_offset_decim(q, frame_size, fft_size, offset, 1); +int srslte_pss_init_fft_offset(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { + return srslte_pss_init_fft_offset_decim(q, frame_size, fft_size, offset, 1); } /* Initializes the PSS synchronization object. @@ -90,7 +90,7 @@ int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size, * It correlates a signal of frame_size samples with the PSS sequence in the frequency * domain. The PSS sequence is transformed using fft_size samples. */ -int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, +int srslte_pss_init_fft_offset_decim(srslte_pss_t *q, uint32_t max_frame_size, uint32_t max_fft_size, int offset, int decimate) { @@ -102,7 +102,7 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, uint32_t N_id_2; uint32_t buffer_size; - bzero(q, sizeof(srslte_pss_synch_t)); + bzero(q, sizeof(srslte_pss_t)); q->N_id_2 = 10; q->ema_alpha = 0.2; @@ -143,7 +143,7 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, } srslte_dft_plan_set_mirror(&q->idftp_input, true); srslte_dft_plan_set_dc(&q->idftp_input, true); - srslte_dft_plan_set_norm(&q->idftp_input, true); + srslte_dft_plan_set_norm(&q->idftp_input, false); bzero(q->tmp_fft2, sizeof(cf_t)*SRSLTE_SYMBOL_SZ_MAX); @@ -183,7 +183,7 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, goto clean_and_exit; } /* The PSS is translated into the time domain for each N_id_2 */ - if (srslte_pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { + if (srslte_pss_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); goto clean_and_exit; } @@ -192,27 +192,25 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, #ifdef CONVOLUTION_FFT - for(N_id_2=0; N_id_2<3; N_id_2++) - q->pss_signal_freq_full[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); - if (srslte_conv_fft_cc_init(&q->conv_fft, frame_size, fft_size)) { fprintf(stderr, "Error initiating convolution FFT\n"); goto clean_and_exit; } - for(int i=0; i<3; i++) { - srslte_dft_run_c(&q->conv_fft.filter_plan, q->pss_signal_time[i], q->pss_signal_freq_full[i]); + for(N_id_2=0; N_id_2<3; N_id_2++) { + q->pss_signal_freq_full[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); + srslte_dft_run_c(&q->conv_fft.filter_plan, q->pss_signal_time[N_id_2], q->pss_signal_freq_full[N_id_2]); } #endif - srslte_pss_synch_reset(q); + srslte_pss_reset(q); ret = SRSLTE_SUCCESS; } clean_and_exit: if (ret == SRSLTE_ERROR) { - srslte_pss_synch_free(q); + srslte_pss_free(q); } return ret; @@ -224,7 +222,7 @@ clean_and_exit: * It correlates a signal of frame_size samples with the PSS sequence in the frequency * domain. The PSS sequence is transformed using fft_size samples. */ -int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { +int srslte_pss_resize(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -233,7 +231,7 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t ret = SRSLTE_ERROR; if (fft_size > q->max_fft_size || frame_size > q->max_frame_size) { - fprintf(stderr, "Error in pss_synch_config(): fft_size and frame_size must be lower than initialized\n"); + fprintf(stderr, "Error in pss_config(): fft_size and frame_size must be lower than initialized\n"); return SRSLTE_ERROR; } @@ -273,7 +271,7 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t // Generate PSS sequences for this FFT size for (N_id_2=0;N_id_2<3;N_id_2++) { - if (srslte_pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { + if (srslte_pss_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); return SRSLTE_ERROR; } @@ -291,7 +289,7 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t #endif - srslte_pss_synch_reset(q); + srslte_pss_reset(q); ret = SRSLTE_SUCCESS; } @@ -299,7 +297,7 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t } -void srslte_pss_synch_free(srslte_pss_synch_t *q) { +void srslte_pss_free(srslte_pss_t *q) { uint32_t i; if (q) { @@ -339,11 +337,11 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) { } - bzero(q, sizeof(srslte_pss_synch_t)); + bzero(q, sizeof(srslte_pss_t)); } } -void srslte_pss_synch_reset(srslte_pss_synch_t *q) { +void srslte_pss_reset(srslte_pss_t *q) { uint32_t buffer_size = q->fft_size + q->frame_size + 1; bzero(q->conv_output_avg, sizeof(float) * buffer_size); } @@ -401,7 +399,7 @@ void srslte_pss_get_slot(cf_t *slot, cf_t *pss_signal, uint32_t nof_prb, srslte_ /** Sets the current N_id_2 value. Returns -1 on error, 0 otherwise */ -int srslte_pss_synch_set_N_id_2(srslte_pss_synch_t *q, uint32_t N_id_2) { +int srslte_pss_set_N_id_2(srslte_pss_t *q, uint32_t N_id_2) { if (!srslte_N_id_2_isvalid((N_id_2))) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); return -1; @@ -413,11 +411,11 @@ int srslte_pss_synch_set_N_id_2(srslte_pss_synch_t *q, uint32_t N_id_2) { /* Sets the weight factor alpha for the exponential moving average of the PSS correlation output */ -void srslte_pss_synch_set_ema_alpha(srslte_pss_synch_t *q, float alpha) { +void srslte_pss_set_ema_alpha(srslte_pss_t *q, float alpha) { q->ema_alpha = alpha; } -float compute_peak_sidelobe(srslte_pss_synch_t *q, uint32_t corr_peak_pos, uint32_t conv_output_len) +float compute_peak_sidelobe(srslte_pss_t *q, uint32_t corr_peak_pos, uint32_t conv_output_len) { // Find end of peak lobe to the right int pl_ub = corr_peak_pos+1; @@ -455,7 +453,7 @@ float compute_peak_sidelobe(srslte_pss_synch_t *q, uint32_t corr_peak_pos, uint3 * * Input buffer must be subframe_size long. */ -int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, const cf_t *input, float *corr_peak_value) +int srslte_pss_find_pss(srslte_pss_t *q, const cf_t *input, float *corr_peak_value) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -474,7 +472,7 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, const cf_t *input, float *c /* Correlate input with PSS sequence * * We do not reverse time-domain PSS signal because it's conjugate is symmetric. - * The conjugate operation on pss_signal_time has been done in srslte_pss_synch_init_N_id_2 + * The conjugate operation on pss_signal_time has been done in srslte_pss_init_N_id_2 * This is why we can use FFT-based convolution */ if (q->frame_size >= q->fft_size) { @@ -545,9 +543,8 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, const cf_t *input, float *c * input signal is in the time-domain. * ce is the returned frequency-domain channel estimates. */ -int srslte_pss_synch_chest(srslte_pss_synch_t *q, const cf_t *input, cf_t ce[SRSLTE_PSS_LEN]) { +int srslte_pss_chest(srslte_pss_t *q, const cf_t *input, cf_t ce[SRSLTE_PSS_LEN]) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX]; if (q != NULL && input != NULL) @@ -559,18 +556,41 @@ int srslte_pss_synch_chest(srslte_pss_synch_t *q, const cf_t *input, cf_t ce[SRS } /* Transform to frequency-domain */ - srslte_dft_run_c(&q->dftp_input, input, input_fft); + srslte_dft_run_c(&q->dftp_input, input, q->tmp_fft); /* Compute channel estimate taking the PSS sequence as reference */ - srslte_vec_prod_conj_ccc(&input_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], q->pss_signal_freq[q->N_id_2], ce, SRSLTE_PSS_LEN); + srslte_vec_prod_conj_ccc(&q->tmp_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], q->pss_signal_freq[q->N_id_2], ce, SRSLTE_PSS_LEN); ret = SRSLTE_SUCCESS; } return ret; } +/* input points to beginning of last OFDM symbol of slot 0 of subframe 0 or 5 + * It must be called after calling srslte_pss_cfo_compute() with filter enabled + */ +void srslte_pss_sic(srslte_pss_t *q, cf_t *input) { + if (q->chest_on_filter) { + + bzero(q->tmp_fft, sizeof(cf_t)*q->fft_size); + + // Pass transmitted PSS sequence through the channel + srslte_vec_prod_ccc(q->pss_signal_freq[q->N_id_2], q->tmp_ce, &q->tmp_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], SRSLTE_PSS_LEN); + + // Get time-domain version of the received PSS + srslte_dft_run_c(&q->idftp_input, q->tmp_fft, q->tmp_fft2); + + // Substract received PSS from this N_id_2 from the input signal + srslte_vec_sc_prod_cfc(q->tmp_fft2, 1.0/q->fft_size, q->tmp_fft2, q->fft_size); + srslte_vec_sub_ccc(input, q->tmp_fft2, input, q->fft_size); + + } else { + fprintf(stderr, "Error calling srslte_pss_sic(): need to enable channel estimation on filtering\n"); + } +} + // Frequency-domain filtering of the central 64 sub-carriers -void srslte_pss_synch_filter(srslte_pss_synch_t *q, const cf_t *input, cf_t *output) +void srslte_pss_filter(srslte_pss_t *q, const cf_t *input, cf_t *output) { srslte_dft_run_c(&q->dftp_input, input, q->tmp_fft); @@ -578,6 +598,10 @@ void srslte_pss_synch_filter(srslte_pss_synch_t *q, const cf_t *input, cf_t *out &q->tmp_fft[q->fft_size/2-SRSLTE_PSS_LEN/2], sizeof(cf_t)*SRSLTE_PSS_LEN); + if (q->chest_on_filter) { + srslte_vec_prod_conj_ccc(&q->tmp_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], q->pss_signal_freq[q->N_id_2], q->tmp_ce, SRSLTE_PSS_LEN); + } + srslte_dft_run_c(&q->idftp_input, q->tmp_fft2, output); } @@ -586,13 +610,13 @@ void srslte_pss_synch_filter(srslte_pss_synch_t *q, const cf_t *input, cf_t *out * Source: An Efficient CFO Estimation Algorithm for the Downlink of 3GPP-LTE * Feng Wang and Yu Zhu */ -float srslte_pss_synch_cfo_compute(srslte_pss_synch_t* q, const cf_t *pss_recv) { +float srslte_pss_cfo_compute(srslte_pss_t* q, const cf_t *pss_recv) { cf_t y0, y1; const cf_t *pss_ptr = pss_recv; if (q->filter_pss_enable) { - srslte_pss_synch_filter(q, pss_recv, q->tmp_fft); + srslte_pss_filter(q, pss_recv, q->tmp_fft); pss_ptr = (const cf_t*) q->tmp_fft; } diff --git a/lib/src/phy/sync/sss.c b/lib/src/phy/sync/sss.c index 4ed7b1d6c..31091bdb3 100644 --- a/lib/src/phy/sync/sss.c +++ b/lib/src/phy/sync/sss.c @@ -40,7 +40,7 @@ void generate_sss_all_tables(srslte_sss_tables_t *tables, uint32_t N_id_2); void convert_tables(srslte_sss_fc_tables_t *fc_tables, srslte_sss_tables_t *in); void generate_N_id_1_table(uint32_t table[30][30]); -int srslte_sss_synch_init(srslte_sss_synch_t *q, uint32_t fft_size) { +int srslte_sss_init(srslte_sss_t *q, uint32_t fft_size) { if (q != NULL && fft_size <= 2048) @@ -48,10 +48,10 @@ int srslte_sss_synch_init(srslte_sss_synch_t *q, uint32_t fft_size) { uint32_t N_id_2; srslte_sss_tables_t sss_tables; - bzero(q, sizeof(srslte_sss_synch_t)); + bzero(q, sizeof(srslte_sss_t)); if (srslte_dft_plan(&q->dftp_input, fft_size, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) { - srslte_sss_synch_free(q); + srslte_sss_free(q); return SRSLTE_ERROR; } srslte_dft_plan_set_mirror(&q->dftp_input, true); @@ -72,7 +72,7 @@ int srslte_sss_synch_init(srslte_sss_synch_t *q, uint32_t fft_size) { return SRSLTE_ERROR_INVALID_INPUTS; } -int srslte_sss_synch_resize(srslte_sss_synch_t *q, uint32_t fft_size) { +int srslte_sss_resize(srslte_sss_t *q, uint32_t fft_size) { if (q != NULL && fft_size <= 2048) { @@ -81,7 +81,7 @@ int srslte_sss_synch_resize(srslte_sss_synch_t *q, uint32_t fft_size) { return SRSLTE_ERROR; } if (srslte_dft_replan(&q->dftp_input, fft_size)) { - srslte_sss_synch_free(q); + srslte_sss_free(q); return SRSLTE_ERROR; } q->fft_size = fft_size; @@ -90,13 +90,13 @@ int srslte_sss_synch_resize(srslte_sss_synch_t *q, uint32_t fft_size) { return SRSLTE_ERROR_INVALID_INPUTS; } -void srslte_sss_synch_free(srslte_sss_synch_t *q) { +void srslte_sss_free(srslte_sss_t *q) { srslte_dft_plan_free(&q->dftp_input); - bzero(q, sizeof(srslte_sss_synch_t)); + bzero(q, sizeof(srslte_sss_t)); } /** Sets the N_id_2 to search for */ -int srslte_sss_synch_set_N_id_2(srslte_sss_synch_t *q, uint32_t N_id_2) { +int srslte_sss_set_N_id_2(srslte_sss_t *q, uint32_t N_id_2) { if (!srslte_N_id_2_isvalid(N_id_2)) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); return SRSLTE_ERROR; @@ -124,12 +124,12 @@ void srslte_sss_put_slot(float *sss, cf_t *slot, uint32_t nof_prb, srslte_cp_t c } /** Sets the SSS correlation peak detection threshold */ -void srslte_sss_synch_set_threshold(srslte_sss_synch_t *q, float threshold) { +void srslte_sss_set_threshold(srslte_sss_t *q, float threshold) { q->corr_peak_threshold = threshold; } /** Returns the subframe index based on the m0 and m1 values */ -uint32_t srslte_sss_synch_subframe(uint32_t m0, uint32_t m1) { +uint32_t srslte_sss_subframe(uint32_t m0, uint32_t m1) { if (m1 > m0) { return 0; } else { @@ -138,7 +138,7 @@ uint32_t srslte_sss_synch_subframe(uint32_t m0, uint32_t m1) { } /** Returns the N_id_1 value based on the m0 and m1 values */ -int srslte_sss_synch_N_id_1(srslte_sss_synch_t *q, uint32_t m0, uint32_t m1) { +int srslte_sss_N_id_1(srslte_sss_t *q, uint32_t m0, uint32_t m1) { int N_id_1 = -1; if (m1 > m0) { if (m0 < 30 && m1 - 1 < 30) { diff --git a/lib/src/phy/sync/sync.c b/lib/src/phy/sync/sync.c index a74be30d6..13a5f7e69 100644 --- a/lib/src/phy/sync/sync.c +++ b/lib/src/phy/sync/sync.c @@ -77,7 +77,6 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o q->cfo_cp_enable = false; q->cfo_i_initiated = false; q->pss_filtering_enabled = false; - q->sss_filtering_enabled = false; q->fft_size = fft_size; q->frame_size = frame_size; @@ -119,11 +118,11 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o decimate = 1; } - if (srslte_pss_synch_init_fft_offset_decim(&q->pss, max_offset, fft_size, 0, decimate)) { + if (srslte_pss_init_fft_offset_decim(&q->pss, max_offset, fft_size, 0, decimate)) { fprintf(stderr, "Error initializing PSS object\n"); goto clean_exit; } - if (srslte_sss_synch_init(&q->sss, fft_size)) { + if (srslte_sss_init(&q->sss, fft_size)) { fprintf(stderr, "Error initializing SSS object\n"); goto clean_exit; } @@ -151,8 +150,8 @@ void srslte_sync_free(srslte_sync_t *q) { if (q) { - srslte_pss_synch_free(&q->pss); - srslte_sss_synch_free(&q->sss); + srslte_pss_free(&q->pss); + srslte_sss_free(&q->sss); srslte_cfo_free(&q->cfo_corr_frame); srslte_cfo_free(&q->cfo_corr_symbol); srslte_cp_synch_free(&q->cp_synch); @@ -162,7 +161,7 @@ void srslte_sync_free(srslte_sync_t *q) if (q->cfo_i_corr[i]) { free(q->cfo_i_corr[i]); } - srslte_pss_synch_free(&q->pss_i[i]); + srslte_pss_free(&q->pss_i[i]); } } if (q->temp) { @@ -188,11 +187,11 @@ int srslte_sync_resize(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offse q->frame_size = frame_size; q->max_offset = max_offset; - if (srslte_pss_synch_resize(&q->pss, q->max_offset, q->fft_size, 0)) { + if (srslte_pss_resize(&q->pss, q->max_offset, q->fft_size, 0)) { fprintf(stderr, "Error resizing PSS object\n"); return SRSLTE_ERROR; } - if (srslte_sss_synch_resize(&q->sss, q->fft_size)) { + if (srslte_sss_resize(&q->sss, q->fft_size)) { fprintf(stderr, "Error resizing SSS object\n"); return SRSLTE_ERROR; } @@ -215,7 +214,7 @@ int srslte_sync_resize(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offse if (q->cfo_i_initiated) { for (int i=0;i<2;i++) { int offset=(i==0)?-1:1; - if (srslte_pss_synch_resize(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { + if (srslte_pss_resize(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { fprintf(stderr, "Error initializing PSS object\n"); } for (int t=0;tframe_size;t++) { @@ -302,7 +301,7 @@ void srslte_sync_set_cfo_i_enable(srslte_sync_t *q, bool enable) { if (q->cfo_i_enable && !q->cfo_i_initiated) { for (int i=0;i<2;i++) { int offset=(i==0)?-1:1; - if (srslte_pss_synch_init_fft_offset(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { + if (srslte_pss_init_fft_offset(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { fprintf(stderr, "Error initializing PSS object\n"); } for (int t=0;tframe_size;t++) { @@ -313,8 +312,12 @@ void srslte_sync_set_cfo_i_enable(srslte_sync_t *q, bool enable) { } } -void srslte_sync_set_sss_filt_enable(srslte_sync_t *q, bool enable) { - q->sss_filtering_enabled = enable; +void srslte_sync_set_sss_eq_enable(srslte_sync_t *q, bool enable) { + q->sss_channel_equalize = enable; + if (enable) { + q->pss_filtering_enabled = true; + q->pss.chest_on_filter = true; + } } void srslte_sync_set_pss_filt_enable(srslte_sync_t *q, bool enable) { @@ -343,7 +346,7 @@ void srslte_sync_cp_en(srslte_sync_t *q, bool enabled) { void srslte_sync_set_em_alpha(srslte_sync_t *q, float alpha) { - srslte_pss_synch_set_ema_alpha(&q->pss, alpha); + srslte_pss_set_ema_alpha(&q->pss, alpha); } srslte_cp_t srslte_sync_get_cp(srslte_sync_t *q) @@ -434,22 +437,22 @@ int sync_sss_symbol(srslte_sync_t *q, const cf_t *input) { int ret; - srslte_sss_synch_set_N_id_2(&q->sss, q->N_id_2); + srslte_sss_set_N_id_2(&q->sss, q->N_id_2); switch(q->sss_alg) { case SSS_DIFF: - srslte_sss_synch_m0m1_diff(&q->sss, input, &q->m0, &q->m0_value, &q->m1, &q->m1_value); + srslte_sss_m0m1_diff(&q->sss, input, &q->m0, &q->m0_value, &q->m1, &q->m1_value); break; case SSS_PARTIAL_3: - srslte_sss_synch_m0m1_partial(&q->sss, input, 3, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); + srslte_sss_m0m1_partial(&q->sss, input, 3, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); break; case SSS_FULL: - srslte_sss_synch_m0m1_partial(&q->sss, input, 1, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); + srslte_sss_m0m1_partial(&q->sss, input, 1, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); break; } - q->sf_idx = srslte_sss_synch_subframe(q->m0, q->m1); - ret = srslte_sss_synch_N_id_1(&q->sss, q->m0, q->m1); + q->sf_idx = srslte_sss_subframe(q->m0, q->m1); + ret = srslte_sss_N_id_1(&q->sss, q->m0, q->m1); if (ret >= 0) { q->N_id_1 = (uint32_t) ret; DEBUG("SSS detected N_id_1=%d, sf_idx=%d, %s CP\n", @@ -461,9 +464,9 @@ int sync_sss_symbol(srslte_sync_t *q, const cf_t *input) } } -srslte_pss_synch_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q) +srslte_pss_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q) { - srslte_pss_synch_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]}; + srslte_pss_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]}; return pss_obj[q->cfo_i_value+1]; } @@ -481,10 +484,10 @@ static int cfo_i_estimate(srslte_sync_t *q, const cf_t *input, int find_offset, float peak_value; float max_peak_value = -99; int max_cfo_i = 0; - srslte_pss_synch_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]}; + srslte_pss_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]}; for (int cfo_i=0;cfo_i<3;cfo_i++) { - srslte_pss_synch_set_N_id_2(pss_obj[cfo_i], q->N_id_2); - int p = srslte_pss_synch_find_pss(pss_obj[cfo_i], &input[find_offset], &peak_value); + srslte_pss_set_N_id_2(pss_obj[cfo_i], q->N_id_2); + int p = srslte_pss_find_pss(pss_obj[cfo_i], &input[find_offset], &peak_value); if (p < 0) { return -1; } @@ -574,8 +577,8 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin /* Find maximum of PSS correlation. If Integer CFO is enabled, correlation is already done */ if (!q->cfo_i_enable) { - srslte_pss_synch_set_N_id_2(&q->pss, q->N_id_2); - peak_pos = srslte_pss_synch_find_pss(&q->pss, &input_ptr[find_offset], q->threshold>0?&q->peak_value:NULL); + srslte_pss_set_N_id_2(&q->pss, q->N_id_2); + peak_pos = srslte_pss_find_pss(&q->pss, &input_ptr[find_offset], q->threshold>0?&q->peak_value:NULL); if (peak_pos < 0) { fprintf(stderr, "Error calling finding PSS sequence at : %d \n", peak_pos); return SRSLTE_ERROR; @@ -602,12 +605,12 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin // Filter central bands before PSS-based CFO estimation const cf_t *pss_ptr = &input_ptr[find_offset + peak_pos - q->fft_size]; if (q->pss_filtering_enabled) { - srslte_pss_synch_filter(&q->pss, pss_ptr, q->pss_filt); + srslte_pss_filter(&q->pss, pss_ptr, q->pss_filt); pss_ptr = q->pss_filt; } // PSS-based CFO estimation - float cfo_pss = srslte_pss_synch_cfo_compute(&q->pss, pss_ptr); + float cfo_pss = srslte_pss_cfo_compute(&q->pss, pss_ptr); if (!q->cfo_pss_is_set) { q->cfo_pss_mean = cfo_pss; q->cfo_pss_is_set = true; @@ -637,12 +640,11 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin // Correct CFO if detected in PSS if (q->cfo_pss_enable) { srslte_cfo_correct(&q->cfo_corr_symbol, sss_ptr, q->sss_filt, -q->cfo_pss_mean / q->fft_size); - sss_ptr = q->sss_filt; - } - - // Filter central bands before SSS estimation - if (q->sss_filtering_enabled) { - srslte_pss_synch_filter(&q->pss, sss_ptr, q->sss_filt); + // Equalize channel if estimated in PSS + if (q->sss_channel_equalize && q->pss.chest_on_filter && q->pss_filtering_enabled) { + srslte_vec_prod_ccc(&q->sss_filt[q->fft_size/2-SRSLTE_PSS_LEN/2], q->pss.tmp_ce, + &q->sss_filt[q->fft_size/2-SRSLTE_PSS_LEN/2], SRSLTE_PSS_LEN); + } sss_ptr = q->sss_filt; } @@ -681,5 +683,5 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin void srslte_sync_reset(srslte_sync_t *q) { q->M_ext_avg = 0; q->M_norm_avg = 0; - srslte_pss_synch_reset(&q->pss); + srslte_pss_reset(&q->pss); } diff --git a/lib/src/phy/sync/test/pss_file.c b/lib/src/phy/sync/test/pss_file.c index 7f70ad8ff..4087366ec 100644 --- a/lib/src/phy/sync/test/pss_file.c +++ b/lib/src/phy/sync/test/pss_file.c @@ -121,9 +121,9 @@ int main(int argc, char **argv) { srslte_filesource_t fsrc; cf_t *buffer; int frame_cnt, n; - srslte_pss_synch_t pss; + srslte_pss_t pss; srslte_cfo_t cfocorr, cfocorr64; - srslte_sss_synch_t sss; + srslte_sss_t sss; int32_t flen; int peak_idx, last_peak; float peak_value; @@ -152,12 +152,12 @@ int main(int argc, char **argv) { exit(-1); } - if (srslte_pss_synch_init_fft(&pss, flen, fft_size)) { + if (srslte_pss_init_fft(&pss, flen, fft_size)) { fprintf(stderr, "Error initiating PSS\n"); exit(-1); } - if (srslte_pss_synch_set_N_id_2(&pss, N_id_2_sync)) { + if (srslte_pss_set_N_id_2(&pss, N_id_2_sync)) { fprintf(stderr, "Error setting N_id_2=%d\n",N_id_2_sync); exit(-1); } @@ -165,12 +165,12 @@ int main(int argc, char **argv) { srslte_cfo_init(&cfocorr, flen); srslte_cfo_init(&cfocorr64, flen); - if (srslte_sss_synch_init(&sss, fft_size)) { + if (srslte_sss_init(&sss, fft_size)) { fprintf(stderr, "Error initializing SSS object\n"); return SRSLTE_ERROR; } - srslte_sss_synch_set_N_id_2(&sss, N_id_2); + srslte_sss_set_N_id_2(&sss, N_id_2); printf("Opening file...\n"); if (srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) { @@ -210,7 +210,7 @@ int main(int argc, char **argv) { break; } - peak_idx = srslte_pss_synch_find_pss(&pss, buffer, &peak_value); + peak_idx = srslte_pss_find_pss(&pss, buffer, &peak_value); if (peak_idx < 0) { fprintf(stderr, "Error finding PSS peak\n"); exit(-1); @@ -224,14 +224,14 @@ int main(int argc, char **argv) { if (peak_idx >= fft_size) { // Estimate CFO - cfo = srslte_pss_synch_cfo_compute(&pss, &buffer[peak_idx-fft_size]); + cfo = srslte_pss_cfo_compute(&pss, &buffer[peak_idx-fft_size]); mean_cfo = SRSLTE_VEC_CMA(cfo, mean_cfo, frame_cnt); // Correct CFO srslte_cfo_correct(&cfocorr, buffer, buffer, -mean_cfo / fft_size); // Estimate channel - if (srslte_pss_synch_chest(&pss, &buffer[peak_idx-fft_size], ce)) { + if (srslte_pss_chest(&pss, &buffer[peak_idx-fft_size], ce)) { fprintf(stderr, "Error computing channel estimation\n"); exit(-1); } @@ -239,22 +239,22 @@ int main(int argc, char **argv) { // Find SSS int sss_idx = peak_idx-2*fft_size-(SRSLTE_CP_ISNORM(cp)?SRSLTE_CP_LEN(fft_size, SRSLTE_CP_NORM_LEN):SRSLTE_CP_LEN(fft_size, SRSLTE_CP_EXT_LEN)); if (sss_idx >= 0 && sss_idx < flen-fft_size) { - srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error2++; } - INFO("sf_idx = %d\n", srslte_sss_synch_subframe(m0, m1)); - INFO("Partial N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); - srslte_sss_synch_m0m1_diff(&sss, &buffer[sss_idx], &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + INFO("sf_idx = %d\n", srslte_sss_subframe(m0, m1)); + INFO("Partial N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); + srslte_sss_m0m1_diff(&sss, &buffer[sss_idx], &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error3++; } - INFO("Diff N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); - srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + INFO("Diff N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); + srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error1++; } - INFO("Full N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); + INFO("Full N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); } // Estimate CP @@ -269,7 +269,7 @@ int main(int argc, char **argv) { INFO("No space for CFO computation. Frame starts at \n",peak_idx); } - if(srslte_sss_synch_subframe(m0,m1) == 0) + if(srslte_sss_subframe(m0,m1) == 0) { #ifndef DISABLE_GRAPHICS if (!disable_plots) @@ -317,7 +317,7 @@ int main(int argc, char **argv) { } - srslte_pss_synch_free(&pss); + srslte_pss_free(&pss); free(buffer); srslte_filesource_free(&fsrc); #ifndef DISABLE_GRAPHICS diff --git a/lib/src/phy/sync/test/pss_mex.c b/lib/src/phy/sync/test/pss_mex.c index 77922a020..59cc0a897 100644 --- a/lib/src/phy/sync/test/pss_mex.c +++ b/lib/src/phy/sync/test/pss_mex.c @@ -47,7 +47,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { srslte_cell_t cell; - srslte_pss_synch_t pss; + srslte_pss_t pss; cf_t *input_symbols; int frame_len; @@ -74,17 +74,17 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) frame_len = (int) mxGetScalar(prhs[NOF_INPUTS]); } - if (srslte_pss_synch_init_fft(&pss, frame_len, srslte_symbol_sz(cell.nof_prb))) { + if (srslte_pss_init_fft(&pss, frame_len, srslte_symbol_sz(cell.nof_prb))) { fprintf(stderr, "Error initiating PSS\n"); exit(-1); } - if (srslte_pss_synch_set_N_id_2(&pss, cell.id%3)) { + if (srslte_pss_set_N_id_2(&pss, cell.id%3)) { fprintf(stderr, "Error setting N_id_2=%d\n",cell.id%3); exit(-1); } - srslte_pss_synch_set_ema_alpha(&pss, 1.0); + srslte_pss_set_ema_alpha(&pss, 1.0); - int peak_idx = srslte_pss_synch_find_pss(&pss, input_symbols, NULL); + int peak_idx = srslte_pss_find_pss(&pss, input_symbols, NULL); if (nlhs >= 1) { plhs[0] = mxCreateDoubleScalar(peak_idx); @@ -93,7 +93,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) mexutils_write_cf(pss.conv_output, &plhs[1], frame_len, 1); } - srslte_pss_synch_free(&pss); + srslte_pss_free(&pss); free(input_symbols); return; diff --git a/lib/src/phy/sync/test/pss_usrp.c b/lib/src/phy/sync/test/pss_usrp.c index 704340b2f..70881f15b 100644 --- a/lib/src/phy/sync/test/pss_usrp.c +++ b/lib/src/phy/sync/test/pss_usrp.c @@ -125,9 +125,9 @@ int main(int argc, char **argv) { cf_t *buffer; int frame_cnt, n; srslte_rf_t rf; - srslte_pss_synch_t pss; + srslte_pss_t pss; srslte_cfo_t cfocorr, cfocorr64; - srslte_sss_synch_t sss; + srslte_sss_t sss; int32_t flen; int peak_idx, last_peak; float peak_value; @@ -176,12 +176,12 @@ int main(int argc, char **argv) { exit(-1); } - if (srslte_pss_synch_init_fft(&pss, flen, fft_size)) { + if (srslte_pss_init_fft(&pss, flen, fft_size)) { fprintf(stderr, "Error initiating PSS\n"); exit(-1); } - if (srslte_pss_synch_set_N_id_2(&pss, N_id_2_sync)) { + if (srslte_pss_set_N_id_2(&pss, N_id_2_sync)) { fprintf(stderr, "Error setting N_id_2=%d\n",N_id_2_sync); exit(-1); } @@ -189,12 +189,12 @@ int main(int argc, char **argv) { srslte_cfo_init(&cfocorr, flen); srslte_cfo_init(&cfocorr64, flen); - if (srslte_sss_synch_init(&sss, fft_size)) { + if (srslte_sss_init(&sss, fft_size)) { fprintf(stderr, "Error initializing SSS object\n"); exit(-1); } - srslte_sss_synch_set_N_id_2(&sss, N_id_2); + srslte_sss_set_N_id_2(&sss, N_id_2); printf("N_id_2: %d\n", N_id_2); @@ -232,7 +232,7 @@ int main(int argc, char **argv) { exit(-1); } - peak_idx = srslte_pss_synch_find_pss(&pss, buffer, &peak_value); + peak_idx = srslte_pss_find_pss(&pss, buffer, &peak_value); if (peak_idx < 0) { fprintf(stderr, "Error finding PSS peak\n"); exit(-1); @@ -246,14 +246,14 @@ int main(int argc, char **argv) { if (peak_idx >= fft_size) { // Estimate CFO - cfo = srslte_pss_synch_cfo_compute(&pss, &buffer[peak_idx-fft_size]); + cfo = srslte_pss_cfo_compute(&pss, &buffer[peak_idx-fft_size]); mean_cfo = SRSLTE_VEC_CMA(cfo, mean_cfo, frame_cnt); // Correct CFO srslte_cfo_correct(&cfocorr, buffer, buffer, -mean_cfo / fft_size); // Estimate channel - if (srslte_pss_synch_chest(&pss, &buffer[peak_idx-fft_size], ce)) { + if (srslte_pss_chest(&pss, &buffer[peak_idx-fft_size], ce)) { fprintf(stderr, "Error computing channel estimation\n"); exit(-1); } @@ -263,22 +263,22 @@ int main(int argc, char **argv) { if (sss_idx >= 0 && sss_idx < flen-fft_size) { // Filter SSS - srslte_pss_synch_filter(&pss, &buffer[sss_idx], &buffer[sss_idx]); + srslte_pss_filter(&pss, &buffer[sss_idx], &buffer[sss_idx]); - INFO("Full N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); - srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, ce, &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + INFO("Full N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); + srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 1, ce, &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error2++; } - INFO("Partial N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); - srslte_sss_synch_m0m1_diff_coh(&sss, &buffer[sss_idx], ce, &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + INFO("Partial N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); + srslte_sss_m0m1_diff_coh(&sss, &buffer[sss_idx], ce, &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error3++; } - INFO("Diff N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); + INFO("Diff N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); } - srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error1++; } @@ -294,7 +294,7 @@ int main(int argc, char **argv) { INFO("No space for CFO computation. Frame starts at \n",peak_idx); } - if(srslte_sss_synch_subframe(m0,m1) == 0) + if(srslte_sss_subframe(m0,m1) == 0) { #ifndef DISABLE_GRAPHICS if (!disable_plots) @@ -358,8 +358,8 @@ int main(int argc, char **argv) { } - srslte_sss_synch_free(&sss); - srslte_pss_synch_free(&pss); + srslte_sss_free(&sss); + srslte_pss_free(&pss); free(buffer); srslte_rf_close(&rf); diff --git a/lib/src/phy/sync/test/sss_mex.c b/lib/src/phy/sync/test/sss_mex.c index 4c92d81ec..56165fe3d 100644 --- a/lib/src/phy/sync/test/sss_mex.c +++ b/lib/src/phy/sync/test/sss_mex.c @@ -50,7 +50,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { srslte_cell_t cell; - srslte_sss_synch_t sss; + srslte_sss_t sss; cf_t *input_symbols; int frame_len; uint32_t m0, m1; @@ -80,12 +80,12 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) return; } - if (srslte_sss_synch_init(&sss, srslte_symbol_sz(cell.nof_prb))) { + if (srslte_sss_init(&sss, srslte_symbol_sz(cell.nof_prb))) { mexErrMsgTxt("Error initializing SSS object\n"); return; } - srslte_sss_synch_set_N_id_2(&sss, cell.id%3); + srslte_sss_set_N_id_2(&sss, cell.id%3); // Find SSS uint32_t sss_idx = SRSLTE_SLOT_IDX_CPNORM(5,srslte_symbol_sz(cell.nof_prb)); @@ -95,23 +95,23 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } //mexPrintf("SSS begins at %d/%d. Running algorithm %s\n", sss_idx, frame_len, alg); if (!strcmp(alg, "partial")) { - srslte_sss_synch_m0m1_partial(&sss, &input_symbols[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value); + srslte_sss_m0m1_partial(&sss, &input_symbols[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value); } else if (!strcmp(alg, "diff")) { - srslte_sss_synch_m0m1_diff(&sss, &input_symbols[sss_idx], &m0, &m0_value, &m1, &m1_value); + srslte_sss_m0m1_diff(&sss, &input_symbols[sss_idx], &m0, &m0_value, &m1, &m1_value); } else if (!strcmp(alg, "full")) { - srslte_sss_synch_m0m1_partial(&sss, &input_symbols[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); + srslte_sss_m0m1_partial(&sss, &input_symbols[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); } else { mexErrMsgTxt("Unsupported algorithm type\n"); return; } - //mexPrintf("m0: %d, m1: %d, N_id_1: %d\n", m0, m1, srslte_sss_synch_N_id_1(&sss, m0, m1)); + //mexPrintf("m0: %d, m1: %d, N_id_1: %d\n", m0, m1, srslte_sss_N_id_1(&sss, m0, m1)); if (nlhs >= 1) { - plhs[0] = mxCreateDoubleScalar(srslte_sss_synch_N_id_1(&sss, m0, m1)); + plhs[0] = mxCreateDoubleScalar(srslte_sss_N_id_1(&sss, m0, m1)); } if (nlhs >= 2) { - plhs[1] = mxCreateDoubleScalar(srslte_sss_synch_subframe(m0, m1)); + plhs[1] = mxCreateDoubleScalar(srslte_sss_subframe(m0, m1)); } if (nlhs >= 3) { mexutils_write_f(sss.corr_output_m0, &plhs[2], SRSLTE_SSS_N, 1); @@ -119,7 +119,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) if (nlhs >= 4) { mexutils_write_f(sss.corr_output_m1, &plhs[3], SRSLTE_SSS_N, 1); } - srslte_sss_synch_free(&sss); + srslte_sss_free(&sss); free(input_symbols); return; diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index b5d89743f..7eb877b3b 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -272,14 +272,14 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, srslte_sync_set_cfo_cp_enable(&q->sfind, true); srslte_sync_set_cfo_pss_enable(&q->sfind, true); srslte_sync_set_pss_filt_enable(&q->sfind, true); - srslte_sync_set_sss_filt_enable(&q->sfind, true); + srslte_sync_set_sss_eq_enable(&q->sfind, true); // During track, we do CFO correction outside the sync object srslte_sync_set_cfo_i_enable(&q->strack, false); srslte_sync_set_cfo_cp_enable(&q->strack, false); srslte_sync_set_cfo_pss_enable(&q->strack, true); srslte_sync_set_pss_filt_enable(&q->strack, true); - srslte_sync_set_sss_filt_enable(&q->strack, false); + srslte_sync_set_sss_eq_enable(&q->strack, false); // FIXME: CP detection not working very well. Not supporting Extended CP right now srslte_sync_cp_en(&q->strack, false); diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/phch_recv.h index 667f0a93c..6c7ff7717 100644 --- a/srsue/hdr/phy/phch_recv.h +++ b/srsue/hdr/phy/phch_recv.h @@ -102,8 +102,6 @@ private: bool set_frequency(); bool set_cell(); - static void substract_sync(cf_t *buffer, uint32_t nof_prb, srslte_sync_t *sync_obj); - void cell_search_inc(); void resync_sfn(bool is_connected = false, bool rx_now = false); bool stop_sync(); @@ -202,7 +200,7 @@ private: float rsrq; uint32_t offset; } cell_info_t; - void init(srslte::log *log_h); + void init(srslte::log *log_h, bool sic_pss_enabled); void reset(); int find_cells(cf_t *input_buffer, float rx_gain_offset, srslte_cell_t current_cell, uint32_t nof_sf, cell_info_t found_cells[MAX_CELLS]); private: @@ -214,6 +212,7 @@ private: srslte::log *log_h; srslte_sync_t sync_find; + bool sic_pss_enabled; uint32_t current_fft_sz; measure measure_p; }; diff --git a/srsue/src/mac/proc_ra.cc b/srsue/src/mac/proc_ra.cc index 18548be23..0a1855c80 100644 --- a/srsue/src/mac/proc_ra.cc +++ b/srsue/src/mac/proc_ra.cc @@ -394,16 +394,14 @@ void ra_proc::step_response_reception() { void ra_proc::step_response_error() { - if (ra_is_ho) { - state = RA_PROBLEM; - rrc->ho_ra_completed(false); - return; - } preambleTransmissionCounter++; if (preambleTransmissionCounter >= preambleTransMax + 1) { rError("Maximum number of transmissions reached (%d)\n", preambleTransMax); rrc->ra_problem(); state = RA_PROBLEM; + if (ra_is_ho) { + rrc->ho_ra_completed(false); + } } else { backoff_interval_start = phy_h->get_current_tti(); if (backoff_param_ms) { diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 8a25801f2..09a382246 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -233,11 +233,14 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { bpo::value(&args->expert.phy.cfo_loop_ref_min)->default_value(0), "Tolerance (in Hz) of the RS estimation method. Below this value, RS estimation does not feeds back the loop") - ("expert.cfo_loop_pss_conv", bpo::value(&args->expert.phy.cfo_loop_pss_conv)->default_value(20), "After the PSS estimation is below cfo_loop_pss_tol for cfo_loop_pss_timeout times consecutively, RS adjustments are allowed.") + ("expert.sic_pss_enabled", + bpo::value(&args->expert.phy.sic_pss_enabled)->default_value(true), + "Applies Successive Interference Cancellation to PSS signals when searching for neighbour cells. Must be disabled if cells have identical channel and timing.") + ("expert.average_subframe_enabled", bpo::value(&args->expert.phy.average_subframe_enabled)->default_value(false), "Averages in the time domain the channel estimates within 1 subframe. Needs accurate CFO correction.") diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 7a78fc11c..9225c6f73 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -197,6 +197,8 @@ void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) worker_com->args->cfo_loop_pss_tol, worker_com->args->cfo_loop_pss_conv); + q->strack.pss.chest_on_filter = true; + int time_correct_period = worker_com->args->time_correct_period; if (time_correct_period > 0) { srslte_ue_sync_set_sample_offset_correct_period(q, time_correct_period); @@ -629,7 +631,7 @@ void phch_recv::run_thread() worker = (phch_worker *) workers_pool->wait_worker(tti); if (worker) { - for (uint32_t i = 0; i < nof_rx_antennas; i++) { + for (uint32_t i = 0; i < SRSLTE_MAX_PORTS; i++) { buffer[i] = worker->get_buffer(i); } @@ -669,12 +671,12 @@ void phch_recv::run_thread() worker_com->p0_preamble = prach_buffer->get_p0_preamble(); worker_com->cur_radio_power = SRSLTE_MIN(SRSLTE_PC_MAX, worker_com->pathloss+worker_com->p0_preamble); } + workers_pool->start_worker(worker); - // Substract PSS/SSS from current cell before computing intra-frequency - /*if ((tti%5) == 0) { - substract_sync(buffer[0], cell.nof_prb, &ue_sync.strack); - }*/ + if ((tti%5) == 0 && worker_com->args->sic_pss_enabled) { + srslte_pss_sic(&ue_sync.strack.pss, &buffer[0][SRSLTE_SF_LEN_PRB(cell.nof_prb)/2-ue_sync.strack.fft_size]); + } intra_freq_meas.write(tti, buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb)); out_of_sync_cnt = 0; break; @@ -726,24 +728,6 @@ void phch_recv::out_of_sync() { } } -void phch_recv::substract_sync(cf_t *buffer, uint32_t nof_prb, srslte_sync_t *sync_obj) -{ - uint32_t hf_len = SRSLTE_SF_LEN_PRB(nof_prb)/2; - uint32_t fft_sz = srslte_symbol_sz(nof_prb); - - srslte_vec_sc_prod_cfc(sync_obj->pss_filt, 1.0/sqrtf(fft_sz), sync_obj->pss_filt, fft_sz); - srslte_vec_sc_prod_cfc(sync_obj->sss_filt, 1.0/sqrtf(fft_sz), sync_obj->sss_filt, fft_sz); - - srslte_vec_sub_ccc(&buffer[hf_len-fft_sz], - sync_obj->pss_filt, - &buffer[hf_len-fft_sz], - fft_sz); - - srslte_vec_sub_ccc(&buffer[hf_len-2*fft_sz-SRSLTE_CP_LEN(fft_sz, SRSLTE_CP_NORM_LEN)], - sync_obj->sss_filt, - &buffer[hf_len-2*fft_sz-SRSLTE_CP_LEN(fft_sz, SRSLTE_CP_NORM_LEN)], - fft_sz); -} @@ -1194,9 +1178,10 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx) * Secondary cell receiver */ -void phch_recv::scell_recv::init(srslte::log *log_h) +void phch_recv::scell_recv::init(srslte::log *log_h, bool sic_pss_enabled) { this->log_h = log_h; + this->sic_pss_enabled = sic_pss_enabled; // and a separate ue_sync instance @@ -1213,16 +1198,18 @@ void phch_recv::scell_recv::init(srslte::log *log_h) return; } srslte_sync_cp_en(&sync_find, false); - srslte_sync_set_threshold(&sync_find, 1.3); + srslte_sync_set_threshold(&sync_find, 1.2); srslte_sync_set_em_alpha(&sync_find, 0.0); // Configure FIND object behaviour (this configuration is always the same) - srslte_sync_set_cfo_ema_alpha(&sync_find, 0.5); + srslte_sync_set_cfo_ema_alpha(&sync_find, 1.0); srslte_sync_set_cfo_i_enable(&sync_find, false); srslte_sync_set_cfo_cp_enable(&sync_find, false); srslte_sync_set_cfo_pss_enable(&sync_find, true); srslte_sync_set_pss_filt_enable(&sync_find, true); - srslte_sync_set_sss_filt_enable(&sync_find, true); + srslte_sync_set_sss_eq_enable(&sync_find, true); + + sync_find.pss.chest_on_filter = true; reset(); } @@ -1259,76 +1246,79 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, for (uint32_t n_id_2=0;n_id_2<3;n_id_2++) { - srslte_sync_set_N_id_2(&sync_find, n_id_2); - - srslte_sync_find_ret_t sync_res; - //do { - - srslte_sync_reset(&sync_find); - srslte_sync_cfo_reset(&sync_find); - - sync_res = srslte_sync_find(&sync_find, input_buffer, 0, &peak_idx); - - switch(sync_res) { - case SRSLTE_SYNC_ERROR: - return SRSLTE_ERROR; - fprintf(stderr, "Error finding correlation peak\n"); - return SRSLTE_ERROR; - case SRSLTE_SYNC_FOUND: - sf_idx = srslte_sync_get_sf_idx(&sync_find); - cell_id = srslte_sync_get_cell_id(&sync_find); - - if (cell_id >= 0) { - // We found the same cell as before, look another N_id_2 - if ((uint32_t) cell_id == found_cell.id || (uint32_t) cell_id == cell.id) { - sync_res = SRSLTE_SYNC_NOFOUND; - } else { - // We found a new cell ID - found_cell.id = cell_id; - found_cell.nof_ports = 1; // Use port 0 only for measurement - measure_p.set_cell(found_cell); - - // Correct CFO - /* - srslte_cfo_correct(&sync_find.cfo_corr_frame, - input_buffer, - input_cfo_corrected, - -srslte_sync_get_cfo(&sync_find)/sync_find.fft_size); - */ - - switch(measure_p.run_multiple_subframes(input_buffer, peak_idx, sf_idx, nof_sf)) { - case measure::MEASURE_OK: - cells[nof_cells].pci = found_cell.id; - cells[nof_cells].rsrp = measure_p.rsrp(); - cells[nof_cells].rsrq = measure_p.rsrq(); - cells[nof_cells].offset = measure_p.frame_st_idx(); - nof_cells++; - - // Substract interference from input buffer (for the next cell) - //substract_sync(&input_buffer[measure_p.frame_st_idx()], cell.nof_prb, &sync_find); - - Info("INTRA: Found neighbour cell: PCI=%03d, RSRP=%5.1f dBm, peak_idx=%5d, peak_value=%3.2f n_id_2=%d, CFO=%6.1f Hz\n", - cell_id, measure_p.rsrp(), measure_p.frame_st_idx(), sync_find.peak_value, n_id_2, 15000*srslte_sync_get_cfo(&sync_find)); - - break; - case measure::ERROR: - Error("Measuring neighbour cell\n"); - return SRSLTE_ERROR; - default: - break; + if (n_id_2 != (cell.id%3) || sic_pss_enabled) { + srslte_sync_set_N_id_2(&sync_find, n_id_2); + + srslte_sync_find_ret_t sync_res; + + do { + srslte_sync_reset(&sync_find); + srslte_sync_cfo_reset(&sync_find); + + sync_res = srslte_sync_find(&sync_find, input_buffer, 0, &peak_idx); + + switch(sync_res) { + case SRSLTE_SYNC_ERROR: + return SRSLTE_ERROR; + fprintf(stderr, "Error finding correlation peak\n"); + return SRSLTE_ERROR; + case SRSLTE_SYNC_FOUND: + sf_idx = srslte_sync_get_sf_idx(&sync_find); + cell_id = srslte_sync_get_cell_id(&sync_find); + + if (cell_id >= 0) { + // We found the same cell as before, look another N_id_2 + if ((uint32_t) cell_id == found_cell.id || (uint32_t) cell_id == cell.id) { + sync_res = SRSLTE_SYNC_NOFOUND; + } else { + // We found a new cell ID + found_cell.id = cell_id; + found_cell.nof_ports = 1; // Use port 0 only for measurement + measure_p.set_cell(found_cell); + + // Correct CFO + srslte_cfo_correct(&sync_find.cfo_corr_frame, + input_buffer, + input_cfo_corrected, + -srslte_sync_get_cfo(&sync_find)/sync_find.fft_size); + + + switch(measure_p.run_multiple_subframes(input_cfo_corrected, peak_idx, sf_idx, nof_sf)) { + case measure::MEASURE_OK: + cells[nof_cells].pci = found_cell.id; + cells[nof_cells].rsrp = measure_p.rsrp(); + cells[nof_cells].rsrq = measure_p.rsrq(); + cells[nof_cells].offset = measure_p.frame_st_idx(); + + Info("INTRA: Found neighbour cell %d: PCI=%03d, RSRP=%5.1f dBm, peak_idx=%5d, peak_value=%3.2f n_id_2=%d, CFO=%6.1f Hz\n", + nof_cells, cell_id, measure_p.rsrp(), measure_p.frame_st_idx(), sync_find.peak_value, n_id_2, 15000*srslte_sync_get_cfo(&sync_find)); + + nof_cells++; + + if (sic_pss_enabled) { + srslte_pss_sic(&sync_find.pss, &input_buffer[sf_len/2-fft_sz]); + } + + break; + case measure::ERROR: + Error("Measuring neighbour cell\n"); + return SRSLTE_ERROR; + default: + break; + } } + } else { + sync_res = SRSLTE_SYNC_NOFOUND; } - } else { - sync_res = SRSLTE_SYNC_NOFOUND; - } - break; - case SRSLTE_SYNC_FOUND_NOSPACE: - /* If a peak was found but there is not enough space for SSS/CP detection, discard a few samples */ - break; - default: - break; - } - //} while(sync_res == SRSLTE_SYNC_FOUND); + break; + case SRSLTE_SYNC_FOUND_NOSPACE: + /* If a peak was found but there is not enough space for SSS/CP detection, discard a few samples */ + break; + default: + break; + } + } while (sync_res == SRSLTE_SYNC_FOUND && sic_pss_enabled); + } } return nof_cells; } @@ -1380,7 +1370,7 @@ void phch_recv::intra_measure::init(phch_common *common, rrc_interface_phy *rrc, receive_enabled = false; // Start scell - scell.init(log_h); + scell.init(log_h, common->args->sic_pss_enabled); search_buffer = (cf_t*) srslte_vec_malloc(CAPTURE_LEN_SF*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB)*sizeof(cf_t)); diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 461a4f9ee..55c39cfe0 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -1087,7 +1087,9 @@ void rrc::ho_ra_completed(bool ra_successful) { rrc_log->console("HO %ssuccessful\n", ra_successful?"":"un"); pending_mob_reconf = false; - state = RRC_STATE_CONNECTED; + if (ra_successful) { + state = RRC_STATE_CONNECTED; + } } else { rrc_log->error("Received HO random access completed but no pending mobility reconfiguration info\n"); } diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 54b07f8ef..444f9e156 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -154,6 +154,10 @@ enable = false # average_subframe_enabled: Averages in the time domain the channel estimates within 1 subframe. # Needs accurate CFO correction. # +# sic_pss_enabled: Applies Successive Interference Cancellation to PSS signals when searching for neighbour cells. +# Must be disabled if cells have identical channel and timing, for instance if generated from +# the same source. +# # metrics_csv_enable: Write UE metrics to CSV file. # # metrics_csv_filename: File path to use for CSV metrics. @@ -191,6 +195,7 @@ enable = false #sss_algorithm = full #estimator_fil_w = 0.1 #average_subframe_enabled = false +#sic_pss_enabled = true #pregenerate_signals = false #metrics_csv_enable = false #metrics_csv_filename = /tmp/ue_metrics.csv From 78bd71dfa93a4c1ef889e62286f5c14f49217964 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Mon, 4 Dec 2017 11:58:16 -0600 Subject: [PATCH 27/42] Fixed ul retx when not needed --- srsue/hdr/mac/ul_harq.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/srsue/hdr/mac/ul_harq.h b/srsue/hdr/mac/ul_harq.h index d162d35a2..bd38fca97 100644 --- a/srsue/hdr/mac/ul_harq.h +++ b/srsue/hdr/mac/ul_harq.h @@ -219,7 +219,7 @@ private: // Receive and route HARQ feedbacks if (grant) { - if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi[0] != get_ndi() && ack) || + if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi[0] != get_ndi() && harq_feedback) || (grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) || grant->is_from_rar) { @@ -327,12 +327,12 @@ private: current_irv = irv_of_rv[grant->rv[0]%4]; } + Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d, HI=%s, ndi=%d, prev_ndi=%d\n", + pid, current_tx_nb, get_rv(), grant->n_bytes[0], harq_feedback?"ACK":"NACK", grant->ndi[0], cur_grant.ndi[0]); + memcpy(&cur_grant, grant, sizeof(Tgrant)); harq_feedback = false; - Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d, HI=%s\n", - pid, current_tx_nb, get_rv(), grant->n_bytes[0], harq_feedback?"ACK":"NACK"); - generate_tx(tti_tx, action); // HARQ entity requests a non-adaptive transmission From 0bd683b3c4455e1274450d4487a6077f231f0ba5 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 14 Nov 2017 17:11:48 +0100 Subject: [PATCH 28/42] Added UE Mode 3-1 aperiodic reporting --- lib/include/srslte/phy/phch/cqi.h | 21 +++- lib/include/srslte/phy/phch/uci.h | 1 + lib/src/phy/phch/cqi.c | 73 +++++++++++-- lib/src/phy/phch/pucch.c | 2 +- lib/src/phy/ue/ue_dl.c | 4 +- lib/src/phy/ue/ue_ul.c | 28 +++-- srsenb/src/phy/phch_worker.cc | 2 +- srsue/hdr/phy/phch_worker.h | 3 +- srsue/src/phy/phch_worker.cc | 175 ++++++++++++++++++++---------- 9 files changed, 221 insertions(+), 88 deletions(-) diff --git a/lib/include/srslte/phy/phch/cqi.h b/lib/include/srslte/phy/phch/cqi.h index cfc9e92e7..0d0c17fec 100644 --- a/lib/include/srslte/phy/phch/cqi.h +++ b/lib/include/srslte/phy/phch/cqi.h @@ -55,13 +55,22 @@ typedef struct { } srslte_cqi_periodic_cfg_t; /* Table 5.2.2.6.2-1: Fields for channel quality information feedback for higher layer configured subband -CQI reports -(transmission mode 1, transmission mode 2, transmission mode 3, transmission mode 7 and -transmission mode 8 configured without PMI/RI reporting). */ + CQI reports (transmission mode 1, transmission mode 2, transmission mode 3, transmission mode 7 and + transmission mode 8 configured without PMI/RI reporting). */ + +/* Table 5.2.2.6.2-2: Fields for channel quality information (CQI) feedback for higher layer configured subband CQI + reports (transmission mode 4, transmission mode 5 and transmission mode 6). */ + typedef struct SRSLTE_API { - uint8_t wideband_cqi; // 4-bit width - uint32_t subband_diff_cqi; // 2N-bit width - uint32_t N; + uint8_t wideband_cqi_cw0; // 4-bit width + uint32_t subband_diff_cqi_cw0; // 2N-bit width + uint8_t wideband_cqi_cw1; // if RI > 1 then 4-bit width otherwise 0-bit width + uint32_t subband_diff_cqi_cw1; // if RI > 1 then 2N-bit width otherwise 0-bit width + uint32_t pmi; // if RI > 1 then 2-bit width otherwise 1-bit width + uint32_t N; + bool pmi_present; + bool four_antenna_ports; // If cell has 4 antenna ports then true otherwise false + bool rank_is_not_one; // If rank > 1 then true otherwise false } srslte_cqi_hl_subband_t; /* Table 5.2.2.6.3-1: Fields for channel quality information feedback for UE selected subband CQI diff --git a/lib/include/srslte/phy/phch/uci.h b/lib/include/srslte/phy/phch/uci.h index ff315384e..91592501f 100644 --- a/lib/include/srslte/phy/phch/uci.h +++ b/lib/include/srslte/phy/phch/uci.h @@ -73,6 +73,7 @@ typedef struct SRSLTE_API { uint8_t uci_ack; // 1st codeword bit for HARQ-ACK uint8_t uci_ack_2; // 2st codeword bit for HARQ-ACK uint32_t uci_ack_len; + bool ri_periodic_report; bool scheduling_request; bool channel_selection; bool cqi_ack; diff --git a/lib/src/phy/phch/cqi.c b/lib/src/phy/phch/cqi.c index 0041c3fcb..2c0940af5 100644 --- a/lib/src/phy/phch/cqi.c +++ b/lib/src/phy/phch/cqi.c @@ -44,11 +44,38 @@ *******************************************************/ int srslte_cqi_hl_subband_pack(srslte_cqi_hl_subband_t *msg, uint8_t buff[SRSLTE_CQI_MAX_BITS]) { - uint8_t *body_ptr = buff; - srslte_bit_unpack(msg->wideband_cqi, &body_ptr, 4); - srslte_bit_unpack(msg->subband_diff_cqi, &body_ptr, 2*msg->N); - - return 4+2*msg->N; + uint8_t *body_ptr = buff; + uint32_t bit_count = 0; + + /* Unpack codeword 0, common for 3GPP 36.212 Tables 5.2.2.6.2-1 and 5.2.2.6.2-2 */ + srslte_bit_unpack(msg->wideband_cqi_cw0, &body_ptr, 4); + srslte_bit_unpack(msg->subband_diff_cqi_cw0, &body_ptr, 2*msg->N); + bit_count += 4+2*msg->N; + + /* Unpack codeword 1, 3GPP 36.212 Table 5.2.2.6.2-2 */ + if (msg->rank_is_not_one) { + srslte_bit_unpack(msg->wideband_cqi_cw1, &body_ptr, 4); + srslte_bit_unpack(msg->subband_diff_cqi_cw1, &body_ptr, 2*msg->N); + bit_count += 4+2*msg->N; + } + + /* If PMI is present, unpack it */ + if (msg->pmi_present) { + if (msg->four_antenna_ports) { + srslte_bit_unpack(msg->pmi, &body_ptr, 4); + bit_count += 4; + } else { + if (msg->rank_is_not_one) { + srslte_bit_unpack(msg->pmi, &body_ptr, 1); + bit_count += 1; + } else { + srslte_bit_unpack(msg->pmi, &body_ptr, 2); + bit_count += 2; + } + } + } + + return bit_count; } int srslte_cqi_ue_subband_pack(srslte_cqi_ue_subband_t *msg, uint8_t buff[SRSLTE_CQI_MAX_BITS]) @@ -98,11 +125,37 @@ int srslte_cqi_value_pack(srslte_cqi_value_t *value, uint8_t buff[SRSLTE_CQI_MAX int srslte_cqi_hl_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_hl_subband_t *msg) { - uint8_t *body_ptr = buff; - msg->wideband_cqi = srslte_bit_pack(&body_ptr, 4); - msg->subband_diff_cqi = srslte_bit_pack(&body_ptr, 2*msg->N); - - return 4+2*msg->N; + uint8_t *body_ptr = buff; + uint32_t bit_count = 0; + + msg->wideband_cqi_cw0 = (uint8_t) srslte_bit_pack(&body_ptr, 4); + msg->subband_diff_cqi_cw0 = srslte_bit_pack(&body_ptr, 2*msg->N); + bit_count += 4+2*msg->N; + + /* Unpack codeword 1, 3GPP 36.212 Table 5.2.2.6.2-2 */ + if (msg->rank_is_not_one) { + msg->wideband_cqi_cw1 = (uint8_t) srslte_bit_pack(&body_ptr, 4); + msg->subband_diff_cqi_cw1 = srslte_bit_pack(&body_ptr, 2*msg->N); + bit_count += 4+2*msg->N; + } + + /* If PMI is present, unpack it */ + if (msg->pmi_present) { + if (msg->four_antenna_ports) { + msg->pmi = (uint8_t) srslte_bit_pack(&body_ptr, 4); + bit_count += 4; + } else { + if (msg->rank_is_not_one) { + msg->pmi = (uint8_t) srslte_bit_pack(&body_ptr, 1); + bit_count += 1; + } else { + msg->pmi = (uint8_t) srslte_bit_pack(&body_ptr, 2); + bit_count += 2; + } + } + } + + return bit_count; } int srslte_cqi_ue_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_ue_subband_t *msg) diff --git a/lib/src/phy/phch/pucch.c b/lib/src/phy/phch/pucch.c index f9c6bebc1..f9c05104c 100644 --- a/lib/src/phy/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -173,7 +173,7 @@ srslte_pucch_format_t srslte_pucch_get_format(srslte_uci_data_t *uci_data, srslt { srslte_pucch_format_t format = SRSLTE_PUCCH_FORMAT_ERROR; // No CQI data - if (uci_data->uci_cqi_len == 0) { + if (uci_data->uci_cqi_len == 0 && uci_data->uci_ri_len == 0) { // 1-bit ACK + optional SR if (uci_data->uci_ack_len == 1) { format = SRSLTE_PUCCH_FORMAT_1A; diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 134c19ca6..db7118b0c 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -740,6 +740,7 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo } /* Set RI */ + q->ri = best_ri; if (ri != NULL) { *ri = best_ri; } @@ -775,9 +776,10 @@ int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, uint8_t *ri, float *cn) { *cn = _cn; } + q->ri = (uint8_t)((_cn < 17.0f)? 1:0); /* Set rank indicator */ if (!ret && ri) { - *ri = (uint8_t)((_cn < 17.0f)? 1:0); + *ri = (uint8_t) q->ri; } return ret; diff --git a/lib/src/phy/ue/ue_ul.c b/lib/src/phy/ue/ue_ul.c index bb4fd57ae..736fc3470 100644 --- a/lib/src/phy/ue/ue_ul.c +++ b/lib/src/phy/ue/ue_ul.c @@ -273,21 +273,33 @@ int srslte_ue_ul_cfg_grant(srslte_ue_ul_t *q, srslte_ra_ul_grant_t *grant, void pucch_encode_bits(srslte_uci_data_t *uci_data, srslte_pucch_format_t format, uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS], uint8_t pucch2_bits[SRSLTE_PUCCH_MAX_BITS]) -{ +{ + uint8_t uci_buffer[SRSLTE_CQI_MAX_BITS]; + uint8_t uci_buffer_len = 0; + if (format == SRSLTE_PUCCH_FORMAT_1A || format == SRSLTE_PUCCH_FORMAT_1B) { pucch_bits[0] = uci_data->uci_ack; pucch_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 1a } if (format >= SRSLTE_PUCCH_FORMAT_2) { - /* Append Differential CQI */ - memcpy(&uci_data->uci_cqi[uci_data->uci_cqi_len], uci_data->uci_dif_cqi, uci_data->uci_dif_cqi_len); - uci_data->uci_cqi_len += uci_data->uci_dif_cqi_len; + /* Put RI (goes alone) */ + if (uci_data->ri_periodic_report) { + uci_buffer[0] = uci_data->uci_ri; // It assumes only 1 bit of RI + uci_buffer_len += uci_data->uci_ri_len; + } else { + /* Append CQI */ + memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_cqi, uci_data->uci_cqi_len); + uci_buffer_len += uci_data->uci_cqi_len; - /* Append PMI */ - memcpy(&uci_data->uci_cqi[uci_data->uci_cqi_len], uci_data->uci_pmi, uci_data->uci_pmi_len); - uci_data->uci_cqi_len += uci_data->uci_pmi_len; + /* Append Differential CQI */ + memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_dif_cqi, uci_data->uci_dif_cqi_len); + uci_buffer_len += uci_data->uci_dif_cqi_len; - srslte_uci_encode_cqi_pucch(uci_data->uci_cqi, uci_data->uci_cqi_len, pucch_bits); + /* Append PMI */ + memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_pmi, uci_data->uci_pmi_len); + uci_buffer_len += uci_data->uci_pmi_len; + } + srslte_uci_encode_cqi_pucch(uci_buffer, uci_buffer_len, pucch_bits); if (format > SRSLTE_PUCCH_FORMAT_2) { pucch2_bits[0] = uci_data->uci_ack; pucch2_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 2a diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc index c023c13e0..5298e6e7a 100644 --- a/srsenb/src/phy/phch_worker.cc +++ b/srsenb/src/phy/phch_worker.cc @@ -461,7 +461,7 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) if (ue_db[rnti].cqi_en) { wideband_cqi_value = cqi_value.wideband.wideband_cqi; } else if (grants[i].grant.cqi_request) { - wideband_cqi_value = cqi_value.subband_hl.wideband_cqi; + wideband_cqi_value = cqi_value.subband_hl.wideband_cqi_cw0; } snprintf(cqi_str, 64, ", cqi=%d", wideband_cqi_value); } diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index 4f8df27db..5378a9428 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -76,7 +76,8 @@ private: /* Internal methods */ bool extract_fft_and_pdcch_llr(); - + void compute_ri(); + /* ... for DL */ bool decode_pdcch_ul(mac_interface_phy::mac_grant_t *grant); bool decode_pdcch_dl(mac_interface_phy::mac_grant_t *grant); diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 27503c9f7..0068724b4 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -272,39 +272,6 @@ void phch_worker::work_imp() if (dl_action.generate_ack) { set_uci_ack(dl_ack, dl_mac_grant.tb_en); } - - /* Select Rank Indicator by computing Condition Number */ - if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3) { - if (ue_dl.nof_rx_antennas > 1) { - /* If 2 ort more receiving antennas, select RI */ - float cn = 0.0f; - srslte_ue_dl_ri_select(&ue_dl, &uci_data.uci_ri, &cn); - uci_data.uci_ri_len = 1; - } else { - /* If only one receiving antenna, force RI for 1 layer */ - uci_data.uci_ri = 0; - uci_data.uci_ri_len = 1; - Warning("Only one receiving antenna with TM3. Forcing RI=1 layer.\n"); - } - } else if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4){ - float sinr = 0.0f; - uint8 packed_pmi = 0; - srslte_ue_dl_ri_pmi_select(&ue_dl, &uci_data.uci_ri, &packed_pmi, &sinr); - srslte_bit_unpack_vector(&packed_pmi, uci_data.uci_pmi, 2); - uci_data.uci_ri_len = 1; - if (uci_data.uci_ri == 0) { - uci_data.uci_pmi_len = 2; - uci_data.uci_dif_cqi_len = 0; - } else { - uci_data.uci_pmi_len = 1; - uci_data.uci_dif_cqi_len = 3; - } - - /* If only one antenna in TM4 print limitation warning */ - if (ue_dl.nof_rx_antennas < 2) { - Warning("Only one receiving antenna with TM4. Forcing RI=1 layer (PMI=%d).\n", packed_pmi); - } - } } } @@ -360,7 +327,7 @@ void phch_worker::work_imp() phy->set_pending_ack(TTI_RX_ACK(tti), ue_ul.pusch_cfg.grant.n_prb_tilde[0], ul_action.phy_grant.ul.ncs_dmrs); } - } else if (dl_action.generate_ack || uci_data.scheduling_request || uci_data.uci_cqi_len > 0) { + } else if (dl_action.generate_ack || uci_data.scheduling_request || uci_data.uci_cqi_len > 0 || uci_data.uci_ri_len > 0) { encode_pucch(); signal_ready = true; } else if (srs_is_ready_to_send()) { @@ -410,6 +377,42 @@ void phch_worker::work_imp() #endif } +void phch_worker::compute_ri() { + if (uci_data.uci_ri_len > 0) { + /* Do nothing */ + } else if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3) { + if (ue_dl.nof_rx_antennas > 1) { + /* If 2 ort more receiving antennas, select RI */ + float cn = 0.0f; + srslte_ue_dl_ri_select(&ue_dl, &uci_data.uci_ri, &cn); + Info("RI select %d layers, κ=%fdB\n", uci_data.uci_ri + 1, cn); + } else { + /* If only one receiving antenna, force RI for 1 layer */ + uci_data.uci_ri = 0; + Warning("Only one receiving antenna with TM3. Forcing RI=1 layer.\n"); + } + uci_data.uci_ri_len = 1; + } else if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { + float sinr = 0.0f; + uint8 packed_pmi = 0; + srslte_ue_dl_ri_pmi_select(&ue_dl, &uci_data.uci_ri, &packed_pmi, &sinr); + if (uci_data.uci_ri == 0) { + uci_data.uci_pmi_len = 2; + uci_data.uci_dif_cqi_len = 0; + } else { + uci_data.uci_pmi_len = 1; + uci_data.uci_dif_cqi_len = 3; + } + srslte_bit_unpack_vector(&packed_pmi, uci_data.uci_pmi, uci_data.uci_pmi_len); + Info("ri=%d; pmi=%d; SINR=%.1fdB\n", ue_dl.ri, ue_dl.pmi[ue_dl.ri], 10*log10f(ue_dl.sinr[ue_dl.ri][ue_dl.pmi[ue_dl.ri]])); + + /* If only one antenna in TM4 print limitation warning */ + if (ue_dl.nof_rx_antennas < 2) { + Warning("Only one receiving antenna with TM4. Forcing RI=1 layer (PMI=%d).\n", packed_pmi); + } + uci_data.uci_ri_len = 1; + } +} bool phch_worker::extract_fft_and_pdcch_llr() { bool decode_pdcch = true; @@ -823,21 +826,15 @@ void phch_worker::reset_uci() void phch_worker::set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], bool tb_en[SRSLTE_MAX_CODEWORDS]) { - uint32_t nof_tb = 0; - if (tb_en[0]) { - uci_data.uci_ack = (uint8_t) ((ack[0]) ? 1 : 0); - nof_tb = 1; - } else { - uci_data.uci_ack = 1; - } - - if (tb_en[1]) { - uci_data.uci_ack_2 = (uint8_t) ((ack[1]) ? 1 : 0); - nof_tb = 2; + /* Map ACK according to 3GPP 36.212 clause 5.2.3.1 */ + uint32_t nof_ack = 0; + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + if (tb_en[tb]) { + ((nof_ack == 0)?uci_data.uci_ack:uci_data.uci_ack_2) = (uint8_t)(ack[tb]?1:0); + nof_ack++; + } } - - uci_data.uci_ack_len = nof_tb; - + uci_data.uci_ack_len = nof_ack; } void phch_worker::set_uci_sr() @@ -862,14 +859,9 @@ void phch_worker::set_uci_periodic_cqi() if (period_cqi.configured && rnti_is_set) { if (period_cqi.ri_idx_present && srslte_ri_send(period_cqi.pmi_idx, period_cqi.ri_idx, TTI_TX(tti))) { - if (uci_data.uci_ri_len) { - uci_data.uci_cqi[0] = uci_data.uci_ri; - uci_data.uci_cqi_len = uci_data.uci_ri_len; - uci_data.uci_ri_len = 0; - uci_data.uci_dif_cqi_len = 0; - uci_data.uci_pmi_len = 0; - Info("PUCCH: Periodic RI=%d\n", uci_data.uci_cqi[0]); - } + compute_ri(); + uci_data.ri_periodic_report = true; + Info("PUCCH: Periodic RI=%d\n", uci_data.uci_ri); } else if (srslte_cqi_send(period_cqi.pmi_idx, TTI_TX(tti))) { srslte_cqi_value_t cqi_report; if (period_cqi.format_is_subband) { @@ -891,6 +883,16 @@ void phch_worker::set_uci_periodic_cqi() } Info("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db); } + if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { + if (ue_dl.ri == 0) { + uci_data.uci_pmi_len = 2; + } else { + uci_data.uci_pmi_len = 1; + uci_data.uci_dif_cqi_len = 3; + } + uint8_t *ptr = uci_data.uci_pmi; + srslte_bit_unpack(ue_dl.pmi[ue_dl.ri], &ptr, uci_data.uci_pmi_len); + } uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); rar_cqi_request = false; } @@ -912,18 +914,71 @@ void phch_worker::set_uci_aperiodic_cqi() reported RI. For other transmission modes they are reported conditioned on rank 1. */ if (rnti_is_set) { - srslte_cqi_value_t cqi_report; + srslte_cqi_value_t cqi_report = {0}; cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND_HL; - cqi_report.subband_hl.wideband_cqi = srslte_cqi_from_snr(phy->avg_snr_db); + cqi_report.subband_hl.wideband_cqi_cw0 = srslte_cqi_from_snr(phy->avg_snr_db); // TODO: implement subband CQI properly - cqi_report.subband_hl.subband_diff_cqi = 0; // Always report zero offset on all subbands + cqi_report.subband_hl.subband_diff_cqi_cw0 = 0; // Always report zero offset on all subbands cqi_report.subband_hl.N = (cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(cell.nof_prb) : 0; Info("PUSCH: Aperiodic CQI=%d, SNR=%.1f dB, for %d subbands\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db, cqi_report.subband_hl.N); uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); } break; + case LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31: + /* only Higher Layer-configured subband feedback support right now, according to TS36.213 section 7.2.1 + - A single precoding matrix is selected from the codebook subset assuming transmission on set S subbands + - A UE shall report one subband CQI value per codeword for each set S subband which are calculated assuming + the use of the single precoding matrix in all subbands and assuming transmission in the corresponding + subband. + - A UE shall report a wideband CQI value per codeword which is calculated assuming the use of the single + precoding matrix in all subbands and transmission on set S subbands + - The UE shall report the single selected precoding matrix indicator. + - For transmission mode 4 the reported PMI and CQI values are calculated conditioned on the reported RI. For + other transmission modes they are reported conditioned on rank 1. + */ + if (rnti_is_set) { + /* Compute RI, PMI and SINR */ + compute_ri(); + + /* Select RI, PMI and SINR */ + uint32_t ri = ue_dl.ri; // Select RI (0: 1 layer, 1: 2 layer, otherwise: not implemented) + uint32_t pmi = ue_dl.pmi[ri]; // Select PMI + float sinr_db = 10 * log10(ue_dl.sinr[ri][pmi]); + + /* Fill CQI Report */ + srslte_cqi_value_t cqi_report = {0}; + cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND_HL; + + cqi_report.subband_hl.wideband_cqi_cw0 = srslte_cqi_from_snr(sinr_db); + cqi_report.subband_hl.subband_diff_cqi_cw0 = 0; // Always report zero offset on all subbands + + if (ri > 0) { + cqi_report.subband_hl.rank_is_not_one = true; + cqi_report.subband_hl.wideband_cqi_cw1 = srslte_cqi_from_snr(sinr_db); + cqi_report.subband_hl.subband_diff_cqi_cw1 = 0; // Always report zero offset on all subbands + } + + cqi_report.subband_hl.pmi = pmi; + cqi_report.subband_hl.pmi_present = true; + cqi_report.subband_hl.four_antenna_ports = (cell.nof_ports == 4); + + // TODO: implement subband CQI properly + cqi_report.subband_hl.N = (uint32_t) ((cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(cell.nof_prb) : 0); + + if (cqi_report.subband_hl.rank_is_not_one) { + Info("PUSCH: Aperiodic ri~1, CQI=%02d/%02d, SINR=%2.1f/%2.1fdB, pmi=%d for %d subbands\n", + cqi_report.subband_hl.wideband_cqi_cw0, cqi_report.subband_hl.wideband_cqi_cw1, + sinr_db, sinr_db, pmi, cqi_report.subband_hl.N); + } else { + Info("PUSCH: Aperiodic ri=1, CQI=%d/%d, SINR=%2.1f dB, for %d subbands\n", + cqi_report.wideband.wideband_cqi, + phy->avg_snr_db, cqi_report.subband_hl.N); + } + uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); + } + break; default: Warning("Received CQI request but mode %s is not supported\n", liblte_rrc_cqi_report_mode_aperiodic_text[phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic]); @@ -1006,7 +1061,7 @@ void phch_worker::encode_pucch() char timestr[64]; timestr[0]='\0'; - if (uci_data.scheduling_request || uci_data.uci_ack_len > 0 || uci_data.uci_cqi_len > 0) + if (uci_data.scheduling_request || uci_data.uci_ack_len > 0 || uci_data.uci_cqi_len > 0 || uci_data.uci_ri_len > 0) { // Drop CQI if there is collision with ACK From 8ab196901f83caef3759e89b98b1b3b10d26cd1b Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 16 Nov 2017 14:48:03 +0100 Subject: [PATCH 29/42] Added Aperiodic mode 3-1 in enb and some more optimizations --- lib/include/srslte/phy/enb/enb_ul.h | 1 + lib/include/srslte/phy/phch/pusch.h | 1 + lib/include/srslte/phy/phch/uci.h | 36 ++- lib/src/phy/enb/enb_ul.c | 45 +++- lib/src/phy/phch/cqi.c | 37 ++- lib/src/phy/phch/pusch.c | 35 ++- lib/src/phy/phch/sch.c | 19 +- lib/src/phy/phch/test/pusch_test.c | 2 +- lib/src/phy/phch/uci.c | 230 ++++++++---------- lib/src/phy/ue/ue_dl.c | 3 +- srsenb/src/phy/phch_worker.cc | 362 +++++++++++++++++++--------- srsenb/src/upper/rrc.cc | 6 +- srsue/src/phy/phch_worker.cc | 14 +- 13 files changed, 491 insertions(+), 300 deletions(-) diff --git a/lib/include/srslte/phy/enb/enb_ul.h b/lib/include/srslte/phy/enb/enb_ul.h index 0957ccbc0..1b865b7f7 100644 --- a/lib/include/srslte/phy/enb/enb_ul.h +++ b/lib/include/srslte/phy/enb/enb_ul.h @@ -141,6 +141,7 @@ SRSLTE_API int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, uint32_t rv_idx, uint32_t current_tx_nb, uint8_t *data, + srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data, uint32_t tti); diff --git a/lib/include/srslte/phy/phch/pusch.h b/lib/include/srslte/phy/phch/pusch.h index 2328c8ff3..01db068a5 100644 --- a/lib/include/srslte/phy/phch/pusch.h +++ b/lib/include/srslte/phy/phch/pusch.h @@ -142,6 +142,7 @@ SRSLTE_API int srslte_pusch_decode(srslte_pusch_t *q, float noise_estimate, uint16_t rnti, uint8_t *data, + srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data); SRSLTE_API float srslte_pusch_average_noi(srslte_pusch_t *q); diff --git a/lib/include/srslte/phy/phch/uci.h b/lib/include/srslte/phy/phch/uci.h index 91592501f..8e72b5793 100644 --- a/lib/include/srslte/phy/phch/uci.h +++ b/lib/include/srslte/phy/phch/uci.h @@ -131,31 +131,25 @@ SRSLTE_API int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, uint32_t H_prime_total, srslte_uci_bit_t *ri_bits); -SRSLTE_API int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, - int16_t *q_bits, - uint8_t *c_seq, - float beta, - uint32_t H_prime_total, - uint32_t O_cqi, - srslte_uci_bit_t *ack_bits, - uint8_t acks[2], - uint32_t nof_acks); - -SRSLTE_API int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg, - uint8_t data, +SRSLTE_API int srslte_uci_encode_ack_ri(srslte_pusch_cfg_t *cfg, + uint8_t *data, + uint32_t data_len, uint32_t O_cqi, float beta, uint32_t H_prime_total, - srslte_uci_bit_t *ri_bits); - -SRSLTE_API int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, - int16_t *q_bits, - uint8_t *c_seq, - float beta, - uint32_t H_prime_total, - uint32_t O_cqi, srslte_uci_bit_t *ri_bits, - uint8_t *data); + bool is_ri); + +SRSLTE_API int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t *cfg, + int16_t *q_bits, + uint8_t *c_seq, + float beta, + uint32_t H_prime_total, + uint32_t O_cqi, + srslte_uci_bit_t *ack_ri_bits, + uint8_t data[2], + uint32_t nof_bits, + bool is_ri); #endif diff --git a/lib/src/phy/enb/enb_ul.c b/lib/src/phy/enb/enb_ul.c index f94eb0277..8ea5dd3e4 100644 --- a/lib/src/phy/enb/enb_ul.c +++ b/lib/src/phy/enb/enb_ul.c @@ -253,18 +253,22 @@ int srslte_enb_ul_cfg_ue(srslte_enb_ul_t *q, uint16_t rnti, } } -void srslte_enb_ul_fft(srslte_enb_ul_t *q, cf_t *signal_buffer) +void srslte_enb_ul_fft(srslte_enb_ul_t *q) { srslte_ofdm_rx_sf(&q->fft); } int get_pucch(srslte_enb_ul_t *q, uint16_t rnti, uint32_t pdcch_n_cce, uint32_t sf_rx, - srslte_uci_data_t *uci_data, uint8_t bits[SRSLTE_PUCCH_MAX_BITS]) + srslte_uci_data_t *uci_data, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], uint32_t nof_bits) { float noise_power = srslte_chest_ul_get_noise_estimate(&q->chest); srslte_pucch_format_t format = srslte_pucch_get_format(uci_data, q->cell.cp); + if (format == SRSLTE_PUCCH_FORMAT_ERROR) { + fprintf(stderr,"Error getting format\n"); + return SRSLTE_ERROR; + } uint32_t n_pucch = srslte_pucch_get_npucch(pdcch_n_cce, format, uci_data->scheduling_request, &q->users[rnti]->pucch_sched); @@ -273,7 +277,7 @@ int get_pucch(srslte_enb_ul_t *q, uint16_t rnti, return SRSLTE_ERROR; } - int ret_val = srslte_pucch_decode(&q->pucch, format, n_pucch, sf_rx, rnti, q->sf_symbols, q->ce, noise_power, bits); + int ret_val = srslte_pucch_decode(&q->pucch, format, n_pucch, sf_rx, rnti, q->sf_symbols, q->ce, noise_power, bits, nof_bits); if (ret_val < 0) { fprintf(stderr,"Error decoding PUCCH\n"); return SRSLTE_ERROR; @@ -286,16 +290,18 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti, srslte_uci_data_t *uci_data) { uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS]; - - if (q->users[rnti]) { - int ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits); + if (q->users[rnti]) { + uint32_t nof_uci_bits = uci_data->ri_periodic_report ? uci_data->uci_ri_len : (uci_data->uci_cqi_len + + uci_data->uci_dif_cqi_len + + uci_data->uci_pmi_len); + int ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits, nof_uci_bits); // If we are looking for SR and ACK at the same time and ret=0, means there is no SR. // try again to decode ACK only if (uci_data->scheduling_request && uci_data->uci_ack_len && ret_val != 1) { uci_data->scheduling_request = false; - ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits); + ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits, nof_uci_bits); } // update schedulign request @@ -305,12 +311,32 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti, // Save ACK bits if (uci_data->uci_ack_len > 0) { - uci_data->uci_ack = pucch_bits[0]; + uci_data->uci_ack = pucch_bits[0]; + } + + if (uci_data->uci_ack_len > 1) { + uci_data->uci_ack_2 = pucch_bits[1]; } // PUCCH2 CQI bits are decoded inside srslte_pucch_decode() if (uci_data->uci_cqi_len) { memcpy(uci_data->uci_cqi, pucch_bits, uci_data->uci_cqi_len*sizeof(uint8_t)); + } + + if (uci_data->uci_dif_cqi_len) { + memcpy(uci_data->uci_dif_cqi, pucch_bits + uci_data->uci_cqi_len, uci_data->uci_dif_cqi_len*sizeof(uint8_t)); + } + + if (uci_data->uci_pmi_len) { + memcpy(uci_data->uci_pmi, pucch_bits + uci_data->uci_cqi_len + uci_data->uci_dif_cqi_len, + uci_data->uci_pmi_len*sizeof(uint8_t)); + } + + if (uci_data->uci_ri_len) { + uci_data->uci_ri = pucch_bits[0]; /* Assume only one bit of RI */ + } + + if (uci_data->uci_cqi_len || uci_data->uci_ri_len) { if (uci_data->uci_ack_len >= 1) { uci_data->uci_ack = pucch_bits[20]; } @@ -328,7 +354,7 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti, int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srslte_softbuffer_rx_t *softbuffer, uint16_t rnti, uint32_t rv_idx, uint32_t current_tx_nb, - uint8_t *data, srslte_uci_data_t *uci_data, uint32_t tti) + uint8_t *data, srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data, uint32_t tti) { if (q->users[rnti]) { if (srslte_pusch_cfg(&q->pusch, @@ -364,6 +390,7 @@ int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srs softbuffer, q->sf_symbols, q->ce, noise_power, rnti, data, + cqi_value, uci_data); } diff --git a/lib/src/phy/phch/cqi.c b/lib/src/phy/phch/cqi.c index 2c0940af5..8589ee51a 100644 --- a/lib/src/phy/phch/cqi.c +++ b/lib/src/phy/phch/cqi.c @@ -199,17 +199,44 @@ int srslte_cqi_value_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_value_ } int srslte_cqi_size(srslte_cqi_value_t *value) { + int size = 0; + switch(value->type) { case SRSLTE_CQI_TYPE_WIDEBAND: - return 4; + size = 4; + break; case SRSLTE_CQI_TYPE_SUBBAND: - return 4+(value->subband.subband_label_2_bits)?2:1; + size = 4 + (value->subband.subband_label_2_bits) ? 2 : 1; + break; case SRSLTE_CQI_TYPE_SUBBAND_UE: - return 4+2+value->subband_ue.L; + size = 4 + 2 + value->subband_ue.L; + break; case SRSLTE_CQI_TYPE_SUBBAND_HL: - return 4+2*value->subband_hl.N; + /* First codeword */ + size += 4 + 2 * value->subband_hl.N; + + /* Add Second codeword if required */ + if (value->subband_hl.rank_is_not_one && value->subband_hl.pmi_present) { + size += 4 + 2 * value->subband_hl.N; + } + + /* Add PMI if required*/ + if (value->subband_hl.pmi_present) { + if (value->subband_hl.four_antenna_ports) { + size += 4; + } else { + if (value->subband_hl.rank_is_not_one) { + size += 1; + } else { + size += 2; + } + } + } + break; + default: + size = SRSLTE_ERROR; } - return -1; + return size; } static bool srslte_cqi_get_N(uint32_t I_cqi_pmi, uint32_t *N_p, uint32_t *N_offset) { diff --git a/lib/src/phy/phch/pusch.c b/lib/src/phy/phch/pusch.c index a8c6064fc..7876a4f86 100644 --- a/lib/src/phy/phch/pusch.c +++ b/lib/src/phy/phch/pusch.c @@ -566,9 +566,9 @@ int srslte_pusch_decode(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, cf_t *sf_symbols, cf_t *ce, float noise_estimate, uint16_t rnti, - uint8_t *data, srslte_uci_data_t *uci_data) + uint8_t *data, srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data) { - + int ret = SRSLTE_ERROR_INVALID_INPUTS; uint32_t n; if (q != NULL && @@ -607,19 +607,42 @@ int srslte_pusch_decode(srslte_pusch_t *q, // Generate scrambling sequence if not pre-generated srslte_sequence_t *seq = get_user_sequence(q, rnti, cfg->sf_idx, cfg->nbits.nof_bits); + // Set CQI len assuming RI = 1 (3GPP 36.212 Clause 5.2.4.1. Uplink control information on PUSCH without UL-SCH data) + if (cqi_value) { + if (cqi_value->type == SRSLTE_CQI_TYPE_SUBBAND_HL) { + cqi_value->subband_hl.rank_is_not_one = false; + } + uci_data->uci_cqi_len = (uint32_t) srslte_cqi_size(cqi_value); + uci_data->uci_ri_len = (q->cell.nof_ports == 4) ? 2 : 1; + } + // Decode RI/HARQ bits before descrambling if (srslte_ulsch_uci_decode_ri_ack(&q->ul_sch, cfg, softbuffer, q->q, seq->c, uci_data)) { fprintf(stderr, "Error decoding RI/HARQ bits\n"); return SRSLTE_ERROR; } + + // Set CQI len with corresponding RI + if (cqi_value) { + if (cqi_value->type == SRSLTE_CQI_TYPE_SUBBAND_HL) { + cqi_value->subband_hl.rank_is_not_one = (uci_data->uci_ri != 0); + } + uci_data->uci_cqi_len = (uint32_t) srslte_cqi_size(cqi_value); + } // Descrambling srslte_scrambling_s_offset(seq, q->q, 0, cfg->nbits.nof_bits); - - return srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data); - } else { - return SRSLTE_ERROR_INVALID_INPUTS; + + // Decode + ret = srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data); + + // Unpack CQI value if available + if (cqi_value) { + srslte_cqi_value_unpack(uci_data->uci_cqi, cqi_value); + } } + + return ret; } uint32_t srslte_pusch_last_noi(srslte_pusch_t *q) { diff --git a/lib/src/phy/phch/sch.c b/lib/src/phy/phch/sch.c index 930364725..1e972594d 100644 --- a/lib/src/phy/phch/sch.c +++ b/lib/src/phy/phch/sch.c @@ -658,7 +658,7 @@ int srslte_ulsch_uci_decode_ri_ack(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srs if (cfg->cb_segm.tbs == 0) { beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; } - ret = srslte_uci_decode_ack(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, acks, uci_data->uci_ack_len); + ret = srslte_uci_decode_ack_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, acks, uci_data->uci_ack_len, false); if (ret < 0) { return ret; } @@ -678,7 +678,7 @@ int srslte_ulsch_uci_decode_ri_ack(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srs if (cfg->cb_segm.tbs == 0) { beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; } - ret = srslte_uci_decode_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, &uci_data->uci_ri); + ret = srslte_uci_decode_ack_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, &uci_data->uci_ri, uci_data->uci_ri_len, true); if (ret < 0) { return ret; } @@ -756,13 +756,18 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q, uint32_t nb_q = cfg->nbits.nof_bits; uint32_t Qm = cfg->grant.Qm; - // Encode RI - if (uci_data.uci_ri_len > 0) { + // Encode RI if CQI enabled + if (uci_data.uci_ri_len > 0 || uci_data.uci_cqi_len > 0) { + /* If no RI is reported set it to zero as specified in 3GPP 36.213 clause 7.2.1 */ + if (uci_data.uci_ri_len == 0) { + uci_data.uci_ri = 0; + } float beta = beta_ri_offset[cfg->uci_cfg.I_offset_ri]; if (cfg->cb_segm.tbs == 0) { beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; } - ret = srslte_uci_encode_ri(cfg, uci_data.uci_ri, uci_data.uci_cqi_len, beta, nb_q/Qm, q->ack_ri_bits); + uint8_t ri[2] = {uci_data.uci_ri, 0}; + ret = srslte_uci_encode_ack_ri(cfg, ri, uci_data.uci_ri_len, uci_data.uci_cqi_len, beta, nb_q/Qm, q->ack_ri_bits, true); if (ret < 0) { return ret; } @@ -809,8 +814,8 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q, if (cfg->cb_segm.tbs == 0) { beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; } - ret = srslte_uci_encode_ack(cfg, acks, uci_data.uci_ack_len, uci_data.uci_cqi_len, - beta, nb_q / Qm, &q->ack_ri_bits[Q_prime_ri * Qm]); + ret = srslte_uci_encode_ack_ri(cfg, acks, uci_data.uci_ack_len, uci_data.uci_cqi_len, + beta, nb_q / Qm, &q->ack_ri_bits[Q_prime_ri * Qm], false); if (ret < 0) { return ret; } diff --git a/lib/src/phy/phch/test/pusch_test.c b/lib/src/phy/phch/test/pusch_test.c index cf0be75c3..651803617 100644 --- a/lib/src/phy/phch/test/pusch_test.c +++ b/lib/src/phy/phch/test/pusch_test.c @@ -252,7 +252,7 @@ int main(int argc, char **argv) { } gettimeofday(&t[1], NULL); - int r = srslte_pusch_decode(&pusch_rx, &cfg, &softbuffer_rx, sf_symbols, ce, 0, rnti, data, &uci_data_rx); + int r = srslte_pusch_decode(&pusch_rx, &cfg, &softbuffer_rx, sf_symbols, ce, 0, rnti, data, NULL, &uci_data_rx); gettimeofday(&t[2], NULL); get_time_interval(t); if (r) { diff --git a/lib/src/phy/phch/uci.c b/lib/src/phy/phch/uci.c index cb09ca08b..8a1a36544 100644 --- a/lib/src/phy/phch/uci.c +++ b/lib/src/phy/phch/uci.c @@ -103,26 +103,29 @@ static uint8_t M_basis_seq_pucch[20][13]={ {1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1}, {1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0}, - }; + }; void srslte_uci_cqi_pucch_init(srslte_uci_cqi_pucch_t *q) { - uint8_t word[16]; - - uint32_t nwords = 16; - for (uint32_t w=0;wcqi_table[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B*sizeof(int8_t)); - q->cqi_table_s[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B*sizeof(int16_t)); + uint8_t word[16]; + + uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH; + q->cqi_table = srslte_vec_malloc(nwords * sizeof(int8_t *)); + q->cqi_table_s = srslte_vec_malloc(nwords * sizeof(int16_t *)); + + for (uint32_t w = 0; w < nwords; w++) { + q->cqi_table[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B * sizeof(int8_t)); + q->cqi_table_s[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B * sizeof(int16_t)); uint8_t *ptr = word; - srslte_bit_unpack(w, &ptr, 4); - srslte_uci_encode_cqi_pucch(word, 4, q->cqi_table[w]); - for (int j=0;jcqi_table_s[w][j] = 2*q->cqi_table[w][j]-1; + srslte_bit_unpack(w, &ptr, SRSLTE_UCI_MAX_CQI_LEN_PUCCH); + srslte_uci_encode_cqi_pucch(word, SRSLTE_UCI_MAX_CQI_LEN_PUCCH, q->cqi_table[w]); + for (int j = 0; j < SRSLTE_UCI_CQI_CODED_PUCCH_B; j++) { + q->cqi_table_s[w][j] = (int16_t)(2 * q->cqi_table[w][j] - 1); } } } void srslte_uci_cqi_pucch_free(srslte_uci_cqi_pucch_t *q) { - uint32_t nwords = 16; + uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH; for (uint32_t w=0;wcqi_table[w]) { free(q->cqi_table[w]); @@ -131,6 +134,8 @@ void srslte_uci_cqi_pucch_free(srslte_uci_cqi_pucch_t *q) { free(q->cqi_table_s[w]); } } + free(q->cqi_table); + free(q->cqi_table_s); } /* Encode UCI CQI/PMI as described in 5.2.3.3 of 36.212 @@ -151,17 +156,32 @@ int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_b } } +int srslte_uci_encode_cqi_pucch_from_table(srslte_uci_cqi_pucch_t *q, uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]) +{ + if (cqi_len <= SRSLTE_UCI_MAX_CQI_LEN_PUCCH) { + bzero(&cqi_data[cqi_len], SRSLTE_UCI_MAX_CQI_LEN_PUCCH - cqi_len); + uint8_t *ptr = cqi_data; + uint32_t packed = srslte_bit_pack(&ptr, SRSLTE_UCI_MAX_CQI_LEN_PUCCH); + memcpy(b_bits, q->cqi_table[packed], SRSLTE_UCI_CQI_CODED_PUCCH_B); + + return SRSLTE_SUCCESS; + } else { + return SRSLTE_ERROR_INVALID_INPUTS; + } +} + /* Decode UCI CQI/PMI over PUCCH */ int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, int16_t b_bits[32], uint8_t *cqi_data, uint32_t cqi_len) { - if (cqi_len == 4 && + if (cqi_len < SRSLTE_UCI_MAX_CQI_LEN_PUCCH && b_bits != NULL && cqi_data != NULL) { uint32_t max_w = 0; - int32_t max_corr = INT32_MIN; - for (uint32_t w=0;w<16;w++) { + int32_t max_corr = INT32_MIN; + uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH; + for (uint32_t w=0;wcqi_table_s[w], b_bits, SRSLTE_UCI_CQI_CODED_PUCCH_B); @@ -172,7 +192,7 @@ int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, int16_t b_bits[32 } // Convert word to bits again uint8_t *ptr = cqi_data; - srslte_bit_unpack(max_w, &ptr, cqi_len); + srslte_bit_unpack(max_w, &ptr, SRSLTE_UCI_MAX_CQI_LEN_PUCCH); INFO("Decoded CQI: w=%d, corr=%d\n", max_w, max_corr); return max_corr; @@ -586,9 +606,7 @@ static uint32_t encode_ri_ack(uint8_t data[2], uint32_t data_len, srslte_uci_bit /* Decode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212 * Currently only supporting 1-bit HARQ */ -#ifndef MIMO_ENB - -static int32_t decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos) +static int32_t decode_ri_ack_1bit(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos) { uint32_t p0 = pos[0].position; uint32_t p1 = pos[1].position; @@ -598,33 +616,8 @@ static int32_t decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t * return -(q0+q1); } -int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, - float beta, uint32_t H_prime_total, - uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t acks[2], uint32_t nof_acks) -{ - int32_t rx_ack = 0; - if (beta < 0) { - fprintf(stderr, "Error beta is reserved\n"); - return -1; - } - - uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta); - - // Use the same interleaver function to get the HARQ bit position - for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]); - rx_ack += (int32_t) decode_ri_ack(q_bits, c_seq, &ack_bits[cfg->grant.Qm*i]); - } - - if (acks) { - acks[0] = rx_ack>0; - } - return (int) Qprime; -} -#else - -static void decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos, uint32_t Qm, int32_t data[3]) +static void decode_ri_ack_2bits(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos, uint32_t Qm, int32_t data[3]) { uint32_t p0 = pos[Qm * 0 + 0].position; uint32_t p1 = pos[Qm * 0 + 1].position; @@ -645,118 +638,91 @@ static void decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos data[2] -= q2 + q5; } -int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, - float beta, uint32_t H_prime_total, - uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t acks[2], uint32_t nof_acks) -{ - int32_t acks_sum[3] = {0, 0, 0}; - +/* Encode UCI ACK/RI bits as described in 5.2.2.6 of 36.212 + * Currently only supporting 1-bit RI + */ +int srslte_uci_encode_ack_ri(srslte_pusch_cfg_t *cfg, + uint8_t *data, uint32_t data_len, + uint32_t O_cqi, float beta, uint32_t H_prime_total, + srslte_uci_bit_t *bits, bool ack_ri) { if (beta < 0) { fprintf(stderr, "Error beta is reserved\n"); - return -1; + return -1; } + uint32_t Qprime = Q_prime_ri_ack(cfg, data_len, O_cqi, beta); + srslte_uci_bit_type_t q_encoded_bits[18]; - uint32_t Qprime = Q_prime_ri_ack(cfg, nof_acks, O_cqi, beta); + uint32_t nof_encoded_bits = encode_ri_ack(data, data_len, q_encoded_bits, cfg->grant.Qm); - // Use the same interleaver function to get the HARQ bit position for (uint32_t i = 0; i < Qprime; i++) { - uci_ulsch_interleave_ack_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]); - if ((i % 3 == 0) && i > 0) { - decode_ri_ack(q_bits, &c_seq[0], &ack_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, acks_sum); + if (ack_ri) { + uci_ulsch_interleave_ri_gen(i, + cfg->grant.Qm, + H_prime_total, + cfg->nbits.nof_symb, + cfg->cp, + &bits[cfg->grant.Qm * i]); + } else { + uci_ulsch_interleave_ack_gen(i, + cfg->grant.Qm, + H_prime_total, + cfg->nbits.nof_symb, + cfg->cp, + &bits[cfg->grant.Qm * i]); } + uci_ulsch_interleave_put(&q_encoded_bits[(i * cfg->grant.Qm) % nof_encoded_bits], + cfg->grant.Qm, + &bits[cfg->grant.Qm * i]); } - if (acks) { - acks[0] = (uint8_t)(acks_sum[0] > 0); - acks[1] = (uint8_t)(acks_sum[1] > 0); - // TODO: Do something with acks_sum[2] - } - return (int) Qprime; -} -#endif - -/* Encode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212 - * Currently only supporting 1-bit HARQ - */ -int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, uint8_t acks[2], uint32_t nof_acks, - uint32_t O_cqi, float beta, uint32_t H_prime_total, - srslte_uci_bit_t *ack_bits) -{ - if (beta < 0) { - fprintf(stderr, "Error beta is reserved\n"); - return -1; - } - - uint32_t Qprime = Q_prime_ri_ack(cfg, nof_acks, O_cqi, beta); - srslte_uci_bit_type_t q_encoded_bits[18]; - - uint32_t nof_encoded_bits = encode_ri_ack(acks, nof_acks, q_encoded_bits, cfg->grant.Qm); - - for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]); - uci_ulsch_interleave_put(&q_encoded_bits[(i*cfg->grant.Qm)%nof_encoded_bits], cfg->grant.Qm, &ack_bits[cfg->grant.Qm*i]); - } - return (int) Qprime; } -/* Encode UCI RI bits as described in 5.2.2.6 of 36.212 +/* Decode UCI ACK/RI bits as described in 5.2.2.6 of 36.212 * Currently only supporting 1-bit RI */ -int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, - float beta, uint32_t H_prime_total, - uint32_t O_cqi, srslte_uci_bit_t *ri_bits, uint8_t *data) +int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, + float beta, uint32_t H_prime_total, + uint32_t O_cqi, srslte_uci_bit_t *ack_ri_bits, uint8_t data[2], uint32_t nof_bits, bool is_ri) { - int32_t ri_sum[3] = {0, 0, 0}; - + int32_t sum[3] = {0, 0, 0}; + if (beta < 0) { fprintf(stderr, "Error beta is reserved\n"); - return -1; + return -1; } - uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta); + uint32_t Qprime = Q_prime_ri_ack(cfg, nof_bits, O_cqi, beta); - // Use the same interleaver function to get the HARQ bit position - for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]); - if ((i % 3 == 0) && i > 0) { - //decode_ri_ack(q_bits, &c_seq[0], &ri_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, ri_sum); - } - } + for (uint32_t i = 0; i < Qprime; i++) { + if (is_ri) { + uci_ulsch_interleave_ri_gen(i, + cfg->grant.Qm, + H_prime_total, + cfg->nbits.nof_symb, + cfg->cp, + &ack_ri_bits[cfg->grant.Qm * i]); + } else { + uci_ulsch_interleave_ack_gen(i, + cfg->grant.Qm, + H_prime_total, + cfg->nbits.nof_symb, + cfg->cp, + &ack_ri_bits[cfg->grant.Qm * i]); - if (data) { - *data = (uint8_t) ((ri_sum[0] + ri_sum[1] + ri_sum[2]) > 0); + } + if (nof_bits == 2 && (i % 3 == 0) && i > 0) { + decode_ri_ack_2bits(q_bits, &c_seq[0], &ack_ri_bits[cfg->grant.Qm * (i - 3)], cfg->grant.Qm, sum); + } else if (nof_bits == 1) { + sum[0] += (int32_t) decode_ri_ack_1bit(q_bits, c_seq, &ack_ri_bits[cfg->grant.Qm * i]); + } } - return (int) Qprime; -} - - -/* Encode UCI RI bits as described in 5.2.2.6 of 36.212 - * Currently only supporting 1-bit RI - */ -int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg, - uint8_t ri, - uint32_t O_cqi, float beta, uint32_t H_prime_total, - srslte_uci_bit_t *ri_bits) -{ - // FIXME: It supports RI of 1 bit only - uint8_t data[2] = {ri, 0}; - if (beta < 0) { - fprintf(stderr, "Error beta is reserved\n"); - return -1; + data[0] = (uint8_t) (sum[0] > 0); + if (nof_bits == 2) { + data[1] = (uint8_t) (sum[1] > 0); } - uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta); - srslte_uci_bit_type_t q_encoded_bits[18]; - uint32_t nof_encoded_bits = encode_ri_ack(data, 1, q_encoded_bits, cfg->grant.Qm); - - for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]); - uci_ulsch_interleave_put(&q_encoded_bits[(i*cfg->grant.Qm)%nof_encoded_bits], cfg->grant.Qm, &ri_bits[cfg->grant.Qm*i]); - } - return (int) Qprime; } - diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index db7118b0c..4183016e0 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -725,7 +725,8 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo /* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */ for (uint32_t nof_layers = 1; nof_layers <= SRSLTE_MAX_LAYERS; nof_layers++) { float _sinr = q->sinr[nof_layers - 1][q->pmi[nof_layers - 1]] * nof_layers * nof_layers; - if (_sinr > best_sinr + 0.1) { + /* Find best SINR, force maximum number of layers if SNR is higher than 30 dB */ + if (_sinr > best_sinr + 0.1 || _sinr > 1.0e+3) { best_sinr = _sinr; best_pmi = (uint8_t) q->pmi[nof_layers - 1]; best_ri = (uint8_t) (nof_layers - 1); diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc index 5298e6e7a..990633aa7 100644 --- a/srsenb/src/phy/phch_worker.cc +++ b/srsenb/src/phy/phch_worker.cc @@ -88,16 +88,19 @@ void phch_worker::init(phch_common* phy_, srslte::log *log_h_) pthread_mutex_init(&mutex, NULL); // Init cell here - signal_buffer_rx = (cf_t*) srslte_vec_malloc(2*SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t)); - if (!signal_buffer_rx) { - fprintf(stderr, "Error allocating memory\n"); - return; - } - bzero(&signal_buffer_tx, sizeof(cf_t *) * SRSLTE_MAX_PORTS); - signal_buffer_tx[0] = (cf_t*) srslte_vec_malloc(2*SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t)); - if (!signal_buffer_tx[0]) { - fprintf(stderr, "Error allocating memory\n"); - return; + for(int p = 0; p < SRSLTE_MAX_PORTS; p++) { + signal_buffer_rx[p] = (cf_t *) srslte_vec_malloc(2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); + if (!signal_buffer_rx[p]) { + fprintf(stderr, "Error allocating memory\n"); + return; + } + bzero(signal_buffer_rx[p], 2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); + signal_buffer_tx[p] = (cf_t *) srslte_vec_malloc(2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); + if (!signal_buffer_tx[p]) { + fprintf(stderr, "Error allocating memory\n"); + return; + } + bzero(signal_buffer_tx[p], 2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); } if (srslte_enb_dl_init(&enb_dl, signal_buffer_tx, phy->cell.nof_prb)) { fprintf(stderr, "Error initiating ENB DL\n"); @@ -107,7 +110,7 @@ void phch_worker::init(phch_common* phy_, srslte::log *log_h_) fprintf(stderr, "Error initiating ENB DL\n"); return; } - if (srslte_enb_ul_init(&enb_ul, signal_buffer_rx, phy->cell.nof_prb)) { + if (srslte_enb_ul_init(&enb_ul, signal_buffer_rx[0], phy->cell.nof_prb)) { fprintf(stderr, "Error initiating ENB UL\n"); return; } @@ -154,12 +157,12 @@ void phch_worker::stop() srslte_enb_dl_free(&enb_dl); srslte_enb_ul_free(&enb_ul); - if (signal_buffer_rx) { - free(signal_buffer_rx); - } - for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { - if (signal_buffer_tx[i]) { - free(signal_buffer_tx[i]); + for (int p = 0; p < SRSLTE_MAX_PORTS; p++) { + if (signal_buffer_rx[p]) { + free(signal_buffer_rx[p]); + } + if (signal_buffer_tx[p]) { + free(signal_buffer_tx[p]); } } pthread_mutex_unlock(&mutex); @@ -171,9 +174,9 @@ void phch_worker::reset() ue_db.clear(); } -cf_t* phch_worker::get_buffer_rx() +cf_t* phch_worker::get_buffer_rx(uint32_t antenna_idx) { - return signal_buffer_rx; + return signal_buffer_rx[antenna_idx]; } void phch_worker::set_time(uint32_t tti_, uint32_t tx_mutex_cnt_, srslte_timestamp_t tx_time_) @@ -214,12 +217,29 @@ uint32_t phch_worker::get_nof_rnti() { return ue_db.size(); } +void phch_worker::set_conf_dedicated_ack(uint16_t rnti, bool ack){ + pthread_mutex_lock(&mutex); + if (ue_db.count(rnti)) { + ue_db[rnti].dedicated_ack = ack; + } else { + Error("Setting dedicated ack: rnti=0x%x does not exist\n"); + } + pthread_mutex_unlock(&mutex); +} + void phch_worker::set_config_dedicated(uint16_t rnti, srslte_uci_cfg_t *uci_cfg, srslte_pucch_sched_t *pucch_sched, - srslte_refsignal_srs_cfg_t *srs_cfg, - uint32_t I_sr, bool pucch_cqi, uint32_t pmi_idx, bool pucch_cqi_ack) + srslte_refsignal_srs_cfg_t *srs_cfg, + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated) { + uint32_t I_sr = dedicated->sched_request_cnfg.sr_cnfg_idx; + bool pucch_cqi = dedicated->cqi_report_cnfg.report_periodic_setup_present; + uint32_t pmi_idx = dedicated->cqi_report_cnfg.report_periodic.pmi_cnfg_idx; + bool pucch_cqi_ack = dedicated->cqi_report_cnfg.report_periodic.simult_ack_nack_and_cqi; + bool pucch_ri = dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx_present; + uint32_t ri_idx = dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx; + pthread_mutex_lock(&mutex); if (ue_db.count(rnti)) { pucch_sched->N_pucch_1 = phy->pucch_cfg.n1_pucch_an; @@ -237,6 +257,16 @@ void phch_worker::set_config_dedicated(uint16_t rnti, ue_db[rnti].cqi_en = false; } + if (pucch_ri) { + ue_db[rnti].ri_idx = ri_idx; + ue_db[rnti].ri_en = true; + } else { + ue_db[rnti].ri_idx = 0; + ue_db[rnti].ri_en = false; + } + + /* Copy all dedicated RRC configuration to UE */ + memcpy(&ue_db[rnti].dedicated, dedicated, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT)); } else { Error("Setting config dedicated: rnti=0x%x does not exist\n"); } @@ -278,7 +308,7 @@ void phch_worker::work_imp() } pthread_mutex_lock(&mutex); - + mac_interface_phy::ul_sched_t *ul_grants = phy->ul_grants; mac_interface_phy::dl_sched_t *dl_grants = phy->dl_grants; mac_interface_phy *mac = phy->mac; @@ -293,7 +323,7 @@ void phch_worker::work_imp() } // Process UL signal - srslte_enb_ul_fft(&enb_ul, signal_buffer_rx); + srslte_enb_ul_fft(&enb_ul); // Decode pending UL grants for the tti they were scheduled decode_pusch(ul_grants[t_rx].sched_grants, ul_grants[t_rx].nof_grants); @@ -335,15 +365,22 @@ void phch_worker::work_imp() phy->ack_clear(TTIMOD(TTI_TX(t_tx_dl))); for (uint32_t i=0;i= SRSLTE_CRNTI_START && dl_grants[t_tx_dl].sched_grants[i].rnti <= SRSLTE_CRNTI_END) { - phy->ack_set_pending(TTIMOD(TTI_TX(t_tx_dl)), dl_grants[t_tx_dl].sched_grants[i].rnti, dl_grants[t_tx_dl].sched_grants[i].location.ncce); + uint16_t rnti = dl_grants[t_tx_dl].sched_grants[i].rnti; + if (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END) { + /* For each TB */ + for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) { + /* If TB enabled, set pending ACK */ + if (dl_grants[t_tx_dl].sched_grants[i].grant.tb_en[tb_idx]) { + phy->ack_set_pending(TTIMOD(TTI_TX(t_tx_dl)), rnti, tb_idx, dl_grants[t_tx_dl].sched_grants[i].location.ncce); + } + } } } // Generate signal and transmit srslte_enb_dl_gen_signal(&enb_dl); Debug("Sending to radio\n"); - phy->worker_end(tx_mutex_cnt, signal_buffer_tx[0], SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time); + phy->worker_end(tx_mutex_cnt, signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time); #ifdef DEBUG_WRITE_FILE fwrite(signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t), 1, f); @@ -387,24 +424,39 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) gettimeofday(&t[1], NULL); #endif + bool acks_pending[SRSLTE_MAX_TB] = {false}; + // Get pending ACKs with an associated PUSCH transmission - if (phy->ack_is_pending(t_rx, rnti)) { - uci_data.uci_ack_len = 1; + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + acks_pending[tb] = phy->ack_is_pending(t_rx, rnti, tb); + if (acks_pending[tb]) { + uci_data.uci_ack_len++; + } } + // Configure PUSCH CQI channel - srslte_cqi_value_t cqi_value; + srslte_cqi_value_t cqi_value = {0}; bool cqi_enabled = false; - if (ue_db[rnti].cqi_en && srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { +#if 0 + if (ue_db[rnti].cqi_en && ue_db[rnti].ri_en && srslte_ri_send(ue_db[rnti].pmi_idx, ue_db[rnti].ri_idx, tti_rx) ) { + uci_data.uci_ri_len = 1; /* Asumes only 1 bit for RI */ + ri_enabled = true; + } else if (ue_db[rnti].cqi_en && srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND; cqi_enabled = true; - } else if (grants[i].grant.cqi_request) { + if (ue_db[rnti].dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { + //uci_data.uci_dif_cqi_len = 3; + uci_data.uci_pmi_len = 2; + } + } else +#endif + if (grants[i].grant.cqi_request) { cqi_value.type = SRSLTE_CQI_TYPE_SUBBAND_HL; cqi_value.subband_hl.N = (phy->cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(phy->cell.nof_prb) : 0; + cqi_value.subband_hl.four_antenna_ports = (phy->cell.nof_ports == 4); + cqi_value.subband_hl.pmi_present = (ue_db[rnti].dedicated.cqi_report_cnfg.report_mode_aperiodic == LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31); cqi_enabled = true; } - if (cqi_enabled) { - uci_data.uci_cqi_len = srslte_cqi_size(&cqi_value); - } // mark this tti as having an ul grant to avoid pucch ue_db[rnti].has_grant_tti = tti_rx; @@ -412,22 +464,6 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) srslte_ra_ul_grant_t phy_grant; int res = -1; if (!srslte_ra_ul_dci_to_grant(&grants[i].grant, enb_ul.cell.nof_prb, n_rb_ho, &phy_grant)) { - - // Handle Format0 adaptive retx - // Use last TBS for this TB in case of mcs>28 - if (phy_grant.mcs.idx > 28) { - phy_grant.mcs.tbs = ue_db[rnti].last_ul_tbs[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)]; - Info("RETX: mcs=%d, old_tbs=%d pid=%d\n", phy_grant.mcs.idx, phy_grant.mcs.tbs, TTI_TX(tti_rx)%(2*HARQ_DELAY_MS)); - } - ue_db[rnti].last_ul_tbs[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)] = phy_grant.mcs.tbs; - - if (phy_grant.mcs.mod == SRSLTE_MOD_LAST) { - phy_grant.mcs.mod = ue_db[rnti].last_ul_mod[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)]; - phy_grant.Qm = srslte_mod_bits_x_symbol(phy_grant.mcs.mod); - } - ue_db[rnti].last_ul_mod[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)] = phy_grant.mcs.mod; - - if (phy_grant.mcs.mod == SRSLTE_MOD_64QAM) { phy_grant.mcs.mod = SRSLTE_MOD_16QAM; } @@ -436,6 +472,7 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) rnti, grants[i].rv_idx, grants[i].current_tx_nb, grants[i].data, + (cqi_enabled) ? &cqi_value : NULL, &uci_data, sf_rx); } else { @@ -457,11 +494,24 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) char cqi_str[64]; if (cqi_enabled) { - srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value); if (ue_db[rnti].cqi_en) { wideband_cqi_value = cqi_value.wideband.wideband_cqi; } else if (grants[i].grant.cqi_request) { wideband_cqi_value = cqi_value.subband_hl.wideband_cqi_cw0; + if (cqi_value.subband_hl.pmi_present) { + if (cqi_value.subband_hl.rank_is_not_one) { + Info("PUSCH: Aperiodic ri~1, CQI=%02d/%02d, pmi=%d for %d subbands\n", + cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.wideband_cqi_cw1, + cqi_value.subband_hl.pmi, cqi_value.subband_hl.N); + } else { + Info("PUSCH: Aperiodic ri=1, CQI=%02d, pmi=%d for %d subbands\n", + cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.pmi, cqi_value.subband_hl.N); + } + } else { + Info("PUSCH: Aperiodic ri%s, CQI=%02d for %d subbands\n", + cqi_value.subband_hl.rank_is_not_one?"~1":"=1", + cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.N); + } } snprintf(cqi_str, 64, ", cqi=%d", wideband_cqi_value); } @@ -481,14 +531,16 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) } */ log_h->info_hex(grants[i].data, phy_grant.mcs.tbs/8, - "PUSCH: rnti=0x%x, prb=(%d,%d), tbs=%d, mcs=%d, rv=%d, snr=%.1f dB, n_iter=%d, crc=%s%s%s%s\n", + "PUSCH: rnti=0x%x, prb=(%d,%d), tbs=%d, mcs=%d, rv=%d, snr=%.1f dB, n_iter=%d, crc=%s%s%s%s%s\n", rnti, phy_grant.n_prb[0], phy_grant.n_prb[0]+phy_grant.L_prb, phy_grant.mcs.tbs/8, phy_grant.mcs.idx, grants[i].grant.rv_idx, snr_db, srslte_pusch_last_noi(&enb_ul.pusch), crc_res?"OK":"KO", - uci_data.uci_ack_len>0?(uci_data.uci_ack?", ack=1":", ack=0"):"", + (uci_data.uci_ack_len)?(uci_data.uci_ack?"1":"0"):"", + (uci_data.uci_ack_len > 1)?(uci_data.uci_ack_2?"1":"0"):"", uci_data.uci_cqi_len>0?cqi_str:"", + uci_data.uci_ri_len>0?(uci_data.uci_ri?", ri=0":", ri=1"):"", timestr); // Notify MAC of RL status @@ -503,17 +555,28 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) // Notify MAC new received data and HARQ Indication value phy->mac->crc_info(tti_rx, rnti, phy_grant.mcs.tbs/8, crc_res); - if (uci_data.uci_ack_len) { - phy->mac->ack_info(tti_rx, rnti, uci_data.uci_ack && (crc_res || snr_db > PUSCH_RL_SNR_DB_TH)); + uint32_t ack_idx = 0; + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + if (acks_pending[tb]) { + bool ack = ((ack_idx++ == 0) ? uci_data.uci_ack : uci_data.uci_ack_2); + bool valid = (crc_res || snr_db > PUSCH_RL_SNR_DB_TH); + phy->mac->ack_info(tti_rx, rnti, tb, ack && valid); + } } - // Notify MAC of UL SNR and DL CQI + // Notify MAC of UL SNR, DL CQI and DL RI if (snr_db >= PUSCH_RL_SNR_DB_TH) { phy->mac->snr_info(tti_rx, rnti, snr_db); } if (uci_data.uci_cqi_len>0 && crc_res) { phy->mac->cqi_info(tti_rx, rnti, wideband_cqi_value); } + if (uci_data.uci_ri_len > 0 && crc_res) { + phy->mac->ri_info(tti_rx, rnti, uci_data.uci_ri); + } + if (cqi_value.subband_hl.pmi_present && crc_res) { + phy->mac->pmi_info(tti_rx, rnti, cqi_value.subband_hl.pmi); + } // Save metrics stats ue_db[rnti].metrics_ul(phy_grant.mcs.idx, 0, snr_db, srslte_pusch_last_noi(&enb_ul.pusch)); @@ -532,7 +595,8 @@ int phch_worker::decode_pucch() if (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END && ue_db[rnti].has_grant_tti != (int) tti_rx) { // Check if user needs to receive PUCCH - bool needs_pucch = false, needs_ack=false, needs_sr=false, needs_cqi=false; + bool needs_pucch = false, needs_ack[SRSLTE_MAX_TB] = {false}, needs_sr = false, needs_cqi = false, + needs_ri = false; uint32_t last_n_pdcch = 0; bzero(&uci_data, sizeof(srslte_uci_data_t)); @@ -544,18 +608,32 @@ int phch_worker::decode_pucch() } } - if (phy->ack_is_pending(t_rx, rnti, &last_n_pdcch)) { - needs_pucch = true; - needs_ack = true; - uci_data.uci_ack_len = 1; + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + needs_ack[tb] = phy->ack_is_pending(t_rx, rnti, tb, &last_n_pdcch); + if (needs_ack[tb]) { + needs_pucch = true; + uci_data.uci_ack_len++; + } } srslte_cqi_value_t cqi_value; - if (ue_db[rnti].cqi_en && (ue_db[rnti].pucch_cqi_ack || !needs_ack)) { - if (srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated = &ue_db[rnti].dedicated; + LIBLTE_RRC_TRANSMISSION_MODE_ENUM tx_mode = dedicated->antenna_info_explicit_value.tx_mode; + + if (ue_db[rnti].cqi_en && (ue_db[rnti].pucch_cqi_ack || !needs_ack[0] || !needs_ack[1])) { + if (ue_db[rnti].ri_en && srslte_ri_send(ue_db[rnti].pmi_idx, ue_db[rnti].ri_idx, tti_rx)) { + needs_pucch = true; + needs_ri = true; + uci_data.uci_ri_len = 1; + uci_data.ri_periodic_report = true; + } else if (srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { needs_pucch = true; needs_cqi = true; cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND; uci_data.uci_cqi_len = srslte_cqi_size(&cqi_value); + if (tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { + //uci_data.uci_dif_cqi_len = 3; + uci_data.uci_pmi_len = 2; + } } } @@ -564,26 +642,48 @@ int phch_worker::decode_pucch() fprintf(stderr, "Error getting PUCCH\n"); return SRSLTE_ERROR; } - if (uci_data.uci_ack_len > 0) { - phy->mac->ack_info(tti_rx, rnti, uci_data.uci_ack && (srslte_pucch_get_last_corr(&enb_ul.pucch) >= PUCCH_RL_CORR_TH)); + /* If only one ACK is required, it can be for TB0 or TB1 */ + uint32_t ack_idx = 0; + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + if (needs_ack[tb]) { + bool ack = ((ack_idx++ == 0) ? uci_data.uci_ack : uci_data.uci_ack_2); + bool valid = srslte_pucch_get_last_corr(&enb_ul.pucch) >= PUCCH_RL_CORR_TH; + phy->mac->ack_info(tti_rx, rnti, tb, ack && valid); + } } if (uci_data.scheduling_request) { phy->mac->sr_detected(tti_rx, rnti); } + + char cqi_ri_str[64]; + if (srslte_pucch_get_last_corr(&enb_ul.pucch) > PUCCH_RL_CORR_TH) { + if (uci_data.uci_ri_len && needs_ri) { + phy->mac->ri_info(tti_rx, rnti, uci_data.uci_ri); + sprintf(cqi_ri_str, ", ri=%d", uci_data.uci_ri); + } else if (uci_data.uci_cqi_len && needs_cqi) { + srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value); + phy->mac->cqi_info(tti_rx, rnti, cqi_value.wideband.wideband_cqi); + sprintf(cqi_ri_str, ", cqi=%d", cqi_value.wideband.wideband_cqi); + + if (uci_data.uci_pmi_len) { + uint32_t packed_pmi = uci_data.uci_pmi[0]; + if (uci_data.uci_pmi_len > 1) { + packed_pmi = (packed_pmi << 1) + uci_data.uci_pmi[1]; + } + phy->mac->pmi_info(tti_rx, rnti, packed_pmi); + sprintf(cqi_ri_str, "%s, pmi=%c", cqi_ri_str, packed_pmi + 0x30); + } - char cqi_str[64]; - if (uci_data.uci_cqi_len) { - srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value); - phy->mac->cqi_info(tti_rx, rnti, cqi_value.wideband.wideband_cqi); - sprintf(cqi_str, ", cqi=%d", cqi_value.wideband.wideband_cqi); + } } - log_h->info("PUCCH: rnti=0x%x, corr=%.2f, n_pucch=%d, n_prb=%d%s%s%s\n", + log_h->info("PUCCH: rnti=0x%x, corr=%.2f, n_pucch=%d, n_prb=%d%s%s%s%s\n", rnti, srslte_pucch_get_last_corr(&enb_ul.pucch), enb_ul.pucch.last_n_pucch, enb_ul.pucch.last_n_prb, - needs_ack?(uci_data.uci_ack?", ack=1":", ack=0"):"", + (uci_data.uci_ack_len)?(uci_data.uci_ack?", ack=1":", ack=0"):"", + (uci_data.uci_ack_len > 1)?(uci_data.uci_ack_2?"1":"0"):"", needs_sr?(uci_data.scheduling_request?", sr=yes":", sr=no"):"", - needs_cqi?cqi_str:""); + (needs_cqi || needs_ri)?cqi_ri_str:""); // Notify MAC of RL status @@ -642,25 +742,16 @@ int phch_worker::encode_pdcch_ul(srslte_enb_ul_pusch_t *grants, uint32_t nof_gra int phch_worker::encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants) { for (uint32_t i=0;irnti; if (rnti) { - srslte_dci_format_t format = SRSLTE_DCI_FORMAT1; - switch(grants[i].grant.alloc_type) { - case SRSLTE_RA_ALLOC_TYPE0: - case SRSLTE_RA_ALLOC_TYPE1: - format = SRSLTE_DCI_FORMAT1; - break; - case SRSLTE_RA_ALLOC_TYPE2: - format = SRSLTE_DCI_FORMAT1A; - break; - } - if (srslte_enb_dl_put_pdcch_dl(&enb_dl, &grants[i].grant, format, grants[i].location, rnti, sf_tx)) { + if (srslte_enb_dl_put_pdcch_dl(&enb_dl, &grants[i].grant, grant->dci_format, grants[i].location, rnti, sf_tx)) { fprintf(stderr, "Error putting PDCCH %d\n",i); return SRSLTE_ERROR; } if (LOG_THIS(rnti)) { - Info("PDCCH: DL DCI %s rnti=0x%x, cce_index=%d, L=%d, tti_tx_dl=%d\n", srslte_dci_format_string(format), + Info("PDCCH: DL DCI %s rnti=0x%x, cce_index=%d, L=%d, tti_tx_dl=%d\n", srslte_dci_format_string(grant->dci_format), rnti, grants[i].location.ncce, (1<info_hex(ptr, len, - "PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tbs=%d, mcs=%d, rv=%d, tti_tx_dl=%d\n", - rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process, - phy_grant.mcs[0].tbs/8, phy_grant.mcs[0].idx, grants[i].grant.rv_idx, tti_tx_dl); + "PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tti_tx_dl=%d, tx_scheme=%s%s%s%s\n", + rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process, tti_tx_dl, + srslte_mimotype2str(mimo_type), pinfo_str, tbstr[0], tbstr[1]); } - srslte_softbuffer_tx_t *sb[SRSLTE_MAX_CODEWORDS] = {grants[i].softbuffer, NULL}; - uint8_t *d[SRSLTE_MAX_CODEWORDS] = {grants[i].data, NULL}; - int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, 0}; + int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, grants[i].grant.rv_idx_1}; - - if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, sb, rnti, rv, sf_tx, d, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0)) - { - fprintf(stderr, "Error putting PDSCH %d\n",i); - return SRSLTE_ERROR; + if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, grants[i].softbuffers, rnti, rv, sf_tx, grants[i].data, mimo_type)) { + fprintf(stderr, "Error putting PDSCH %d\n", i); + return SRSLTE_ERROR; } - // Save metrics stats + // Save metrics stats ue_db[rnti].metrics_dl(phy_grant.mcs[0].idx); } } - return SRSLTE_SUCCESS; + return SRSLTE_SUCCESS; } diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index e176e8ac5..29cbdef8e 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -1142,7 +1142,11 @@ void rrc::ue::send_connection_setup(bool is_setup) phy_cfg->cqi_report_cnfg_present = true; if(parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_APERIODIC) { phy_cfg->cqi_report_cnfg.report_mode_aperiodic_present = true; - phy_cfg->cqi_report_cnfg.report_mode_aperiodic = LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30; + if (phy_cfg->antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { + phy_cfg->cqi_report_cnfg.report_mode_aperiodic = LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31; + } else { + phy_cfg->cqi_report_cnfg.report_mode_aperiodic = LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30; + } } else { phy_cfg->cqi_report_cnfg.report_periodic_present = true; phy_cfg->cqi_report_cnfg.report_periodic_setup_present = true; diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 0068724b4..2beff5900 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -859,7 +859,9 @@ void phch_worker::set_uci_periodic_cqi() if (period_cqi.configured && rnti_is_set) { if (period_cqi.ri_idx_present && srslte_ri_send(period_cqi.pmi_idx, period_cqi.ri_idx, TTI_TX(tti))) { + /* Compute RI, PMI and SINR */ compute_ri(); + uci_data.ri_periodic_report = true; Info("PUCCH: Periodic RI=%d\n", uci_data.uci_ri); } else if (srslte_cqi_send(period_cqi.pmi_idx, TTI_TX(tti))) { @@ -902,6 +904,9 @@ void phch_worker::set_uci_periodic_cqi() void phch_worker::set_uci_aperiodic_cqi() { if (phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic_present) { + /* Compute RI, PMI and SINR */ + compute_ri(); + switch(phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic) { case LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30: /* only Higher Layer-configured subband feedback support right now, according to TS36.213 section 7.2.1 @@ -939,9 +944,6 @@ void phch_worker::set_uci_aperiodic_cqi() other transmission modes they are reported conditioned on rank 1. */ if (rnti_is_set) { - /* Compute RI, PMI and SINR */ - compute_ri(); - /* Select RI, PMI and SINR */ uint32_t ri = ue_dl.ri; // Select RI (0: 1 layer, 1: 2 layer, otherwise: not implemented) uint32_t pmi = ue_dl.pmi[ri]; // Select PMI @@ -972,9 +974,9 @@ void phch_worker::set_uci_aperiodic_cqi() cqi_report.subband_hl.wideband_cqi_cw0, cqi_report.subband_hl.wideband_cqi_cw1, sinr_db, sinr_db, pmi, cqi_report.subband_hl.N); } else { - Info("PUSCH: Aperiodic ri=1, CQI=%d/%d, SINR=%2.1f dB, for %d subbands\n", - cqi_report.wideband.wideband_cqi, - phy->avg_snr_db, cqi_report.subband_hl.N); + Info("PUSCH: Aperiodic ri=1, CQI=%02d, SINR=%2.1f, pmi=%d for %d subbands\n", + cqi_report.subband_hl.wideband_cqi_cw0, + sinr_db, pmi, cqi_report.subband_hl.N); } uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); } From eefbdbc9132a4d8f5d0e6aece6062dcc58c2bf7e Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Mon, 4 Dec 2017 12:07:49 -0600 Subject: [PATCH 30/42] Revert "Added Aperiodic mode 3-1 in enb and some more optimizations" This reverts commit 8ab196901f83caef3759e89b98b1b3b10d26cd1b. --- lib/include/srslte/phy/enb/enb_ul.h | 1 - lib/include/srslte/phy/phch/pusch.h | 1 - lib/include/srslte/phy/phch/uci.h | 36 +-- lib/src/phy/enb/enb_ul.c | 45 +--- lib/src/phy/phch/cqi.c | 37 +-- lib/src/phy/phch/pusch.c | 35 +-- lib/src/phy/phch/sch.c | 19 +- lib/src/phy/phch/test/pusch_test.c | 2 +- lib/src/phy/phch/uci.c | 230 ++++++++++-------- lib/src/phy/ue/ue_dl.c | 3 +- srsenb/src/phy/phch_worker.cc | 362 +++++++++------------------- srsenb/src/upper/rrc.cc | 6 +- srsue/src/phy/phch_worker.cc | 14 +- 13 files changed, 300 insertions(+), 491 deletions(-) diff --git a/lib/include/srslte/phy/enb/enb_ul.h b/lib/include/srslte/phy/enb/enb_ul.h index 1b865b7f7..0957ccbc0 100644 --- a/lib/include/srslte/phy/enb/enb_ul.h +++ b/lib/include/srslte/phy/enb/enb_ul.h @@ -141,7 +141,6 @@ SRSLTE_API int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, uint32_t rv_idx, uint32_t current_tx_nb, uint8_t *data, - srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data, uint32_t tti); diff --git a/lib/include/srslte/phy/phch/pusch.h b/lib/include/srslte/phy/phch/pusch.h index 01db068a5..2328c8ff3 100644 --- a/lib/include/srslte/phy/phch/pusch.h +++ b/lib/include/srslte/phy/phch/pusch.h @@ -142,7 +142,6 @@ SRSLTE_API int srslte_pusch_decode(srslte_pusch_t *q, float noise_estimate, uint16_t rnti, uint8_t *data, - srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data); SRSLTE_API float srslte_pusch_average_noi(srslte_pusch_t *q); diff --git a/lib/include/srslte/phy/phch/uci.h b/lib/include/srslte/phy/phch/uci.h index 8e72b5793..91592501f 100644 --- a/lib/include/srslte/phy/phch/uci.h +++ b/lib/include/srslte/phy/phch/uci.h @@ -131,25 +131,31 @@ SRSLTE_API int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, uint32_t H_prime_total, srslte_uci_bit_t *ri_bits); -SRSLTE_API int srslte_uci_encode_ack_ri(srslte_pusch_cfg_t *cfg, - uint8_t *data, - uint32_t data_len, +SRSLTE_API int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, + int16_t *q_bits, + uint8_t *c_seq, + float beta, + uint32_t H_prime_total, + uint32_t O_cqi, + srslte_uci_bit_t *ack_bits, + uint8_t acks[2], + uint32_t nof_acks); + +SRSLTE_API int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg, + uint8_t data, uint32_t O_cqi, float beta, uint32_t H_prime_total, + srslte_uci_bit_t *ri_bits); + +SRSLTE_API int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, + int16_t *q_bits, + uint8_t *c_seq, + float beta, + uint32_t H_prime_total, + uint32_t O_cqi, srslte_uci_bit_t *ri_bits, - bool is_ri); - -SRSLTE_API int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t *cfg, - int16_t *q_bits, - uint8_t *c_seq, - float beta, - uint32_t H_prime_total, - uint32_t O_cqi, - srslte_uci_bit_t *ack_ri_bits, - uint8_t data[2], - uint32_t nof_bits, - bool is_ri); + uint8_t *data); #endif diff --git a/lib/src/phy/enb/enb_ul.c b/lib/src/phy/enb/enb_ul.c index 8ea5dd3e4..f94eb0277 100644 --- a/lib/src/phy/enb/enb_ul.c +++ b/lib/src/phy/enb/enb_ul.c @@ -253,22 +253,18 @@ int srslte_enb_ul_cfg_ue(srslte_enb_ul_t *q, uint16_t rnti, } } -void srslte_enb_ul_fft(srslte_enb_ul_t *q) +void srslte_enb_ul_fft(srslte_enb_ul_t *q, cf_t *signal_buffer) { srslte_ofdm_rx_sf(&q->fft); } int get_pucch(srslte_enb_ul_t *q, uint16_t rnti, uint32_t pdcch_n_cce, uint32_t sf_rx, - srslte_uci_data_t *uci_data, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], uint32_t nof_bits) + srslte_uci_data_t *uci_data, uint8_t bits[SRSLTE_PUCCH_MAX_BITS]) { float noise_power = srslte_chest_ul_get_noise_estimate(&q->chest); srslte_pucch_format_t format = srslte_pucch_get_format(uci_data, q->cell.cp); - if (format == SRSLTE_PUCCH_FORMAT_ERROR) { - fprintf(stderr,"Error getting format\n"); - return SRSLTE_ERROR; - } uint32_t n_pucch = srslte_pucch_get_npucch(pdcch_n_cce, format, uci_data->scheduling_request, &q->users[rnti]->pucch_sched); @@ -277,7 +273,7 @@ int get_pucch(srslte_enb_ul_t *q, uint16_t rnti, return SRSLTE_ERROR; } - int ret_val = srslte_pucch_decode(&q->pucch, format, n_pucch, sf_rx, rnti, q->sf_symbols, q->ce, noise_power, bits, nof_bits); + int ret_val = srslte_pucch_decode(&q->pucch, format, n_pucch, sf_rx, rnti, q->sf_symbols, q->ce, noise_power, bits); if (ret_val < 0) { fprintf(stderr,"Error decoding PUCCH\n"); return SRSLTE_ERROR; @@ -290,18 +286,16 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti, srslte_uci_data_t *uci_data) { uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS]; - + if (q->users[rnti]) { - uint32_t nof_uci_bits = uci_data->ri_periodic_report ? uci_data->uci_ri_len : (uci_data->uci_cqi_len + - uci_data->uci_dif_cqi_len + - uci_data->uci_pmi_len); - int ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits, nof_uci_bits); + + int ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits); // If we are looking for SR and ACK at the same time and ret=0, means there is no SR. // try again to decode ACK only if (uci_data->scheduling_request && uci_data->uci_ack_len && ret_val != 1) { uci_data->scheduling_request = false; - ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits, nof_uci_bits); + ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits); } // update schedulign request @@ -311,32 +305,12 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti, // Save ACK bits if (uci_data->uci_ack_len > 0) { - uci_data->uci_ack = pucch_bits[0]; - } - - if (uci_data->uci_ack_len > 1) { - uci_data->uci_ack_2 = pucch_bits[1]; + uci_data->uci_ack = pucch_bits[0]; } // PUCCH2 CQI bits are decoded inside srslte_pucch_decode() if (uci_data->uci_cqi_len) { memcpy(uci_data->uci_cqi, pucch_bits, uci_data->uci_cqi_len*sizeof(uint8_t)); - } - - if (uci_data->uci_dif_cqi_len) { - memcpy(uci_data->uci_dif_cqi, pucch_bits + uci_data->uci_cqi_len, uci_data->uci_dif_cqi_len*sizeof(uint8_t)); - } - - if (uci_data->uci_pmi_len) { - memcpy(uci_data->uci_pmi, pucch_bits + uci_data->uci_cqi_len + uci_data->uci_dif_cqi_len, - uci_data->uci_pmi_len*sizeof(uint8_t)); - } - - if (uci_data->uci_ri_len) { - uci_data->uci_ri = pucch_bits[0]; /* Assume only one bit of RI */ - } - - if (uci_data->uci_cqi_len || uci_data->uci_ri_len) { if (uci_data->uci_ack_len >= 1) { uci_data->uci_ack = pucch_bits[20]; } @@ -354,7 +328,7 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti, int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srslte_softbuffer_rx_t *softbuffer, uint16_t rnti, uint32_t rv_idx, uint32_t current_tx_nb, - uint8_t *data, srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data, uint32_t tti) + uint8_t *data, srslte_uci_data_t *uci_data, uint32_t tti) { if (q->users[rnti]) { if (srslte_pusch_cfg(&q->pusch, @@ -390,7 +364,6 @@ int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srs softbuffer, q->sf_symbols, q->ce, noise_power, rnti, data, - cqi_value, uci_data); } diff --git a/lib/src/phy/phch/cqi.c b/lib/src/phy/phch/cqi.c index 8589ee51a..2c0940af5 100644 --- a/lib/src/phy/phch/cqi.c +++ b/lib/src/phy/phch/cqi.c @@ -199,44 +199,17 @@ int srslte_cqi_value_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_value_ } int srslte_cqi_size(srslte_cqi_value_t *value) { - int size = 0; - switch(value->type) { case SRSLTE_CQI_TYPE_WIDEBAND: - size = 4; - break; + return 4; case SRSLTE_CQI_TYPE_SUBBAND: - size = 4 + (value->subband.subband_label_2_bits) ? 2 : 1; - break; + return 4+(value->subband.subband_label_2_bits)?2:1; case SRSLTE_CQI_TYPE_SUBBAND_UE: - size = 4 + 2 + value->subband_ue.L; - break; + return 4+2+value->subband_ue.L; case SRSLTE_CQI_TYPE_SUBBAND_HL: - /* First codeword */ - size += 4 + 2 * value->subband_hl.N; - - /* Add Second codeword if required */ - if (value->subband_hl.rank_is_not_one && value->subband_hl.pmi_present) { - size += 4 + 2 * value->subband_hl.N; - } - - /* Add PMI if required*/ - if (value->subband_hl.pmi_present) { - if (value->subband_hl.four_antenna_ports) { - size += 4; - } else { - if (value->subband_hl.rank_is_not_one) { - size += 1; - } else { - size += 2; - } - } - } - break; - default: - size = SRSLTE_ERROR; + return 4+2*value->subband_hl.N; } - return size; + return -1; } static bool srslte_cqi_get_N(uint32_t I_cqi_pmi, uint32_t *N_p, uint32_t *N_offset) { diff --git a/lib/src/phy/phch/pusch.c b/lib/src/phy/phch/pusch.c index 7876a4f86..a8c6064fc 100644 --- a/lib/src/phy/phch/pusch.c +++ b/lib/src/phy/phch/pusch.c @@ -566,9 +566,9 @@ int srslte_pusch_decode(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, cf_t *sf_symbols, cf_t *ce, float noise_estimate, uint16_t rnti, - uint8_t *data, srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data) + uint8_t *data, srslte_uci_data_t *uci_data) { - int ret = SRSLTE_ERROR_INVALID_INPUTS; + uint32_t n; if (q != NULL && @@ -607,42 +607,19 @@ int srslte_pusch_decode(srslte_pusch_t *q, // Generate scrambling sequence if not pre-generated srslte_sequence_t *seq = get_user_sequence(q, rnti, cfg->sf_idx, cfg->nbits.nof_bits); - // Set CQI len assuming RI = 1 (3GPP 36.212 Clause 5.2.4.1. Uplink control information on PUSCH without UL-SCH data) - if (cqi_value) { - if (cqi_value->type == SRSLTE_CQI_TYPE_SUBBAND_HL) { - cqi_value->subband_hl.rank_is_not_one = false; - } - uci_data->uci_cqi_len = (uint32_t) srslte_cqi_size(cqi_value); - uci_data->uci_ri_len = (q->cell.nof_ports == 4) ? 2 : 1; - } - // Decode RI/HARQ bits before descrambling if (srslte_ulsch_uci_decode_ri_ack(&q->ul_sch, cfg, softbuffer, q->q, seq->c, uci_data)) { fprintf(stderr, "Error decoding RI/HARQ bits\n"); return SRSLTE_ERROR; } - - // Set CQI len with corresponding RI - if (cqi_value) { - if (cqi_value->type == SRSLTE_CQI_TYPE_SUBBAND_HL) { - cqi_value->subband_hl.rank_is_not_one = (uci_data->uci_ri != 0); - } - uci_data->uci_cqi_len = (uint32_t) srslte_cqi_size(cqi_value); - } // Descrambling srslte_scrambling_s_offset(seq, q->q, 0, cfg->nbits.nof_bits); - - // Decode - ret = srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data); - - // Unpack CQI value if available - if (cqi_value) { - srslte_cqi_value_unpack(uci_data->uci_cqi, cqi_value); - } + + return srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data); + } else { + return SRSLTE_ERROR_INVALID_INPUTS; } - - return ret; } uint32_t srslte_pusch_last_noi(srslte_pusch_t *q) { diff --git a/lib/src/phy/phch/sch.c b/lib/src/phy/phch/sch.c index 1e972594d..930364725 100644 --- a/lib/src/phy/phch/sch.c +++ b/lib/src/phy/phch/sch.c @@ -658,7 +658,7 @@ int srslte_ulsch_uci_decode_ri_ack(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srs if (cfg->cb_segm.tbs == 0) { beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; } - ret = srslte_uci_decode_ack_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, acks, uci_data->uci_ack_len, false); + ret = srslte_uci_decode_ack(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, acks, uci_data->uci_ack_len); if (ret < 0) { return ret; } @@ -678,7 +678,7 @@ int srslte_ulsch_uci_decode_ri_ack(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srs if (cfg->cb_segm.tbs == 0) { beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; } - ret = srslte_uci_decode_ack_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, &uci_data->uci_ri, uci_data->uci_ri_len, true); + ret = srslte_uci_decode_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, &uci_data->uci_ri); if (ret < 0) { return ret; } @@ -756,18 +756,13 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q, uint32_t nb_q = cfg->nbits.nof_bits; uint32_t Qm = cfg->grant.Qm; - // Encode RI if CQI enabled - if (uci_data.uci_ri_len > 0 || uci_data.uci_cqi_len > 0) { - /* If no RI is reported set it to zero as specified in 3GPP 36.213 clause 7.2.1 */ - if (uci_data.uci_ri_len == 0) { - uci_data.uci_ri = 0; - } + // Encode RI + if (uci_data.uci_ri_len > 0) { float beta = beta_ri_offset[cfg->uci_cfg.I_offset_ri]; if (cfg->cb_segm.tbs == 0) { beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; } - uint8_t ri[2] = {uci_data.uci_ri, 0}; - ret = srslte_uci_encode_ack_ri(cfg, ri, uci_data.uci_ri_len, uci_data.uci_cqi_len, beta, nb_q/Qm, q->ack_ri_bits, true); + ret = srslte_uci_encode_ri(cfg, uci_data.uci_ri, uci_data.uci_cqi_len, beta, nb_q/Qm, q->ack_ri_bits); if (ret < 0) { return ret; } @@ -814,8 +809,8 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q, if (cfg->cb_segm.tbs == 0) { beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; } - ret = srslte_uci_encode_ack_ri(cfg, acks, uci_data.uci_ack_len, uci_data.uci_cqi_len, - beta, nb_q / Qm, &q->ack_ri_bits[Q_prime_ri * Qm], false); + ret = srslte_uci_encode_ack(cfg, acks, uci_data.uci_ack_len, uci_data.uci_cqi_len, + beta, nb_q / Qm, &q->ack_ri_bits[Q_prime_ri * Qm]); if (ret < 0) { return ret; } diff --git a/lib/src/phy/phch/test/pusch_test.c b/lib/src/phy/phch/test/pusch_test.c index 651803617..cf0be75c3 100644 --- a/lib/src/phy/phch/test/pusch_test.c +++ b/lib/src/phy/phch/test/pusch_test.c @@ -252,7 +252,7 @@ int main(int argc, char **argv) { } gettimeofday(&t[1], NULL); - int r = srslte_pusch_decode(&pusch_rx, &cfg, &softbuffer_rx, sf_symbols, ce, 0, rnti, data, NULL, &uci_data_rx); + int r = srslte_pusch_decode(&pusch_rx, &cfg, &softbuffer_rx, sf_symbols, ce, 0, rnti, data, &uci_data_rx); gettimeofday(&t[2], NULL); get_time_interval(t); if (r) { diff --git a/lib/src/phy/phch/uci.c b/lib/src/phy/phch/uci.c index 8a1a36544..cb09ca08b 100644 --- a/lib/src/phy/phch/uci.c +++ b/lib/src/phy/phch/uci.c @@ -103,29 +103,26 @@ static uint8_t M_basis_seq_pucch[20][13]={ {1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1}, {1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0}, - }; + }; void srslte_uci_cqi_pucch_init(srslte_uci_cqi_pucch_t *q) { - uint8_t word[16]; - - uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH; - q->cqi_table = srslte_vec_malloc(nwords * sizeof(int8_t *)); - q->cqi_table_s = srslte_vec_malloc(nwords * sizeof(int16_t *)); - - for (uint32_t w = 0; w < nwords; w++) { - q->cqi_table[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B * sizeof(int8_t)); - q->cqi_table_s[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B * sizeof(int16_t)); + uint8_t word[16]; + + uint32_t nwords = 16; + for (uint32_t w=0;wcqi_table[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B*sizeof(int8_t)); + q->cqi_table_s[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B*sizeof(int16_t)); uint8_t *ptr = word; - srslte_bit_unpack(w, &ptr, SRSLTE_UCI_MAX_CQI_LEN_PUCCH); - srslte_uci_encode_cqi_pucch(word, SRSLTE_UCI_MAX_CQI_LEN_PUCCH, q->cqi_table[w]); - for (int j = 0; j < SRSLTE_UCI_CQI_CODED_PUCCH_B; j++) { - q->cqi_table_s[w][j] = (int16_t)(2 * q->cqi_table[w][j] - 1); + srslte_bit_unpack(w, &ptr, 4); + srslte_uci_encode_cqi_pucch(word, 4, q->cqi_table[w]); + for (int j=0;jcqi_table_s[w][j] = 2*q->cqi_table[w][j]-1; } } } void srslte_uci_cqi_pucch_free(srslte_uci_cqi_pucch_t *q) { - uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH; + uint32_t nwords = 16; for (uint32_t w=0;wcqi_table[w]) { free(q->cqi_table[w]); @@ -134,8 +131,6 @@ void srslte_uci_cqi_pucch_free(srslte_uci_cqi_pucch_t *q) { free(q->cqi_table_s[w]); } } - free(q->cqi_table); - free(q->cqi_table_s); } /* Encode UCI CQI/PMI as described in 5.2.3.3 of 36.212 @@ -156,32 +151,17 @@ int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_b } } -int srslte_uci_encode_cqi_pucch_from_table(srslte_uci_cqi_pucch_t *q, uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]) -{ - if (cqi_len <= SRSLTE_UCI_MAX_CQI_LEN_PUCCH) { - bzero(&cqi_data[cqi_len], SRSLTE_UCI_MAX_CQI_LEN_PUCCH - cqi_len); - uint8_t *ptr = cqi_data; - uint32_t packed = srslte_bit_pack(&ptr, SRSLTE_UCI_MAX_CQI_LEN_PUCCH); - memcpy(b_bits, q->cqi_table[packed], SRSLTE_UCI_CQI_CODED_PUCCH_B); - - return SRSLTE_SUCCESS; - } else { - return SRSLTE_ERROR_INVALID_INPUTS; - } -} - /* Decode UCI CQI/PMI over PUCCH */ int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, int16_t b_bits[32], uint8_t *cqi_data, uint32_t cqi_len) { - if (cqi_len < SRSLTE_UCI_MAX_CQI_LEN_PUCCH && + if (cqi_len == 4 && b_bits != NULL && cqi_data != NULL) { uint32_t max_w = 0; - int32_t max_corr = INT32_MIN; - uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH; - for (uint32_t w=0;wcqi_table_s[w], b_bits, SRSLTE_UCI_CQI_CODED_PUCCH_B); @@ -192,7 +172,7 @@ int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, int16_t b_bits[32 } // Convert word to bits again uint8_t *ptr = cqi_data; - srslte_bit_unpack(max_w, &ptr, SRSLTE_UCI_MAX_CQI_LEN_PUCCH); + srslte_bit_unpack(max_w, &ptr, cqi_len); INFO("Decoded CQI: w=%d, corr=%d\n", max_w, max_corr); return max_corr; @@ -606,7 +586,9 @@ static uint32_t encode_ri_ack(uint8_t data[2], uint32_t data_len, srslte_uci_bit /* Decode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212 * Currently only supporting 1-bit HARQ */ -static int32_t decode_ri_ack_1bit(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos) +#ifndef MIMO_ENB + +static int32_t decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos) { uint32_t p0 = pos[0].position; uint32_t p1 = pos[1].position; @@ -616,8 +598,33 @@ static int32_t decode_ri_ack_1bit(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bi return -(q0+q1); } +int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, + float beta, uint32_t H_prime_total, + uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t acks[2], uint32_t nof_acks) +{ + int32_t rx_ack = 0; -static void decode_ri_ack_2bits(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos, uint32_t Qm, int32_t data[3]) + if (beta < 0) { + fprintf(stderr, "Error beta is reserved\n"); + return -1; + } + + uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta); + + // Use the same interleaver function to get the HARQ bit position + for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]); + rx_ack += (int32_t) decode_ri_ack(q_bits, c_seq, &ack_bits[cfg->grant.Qm*i]); + } + + if (acks) { + acks[0] = rx_ack>0; + } + return (int) Qprime; +} +#else + +static void decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos, uint32_t Qm, int32_t data[3]) { uint32_t p0 = pos[Qm * 0 + 0].position; uint32_t p1 = pos[Qm * 0 + 1].position; @@ -638,91 +645,118 @@ static void decode_ri_ack_2bits(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_ data[2] -= q2 + q5; } -/* Encode UCI ACK/RI bits as described in 5.2.2.6 of 36.212 - * Currently only supporting 1-bit RI - */ -int srslte_uci_encode_ack_ri(srslte_pusch_cfg_t *cfg, - uint8_t *data, uint32_t data_len, - uint32_t O_cqi, float beta, uint32_t H_prime_total, - srslte_uci_bit_t *bits, bool ack_ri) { +int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, + float beta, uint32_t H_prime_total, + uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t acks[2], uint32_t nof_acks) +{ + int32_t acks_sum[3] = {0, 0, 0}; + if (beta < 0) { fprintf(stderr, "Error beta is reserved\n"); - return -1; + return -1; } - uint32_t Qprime = Q_prime_ri_ack(cfg, data_len, O_cqi, beta); - srslte_uci_bit_type_t q_encoded_bits[18]; - uint32_t nof_encoded_bits = encode_ri_ack(data, data_len, q_encoded_bits, cfg->grant.Qm); + uint32_t Qprime = Q_prime_ri_ack(cfg, nof_acks, O_cqi, beta); + // Use the same interleaver function to get the HARQ bit position for (uint32_t i = 0; i < Qprime; i++) { - if (ack_ri) { - uci_ulsch_interleave_ri_gen(i, - cfg->grant.Qm, - H_prime_total, - cfg->nbits.nof_symb, - cfg->cp, - &bits[cfg->grant.Qm * i]); - } else { - uci_ulsch_interleave_ack_gen(i, - cfg->grant.Qm, - H_prime_total, - cfg->nbits.nof_symb, - cfg->cp, - &bits[cfg->grant.Qm * i]); + uci_ulsch_interleave_ack_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]); + if ((i % 3 == 0) && i > 0) { + decode_ri_ack(q_bits, &c_seq[0], &ack_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, acks_sum); } - uci_ulsch_interleave_put(&q_encoded_bits[(i * cfg->grant.Qm) % nof_encoded_bits], - cfg->grant.Qm, - &bits[cfg->grant.Qm * i]); } + if (acks) { + acks[0] = (uint8_t)(acks_sum[0] > 0); + acks[1] = (uint8_t)(acks_sum[1] > 0); + // TODO: Do something with acks_sum[2] + } + return (int) Qprime; +} +#endif + +/* Encode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212 + * Currently only supporting 1-bit HARQ + */ +int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, uint8_t acks[2], uint32_t nof_acks, + uint32_t O_cqi, float beta, uint32_t H_prime_total, + srslte_uci_bit_t *ack_bits) +{ + if (beta < 0) { + fprintf(stderr, "Error beta is reserved\n"); + return -1; + } + + uint32_t Qprime = Q_prime_ri_ack(cfg, nof_acks, O_cqi, beta); + srslte_uci_bit_type_t q_encoded_bits[18]; + + uint32_t nof_encoded_bits = encode_ri_ack(acks, nof_acks, q_encoded_bits, cfg->grant.Qm); + + for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]); + uci_ulsch_interleave_put(&q_encoded_bits[(i*cfg->grant.Qm)%nof_encoded_bits], cfg->grant.Qm, &ack_bits[cfg->grant.Qm*i]); + } + return (int) Qprime; } -/* Decode UCI ACK/RI bits as described in 5.2.2.6 of 36.212 +/* Encode UCI RI bits as described in 5.2.2.6 of 36.212 * Currently only supporting 1-bit RI */ -int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, - float beta, uint32_t H_prime_total, - uint32_t O_cqi, srslte_uci_bit_t *ack_ri_bits, uint8_t data[2], uint32_t nof_bits, bool is_ri) +int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, + float beta, uint32_t H_prime_total, + uint32_t O_cqi, srslte_uci_bit_t *ri_bits, uint8_t *data) { - int32_t sum[3] = {0, 0, 0}; - + int32_t ri_sum[3] = {0, 0, 0}; + if (beta < 0) { fprintf(stderr, "Error beta is reserved\n"); - return -1; + return -1; } - uint32_t Qprime = Q_prime_ri_ack(cfg, nof_bits, O_cqi, beta); + uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta); - for (uint32_t i = 0; i < Qprime; i++) { - if (is_ri) { - uci_ulsch_interleave_ri_gen(i, - cfg->grant.Qm, - H_prime_total, - cfg->nbits.nof_symb, - cfg->cp, - &ack_ri_bits[cfg->grant.Qm * i]); - } else { - uci_ulsch_interleave_ack_gen(i, - cfg->grant.Qm, - H_prime_total, - cfg->nbits.nof_symb, - cfg->cp, - &ack_ri_bits[cfg->grant.Qm * i]); - - } - if (nof_bits == 2 && (i % 3 == 0) && i > 0) { - decode_ri_ack_2bits(q_bits, &c_seq[0], &ack_ri_bits[cfg->grant.Qm * (i - 3)], cfg->grant.Qm, sum); - } else if (nof_bits == 1) { - sum[0] += (int32_t) decode_ri_ack_1bit(q_bits, c_seq, &ack_ri_bits[cfg->grant.Qm * i]); + // Use the same interleaver function to get the HARQ bit position + for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]); + if ((i % 3 == 0) && i > 0) { + //decode_ri_ack(q_bits, &c_seq[0], &ri_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, ri_sum); } } - data[0] = (uint8_t) (sum[0] > 0); - if (nof_bits == 2) { - data[1] = (uint8_t) (sum[1] > 0); + if (data) { + *data = (uint8_t) ((ri_sum[0] + ri_sum[1] + ri_sum[2]) > 0); } + return (int) Qprime; +} + + +/* Encode UCI RI bits as described in 5.2.2.6 of 36.212 + * Currently only supporting 1-bit RI + */ +int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg, + uint8_t ri, + uint32_t O_cqi, float beta, uint32_t H_prime_total, + srslte_uci_bit_t *ri_bits) +{ + // FIXME: It supports RI of 1 bit only + uint8_t data[2] = {ri, 0}; + if (beta < 0) { + fprintf(stderr, "Error beta is reserved\n"); + return -1; + } + uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta); + srslte_uci_bit_type_t q_encoded_bits[18]; + + uint32_t nof_encoded_bits = encode_ri_ack(data, 1, q_encoded_bits, cfg->grant.Qm); + + for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]); + uci_ulsch_interleave_put(&q_encoded_bits[(i*cfg->grant.Qm)%nof_encoded_bits], cfg->grant.Qm, &ri_bits[cfg->grant.Qm*i]); + } + return (int) Qprime; } + diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 4183016e0..db7118b0c 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -725,8 +725,7 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo /* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */ for (uint32_t nof_layers = 1; nof_layers <= SRSLTE_MAX_LAYERS; nof_layers++) { float _sinr = q->sinr[nof_layers - 1][q->pmi[nof_layers - 1]] * nof_layers * nof_layers; - /* Find best SINR, force maximum number of layers if SNR is higher than 30 dB */ - if (_sinr > best_sinr + 0.1 || _sinr > 1.0e+3) { + if (_sinr > best_sinr + 0.1) { best_sinr = _sinr; best_pmi = (uint8_t) q->pmi[nof_layers - 1]; best_ri = (uint8_t) (nof_layers - 1); diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc index 990633aa7..5298e6e7a 100644 --- a/srsenb/src/phy/phch_worker.cc +++ b/srsenb/src/phy/phch_worker.cc @@ -88,19 +88,16 @@ void phch_worker::init(phch_common* phy_, srslte::log *log_h_) pthread_mutex_init(&mutex, NULL); // Init cell here - for(int p = 0; p < SRSLTE_MAX_PORTS; p++) { - signal_buffer_rx[p] = (cf_t *) srslte_vec_malloc(2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); - if (!signal_buffer_rx[p]) { - fprintf(stderr, "Error allocating memory\n"); - return; - } - bzero(signal_buffer_rx[p], 2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); - signal_buffer_tx[p] = (cf_t *) srslte_vec_malloc(2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); - if (!signal_buffer_tx[p]) { - fprintf(stderr, "Error allocating memory\n"); - return; - } - bzero(signal_buffer_tx[p], 2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); + signal_buffer_rx = (cf_t*) srslte_vec_malloc(2*SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t)); + if (!signal_buffer_rx) { + fprintf(stderr, "Error allocating memory\n"); + return; + } + bzero(&signal_buffer_tx, sizeof(cf_t *) * SRSLTE_MAX_PORTS); + signal_buffer_tx[0] = (cf_t*) srslte_vec_malloc(2*SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t)); + if (!signal_buffer_tx[0]) { + fprintf(stderr, "Error allocating memory\n"); + return; } if (srslte_enb_dl_init(&enb_dl, signal_buffer_tx, phy->cell.nof_prb)) { fprintf(stderr, "Error initiating ENB DL\n"); @@ -110,7 +107,7 @@ void phch_worker::init(phch_common* phy_, srslte::log *log_h_) fprintf(stderr, "Error initiating ENB DL\n"); return; } - if (srslte_enb_ul_init(&enb_ul, signal_buffer_rx[0], phy->cell.nof_prb)) { + if (srslte_enb_ul_init(&enb_ul, signal_buffer_rx, phy->cell.nof_prb)) { fprintf(stderr, "Error initiating ENB UL\n"); return; } @@ -157,12 +154,12 @@ void phch_worker::stop() srslte_enb_dl_free(&enb_dl); srslte_enb_ul_free(&enb_ul); - for (int p = 0; p < SRSLTE_MAX_PORTS; p++) { - if (signal_buffer_rx[p]) { - free(signal_buffer_rx[p]); - } - if (signal_buffer_tx[p]) { - free(signal_buffer_tx[p]); + if (signal_buffer_rx) { + free(signal_buffer_rx); + } + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + if (signal_buffer_tx[i]) { + free(signal_buffer_tx[i]); } } pthread_mutex_unlock(&mutex); @@ -174,9 +171,9 @@ void phch_worker::reset() ue_db.clear(); } -cf_t* phch_worker::get_buffer_rx(uint32_t antenna_idx) +cf_t* phch_worker::get_buffer_rx() { - return signal_buffer_rx[antenna_idx]; + return signal_buffer_rx; } void phch_worker::set_time(uint32_t tti_, uint32_t tx_mutex_cnt_, srslte_timestamp_t tx_time_) @@ -217,29 +214,12 @@ uint32_t phch_worker::get_nof_rnti() { return ue_db.size(); } -void phch_worker::set_conf_dedicated_ack(uint16_t rnti, bool ack){ - pthread_mutex_lock(&mutex); - if (ue_db.count(rnti)) { - ue_db[rnti].dedicated_ack = ack; - } else { - Error("Setting dedicated ack: rnti=0x%x does not exist\n"); - } - pthread_mutex_unlock(&mutex); -} - void phch_worker::set_config_dedicated(uint16_t rnti, srslte_uci_cfg_t *uci_cfg, srslte_pucch_sched_t *pucch_sched, - srslte_refsignal_srs_cfg_t *srs_cfg, - LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated) + srslte_refsignal_srs_cfg_t *srs_cfg, + uint32_t I_sr, bool pucch_cqi, uint32_t pmi_idx, bool pucch_cqi_ack) { - uint32_t I_sr = dedicated->sched_request_cnfg.sr_cnfg_idx; - bool pucch_cqi = dedicated->cqi_report_cnfg.report_periodic_setup_present; - uint32_t pmi_idx = dedicated->cqi_report_cnfg.report_periodic.pmi_cnfg_idx; - bool pucch_cqi_ack = dedicated->cqi_report_cnfg.report_periodic.simult_ack_nack_and_cqi; - bool pucch_ri = dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx_present; - uint32_t ri_idx = dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx; - pthread_mutex_lock(&mutex); if (ue_db.count(rnti)) { pucch_sched->N_pucch_1 = phy->pucch_cfg.n1_pucch_an; @@ -257,16 +237,6 @@ void phch_worker::set_config_dedicated(uint16_t rnti, ue_db[rnti].cqi_en = false; } - if (pucch_ri) { - ue_db[rnti].ri_idx = ri_idx; - ue_db[rnti].ri_en = true; - } else { - ue_db[rnti].ri_idx = 0; - ue_db[rnti].ri_en = false; - } - - /* Copy all dedicated RRC configuration to UE */ - memcpy(&ue_db[rnti].dedicated, dedicated, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT)); } else { Error("Setting config dedicated: rnti=0x%x does not exist\n"); } @@ -308,7 +278,7 @@ void phch_worker::work_imp() } pthread_mutex_lock(&mutex); - + mac_interface_phy::ul_sched_t *ul_grants = phy->ul_grants; mac_interface_phy::dl_sched_t *dl_grants = phy->dl_grants; mac_interface_phy *mac = phy->mac; @@ -323,7 +293,7 @@ void phch_worker::work_imp() } // Process UL signal - srslte_enb_ul_fft(&enb_ul); + srslte_enb_ul_fft(&enb_ul, signal_buffer_rx); // Decode pending UL grants for the tti they were scheduled decode_pusch(ul_grants[t_rx].sched_grants, ul_grants[t_rx].nof_grants); @@ -365,22 +335,15 @@ void phch_worker::work_imp() phy->ack_clear(TTIMOD(TTI_TX(t_tx_dl))); for (uint32_t i=0;i= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END) { - /* For each TB */ - for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) { - /* If TB enabled, set pending ACK */ - if (dl_grants[t_tx_dl].sched_grants[i].grant.tb_en[tb_idx]) { - phy->ack_set_pending(TTIMOD(TTI_TX(t_tx_dl)), rnti, tb_idx, dl_grants[t_tx_dl].sched_grants[i].location.ncce); - } - } + if (dl_grants[t_tx_dl].sched_grants[i].rnti >= SRSLTE_CRNTI_START && dl_grants[t_tx_dl].sched_grants[i].rnti <= SRSLTE_CRNTI_END) { + phy->ack_set_pending(TTIMOD(TTI_TX(t_tx_dl)), dl_grants[t_tx_dl].sched_grants[i].rnti, dl_grants[t_tx_dl].sched_grants[i].location.ncce); } } // Generate signal and transmit srslte_enb_dl_gen_signal(&enb_dl); Debug("Sending to radio\n"); - phy->worker_end(tx_mutex_cnt, signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time); + phy->worker_end(tx_mutex_cnt, signal_buffer_tx[0], SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time); #ifdef DEBUG_WRITE_FILE fwrite(signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t), 1, f); @@ -424,39 +387,24 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) gettimeofday(&t[1], NULL); #endif - bool acks_pending[SRSLTE_MAX_TB] = {false}; - // Get pending ACKs with an associated PUSCH transmission - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - acks_pending[tb] = phy->ack_is_pending(t_rx, rnti, tb); - if (acks_pending[tb]) { - uci_data.uci_ack_len++; - } + if (phy->ack_is_pending(t_rx, rnti)) { + uci_data.uci_ack_len = 1; } - // Configure PUSCH CQI channel - srslte_cqi_value_t cqi_value = {0}; + srslte_cqi_value_t cqi_value; bool cqi_enabled = false; -#if 0 - if (ue_db[rnti].cqi_en && ue_db[rnti].ri_en && srslte_ri_send(ue_db[rnti].pmi_idx, ue_db[rnti].ri_idx, tti_rx) ) { - uci_data.uci_ri_len = 1; /* Asumes only 1 bit for RI */ - ri_enabled = true; - } else if (ue_db[rnti].cqi_en && srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { + if (ue_db[rnti].cqi_en && srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND; cqi_enabled = true; - if (ue_db[rnti].dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { - //uci_data.uci_dif_cqi_len = 3; - uci_data.uci_pmi_len = 2; - } - } else -#endif - if (grants[i].grant.cqi_request) { + } else if (grants[i].grant.cqi_request) { cqi_value.type = SRSLTE_CQI_TYPE_SUBBAND_HL; cqi_value.subband_hl.N = (phy->cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(phy->cell.nof_prb) : 0; - cqi_value.subband_hl.four_antenna_ports = (phy->cell.nof_ports == 4); - cqi_value.subband_hl.pmi_present = (ue_db[rnti].dedicated.cqi_report_cnfg.report_mode_aperiodic == LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31); cqi_enabled = true; } + if (cqi_enabled) { + uci_data.uci_cqi_len = srslte_cqi_size(&cqi_value); + } // mark this tti as having an ul grant to avoid pucch ue_db[rnti].has_grant_tti = tti_rx; @@ -464,6 +412,22 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) srslte_ra_ul_grant_t phy_grant; int res = -1; if (!srslte_ra_ul_dci_to_grant(&grants[i].grant, enb_ul.cell.nof_prb, n_rb_ho, &phy_grant)) { + + // Handle Format0 adaptive retx + // Use last TBS for this TB in case of mcs>28 + if (phy_grant.mcs.idx > 28) { + phy_grant.mcs.tbs = ue_db[rnti].last_ul_tbs[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)]; + Info("RETX: mcs=%d, old_tbs=%d pid=%d\n", phy_grant.mcs.idx, phy_grant.mcs.tbs, TTI_TX(tti_rx)%(2*HARQ_DELAY_MS)); + } + ue_db[rnti].last_ul_tbs[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)] = phy_grant.mcs.tbs; + + if (phy_grant.mcs.mod == SRSLTE_MOD_LAST) { + phy_grant.mcs.mod = ue_db[rnti].last_ul_mod[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)]; + phy_grant.Qm = srslte_mod_bits_x_symbol(phy_grant.mcs.mod); + } + ue_db[rnti].last_ul_mod[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)] = phy_grant.mcs.mod; + + if (phy_grant.mcs.mod == SRSLTE_MOD_64QAM) { phy_grant.mcs.mod = SRSLTE_MOD_16QAM; } @@ -472,7 +436,6 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) rnti, grants[i].rv_idx, grants[i].current_tx_nb, grants[i].data, - (cqi_enabled) ? &cqi_value : NULL, &uci_data, sf_rx); } else { @@ -494,24 +457,11 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) char cqi_str[64]; if (cqi_enabled) { + srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value); if (ue_db[rnti].cqi_en) { wideband_cqi_value = cqi_value.wideband.wideband_cqi; } else if (grants[i].grant.cqi_request) { wideband_cqi_value = cqi_value.subband_hl.wideband_cqi_cw0; - if (cqi_value.subband_hl.pmi_present) { - if (cqi_value.subband_hl.rank_is_not_one) { - Info("PUSCH: Aperiodic ri~1, CQI=%02d/%02d, pmi=%d for %d subbands\n", - cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.wideband_cqi_cw1, - cqi_value.subband_hl.pmi, cqi_value.subband_hl.N); - } else { - Info("PUSCH: Aperiodic ri=1, CQI=%02d, pmi=%d for %d subbands\n", - cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.pmi, cqi_value.subband_hl.N); - } - } else { - Info("PUSCH: Aperiodic ri%s, CQI=%02d for %d subbands\n", - cqi_value.subband_hl.rank_is_not_one?"~1":"=1", - cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.N); - } } snprintf(cqi_str, 64, ", cqi=%d", wideband_cqi_value); } @@ -531,16 +481,14 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) } */ log_h->info_hex(grants[i].data, phy_grant.mcs.tbs/8, - "PUSCH: rnti=0x%x, prb=(%d,%d), tbs=%d, mcs=%d, rv=%d, snr=%.1f dB, n_iter=%d, crc=%s%s%s%s%s\n", + "PUSCH: rnti=0x%x, prb=(%d,%d), tbs=%d, mcs=%d, rv=%d, snr=%.1f dB, n_iter=%d, crc=%s%s%s%s\n", rnti, phy_grant.n_prb[0], phy_grant.n_prb[0]+phy_grant.L_prb, phy_grant.mcs.tbs/8, phy_grant.mcs.idx, grants[i].grant.rv_idx, snr_db, srslte_pusch_last_noi(&enb_ul.pusch), crc_res?"OK":"KO", - (uci_data.uci_ack_len)?(uci_data.uci_ack?"1":"0"):"", - (uci_data.uci_ack_len > 1)?(uci_data.uci_ack_2?"1":"0"):"", + uci_data.uci_ack_len>0?(uci_data.uci_ack?", ack=1":", ack=0"):"", uci_data.uci_cqi_len>0?cqi_str:"", - uci_data.uci_ri_len>0?(uci_data.uci_ri?", ri=0":", ri=1"):"", timestr); // Notify MAC of RL status @@ -555,28 +503,17 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) // Notify MAC new received data and HARQ Indication value phy->mac->crc_info(tti_rx, rnti, phy_grant.mcs.tbs/8, crc_res); - uint32_t ack_idx = 0; - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - if (acks_pending[tb]) { - bool ack = ((ack_idx++ == 0) ? uci_data.uci_ack : uci_data.uci_ack_2); - bool valid = (crc_res || snr_db > PUSCH_RL_SNR_DB_TH); - phy->mac->ack_info(tti_rx, rnti, tb, ack && valid); - } + if (uci_data.uci_ack_len) { + phy->mac->ack_info(tti_rx, rnti, uci_data.uci_ack && (crc_res || snr_db > PUSCH_RL_SNR_DB_TH)); } - // Notify MAC of UL SNR, DL CQI and DL RI + // Notify MAC of UL SNR and DL CQI if (snr_db >= PUSCH_RL_SNR_DB_TH) { phy->mac->snr_info(tti_rx, rnti, snr_db); } if (uci_data.uci_cqi_len>0 && crc_res) { phy->mac->cqi_info(tti_rx, rnti, wideband_cqi_value); } - if (uci_data.uci_ri_len > 0 && crc_res) { - phy->mac->ri_info(tti_rx, rnti, uci_data.uci_ri); - } - if (cqi_value.subband_hl.pmi_present && crc_res) { - phy->mac->pmi_info(tti_rx, rnti, cqi_value.subband_hl.pmi); - } // Save metrics stats ue_db[rnti].metrics_ul(phy_grant.mcs.idx, 0, snr_db, srslte_pusch_last_noi(&enb_ul.pusch)); @@ -595,8 +532,7 @@ int phch_worker::decode_pucch() if (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END && ue_db[rnti].has_grant_tti != (int) tti_rx) { // Check if user needs to receive PUCCH - bool needs_pucch = false, needs_ack[SRSLTE_MAX_TB] = {false}, needs_sr = false, needs_cqi = false, - needs_ri = false; + bool needs_pucch = false, needs_ack=false, needs_sr=false, needs_cqi=false; uint32_t last_n_pdcch = 0; bzero(&uci_data, sizeof(srslte_uci_data_t)); @@ -608,32 +544,18 @@ int phch_worker::decode_pucch() } } - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - needs_ack[tb] = phy->ack_is_pending(t_rx, rnti, tb, &last_n_pdcch); - if (needs_ack[tb]) { - needs_pucch = true; - uci_data.uci_ack_len++; - } + if (phy->ack_is_pending(t_rx, rnti, &last_n_pdcch)) { + needs_pucch = true; + needs_ack = true; + uci_data.uci_ack_len = 1; } srslte_cqi_value_t cqi_value; - LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated = &ue_db[rnti].dedicated; - LIBLTE_RRC_TRANSMISSION_MODE_ENUM tx_mode = dedicated->antenna_info_explicit_value.tx_mode; - - if (ue_db[rnti].cqi_en && (ue_db[rnti].pucch_cqi_ack || !needs_ack[0] || !needs_ack[1])) { - if (ue_db[rnti].ri_en && srslte_ri_send(ue_db[rnti].pmi_idx, ue_db[rnti].ri_idx, tti_rx)) { - needs_pucch = true; - needs_ri = true; - uci_data.uci_ri_len = 1; - uci_data.ri_periodic_report = true; - } else if (srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { + if (ue_db[rnti].cqi_en && (ue_db[rnti].pucch_cqi_ack || !needs_ack)) { + if (srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { needs_pucch = true; needs_cqi = true; cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND; uci_data.uci_cqi_len = srslte_cqi_size(&cqi_value); - if (tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { - //uci_data.uci_dif_cqi_len = 3; - uci_data.uci_pmi_len = 2; - } } } @@ -642,48 +564,26 @@ int phch_worker::decode_pucch() fprintf(stderr, "Error getting PUCCH\n"); return SRSLTE_ERROR; } - /* If only one ACK is required, it can be for TB0 or TB1 */ - uint32_t ack_idx = 0; - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - if (needs_ack[tb]) { - bool ack = ((ack_idx++ == 0) ? uci_data.uci_ack : uci_data.uci_ack_2); - bool valid = srslte_pucch_get_last_corr(&enb_ul.pucch) >= PUCCH_RL_CORR_TH; - phy->mac->ack_info(tti_rx, rnti, tb, ack && valid); - } + if (uci_data.uci_ack_len > 0) { + phy->mac->ack_info(tti_rx, rnti, uci_data.uci_ack && (srslte_pucch_get_last_corr(&enb_ul.pucch) >= PUCCH_RL_CORR_TH)); } if (uci_data.scheduling_request) { phy->mac->sr_detected(tti_rx, rnti); } - - char cqi_ri_str[64]; - if (srslte_pucch_get_last_corr(&enb_ul.pucch) > PUCCH_RL_CORR_TH) { - if (uci_data.uci_ri_len && needs_ri) { - phy->mac->ri_info(tti_rx, rnti, uci_data.uci_ri); - sprintf(cqi_ri_str, ", ri=%d", uci_data.uci_ri); - } else if (uci_data.uci_cqi_len && needs_cqi) { - srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value); - phy->mac->cqi_info(tti_rx, rnti, cqi_value.wideband.wideband_cqi); - sprintf(cqi_ri_str, ", cqi=%d", cqi_value.wideband.wideband_cqi); - - if (uci_data.uci_pmi_len) { - uint32_t packed_pmi = uci_data.uci_pmi[0]; - if (uci_data.uci_pmi_len > 1) { - packed_pmi = (packed_pmi << 1) + uci_data.uci_pmi[1]; - } - phy->mac->pmi_info(tti_rx, rnti, packed_pmi); - sprintf(cqi_ri_str, "%s, pmi=%c", cqi_ri_str, packed_pmi + 0x30); - } - } + char cqi_str[64]; + if (uci_data.uci_cqi_len) { + srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value); + phy->mac->cqi_info(tti_rx, rnti, cqi_value.wideband.wideband_cqi); + sprintf(cqi_str, ", cqi=%d", cqi_value.wideband.wideband_cqi); } - log_h->info("PUCCH: rnti=0x%x, corr=%.2f, n_pucch=%d, n_prb=%d%s%s%s%s\n", + log_h->info("PUCCH: rnti=0x%x, corr=%.2f, n_pucch=%d, n_prb=%d%s%s%s\n", rnti, srslte_pucch_get_last_corr(&enb_ul.pucch), enb_ul.pucch.last_n_pucch, enb_ul.pucch.last_n_prb, - (uci_data.uci_ack_len)?(uci_data.uci_ack?", ack=1":", ack=0"):"", - (uci_data.uci_ack_len > 1)?(uci_data.uci_ack_2?"1":"0"):"", + needs_ack?(uci_data.uci_ack?", ack=1":", ack=0"):"", needs_sr?(uci_data.scheduling_request?", sr=yes":", sr=no"):"", - (needs_cqi || needs_ri)?cqi_ri_str:""); + needs_cqi?cqi_str:""); // Notify MAC of RL status @@ -742,16 +642,25 @@ int phch_worker::encode_pdcch_ul(srslte_enb_ul_pusch_t *grants, uint32_t nof_gra int phch_worker::encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants) { for (uint32_t i=0;irnti; + uint16_t rnti = grants[i].rnti; if (rnti) { - if (srslte_enb_dl_put_pdcch_dl(&enb_dl, &grants[i].grant, grant->dci_format, grants[i].location, rnti, sf_tx)) { + srslte_dci_format_t format = SRSLTE_DCI_FORMAT1; + switch(grants[i].grant.alloc_type) { + case SRSLTE_RA_ALLOC_TYPE0: + case SRSLTE_RA_ALLOC_TYPE1: + format = SRSLTE_DCI_FORMAT1; + break; + case SRSLTE_RA_ALLOC_TYPE2: + format = SRSLTE_DCI_FORMAT1A; + break; + } + if (srslte_enb_dl_put_pdcch_dl(&enb_dl, &grants[i].grant, format, grants[i].location, rnti, sf_tx)) { fprintf(stderr, "Error putting PDCCH %d\n",i); return SRSLTE_ERROR; } if (LOG_THIS(rnti)) { - Info("PDCCH: DL DCI %s rnti=0x%x, cce_index=%d, L=%d, tti_tx_dl=%d\n", srslte_dci_format_string(grant->dci_format), + Info("PDCCH: DL DCI %s rnti=0x%x, cce_index=%d, L=%d, tti_tx_dl=%d\n", srslte_dci_format_string(format), rnti, grants[i].location.ncce, (1<info_hex(ptr, len, - "PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tti_tx_dl=%d, tx_scheme=%s%s%s%s\n", - rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process, tti_tx_dl, - srslte_mimotype2str(mimo_type), pinfo_str, tbstr[0], tbstr[1]); + "PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tbs=%d, mcs=%d, rv=%d, tti_tx_dl=%d\n", + rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process, + phy_grant.mcs[0].tbs/8, phy_grant.mcs[0].idx, grants[i].grant.rv_idx, tti_tx_dl); } - int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, grants[i].grant.rv_idx_1}; + srslte_softbuffer_tx_t *sb[SRSLTE_MAX_CODEWORDS] = {grants[i].softbuffer, NULL}; + uint8_t *d[SRSLTE_MAX_CODEWORDS] = {grants[i].data, NULL}; + int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, 0}; - if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, grants[i].softbuffers, rnti, rv, sf_tx, grants[i].data, mimo_type)) { - fprintf(stderr, "Error putting PDSCH %d\n", i); - return SRSLTE_ERROR; + + if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, sb, rnti, rv, sf_tx, d, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0)) + { + fprintf(stderr, "Error putting PDSCH %d\n",i); + return SRSLTE_ERROR; } - // Save metrics stats + // Save metrics stats ue_db[rnti].metrics_dl(phy_grant.mcs[0].idx); } } - return SRSLTE_SUCCESS; + return SRSLTE_SUCCESS; } diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index 29cbdef8e..e176e8ac5 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -1142,11 +1142,7 @@ void rrc::ue::send_connection_setup(bool is_setup) phy_cfg->cqi_report_cnfg_present = true; if(parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_APERIODIC) { phy_cfg->cqi_report_cnfg.report_mode_aperiodic_present = true; - if (phy_cfg->antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { - phy_cfg->cqi_report_cnfg.report_mode_aperiodic = LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31; - } else { - phy_cfg->cqi_report_cnfg.report_mode_aperiodic = LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30; - } + phy_cfg->cqi_report_cnfg.report_mode_aperiodic = LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30; } else { phy_cfg->cqi_report_cnfg.report_periodic_present = true; phy_cfg->cqi_report_cnfg.report_periodic_setup_present = true; diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 2beff5900..0068724b4 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -859,9 +859,7 @@ void phch_worker::set_uci_periodic_cqi() if (period_cqi.configured && rnti_is_set) { if (period_cqi.ri_idx_present && srslte_ri_send(period_cqi.pmi_idx, period_cqi.ri_idx, TTI_TX(tti))) { - /* Compute RI, PMI and SINR */ compute_ri(); - uci_data.ri_periodic_report = true; Info("PUCCH: Periodic RI=%d\n", uci_data.uci_ri); } else if (srslte_cqi_send(period_cqi.pmi_idx, TTI_TX(tti))) { @@ -904,9 +902,6 @@ void phch_worker::set_uci_periodic_cqi() void phch_worker::set_uci_aperiodic_cqi() { if (phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic_present) { - /* Compute RI, PMI and SINR */ - compute_ri(); - switch(phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic) { case LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30: /* only Higher Layer-configured subband feedback support right now, according to TS36.213 section 7.2.1 @@ -944,6 +939,9 @@ void phch_worker::set_uci_aperiodic_cqi() other transmission modes they are reported conditioned on rank 1. */ if (rnti_is_set) { + /* Compute RI, PMI and SINR */ + compute_ri(); + /* Select RI, PMI and SINR */ uint32_t ri = ue_dl.ri; // Select RI (0: 1 layer, 1: 2 layer, otherwise: not implemented) uint32_t pmi = ue_dl.pmi[ri]; // Select PMI @@ -974,9 +972,9 @@ void phch_worker::set_uci_aperiodic_cqi() cqi_report.subband_hl.wideband_cqi_cw0, cqi_report.subband_hl.wideband_cqi_cw1, sinr_db, sinr_db, pmi, cqi_report.subband_hl.N); } else { - Info("PUSCH: Aperiodic ri=1, CQI=%02d, SINR=%2.1f, pmi=%d for %d subbands\n", - cqi_report.subband_hl.wideband_cqi_cw0, - sinr_db, pmi, cqi_report.subband_hl.N); + Info("PUSCH: Aperiodic ri=1, CQI=%d/%d, SINR=%2.1f dB, for %d subbands\n", + cqi_report.wideband.wideband_cqi, + phy->avg_snr_db, cqi_report.subband_hl.N); } uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); } From e720568e82bddff75fd5da98302ab0d460bf7052 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Mon, 4 Dec 2017 12:08:02 -0600 Subject: [PATCH 31/42] Revert "Added UE Mode 3-1 aperiodic reporting" This reverts commit 0bd683b3c4455e1274450d4487a6077f231f0ba5. --- lib/include/srslte/phy/phch/cqi.h | 21 +--- lib/include/srslte/phy/phch/uci.h | 1 - lib/src/phy/phch/cqi.c | 73 ++----------- lib/src/phy/phch/pucch.c | 2 +- lib/src/phy/ue/ue_dl.c | 4 +- lib/src/phy/ue/ue_ul.c | 28 ++--- srsenb/src/phy/phch_worker.cc | 2 +- srsue/hdr/phy/phch_worker.h | 3 +- srsue/src/phy/phch_worker.cc | 175 ++++++++++-------------------- 9 files changed, 88 insertions(+), 221 deletions(-) diff --git a/lib/include/srslte/phy/phch/cqi.h b/lib/include/srslte/phy/phch/cqi.h index 0d0c17fec..cfc9e92e7 100644 --- a/lib/include/srslte/phy/phch/cqi.h +++ b/lib/include/srslte/phy/phch/cqi.h @@ -55,22 +55,13 @@ typedef struct { } srslte_cqi_periodic_cfg_t; /* Table 5.2.2.6.2-1: Fields for channel quality information feedback for higher layer configured subband - CQI reports (transmission mode 1, transmission mode 2, transmission mode 3, transmission mode 7 and - transmission mode 8 configured without PMI/RI reporting). */ - -/* Table 5.2.2.6.2-2: Fields for channel quality information (CQI) feedback for higher layer configured subband CQI - reports (transmission mode 4, transmission mode 5 and transmission mode 6). */ - +CQI reports +(transmission mode 1, transmission mode 2, transmission mode 3, transmission mode 7 and +transmission mode 8 configured without PMI/RI reporting). */ typedef struct SRSLTE_API { - uint8_t wideband_cqi_cw0; // 4-bit width - uint32_t subband_diff_cqi_cw0; // 2N-bit width - uint8_t wideband_cqi_cw1; // if RI > 1 then 4-bit width otherwise 0-bit width - uint32_t subband_diff_cqi_cw1; // if RI > 1 then 2N-bit width otherwise 0-bit width - uint32_t pmi; // if RI > 1 then 2-bit width otherwise 1-bit width - uint32_t N; - bool pmi_present; - bool four_antenna_ports; // If cell has 4 antenna ports then true otherwise false - bool rank_is_not_one; // If rank > 1 then true otherwise false + uint8_t wideband_cqi; // 4-bit width + uint32_t subband_diff_cqi; // 2N-bit width + uint32_t N; } srslte_cqi_hl_subband_t; /* Table 5.2.2.6.3-1: Fields for channel quality information feedback for UE selected subband CQI diff --git a/lib/include/srslte/phy/phch/uci.h b/lib/include/srslte/phy/phch/uci.h index 91592501f..ff315384e 100644 --- a/lib/include/srslte/phy/phch/uci.h +++ b/lib/include/srslte/phy/phch/uci.h @@ -73,7 +73,6 @@ typedef struct SRSLTE_API { uint8_t uci_ack; // 1st codeword bit for HARQ-ACK uint8_t uci_ack_2; // 2st codeword bit for HARQ-ACK uint32_t uci_ack_len; - bool ri_periodic_report; bool scheduling_request; bool channel_selection; bool cqi_ack; diff --git a/lib/src/phy/phch/cqi.c b/lib/src/phy/phch/cqi.c index 2c0940af5..0041c3fcb 100644 --- a/lib/src/phy/phch/cqi.c +++ b/lib/src/phy/phch/cqi.c @@ -44,38 +44,11 @@ *******************************************************/ int srslte_cqi_hl_subband_pack(srslte_cqi_hl_subband_t *msg, uint8_t buff[SRSLTE_CQI_MAX_BITS]) { - uint8_t *body_ptr = buff; - uint32_t bit_count = 0; - - /* Unpack codeword 0, common for 3GPP 36.212 Tables 5.2.2.6.2-1 and 5.2.2.6.2-2 */ - srslte_bit_unpack(msg->wideband_cqi_cw0, &body_ptr, 4); - srslte_bit_unpack(msg->subband_diff_cqi_cw0, &body_ptr, 2*msg->N); - bit_count += 4+2*msg->N; - - /* Unpack codeword 1, 3GPP 36.212 Table 5.2.2.6.2-2 */ - if (msg->rank_is_not_one) { - srslte_bit_unpack(msg->wideband_cqi_cw1, &body_ptr, 4); - srslte_bit_unpack(msg->subband_diff_cqi_cw1, &body_ptr, 2*msg->N); - bit_count += 4+2*msg->N; - } - - /* If PMI is present, unpack it */ - if (msg->pmi_present) { - if (msg->four_antenna_ports) { - srslte_bit_unpack(msg->pmi, &body_ptr, 4); - bit_count += 4; - } else { - if (msg->rank_is_not_one) { - srslte_bit_unpack(msg->pmi, &body_ptr, 1); - bit_count += 1; - } else { - srslte_bit_unpack(msg->pmi, &body_ptr, 2); - bit_count += 2; - } - } - } - - return bit_count; + uint8_t *body_ptr = buff; + srslte_bit_unpack(msg->wideband_cqi, &body_ptr, 4); + srslte_bit_unpack(msg->subband_diff_cqi, &body_ptr, 2*msg->N); + + return 4+2*msg->N; } int srslte_cqi_ue_subband_pack(srslte_cqi_ue_subband_t *msg, uint8_t buff[SRSLTE_CQI_MAX_BITS]) @@ -125,37 +98,11 @@ int srslte_cqi_value_pack(srslte_cqi_value_t *value, uint8_t buff[SRSLTE_CQI_MAX int srslte_cqi_hl_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_hl_subband_t *msg) { - uint8_t *body_ptr = buff; - uint32_t bit_count = 0; - - msg->wideband_cqi_cw0 = (uint8_t) srslte_bit_pack(&body_ptr, 4); - msg->subband_diff_cqi_cw0 = srslte_bit_pack(&body_ptr, 2*msg->N); - bit_count += 4+2*msg->N; - - /* Unpack codeword 1, 3GPP 36.212 Table 5.2.2.6.2-2 */ - if (msg->rank_is_not_one) { - msg->wideband_cqi_cw1 = (uint8_t) srslte_bit_pack(&body_ptr, 4); - msg->subband_diff_cqi_cw1 = srslte_bit_pack(&body_ptr, 2*msg->N); - bit_count += 4+2*msg->N; - } - - /* If PMI is present, unpack it */ - if (msg->pmi_present) { - if (msg->four_antenna_ports) { - msg->pmi = (uint8_t) srslte_bit_pack(&body_ptr, 4); - bit_count += 4; - } else { - if (msg->rank_is_not_one) { - msg->pmi = (uint8_t) srslte_bit_pack(&body_ptr, 1); - bit_count += 1; - } else { - msg->pmi = (uint8_t) srslte_bit_pack(&body_ptr, 2); - bit_count += 2; - } - } - } - - return bit_count; + uint8_t *body_ptr = buff; + msg->wideband_cqi = srslte_bit_pack(&body_ptr, 4); + msg->subband_diff_cqi = srslte_bit_pack(&body_ptr, 2*msg->N); + + return 4+2*msg->N; } int srslte_cqi_ue_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_ue_subband_t *msg) diff --git a/lib/src/phy/phch/pucch.c b/lib/src/phy/phch/pucch.c index f9c05104c..f9c6bebc1 100644 --- a/lib/src/phy/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -173,7 +173,7 @@ srslte_pucch_format_t srslte_pucch_get_format(srslte_uci_data_t *uci_data, srslt { srslte_pucch_format_t format = SRSLTE_PUCCH_FORMAT_ERROR; // No CQI data - if (uci_data->uci_cqi_len == 0 && uci_data->uci_ri_len == 0) { + if (uci_data->uci_cqi_len == 0) { // 1-bit ACK + optional SR if (uci_data->uci_ack_len == 1) { format = SRSLTE_PUCCH_FORMAT_1A; diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index db7118b0c..134c19ca6 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -740,7 +740,6 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo } /* Set RI */ - q->ri = best_ri; if (ri != NULL) { *ri = best_ri; } @@ -776,10 +775,9 @@ int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, uint8_t *ri, float *cn) { *cn = _cn; } - q->ri = (uint8_t)((_cn < 17.0f)? 1:0); /* Set rank indicator */ if (!ret && ri) { - *ri = (uint8_t) q->ri; + *ri = (uint8_t)((_cn < 17.0f)? 1:0); } return ret; diff --git a/lib/src/phy/ue/ue_ul.c b/lib/src/phy/ue/ue_ul.c index 736fc3470..bb4fd57ae 100644 --- a/lib/src/phy/ue/ue_ul.c +++ b/lib/src/phy/ue/ue_ul.c @@ -273,33 +273,21 @@ int srslte_ue_ul_cfg_grant(srslte_ue_ul_t *q, srslte_ra_ul_grant_t *grant, void pucch_encode_bits(srslte_uci_data_t *uci_data, srslte_pucch_format_t format, uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS], uint8_t pucch2_bits[SRSLTE_PUCCH_MAX_BITS]) -{ - uint8_t uci_buffer[SRSLTE_CQI_MAX_BITS]; - uint8_t uci_buffer_len = 0; - +{ if (format == SRSLTE_PUCCH_FORMAT_1A || format == SRSLTE_PUCCH_FORMAT_1B) { pucch_bits[0] = uci_data->uci_ack; pucch_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 1a } if (format >= SRSLTE_PUCCH_FORMAT_2) { - /* Put RI (goes alone) */ - if (uci_data->ri_periodic_report) { - uci_buffer[0] = uci_data->uci_ri; // It assumes only 1 bit of RI - uci_buffer_len += uci_data->uci_ri_len; - } else { - /* Append CQI */ - memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_cqi, uci_data->uci_cqi_len); - uci_buffer_len += uci_data->uci_cqi_len; + /* Append Differential CQI */ + memcpy(&uci_data->uci_cqi[uci_data->uci_cqi_len], uci_data->uci_dif_cqi, uci_data->uci_dif_cqi_len); + uci_data->uci_cqi_len += uci_data->uci_dif_cqi_len; - /* Append Differential CQI */ - memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_dif_cqi, uci_data->uci_dif_cqi_len); - uci_buffer_len += uci_data->uci_dif_cqi_len; + /* Append PMI */ + memcpy(&uci_data->uci_cqi[uci_data->uci_cqi_len], uci_data->uci_pmi, uci_data->uci_pmi_len); + uci_data->uci_cqi_len += uci_data->uci_pmi_len; - /* Append PMI */ - memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_pmi, uci_data->uci_pmi_len); - uci_buffer_len += uci_data->uci_pmi_len; - } - srslte_uci_encode_cqi_pucch(uci_buffer, uci_buffer_len, pucch_bits); + srslte_uci_encode_cqi_pucch(uci_data->uci_cqi, uci_data->uci_cqi_len, pucch_bits); if (format > SRSLTE_PUCCH_FORMAT_2) { pucch2_bits[0] = uci_data->uci_ack; pucch2_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 2a diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc index 5298e6e7a..c023c13e0 100644 --- a/srsenb/src/phy/phch_worker.cc +++ b/srsenb/src/phy/phch_worker.cc @@ -461,7 +461,7 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) if (ue_db[rnti].cqi_en) { wideband_cqi_value = cqi_value.wideband.wideband_cqi; } else if (grants[i].grant.cqi_request) { - wideband_cqi_value = cqi_value.subband_hl.wideband_cqi_cw0; + wideband_cqi_value = cqi_value.subband_hl.wideband_cqi; } snprintf(cqi_str, 64, ", cqi=%d", wideband_cqi_value); } diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index 5378a9428..4f8df27db 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -76,8 +76,7 @@ private: /* Internal methods */ bool extract_fft_and_pdcch_llr(); - void compute_ri(); - + /* ... for DL */ bool decode_pdcch_ul(mac_interface_phy::mac_grant_t *grant); bool decode_pdcch_dl(mac_interface_phy::mac_grant_t *grant); diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 0068724b4..27503c9f7 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -272,6 +272,39 @@ void phch_worker::work_imp() if (dl_action.generate_ack) { set_uci_ack(dl_ack, dl_mac_grant.tb_en); } + + /* Select Rank Indicator by computing Condition Number */ + if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3) { + if (ue_dl.nof_rx_antennas > 1) { + /* If 2 ort more receiving antennas, select RI */ + float cn = 0.0f; + srslte_ue_dl_ri_select(&ue_dl, &uci_data.uci_ri, &cn); + uci_data.uci_ri_len = 1; + } else { + /* If only one receiving antenna, force RI for 1 layer */ + uci_data.uci_ri = 0; + uci_data.uci_ri_len = 1; + Warning("Only one receiving antenna with TM3. Forcing RI=1 layer.\n"); + } + } else if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4){ + float sinr = 0.0f; + uint8 packed_pmi = 0; + srslte_ue_dl_ri_pmi_select(&ue_dl, &uci_data.uci_ri, &packed_pmi, &sinr); + srslte_bit_unpack_vector(&packed_pmi, uci_data.uci_pmi, 2); + uci_data.uci_ri_len = 1; + if (uci_data.uci_ri == 0) { + uci_data.uci_pmi_len = 2; + uci_data.uci_dif_cqi_len = 0; + } else { + uci_data.uci_pmi_len = 1; + uci_data.uci_dif_cqi_len = 3; + } + + /* If only one antenna in TM4 print limitation warning */ + if (ue_dl.nof_rx_antennas < 2) { + Warning("Only one receiving antenna with TM4. Forcing RI=1 layer (PMI=%d).\n", packed_pmi); + } + } } } @@ -327,7 +360,7 @@ void phch_worker::work_imp() phy->set_pending_ack(TTI_RX_ACK(tti), ue_ul.pusch_cfg.grant.n_prb_tilde[0], ul_action.phy_grant.ul.ncs_dmrs); } - } else if (dl_action.generate_ack || uci_data.scheduling_request || uci_data.uci_cqi_len > 0 || uci_data.uci_ri_len > 0) { + } else if (dl_action.generate_ack || uci_data.scheduling_request || uci_data.uci_cqi_len > 0) { encode_pucch(); signal_ready = true; } else if (srs_is_ready_to_send()) { @@ -377,42 +410,6 @@ void phch_worker::work_imp() #endif } -void phch_worker::compute_ri() { - if (uci_data.uci_ri_len > 0) { - /* Do nothing */ - } else if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3) { - if (ue_dl.nof_rx_antennas > 1) { - /* If 2 ort more receiving antennas, select RI */ - float cn = 0.0f; - srslte_ue_dl_ri_select(&ue_dl, &uci_data.uci_ri, &cn); - Info("RI select %d layers, κ=%fdB\n", uci_data.uci_ri + 1, cn); - } else { - /* If only one receiving antenna, force RI for 1 layer */ - uci_data.uci_ri = 0; - Warning("Only one receiving antenna with TM3. Forcing RI=1 layer.\n"); - } - uci_data.uci_ri_len = 1; - } else if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { - float sinr = 0.0f; - uint8 packed_pmi = 0; - srslte_ue_dl_ri_pmi_select(&ue_dl, &uci_data.uci_ri, &packed_pmi, &sinr); - if (uci_data.uci_ri == 0) { - uci_data.uci_pmi_len = 2; - uci_data.uci_dif_cqi_len = 0; - } else { - uci_data.uci_pmi_len = 1; - uci_data.uci_dif_cqi_len = 3; - } - srslte_bit_unpack_vector(&packed_pmi, uci_data.uci_pmi, uci_data.uci_pmi_len); - Info("ri=%d; pmi=%d; SINR=%.1fdB\n", ue_dl.ri, ue_dl.pmi[ue_dl.ri], 10*log10f(ue_dl.sinr[ue_dl.ri][ue_dl.pmi[ue_dl.ri]])); - - /* If only one antenna in TM4 print limitation warning */ - if (ue_dl.nof_rx_antennas < 2) { - Warning("Only one receiving antenna with TM4. Forcing RI=1 layer (PMI=%d).\n", packed_pmi); - } - uci_data.uci_ri_len = 1; - } -} bool phch_worker::extract_fft_and_pdcch_llr() { bool decode_pdcch = true; @@ -826,15 +823,21 @@ void phch_worker::reset_uci() void phch_worker::set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], bool tb_en[SRSLTE_MAX_CODEWORDS]) { - /* Map ACK according to 3GPP 36.212 clause 5.2.3.1 */ - uint32_t nof_ack = 0; - for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { - if (tb_en[tb]) { - ((nof_ack == 0)?uci_data.uci_ack:uci_data.uci_ack_2) = (uint8_t)(ack[tb]?1:0); - nof_ack++; - } + uint32_t nof_tb = 0; + if (tb_en[0]) { + uci_data.uci_ack = (uint8_t) ((ack[0]) ? 1 : 0); + nof_tb = 1; + } else { + uci_data.uci_ack = 1; } - uci_data.uci_ack_len = nof_ack; + + if (tb_en[1]) { + uci_data.uci_ack_2 = (uint8_t) ((ack[1]) ? 1 : 0); + nof_tb = 2; + } + + uci_data.uci_ack_len = nof_tb; + } void phch_worker::set_uci_sr() @@ -859,9 +862,14 @@ void phch_worker::set_uci_periodic_cqi() if (period_cqi.configured && rnti_is_set) { if (period_cqi.ri_idx_present && srslte_ri_send(period_cqi.pmi_idx, period_cqi.ri_idx, TTI_TX(tti))) { - compute_ri(); - uci_data.ri_periodic_report = true; - Info("PUCCH: Periodic RI=%d\n", uci_data.uci_ri); + if (uci_data.uci_ri_len) { + uci_data.uci_cqi[0] = uci_data.uci_ri; + uci_data.uci_cqi_len = uci_data.uci_ri_len; + uci_data.uci_ri_len = 0; + uci_data.uci_dif_cqi_len = 0; + uci_data.uci_pmi_len = 0; + Info("PUCCH: Periodic RI=%d\n", uci_data.uci_cqi[0]); + } } else if (srslte_cqi_send(period_cqi.pmi_idx, TTI_TX(tti))) { srslte_cqi_value_t cqi_report; if (period_cqi.format_is_subband) { @@ -883,16 +891,6 @@ void phch_worker::set_uci_periodic_cqi() } Info("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db); } - if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { - if (ue_dl.ri == 0) { - uci_data.uci_pmi_len = 2; - } else { - uci_data.uci_pmi_len = 1; - uci_data.uci_dif_cqi_len = 3; - } - uint8_t *ptr = uci_data.uci_pmi; - srslte_bit_unpack(ue_dl.pmi[ue_dl.ri], &ptr, uci_data.uci_pmi_len); - } uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); rar_cqi_request = false; } @@ -914,71 +912,18 @@ void phch_worker::set_uci_aperiodic_cqi() reported RI. For other transmission modes they are reported conditioned on rank 1. */ if (rnti_is_set) { - srslte_cqi_value_t cqi_report = {0}; + srslte_cqi_value_t cqi_report; cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND_HL; - cqi_report.subband_hl.wideband_cqi_cw0 = srslte_cqi_from_snr(phy->avg_snr_db); + cqi_report.subband_hl.wideband_cqi = srslte_cqi_from_snr(phy->avg_snr_db); // TODO: implement subband CQI properly - cqi_report.subband_hl.subband_diff_cqi_cw0 = 0; // Always report zero offset on all subbands + cqi_report.subband_hl.subband_diff_cqi = 0; // Always report zero offset on all subbands cqi_report.subband_hl.N = (cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(cell.nof_prb) : 0; Info("PUSCH: Aperiodic CQI=%d, SNR=%.1f dB, for %d subbands\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db, cqi_report.subband_hl.N); uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); } break; - case LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31: - /* only Higher Layer-configured subband feedback support right now, according to TS36.213 section 7.2.1 - - A single precoding matrix is selected from the codebook subset assuming transmission on set S subbands - - A UE shall report one subband CQI value per codeword for each set S subband which are calculated assuming - the use of the single precoding matrix in all subbands and assuming transmission in the corresponding - subband. - - A UE shall report a wideband CQI value per codeword which is calculated assuming the use of the single - precoding matrix in all subbands and transmission on set S subbands - - The UE shall report the single selected precoding matrix indicator. - - For transmission mode 4 the reported PMI and CQI values are calculated conditioned on the reported RI. For - other transmission modes they are reported conditioned on rank 1. - */ - if (rnti_is_set) { - /* Compute RI, PMI and SINR */ - compute_ri(); - - /* Select RI, PMI and SINR */ - uint32_t ri = ue_dl.ri; // Select RI (0: 1 layer, 1: 2 layer, otherwise: not implemented) - uint32_t pmi = ue_dl.pmi[ri]; // Select PMI - float sinr_db = 10 * log10(ue_dl.sinr[ri][pmi]); - - /* Fill CQI Report */ - srslte_cqi_value_t cqi_report = {0}; - cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND_HL; - - cqi_report.subband_hl.wideband_cqi_cw0 = srslte_cqi_from_snr(sinr_db); - cqi_report.subband_hl.subband_diff_cqi_cw0 = 0; // Always report zero offset on all subbands - - if (ri > 0) { - cqi_report.subband_hl.rank_is_not_one = true; - cqi_report.subband_hl.wideband_cqi_cw1 = srslte_cqi_from_snr(sinr_db); - cqi_report.subband_hl.subband_diff_cqi_cw1 = 0; // Always report zero offset on all subbands - } - - cqi_report.subband_hl.pmi = pmi; - cqi_report.subband_hl.pmi_present = true; - cqi_report.subband_hl.four_antenna_ports = (cell.nof_ports == 4); - - // TODO: implement subband CQI properly - cqi_report.subband_hl.N = (uint32_t) ((cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(cell.nof_prb) : 0); - - if (cqi_report.subband_hl.rank_is_not_one) { - Info("PUSCH: Aperiodic ri~1, CQI=%02d/%02d, SINR=%2.1f/%2.1fdB, pmi=%d for %d subbands\n", - cqi_report.subband_hl.wideband_cqi_cw0, cqi_report.subband_hl.wideband_cqi_cw1, - sinr_db, sinr_db, pmi, cqi_report.subband_hl.N); - } else { - Info("PUSCH: Aperiodic ri=1, CQI=%d/%d, SINR=%2.1f dB, for %d subbands\n", - cqi_report.wideband.wideband_cqi, - phy->avg_snr_db, cqi_report.subband_hl.N); - } - uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); - } - break; default: Warning("Received CQI request but mode %s is not supported\n", liblte_rrc_cqi_report_mode_aperiodic_text[phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic]); @@ -1061,7 +1006,7 @@ void phch_worker::encode_pucch() char timestr[64]; timestr[0]='\0'; - if (uci_data.scheduling_request || uci_data.uci_ack_len > 0 || uci_data.uci_cqi_len > 0 || uci_data.uci_ri_len > 0) + if (uci_data.scheduling_request || uci_data.uci_ack_len > 0 || uci_data.uci_cqi_len > 0) { // Drop CQI if there is collision with ACK From 93a47df01568a8ce66ec40151fb6e770eb282245 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Mon, 4 Dec 2017 15:00:23 -0600 Subject: [PATCH 32/42] Fixed segfault when exit due to prach destructor --- srsue/hdr/phy/prach.h | 4 ++-- srsue/src/phy/prach.cc | 19 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/srsue/hdr/phy/prach.h b/srsue/hdr/phy/prach.h index 2872c374c..8218ca644 100644 --- a/srsue/hdr/phy/prach.h +++ b/srsue/hdr/phy/prach.h @@ -49,7 +49,7 @@ namespace srsue { target_power_dbm = 0; mem_initiated = false; cell_initiated = false; - bzero(signal_buffer, sizeof(signal_buffer)); + signal_buffer = NULL; } ~prach(); void init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config, uint32_t max_prb, phy_args_t *args, srslte::log *log_h); @@ -78,7 +78,7 @@ namespace srsue { srslte_prach_t prach_obj; int transmitted_tti; srslte_cell_t cell; - cf_t *signal_buffer[SRSLTE_MAX_PORTS]; + cf_t *signal_buffer; srslte_cfo_t cfo_h; float target_power_dbm; diff --git a/srsue/src/phy/prach.cc b/srsue/src/phy/prach.cc index bd7550457..182a66aa7 100644 --- a/srsue/src/phy/prach.cc +++ b/srsue/src/phy/prach.cc @@ -75,12 +75,10 @@ void prach::init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config_, uint32_t max_prb, return; } srslte_cfo_set_tol(&cfo_h, 0); - for (int p = 0; p < SRSLTE_MAX_PORTS; p++) { - signal_buffer[p] = (cf_t *) srslte_vec_malloc(SRSLTE_PRACH_MAX_LEN * sizeof(cf_t)); - if (!signal_buffer[p]) { - perror("malloc"); - return; - } + signal_buffer = (cf_t *) srslte_vec_malloc(SRSLTE_PRACH_MAX_LEN * sizeof(cf_t)); + if (!signal_buffer) { + perror("malloc"); + return; } if (srslte_prach_init(&prach_obj, srslte_symbol_sz(max_prb))) { Error("Initiating PRACH library\n"); @@ -184,7 +182,7 @@ void prach::send(srslte::radio *radio_handler, float cfo, float pathloss, srslte float old_gain = radio_handler->get_tx_gain(); // Correct CFO before transmission FIXME: UL SISO Only - srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer[0], cfo / srslte_symbol_sz(cell.nof_prb)); + srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer, cfo / srslte_symbol_sz(cell.nof_prb)); // If power control is enabled, choose amplitude and power if (args->ul_pwr_ctrl_en) { @@ -195,10 +193,10 @@ void prach::send(srslte::radio *radio_handler, float cfo, float pathloss, srslte radio_handler->set_tx_power(tx_power); // Scale signal - float digital_power = srslte_vec_avg_power_cf(signal_buffer[0], len); + float digital_power = srslte_vec_avg_power_cf(signal_buffer, len); float scale = sqrtf(pow(10,tx_power/10)/digital_power); - srslte_vec_sc_prod_cfc(signal_buffer[0], scale, signal_buffer[0], len); + srslte_vec_sc_prod_cfc(signal_buffer, scale, signal_buffer, len); log_h->console("PRACH: Pathloss=%.2f dB, Target power %.2f dBm, TX_power %.2f dBm, TX_gain %.1f dB\n", pathloss, target_power_dbm, tx_power, radio_handler->get_tx_gain(), scale); @@ -210,7 +208,8 @@ void prach::send(srslte::radio *radio_handler, float cfo, float pathloss, srslte Debug("TX PRACH: Power control for PRACH is disabled, setting gain to %.0f dB\n", prach_gain); } - radio_handler->tx((void **) signal_buffer, len, tx_time); + void *tmp_buffer[SRSLTE_MAX_PORTS] = {signal_buffer, NULL, NULL, NULL}; + radio_handler->tx(tmp_buffer, len, tx_time); radio_handler->tx_end(); Info("PRACH: Transmitted preamble=%d, CFO=%.2f KHz, tx_time=%f\n", From 082da2f7b605143d225a264b3f2a60f1bf4e5f0b Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Wed, 13 Dec 2017 10:00:38 +0100 Subject: [PATCH 33/42] Added filter for maximum PSS CFO detection value. Increased averaging for PSS CFO estimation --- lib/src/phy/sync/sync.c | 4 +++- srsue/src/main.cc | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/src/phy/sync/sync.c b/lib/src/phy/sync/sync.c index 13a5f7e69..8b7bbd69c 100644 --- a/lib/src/phy/sync/sync.c +++ b/lib/src/phy/sync/sync.c @@ -42,6 +42,8 @@ #define DEFAULT_CFO_TOL 0.0 // Hz +#define MAX_CFO_PSS_OFFSET 7000 + static bool fft_size_isvalid(uint32_t fft_size) { if (fft_size >= SRSLTE_SYNC_FFT_SZ_MIN && fft_size <= SRSLTE_SYNC_FFT_SZ_MAX && (fft_size%64) == 0) { return true; @@ -614,7 +616,7 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin if (!q->cfo_pss_is_set) { q->cfo_pss_mean = cfo_pss; q->cfo_pss_is_set = true; - } else { + } else if (15000*fabsf(cfo_pss) < MAX_CFO_PSS_OFFSET) { q->cfo_pss_mean = SRSLTE_VEC_EMA(cfo_pss, q->cfo_pss_mean, q->cfo_ema_alpha); } diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 09a382246..6df1cac99 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -205,7 +205,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { "Tolerance (in Hz) for digital CFO compensation (needs to be low if average_subframe_enabled=true.") ("expert.cfo_pss_ema", - bpo::value(&args->expert.phy.cfo_pss_ema)->default_value(0.1), + bpo::value(&args->expert.phy.cfo_pss_ema)->default_value(0.01), "CFO Exponential Moving Average coefficient for PSS estimation during TRACK.") ("expert.cfo_ref_ema", From 4c2b6fbd294f0f1418d1c8df44e728d4aff6d4f3 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Wed, 13 Dec 2017 10:03:39 +0100 Subject: [PATCH 34/42] Added check for serving PCI target HO --- srsue/src/upper/rrc.cc | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index d6ba7d5df..8a03e21a6 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -1118,15 +1118,20 @@ void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGU if (reconfig->mob_ctrl_info_present) { - rrc_log->info("Received HO command to target PCell=%d\n", reconfig->mob_ctrl_info.target_pci); - rrc_log->console("Received HO command to target PCell=%d, NCC=%d\n", - reconfig->mob_ctrl_info.target_pci, reconfig->sec_cnfg_ho.intra_lte.next_hop_chaining_count); + if (reconfig->mob_ctrl_info.target_pci == phy->get_current_pci()) { + rrc_log->warning("Received HO command to own cell\n"); + send_rrc_con_reconfig_complete(pdu); + } else { + rrc_log->info("Received HO command to target PCell=%d\n", reconfig->mob_ctrl_info.target_pci); + rrc_log->console("Received HO command to target PCell=%d, NCC=%d\n", + reconfig->mob_ctrl_info.target_pci, reconfig->sec_cnfg_ho.intra_lte.next_hop_chaining_count); - // store mobilityControlInfo - memcpy(&mob_reconf, reconfig, sizeof(LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT)); - pending_mob_reconf = true; + // store mobilityControlInfo + memcpy(&mob_reconf, reconfig, sizeof(LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT)); + pending_mob_reconf = true; - state = RRC_STATE_HO_PREPARE; + state = RRC_STATE_HO_PREPARE; + } } else { // Section 5.3.5.3 @@ -2741,16 +2746,14 @@ void rrc::rrc_meas::parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *cfg) void rrc::rrc_meas::update_phy() { phy->meas_reset(); - if (pcell_measurement.ms[RSRP] < s_measure_value || !s_measure_enabled) { - for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { - meas_t m = iter->second; - meas_obj_t o = objects[m.object_id]; - // Instruct PHY to look for neighbour cells on this frequency - phy->meas_start(o.earfcn); - for(std::map::iterator iter=o.cells.begin(); iter!=o.cells.end(); ++iter) { - // Instruct PHY to look for cells IDs on this frequency - phy->meas_start(o.earfcn, iter->second.pci); - } + for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { + meas_t m = iter->second; + meas_obj_t o = objects[m.object_id]; + // Instruct PHY to look for neighbour cells on this frequency + phy->meas_start(o.earfcn); + for(std::map::iterator iter=o.cells.begin(); iter!=o.cells.end(); ++iter) { + // Instruct PHY to look for cells IDs on this frequency + phy->meas_start(o.earfcn, iter->second.pci); } } } From f3ee6c0009e91e07f81aef91c35765ba3b7d63a3 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Wed, 13 Dec 2017 10:18:52 +0100 Subject: [PATCH 35/42] Minor logging changes --- srsue/src/upper/rrc.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 8a03e21a6..2ea1b877d 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -675,7 +675,7 @@ void rrc::cell_reselection_eval(float rsrp, float rsrq) { // Intra-frequency cell-reselection criteria - if (get_srxlev(rsrp) > cell_resel_cfg.s_intrasearchP && rsrp > -70.0) { + if (get_srxlev(rsrp) > cell_resel_cfg.s_intrasearchP && rsrp > -95.0) { // UE may not perform intra-frequency measurements. phy->meas_reset(); // keep measuring serving cell @@ -1033,9 +1033,13 @@ bool rrc::ho_prepare() { } if (mob_reconf.mob_ctrl_info.rach_cnfg_ded_present) { + rrc_log->info("Starting non-contention based RA with preamble_idx=%d, mask_idx=%d\n", + mob_reconf.mob_ctrl_info.rach_cnfg_ded.preamble_index, + mob_reconf.mob_ctrl_info.rach_cnfg_ded.prach_mask_index); mac->start_noncont_ho(mob_reconf.mob_ctrl_info.rach_cnfg_ded.preamble_index, mob_reconf.mob_ctrl_info.rach_cnfg_ded.prach_mask_index); } else { + rrc_log->info("Starting contention-based RA\n"); mac->start_cont_ho(); } @@ -1049,7 +1053,7 @@ bool rrc::ho_prepare() { if (mob_reconf.sec_cnfg_ho.intra_lte.sec_alg_cnfg_present) { cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) mob_reconf.sec_cnfg_ho.intra_lte.sec_alg_cnfg.cipher_alg; integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) mob_reconf.sec_cnfg_ho.intra_lte.sec_alg_cnfg.int_alg; - rrc_log->console("Warning changed Cipering to %s and Integrity to %s\n", + rrc_log->info("Changed Ciphering to %s and Integrity to %s\n", ciphering_algorithm_id_text[cipher_algo], integrity_algorithm_id_text[integ_algo]); } @@ -2237,13 +2241,13 @@ void rrc::rrc_meas::init(rrc *parent) { void rrc::rrc_meas::reset() { - bzero(&pcell_measurement, sizeof(meas_value_t)); filter_k_rsrp = liblte_rrc_filter_coefficient_num[LIBLTE_RRC_FILTER_COEFFICIENT_FC4]; filter_k_rsrq = liblte_rrc_filter_coefficient_num[LIBLTE_RRC_FILTER_COEFFICIENT_FC4]; objects.clear(); active.clear(); reports_cfg.clear(); phy->meas_reset(); + bzero(&pcell_measurement, sizeof(meas_value_t)); } /* L3 filtering 5.5.3.2 */ From 09dc96a3700f667c97a7a7d538f19515f9de07f5 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Wed, 13 Dec 2017 10:20:19 +0100 Subject: [PATCH 36/42] Changed neighbour cell to find PSS over multiple frames --- srsue/src/phy/phch_recv.cc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 9225c6f73..9b728cddd 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -155,7 +155,6 @@ void phch_recv::radio_error() } void phch_recv::set_cfo(float cfo) { - Debug("set_ref_cfo=%f\n",cfo*15000); srslte_ue_sync_set_cfo_ref(&ue_sync, cfo); } @@ -645,9 +644,6 @@ void phch_recv::run_thread() worker->set_cfo(ul_dl_factor * metrics.cfo / 15000); worker_com->set_sync_metrics(metrics); - Debug("current_cfo=%f, pss_stable_cnt=%d, cfo_pss=%f Hz\n", - metrics.cfo, ue_sync.pss_stable_cnt, srslte_sync_get_cfo(&ue_sync.strack)*15000); - worker->set_sample_offset(srslte_ue_sync_get_sfo(&ue_sync)/1000); /* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */ @@ -1193,7 +1189,8 @@ void phch_recv::scell_recv::init(srslte::log *log_h, bool sic_pss_enabled) measure_p.init(sf_buffer, log_h, 1, DEFAULT_MEASUREMENT_LEN); - if(srslte_sync_init(&sync_find, 15*max_sf_size, 5*max_sf_size, max_fft_sz)) { + //do this different we don't need all this search window. + if(srslte_sync_init(&sync_find, 50*max_sf_size, 5*max_sf_size, max_fft_sz)) { fprintf(stderr, "Error initiating sync_find\n"); return; } @@ -1211,6 +1208,10 @@ void phch_recv::scell_recv::init(srslte::log *log_h, bool sic_pss_enabled) sync_find.pss.chest_on_filter = true; + if (!sic_pss_enabled) { + sync_find.sss_channel_equalize = false; + } + reset(); } @@ -1255,7 +1256,10 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, srslte_sync_reset(&sync_find); srslte_sync_cfo_reset(&sync_find); - sync_res = srslte_sync_find(&sync_find, input_buffer, 0, &peak_idx); + int sf5_cnt=0; + do { + sync_res = srslte_sync_find(&sync_find, input_buffer, sf5_cnt*5*sf_len, &peak_idx); + } while(sync_res != SRSLTE_SYNC_FOUND && sf5_cnt < nof_sf/5); switch(sync_res) { case SRSLTE_SYNC_ERROR: From dff5a6f628a46ce3df2b2be35235413320061c75 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Wed, 13 Dec 2017 18:26:26 +0100 Subject: [PATCH 37/42] Initialize variables in rrc/enb. Fixes #122 --- srsenb/hdr/upper/rrc.h | 2 +- srsenb/src/upper/rrc.cc | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/srsenb/hdr/upper/rrc.h b/srsenb/hdr/upper/rrc.h index e0b9dd158..f30b91794 100644 --- a/srsenb/hdr/upper/rrc.h +++ b/srsenb/hdr/upper/rrc.h @@ -264,7 +264,7 @@ public: uint32_t cqi_idx; bool cqi_allocated; int cqi_sched_sf_idx; - bool cqi_sched_prb_idx; + int cqi_sched_prb_idx; int get_drbid_config(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb, int drbid); }; diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index e176e8ac5..9c0422357 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -699,10 +699,19 @@ rrc::ue::ue() { parent = NULL; set_activity(); - sr_allocated = false; has_tmsi = false; connect_notified = false; transaction_id = 0; + sr_allocated = false; + sr_sched_sf_idx = 0; + sr_sched_prb_idx = 0; + sr_N_pucch = 0; + sr_I = 0; + cqi_allocated = false; + cqi_pucch = 0; + cqi_idx = 0; + cqi_sched_sf_idx = 0; + cqi_sched_prb_idx = 0; state = RRC_STATE_IDLE; } From 7e29430c81436763eabc876c01546cf7d53ef0d1 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Thu, 14 Dec 2017 11:15:26 +0100 Subject: [PATCH 38/42] remove unused function --- srsue/hdr/phy/phch_worker.h | 4 +--- srsue/src/phy/phch_recv.cc | 2 +- srsue/src/phy/phch_worker.cc | 4 ---- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index 5378a9428..f711ade09 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -67,9 +67,7 @@ public: int read_pdsch_d(cf_t *pdsch_d); void start_plot(); - float get_ref_cfo(); - -private: +private: /* Inherited from thread_pool::worker. Function called every subframe to run the DL/UL processing */ void work_imp(); diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 9b728cddd..473011d7b 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -1256,7 +1256,7 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, srslte_sync_reset(&sync_find); srslte_sync_cfo_reset(&sync_find); - int sf5_cnt=0; + uint32_t sf5_cnt=0; do { sync_res = srslte_sync_find(&sync_find, input_buffer, sf5_cnt*5*sf_len, &peak_idx); } while(sync_res != SRSLTE_SYNC_FOUND && sf5_cnt < nof_sf/5); diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index a5ccc9982..934be8aa7 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -141,10 +141,6 @@ bool phch_worker::init(uint32_t max_prb, srslte::log *log_h, chest_feedback_itf return true; } -float phch_worker::get_ref_cfo() { - return srslte_chest_dl_get_cfo(&ue_dl.chest); -} - bool phch_worker::set_cell(srslte_cell_t cell_) { if (cell.id != cell_.id || !cell_initiated) { From 39f9f15232aaa13d1a0748c05d9d5553e0bf9a0a Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Thu, 14 Dec 2017 12:34:57 +0100 Subject: [PATCH 39/42] Fixed bug with 2 rx antennas --- lib/src/phy/rf/rf_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/phy/rf/rf_utils.c b/lib/src/phy/rf/rf_utils.c index 68857d41d..892ad817e 100644 --- a/lib/src/phy/rf/rf_utils.c +++ b/lib/src/phy/rf/rf_utils.c @@ -122,7 +122,7 @@ int rf_mib_decoder(srslte_rf_t *rf, uint32_t nof_rx_antennas,cell_search_cfg_t * srslte_rf_set_rx_srate(rf, (float) srate); INFO("Starting receiver...\n", 0); - srslte_rf_start_rx_stream(rf, true); + srslte_rf_start_rx_stream(rf, false); /* Find and decody MIB */ ret = srslte_ue_mib_sync_decode(&ue_mib, config->max_frames_pbch, bch_payload, &cell->nof_ports, NULL); From 95f6eb87c8d197a123503b4a7eb473290d1167ad Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Thu, 14 Dec 2017 12:57:10 +0100 Subject: [PATCH 40/42] Minor issue with paging --- srsue/src/mac/mac.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc index 8813032f5..86b644b8d 100644 --- a/srsue/src/mac/mac.cc +++ b/srsue/src/mac/mac.cc @@ -278,6 +278,7 @@ void mac::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy:: memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); action->generate_ack = false; action->decode_enabled[0] = true; + action->decode_enabled[1] = false; srslte_softbuffer_rx_reset_cb(&pch_softbuffer, 1); action->payload_ptr[0] = pch_payload_buffer; action->softbuffers[0] = &pch_softbuffer; From 60b81f47f1cb941cbde08b47930538d33d662d19 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Thu, 14 Dec 2017 12:57:44 +0100 Subject: [PATCH 41/42] Do chest on filter only when sic_pss is enabled. Do not equalize SSS by default (something is not ok and takes more time to decode it) --- lib/src/phy/ue/ue_sync.c | 2 +- srsue/src/phy/phch_recv.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index 7eb877b3b..511cdde2f 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -272,7 +272,7 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, srslte_sync_set_cfo_cp_enable(&q->sfind, true); srslte_sync_set_cfo_pss_enable(&q->sfind, true); srslte_sync_set_pss_filt_enable(&q->sfind, true); - srslte_sync_set_sss_eq_enable(&q->sfind, true); + srslte_sync_set_sss_eq_enable(&q->sfind, false); // During track, we do CFO correction outside the sync object srslte_sync_set_cfo_i_enable(&q->strack, false); diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 473011d7b..06ae1baa2 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -196,7 +196,7 @@ void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) worker_com->args->cfo_loop_pss_tol, worker_com->args->cfo_loop_pss_conv); - q->strack.pss.chest_on_filter = true; + q->strack.pss.chest_on_filter = worker_com->args->sic_pss_enabled; int time_correct_period = worker_com->args->time_correct_period; if (time_correct_period > 0) { From abbbae9e81fdb937b7fe7e8778579baed986fc6d Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 14 Dec 2017 17:36:58 +0100 Subject: [PATCH 42/42] rf_uhd_imp tx forces zeros if null pointer buffer --- lib/src/phy/rf/rf_uhd_imp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/phy/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c index c39bb2604..75482eaa1 100644 --- a/lib/src/phy/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -790,7 +790,7 @@ int rf_uhd_send_timed_multi(void *h, int n = 0; cf_t *data_c[4]; for (int i = 0; i < 4; i++) { - data_c[i] = data[i]; + data_c[i] = data[i] ? data[i] : zero_mem; } do { size_t tx_samples = handler->tx_nof_samples;