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 result\n");
    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 search\n");
      // 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 cell\n");
    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 resynchronization\n");
  } else {
    if (!srslte_cellid_isvalid(new_cell->pci)) {
      log_h->error("Cell Select: Invalid cell_id=%d\n", new_cell->pci);
      return ret;
    }
    Info("Cell Select: Starting cell selection for PCI=%d, EARFCN=%d\n", 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 IDLE\n");
  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 cell\n");
      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=%d\n", new_cell->earfcn);
      if (!set_frequency()) {
        Error("Cell Select: Setting new frequency EARFCN=%d\n", 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 rate\n");
    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 SFN\n");
  }

  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 supported\n");
              log_h->console("Detected cell during SFN synchronization differs from configured cell. Cell reselection "
                             "to cells with different MIB is not supported\n");
              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 result\n");
    return proc_outcome_t::yield;
  }

  if (not event.cs_ret) {
    Error("Couldn't select new serving cell\n");
    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 received\n");
  }
  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 passed\n");
      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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值