我是靠谱客的博主 酷酷指甲油,最近开发中收集的这篇文章主要介绍srsLTE 源码分析 UE_05 PLMN选择之小区选择前言代码流程,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

前言

在上一篇文章中,介绍了小区搜索的代码流程,从ue.switch_on()流程开始,最终是如何让物理层去搜索PSS、SSS以及MIB信息。这一章节,我们接着分析下小区选择的代码。这里的小区选择指的是初始小区选择要注意和普通的小区选择的区别:

  • 终端在进行初始小区选择会在每个可用频点上都去进行;
  • 每个频点终端只关注最强的小区信号,而且要和小区进行同步;
  • 在解到SIB1之后,获取PLMN信息之后,不会进行小区驻留。

再来看一下,SIB1里面要携带哪些信息:

  • plmn-IdentityList
  • cellReservedForOperatorUse
  • trackingAreaCode
  • cellBarred
  • intraFreqReselection
  • csg-Indication
  • q-RxLevMinOffset
  • p-Max
  • frequencyBandIndicator
  • si-Periodicity
  • sib-MappingInfo
  • si-WindowLength
  • systemInfoValueTag
  • csg-Identity
  • imsEmergencySupportIndicator
  • q-QualMin
  • q-QualMinOffset

代码流程

rrc_procedures.cc

从代码中可以看出,在执行完 phy->cell_search()流程之后,会将cell_search_completed的任务push到任务队列中,后续的ue_stack_lte线程会调用cell_search_completed任务,在cell_search_completed函数中,会进行一系列的调用,最终会执行stack->start_cell_select的流程。
rrc::cell_search_completed
-> cell_searcher.trigger();
-> cell_search_proc::react ()
->cell_search_proc::handle_cell_found()
->stack->start_cell_select
这里要注意的一点是pending_tasks.push()执行之后,background_tasks线程的start_cell_search()任务就结束了,background_tasks线程可以继续执行新的任务。start_cell_select()代码过程和start_cell_search类似,它也是在background_tasks线程中创建的任务,且在phy->cell_select时会进行阻塞。


void ue_stack_lte::start_cell_select(const phy_interface_rrc_lte::phy_cell_t* phy_cell)
{
background_tasks.push_task([this, phy_cell](uint32_t worker_id) {
bool ret = phy->cell_select(phy_cell);
// notify back RRC
pending_tasks.push(background_queue_id, [this, ret]() { rrc.cell_select_completed(ret); });
});
}
void ue_stack_lte::start_cell_search()
{
background_tasks.push_task([this](uint32_t worker_id) {
phy_interface_rrc_lte::phy_cell_t
found_cell;
phy_interface_rrc_lte::cell_search_ret_t ret = phy->cell_search(&found_cell);
// notify back RRC
pending_tasks.push(background_queue_id, [this, found_cell, ret]() { rrc.cell_search_completed(ret, found_cell); });
});
}
proc_outcome_t rrc::cell_search_proc::react(const cell_search_event_t& event)
{
if (state != state_t::phy_cell_search) {
Error("Received unexpected cell search resultn");
return proc_outcome_t::error;
}
search_result = event;
Info("PHY cell search completed.n");
// Transition to SI Acquire or finish
switch (search_result.cs_ret.found) {
case phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND:
return handle_cell_found(search_result.found_cell);
case phy_interface_rrc_lte::cell_search_ret_t::CELL_NOT_FOUND:
rrc_ptr->phy_sync_state = phy_unknown_sync;
Info("No cells found.n");
// do nothing
return proc_outcome_t::success;
case phy_interface_rrc_lte::cell_search_ret_t::ERROR:
Error("Error while performing cell searchn");
// TODO: check what errors can happen (currently not handled in our code)
return proc_outcome_t::error;
}
return proc_outcome_t::yield;
}
proc_outcome_t rrc::cell_search_proc::handle_cell_found(const phy_interface_rrc_lte::phy_cell_t& new_cell)
{
Info("Cell found in this frequency. Setting new serving cell EARFCN=%d PCI=%d ...n", new_cell.earfcn, new_cell.pci);
// Create a cell with NaN RSRP. Will be updated by new_phy_meas() during SIB search.
if (not rrc_ptr->add_neighbour_cell(unique_cell_t(new cell_t(new_cell)))) {
Error("Could not add new found celln");
return proc_outcome_t::error;
}
rrc_ptr->set_serving_cell(new_cell, false);
// set new serving cell in PHY
state = state_t::phy_cell_select;
rrc_ptr->stack->start_cell_select(&rrc_ptr->serving_cell->phy_cell);
return proc_outcome_t::yield;
}

sync.cc

sync::cell_select()会配置物理层的工作频点和PCI,做一些初始化的工作,后续会调用phy_state.run_sfn_sync();这个会让 run_thread()进入到sync_state::SFN_SYNC状态,该状态会调用sfn_p.run_subframe,该函数会完成再一次完成PSS、SSS、以及MIB的解码,完成和配置小区的下行同步。
sfn_p.run_subframe如果和基站顺利的同步完成之后,就会进入CAMPING状态,为后续的SIB1做准备。并且通过 stack->in_sync()接口通知RRC进入in_sync状态。
这里需要解释的一点,在213协议中,小区搜索,UE只需要解PSS和SSS信号,并且找到信号最强的小区。但在srsLTE的代码实现中,小区搜索的过程不但通过PSS、SSS信号取得下行的时频资源同步,还解了MIB消息。
在小区选择的过程中,又一次解了PSS、SSS还有MIB消息,并且将两次的结果做了一次比较,至于为什么这么做,原因未知,有知道的小伙伴可以评论区留言,感谢!


void run_sfn_sync()
{
std::lock_guard<std::mutex> lock(outside);
go_state(SFN_SYNC);
wait_state_run();
wait_state_next();
}
/* Cell select synchronizes to a new cell (e.g. during HO or during cell reselection on IDLE) or
* re-synchronizes with the current cell if cell argument is NULL
*/
bool sync::cell_select(const phy_interface_rrc_lte::phy_cell_t* new_cell)
{
std::unique_lock<std::mutex> ul(rrc_mutex);
bool ret = false;
int
cnt = 0;
// Move state to IDLE
if (new_cell == nullptr) {
Info("Cell Select: Starting cell resynchronizationn");
} else {
if (!srslte_cellid_isvalid(new_cell->pci)) {
log_h->error("Cell Select: Invalid cell_id=%dn", new_cell->pci);
return ret;
}
Info("Cell Select: Starting cell selection for PCI=%d, EARFCN=%dn", new_cell->pci, new_cell->earfcn);
}
// Wait for any pending PHICH
while (worker_com->is_any_ul_pending_ack() && cnt < 10) {
usleep(1000);
cnt++;
Info("Cell Select: waiting pending PHICH (cnt=%d)n", cnt);
}
Info("Cell Select: Going to IDLEn");
phy_state.go_idle();
worker_com->reset();
sfn_p.reset();
search_p.reset();
srslte_ue_sync_reset(&ue_sync);
/* Reconfigure cell if necessary */
if (new_cell != nullptr) {
cell.id = new_cell->pci;
if (not set_cell(new_cell->cfo_hz)) {
Error("Cell Select: Reconfiguring celln");
return ret;
}
/* Select new frequency if necessary */
if ((int)new_cell->earfcn != current_earfcn) {
current_earfcn = new_cell->earfcn;
// Stop all intra-frequency measurement before changing frequency
meas_stop();
Info("Cell Select: Setting new frequency EARFCN=%dn", new_cell->earfcn);
if (!set_frequency()) {
Error("Cell Select: Setting new frequency EARFCN=%dn", new_cell->earfcn);
return ret;
}
}
// Reconfigure first intra-frequency measurement
intra_freq_meas[0]->set_primary_cell(current_earfcn, cell);
}
/* Change sampling rate if necessary */
if (srate_mode != SRATE_CAMP) {
log_h->info("Cell Select: Setting CAMPING sampling raten");
set_sampling_rate();
}
/* SFN synchronization */
phy_state.run_sfn_sync();
if (phy_state.is_camping()) {
Info("Cell Select: SFN synchronized. CAMPING...n");
stack->in_sync();
ret = true;
} else {
Info("Cell Select: Could not synchronize SFNn");
}
return ret;
}
void sync::run_thread()
{
//.......
switch (phy_state.run_state()) {
case sync_state::SFN_SYNC:
/* SFN synchronization using MIB. run_subframe() receives and processes 1 subframe
* and returns
*/
temp_cell = cell;
switch (sfn_p.run_subframe(&temp_cell, &tti, mib)) {
case sfn_sync::SFN_FOUND:
if (memcmp(&cell, &temp_cell, sizeof(srslte_cell_t))) {
srslte_cell_fprint(stdout, &cell, 0);
srslte_cell_fprint(stdout, &temp_cell, 0);
log_h->error("Detected cell during SFN synchronization differs from configured cell. Cell reselection to "
"cells with different MIB is not supportedn");
log_h->console("Detected cell during SFN synchronization differs from configured cell. Cell reselection "
"to cells with different MIB is not supportedn");
phy_state.state_exit(false);
}
stack->in_sync();
phy_state.state_exit();
break;
case sfn_sync::IDLE:
break;
default:
phy_state.state_exit(false);
break;
}
break;
}
// Increase TTI counter
tti = (tti + 1) % 10240;
}
}

