从OAI学习5G
从OAI代码学习5G
学习一个东西最好的办法就是自己动手做一遍,很多细节的问题会在这个过程中暴露出来,这是单纯看书或文档很难做到的。
5G兴起,为了学习5G,看3gpp文档实在太痛苦,而自己写协议栈?似乎有点不切实际。于是想到找个协议栈的源码来研究研究。而开源协议栈源码中最著名的似乎是openairinterface,正好OAI也已经实现了5G的一些基本功能,就拿它来练手了。本篇所用的是2019.3.27日下载的代码。后续如果有更新再做修改。
由于原来一直看的是终端侧的协议,所以OAI也从UE的代码入手。
先放一张主函数的流程图:
UE的主函数
UE的主函数在nr-uesoftmodem.c中:
int main( int argc, char **argv ) {
//这里就是终端的入口啦,接下来定义了几个不知所云的变量,OAI的代码注释真的有些业余啊
int i;//j,k,aa,re;
#if defined (XFORMS)
void *status;
#endif
int CC_id; //这个据说是compoent carrier ID,如果没有载波聚合,应该就是0吧
uint8_t abstraction_flag=0;
//uint8_t beta_ACK=0,beta_RI=0,beta_CQI=2;
#if defined (XFORMS)
int ret;
#endif
PHY_VARS_NR_UE *UE[MAX_NUM_CCs]; //定义UE结构体数组,就相当于UE对象实例。这个定义很简单,但是用于定义等结构体却值得研究。
PHY_VARS_NR_UE结构体
这个结构体是干啥用的呢?
我们先跳到这个结构体的定义看看。由于这个结构体的定义太长,我们只从源码截开头的一段:
/// Top-level PHY Data Structure for UE
typedef struct {
/// \brief Module ID indicator for this instance
uint8_t Mod_id;
/// \brief Component carrier ID for this PHY instance
uint8_t CC_id;
/// \brief Mapping of CC_id antennas to cards
openair0_rf_map rf_map;
//uint8_t local_flag;
/// \brief Indicator of current run mode of UE (normal_txrx, rx_calib_ue, no_L2_connect, debug_prach)
runmode_t mode;
/// \brief Indicator that UE should perform band scanning
int UE_scan;
/// \brief Indicator that UE should perform coarse scanning around carrier
int UE_scan_carrier;
/// \brief Indicator that UE should enable estimation and compensation of frequency offset
int UE_fo_compensation;
/// \brief Indicator that UE is synchronized to an eNB
int is_synchronized;
/// Data structure for UE process scheduling
UE_nr_proc_t proc;
/// Flag to indicate the UE shouldn't do timing correction at all
int no_timing_correction;
/// \brief Total gain of the TX chain (16-bit baseband I/Q to antenna)
uint32_t tx_total_gain_dB;
/// \brief Total gain of the RX chain (antenna to baseband I/Q) This is a function of rx_gain_mode (and the corresponding gain) and the rx_gain of the card.
uint32_t rx_total_gain_dB;
/// \brief Total gains with maximum RF gain stage (ExpressMIMO2/Lime)
uint32_t rx_gain_max[4];
看第一行注释,直译过来就是用于UE的最高等级物理层数据结构,其实就是定义了UE物理层相关的各个参数,比如:终端的接收功率增益,发射功率增益,是否同步,射频通路的映射关系等等等等。
说等等等等,是因为后面确实还有很多相关参数,感兴趣的可以参阅源码。
跳回主函数:
定义来UE结构体数组之后,主函数调用了几个用于初始化的函数,如下:
start_background_system(); //新起一个进程,用于运行system()系统调用,根据注释这是为了UE设置IP地址用的,因为与理解5G无关,暂时先不关心它
if ( load_configmodule(argc,argv) == NULL) {
//解析命令行参数,对系统做一些配置,比如debug level之类,看起来跟5G概念也没有直接关系,暂时pass
exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
}
CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP); //这句和下面的也都是对系统做配置
#ifdef DEBUG_CONSOLE
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
#endif
set_default_frame_parms(frame_parms); //重点来了,设置5G帧默认参数
跳过用于系统设置的函数,我们看最后一个设置默认帧参数的函数。
set_default_frame_parms(frame_parms) 函数
打开这个函数看看具体做了哪些设置:
void set_default_frame_parms(NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs])