随机接入之RAR处理
前言
前面一篇文章用了思维导图的方式,发现思维导图对代码流程的展现的确比较清晰,后续将继续延续思维导图的方式,由于图片较长,读者可以保存下来细细琢磨。LTE的系统还是一个比较大的系统,由于写文章的时间不多,更新会比较慢。如果项目中有用到srsLTE的代码或者希望得到相关培训的读者,可以私信作者。码字不易,请喜欢本系列文章的读者 点赞+收藏+关注!
代码流程思维导图
本篇文章主要将介绍srsLTE的RAR相关代码,先看一张RAR流程的代码流程图,可以结合后面的分析代码,再看一下这张图,收获可能会更大。
RAR(MSG2)的结构
RAR MAC header
MAC头大小可变,由下列域组成:
——E:扩展域,扩展域是一个标志位,指示MAC头中是否还有其他的域。如果E域设定为“1”,则表示其后至少还有另一组E/T/RAPID域。如果E域设置为“0”,表示从其后的字节起为MAC RAR或者填充;
——T:类型域,类型域是一个标志位,指示MAC子头中包含的是一个随机接入前导码ID还是一个Backoff指示。如果T域为“0”,指示子头中存在一个Backoff指示(BI)域。如果T域为“1”,指示子头中存在一个随机接入前导码ID(RAPID)域;
——R::预留比特,设置为 “0”;
——BI:Backoff指示域表明小区处于过载状态。BI域的长度为4bits;
——RAPID:随机接入前导码标识域指明了已发送的随机接入前导码, RAPID域的长度为6bits。UE会根据这个RAPID和自己发送的preamble进行比较,如果相同,则说明这个RAR是发给自己的,否则,丢弃这次的RAR。
MAC头和子头都是字节对齐。
RAR MAC payload
MAC RAR长度固定,包含下列域:
——R::预留比特,设置为 “0”;
——Timing Advance Command:时间提前命令域,指示用于UE时间调整量的索引值, TA (0, 1, 2… 1282) 。时间提前命令域的长度是11bits;UE收到RAR之后,需要将TA的值配置给物理层,由物理层控制后续MSG3在空口的时延,以保证不同UE的信号到达基站的时间大致是一致的。
——UL Grant:上行授权域,指示用于上行传输的资源 。上行授权域的长度是20 bits,MSG3实际上就是使用该资源发送;
——Temporary C-RNTI:临时C-RNTI 域,指示UE在随机接入过程中使用的临时C-RNTI,临时C-RNTI 域的长度是16 bits,TC-RNTI在MSG3的加扰和解扰中会用到。
MAC RAR字节对齐。
RA-RNTI
LTE常见RNTI用途
RA-RNTI的计算
RA-RNTI的用途仅用于随机接入响应这条消息,基站往UE发送RAR时,PDCCH和PDSCH需要使用RA-RNTI进行加扰,UE也需要使用RA-RNTI进行解扰。这里有一个问题,UE和基站是如何使用相同的RA-RNTI的呢?答案是UE和基站会使用相同的公式独立进行计算,由于输入的参数是相同的,因此,得到RA-RNTI也是一致的。
公式: RA-RNTI= 1 + t_id+10*f_id
t_id为指定PRACH资源第一个子帧的索引,取值范围为(0≤ t_id <10);f_id为该子帧指定的PRACH以频域递增顺序的索引,取值范围为(0≤ f_id< 6)。
RAR的接收窗口
一旦随机接入前导码被传输,不考虑是否有测量间隔,为接收到随机接入响应,UE应在随机接入响应窗中监测以RA-RNTI为标识的PDCCH。随机接入响应窗始于包含前导码发送结束的子帧加上3个子帧,窗长为ra-ResponseWindowSize个子帧长。
这里有的读者可能比较难以理解为什么要加上3个子帧,因为从prach被发送开始计算,基站需要处理prach,并且基站还要调度RAR,这都是需要时间的,也就是说在prach之后的3个TTI,UE不会得到RAR。
代码流程分析
这里需要搞清楚的一点是,随机接入的整个流程是由MAC层控制的,物理层在哪个TTI需要解哪个RNTI等都受MAC的控制。
cc_worker::work_dl_regular()
bool cc_worker::work_dl_regular()
{
bool dl_ack[SRSLTE_MAX_CODEWORDS] = {};
mac_interface_phy_lte::tb_action_dl_t dl_action = {};
bool found_dl_grant = false;
sf_cfg_dl.sf_type = SRSLTE_SF_NORM;
// Set default channel estimation
ue_dl_cfg.chest_cfg = chest_default_cfg;
/* For TDD, when searching for SIB1, the ul/dl configuration is unknown and need to do blind search over
* the possible mi values
*/
uint32_t mi_set_len;
if (cell.frame_type == SRSLTE_TDD && !sf_cfg_dl.tdd_config.configured) {
mi_set_len = 3;
} else {
mi_set_len = 1;
}
// Blind search PHICH mi value
for (uint32_t i = 0; i < mi_set_len && !found_dl_grant; i++) {
if (mi_set_len == 1) {
srslte_ue_dl_set_mi_auto(&ue_dl);
} else {
srslte_ue_dl_set_mi_manual(&ue_dl, i);
}
/* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, &sf_cfg_dl, &ue_dl_cfg) < 0) {
Error("Getting PDCCH FFT estimate\n");
return false;
}
/* Look for DL and UL dci(s) if this is PCell, or no cross-carrier scheduling is enabled */
if ((cc_idx == 0) || (!ue_dl_cfg.cfg.dci.cif_present)) {
//解下行的DCI
found_dl_grant = decode_pdcch_dl() > 0;
//解上行的DCI
decode_pdcch_ul();
}
}
srslte_dci_dl_t dci_dl = {};
uint32_t grant_cc_idx = 0;
bool has_dl_grant = phy->get_dl_pending_grant(CURRENT_TTI, cc_idx, &grant_cc_idx, &dci_dl);
// If found a dci for this carrier, generate a grant, pass it to MAC and decode the associated PDSCH
if (has_dl_grant) {
// Read last TB from last retx for this pid
for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
ue_dl_cfg.cfg.pdsch.grant.last_tbs[i] = phy->last_dl_tbs[dci_dl.pid][cc_idx][i];
}
// Generate PHY grant
if (srslte_ue_dl_dci_to_pdsch_grant(&ue_dl, &sf_cfg_dl, &ue_dl_cfg, &dci_dl, &ue_dl_cfg.cfg.pdsch.grant)) {
Error("Converting DCI message to DL dci\n");
return -1;
}
// Save TB for next retx
for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
phy->last_dl_tbs[dci_dl.pid][cc_idx][i] = ue_dl_cfg.cfg.pdsch.grant.last_tbs[i];
}
// Set RNTI
ue_dl_cfg.cfg.pdsch.rnti = dci_dl.rnti;
// Generate MAC grant
mac_interface_phy_lte::mac_grant_dl_t mac_grant = {};
dl_phy_to_mac_grant(&ue_dl_cfg.cfg.pdsch.grant, &dci_dl, &mac_grant);
// Save ACK resource configuration
srslte_pdsch_ack_resource_t ack_resource = {dci_dl.dai, dci_dl.location.ncce, grant_cc_idx, dci_dl.tpc_pucch};
// Send grant to MAC and get action for this TB, then call tb_decoded to unlock MAC
//new_grant_dl会分配空间,下行的数据会存放在该空间,分配时需要下行DCI的信息
phy->stack->new_grant_dl(cc_idx, mac_grant, &dl_action);
//物理层根据DCI信息解decode_pdsch,并将数据放在指定的位置
decode_pdsch(ack_resource, &dl_action, dl_ack);
//通知高层进行tb的处理,如HARQ等,这里是高层协议栈处理数据的总的入口
phy->stack->tb_decoded(cc_idx, mac_grant, dl_ack);
}
/* Decode PHICH */
decode_phich();
return true;
}
cc_worker::decode_pdcch_dl()
int cc_worker::decode_pdcch_dl()
{
int nof_grants = 0;
//得到需要解扰需要的RNTI,不同的RNTI的搜索空间不一样,这个和TM模式,TS方式有关,在后续专题再介绍。
uint16_t dl_rnti = phy->stack->get_dl_sched_rnti(CURRENT_TTI);
if (dl_rnti != SRSLTE_INVALID_RNTI) {
srslte_dci_dl_t dci[SRSLTE_MAX_CARRIERS] = {};
/* Blind search first without cross scheduling then with it if enabled */
for (int i = 0; i < (ue_dl_cfg.cfg.dci.cif_present ? 2 : 1) && !nof_grants; i++) {
Debug("PDCCH looking for rnti=0x%x\n", dl_rnti);
ue_dl_cfg.cfg.dci.cif_enabled = i > 0;
//物理层会根据输入在不同的搜索空间尝试搜索下行DCI
nof_grants = srslte_ue_dl_find_dl_dci(&ue_dl, &sf_cfg_dl, &ue_dl_cfg, dl_rnti, dci);
if (nof_grants < 0) {
Error("Looking for DL grants\n");
return -1;
}
}
// If RAR dci, save TTI
if (nof_grants > 0 && SRSLTE_RNTI_ISRAR(dl_rnti)) {
//设置RAR的RNTI
phy->set_rar_grant_tti(CURRENT_TTI);
}
for (int k = 0; k < nof_grants; k++) {
// Save dci to CC index
phy->set_dl_pending_grant(CURRENT_TTI, dci[k].cif_present ? dci[k].cif : cc_idx, cc_idx, &dci[k]);
// Logging
if (log_h->get_level() >= srslte::LOG_LEVEL_INFO) {
char str[512];
srslte_dci_dl_info(&dci[k], str, 512);
log_h->info("PDCCH: cc=%d, %s, snr=%.1f dB\n", cc_idx, str, ue_dl.chest_res.snr_db);
}
}
}
return nof_grants;
}
cc_worker::work_dl_regular()
// Process Timing Advance Command as defined in Section 5.2
void ra_proc::process_timeadv_cmd(uint32_t ta)
{
if (preambleIndex == 0) {
// Preamble not selected by UE MAC
phy_h->set_timeadv_rar(ta);
// Only if timer is running reset the timer
if (time_alignment_timer->is_running()) {
time_alignment_timer->run();
}
Debug("Applying RAR TA CMD %d\n", ta);
} else {
// Preamble selected by UE MAC
if (!time_alignment_timer->is_running()) {
//TA下发给物理层,后续通过MAC-CE下发的TA也要下发物理层
phy_h->set_timeadv_rar(ta);
time_alignment_timer->run();
Debug("Applying RAR TA CMD %d\n", ta);
} else {
// Ignore TA CMD
Warning("Ignoring RAR TA CMD because timeAlignmentTimer still running\n");
}
}
}
/* Called upon the reception of a DL grant for RA-RNTI
* Configures the action and softbuffer for the reception of the associated TB
*/
void ra_proc::new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action)
{
bzero(action, sizeof(mac_interface_phy_lte::tb_action_dl_t));
if (grant.tb[0].tbs < MAX_RAR_PDU_LEN) {
rDebug("DL dci found RA-RNTI=%d\n", ra_rnti);
action->tb[0].enabled = true;
//指定TB解码的位置,后续的处理从这里取数据
action->tb[0].payload = rar_pdu_buffer;
action->tb[0].rv = grant.tb[0].rv;
action->tb[0].softbuffer.rx = &softbuffer_rar;
rar_grant_nbytes = grant.tb[0].tbs;
if (action->tb[0].rv == 0) {
srslte_softbuffer_rx_reset(&softbuffer_rar);
}
} else {
rError("Received RAR dci exceeds buffer length (%d>%d)\n", grant.tb[0].tbs, MAX_RAR_PDU_LEN);
}
}
/* Called upon the successful decoding of a TB addressed to RA-RNTI.
* Processes the reception of a RAR as defined in 5.1.4
*/
void ra_proc::tb_decoded_ok(const uint8_t cc_idx, const uint32_t tti)
{
if (pcap) {
pcap->write_dl_ranti(rar_pdu_buffer, rar_grant_nbytes, ra_rnti, true, tti, cc_idx);
}
rDebug("RAR decoded successfully TBS=%d\n", rar_grant_nbytes);
rar_pdu_msg.init_rx(rar_grant_nbytes);
rar_pdu_msg.parse_packet(rar_pdu_buffer);
// Set Backoff parameter
if (rar_pdu_msg.has_backoff()) {
backoff_param_ms = backoff_table[rar_pdu_msg.get_backoff() % 16];
} else {
backoff_param_ms = 0;
}
current_ta = 0;
while (rar_pdu_msg.next()) {
//判断RAR是否是属于自己的
if (rar_pdu_msg.get()->has_rapid() && rar_pdu_msg.get()->get_rapid() == sel_preamble) {
rar_received = true;
//处理TA
process_timeadv_cmd(rar_pdu_msg.get()->get_ta_cmd());
// TODO: Indicate received target power
// phy_h->set_target_power_rar(iniReceivedTargetPower, (preambleTransmissionCounter-1)*powerRampingStep);
uint8_t grant[srslte::rar_subh::RAR_GRANT_LEN];
rar_pdu_msg.get()->get_sched_grant(grant);
rntis->rar_rnti = 0;
phy_h->set_rar_grant(grant, rar_pdu_msg.get()->get_temp_crnti());
current_ta = rar_pdu_msg.get()->get_ta_cmd();
rInfo("RAPID=%d, TA=%d, T-CRNTI=0x%x\n",
sel_preamble,
rar_pdu_msg.get()->get_ta_cmd(),
rar_pdu_msg.get()->get_temp_crnti());
if (preambleIndex > 0) {
//非竞争
// Preamble selected by Network
complete();
} else {
// Preamble selected by UE MAC
//准备发送MSG3
mux_unit->msg3_prepare();
//保存TC-RNTI
rntis->temp_rnti = rar_pdu_msg.get()->get_temp_crnti();
// If this is the first successfully received RAR within this procedure, Msg3 is empty
if (mux_unit->msg3_is_empty()) {
// Save transmitted C-RNTI (if any)
transmitted_crnti = rntis->crnti;
// If we have a C-RNTI, tell Mux unit to append C-RNTI CE if no CCCH SDU transmission
if (transmitted_crnti) {
//MSG3是MAC-CE CRNTI的情况
rInfo("Appending C-RNTI MAC CE 0x%x in next transmission\n", transmitted_crnti);
mux_unit->append_crnti_ce_next_tx(transmitted_crnti);
}
}
// Save transmitted UE contention id, as defined by higher layers
//保存竞争ID,后续收到MSG4之后,判断是否竞争解决
transmitted_contention_id = rntis->contention_id;
rDebug("Waiting for Contention Resolution\n");
state = CONTENTION_RESOLUTION;
}
} else {
if (rar_pdu_msg.get()->has_rapid()) {
rInfo("Found RAR for preamble %d\n", rar_pdu_msg.get()->get_rapid());
}
}
}
}