前沿

之前的文章介绍PLMN是如何被搜索到的,在搜索到PLMN全部搜索之后,UE会选择其中的一个PLMN进行驻留。这个过程相对前面的内容来讲比较简单,本文来分析下srsLTE的代码是如何选择PLMN的。

RRC层的PLMN搜索过程

RRC层会进行全频段的PLMN扫描,收集周围的全部PLMN,并进行存储,并在全频段扫描之后,通知NAS层PLMN搜索过程结果,NAS层会进行PLMN 选择,选择完之后会发起RRC 信令连接的过程。

rrc::plmn_search_proc::plmn_search_proc(rrc* parent_) : rrc_ptr(parent_), log_h(srslte::logmap::get("RRC")) {}proc_outcome_t rrc::plmn_search_proc::init()
{Info("Starting PLMN search\n");nof_plmns       = 0;cell_search_fut = rrc_ptr->cell_searcher.get_future();if (not rrc_ptr->cell_searcher.launch(&cell_search_fut)) {Error("Failed due to fail to init cell search...\n");return proc_outcome_t::error;}return step();
}/* NAS interface to search for available PLMNs.* It goes through all known frequencies, synchronizes and receives SIB1 for each to extract PLMN.* The function is blocking and waits until all frequencies have been* searched and PLMNs are obtained.*/
proc_outcome_t rrc::plmn_search_proc::step()
{if (rrc_ptr->cell_searcher.run()) {// wait for new TTIreturn proc_outcome_t::yield;}if (cell_search_fut.is_error() or cell_search_fut.value()->found == phy_interface_rrc_lte::cell_search_ret_t::ERROR) {// stop searchnof_plmns = -1;Error("Failed due to failed cell search sub-procedure\n");return proc_outcome_t::error;}
//解到SIB1之后,保存PLMN和TACif (cell_search_fut.value()->found == phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND) {if (rrc_ptr->serving_cell->has_sib1()) {// Save PLMN and TAC to NASfor (uint32_t i = 0; i < rrc_ptr->serving_cell->nof_plmns(); i++) {if (nof_plmns < MAX_FOUND_PLMNS) {found_plmns[nof_plmns].plmn_id = rrc_ptr->serving_cell->get_plmn(i);found_plmns[nof_plmns].tac     = rrc_ptr->serving_cell->get_tac();nof_plmns++;} else {Error("No more space for plmns (%d)\n", nof_plmns);}}} else {Error("SIB1 not acquired\n");}}if (cell_search_fut.value()->last_freq == phy_interface_rrc_lte::cell_search_ret_t::NO_MORE_FREQS) {Info("completed PLMN search\n");return proc_outcome_t::success;}if (not rrc_ptr->cell_searcher.launch(&cell_search_fut)) {Error("Failed due to fail to init cell search...\n");return proc_outcome_t::error;}// run againreturn step();
}void rrc::plmn_search_proc::then(const srslte::proc_state_t& result) const
{// on cleanup, call plmn_search_completedif (result.is_success()) {Info("completed with success\n");//RRC层的PLMN search过程结束之后将结果通知给NAS层rrc_ptr->nas->plmn_search_completed(found_plmns, nof_plmns);} else {Error("PLMN Search completed with an error\n");rrc_ptr->nas->plmn_search_completed(nullptr, -1);}
}

NAS层的PLMN选择

NAS层的plmn_search_completed函数接口,会trigger NAS层的PLMN搜索过程的react函数。

void nas::plmn_search_completed(const rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS],int                                   nof_plmns)
{//trigger plmn_search_proc的react函数  plmn_searcher.trigger(plmn_search_proc::plmn_search_complete_t(found_plmns, nof_plmns));
}

react函数的代码流程

关键步骤如下:
1、NAS层保存PLMN搜索结果;
2、执行PLMN选择;
3、发起建立RRC连接的过程。