ue_stack_lte.cc

物理层的SFN_SYNC状态结束之后,background_tasks线程的cell_select函数会随之结束,后续会接着调用rrc::cell_select_completed结果完成小区选择的流程。

void ue_stack_lte::start_cell_select(const phy_interface_rrc_lte::phy_cell_t* phy_cell)
{
background_tasks.push_task([this, phy_cell](uint32_t worker_id) {
bool ret = phy->cell_select(phy_cell);
// notify back RRC
pending_tasks.push(background_queue_id, [this, ret]() { rrc.cell_select_completed(ret); });
});
}

rrc.cc

rrc的cell_select_completed函数里面调用cell_searcher.trigger函数,这个会触发cell_searcher和cell_selector的react函数。

void rrc::cell_select_completed(bool cs_ret)
{
cell_select_event_t ev{cs_ret};
cell_searcher.trigger(ev);
cell_selector.trigger(ev);
}

rrc.cc

cell_search_proc过程的会进入到state_t::wait_measurement状态,wait_measurement后续会触发SIB1的过程。
cell_selection_proc过程会进入wait_in_sync状态,step_wait_in_sync()会进一步开启serv_cell_cfg过程,serv_cell_cfg由于还没有收到SIB1,其他SIB的解码过程不会被执行。

proc_outcome_t rrc::cell_search_proc::react(const cell_select_event_t& event)
{
if (state != state_t::phy_cell_select) {
Warning("Received unexpected cell search resultn");
return proc_outcome_t::yield;
}
if (not event.cs_ret) {
Error("Couldn't select new serving celln");
return proc_outcome_t::error;
}
if (not rrc_ptr->phy->cell_is_camping()) {
Warning("Could not camp on found cell.n");
return proc_outcome_t::error;
}
if (not std::isnormal(rrc_ptr->serving_cell->get_rsrp())) {
Info("No valid measurement found for the serving cell. Wait for valid measurement...n");
}
state = state_t::wait_measurement;
return proc_outcome_t::yield;
}
proc_outcome_t rrc::cell_selection_proc::react(const cell_select_event_t& event)
{
switch (state) {
case search_state_t::cell_selection: {
return step_cell_selection(event);
}
case search_state_t::serv_cell_camp: {
return step_serv_cell_camp(event);
}
case search_state_t::cell_search:
// cell search may call cell_select
break;
default:
Warning("Unexpected cell selection event receivedn");
}
return proc_outcome_t::yield;
}
proc_outcome_t rrc::cell_selection_proc::step_wait_in_sync()
{
if (rrc_ptr->phy_sync_state == phy_in_sync) {
if (rrc_ptr->cell_selection_criteria(rrc_ptr->serving_cell->get_rsrp())) {
Info("PHY is in SYNC and cell selection passedn");
if (not rrc_ptr->serv_cell_cfg.launch(&serv_cell_cfg_fut, rrc_ptr->ue_required_sibs)) {
return proc_outcome_t::error;
}
state = search_state_t::cell_config;
} else {
Info("PHY is in SYNC but cell selection did not pass. Go back to select step.n");
cs_result
= cs_result_t::no_cell;
neigh_index
= 0;
// TODO: go back to the start?
discard_serving = true; // Discard this cell
return start_cell_selection();
}
}
return proc_outcome_t::yield;
}

最后

以上就是酷酷指甲油为你收集整理的srsLTE 源码分析 UE_05 PLMN选择之小区选择前言代码流程的全部内容,希望文章能够帮你解决srsLTE 源码分析 UE_05 PLMN选择之小区选择前言代码流程所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(36)

评论列表共有 0 条评论

立即
投稿
返回
顶部