|
|
|
@ -41,6 +41,7 @@ namespace srsue {
|
|
|
|
|
|
|
|
|
|
int radio_recv_wrapper_cs(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) {
|
|
|
|
|
srslte::radio_multi *radio_h = (srslte::radio_multi *) h;
|
|
|
|
|
|
|
|
|
|
if (radio_h->rx_now(data, nsamples, rx_time)) {
|
|
|
|
|
int offset = nsamples - radio_h->get_tti_len();
|
|
|
|
|
if (abs(offset) < 10 && offset != 0) {
|
|
|
|
@ -226,7 +227,7 @@ bool phch_recv::set_cell() {
|
|
|
|
|
return cell_is_set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool phch_recv::cell_search(int force_N_id_2) {
|
|
|
|
|
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];
|
|
|
|
@ -238,7 +239,7 @@ bool phch_recv::cell_search(int force_N_id_2) {
|
|
|
|
|
srate_mode = SRATE_FIND;
|
|
|
|
|
radio_h->set_rx_srate(1.92e6);
|
|
|
|
|
}
|
|
|
|
|
radio_h->start_rx();
|
|
|
|
|
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;
|
|
|
|
@ -257,13 +258,12 @@ bool phch_recv::cell_search(int force_N_id_2) {
|
|
|
|
|
last_gain = srslte_agc_get_gain(&cs.ue_sync.agc);
|
|
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
radio_h->stop_rx();
|
|
|
|
|
Error("SYNC: Error decoding MIB: Error searching PSS\n");
|
|
|
|
|
return false;
|
|
|
|
|
return -1;
|
|
|
|
|
} else if (ret == 0) {
|
|
|
|
|
radio_h->stop_rx();
|
|
|
|
|
stop_rx();
|
|
|
|
|
Info("SYNC: Could not find any cell in this frequency\n");
|
|
|
|
|
return false;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
// Save result
|
|
|
|
|
cell.id = found_cells[max_peak_cell].cell_id;
|
|
|
|
@ -294,7 +294,7 @@ bool phch_recv::cell_search(int force_N_id_2) {
|
|
|
|
|
ret = srslte_ue_mib_sync_decode(&ue_mib_sync,
|
|
|
|
|
40,
|
|
|
|
|
bch_payload, &cell.nof_ports, &sfn_offset);
|
|
|
|
|
radio_h->stop_rx();
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
@ -311,9 +311,12 @@ bool phch_recv::cell_search(int force_N_id_2) {
|
|
|
|
|
cell.id, cell.nof_prb, cell.nof_ports, cellsearch_cfo/1000);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
} else if (ret == 0) {
|
|
|
|
|
Warning("SYNC: Found PSS but could not decode PBCH\n");
|
|
|
|
|
return false;
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
|
|
|
|
Error("SYNC: Receiving MIB\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -391,8 +394,8 @@ int phch_recv::cell_meas_rsrp() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void phch_recv::resync_sfn() {
|
|
|
|
|
radio_h->stop_rx();
|
|
|
|
|
radio_h->start_rx();
|
|
|
|
|
stop_rx();
|
|
|
|
|
start_rx();
|
|
|
|
|
srslte_ue_mib_reset(&ue_mib);
|
|
|
|
|
Info("SYNC: Starting SFN synchronization\n");
|
|
|
|
|
sync_sfn_cnt = 0;
|
|
|
|
@ -417,24 +420,28 @@ bool phch_recv::stop_sync() {
|
|
|
|
|
void phch_recv::cell_search_inc()
|
|
|
|
|
{
|
|
|
|
|
cur_earfcn_index++;
|
|
|
|
|
Info("SYNC: Cell Search idx %d/%d\n", cur_earfcn_index, earfcn.size());
|
|
|
|
|
if (cur_earfcn_index >= 0) {
|
|
|
|
|
if (cur_earfcn_index >= (int) earfcn.size() - 1) {
|
|
|
|
|
cur_earfcn_index = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
usleep(100000);
|
|
|
|
|
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() {
|
|
|
|
|
if (cell_search_in_progress) {
|
|
|
|
|
void phch_recv::cell_search_next(bool reset) {
|
|
|
|
|
if (cell_search_in_progress || reset) {
|
|
|
|
|
cell_search_in_progress = false;
|
|
|
|
|
if (!stop_sync()) {
|
|
|
|
|
log_h->warning("SYNC: Couldn't stop PHY\n");
|
|
|
|
|
}
|
|
|
|
|
if (reset) {
|
|
|
|
|
cur_earfcn_index = -1;
|
|
|
|
|
}
|
|
|
|
|
cell_search_inc();
|
|
|
|
|
phy_state = CELL_SEARCH;
|
|
|
|
|
cell_search_in_progress = true;
|
|
|
|
@ -443,16 +450,22 @@ void phch_recv::cell_search_next() {
|
|
|
|
|
|
|
|
|
|
void phch_recv::cell_search_start() {
|
|
|
|
|
if (earfcn.size() > 0) {
|
|
|
|
|
cell_search_in_progress = true;
|
|
|
|
|
cur_earfcn_index = -1;
|
|
|
|
|
cell_search_next();
|
|
|
|
|
log_h->info("SYNC: Starting Cell Search procedure in %d EARFCNs...\n", earfcn.size());
|
|
|
|
|
Info("SYNC: Starting Cell Search procedure in %d EARFCNs...\n", earfcn.size());
|
|
|
|
|
cell_search_next(true);
|
|
|
|
|
} else {
|
|
|
|
|
log_h->info("SYNC: Empty EARFCN list. Stopping cell search...\n");
|
|
|
|
|
Info("SYNC: Empty EARFCN list. Stopping cell search...\n");
|
|
|
|
|
log_h->console("Empty EARFCN list. Stopping cell search...\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void phch_recv::cell_search_stop() {
|
|
|
|
|
Info("SYNC: Stopping Cell Search procedure...\n");
|
|
|
|
|
if (!stop_sync()) {
|
|
|
|
|
Error("SYNC: Stopping cell search\n");
|
|
|
|
|
}
|
|
|
|
|
cell_search_in_progress = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) {
|
|
|
|
|
|
|
|
|
|
// Check if we are already camping in this cell
|
|
|
|
@ -476,6 +489,8 @@ bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) {
|
|
|
|
|
|
|
|
|
|
current_earfcn = earfcn;
|
|
|
|
|
|
|
|
|
|
printf("cell select called set frequency\n");
|
|
|
|
|
|
|
|
|
|
if (set_frequency()) {
|
|
|
|
|
this->cell = cell;
|
|
|
|
|
log_h->info("Cell Select: Configuring cell...\n");
|
|
|
|
@ -536,7 +551,6 @@ void phch_recv::set_sampling_rate()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void phch_recv::run_thread() {
|
|
|
|
|
int sync_res;
|
|
|
|
|
phch_worker *worker = NULL;
|
|
|
|
|
cf_t *buffer[SRSLTE_MAX_PORTS];
|
|
|
|
|
phy_state = IDLE;
|
|
|
|
@ -549,20 +563,28 @@ void phch_recv::run_thread() {
|
|
|
|
|
}
|
|
|
|
|
switch (phy_state) {
|
|
|
|
|
case CELL_SEARCH:
|
|
|
|
|
if (cell_search() && cell_search_in_progress) {
|
|
|
|
|
if (!srslte_cell_isvalid(&cell)) {
|
|
|
|
|
Error("SYNC: Detected invalid cell\n");
|
|
|
|
|
phy_state = IDLE;
|
|
|
|
|
if (cell_search_in_progress) {
|
|
|
|
|
switch(cell_search()) {
|
|
|
|
|
case 1:
|
|
|
|
|
if (!srslte_cell_isvalid(&cell)) {
|
|
|
|
|
Error("SYNC: Detected invalid cell\n");
|
|
|
|
|
phy_state = IDLE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (set_cell()) {
|
|
|
|
|
set_sampling_rate();
|
|
|
|
|
resync_sfn();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (set_cell()) {
|
|
|
|
|
set_sampling_rate();
|
|
|
|
|
resync_sfn();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
if (cell_search_in_progress) {
|
|
|
|
|
cell_search_inc();
|
|
|
|
|
case 0:
|
|
|
|
|
if (cell_search_in_progress) {
|
|
|
|
|
cell_search_inc();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
log_h->error("SYNC: Receiving frorm radio.\n");
|
|
|
|
|
phy_state = IDLE;
|
|
|
|
|
radio_h->reset();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
@ -571,10 +593,6 @@ void phch_recv::run_thread() {
|
|
|
|
|
srslte_ue_sync_decode_sss_on_track(&ue_sync, true);
|
|
|
|
|
|
|
|
|
|
switch (cell_sync_sfn()) {
|
|
|
|
|
default:
|
|
|
|
|
log_h->console("SYNC: Going IDLE\n");
|
|
|
|
|
phy_state = IDLE;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
srslte_ue_sync_set_agc_period(&ue_sync, 20);
|
|
|
|
|
if (!cell_search_in_progress) {
|
|
|
|
@ -588,6 +606,11 @@ void phch_recv::run_thread() {
|
|
|
|
|
break;
|
|
|
|
|
case 0:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
log_h->error("SYNC: Receiving frorm radio.\n");
|
|
|
|
|
phy_state = IDLE;
|
|
|
|
|
radio_h->reset();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
sync_sfn_cnt++;
|
|
|
|
|
if (sync_sfn_cnt >= SYNC_SFN_TIMEOUT) {
|
|
|
|
@ -604,10 +627,13 @@ void phch_recv::run_thread() {
|
|
|
|
|
rrc->cell_found(earfcn[cur_earfcn_index], cell, 10*log10(measure_rsrp/1000));
|
|
|
|
|
break;
|
|
|
|
|
case 0:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
log_h->error("SYNC: Getting RSRP cell measurement.\n");
|
|
|
|
|
cell_search_next();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
log_h->error("SYNC: Receiving frorm radio.\n");
|
|
|
|
|
phy_state = IDLE;
|
|
|
|
|
radio_h->reset();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case CELL_CAMP:
|
|
|
|
@ -618,53 +644,57 @@ void phch_recv::run_thread() {
|
|
|
|
|
buffer[i] = worker->get_buffer(i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sync_res = srslte_ue_sync_zerocopy_multi(&ue_sync, buffer);
|
|
|
|
|
if (sync_res == 1) {
|
|
|
|
|
|
|
|
|
|
log_h->step(tti);
|
|
|
|
|
|
|
|
|
|
Debug("SYNC: Worker %d synchronized\n", worker->get_id());
|
|
|
|
|
|
|
|
|
|
metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync);
|
|
|
|
|
metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync);
|
|
|
|
|
worker->set_cfo(ul_dl_factor * metrics.cfo / 15000);
|
|
|
|
|
worker_com->set_sync_metrics(metrics);
|
|
|
|
|
|
|
|
|
|
float sample_offset = (float) srslte_ue_sync_get_sfo(&ue_sync) / 1000;
|
|
|
|
|
worker->set_sample_offset(sample_offset);
|
|
|
|
|
|
|
|
|
|
/* Compute TX time: Any transmission happens in TTI4 thus advance 4 ms the reception time */
|
|
|
|
|
srslte_timestamp_t rx_time, tx_time, tx_time_prach;
|
|
|
|
|
srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time);
|
|
|
|
|
srslte_timestamp_copy(&tx_time, &rx_time);
|
|
|
|
|
srslte_timestamp_add(&tx_time, 0, 4e-3 - time_adv_sec);
|
|
|
|
|
worker->set_tx_time(tx_time);
|
|
|
|
|
|
|
|
|
|
Debug("SYNC: Setting TTI=%d, tx_mutex=%d to worker %d\n", tti, tx_mutex_cnt, worker->get_id());
|
|
|
|
|
worker->set_tti(tti, tx_mutex_cnt);
|
|
|
|
|
tx_mutex_cnt = (tx_mutex_cnt+1) % nof_tx_mutex;
|
|
|
|
|
|
|
|
|
|
// Check if we need to TX a PRACH
|
|
|
|
|
if (prach_buffer->is_ready_to_send(tti)) {
|
|
|
|
|
srslte_timestamp_copy(&tx_time_prach, &rx_time);
|
|
|
|
|
srslte_timestamp_add(&tx_time_prach, 0, prach::tx_advance_sf * 1e-3);
|
|
|
|
|
prach_buffer->send(radio_h, ul_dl_factor * metrics.cfo / 15000, worker_com->pathloss, tx_time_prach);
|
|
|
|
|
radio_h->tx_end();
|
|
|
|
|
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);
|
|
|
|
|
// Notify RRC in-sync every 1 frame
|
|
|
|
|
if ((tti % 10) == 0) {
|
|
|
|
|
rrc->in_sync();
|
|
|
|
|
log_h->debug("SYNC: Sending in-sync to RRC\n");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
log_h->error("SYNC: Sync error. Sending out-of-sync to RRC\n");
|
|
|
|
|
// Notify RRC of out-of-sync frame
|
|
|
|
|
rrc->out_of_sync();
|
|
|
|
|
worker->release();
|
|
|
|
|
worker_com->reset_ul();
|
|
|
|
|
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);
|
|
|
|
|
metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync);
|
|
|
|
|
worker->set_cfo(ul_dl_factor * metrics.cfo / 15000);
|
|
|
|
|
worker_com->set_sync_metrics(metrics);
|
|
|
|
|
|
|
|
|
|
worker->set_sample_offset(srslte_ue_sync_get_sfo(&ue_sync)/1000);
|
|
|
|
|
|
|
|
|
|
/* Compute TX time: Any transmission happens in TTI4 thus advance 4 ms the reception time */
|
|
|
|
|
srslte_timestamp_t rx_time, tx_time, tx_time_prach;
|
|
|
|
|
srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time);
|
|
|
|
|
srslte_timestamp_copy(&tx_time, &rx_time);
|
|
|
|
|
srslte_timestamp_add(&tx_time, 0, 4e-3 - time_adv_sec);
|
|
|
|
|
worker->set_tx_time(tx_time);
|
|
|
|
|
|
|
|
|
|
Debug("SYNC: Setting TTI=%d, tx_mutex=%d to worker %d\n", tti, tx_mutex_cnt, worker->get_id());
|
|
|
|
|
worker->set_tti(tti, tx_mutex_cnt);
|
|
|
|
|
tx_mutex_cnt = (tx_mutex_cnt+1) % nof_tx_mutex;
|
|
|
|
|
|
|
|
|
|
// Check if we need to TX a PRACH
|
|
|
|
|
if (prach_buffer->is_ready_to_send(tti)) {
|
|
|
|
|
srslte_timestamp_copy(&tx_time_prach, &rx_time);
|
|
|
|
|
srslte_timestamp_add(&tx_time_prach, 0, prach::tx_advance_sf * 1e-3);
|
|
|
|
|
prach_buffer->send(radio_h, ul_dl_factor * metrics.cfo / 15000, worker_com->pathloss, tx_time_prach);
|
|
|
|
|
radio_h->tx_end();
|
|
|
|
|
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);
|
|
|
|
|
// Notify RRC in-sync every 1 frame
|
|
|
|
|
if ((tti % 10) == 0) {
|
|
|
|
|
rrc->in_sync();
|
|
|
|
|
log_h->debug("SYNC: Sending in-sync to RRC\n");
|
|
|
|
|
}
|
|
|
|
|
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();
|
|
|
|
|
worker->release();
|
|
|
|
|
worker_com->reset_ul();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
log_h->error("SYNC: Receiving frorm radio.\n");
|
|
|
|
|
phy_state = IDLE;
|
|
|
|
|
radio_h->reset();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here
|
|
|
|
@ -673,7 +703,7 @@ void phch_recv::run_thread() {
|
|
|
|
|
break;
|
|
|
|
|
case IDLE:
|
|
|
|
|
if (!is_in_idle) {
|
|
|
|
|
radio_h->stop_rx();
|
|
|
|
|
stop_rx();
|
|
|
|
|
}
|
|
|
|
|
is_in_idle = true;
|
|
|
|
|
usleep(1000);
|
|
|
|
@ -682,6 +712,22 @@ 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;
|
|
|
|
|
}
|
|
|
|
|