Improved neighbour cell accuracy. Changed RRC to avoid segfault when neighbour cell addition

This commit is contained in:
Ismael Gomez 2018-02-02 19:31:22 +01:00
parent be62b8a179
commit a279ab47f0
13 changed files with 518 additions and 331 deletions

View File

@ -161,7 +161,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;
virtual void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn = -1, int pci = -1) = 0;
};
// RRC interface for NAS

View File

@ -5,9 +5,11 @@
#include "srslte/config.h"
#include <pthread.h>
#include <stdint.h>
#include <stdbool.h>
typedef struct {
uint8_t *buffer;
bool active;
int capacity;
int count;
int wpm;
@ -34,6 +36,7 @@ SRSLTE_API int srslte_ringbuffer_read(srslte_ringbuffer_t *q,
void *ptr,
int nof_bytes);
SRSLTE_API void srslte_ringbuffer_stop(srslte_ringbuffer_t *q);
#endif

View File

@ -293,9 +293,10 @@ uint32_t srslte_pdcch_common_locations_ncce(uint32_t nof_cce, srslte_dci_locatio
for (l = 3; l > 1; l--) {
L = (1 << l);
for (i = 0; i < SRSLTE_MIN(nof_cce, 16) / (L); i++) {
if (k < max_candidates) {
c[k].L = l;
c[k].ncce = (L) * (i % (nof_cce / (L)));
uint32_t ncce = (L) * (i % (nof_cce / (L)));
if (k < max_candidates && ncce + L <= nof_cce) {
c[k].L = l;
c[k].ncce = ncce;
DEBUG("Common SS Candidate %d: nCCE: %d, L: %d\n",
k, c[k].ncce, c[k].L);
k++;

View File

@ -71,7 +71,7 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o
q->N_id_1 = 1000;
q->cfo_ema_alpha = CFO_EMA_ALPHA;
q->sss_alg = SSS_FULL;
q->sss_alg = SSS_PARTIAL_3;
q->detect_cp = true;
q->sss_en = true;

View File

@ -11,7 +11,7 @@ int srslte_ringbuffer_init(srslte_ringbuffer_t *q, int capacity)
if (!q->buffer) {
return -1;
}
q->active = true;
q->capacity = capacity;
srslte_ringbuffer_reset(q);
@ -24,6 +24,7 @@ int srslte_ringbuffer_init(srslte_ringbuffer_t *q, int capacity)
void srslte_ringbuffer_free(srslte_ringbuffer_t *q)
{
if (q) {
srslte_ringbuffer_stop(q);
if (q->buffer) {
free(q->buffer);
q->buffer = NULL;
@ -52,6 +53,9 @@ 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->active) {
return 0;
}
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);
@ -77,9 +81,12 @@ 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) {
while(q->count < nof_bytes && q->active) {
pthread_cond_wait(&q->cvar, &q->mutex);
}
if (!q->active) {
return 0;
}
if (nof_bytes + q->rpm > q->capacity) {
int x = q->capacity - q->rpm;
memcpy(ptr, &q->buffer[q->rpm], x);
@ -96,5 +103,9 @@ int srslte_ringbuffer_read(srslte_ringbuffer_t *q, void *p, int nof_bytes)
return nof_bytes;
}
void srslte_ringbuffer_stop(srslte_ringbuffer_t *q) {
pthread_mutex_lock(&q->mutex);
pthread_cond_broadcast(&q->cvar);
pthread_mutex_unlock(&q->mutex);
}

View File

@ -113,7 +113,7 @@ private:
void run_thread();
static const int MAC_MAIN_THREAD_PRIO = -1; // Use default high-priority below UHD
static const int MAC_PDU_THREAD_PRIO = -1;
static const int MAC_PDU_THREAD_PRIO = DEFAULT_PRIORITY-5;
static const int MAC_NOF_HARQ_PROC = 2*HARQ_DELAY_MS;
// Interaction with PHY

View File

@ -166,7 +166,7 @@ private:
typedef enum {IDLE, MEASURE_OK, ERROR} ret_code;
~measure();
void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h,
void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, srslte::radio *radio_h,
uint32_t nof_rx_antennas, uint32_t nof_subframes = RSRP_MEASURE_NOF_FRAMES);
void reset();
void set_cell(srslte_cell_t cell);
@ -182,11 +182,12 @@ private:
srslte::log *log_h;
srslte_ue_dl_t ue_dl;
cf_t *buffer[SRSLTE_MAX_PORTS];
srslte::radio *radio_h;
uint32_t cnt;
uint32_t nof_subframes;
uint32_t current_prb;
float rx_gain_offset;
float mean_rsrp, mean_rsrq, mean_snr;
float mean_rsrp, mean_rsrq, mean_snr, mean_rssi;
uint32_t final_offset;
const static int RSRP_MEASURE_NOF_FRAMES = 5;
};
@ -201,13 +202,11 @@ private:
float rsrq;
uint32_t offset;
} cell_info_t;
void init(srslte::log *log_h, bool sic_pss_enabled);
void init(srslte::log *log_h, bool sic_pss_enabled, uint32_t max_sf_window);
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:
const static int DEFAULT_MEASUREMENT_LEN = 10;
cf_t *input_cfo_corrected;
cf_t *sf_buffer[SRSLTE_MAX_PORTS];
srslte::log *log_h;
@ -235,8 +234,10 @@ private:
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_LEN_MS = 20;
const static int INTRA_FREQ_MEAS_PERIOD_MS = 200;
const static int INTRA_FREQ_MEAS_PRIO = DEFAULT_PRIORITY + 5;
scell_recv scell;
rrc_interface_phy *rrc;
srslte::log *log_h;
@ -260,6 +261,8 @@ private:
srslte_ringbuffer_t ring_buffer;
};
// 36.133 9.1.2.1 for band 7
const static float ABSOLUTE_RSRP_THRESHOLD_DBM = -125;
// Objects for internal use

View File

@ -51,6 +51,58 @@ using srslte::byte_buffer_t;
namespace srsue {
class cell_t
{
public:
bool is_valid() {
return earfcn != 0 && srslte_cell_isvalid(&phy_cell);
}
bool equals(cell_t *x) {
return equals(x->earfcn, x->phy_cell.id);
}
bool equals(uint32_t earfcn, uint32_t pci) {
return earfcn == this->earfcn && pci == phy_cell.id;
}
bool greater(cell_t *x) {
return x->rsrp > rsrp;
}
bool plmn_equals(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {
for (uint32_t i = 0; i < sib1.N_plmn_ids; i++) {
if (plmn_id.mcc == sib1.plmn_id[i].id.mcc && plmn_id.mnc == sib1.plmn_id[i].id.mnc) {
return true;
}
}
return false;
}
cell_t() {
this->has_valid_sib1 = false;
this->has_valid_sib2 = false;
this->has_valid_sib3 = false;
}
cell_t(srslte_cell_t phy_cell, uint32_t earfcn, float rsrp) {
this->has_valid_sib1 = false;
this->has_valid_sib2 = false;
this->has_valid_sib3 = false;
this->phy_cell = phy_cell;
this->rsrp = rsrp;
this->earfcn = earfcn;
}
uint32_t earfcn;
srslte_cell_t phy_cell;
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_3_STRUCT sib3;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT sib13;
};
class rrc
:public rrc_interface_nas
,public rrc_interface_phy
@ -100,7 +152,7 @@ public:
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);
void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn, int pci);
// MAC interface
void ho_ra_completed(bool ra_successful);
@ -154,7 +206,7 @@ private:
bool first_stimsi_attempt;
uint16_t ho_src_rnti;
int ho_src_cell_idx;
cell_t ho_src_cell;
phy_interface_rrc::phy_cfg_t ho_src_phy_cfg;
mac_interface_rrc::mac_cfg_t ho_src_mac_cfg;
bool pending_mob_reconf;
@ -215,28 +267,18 @@ private:
}
}
typedef struct {
uint32_t earfcn;
srslte_cell_t phy_cell;
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_3_STRUCT sib3;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT sib13;
} cell_t;
// List of strongest neighbour cell
const static int NOF_NEIGHBOUR_CELLS = 8;
std::vector<cell_t*> neighbour_cells;
cell_t *serving_cell;
void set_serving_cell(uint32_t cell_idx);
void set_serving_cell(uint32_t earfcn, uint32_t pci);
const static int MAX_KNOWN_CELLS = 64;
cell_t known_cells[MAX_KNOWN_CELLS];
cell_t *current_cell;
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);
int find_neighbour_cell(uint32_t earfcn, uint32_t pci);
bool add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp);
bool add_neighbour_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp);
bool add_neighbour_cell(cell_t *cell);
void sort_neighbour_cells();
typedef enum {
SI_ACQUIRE_IDLE = 0,
@ -253,7 +295,6 @@ private:
void select_next_cell_in_plmn();
LIBLTE_RRC_PLMN_IDENTITY_STRUCT selected_plmn_id;
int last_selected_cell;
bool thread_running;
void run_thread();
@ -395,10 +436,10 @@ private:
// Helpers
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();
void radio_link_failure();
void leave_connected();
static void* start_sib_thread(void *rrc_);
void sib_search();

View File

@ -242,7 +242,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
"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<bool>(&args->expert.phy.sic_pss_enabled)->default_value(true),
bpo::value<bool>(&args->expert.phy.sic_pss_enabled)->default_value(false),
"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",

View File

@ -91,7 +91,7 @@ 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(sf_buffer, log_h, nof_rx_antennas);
measure_p.init(sf_buffer, log_h, radio_h, nof_rx_antennas);
// Start intra-frequency measurement
intra_freq_meas.init(worker_com, rrc, log_h);
@ -617,6 +617,7 @@ void phch_recv::run_thread()
log_h->info("Sync OK. Camping on cell PCI=%d...\n", cell.id);
phy_state = CELL_CAMP;
} else {
log_h->info("Sync OK. Measuring PCI=%d...\n", cell.id);
measure_p.reset();
phy_state = CELL_MEASURE;
}
@ -1037,8 +1038,10 @@ phch_recv::sfn_sync::ret_code phch_recv::sfn_sync::run_subframe(srslte_cell_t *c
/*********
* Measurement class
*/
void phch_recv::measure::init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, uint32_t nof_subframes)
void phch_recv::measure::init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, srslte::radio *radio_h, uint32_t nof_rx_antennas, uint32_t nof_subframes)
{
this->radio_h = radio_h;
this->log_h = log_h;
this->nof_subframes = nof_subframes;
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
@ -1061,6 +1064,7 @@ void phch_recv::measure::reset() {
mean_rsrp = 0;
mean_rsrq = 0;
mean_snr = 0;
mean_rssi = 0;
}
void phch_recv::measure::set_cell(srslte_cell_t cell)
@ -1121,7 +1125,7 @@ phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *in
sf_idx ++;
}
float max_rsrp = -99;
float max_rsrp = -200;
int best_test_offset = 0;
int test_offset = 0;
bool found_best = false;
@ -1182,16 +1186,18 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx)
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));
float rssi = 10*log10(srslte_vec_avg_power_cf(buffer[0], SRSLTE_SF_LEN_PRB(current_prb))) + 30;
if (cnt == 0) {
mean_rsrp = rsrp;
mean_rsrq = rsrq;
mean_snr = snr;
mean_rssi = rssi;
} else {
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_snr = SRSLTE_VEC_CMA(snr, mean_snr, cnt);
mean_rssi = SRSLTE_VEC_CMA(rssi, mean_rssi, cnt);
}
cnt++;
@ -1199,6 +1205,20 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx)
cnt, nof_subframes, sf_idx, rsrp, snr);
if (cnt >= nof_subframes) {
// Calibrate RSRP if no gain offset measurements
if (rx_gain_offset == 0 && radio_h) {
float temporal_offset = 0;
if (radio_h->has_rssi()) {
temporal_offset = mean_rssi - radio_h->get_rssi() + 30;
} else {
temporal_offset = radio_h->get_rx_gain();
}
mean_rsrp -= temporal_offset;
}
}
if (cnt > 2) {
return MEASURE_OK;
} else {
return IDLE;
@ -1214,7 +1234,7 @@ 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, bool sic_pss_enabled)
void phch_recv::scell_recv::init(srslte::log *log_h, bool sic_pss_enabled, uint32_t max_sf_window)
{
this->log_h = log_h;
this->sic_pss_enabled = sic_pss_enabled;
@ -1227,23 +1247,24 @@ void phch_recv::scell_recv::init(srslte::log *log_h, bool sic_pss_enabled)
sf_buffer[0] = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*max_sf_size);
input_cfo_corrected = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*15*max_sf_size);
measure_p.init(sf_buffer, log_h, 1, DEFAULT_MEASUREMENT_LEN);
measure_p.init(sf_buffer, log_h, NULL, 1, max_sf_window);
//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)) {
if(srslte_sync_init(&sync_find, max_sf_window*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_em_alpha(&sync_find, 0.0);
srslte_sync_set_cfo_pss_enable(&sync_find, true);
srslte_sync_set_threshold(&sync_find, 1.7);
srslte_sync_set_em_alpha(&sync_find, 0.3);
// Configure FIND object behaviour (this configuration is always the same)
srslte_sync_set_cfo_ema_alpha(&sync_find, 1.0);
srslte_sync_set_cfo_i_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_eq_enable(&sync_find, true);
srslte_sync_set_sss_eq_enable(&sync_find, false);
sync_find.pss.chest_on_filter = true;
@ -1280,39 +1301,55 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset,
srslte_cell_t found_cell;
memcpy(&found_cell, &cell, sizeof(srslte_cell_t));
found_cell.id = 10000;
measure_p.set_rx_gain_offset(rx_gain_offset);
for (uint32_t n_id_2=0;n_id_2<3;n_id_2++) {
found_cell.id = 10000;
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;
srslte_sync_find_ret_t sync_res, best_sync_res;
do {
srslte_sync_reset(&sync_find);
srslte_sync_cfo_reset(&sync_find);
int sf5_cnt=-1;
do {
sf5_cnt++;
sync_res = srslte_sync_find(&sync_find, input_buffer, sf5_cnt*5*sf_len, &peak_idx);
} while(sync_res != SRSLTE_SYNC_FOUND && (uint32_t) sf5_cnt + 1 < nof_sf/5);
best_sync_res = SRSLTE_SYNC_NOFOUND;
sync_res = SRSLTE_SYNC_NOFOUND;
cell_id = 0;
float max_peak = -1;
uint32_t max_sf5 = 0;
uint32_t max_sf_idx = 0;
switch(sync_res) {
for (uint32_t sf5_cnt=0;sf5_cnt<nof_sf/5;sf5_cnt++) {
sync_res = srslte_sync_find(&sync_find, input_buffer, sf5_cnt*5*sf_len, &peak_idx);
Info("INTRA: n_id_2=%d, cnt=%d/%d, sync_res=%d, sf_idx=%d, peak_idx=%d, peak_value=%f\n",
n_id_2, sf5_cnt, nof_sf/5, sync_res, srslte_sync_get_sf_idx(&sync_find), peak_idx, sync_find.peak_value);
if (sync_find.peak_value > max_peak && sync_res == SRSLTE_SYNC_FOUND) {
best_sync_res = sync_res;
max_sf5 = sf5_cnt;
max_sf_idx = srslte_sync_get_sf_idx(&sync_find);
cell_id = srslte_sync_get_cell_id(&sync_find);
}
}
switch(best_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);
sf_idx = (10-max_sf_idx - 5*(max_sf5%2))%10;
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) {
Info("n_id_2=%d, PCI=%d, found_cell.id=%d, cell.id=%d\n", n_id_2, cell_id, found_cell.id, cell.id);
sync_res = SRSLTE_SYNC_NOFOUND;
} else {
// We found a new cell ID
@ -1321,34 +1358,42 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset,
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+sf5_cnt*5*sf_len, sf_idx, nof_sf)) {
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();
// Consider a cell to be detectable 8.1.2.2.1.1 from 36.133. Currently only using first condition
if (measure_p.rsrp() > ABSOLUTE_RSRP_THRESHOLD_DBM) {
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, sf5_cnt=%d, 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, sf5_cnt, n_id_2, 15000*srslte_sync_get_cfo(&sync_find));
Info(
"INTRA: Found neighbour cell %d: PCI=%03d, RSRP=%5.1f dBm, peak_idx=%5d, peak_value=%3.2f, sf=%d, max_sf=%d, 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,
sf_idx, max_sf5, n_id_2, 15000 * srslte_sync_get_cfo(&sync_find));
nof_cells++;
nof_cells++;
if (sic_pss_enabled) {
srslte_pss_sic(&sync_find.pss, &input_buffer[sf5_cnt*5*sf_len+sf_len/2-fft_sz]);
/*
if (sic_pss_enabled) {
srslte_pss_sic(&sync_find.pss, &input_buffer[sf5_cnt * 5 * sf_len + sf_len / 2 - fft_sz]);
}*/
}
break;
default:
Info("INTRA: Not enough samples to measure PCI=%d\n", cell_id);
break;
case measure::ERROR:
Error("Measuring neighbour cell\n");
return SRSLTE_ERROR;
default:
break;
}
}
} else {
@ -1414,20 +1459,21 @@ void phch_recv::intra_measure::init(phch_common *common, rrc_interface_phy *rrc,
receive_enabled = false;
// Start scell
scell.init(log_h, common->args->sic_pss_enabled);
scell.init(log_h, common->args->sic_pss_enabled, INTRA_FREQ_MEAS_LEN_MS);
search_buffer = (cf_t*) srslte_vec_malloc(CAPTURE_LEN_SF*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB)*sizeof(cf_t));
search_buffer = (cf_t*) srslte_vec_malloc(INTRA_FREQ_MEAS_LEN_MS*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB)*sizeof(cf_t));
if (srslte_ringbuffer_init(&ring_buffer, sizeof(cf_t)*100*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB))) {
if (srslte_ringbuffer_init(&ring_buffer, sizeof(cf_t)*INTRA_FREQ_MEAS_LEN_MS*2*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB))) {
return;
}
running = true;
start();
start(INTRA_FREQ_MEAS_PRIO);
}
void phch_recv::intra_measure::stop() {
running = false;
srslte_ringbuffer_stop(&ring_buffer);
tti_sync.increase();
wait_thread_finish();
}
@ -1493,7 +1539,7 @@ void phch_recv::intra_measure::write(uint32_t tti, cf_t *data, uint32_t nsamples
receiving = false;
} else {
receive_cnt++;
if (receive_cnt == CAPTURE_LEN_SF) {
if (receive_cnt == INTRA_FREQ_MEAS_LEN_MS) {
tti_sync.increase();
receiving = false;
}
@ -1510,9 +1556,9 @@ void phch_recv::intra_measure::run_thread()
}
if (running) {
// 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);
// Read data from buffer and find cells in it
srslte_ringbuffer_read(&ring_buffer, search_buffer, INTRA_FREQ_MEAS_LEN_MS*current_sflen*sizeof(cf_t));
int found_cells = scell.find_cells(search_buffer, common->rx_gain_offset, primary_cell, INTRA_FREQ_MEAS_LEN_MS, info);
receiving = false;
for (int i=0;i<found_cells;i++) {

View File

@ -52,6 +52,7 @@ rrc::rrc()
{
n310_cnt = 0;
n311_cnt = 0;
serving_cell = new cell_t();
}
static void liblte_rrc_handler(void *ctx, char *str) {
@ -89,8 +90,6 @@ 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();
@ -210,13 +209,13 @@ void rrc::run_thread() {
* Cell is selected when all SIBs downloaded or applied.
*/
if (phy->sync_status()) {
if (!current_cell->has_valid_sib1) {
if (!serving_cell->has_valid_sib1) {
si_acquire_state = SI_ACQUIRE_SIB1;
sysinfo_index = 0;
} else if (!current_cell->has_valid_sib2) {
} else if (!serving_cell->has_valid_sib2) {
si_acquire_state = SI_ACQUIRE_SIB2;
} else {
apply_sib2_configs(&current_cell->sib2);
apply_sib2_configs(&serving_cell->sib2);
si_acquire_state = SI_ACQUIRE_IDLE;
state = RRC_STATE_CELL_SELECTED;
}
@ -228,6 +227,7 @@ void rrc::run_thread() {
rrc_log->info("RRC Cell Selecting: timeout expired. Starting Cell Search...\n");
plmn_select_timeout = 0;
select_cell_timeout = 0;
serving_cell->in_sync = false;
phy->cell_search_start();
}
}
@ -254,7 +254,7 @@ void rrc::run_thread() {
} else {
rrc_log->info("RRC Cell Selected: Starting paging and going to IDLE...\n");
mac->pcch_start_rx();
state = RRC_STATE_IDLE;
state = RRC_STATE_LEAVE_CONNECTED;
}
break;
case RRC_STATE_CONNECTING:
@ -287,25 +287,7 @@ 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;
measurements.reset();
pdcp->reset();
rlc->reset();
phy->reset();
mac->reset();
set_phy_default();
set_mac_default();
mac_timers->timer_get(t310)->stop();
mac_timers->timer_get(t311)->stop();
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());
}
leave_connected();
// Move to RRC_IDLE
state = RRC_STATE_IDLE;
break;
@ -370,19 +352,19 @@ void rrc::run_si_acquisition_procedure()
break;
case SI_ACQUIRE_SIB2:
// 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];
if(sysinfo_index < serving_cell->sib1.N_sched_info) {
si_win_len = liblte_rrc_si_window_length_num[serving_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];
period = liblte_rrc_si_periodicity_num[serving_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];
si_win_len = liblte_rrc_si_window_length_num[serving_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",
@ -421,19 +403,15 @@ void rrc::run_si_acquisition_procedure()
*******************************************************************************/
uint16_t rrc::get_mcc() {
if (current_cell) {
if (current_cell->sib1.N_plmn_ids > 0) {
return current_cell->sib1.plmn_id[0].id.mcc;
}
if (serving_cell->sib1.N_plmn_ids > 0) {
return serving_cell->sib1.plmn_id[0].id.mcc;
}
return 0;
}
uint16_t rrc::get_mnc() {
if (current_cell) {
if (current_cell->sib1.N_plmn_ids > 0) {
return current_cell->sib1.plmn_id[0].id.mnc;
}
if (serving_cell->sib1.N_plmn_ids > 0) {
return serving_cell->sib1.plmn_id[0].id.mnc;
}
return 0;
}
@ -468,188 +446,265 @@ void rrc::plmn_select_rrc(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {
// Sort cells according to RSRP
selected_plmn_id = plmn_id;
last_selected_cell = -1;
select_cell_timeout = 0;
state = RRC_STATE_CELL_SELECTING;
select_next_cell_in_plmn();
}
} else {
rrc_log->warning("Requested PLMN select in incorrect state %s\n", rrc_state_text[state]);
}
}
void rrc::select_next_cell_in_plmn() {
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) {
rrc_log->info("Selecting cell PCI=%d, EARFCN=%d, Cell ID=0x%x\n",
known_cells[i].phy_cell.id, known_cells[i].earfcn,
known_cells[i].sib1.cell_id);
rrc_log->console("Select cell: PCI=%d, EARFCN=%d, Cell ID=0x%x\n",
known_cells[i].phy_cell.id, known_cells[i].earfcn,
known_cells[i].sib1.cell_id);
// Check that cell satisfies S criteria
if (known_cells[i].in_sync) { // %% rsrp > S dbm
// Try to select Cell
if (phy->cell_select(known_cells[i].earfcn, known_cells[i].phy_cell))
{
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",
known_cells[i].earfcn, known_cells[i].sib1.cell_id);
}
}
void rrc::set_serving_cell(uint32_t earfcn, uint32_t pci) {
int cell_idx = find_neighbour_cell(earfcn, pci);
if (cell_idx >= 0) {
set_serving_cell(cell_idx);
} else {
rrc_log->error("Setting serving cell: Unkonwn cell with earfcn=%d, PCI=%d\n", earfcn, pci);
}
}
void rrc::set_serving_cell(uint32_t cell_idx) {
if (cell_idx < neighbour_cells.size())
{
// Remove future serving cell from neighbours to make space for current serving cell
cell_t *new_serving_cell = neighbour_cells[cell_idx];
if (!new_serving_cell) {
rrc_log->error("Setting serving cell. Index %d is empty\n", cell_idx);
return;
}
neighbour_cells.erase(std::remove(neighbour_cells.begin(), neighbour_cells.end(), neighbour_cells[cell_idx]), neighbour_cells.end());
// Move serving cell to neighbours list
if (serving_cell->is_valid()) {
// Make sure it does not exist already
int serving_idx = find_neighbour_cell(serving_cell->earfcn, serving_cell->phy_cell.id);
if (serving_idx >= 0 && (uint32_t) serving_idx < neighbour_cells.size()) {
printf("Error serving cell is already in the neighbour list. Removing it\n");
neighbour_cells.erase(std::remove(neighbour_cells.begin(), neighbour_cells.end(), neighbour_cells[serving_idx]), neighbour_cells.end());
}
// If not in the list, add it to the list of neighbours (sorted inside the function)
if (!add_neighbour_cell(serving_cell)) {
rrc_log->info("Serving cell not added to list of neighbours. Worse than current neighbours\n");
}
}
// Set new serving cell
serving_cell = new_serving_cell;
printf("Setting new serving cell idx=%d, PCI=%d, nof_neighbours=%d\n",
cell_idx, serving_cell->phy_cell.id, neighbour_cells.size());
rrc_log->info("Setting serving cell idx=%d, earfcn=%d, PCI=%d, nof_neighbours=%d\n",
cell_idx, serving_cell->earfcn, serving_cell->phy_cell.id, neighbour_cells.size());
} else {
rrc_log->error("Setting invalid serving cell idx %d\n", cell_idx);
}
}
void rrc::select_next_cell_in_plmn() {
// Neighbour cells are sorted in descending order of RSRP
for (uint32_t i = 0; i < neighbour_cells.size(); i++) {
if (neighbour_cells[i]->plmn_equals(selected_plmn_id) &&
neighbour_cells[i]->in_sync) // matches S criteria
{
// Try to select Cell
if (phy->cell_select(neighbour_cells[i]->earfcn, neighbour_cells[i]->phy_cell)) {
set_serving_cell(i);
rrc_log->info("Selected cell PCI=%d, EARFCN=%d, Cell ID=0x%x\n",
serving_cell->phy_cell.id, serving_cell->earfcn,
serving_cell->sib1.cell_id);
rrc_log->console("Selected cell PCI=%d, EARFCN=%d, Cell ID=0x%x\n",
serving_cell->phy_cell.id, serving_cell->earfcn,
serving_cell->sib1.cell_id);
} else {
// Set to out-of-sync if can't synchronize
neighbour_cells[i]->in_sync = false;
rrc_log->warning("Selecting cell EARFCN=%d, Cell ID=0x%x.\n",
neighbour_cells[i]->earfcn, neighbour_cells[i]->sib1.cell_id);
}
return;
}
}
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) {
void rrc::new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn_i, int pci_i) {
if (earfcn_i < 0 || pci_i < 0) {
earfcn_i = serving_cell->earfcn;
pci_i = serving_cell->phy_cell.id;
}
uint32_t earfcn = (uint32_t) earfcn_i;
uint32_t pci = (uint32_t) pci_i;
// Measurements in RRC_CONNECTED go through measuremnt class to log reports etc.
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
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);
// Measurements in RRC_IDLE update serving cell and check for reselection
} else {
// Update serving cell
if (serving_cell->equals(earfcn, pci)) {
cell_reselection_eval(rsrp, rsrq);
serving_cell->rsrp = rsrp;
rrc_log->info("MEAS: New measurement serving cell in IDLE, rsrp=%f, rsrq=%f, tti=%d\n", rsrp, rsrq, tti);
// Or update/add neighbour cell
} else {
if (add_neighbour_cell(earfcn, pci, rsrp)) {
rrc_log->info("MEAS: New measurement neighbour in IDLE, PCI=%d, RSRP=%.1f dBm.\n", pci, rsrp);
} else {
rrc_log->info("MEAS: Neighbour Cell in IDLE PCI=%d, RSRP=%.1f dBm not added. Worse than current neighbours\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())
// Verify cell selection criteria with strongest neighbour cell (always first)
if (cell_selection_eval(neighbour_cells[0]->rsrp) &&
neighbour_cells[0]->rsrp > serving_cell->rsrp + 5)
{
rrc_log->info("Selecting best neighbour cell PCI=%d, rsrp=%.1f dBm\n", best_cell.id, known_cells[best_cell_idx].rsrp);
set_serving_cell(0);
rrc_log->info("Selecting best neighbour cell PCI=%d, rsrp=%.1f dBm\n", serving_cell->phy_cell.id, serving_cell->rsrp);
state = RRC_STATE_CELL_SELECTING;
current_cell = &known_cells[best_cell_idx];
phy->cell_select(phy->get_current_earfcn(), best_cell);
phy->cell_select(serving_cell->earfcn, serving_cell->phy_cell);
}
}
}
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 < 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;
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);
bool found = false;
int cell_idx = -1;
if (!current_cell->has_valid_sib1) {
si_acquire_state = SI_ACQUIRE_SIB1;
} else if (state == RRC_STATE_PLMN_SELECTION) {
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();
}
return;
if (serving_cell->equals(earfcn, phy_cell.id)) {
serving_cell->rsrp = rsrp;
serving_cell->in_sync = true;
found = true;
} else {
// Check if cell is in our list of neighbour cells
cell_idx = find_neighbour_cell(earfcn, phy_cell.id);
if (cell_idx >= 0) {
set_serving_cell(cell_idx);
serving_cell->rsrp = rsrp;
serving_cell->in_sync = true;
found = true;
}
}
// 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;
}
if (found) {
rrc_log->info("Updating %s cell EARFCN=%d, PCI=%d, RSRP=%.1f dBm\n",
cell_idx>=0?"neighbour":"serving",
serving_cell->earfcn,
serving_cell->phy_cell.id,
serving_cell->rsrp);
si_acquire_state = SI_ACQUIRE_SIB1;
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);
}
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<MAX_KNOWN_CELLS;i++) {
if (known_cells[i].earfcn == earfcn) {
if (known_cells[i].rsrp > best_rsrp) {
best_rsrp = known_cells[i].rsrp;
best_cell_idx = i;
if (!serving_cell->has_valid_sib1) {
si_acquire_state = SI_ACQUIRE_SIB1;
} else if (state == RRC_STATE_PLMN_SELECTION) {
for (uint32_t j = 0; j < serving_cell->sib1.N_plmn_ids; j++) {
nas->plmn_found(serving_cell->sib1.plmn_id[j].id, serving_cell->sib1.tracking_area_code);
}
usleep(5000);
phy->cell_search_next();
}
} else {
// add to list of known cells and set current_cell
if (!add_neighbour_cell(earfcn, phy_cell, rsrp)) {
rrc_log->info("No more space for neighbour cells (detected cell RSRP=%.1f dBm worse than current %d neighbours)\n",
rsrp, NOF_NEIGHBOUR_CELLS);
usleep(5000);
phy->cell_search_next();
} else {
set_serving_cell(earfcn, phy_cell.id);
si_acquire_state = SI_ACQUIRE_SIB1;
rrc_log->info("New Cell: PCI=%d, PRB=%d, Ports=%d, EARFCN=%d, RSRP=%.1f dBm\n",
serving_cell->phy_cell.id, serving_cell->phy_cell.nof_prb, serving_cell->phy_cell.nof_ports,
serving_cell->earfcn, serving_cell->rsrp);
}
}
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) {
bool sort_rsrp(cell_t *u1, cell_t *u2) {
return !u1->greater(u2);
}
// Sort neighbour cells by decreasing order of RSRP
void rrc::sort_neighbour_cells() {
for (uint32_t i=1;i<neighbour_cells.size();i++) {
if (neighbour_cells[i]->in_sync == false) {
rrc_log->info("Removing neighbour cell PCI=%d, out_of_sync\n", neighbour_cells[i]->phy_cell.id);
neighbour_cells.erase(std::remove(neighbour_cells.begin(), neighbour_cells.end(), neighbour_cells[i]), neighbour_cells.end());
}
}
std::sort(neighbour_cells.begin(), neighbour_cells.end(), sort_rsrp);
char ordered[512];
int n=0;
n += snprintf(ordered, 512, "[pci=%d, rsrsp=%.2f", neighbour_cells[0]->phy_cell.id, neighbour_cells[0]->rsrp);
for (uint32_t i=1;i<neighbour_cells.size();i++) {
n += snprintf(&ordered[n], 512-n, " | pci=%d, rsrp=%.2f", neighbour_cells[i]->phy_cell.id, neighbour_cells[i]->rsrp);
}
rrc_log->info("Sorted neighbour cells: %s]\n", ordered);
}
bool rrc::add_neighbour_cell(cell_t *new_cell) {
bool ret = false;
if (neighbour_cells.size() < NOF_NEIGHBOUR_CELLS - 1) {
ret = true;
} else if (!neighbour_cells[neighbour_cells.size()-1]->greater(new_cell)) {
// Delete old one
delete neighbour_cells[neighbour_cells.size()-1];
neighbour_cells.erase(std::remove(neighbour_cells.begin(), neighbour_cells.end(), neighbour_cells[neighbour_cells.size()-1]), neighbour_cells.end());
ret = true;
}
if (ret) {
neighbour_cells.push_back(new_cell);
}
rrc_log->info("Added neighbour cell EARFCN=%d, PCI=%d, nof_neighbours=%d\n",
new_cell->earfcn, new_cell->phy_cell.id, neighbour_cells.size());
sort_neighbour_cells();
return ret;
}
// If only neighbour PCI is provided, copy full cell from serving cell
bool rrc::add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp) {
srslte_cell_t serving_phy;
serving_phy = serving_cell->phy_cell;
serving_phy.id = pci;
return add_neighbour_cell(earfcn, serving_phy, rsrp);
}
bool rrc::add_neighbour_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) {
if (earfcn == 0) {
return NULL;
}
int idx = find_cell_idx(earfcn, phy_cell.id);
if (idx >= 0) {
known_cells[idx].rsrp = rsrp;
return &known_cells[idx];
earfcn = serving_cell->earfcn;
}
// if does not exist, find empty slot
int i=0;
while(i<MAX_KNOWN_CELLS && known_cells[i].earfcn) {
i++;
}
if (i==MAX_KNOWN_CELLS) {
rrc_log->error("Can't add more cells\n");
return NULL;
// First check if already exists
int cell_idx = find_neighbour_cell(earfcn, phy_cell.id);
rrc_log->info("Adding PCI=%d, earfcn=%d, cell_idx=%d\n", phy_cell.id, earfcn, cell_idx);
// If exists, update RSRP, sort again and return
if (cell_idx >= 0) {
neighbour_cells[cell_idx]->rsrp = rsrp;
sort_neighbour_cells();
return true;
}
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];
// If not, create a new one
cell_t *new_cell = new cell_t(phy_cell, earfcn, rsrp);
return add_neighbour_cell(new_cell);
}
void rrc::add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp) {
int idx = find_cell_idx(earfcn, pci);
if (idx >= 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) {
int rrc::find_neighbour_cell(uint32_t earfcn, uint32_t pci) {
for (uint32_t i = 0; i < neighbour_cells.size(); i++) {
if (neighbour_cells[i]->equals(earfcn, pci)) {
return (int) i;
}
}
@ -720,24 +775,28 @@ float rrc::get_squal(float Qqualmeas) {
*
*******************************************************************************/
// Detection of physical layer problems (5.3.11.1)
// Detection of physical layer problems in RRC_CONNECTED (5.3.11.1)
void rrc::out_of_sync() {
current_cell->in_sync = false;
if (!mac_timers->timer_get(t311)->is_running() && !mac_timers->timer_get(t310)->is_running()) {
n310_cnt++;
if (n310_cnt == N310) {
mac_timers->timer_get(t310)->reset();
mac_timers->timer_get(t310)->run();
n310_cnt = 0;
phy->sync_reset();
rrc_log->info("Detected %d out-of-sync from PHY. Trying to resync. Starting T310 timer\n", N310);
serving_cell->in_sync = false;
if (state == RRC_STATE_CONNECTED) {
if (!mac_timers->timer_get(t311)->is_running() && !mac_timers->timer_get(t310)->is_running()) {
n310_cnt++;
if (n310_cnt == N310) {
mac_timers->timer_get(t310)->reset();
mac_timers->timer_get(t310)->run();
n310_cnt = 0;
phy->sync_reset();
rrc_log->info("Detected %d out-of-sync from PHY. Trying to resync. Starting T310 timer\n", N310);
}
}
} else {
phy->sync_reset();
}
}
// Recovery of physical layer problems (5.3.11.2)
void rrc::in_sync() {
current_cell->in_sync = true;
serving_cell->in_sync = true;
if (mac_timers->timer_get(t310)->is_running()) {
n311_cnt++;
if (n311_cnt == N311) {
@ -861,7 +920,7 @@ void rrc::send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause,
uint8_t *msg_ptr = varShortMAC;
// ASN.1 encode byte-aligned VarShortMAC-Input
liblte_rrc_pack_cell_identity_ie(current_cell->sib1.cell_id, &msg_ptr);
liblte_rrc_pack_cell_identity_ie(serving_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];
@ -869,7 +928,7 @@ void rrc::send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause,
srslte_bit_pack_vector(varShortMAC, varShortMAC_packed, (4+2+4)*8);
rrc_log->info("Generated varShortMAC: cellId=0x%x, PCI=%d, rnti=%d\n",
current_cell->sib1.cell_id, phy->get_current_pci(), crnti);
serving_cell->sib1.cell_id, phy->get_current_pci(), crnti);
// Compute MAC-I
uint8_t mac_key[4];
@ -997,9 +1056,9 @@ 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);
int target_cell_idx = find_neighbour_cell(serving_cell->earfcn, mob_reconf.mob_ctrl_info.target_pci);
if (target_cell_idx < 0) {
rrc_log->error("Could not find target cell earfcn=%d, pci=%d\n", serving_cell->earfcn, mob_reconf.mob_ctrl_info.target_pci);
return false;
}
@ -1007,16 +1066,12 @@ bool rrc::ho_prepare() {
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) {
mob_reconf.mob_ctrl_info.carrier_freq_eutra.dl_carrier_freq != serving_cell->earfcn) {
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;
}
// Save serving cell and current configuration
ho_src_cell = *serving_cell;
phy->get_config(&ho_src_phy_cfg);
mac->get_config(&ho_src_mac_cfg);
mac_interface_rrc::ue_rnti_t uernti;
@ -1033,9 +1088,9 @@ bool 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);
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);
rrc_log->info("Selecting new cell pci=%d\n", neighbour_cells[target_cell_idx]->phy_cell.id);
if (!phy->cell_handover(neighbour_cells[target_cell_idx]->phy_cell)) {
rrc_log->error("Could not synchronize with target cell pci=%d\n", neighbour_cells[target_cell_idx]->phy_cell.id);
return false;
}
@ -1110,8 +1165,8 @@ void rrc::ho_ra_completed(bool ra_successful) {
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);
if (!phy->cell_handover(ho_src_cell.phy_cell)) {
rrc_log->error("Could not synchronize with target cell pci=%d\n", ho_src_cell.phy_cell.id);
return;
}
@ -1165,14 +1220,37 @@ void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGU
}
}
/* Actions upon reception of RRCConnectionRelease 5.3.8.3 */
/* Actions upon reception of RRCConnectionRelease 5.3.8.3 */
void rrc::rrc_connection_release() {
// Save idleModeMobilityControlInfo, etc.
state = RRC_STATE_LEAVE_CONNECTED;
rrc_log->console("Received RRC Connection Release\n");
}
/* Actions upon leaving RRC_CONNECTED 5.3.12 */
void rrc::leave_connected()
{
rrc_log->console("RRC IDLE\n");
rrc_log->info("Leaving RRC_CONNECTED state\n");
drb_up = false;
measurements.reset();
pdcp->reset();
rlc->reset();
phy->reset();
mac->reset();
set_phy_default();
set_mac_default();
mac_timers->timer_get(t301)->stop();
mac_timers->timer_get(t310)->stop();
mac_timers->timer_get(t311)->stop();
mac_timers->timer_get(t304)->stop();
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());
}
}
@ -1213,24 +1291,24 @@ void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu) {
rrc_log->info("Processing SIB: %d\n", liblte_rrc_sys_info_block_type_num[dlsch_msg.sibs[i].sib_type]);
if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[i].sib_type && SI_ACQUIRE_SIB1 == si_acquire_state) {
memcpy(&current_cell->sib1, &dlsch_msg.sibs[i].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT));
current_cell->has_valid_sib1 = true;
memcpy(&serving_cell->sib1, &dlsch_msg.sibs[i].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT));
serving_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(&current_cell->sib2, &dlsch_msg.sibs[i].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT));
current_cell->has_valid_sib2 = true;
} else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[i].sib_type && !serving_cell->has_valid_sib2) {
memcpy(&serving_cell->sib2, &dlsch_msg.sibs[i].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT));
serving_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(&current_cell->sib3, &dlsch_msg.sibs[i].sib.sib3, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT));
current_cell->has_valid_sib3 = true;
} else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3 == dlsch_msg.sibs[i].sib_type && !serving_cell->has_valid_sib3) {
memcpy(&serving_cell->sib3, &dlsch_msg.sibs[i].sib.sib3, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT));
serving_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(&current_cell->sib13, &dlsch_msg.sibs[0].sib.sib13, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT));
current_cell->has_valid_sib13 = true;
}else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13 == dlsch_msg.sibs[i].sib_type && !serving_cell->has_valid_sib13) {
memcpy(&serving_cell->sib13, &dlsch_msg.sibs[0].sib.sib13, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT));
serving_cell->has_valid_sib13 = true;
handle_sib13();
}
}
if(current_cell->has_valid_sib2) {
if(serving_cell->has_valid_sib2) {
sysinfo_index++;
}
}
@ -1238,16 +1316,16 @@ void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu) {
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]);
serving_cell->sib1.cell_id&0xfff,
liblte_rrc_si_window_length_num[serving_cell->sib1.si_window_length],
liblte_rrc_si_periodicity_num[serving_cell->sib1.sched_info[0].si_periodicity]);
// Print SIB scheduling info
uint32_t i,j;
for(i=0;i<current_cell->sib1.N_sched_info;i++){
for(j=0;j<current_cell->sib1.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;
for(i=0;i<serving_cell->sib1.N_sched_info;i++){
for(j=0;j<serving_cell->sib1.sched_info[i].N_sib_mapping_info;j++){
LIBLTE_RRC_SIB_TYPE_ENUM t = serving_cell->sib1.sched_info[i].sib_mapping_info[j].sib_type;
LIBLTE_RRC_SI_PERIODICITY_ENUM p = serving_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]);
@ -1255,16 +1333,16 @@ void rrc::handle_sib1()
}
// Set TDD Config
if(current_cell->sib1.tdd) {
phy->set_config_tdd(&current_cell->sib1.tdd_cnfg);
if(serving_cell->sib1.tdd) {
phy->set_config_tdd(&serving_cell->sib1.tdd_cnfg);
}
current_cell->has_valid_sib1 = true;
serving_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);
for (uint32_t i = 0; i < serving_cell->sib1.N_plmn_ids; i++) {
nas->plmn_found(serving_cell->sib1.plmn_id[i].id, serving_cell->sib1.tracking_area_code);
}
// Jump to next state
@ -1287,7 +1365,7 @@ void rrc::handle_sib2()
{
rrc_log->info("SIB2 received\n");
apply_sib2_configs(&current_cell->sib2);
apply_sib2_configs(&serving_cell->sib2);
}
@ -1295,7 +1373,7 @@ void rrc::handle_sib3()
{
rrc_log->info("SIB3 received\n");
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3 = &current_cell->sib3;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3 = &serving_cell->sib3;
// cellReselectionInfoCommon
cell_resel_cfg.q_hyst = liblte_rrc_q_hyst_num[sib3->q_hyst];
@ -1317,9 +1395,9 @@ void rrc::handle_sib13()
{
rrc_log->info("SIB13 received\n");
// mac->set_config_mbsfn_sib13(&current_cell->sib13.mbsfn_area_info_list_r9[0],
// current_cell->sib13.mbsfn_area_info_list_r9_size,
// &current_cell->sib13.mbsfn_notification_config);
// mac->set_config_mbsfn_sib13(&serving_cell->sib13.mbsfn_area_info_list_r9[0],
// serving_cell->sib13.mbsfn_area_info_list_r9_size,
// &serving_cell->sib13.mbsfn_notification_config);
}
@ -1499,7 +1577,7 @@ void rrc::parse_dl_ccch(byte_buffer_t *pdu) {
case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REJ:
rrc_log->info("Connection Reject received. Wait time: %d\n",
dl_ccch_msg.msg.rrc_con_rej.wait_time);
state = RRC_STATE_IDLE;
state = RRC_STATE_LEAVE_CONNECTED;
break;
case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_SETUP:
rrc_log->info("Connection Setup received\n");
@ -1607,7 +1685,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) {
*
*******************************************************************************/
void rrc::enable_capabilities() {
bool enable_ul_64 = args.ue_category >= 5 && current_cell->sib2.rr_config_common_sib.pusch_cnfg.enable_64_qam;
bool enable_ul_64 = args.ue_category >= 5 && serving_cell->sib2.rr_config_common_sib.pusch_cnfg.enable_64_qam;
rrc_log->info("%s 64QAM PUSCH\n", enable_ul_64 ? "Enabling" : "Disabling");
phy->set_config_64qam_en(enable_ul_64);
}
@ -2272,14 +2350,20 @@ 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)
{
float values[NOF_MEASUREMENTS] = {rsrp, rsrq};
// This indicates serving cell
if (earfcn == 0) {
if (parent->serving_cell->equals(earfcn, pci)) {
log_h->info("MEAS: New measurement serving cell, rsrp=%f, rsrq=%f, tti=%d\n", rsrp, rsrq, tti);
L3_filter(&pcell_measurement, values);
// Update serving cell measurement
parent->serving_cell->rsrp = rsrp;
} else {
// Add to known cells
// Add to list of neighbour 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);
@ -2299,8 +2383,6 @@ 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);
}
}