proc_outcome_t nas::plmn_search_proc::react(const plmn_search_complete_t& t)
{if (state != state_t::plmn_search) {ProcWarning("PLMN Search Complete was received but PLMN Search is not running.\n");return proc_outcome_t::yield; // ignore}// check whether the state hasn't changedif (nas_ptr->state != EMM_STATE_DEREGISTERED or nas_ptr->plmn_is_selected) {ProcError("ProcError while searching for PLMNs\n");return proc_outcome_t::error;}if (t.nof_plmns < 0) {ProcError("Error while searching for PLMNs\n");return proc_outcome_t::error;}if (t.nof_plmns == 0) {ProcWarning("Did not find any PLMN in the set of frequencies.\n");return proc_outcome_t::error;}// Save PLMNsnas_ptr->known_plmns.clear();for (int i = 0; i < t.nof_plmns; i++) {nas_ptr->known_plmns.push_back(t.found_plmns[i].plmn_id);nas_ptr->nas_log->info("Found PLMN:  Id=%s, TAC=%d\n", t.found_plmns[i].plmn_id.to_string().c_str(), t.found_plmns[i].tac);nas_ptr->nas_log->console("Found PLMN:  Id=%s, TAC=%d\n", t.found_plmns[i].plmn_id.to_string().c_str(), t.found_plmns[i].tac);}nas_ptr->select_plmn();// Select PLMN in request establishment of RRC connectionif (not nas_ptr->plmn_is_selected) {ProcError("PLMN is not selected because no suitable PLMN was found\n");return proc_outcome_t::error;}nas_ptr->rrc->plmn_select(nas_ptr->current_plmn);state = state_t::rrc_connect;if (not nas_ptr->rrc_connector.launch(srslte::establishment_cause_t::mo_sig, nullptr)) {ProcError("Unable to initiate RRC connection.\n");return proc_outcome_t::error;}nas_ptr->callbacks.add_proc(nas_ptr->rrc_connector);return proc_outcome_t::yield;
}

PLMN选择

PLMN选择会将搜索的结果和本地的PLMN(home_plmn)进行比较,如果找到,返回成功。如果没有,就选择第一个PLMN。
这里的home_plmn是在SIM卡存储的信息,开机时,NAS会从通过接口从SIM卡中获取信息,此外还有s-tmsi等信息。这里多介绍下SIM卡,SIM除了有存储的功能,还有处理加密等计算的功能。

void nas::select_plmn()
{plmn_is_selected = false;// First find if Home PLMN is availablefor (const srslte::plmn_id_t& known_plmn : known_plmns) {if (known_plmn == home_plmn) {nas_log->info("Selecting Home PLMN Id=%s\n", known_plmn.to_string().c_str());plmn_is_selected = true;current_plmn     = known_plmn;return;}}// If not, select the first available PLMNif (not known_plmns.empty()) {nas_log->info("Could not find Home PLMN Id=%s, trying to connect to PLMN Id=%s\n",home_plmn.to_string().c_str(),known_plmns[0].to_string().c_str());nas_log->console("Could not find Home PLMN Id=%s, trying to connect to PLMN Id=%s\n",home_plmn.to_string().c_str(),known_plmns[0].to_string().c_str());plmn_is_selected = true;current_plmn     = known_plmns[0];}// reset attach attempt counter (Sec. 5.2.2.3.4)if (plmn_is_selected) {attach_attempt_counter = 0;}
}

总结

至此,现在才获取PLMN,但是UE的入网流程还有很远,虽然从代码上来分析,从NAS->RRC->MAC层,以这样的方式来看比较直观,但是,从空口报文的分析来看,MAC层的随机接入是在前面的,后续的过程,我们将以空口的报文顺序来分析代码流程。

如对本系列文章感兴趣,欢迎关注、收藏,有新的文档,平台会第一时间推送。

srsLTE 源码分析 UE_07 PLMN选择相关推荐

  1. srsLTE 源码分析 UE_05 PLMN选择之小区选择

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

  2. srsLTE 源码分析 UE_04 PLMN选择之小区搜索

    小区搜索代码流程 PLMN选择LTE的第一个流程,但是由于PLMN涉及的代码量较大,放在一篇文章中,内容过多,因此,这一篇主要先针对小区搜索的流程进行代码梳理.小区搜索主要是PSS.SSS.MIB的解 ...

  3. srsLTE 源码分析 UE_06 PLMN选择之SIB1

    前沿 SIB1和MIB不同,它是在PDSCH上传输,它的解调需要了解以下几点: 1.DCI在公共搜索空间,使用SI-RNTI加工: 2.SIB1在每个系统帧的子帧5上发送: 3.需要在PDCCH里面先 ...

  4. Android 音频源码分析——AudioTrack设备选择

    Android 音频源码分析--AndroidRecord录音(一) Android 音频源码分析--AndroidRecord录音(二) Android 音频源码分析--AndroidRecord音 ...

  5. srsLTE源码分析(一)---enb协议栈入口

    在srslte中,代码的运行机制主要采用线程池,多队列,时间序列等方式来运作的.他们之间相互配合协调运作各个功能.在进入整个程序之前,笔者先简单的说一下线程池的基本原理,线程池实际上主要有两个部分的线 ...

  6. srsLTE 源码分析 UE_08 随机接入 之开启前的准备

    前言 通过前面的文章,读者应该对PLMN的搜索和选择有了一定的了解,接下来的几篇文章,我们会对随机接入的代码和流程进行分析.随机接入是MAC层的一项重要的任务,主要目的是实现UE和基站的上行同步,它从 ...

  7. srsLTE 源码分析 UE_09 随机接入 之PRACH发送

    前言 前一篇文章介绍SIB2相关的内容,PRACH必须要再SIB2之后再进行发送,原因是PRACH相关参数是在SIB2携带.这一篇文章将详细介绍下,PRACH的发送过程,这个过程在代码的流程有些长,如 ...

  8. 【Spring实战】----Security4.1.3鉴权之美--基于投票的AccessDecisionManager实现及源码分析

    一.背景知识 Spring实战篇系列----Security4.1.3认证过程源码分析和Spring实战篇系列----Security4.1.3实现根据请求跳转不同登录页以及登录后根据权限跳转到不同页 ...

  9. Hbase Compaction 源码分析 - CompactSplitThread 线程池选择

    目录 CompactSplitThread requestCompactionInternal方法 selectCompaction方法 requestCompaction方法 其他相关文章 Hbas ...

最新文章

  1. 办公计算机培训方案,计算机办公软件应用培训教学计划规划方案.docx
  2. Hadoop 4、Hadoop MapReduce的工作原理
  3. vue数据源转json问题
  4. Android性能优化之虚拟机调优
  5. c#3.0关于JSON简单操作的实用帮助类(泛型实现)
  6. linux构建主从域名服务器
  7. 使用正则表达式实现将浮点数点左边的数每三位添加一个逗号
  8. BI和报表等于数据分析?终于有人讲清楚了它们的区别
  9. 05.javascript访问CSS
  10. js常用设计模式实现(一)单例模式
  11. app架构师实践指南pdf,分享一些行业经验,看完这一篇你就懂了
  12. 苹果手机怎么无线投屏?苹果手机无线投屏到电脑
  13. UPC 备战省赛第六场 Bumped!
  14. modelsim/Questasim中添加xilinx ip库,并仿真成功
  15. Redis 集群规范(中文稿)(MOVED错误码及ASK错误码
  16. 深度学习面试题总结1-20
  17. kali Linux 2020.1B 最详细安装教程
  18. C#中用RSA算法生成公钥和私钥
  19. Linux定时重启任务示例
  20. NGINX免费配置二级域名及同时开启HTTPS(HTTP强制转HTTPS)nodejs的express后端项目,前端next.js的SSR项目

热门文章

  1. 2021-10-24 NodeJS面试题
  2. 美团面试题:DCL单例模式需不需要volatile?
  3. 开题报告:基于java餐厅网站和座位预定系统 毕业设计论文开题报告模板
  4. python监控摄像头或网络通常情况
  5. python函数图像绘制
  6. 优思学院|带你从零开始学习六西格玛
  7. java函数是什么意思啊_[求助]请问setHorizontalAlignment是什么意思!什么函数来
  8. JAVA——实现求出1到100之间的既是3的倍数又是5倍数的数字之和.
  9. SVM算法面试问题汇总
  10. 开发 transport 协议转换层