mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
Paging (MAC): schedule PCCH in DL path at PF/PO
At each DL slot, schedule_nr_pcch() scans pcch_queue for records whose UE paging occasion matches (frame, slot), encodes one PCCH-Message via do_NR_Paging(), and fills P-RNTI PDCCH/PDSCH NFAPI PDUs. Paging occasion detection is now owned by MAC via PCCH scheduler helper that implements PF/PO computation per TS 38.304 §7. Computation is determined by defaultPagingCycle (T), nAndPagingFrameOffset (N), ns (Ns), with PF formula (SFN + PF_offset) mod T = (T div N) * (UE_ID mod N), and PO slot mapping for Ns = 1/2/4. Paging is transmitted only when (frame, slot) is the UE's paging occasion (TS 38.304 §7.1) and when a Type2-PDCCH CSS is configured via pagingSearchSpace, so the UE can receive it. The RRC PCCH path is simplified accordingly. Changes In `openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_pcch.c`: - Add paging-specific scheduling logic, including `is_paging_occasion()`, paging-search-space resolution, and `nr_fill_nfapi_dl_PCCH_pdu()` - Add `schedule_nr_pcch()` implementation to allocate CCE/PDSCH resources, populate DL/TX NFAPI requests, encode at PO via do_NR_Paging() In gNB scheduler: - Invoke `schedule_nr_pcch()` in SA-mode DL scheduling In `openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c`: - Add PCCH scheduling helpers to be reused at UE side Also: - Remove no longer relevant `rrc_gNB_generate_pcch_msg()` from `rrc_gNB.c` Signed-off-by: Guido Casati <guido.casati@openairinterface.org>
This commit is contained in:
@@ -49,6 +49,9 @@
|
|||||||
* defined for NGAP in TS 38.413 - maxnoofDRBs */
|
* defined for NGAP in TS 38.413 - maxnoofDRBs */
|
||||||
#define MAX_PDUS_PER_UE (8) /* Maximum number of PDU Sessions per UE */
|
#define MAX_PDUS_PER_UE (8) /* Maximum number of PDU Sessions per UE */
|
||||||
|
|
||||||
|
/** Maximum value of nrofPDCCH-MonitoringOccasionPerSSB-InPO-r16 (TS 38.331 PCCH-Config) */
|
||||||
|
#define NR_PCCH_MAX_MO_PER_SSB_IN_PO 4
|
||||||
|
|
||||||
#define NB_RB_MBMS_MAX (29 * 16) /* 29 = LTE_maxSessionPerPMCH + 16 = LTE_maxServiceCount from LTE_asn_constant.h */
|
#define NB_RB_MBMS_MAX (29 * 16) /* 29 = LTE_maxSessionPerPMCH + 16 = LTE_maxServiceCount from LTE_asn_constant.h */
|
||||||
|
|
||||||
#define NB_RAB_MAX 11 /* from LTE_maxDRB in LTE_asn_constant.h */
|
#define NB_RAB_MAX 11 /* from LTE_maxDRB in LTE_asn_constant.h */
|
||||||
|
|||||||
@@ -274,6 +274,12 @@ typedef struct {
|
|||||||
uint8_t CRNTI_2: 8; // octet 11 [7:0]
|
uint8_t CRNTI_2: 8; // octet 11 [7:0]
|
||||||
} __attribute__((__packed__)) NR_MAC_SUCCESS_RAR;
|
} __attribute__((__packed__)) NR_MAC_SUCCESS_RAR;
|
||||||
|
|
||||||
|
/* P-RNTI DCI 1_0 Short Messages Indicator values (TS 38.212 Table 7.3.1.2.1-1). */
|
||||||
|
#define NR_DCI_PRNTI_SMI_RESERVED 0 /* 00: reserved */
|
||||||
|
#define NR_DCI_PRNTI_SMI_PAGING_SCHED_ONLY 1 /* 01: PDSCH carries paging, no Short Message */
|
||||||
|
#define NR_DCI_PRNTI_SMI_SHORT_MSG_ONLY 2 /* 10: Short Message only */
|
||||||
|
#define NR_DCI_PRNTI_SMI_PAGING_AND_SHORT 3 /* 11: PDSCH paging and Short Message */
|
||||||
|
|
||||||
// DCI pdu structures. Used by both gNB and UE.
|
// DCI pdu structures. Used by both gNB and UE.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "nr_mac.h"
|
#include "nr_mac.h"
|
||||||
#include "nr_mac_common.h"
|
#include "nr_mac_common.h"
|
||||||
|
#include "NR_PagingCycle.h"
|
||||||
#include "common/utils/bits.h"
|
#include "common/utils/bits.h"
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <executables/softmodem-common.h>
|
#include <executables/softmodem-common.h>
|
||||||
@@ -4939,3 +4940,210 @@ int get_j_for_k2(int mu)
|
|||||||
AssertFatal(mu >= 0 && mu < sizeofArray(j_table), "Invalid numerology %d\n", mu);
|
AssertFatal(mu >= 0 && mu < sizeofArray(j_table), "Invalid numerology %d\n", mu);
|
||||||
return j_table[mu];
|
return j_table[mu];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief T: DRX cycle of the UE in radio frames (TS 38.304 §7.1).
|
||||||
|
* @return T = defaultPagingCycle from PCCH-Config (mandatory, TS 38.331). */
|
||||||
|
uint16_t nr_pcch_default_paging_cycle_rf(const NR_PCCH_Config_t *pcch)
|
||||||
|
{
|
||||||
|
DevAssert(pcch != NULL);
|
||||||
|
switch (pcch->defaultPagingCycle) {
|
||||||
|
case NR_PagingCycle_rf32:
|
||||||
|
return 32;
|
||||||
|
case NR_PagingCycle_rf64:
|
||||||
|
return 64;
|
||||||
|
case NR_PagingCycle_rf128:
|
||||||
|
return 128;
|
||||||
|
case NR_PagingCycle_rf256:
|
||||||
|
return 256;
|
||||||
|
default:
|
||||||
|
AssertFatal(false,
|
||||||
|
"SIB1 PCCH-Config: invalid defaultPagingCycle %ld (TS 38.331: rf32/64/128/256)\n",
|
||||||
|
pcch->defaultPagingCycle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Derive N and PF_offset from PCCH-Config.nAndPagingFrameOffset (TS 38.331), per TS 38.304 §7.1.
|
||||||
|
* N is the number of paging frames per DRX cycle T.
|
||||||
|
* PF_offset is the offset (in radio frames) applied to SFN in the PF equation. */
|
||||||
|
void nr_pcch_n_and_paging_frame_offset(const NR_PCCH_Config_t *pcch, uint16_t T, uint16_t *N, uint8_t *PF_offset)
|
||||||
|
{
|
||||||
|
DevAssert(pcch != NULL);
|
||||||
|
DevAssert(N != NULL && PF_offset != NULL);
|
||||||
|
const union NR_PCCH_Config__NR_nAndPagingFrameOffset_u *choice = &pcch->nAndPagingFrameOffset.choice;
|
||||||
|
switch (pcch->nAndPagingFrameOffset.present) {
|
||||||
|
case NR_PCCH_Config__nAndPagingFrameOffset_PR_oneT:
|
||||||
|
/* PF offset is 0 */
|
||||||
|
*N = T;
|
||||||
|
*PF_offset = 0;
|
||||||
|
break;
|
||||||
|
case NR_PCCH_Config__nAndPagingFrameOffset_PR_halfT:
|
||||||
|
/* PF offset (0..1) */
|
||||||
|
*N = T / 2;
|
||||||
|
*PF_offset = choice->halfT;
|
||||||
|
break;
|
||||||
|
case NR_PCCH_Config__nAndPagingFrameOffset_PR_quarterT:
|
||||||
|
/* PF offset (0..3) */
|
||||||
|
*N = T / 4;
|
||||||
|
*PF_offset = choice->quarterT;
|
||||||
|
break;
|
||||||
|
case NR_PCCH_Config__nAndPagingFrameOffset_PR_oneEighthT:
|
||||||
|
/* PF offset (0..7) */
|
||||||
|
*N = T / 8;
|
||||||
|
*PF_offset = choice->oneEighthT;
|
||||||
|
break;
|
||||||
|
case NR_PCCH_Config__nAndPagingFrameOffset_PR_oneSixteenthT:
|
||||||
|
/* PF offset (0..15) */
|
||||||
|
*N = T / 16;
|
||||||
|
*PF_offset = choice->oneSixteenthT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
AssertFatal(false, "SIB1 PCCH-Config: unsupported nAndPagingFrameOffset present=%d\n", pcch->nAndPagingFrameOffset.present);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Returns the number of paging occasions per paging frame (TS 38.331 PCCH-Config). */
|
||||||
|
uint8_t nr_pcch_ns_per_pf(const NR_PCCH_Config_t *pcch)
|
||||||
|
{
|
||||||
|
DevAssert(pcch != NULL);
|
||||||
|
switch (pcch->ns) {
|
||||||
|
case NR_PCCH_Config__ns_one:
|
||||||
|
return 1;
|
||||||
|
case NR_PCCH_Config__ns_two:
|
||||||
|
return 2;
|
||||||
|
case NR_PCCH_Config__ns_four:
|
||||||
|
return 4;
|
||||||
|
default:
|
||||||
|
AssertFatal(false, "SIB1 PCCH-Config: unsupported ns %ld (TS 38.331: one, two, four)\n", pcch->ns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Resolve start MO index for the (i_s + 1)-th PO from PCCH-Config.firstPDCCH-MonitoringOccasionOfPO (TS 38.331).
|
||||||
|
* @return true and sets *start_mo when list entry i_s exists, false otherwise (start_mo unchanged). */
|
||||||
|
bool nr_pcch_first_pdcch_start_mo(const struct NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO *po_list,
|
||||||
|
uint8_t i_s,
|
||||||
|
int *start_mo)
|
||||||
|
{
|
||||||
|
DevAssert(po_list != NULL);
|
||||||
|
DevAssert(start_mo != NULL);
|
||||||
|
|
||||||
|
switch (po_list->present) {
|
||||||
|
case NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO_PR_NOTHING:
|
||||||
|
return false;
|
||||||
|
case NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO_PR_sCS15KHZoneT: {
|
||||||
|
const struct NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO__sCS15KHZoneT *seq = po_list->choice.sCS15KHZoneT;
|
||||||
|
if (!seq || i_s >= seq->list.count)
|
||||||
|
return false;
|
||||||
|
*start_mo = *seq->list.array[i_s];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO_PR_sCS30KHZoneT_SCS15KHZhalfT: {
|
||||||
|
const struct NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO__sCS30KHZoneT_SCS15KHZhalfT *seq =
|
||||||
|
po_list->choice.sCS30KHZoneT_SCS15KHZhalfT;
|
||||||
|
if (!seq || i_s >= seq->list.count)
|
||||||
|
return false;
|
||||||
|
*start_mo = *seq->list.array[i_s];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO_PR_sCS60KHZoneT_SCS30KHZhalfT_SCS15KHZquarterT: {
|
||||||
|
const struct NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO__sCS60KHZoneT_SCS30KHZhalfT_SCS15KHZquarterT *seq =
|
||||||
|
po_list->choice.sCS60KHZoneT_SCS30KHZhalfT_SCS15KHZquarterT;
|
||||||
|
if (!seq || i_s >= seq->list.count)
|
||||||
|
return false;
|
||||||
|
*start_mo = *seq->list.array[i_s];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO_PR_sCS120KHZoneT_SCS60KHZhalfT_SCS30KHZquarterT_SCS15KHZoneEighthT: {
|
||||||
|
const struct
|
||||||
|
NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO__sCS120KHZoneT_SCS60KHZhalfT_SCS30KHZquarterT_SCS15KHZoneEighthT *seq =
|
||||||
|
po_list->choice.sCS120KHZoneT_SCS60KHZhalfT_SCS30KHZquarterT_SCS15KHZoneEighthT;
|
||||||
|
if (!seq || i_s >= seq->list.count)
|
||||||
|
return false;
|
||||||
|
*start_mo = *seq->list.array[i_s];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO_PR_sCS120KHZhalfT_SCS60KHZquarterT_SCS30KHZoneEighthT_SCS15KHZoneSixteenthT: {
|
||||||
|
const struct
|
||||||
|
NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO__sCS120KHZhalfT_SCS60KHZquarterT_SCS30KHZoneEighthT_SCS15KHZoneSixteenthT
|
||||||
|
*seq = po_list->choice.sCS120KHZhalfT_SCS60KHZquarterT_SCS30KHZoneEighthT_SCS15KHZoneSixteenthT;
|
||||||
|
if (!seq || i_s >= seq->list.count)
|
||||||
|
return false;
|
||||||
|
*start_mo = *seq->list.array[i_s];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO_PR_sCS480KHZoneT_SCS120KHZquarterT_SCS60KHZoneEighthT_SCS30KHZoneSixteenthT: {
|
||||||
|
const struct
|
||||||
|
NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO__sCS480KHZoneT_SCS120KHZquarterT_SCS60KHZoneEighthT_SCS30KHZoneSixteenthT
|
||||||
|
*seq = po_list->choice.sCS480KHZoneT_SCS120KHZquarterT_SCS60KHZoneEighthT_SCS30KHZoneSixteenthT;
|
||||||
|
if (!seq || i_s >= seq->list.count)
|
||||||
|
return false;
|
||||||
|
*start_mo = *seq->list.array[i_s];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO_PR_sCS480KHZhalfT_SCS120KHZoneEighthT_SCS60KHZoneSixteenthT: {
|
||||||
|
const struct NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO__sCS480KHZhalfT_SCS120KHZoneEighthT_SCS60KHZoneSixteenthT
|
||||||
|
*seq = po_list->choice.sCS480KHZhalfT_SCS120KHZoneEighthT_SCS60KHZoneSixteenthT;
|
||||||
|
if (!seq || i_s >= seq->list.count)
|
||||||
|
return false;
|
||||||
|
*start_mo = *seq->list.array[i_s];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO_PR_sCS480KHZquarterT_SCS120KHZoneSixteenthT: {
|
||||||
|
const struct NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO__sCS480KHZquarterT_SCS120KHZoneSixteenthT *seq =
|
||||||
|
po_list->choice.sCS480KHZquarterT_SCS120KHZoneSixteenthT;
|
||||||
|
if (!seq || i_s >= seq->list.count)
|
||||||
|
return false;
|
||||||
|
*start_mo = *seq->list.array[i_s];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
AssertFatal(false, "Unsupported firstPDCCH-MonitoringOccasionOfPO choice %d\n", po_list->present);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief TS 38.304 §7.1: true if @p frame is a paging frame for @p ue_id (PF equation). */
|
||||||
|
bool nr_pcch_sfn_is_pf(uint16_t frame, uint8_t PF_offset, uint16_t T, uint16_t N, uint16_t ue_id)
|
||||||
|
{
|
||||||
|
return (frame + PF_offset) % T == (T / N) * (ue_id % N);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief TS 38.304 §7.1: paging occasion index */
|
||||||
|
uint8_t nr_pcch_po_index(uint16_t ue_id, uint16_t N, uint8_t Ns)
|
||||||
|
{
|
||||||
|
return (ue_id / N) % Ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief TS 38.304 §7.1: SearchSpaceId 0, Ns = 2. PO in first or second half-frame per i_s. */
|
||||||
|
bool nr_pcch_ss0_po_half_frame(uint8_t i_s, int slot, int slots_per_frame)
|
||||||
|
{
|
||||||
|
const int half = slots_per_frame / 2;
|
||||||
|
return (i_s == 0 && slot < half) || (i_s == 1 && slot >= half);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief TS 38.304 §7.1 + TS 38.213: Type2 paging - slot aligns to SS MO period, MO index in PF must lie in [start_mo, end_mo].
|
||||||
|
* PDCCH MOs in the PF are numbered from zero from the first such occasion (MOs at offset + k*period, where k0 first in PF, k
|
||||||
|
* current). */
|
||||||
|
bool nr_pcch_type2_po_mo_in_range(int frame, int slot, int slots_per_frame, int period, int offset, int start_mo, int end_mo)
|
||||||
|
{
|
||||||
|
const int frame_start_slot = frame * slots_per_frame;
|
||||||
|
const int global_slot = frame_start_slot + slot;
|
||||||
|
if (global_slot < offset || (global_slot - offset) % period != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const int diff = frame_start_slot - offset;
|
||||||
|
const int k0 = diff <= 0 ? 0 : (diff + period - 1) / period;
|
||||||
|
const int k = (global_slot - offset) / period;
|
||||||
|
const int mo_index_in_pf = k - k0;
|
||||||
|
const bool in_range = mo_index_in_pf >= start_mo && mo_index_in_pf <= end_mo;
|
||||||
|
if (in_range) {
|
||||||
|
LOG_D(NR_MAC,
|
||||||
|
"Type2 paging PO: frame=%d slot=%d mo_index_in_pf=%d range [%d,%d] period=%d offset=%d\n",
|
||||||
|
frame,
|
||||||
|
slot,
|
||||||
|
mo_index_in_pf,
|
||||||
|
start_mo,
|
||||||
|
end_mo,
|
||||||
|
period,
|
||||||
|
offset);
|
||||||
|
}
|
||||||
|
return in_range;
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "NR_MIB.h"
|
#include "NR_MIB.h"
|
||||||
#include "NR_CellGroupConfig.h"
|
#include "NR_CellGroupConfig.h"
|
||||||
#include "NR_UE-NR-Capability.h"
|
#include "NR_UE-NR-Capability.h"
|
||||||
|
#include "NR_PCCH-Config.h"
|
||||||
#include "nr_mac.h"
|
#include "nr_mac.h"
|
||||||
#include "nr_prach_config.h"
|
#include "nr_prach_config.h"
|
||||||
#include "common/utils/nr/nr_common.h"
|
#include "common/utils/nr/nr_common.h"
|
||||||
@@ -307,4 +308,22 @@ int get_delta_for_k2(int mu);
|
|||||||
|
|
||||||
int get_j_for_k2(int mu);
|
int get_j_for_k2(int mu);
|
||||||
|
|
||||||
|
uint16_t nr_pcch_default_paging_cycle_rf(const NR_PCCH_Config_t *pcch);
|
||||||
|
|
||||||
|
void nr_pcch_n_and_paging_frame_offset(const NR_PCCH_Config_t *pcch, uint16_t T, uint16_t *N, uint8_t *PF_offset);
|
||||||
|
|
||||||
|
uint8_t nr_pcch_ns_per_pf(const NR_PCCH_Config_t *pcch);
|
||||||
|
|
||||||
|
bool nr_pcch_first_pdcch_start_mo(const struct NR_PCCH_Config__firstPDCCH_MonitoringOccasionOfPO *po_list,
|
||||||
|
uint8_t i_s,
|
||||||
|
int *start_mo);
|
||||||
|
|
||||||
|
bool nr_pcch_sfn_is_pf(uint16_t frame, uint8_t PF_offset, uint16_t T, uint16_t N, uint16_t ue_id);
|
||||||
|
|
||||||
|
uint8_t nr_pcch_po_index(uint16_t ue_id, uint16_t N, uint8_t Ns);
|
||||||
|
|
||||||
|
bool nr_pcch_ss0_po_half_frame(uint8_t i_s, int slot, int slots_per_frame);
|
||||||
|
|
||||||
|
bool nr_pcch_type2_po_mo_in_range(int frame, int slot, int slots_per_frame, int period, int offset, int start_mo, int end_mo);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, slot_t slo
|
|||||||
if (IS_SA_MODE(get_softmodem_params())) {
|
if (IS_SA_MODE(get_softmodem_params())) {
|
||||||
schedule_nr_sib1(module_idP, frame, slot, &sched_info->DL_req, &sched_info->TX_req);
|
schedule_nr_sib1(module_idP, frame, slot, &sched_info->DL_req, &sched_info->TX_req);
|
||||||
schedule_nr_other_sib(module_idP, frame, slot, &sched_info->DL_req, &sched_info->TX_req);
|
schedule_nr_other_sib(module_idP, frame, slot, &sched_info->DL_req, &sched_info->TX_req);
|
||||||
|
schedule_nr_pcch(gNB, frame, slot, &sched_info->DL_req, &sched_info->TX_req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,10 @@
|
|||||||
#include "NR_MAC_gNB/nr_mac_gNB.h"
|
#include "NR_MAC_gNB/nr_mac_gNB.h"
|
||||||
#include "NR_MAC_gNB/mac_proto.h"
|
#include "NR_MAC_gNB/mac_proto.h"
|
||||||
#include "common/utils/LOG/log.h"
|
#include "common/utils/LOG/log.h"
|
||||||
|
#include "common/utils/bits.h"
|
||||||
#include "common/utils/ds/byte_array.h"
|
#include "common/utils/ds/byte_array.h"
|
||||||
#include "openair2/RRC/NR/MESSAGES/asn1_msg.h"
|
#include "openair2/RRC/NR/MESSAGES/asn1_msg.h"
|
||||||
|
#include "NR_PCCH-Config.h"
|
||||||
|
|
||||||
void nr_mac_pcch_queue_free(NR_COMMON_channels_t *cc)
|
void nr_mac_pcch_queue_free(NR_COMMON_channels_t *cc)
|
||||||
{
|
{
|
||||||
@@ -37,6 +39,13 @@ static void nr_mac_pcch_queue_push(spsc_q_t *q, module_id_t module_id, const nr_
|
|||||||
LOG_W(NR_MAC, "[gNB %d] PCCH queue full, dropping paging record\n", module_id);
|
LOG_W(NR_MAC, "[gNB %d] PCCH queue full, dropping paging record\n", module_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Re-queue records after a failed PO transmission attempt */
|
||||||
|
static void nr_mac_pcch_queue_reenqueue(spsc_q_t *q, module_id_t module_id, const nr_mac_pcch_record_t *items, int count)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
nr_mac_pcch_queue_push(q, module_id, &items[i]);
|
||||||
|
}
|
||||||
|
|
||||||
/** @brief Enqueue a pending CN paging record for transmission at the UE's PO.
|
/** @brief Enqueue a pending CN paging record for transmission at the UE's PO.
|
||||||
*
|
*
|
||||||
* Stores identity only: PCCH-Message (Paging, TS 38.331 §6.2.2) encoding is deferred
|
* Stores identity only: PCCH-Message (Paging, TS 38.331 §6.2.2) encoding is deferred
|
||||||
@@ -62,3 +71,576 @@ void nr_mac_pcch_enqueue(module_id_t module_id, uint64_t fiveg_s_tmsi, uint16_t
|
|||||||
|
|
||||||
LOG_I(NR_MAC, "[gNB %d] PCCH record enqueued UE_ID=%u (5G-S-TMSI=0x%012lx)\n", module_id, item.ue_id, fiveg_s_tmsi);
|
LOG_I(NR_MAC, "[gNB %d] PCCH record enqueued UE_ID=%u (5G-S-TMSI=0x%012lx)\n", module_id, item.ue_id, fiveg_s_tmsi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Get paging search space (Type2-PDCCH CSS) from common search space list by pagingSearchSpace ID.
|
||||||
|
* TS 38.331 PDCCH-ConfigCommon: pagingSearchSpace is the ID of the search space for paging
|
||||||
|
* on the initial DL BWP. If this field is absent, the UE does not receive paging on this BWP
|
||||||
|
* (TS 38.213 §10), so we do not schedule PCCH here either.
|
||||||
|
* @return the SearchSpace from commonSearchSpaceList whose searchSpaceId matches the SS referenced
|
||||||
|
* by the pagingSearchSpace ID and whose searchSpaceType is common, or NULL otherwise. */
|
||||||
|
static NR_SearchSpace_t *get_paging_search_space(NR_ServingCellConfigCommon_t *scc)
|
||||||
|
{
|
||||||
|
NR_PDCCH_ConfigCommon_t *pdcch = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup;
|
||||||
|
if (!pdcch->pagingSearchSpace || !pdcch->commonSearchSpaceList)
|
||||||
|
return NULL;
|
||||||
|
NR_SearchSpaceId_t id = *pdcch->pagingSearchSpace;
|
||||||
|
for (int i = 0; i < pdcch->commonSearchSpaceList->list.count; i++) {
|
||||||
|
NR_SearchSpace_t *ss = pdcch->commonSearchSpaceList->list.array[i];
|
||||||
|
if (ss->searchSpaceId != id)
|
||||||
|
continue;
|
||||||
|
if (ss->searchSpaceType == NULL || ss->searchSpaceType->present != NR_SearchSpace__searchSpaceType_PR_common)
|
||||||
|
return NULL;
|
||||||
|
return ss;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief True if (frame, slot) is a Type0-PDCCH monitoring occasion (TS 38.213 Clause 13).
|
||||||
|
*
|
||||||
|
* Type0-PDCCH CSS carries RMSI (SIB1). When SearchSpaceId = 0 for pagingSearchSpace, TS 38.304
|
||||||
|
* requires paging PDCCH monitoring occasions to be the same as for RMSI, so we reuse this check
|
||||||
|
* for Ns=1 paging PO slot selection. */
|
||||||
|
static bool is_type0_occasion_paging(gNB_MAC_INST *mac, NR_ServingCellConfigCommon_t *scc, uint16_t frame, uint16_t slot)
|
||||||
|
{
|
||||||
|
DevAssert(mac);
|
||||||
|
DevAssert(scc);
|
||||||
|
const int L_max = get_max_ssbs(scc);
|
||||||
|
// Loops over all SSB indices, returns true if (frame, slot) is the Type0-PDCCH CSS monitoring occasion for any SSB
|
||||||
|
for (int i = 0; i < L_max; i++) {
|
||||||
|
if (is_type0_occasion(scc, &mac->type0_PDCCH_CSS_config[i], frame, slot))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Build NFAPI DL TTI PDUs (PDCCH + PDSCH) for PCCH with P-RNTI.
|
||||||
|
*
|
||||||
|
* Builds:
|
||||||
|
* - PDCCH PDU carrying DCI format 1_0 with CRC scrambled by P-RNTI (TS 38.212 §7.3.1.2.1) in the
|
||||||
|
* Type2-PDCCH common search space configured by pagingSearchSpace (TS 38.213 §10.1).
|
||||||
|
* - PDSCH PDU carrying the Paging RRC PDU (PCCH-Message, TS 38.331).
|
||||||
|
* NFAPI envelopes follow SCF NFAPI DL_TTI.request (PDCCH/PDSCH PDU types).
|
||||||
|
*
|
||||||
|
* @param mac gNB MAC instance
|
||||||
|
* @param pdsch PDSCH allocation parameters (TDA, BWP, MCS, RB allocation, TBS)
|
||||||
|
* @param pdcch PDCCH allocation parameters (CCE/REG mapping, BWP)
|
||||||
|
* @param search_space Paging search space (Type2-PDCCH CSS)
|
||||||
|
* @param coreset CORESET referenced by the search space
|
||||||
|
* @param aggregation_level PDCCH aggregation level (TS 38.213 §10.1, Table 10.1-1)
|
||||||
|
* @param cce_index First CCE index of the chosen candidate
|
||||||
|
* @param dl_req DL TTI request body to fill (PDCCH+PDSCH PDUs)
|
||||||
|
* @param pdu_index TX_DATA PDU index linking PDSCH grant to payload
|
||||||
|
* @param beam_index Internal beam index */
|
||||||
|
static void nr_fill_nfapi_dl_PCCH_pdu(gNB_MAC_INST *mac,
|
||||||
|
NR_sched_pdsch_t *pdsch,
|
||||||
|
NR_sched_pdcch_t *pdcch,
|
||||||
|
NR_SearchSpace_t *search_space,
|
||||||
|
NR_ControlResourceSet_t *coreset,
|
||||||
|
int aggregation_level,
|
||||||
|
int cce_index,
|
||||||
|
nfapi_nr_dl_tti_request_body_t *dl_req,
|
||||||
|
int pdu_index,
|
||||||
|
int beam_index)
|
||||||
|
{
|
||||||
|
const int CC_id = 0;
|
||||||
|
NR_COMMON_channels_t *cc = &mac->common_channels[CC_id];
|
||||||
|
NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
|
||||||
|
const uint16_t pdcch_pdu_size = 4 + sizeof(nfapi_nr_dl_tti_pdcch_pdu);
|
||||||
|
const uint16_t pdsch_pdu_size = 4 + sizeof(nfapi_nr_dl_tti_pdsch_pdu);
|
||||||
|
|
||||||
|
nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdcch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs];
|
||||||
|
memset(dl_tti_pdcch_pdu, 0, sizeof(*dl_tti_pdcch_pdu));
|
||||||
|
dl_tti_pdcch_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE;
|
||||||
|
dl_tti_pdcch_pdu->PDUSize = pdcch_pdu_size;
|
||||||
|
dl_req->nPDUs += 1;
|
||||||
|
nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15;
|
||||||
|
nr_configure_pdcch(pdcch_pdu_rel15, coreset, pdcch);
|
||||||
|
|
||||||
|
nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs];
|
||||||
|
memset(dl_tti_pdsch_pdu, 0, sizeof(*dl_tti_pdsch_pdu));
|
||||||
|
dl_tti_pdsch_pdu->PDUType = NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE;
|
||||||
|
dl_tti_pdsch_pdu->PDUSize = pdsch_pdu_size;
|
||||||
|
dl_req->nPDUs += 1;
|
||||||
|
|
||||||
|
const uint16_t fapi_beam = convert_to_fapi_beam(beam_index, mac->beam_info.beam_mode);
|
||||||
|
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 =
|
||||||
|
prepare_pdsch_pdu(dl_tti_pdsch_pdu, mac, NULL, pdsch, NULL, false, 0, P_RNTI, fapi_beam, 1, pdu_index);
|
||||||
|
|
||||||
|
nfapi_nr_dl_dci_pdu_t *dci_pdu = prepare_dci_pdu(pdcch_pdu_rel15,
|
||||||
|
scc,
|
||||||
|
search_space,
|
||||||
|
coreset,
|
||||||
|
pdsch->ant_port_idx.spatialStreamIndices,
|
||||||
|
aggregation_level,
|
||||||
|
cce_index,
|
||||||
|
fapi_beam,
|
||||||
|
P_RNTI);
|
||||||
|
pdcch_pdu_rel15->numDlDci++;
|
||||||
|
|
||||||
|
const nr_dci_format_t dci_format = NR_DL_DCI_FORMAT_1_0;
|
||||||
|
const nr_rnti_type_t rnti_type = TYPE_P_RNTI_;
|
||||||
|
dci_pdu_rel15_t dci_payload = prepare_dci_dl_payload(mac,
|
||||||
|
NULL,
|
||||||
|
rnti_type,
|
||||||
|
NR_SearchSpace__searchSpaceType_PR_common,
|
||||||
|
pdsch_pdu_rel15,
|
||||||
|
pdsch,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
false);
|
||||||
|
/* TS 38.212 Table 7.3.1.2.1-1: we are scheduling PCCH-Message on PDSCH, with no short messages, so the
|
||||||
|
* P-RNTI DCI must use SMI=01 (NR_DCI_PRNTI_SMI_PAGING_SCHED_ONLY). */
|
||||||
|
dci_payload.short_messages_indicator = NR_DCI_PRNTI_SMI_PAGING_SCHED_ONLY;
|
||||||
|
|
||||||
|
fill_dci_pdu_rel15(NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
dci_pdu,
|
||||||
|
&dci_payload,
|
||||||
|
dci_format,
|
||||||
|
rnti_type,
|
||||||
|
0,
|
||||||
|
search_space,
|
||||||
|
coreset,
|
||||||
|
0,
|
||||||
|
mac->cset0_bwp_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Returns true if (frame, slot) is a paging occasion (PO) for a given UE.
|
||||||
|
*
|
||||||
|
* Implements TS 38.304 §7.1 PF/PO determination and the mapping to PDCCH
|
||||||
|
* monitoring occasions based on the configured paging search space.
|
||||||
|
*
|
||||||
|
* Scope: CN-initiated paging in RRC_IDLE only (UE_ID = 5G-S-TMSI mod 1024).
|
||||||
|
*
|
||||||
|
* - PF (Paging Frame) condition: (SFN + PF_offset) mod T = (T / N) * (UE_ID mod N)
|
||||||
|
* - PO (Paging Occasion) index: i_s = floor(UE_ID / N) mod Ns
|
||||||
|
* where T, N, Ns and PF_offset are derived from PCCH-Config (SIB1), and
|
||||||
|
* UE_ID is 5G-S-TMSI mod 1024.
|
||||||
|
*
|
||||||
|
* For SearchSpaceId = 0, Ns is 1 or 2 and this function reuses the Type0-PDCCH
|
||||||
|
* (RMSI) timing per TS 38.213 §13 (Type0 CSS) to decide the slot(s) belonging
|
||||||
|
* to the PO. For SearchSpaceId != 0 (Type2), the PO is S*X consecutive PDCCH
|
||||||
|
* monitoring occasions (MOs), where S is the number of actually transmitted
|
||||||
|
* SSBs (derived from ssb-PositionsInBurst in SIB1) and X is the number of
|
||||||
|
* PDCCH MOs per SSB in the PO (nrofPDCCH-MonitoringOccasionPerSSB-InPO if
|
||||||
|
* configured, otherwise X = 1). The [x*S+K]-th MO in the PO maps to the K-th
|
||||||
|
* transmitted SSB, per TS 38.304 §7.1.
|
||||||
|
*
|
||||||
|
* A PO (frame, slot) is valid if it is a MO of the paging search space and its
|
||||||
|
* index within the PF falls in the prescribed range. When configured,
|
||||||
|
* firstPDCCH-MonitoringOccasionOfPO provides the start MO index of the
|
||||||
|
* (i_s+1)-th PO, otherwise it defaults to i_s*S*X (the first PO).
|
||||||
|
*
|
||||||
|
* @param pcch PCCH-Config from SIB1 (N, PF_offset, Ns, T)
|
||||||
|
* @param frame System frame number
|
||||||
|
* @param slot Slot index within the frame
|
||||||
|
* @param ue_id UE_ID used in computation of PF/PO (5G-S-TMSI mod 1024)
|
||||||
|
* @param mac pointer to gNB MAC instance
|
||||||
|
* @param scc pointer to ServingCellConfigCommon
|
||||||
|
* @return true if (frame, slot) is a paging occasion for ue_id, false otherwise. */
|
||||||
|
static bool is_paging_occasion(const NR_PCCH_Config_t *pcch,
|
||||||
|
uint16_t frame,
|
||||||
|
uint16_t slot,
|
||||||
|
uint16_t ue_id,
|
||||||
|
gNB_MAC_INST *mac,
|
||||||
|
NR_ServingCellConfigCommon_t *scc)
|
||||||
|
{
|
||||||
|
DevAssert(pcch);
|
||||||
|
DevAssert(mac);
|
||||||
|
DevAssert(scc);
|
||||||
|
|
||||||
|
/* TS 38.213 §10.1 (Type2-PDCCH CSS on the primary cell of the MCG, i.e. the PCell) /
|
||||||
|
* TS 38.331 PDCCH-ConfigCommon: If a UE is not provided pagingSearchSpace for Type2-PDCCH
|
||||||
|
* CSS set, the UE does not monitor PDCCH for Type2-PDCCH CSS set on the DL BWP. */
|
||||||
|
NR_SearchSpace_t *ss = get_paging_search_space(scc);
|
||||||
|
if (ss == NULL) {
|
||||||
|
LOG_D(NR_MAC, "[%04d.%02d][gNB %d] No pagingSearchSpace configured for PCCH (UE_ID=%u)\n", frame, slot, mac->Mod_id, ue_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* T: DRX cycle of the UE in radio frames (TS 38.304 §7.1). */
|
||||||
|
const uint16_t T = nr_pcch_default_paging_cycle_rf(pcch);
|
||||||
|
uint16_t N;
|
||||||
|
uint8_t PF_offset;
|
||||||
|
/** N and PF_offset: derived from nAndPagingFrameOffset (TS 38.331 PCCH-Config), per TS 38.304 §7.1.
|
||||||
|
* N spreads UEs across the T radio frames so that each UE has exactly
|
||||||
|
* one PF per DRX cycle. Larger N means more PFs per cycle. It is encoded in nAndPagingFrameOffset.
|
||||||
|
* Valid N depends on pagingSearchSpace, SS/PBCH block and CORESET multiplexing pattern (TS 38.213),
|
||||||
|
* and ssb-periodicityServingCell: this function uses the configured value. Validity is enforced
|
||||||
|
* when building SIB1 / PCCH-Config. */
|
||||||
|
nr_pcch_n_and_paging_frame_offset(pcch, T, &N, &PF_offset);
|
||||||
|
/* Ns: number of paging occasions per paging frame (TS 38.331 PCCH-Config). */
|
||||||
|
const uint8_t Ns = nr_pcch_ns_per_pf(pcch);
|
||||||
|
|
||||||
|
/* TS 38.304 §7.1 Paging Frame condition for which this SFN is a PF for ue_id */
|
||||||
|
if (!nr_pcch_sfn_is_pf(frame, PF_offset, T, N, ue_id)) {
|
||||||
|
LOG_D(NR_MAC,
|
||||||
|
"[%04d.%02d][gNB %d] not in PF (UE_ID=%u T=%u N=%u PF_offset=%u)\n",
|
||||||
|
frame,
|
||||||
|
slot,
|
||||||
|
mac->Mod_id,
|
||||||
|
ue_id,
|
||||||
|
T,
|
||||||
|
N,
|
||||||
|
PF_offset);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TS 38.304 §7.1 Paging Occasion index in this PF
|
||||||
|
* The UE then monitors the (i_s + 1)-th PO within this PF. */
|
||||||
|
const uint8_t i_s = nr_pcch_po_index(ue_id, N, Ns);
|
||||||
|
const long ss_id = ss->searchSpaceId;
|
||||||
|
LOG_D(NR_MAC,
|
||||||
|
"[%04d.%03d] [gNB %d] in PF for UE_ID=%u (i_s=%u Ns=%u ss_id=%ld)\n",
|
||||||
|
frame,
|
||||||
|
slot,
|
||||||
|
mac->Mod_id,
|
||||||
|
ue_id,
|
||||||
|
i_s,
|
||||||
|
Ns,
|
||||||
|
ss_id);
|
||||||
|
|
||||||
|
/* TS 38.304 §7.1 + TS 38.213 §10.1: PO slot timing within the PF depends on pagingSearchSpace (SearchSpaceId).
|
||||||
|
*
|
||||||
|
* If pagingSearchSpace identifies SearchSpaceId = 0 (TS 38.213 §10.1): the UE uses PDCCH monitoring
|
||||||
|
* occasions as for Type0/RMSI (TS 38.213 Clause 13), same occasions as for RMSI. TS 38.304 §7.1 then restricts
|
||||||
|
* Ns to 1 or 2 only for this case:
|
||||||
|
* Ns = 1: PO starts at the first paging MO in the PF, delegate to Type0 occasion check.
|
||||||
|
* Ns = 2: PO occupies the first or second half of the PF according to i_s (0 or 1).
|
||||||
|
*
|
||||||
|
* If SearchSpaceId != 0 (e.g. 2): Type2-PDCCH CSS per §10.1. Paging timing is based on
|
||||||
|
* firstPDCCH-MonitoringOccasionOfPO and nrofPDCCH-MonitoringOccasionPerSSB-InPO. PO spans
|
||||||
|
* S*X consecutive MOs (handled below). */
|
||||||
|
if (ss_id == 0) {
|
||||||
|
/* TS 38.304 §7.1: When SearchSpaceId = 0 for pagingSearchSpace, Ns is either 1 or 2. */
|
||||||
|
AssertFatal(Ns <= 2, "TS 38.304 §7.1: Ns=%u invalid when pagingSearchSpace is SearchSpaceId 0 (must be 1 or 2)\n", Ns);
|
||||||
|
|
||||||
|
/* Ns = 1: single PO in the PF, starting at the first PDCCH MO for paging (same MOs as RMSI, TS 38.213 §13). */
|
||||||
|
if (Ns == 1)
|
||||||
|
return is_type0_occasion_paging(mac, scc, frame, slot);
|
||||||
|
|
||||||
|
/* Ns = 2: PO in first half (i_s = 0) or second half (i_s = 1) of the PF (TS 38.304 §7.1). */
|
||||||
|
if (Ns == 2) {
|
||||||
|
const int n_slots_frame = mac->frame_structure.numb_slots_frame;
|
||||||
|
return nr_pcch_ss0_po_half_frame(i_s, slot, n_slots_frame);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
/* Type2 paging (SearchSpaceId != 0), TS 38.304 §7.1, TS 38.331 PCCH-Config, TS 38.213 §10.1:
|
||||||
|
* The (i_s+1)-th PO is S*X consecutive PDCCH monitoring occasions (MOs) in the PF.
|
||||||
|
* - S = number of actually transmitted SSBs (ssb-PositionsInBurst in SIB1, TS 38.304 §7.1)
|
||||||
|
* - X = nrofPDCCH-MonitoringOccasionPerSSB-InPO if present, else 1
|
||||||
|
* - firstPDCCH-MonitoringOccasionOfPO: when present, (i_s+1)th entry gives start_mo; when absent,
|
||||||
|
* default is start_mo = i_s*S*X (TS 38.331)
|
||||||
|
* - MO slots follow monitoringSlotPeriodicityAndOffset (TS 38.213 §10.1): slot indices offset + k*period.
|
||||||
|
* - Simplifications:
|
||||||
|
* - MOs that overlap UL symbols per tdd-UL-DL-ConfigurationCommon are not excluded from numbering (TS 38.304 §7.1)
|
||||||
|
* - PO evaluation is PF-local only (a PO may span multiple frames / search-space periods).
|
||||||
|
* - MO indices within the PF are numbered from the first paging MO slot in this frame: current slot must fall in
|
||||||
|
* [start_mo, end_mo].
|
||||||
|
*
|
||||||
|
* Note: this implementation assumes one paging MO per matched slot (typical for duration=1 and one
|
||||||
|
* monitoringSymbolsWithinSlot group). For other cases (duration>1 or multiple groups), the MO index
|
||||||
|
* calculation needs to be adjusted. */
|
||||||
|
int period = 0;
|
||||||
|
int offset = 0;
|
||||||
|
get_monitoring_period_offset(ss, &period, &offset);
|
||||||
|
const int n_slots_frame = mac->frame_structure.numb_slots_frame;
|
||||||
|
|
||||||
|
uint8_t ssb_len = 0;
|
||||||
|
const uint64_t ssb_bmp = get_ssb_bitmap_and_len(scc, &ssb_len);
|
||||||
|
const uint64_t ssb_bits = ssb_bmp >> (64 - ssb_len);
|
||||||
|
const int S = count_bits64(ssb_bits);
|
||||||
|
AssertFatal(S > 0, "ssb-PositionsInBurst has no transmitted SSB (S must be >= 1 for paging)\n");
|
||||||
|
int X = 1;
|
||||||
|
if (pcch->ext1 != NULL && pcch->ext1->nrofPDCCH_MonitoringOccasionPerSSB_InPO_r16 != NULL) {
|
||||||
|
X = *pcch->ext1->nrofPDCCH_MonitoringOccasionPerSSB_InPO_r16;
|
||||||
|
AssertFatal(X >= 2 && X <= NR_PCCH_MAX_MO_PER_SSB_IN_PO,
|
||||||
|
"TS 38.331 PCCH-Config: nrofPDCCH-MonitoringOccasionPerSSB-InPO-r16=%d out of range (2..%d)\n",
|
||||||
|
X,
|
||||||
|
NR_PCCH_MAX_MO_PER_SSB_IN_PO);
|
||||||
|
}
|
||||||
|
int start_mo = i_s * S * X;
|
||||||
|
if (pcch->firstPDCCH_MonitoringOccasionOfPO)
|
||||||
|
nr_pcch_first_pdcch_start_mo(pcch->firstPDCCH_MonitoringOccasionOfPO, i_s, &start_mo);
|
||||||
|
int end_mo = start_mo + S * X - 1;
|
||||||
|
|
||||||
|
/* TS 38.304 §7.1: PDCCH monitoring occasions for paging in the PF are sequentially numbered from zero
|
||||||
|
* starting from the first such occasion. TS 38.213: MOs at offset + k*period; k0 = first in PF, k = current. */
|
||||||
|
return nr_pcch_type2_po_mo_in_range(frame, slot, n_slots_frame, period, offset, start_mo, end_mo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
frame_t frame;
|
||||||
|
slot_t slot;
|
||||||
|
const NR_PCCH_Config_t *pcch;
|
||||||
|
gNB_MAC_INST *mac;
|
||||||
|
NR_ServingCellConfigCommon_t *scc;
|
||||||
|
} nr_mac_pcch_po_ctx_t;
|
||||||
|
|
||||||
|
/** @brief TS 38.304 §7.1: transmit Paging only at the UE's paging occasion (PF/PO).
|
||||||
|
*
|
||||||
|
* This function checks if the current (frame, slot) is a paging occasion for the given UE_ID.
|
||||||
|
* It returns true if the current (frame, slot) is a paging occasion for the given UE_ID, false otherwise.
|
||||||
|
*
|
||||||
|
* @param data Queued head ue_id
|
||||||
|
* @param user This TTI frame, slot, pcch, mac, scc). PO is per-item and per-slot.
|
||||||
|
* @return true if (frame, slot) is a DL slot and a paging occasion for data's ue_id */
|
||||||
|
static bool nr_mac_pcch_po_match(const void *data, void *user)
|
||||||
|
{
|
||||||
|
const nr_mac_pcch_record_t *item = data;
|
||||||
|
const nr_mac_pcch_po_ctx_t *ctx = user;
|
||||||
|
|
||||||
|
if (!is_dl_slot(ctx->slot, &ctx->mac->frame_structure))
|
||||||
|
return false;
|
||||||
|
return is_paging_occasion(ctx->pcch, ctx->frame, ctx->slot, item->ue_id, ctx->mac, ctx->scc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Schedule PCCH (paging) at the UE's paging occasion for the current (frame, slot).
|
||||||
|
*
|
||||||
|
* In the good case the gNB sends paging once per received NGAP PAGING (one radio page
|
||||||
|
* per cell, TS 38.413 §8.5.1.2), at the UE's PO (TS 38.304 §7.1).
|
||||||
|
*
|
||||||
|
* The network initiates paging by transmitting the Paging message at the UE's paging
|
||||||
|
* occasion as specified in TS 38.304 §7.1 and TS 38.331 §5.3.2. Pending paging records
|
||||||
|
* are dequeued at PO, PCCH SDU is encoded, then scheduled on PDCCH/PDSCH with P-RNTI.
|
||||||
|
*
|
||||||
|
* PDCCH monitoring occasions and aggregation levels for paging follow TS 38.213 (Type0/Type2
|
||||||
|
* PDCCH CSS for paging).
|
||||||
|
*
|
||||||
|
* The network may address multiple UEs in one Paging message (one PagingRecord per UE).
|
||||||
|
* This function is called every TTI from the DL scheduler. It returns without scheduling
|
||||||
|
* if (frameP, slotP) is not a paging occasion for the stored UE_ID or if there is no PCCH payload.
|
||||||
|
*
|
||||||
|
* @param mac gNB MAC instance (common channels and RRC cell config)
|
||||||
|
* @param frameP Current SFN
|
||||||
|
* @param slotP Current slot
|
||||||
|
* @param DL_req DL TTI request to fill with PDCCH/PDSCH for P-RNTI
|
||||||
|
* @param TX_req TX data request for PDSCH payload */
|
||||||
|
void schedule_nr_pcch(gNB_MAC_INST *mac,
|
||||||
|
frame_t frameP,
|
||||||
|
slot_t slotP,
|
||||||
|
nfapi_nr_dl_tti_request_t *DL_req,
|
||||||
|
nfapi_nr_tx_data_request_t *TX_req)
|
||||||
|
{
|
||||||
|
DevAssert(mac);
|
||||||
|
DevAssert(DL_req);
|
||||||
|
DevAssert(TX_req);
|
||||||
|
|
||||||
|
const int CC_id = 0;
|
||||||
|
NR_COMMON_channels_t *cc = &mac->common_channels[CC_id];
|
||||||
|
NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
|
||||||
|
DevAssert(scc);
|
||||||
|
DevAssert(scc->downlinkConfigCommon);
|
||||||
|
|
||||||
|
/* PCCH-Config is in SIB1 (DownlinkConfigCommonSIB) */
|
||||||
|
DevAssert(cc->sib1);
|
||||||
|
DevAssert(cc->sib1->message.choice.c1);
|
||||||
|
NR_SIB1_t *sib1 = cc->sib1->message.choice.c1->choice.systemInformationBlockType1;
|
||||||
|
DevAssert(sib1);
|
||||||
|
DevAssert(sib1->servingCellConfigCommon);
|
||||||
|
const NR_PCCH_Config_t *pcch = &sib1->servingCellConfigCommon->downlinkConfigCommon.pcch_Config;
|
||||||
|
|
||||||
|
nr_mac_pcch_po_ctx_t po_ctx = {
|
||||||
|
.frame = frameP,
|
||||||
|
.slot = slotP,
|
||||||
|
.pcch = pcch,
|
||||||
|
.mac = mac,
|
||||||
|
.scc = scc,
|
||||||
|
};
|
||||||
|
/* Collect every pending record whose paging occasion is this (frame, slot) and encode
|
||||||
|
* them into one PCCH-Message (TS 38.331 §5.3.2 / Paging, up to 32 records).
|
||||||
|
* TS 38.304 §7.1: the gNB transmits Paging at each UE's PO: UEs that share the same PO
|
||||||
|
* (same PF/PO index from ue_id) are paged in the same P-RNTI transmission - one PagingRecord
|
||||||
|
* per UE in the same PDU (PCCH-Message). */
|
||||||
|
nr_mac_pcch_record_t pcch_batch[NR_PCCH_MAX_PAGING_RECORDS];
|
||||||
|
const int batch_count = spsc_q_get_while(&cc->pcch_queue,
|
||||||
|
nr_mac_pcch_po_match,
|
||||||
|
&po_ctx,
|
||||||
|
pcch_batch,
|
||||||
|
sizeof(pcch_batch[0]),
|
||||||
|
NR_PCCH_MAX_PAGING_RECORDS);
|
||||||
|
if (batch_count <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// All records in this batch matched the same (frame, slot), so they share one PO and therefore the same ue_id
|
||||||
|
const uint16_t pcch_ue_id = pcch_batch[0].ue_id;
|
||||||
|
nr_paging_params_t paging_params[NR_PCCH_MAX_PAGING_RECORDS];
|
||||||
|
for (int i = 0; i < batch_count; i++) {
|
||||||
|
/* One PagingRecord per batch entry. CN-initiated paging (NGAP/F1AP) sets PagingUE-Identity to
|
||||||
|
* ng-5G-S-TMSI from the enqueued identity, RAN-initiated paging uses fullI-RNTI (TS 38.331 §6.2.2). */
|
||||||
|
paging_params[i] = (nr_paging_params_t){
|
||||||
|
.ue_identity_type = NR_PagingUE_Identity_PR_ng_5G_S_TMSI,
|
||||||
|
.ue_identity = {.fiveg_s_tmsi = pcch_batch[i].fiveg_s_tmsi},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TS 38.331 §6.2.2: build PCCH-Message (Paging) with pagingRecordList. */
|
||||||
|
byte_array_t pcch_sdu = do_NR_Paging(batch_count, paging_params);
|
||||||
|
if (!pcch_sdu.buf || pcch_sdu.len == 0) {
|
||||||
|
LOG_E(NR_MAC,
|
||||||
|
"[%04d.%02d][gNB %d] do_NR_Paging failed (UE_ID=%u, %d record(s)), re-enqueue\n",
|
||||||
|
frameP,
|
||||||
|
slotP,
|
||||||
|
mac->Mod_id,
|
||||||
|
pcch_ue_id,
|
||||||
|
batch_count);
|
||||||
|
/* PCCH-Message encode failed at this PO: re-queue for next matching PO. */
|
||||||
|
nr_mac_pcch_queue_reenqueue(&cc->pcch_queue, mac->Mod_id, pcch_batch, batch_count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_I(NR_MAC,
|
||||||
|
"[%04d.%02d][gNB %d] Paging occasion for PCCH: UE_ID=%u records=%d pcch_pdu_len=%zu\n",
|
||||||
|
frameP,
|
||||||
|
slotP,
|
||||||
|
mac->Mod_id,
|
||||||
|
pcch_ue_id,
|
||||||
|
batch_count,
|
||||||
|
pcch_sdu.len);
|
||||||
|
|
||||||
|
/* pagingSearchSpace (Type2-PDCCH CSS) */
|
||||||
|
NR_SearchSpace_t *ss = get_paging_search_space(scc);
|
||||||
|
DevAssert(ss != NULL);
|
||||||
|
|
||||||
|
/* TS 38.213 §10.1: pagingSearchSpace (Type2-PDCCH CSS) references the controlResourceSetId of the CORESET
|
||||||
|
* used for PDCCH paging monitoring occasions. */
|
||||||
|
AssertFatal(ss->controlResourceSetId,
|
||||||
|
"schedule_nr_pcch: paging search space id %ld has NULL controlResourceSetId\n",
|
||||||
|
ss->searchSpaceId);
|
||||||
|
NR_ControlResourceSet_t *coreset = get_coreset(mac, scc, NULL, *ss->controlResourceSetId);
|
||||||
|
|
||||||
|
/* Beam selection for this paging occasion.
|
||||||
|
* Spec (TS 38.304 §7.1, multi-beam): the same paging message and Short Message are repeated in all
|
||||||
|
* transmitted beams. We currently transmit paging on a single SSB/beam (the first active SSB) per
|
||||||
|
* occasion. TODO: extend to per-beam repetition. */
|
||||||
|
int ssb_for_paging = 0;
|
||||||
|
if (cc->num_active_ssb > 0)
|
||||||
|
ssb_for_paging = cc->ssb_index[0];
|
||||||
|
int beam_index = get_beam_from_ssbidx(mac, ssb_for_paging);
|
||||||
|
const int n_slots_frame = mac->frame_structure.numb_slots_frame;
|
||||||
|
NR_beam_alloc_t beam = beam_allocation_procedure(&mac->beam_info, frameP, slotP, beam_index, n_slots_frame);
|
||||||
|
AssertFatal(beam.idx >= 0, "Cannot allocate beam for PCCH paging (ssb=%d)\n", ssb_for_paging);
|
||||||
|
|
||||||
|
/* Determine CCE aggregation level and allocate CCE for PCCH PDCCH in the paging search space (Type2-PDCCH CSS set),
|
||||||
|
* configured by pagingSearchSpace in PDCCH-ConfigCommon for DCI format 1_0 with CRC scrambled by P-RNTI
|
||||||
|
* on the primary cell of the MCG. Aggregation levels and PDCCH candidates follow TS 38.213 §10.1 and Table 10.1-1;
|
||||||
|
* PRBs used by this PDCCH are then reserved in the VRB map. */
|
||||||
|
NR_BWP_t *initial_dl_bwp = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters;
|
||||||
|
NR_sched_pdcch_t sched_pdcch = set_pdcch_structure(mac, ss, coreset, scc, initial_dl_bwp, mac->type0_PDCCH_CSS_config);
|
||||||
|
int aggregation_level = 0;
|
||||||
|
int CCEIndex = get_cce_index(mac, CC_id, slotP, 0, &aggregation_level, beam.idx, ss, coreset, &sched_pdcch, 0.0f);
|
||||||
|
if (CCEIndex < 0) {
|
||||||
|
LOG_W(NR_MAC,
|
||||||
|
"[%04d.%02d][gNB %d] no free CCE for PCCH (UE_ID=%u, records=%d), re-enqueue\n",
|
||||||
|
frameP,
|
||||||
|
slotP,
|
||||||
|
mac->Mod_id,
|
||||||
|
pcch_ue_id,
|
||||||
|
batch_count);
|
||||||
|
/* No PDCCH resources at this PO: retry in a later cycle */
|
||||||
|
nr_mac_pcch_queue_reenqueue(&cc->pcch_queue, mac->Mod_id, pcch_batch, batch_count);
|
||||||
|
free_byte_array(pcch_sdu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fill_pdcch_vrb_map(mac, CC_id, &sched_pdcch, CCEIndex, aggregation_level, beam.idx);
|
||||||
|
|
||||||
|
/* Allocate PDSCH for PCCH and ensure TBS >= payload, using:
|
||||||
|
* - TimeDomainAllocationList for common PDSCH on initial DL BWP
|
||||||
|
* - TS 38.214 §5.1 (time-domain allocation) and §5.1.3.2 (TBS computation for PDSCH).
|
||||||
|
* Try TDA entries in order and keep the first one whose RB/MCS/TBS allocation fits the payload. */
|
||||||
|
NR_PDSCH_ConfigCommon_t *pdsch_cfg_common = scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup;
|
||||||
|
NR_PDSCH_TimeDomainResourceAllocationList_t *tdalist = pdsch_cfg_common->pdsch_TimeDomainAllocationList;
|
||||||
|
DevAssert(tdalist);
|
||||||
|
AssertFatal(tdalist->list.count > 0, "PCCH-Config: pdsch-TimeDomainAllocationList is empty\n");
|
||||||
|
|
||||||
|
uint16_t *vrb_map = cc->vrb_map[beam.idx];
|
||||||
|
const uint16_t *sidx = mac->radio_config.spatial_stream_index;
|
||||||
|
NR_sched_pdsch_t pdsch_pcch = {0};
|
||||||
|
bool pdsch_ok = false;
|
||||||
|
for (int t = 0; t < tdalist->list.count && !pdsch_ok; t++) {
|
||||||
|
NR_tda_info_t tda_info = set_tda_info_from_list(tdalist, t);
|
||||||
|
NR_pdsch_dmrs_t dmrs_parms = get_dl_dmrs_params(scc, NULL, &tda_info, 1);
|
||||||
|
pdsch_pcch = (NR_sched_pdsch_t){
|
||||||
|
.bwp_info = get_pdsch_bwp_start_size(mac, NULL),
|
||||||
|
.time_domain_allocation = t,
|
||||||
|
.dmrs_parms = dmrs_parms,
|
||||||
|
.tda_info = tda_info,
|
||||||
|
.nrOfLayers = 1,
|
||||||
|
.pm_index = 0,
|
||||||
|
.mcs = 0,
|
||||||
|
.ant_port_idx = {.numSpatialStreamIndices = 1, .spatialStreamIndices[0] = sidx[beam.idx]},
|
||||||
|
};
|
||||||
|
pdsch_ok = update_rb_mcs_tbs(&pdsch_pcch, pcch_sdu.len, vrb_map);
|
||||||
|
}
|
||||||
|
if (!pdsch_ok) {
|
||||||
|
LOG_W(NR_MAC,
|
||||||
|
"[%04d.%02d][gNB %d] cannot allocate PDSCH for PCCH after trying %d TDA entries (UE_ID=%u len=%zu records=%d), re-enqueue\n",
|
||||||
|
frameP,
|
||||||
|
slotP,
|
||||||
|
mac->Mod_id,
|
||||||
|
tdalist->list.count,
|
||||||
|
pcch_ue_id,
|
||||||
|
pcch_sdu.len,
|
||||||
|
batch_count);
|
||||||
|
/* No PDSCH resources at this PO: retry in a later cycle */
|
||||||
|
nr_mac_pcch_queue_reenqueue(&cc->pcch_queue, mac->Mod_id, pcch_batch, batch_count);
|
||||||
|
free_byte_array(pcch_sdu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint16_t slbitmap = SL_to_bitmap(pdsch_pcch.tda_info.startSymbolIndex, pdsch_pcch.tda_info.nrOfSymbols);
|
||||||
|
const int bwp_start = pdsch_pcch.bwp_info.bwpStart;
|
||||||
|
for (int rb = 0; rb < pdsch_pcch.rbSize; rb++)
|
||||||
|
vrb_map[rb + pdsch_pcch.rbStart + bwp_start] |= slbitmap;
|
||||||
|
|
||||||
|
/* Build NFAPI DL_TTI.request and TX_DATA.request entries for PCCH:
|
||||||
|
* - SCF/NFAPI DL_TTI PDCCH/PDSCH PDUs for P-RNTI (DCI 1_0)
|
||||||
|
* - TX_data PDU carrying the PCCH payload, linked via PDU_index. */
|
||||||
|
nfapi_nr_dl_tti_request_body_t *dl_req_body = &DL_req->dl_tti_request_body;
|
||||||
|
int pdu_index = mac->pdu_index[CC_id]++;
|
||||||
|
nr_fill_nfapi_dl_PCCH_pdu(mac,
|
||||||
|
&pdsch_pcch,
|
||||||
|
&sched_pdcch,
|
||||||
|
ss,
|
||||||
|
coreset,
|
||||||
|
aggregation_level,
|
||||||
|
CCEIndex,
|
||||||
|
dl_req_body,
|
||||||
|
pdu_index,
|
||||||
|
beam.idx);
|
||||||
|
|
||||||
|
const int ntx_req = TX_req->Number_of_PDUs;
|
||||||
|
nfapi_nr_pdu_t *tx_req = &TX_req->pdu_list[ntx_req];
|
||||||
|
DevAssert(pdsch_pcch.tb_size >= pcch_sdu.len);
|
||||||
|
DevAssert(pdsch_pcch.tb_size <= sizeof(tx_req->TLVs[0].value.direct));
|
||||||
|
memset(tx_req->TLVs[0].value.direct, 0, pdsch_pcch.tb_size);
|
||||||
|
memcpy(tx_req->TLVs[0].value.direct, pcch_sdu.buf, pcch_sdu.len);
|
||||||
|
free_byte_array(pcch_sdu);
|
||||||
|
tx_req->PDU_index = pdu_index;
|
||||||
|
tx_req->num_TLV = 1;
|
||||||
|
tx_req->TLVs[0].length = pdsch_pcch.tb_size;
|
||||||
|
tx_req->PDU_length = compute_PDU_length(tx_req->num_TLV, tx_req->TLVs[0].length);
|
||||||
|
TX_req->Number_of_PDUs++;
|
||||||
|
TX_req->SFN = frameP;
|
||||||
|
TX_req->Slot = slotP;
|
||||||
|
|
||||||
|
LOG_I(NR_MAC,
|
||||||
|
"[%04d.%02d][gNB %d] PCCH: UE_ID=%u records=%d ss=%ld cset=%ld beam=%d agg=%d CCE=%d tb=%d\n",
|
||||||
|
frameP,
|
||||||
|
slotP,
|
||||||
|
mac->Mod_id,
|
||||||
|
pcch_ue_id,
|
||||||
|
batch_count,
|
||||||
|
ss->searchSpaceId,
|
||||||
|
*ss->controlResourceSetId,
|
||||||
|
beam.idx,
|
||||||
|
aggregation_level,
|
||||||
|
CCEIndex,
|
||||||
|
pdsch_pcch.tb_size);
|
||||||
|
}
|
||||||
|
|||||||
@@ -92,6 +92,11 @@ void nr_ulsch_preprocessor(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp_pusch)
|
|||||||
void nr_mac_pcch_queue_init(NR_COMMON_channels_t *cc);
|
void nr_mac_pcch_queue_init(NR_COMMON_channels_t *cc);
|
||||||
void nr_mac_pcch_queue_free(NR_COMMON_channels_t *cc);
|
void nr_mac_pcch_queue_free(NR_COMMON_channels_t *cc);
|
||||||
void nr_mac_pcch_enqueue(module_id_t module_id, uint64_t fiveg_s_tmsi, uint16_t ue_id);
|
void nr_mac_pcch_enqueue(module_id_t module_id, uint64_t fiveg_s_tmsi, uint16_t ue_id);
|
||||||
|
void schedule_nr_pcch(gNB_MAC_INST *gNB_mac,
|
||||||
|
frame_t frameP,
|
||||||
|
slot_t slotP,
|
||||||
|
nfapi_nr_dl_tti_request_t *DL_req,
|
||||||
|
nfapi_nr_tx_data_request_t *TX_req);
|
||||||
|
|
||||||
////// Random Access MAC-PHY interface functions and primitives ///////
|
////// Random Access MAC-PHY interface functions and primitives ///////
|
||||||
|
|
||||||
|
|||||||
@@ -3758,93 +3758,6 @@ void rrc_gNB_generate_RRCRelease(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int rrc_gNB_generate_pcch_msg(sctp_assoc_t assoc_id, const NR_SIB1_t *sib1, uint32_t tmsi, uint8_t paging_drx)
|
|
||||||
{
|
|
||||||
instance_t instance = 0;
|
|
||||||
const unsigned int Ttab[4] = {32,64,128,256};
|
|
||||||
uint8_t Tc;
|
|
||||||
uint8_t Tue;
|
|
||||||
uint32_t pfoffset;
|
|
||||||
uint32_t N; /* N: min(T,nB). total count of PF in one DRX cycle */
|
|
||||||
uint32_t Ns = 0; /* Ns: max(1,nB/T) */
|
|
||||||
uint32_t T; /* DRX cycle */
|
|
||||||
uint8_t buffer[NR_RRC_BUF_SIZE];
|
|
||||||
|
|
||||||
/* get default DRX cycle from configuration */
|
|
||||||
Tc = sib1->servingCellConfigCommon->downlinkConfigCommon.pcch_Config.defaultPagingCycle;
|
|
||||||
|
|
||||||
Tue = paging_drx;
|
|
||||||
/* set T = min(Tc,Tue) */
|
|
||||||
T = Tc < Tue ? Ttab[Tc] : Ttab[Tue];
|
|
||||||
/* set N = PCCH-Config->nAndPagingFrameOffset */
|
|
||||||
switch (sib1->servingCellConfigCommon->downlinkConfigCommon.pcch_Config.nAndPagingFrameOffset.present) {
|
|
||||||
case NR_PCCH_Config__nAndPagingFrameOffset_PR_oneT:
|
|
||||||
N = T;
|
|
||||||
pfoffset = 0;
|
|
||||||
break;
|
|
||||||
case NR_PCCH_Config__nAndPagingFrameOffset_PR_halfT:
|
|
||||||
N = T/2;
|
|
||||||
pfoffset = 1;
|
|
||||||
break;
|
|
||||||
case NR_PCCH_Config__nAndPagingFrameOffset_PR_quarterT:
|
|
||||||
N = T/4;
|
|
||||||
pfoffset = 3;
|
|
||||||
break;
|
|
||||||
case NR_PCCH_Config__nAndPagingFrameOffset_PR_oneEighthT:
|
|
||||||
N = T/8;
|
|
||||||
pfoffset = 7;
|
|
||||||
break;
|
|
||||||
case NR_PCCH_Config__nAndPagingFrameOffset_PR_oneSixteenthT:
|
|
||||||
N = T/16;
|
|
||||||
pfoffset = 15;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_E(RRC, "[gNB %ld] In rrc_gNB_generate_pcch_msg: pfoffset error (pfoffset %d)\n",
|
|
||||||
instance, sib1->servingCellConfigCommon->downlinkConfigCommon.pcch_Config.nAndPagingFrameOffset.present);
|
|
||||||
return (-1);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (sib1->servingCellConfigCommon->downlinkConfigCommon.pcch_Config.ns) {
|
|
||||||
case NR_PCCH_Config__ns_four:
|
|
||||||
if(*sib1->servingCellConfigCommon->downlinkConfigCommon.initialDownlinkBWP.pdcch_ConfigCommon->choice.setup->pagingSearchSpace == 0){
|
|
||||||
LOG_E(RRC, "[gNB %ld] In rrc_gNB_generate_pcch_msg: ns error only 1 or 2 is allowed when pagingSearchSpace is 0\n",
|
|
||||||
instance);
|
|
||||||
return (-1);
|
|
||||||
} else {
|
|
||||||
Ns = 4;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NR_PCCH_Config__ns_two:
|
|
||||||
Ns = 2;
|
|
||||||
break;
|
|
||||||
case NR_PCCH_Config__ns_one:
|
|
||||||
Ns = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_E(RRC, "[gNB %ld] In rrc_gNB_generate_pcch_msg: ns error (ns %ld)\n",
|
|
||||||
instance, sib1->servingCellConfigCommon->downlinkConfigCommon.pcch_Config.ns);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
(void) N; /* not used, suppress warning */
|
|
||||||
(void) Ns; /* not used, suppress warning */
|
|
||||||
(void) pfoffset; /* not used, suppress warning */
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Create message for PDCP (DLInformationTransfer_t) */
|
|
||||||
int length = do_NR_Paging(instance, buffer, tmsi);
|
|
||||||
if (length == -1) {
|
|
||||||
LOG_I(NR_RRC, "do_Paging error\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
// TODO, send message to pdcp
|
|
||||||
(void) assoc_id;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* F1AP UE Context Management Procedures */
|
/* F1AP UE Context Management Procedures */
|
||||||
|
|
||||||
/** @brief Fill DRB to Be Setup List for F1 UE Context Setup Request
|
/** @brief Fill DRB to Be Setup List for F1 UE Context Setup Request
|
||||||
|
|||||||
Reference in New Issue
Block a user