Merge branch NR_RRC_harq_hacks into NR_RRC_PDCP
This commit is contained in:
@@ -73,7 +73,9 @@
|
||||
#ifdef UESIM_EXPANSION
|
||||
#define MAX_MOBILES_PER_ENB 256
|
||||
#define MAX_MOBILES_PER_ENB_NB_IoT 256
|
||||
#define MAX_MOBILES_PER_GNB 256
|
||||
#define MAX_eNB 2
|
||||
#define MAX_gNB 2
|
||||
#else
|
||||
#ifdef LARGE_SCALE
|
||||
#define MAX_MOBILES_PER_ENB 128
|
||||
|
||||
@@ -76,3 +76,6 @@ MESSAGE_DEF(NAS_DOWNLINK_DATA_IND, MESSAGE_PRIORITY_MED, NasDlDataInd
|
||||
|
||||
// eNB: realtime -> RRC messages
|
||||
MESSAGE_DEF(RRC_SUBFRAME_PROCESS, MESSAGE_PRIORITY_MED, RrcSubframeProcess, rrc_subframe_process)
|
||||
|
||||
// eNB: RLC -> RRC messages
|
||||
MESSAGE_DEF(RLC_SDU_INDICATION, MESSAGE_PRIORITY_MED, RlcSduIndication, rlc_sdu_indication)
|
||||
|
||||
@@ -87,6 +87,8 @@
|
||||
|
||||
#define RRC_SUBFRAME_PROCESS(mSGpTR) (mSGpTR)->ittiMsg.rrc_subframe_process
|
||||
|
||||
#define RLC_SDU_INDICATION(mSGpTR) (mSGpTR)->ittiMsg.rlc_sdu_indication
|
||||
|
||||
//-------------------------------------------------------------------------------------------//
|
||||
typedef struct RrcStateInd_s {
|
||||
Rrc_State_t state;
|
||||
@@ -429,4 +431,12 @@ typedef struct rrc_subframe_process_s {
|
||||
int CC_id;
|
||||
} RrcSubframeProcess;
|
||||
|
||||
// eNB: RLC -> RRC messages
|
||||
typedef struct rlc_sdu_indication_s {
|
||||
int rnti;
|
||||
int is_successful;
|
||||
int srb_id;
|
||||
int message_id;
|
||||
} RlcSduIndication;
|
||||
|
||||
#endif /* RRC_MESSAGES_TYPES_H_ */
|
||||
|
||||
@@ -939,7 +939,7 @@ int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Fle
|
||||
|
||||
for (i = 0; i < MAX_MOBILES_PER_ENB; i++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (RC.mac && RC.mac[mod_id] && RC.mac[mod_id]->UE_list.eNB_UE_stats[UE_PCCID(mod_id,i)][i].harq_pid == 1) {
|
||||
if (RC.mac && RC.mac[mod_id] && RC.mac[mod_id]->UE_info.eNB_UE_stats[UE_PCCID(mod_id,i)][i].harq_pid == 1) {
|
||||
available_harq[i] = j;
|
||||
break;
|
||||
}
|
||||
@@ -977,13 +977,13 @@ int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Fle
|
||||
|
||||
dl_info[i]->harq_process_id = available_harq[UE_id];
|
||||
if (RC.mac && RC.mac[mod_id])
|
||||
RC.mac[mod_id]->UE_list.eNB_UE_stats[UE_PCCID(mod_id, UE_id)][UE_id].harq_pid = 0;
|
||||
RC.mac[mod_id]->UE_info.eNB_UE_stats[UE_PCCID(mod_id, UE_id)][UE_id].harq_pid = 0;
|
||||
dl_info[i]->has_harq_process_id = 1;
|
||||
/* Fill in the status of the HARQ process (2 TBs)*/
|
||||
dl_info[i]->n_harq_status = 2;
|
||||
dl_info[i]->harq_status = malloc(sizeof(uint32_t) * dl_info[i]->n_harq_status);
|
||||
for (j = 0; j < dl_info[i]->n_harq_status; j++) {
|
||||
dl_info[i]->harq_status[j] = RC.mac[mod_id]->UE_list.UE_sched_ctrl[UE_id].round[UE_PCCID(mod_id, UE_id)][j];
|
||||
dl_info[i]->harq_status[j] = RC.mac[mod_id]->UE_info.UE_sched_ctrl[UE_id].round[UE_PCCID(mod_id, UE_id)][j];
|
||||
// TODO: This should be different per TB
|
||||
}
|
||||
// LOG_I(FLEXRAN_AGENT, "Sending subframe trigger for frame %d and subframe %d and harq %d (round %d)\n", flexran_get_current_frame(mod_id), (flexran_get_current_subframe(mod_id) + 1) % 10, dl_info[i]->harq_process_id, dl_info[i]->harq_status[0]);
|
||||
@@ -1357,7 +1357,7 @@ void flexran_agent_init_mac_agent(mid_t mod_id) {
|
||||
for (i = 0; i < MAX_MOBILES_PER_ENB; i++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (RC.mac && RC.mac[mod_id])
|
||||
RC.mac[mod_id]->UE_list.eNB_UE_stats[UE_PCCID(mod_id,i)][i].harq_pid = 0;
|
||||
RC.mac[mod_id]->UE_info.eNB_UE_stats[UE_PCCID(mod_id,i)][i].harq_pid = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +290,7 @@ Protocol__FlexUlCqiReport * copy_ul_cqi_report(Protocol__FlexUlCqiReport * origi
|
||||
full_ul_report->has_sfn_sn = original->has_sfn_sn;
|
||||
full_ul_report->n_cqi_meas = original->n_cqi_meas;
|
||||
|
||||
Protocol__FlexUlCqi **ul_report;
|
||||
Protocol__FlexUlCqi **ul_report=NULL;
|
||||
ul_report = malloc(sizeof(Protocol__FlexUlCqi *) * full_ul_report->n_cqi_meas);
|
||||
if(ul_report == NULL)
|
||||
goto error;
|
||||
@@ -348,7 +348,7 @@ Protocol__FlexDlCqiReport * copy_dl_cqi_report(Protocol__FlexDlCqiReport * origi
|
||||
dl_report->has_sfn_sn = original->has_sfn_sn;
|
||||
dl_report->n_csi_report = original->n_csi_report;
|
||||
|
||||
Protocol__FlexDlCsi **csi_reports;
|
||||
Protocol__FlexDlCsi **csi_reports=NULL;
|
||||
csi_reports = malloc(sizeof(Protocol__FlexDlCsi *) * dl_report->n_csi_report);
|
||||
if (csi_reports == NULL)
|
||||
goto error;
|
||||
@@ -383,7 +383,7 @@ Protocol__FlexPagingBufferReport * copy_paging_buffer_report(Protocol__FlexPagin
|
||||
protocol__flex_paging_buffer_report__init(copy);
|
||||
copy->n_paging_info = original->n_paging_info;
|
||||
|
||||
Protocol__FlexPagingInfo **p_info;
|
||||
Protocol__FlexPagingInfo **p_info=NULL;
|
||||
p_info = malloc(sizeof(Protocol__FlexPagingInfo *) * copy->n_paging_info);
|
||||
if (p_info == NULL)
|
||||
goto error;
|
||||
|
||||
@@ -90,6 +90,7 @@ typedef enum {
|
||||
#define CONFIG_STRING_RU_NBIOTRRC_LIST "NbIoT_RRC_instances"
|
||||
#define CONFIG_STRING_RU_SDR_ADDRS "sdr_addrs"
|
||||
#define CONFIG_STRING_RU_SDR_CLK_SRC "clock_src"
|
||||
#define CONFIG_STRING_RU_SDR_TME_SRC "time_src"
|
||||
#define CONFIG_STRING_RU_SF_EXTENSION "sf_extension"
|
||||
#define CONFIG_STRING_RU_END_OF_BURST_DELAY "end_of_burst_delay"
|
||||
#define CONFIG_STRING_RU_OTA_SYNC_ENABLE "ota_sync_enabled"
|
||||
@@ -117,11 +118,12 @@ typedef enum {
|
||||
#define RU_NBIOTRRC_LIST_IDX 18
|
||||
#define RU_SDR_ADDRS 19
|
||||
#define RU_SDR_CLK_SRC 20
|
||||
#define RU_SF_EXTENSION_IDX 21
|
||||
#define RU_END_OF_BURST_DELAY_IDX 22
|
||||
#define RU_OTA_SYNC_ENABLE_IDX 23
|
||||
#define RU_BF_WEIGHTS_LIST_IDX 24
|
||||
#define RU_IF_FREQUENCY 25
|
||||
#define RU_SDR_TME_SRC 21
|
||||
#define RU_SF_EXTENSION_IDX 22
|
||||
#define RU_END_OF_BURST_DELAY_IDX 23
|
||||
#define RU_OTA_SYNC_ENABLE_IDX 24
|
||||
#define RU_BF_WEIGHTS_LIST_IDX 25
|
||||
#define RU_IF_FREQUENCY 26
|
||||
|
||||
/*-----------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* RU configuration parameters */
|
||||
@@ -149,6 +151,7 @@ typedef enum {
|
||||
{CONFIG_STRING_RU_NBIOTRRC_LIST, NULL, 0, uptr:NULL, defintarrayval:DEFENBS, TYPE_INTARRAY, 1}, \
|
||||
{CONFIG_STRING_RU_SDR_ADDRS, NULL, 0, strptr:NULL, defstrval:"type=b200", TYPE_STRING, 0}, \
|
||||
{CONFIG_STRING_RU_SDR_CLK_SRC, NULL, 0, strptr:NULL, defstrval:"internal", TYPE_STRING, 0}, \
|
||||
{CONFIG_STRING_RU_SDR_TME_SRC, NULL, 0, strptr:NULL, defstrval:"internal", TYPE_STRING, 0}, \
|
||||
{CONFIG_STRING_RU_SF_EXTENSION, NULL, 0, uptr:NULL, defuintval:312, TYPE_UINT, 0}, \
|
||||
{CONFIG_STRING_RU_END_OF_BURST_DELAY, NULL, 0, uptr:NULL, defuintval:400, TYPE_UINT, 0}, \
|
||||
{CONFIG_STRING_RU_OTA_SYNC_ENABLE, NULL, 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0}, \
|
||||
|
||||
@@ -98,7 +98,7 @@ uint16_t flexran_get_future_sfn_sf(mid_t mod_id, int ahead_of_time) {
|
||||
int flexran_get_mac_num_ues(mid_t mod_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.num_UEs;
|
||||
return RC.mac[mod_id]->UE_info.num_UEs;
|
||||
}
|
||||
|
||||
int flexran_get_num_ue_lcs(mid_t mod_id, mid_t ue_id) {
|
||||
@@ -123,7 +123,7 @@ int flexran_get_mac_ue_id_rnti(mid_t mod_id, rnti_t rnti) {
|
||||
|
||||
/* get the (active) UE with RNTI i */
|
||||
for (n = 0; n < MAX_MOBILES_PER_ENB; ++n) {
|
||||
if (RC.mac[mod_id]->UE_list.active[n] == TRUE
|
||||
if (RC.mac[mod_id]->UE_info.active[n] == TRUE
|
||||
&& rnti == UE_RNTI(mod_id, n)) {
|
||||
return n;
|
||||
}
|
||||
@@ -139,7 +139,7 @@ int flexran_get_mac_ue_id(mid_t mod_id, int i) {
|
||||
|
||||
/* get the (i+1)'th active UE */
|
||||
for (n = 0; n < MAX_MOBILES_PER_ENB; ++n) {
|
||||
if (RC.mac[mod_id]->UE_list.active[n] == TRUE) {
|
||||
if (RC.mac[mod_id]->UE_info.active[n] == TRUE) {
|
||||
if (i == 0)
|
||||
return n;
|
||||
|
||||
@@ -159,19 +159,19 @@ rnti_t flexran_get_mac_ue_crnti(mid_t mod_id, mid_t ue_id) {
|
||||
int flexran_get_ue_bsr_ul_buffer_info(mid_t mod_id, mid_t ue_id, lcid_t lcid) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.UE_template[UE_PCCID(mod_id, ue_id)][ue_id].ul_buffer_info[lcid];
|
||||
return RC.mac[mod_id]->UE_info.UE_template[UE_PCCID(mod_id, ue_id)][ue_id].ul_buffer_info[lcid];
|
||||
}
|
||||
|
||||
int8_t flexran_get_ue_phr(mid_t mod_id, mid_t ue_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.UE_template[UE_PCCID(mod_id, ue_id)][ue_id].phr_info;
|
||||
return RC.mac[mod_id]->UE_info.UE_template[UE_PCCID(mod_id, ue_id)][ue_id].phr_info;
|
||||
}
|
||||
|
||||
uint8_t flexran_get_ue_wcqi(mid_t mod_id, mid_t ue_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.UE_sched_ctrl[ue_id].dl_cqi[0];
|
||||
return RC.mac[mod_id]->UE_info.UE_sched_ctrl[ue_id].dl_cqi[0];
|
||||
}
|
||||
|
||||
rlc_buffer_occupancy_t flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) {
|
||||
@@ -180,7 +180,7 @@ rlc_buffer_occupancy_t flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logi
|
||||
rnti_t rnti = flexran_get_mac_ue_crnti(mod_id, ue_id);
|
||||
frame_t frame = flexran_get_current_frame(mod_id);
|
||||
sub_frame_t subframe = flexran_get_current_subframe(mod_id);
|
||||
mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id, frame, subframe, ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0,0, 0
|
||||
mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id, frame, subframe, ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0, 0
|
||||
);
|
||||
return rlc_status.bytes_in_buffer;
|
||||
}
|
||||
@@ -191,7 +191,7 @@ rlc_buffer_occupancy_t flexran_get_num_pdus_buffer(mid_t mod_id, mid_t ue_id, lo
|
||||
rnti_t rnti = flexran_get_mac_ue_crnti(mod_id,ue_id);
|
||||
frame_t frame = flexran_get_current_frame(mod_id);
|
||||
sub_frame_t subframe = flexran_get_current_subframe(mod_id);
|
||||
mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id, frame, subframe, ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0,0, 0
|
||||
mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id, frame, subframe, ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0, 0
|
||||
);
|
||||
return rlc_status.pdus_in_buffer;
|
||||
}
|
||||
@@ -202,7 +202,7 @@ frame_t flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t chann
|
||||
rnti_t rnti = flexran_get_mac_ue_crnti(mod_id,ue_id);
|
||||
frame_t frame = flexran_get_current_frame(mod_id);
|
||||
sub_frame_t subframe = flexran_get_current_subframe(mod_id);
|
||||
mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, frame, subframe, ENB_FLAG_YES, MBMS_FLAG_NO, channel_id, 0,0, 0
|
||||
mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, frame, subframe, ENB_FLAG_YES, MBMS_FLAG_NO, channel_id, 0, 0
|
||||
);
|
||||
return rlc_status.head_sdu_creation_time;
|
||||
}
|
||||
@@ -242,7 +242,7 @@ int32_t flexran_get_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id) {
|
||||
uint32_t flexran_get_total_size_dl_mac_sdus(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_sdu_bytes;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].total_sdu_bytes;
|
||||
}
|
||||
|
||||
uint32_t flexran_get_total_size_ul_mac_sdus(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
@@ -251,7 +251,7 @@ uint32_t flexran_get_total_size_ul_mac_sdus(mid_t mod_id, mid_t ue_id, int cc_id
|
||||
uint64_t bytes = 0;
|
||||
|
||||
for (int i = 0; i < NB_RB_MAX; ++i) {
|
||||
bytes += RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].num_bytes_rx[i];
|
||||
bytes += RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].num_bytes_rx[i];
|
||||
}
|
||||
|
||||
return bytes;
|
||||
@@ -260,135 +260,135 @@ uint32_t flexran_get_total_size_ul_mac_sdus(mid_t mod_id, mid_t ue_id, int cc_id
|
||||
uint32_t flexran_get_TBS_dl(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].TBS;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].TBS;
|
||||
}
|
||||
|
||||
uint32_t flexran_get_TBS_ul(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].ulsch_TBS;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].ulsch_TBS;
|
||||
}
|
||||
|
||||
uint16_t flexran_get_num_prb_retx_dl_per_ue(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used_retx;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].rbs_used_retx;
|
||||
}
|
||||
|
||||
uint32_t flexran_get_num_prb_retx_ul_per_ue(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used_retx_rx;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].rbs_used_retx_rx;
|
||||
}
|
||||
|
||||
uint16_t flexran_get_num_prb_dl_tx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].rbs_used;
|
||||
}
|
||||
|
||||
uint16_t flexran_get_num_prb_ul_rx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used_rx;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].rbs_used_rx;
|
||||
}
|
||||
|
||||
uint8_t flexran_get_ue_wpmi(mid_t mod_id, mid_t ue_id, uint8_t cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.UE_sched_ctrl[ue_id].periodic_wideband_pmi[cc_id];
|
||||
return RC.mac[mod_id]->UE_info.UE_sched_ctrl[ue_id].periodic_wideband_pmi[cc_id];
|
||||
}
|
||||
|
||||
uint8_t flexran_get_mcs1_dl(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].dlsch_mcs1;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].dlsch_mcs1;
|
||||
}
|
||||
|
||||
uint8_t flexran_get_mcs2_dl(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].dlsch_mcs2;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].dlsch_mcs2;
|
||||
}
|
||||
|
||||
uint8_t flexran_get_mcs1_ul(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].ulsch_mcs1;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].ulsch_mcs1;
|
||||
}
|
||||
|
||||
uint8_t flexran_get_mcs2_ul(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].ulsch_mcs2;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].ulsch_mcs2;
|
||||
}
|
||||
|
||||
uint32_t flexran_get_total_prb_dl_tx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_rbs_used;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].total_rbs_used;
|
||||
}
|
||||
|
||||
uint32_t flexran_get_total_prb_ul_rx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_rbs_used_rx;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].total_rbs_used_rx;
|
||||
}
|
||||
|
||||
uint32_t flexran_get_total_num_pdu_dl(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_num_pdus;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].total_num_pdus;
|
||||
}
|
||||
|
||||
uint32_t flexran_get_total_num_pdu_ul(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_num_pdus_rx;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].total_num_pdus_rx;
|
||||
}
|
||||
|
||||
uint64_t flexran_get_total_TBS_dl(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_pdu_bytes;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].total_pdu_bytes;
|
||||
}
|
||||
|
||||
uint64_t flexran_get_total_TBS_ul(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_ulsch_TBS;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].total_ulsch_TBS;
|
||||
}
|
||||
|
||||
int flexran_get_harq_round(mid_t mod_id, uint8_t cc_id, mid_t ue_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].harq_round;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].harq_round;
|
||||
}
|
||||
|
||||
uint32_t flexran_get_num_mac_sdu_tx(mid_t mod_id, mid_t ue_id, int cc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].num_mac_sdu_tx;
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].num_mac_sdu_tx;
|
||||
}
|
||||
|
||||
unsigned char flexran_get_mac_sdu_lcid_index(mid_t mod_id, mid_t ue_id, int cc_id, int index) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].lcid_sdu[index];
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].lcid_sdu[index];
|
||||
}
|
||||
|
||||
uint32_t flexran_get_mac_sdu_size(mid_t mod_id, mid_t ue_id, int cc_id, int lcid) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].sdu_length_tx[lcid];
|
||||
return RC.mac[mod_id]->UE_info.eNB_UE_stats[cc_id][ue_id].sdu_length_tx[lcid];
|
||||
}
|
||||
|
||||
|
||||
/* TODO needs to be revised */
|
||||
void flexran_update_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id) {
|
||||
/*
|
||||
UE_list_t *UE_list=&eNB_mac_inst[mod_id].UE_list;
|
||||
UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[ue_id];
|
||||
UE_info_t *UE_info=&eNB_mac_inst[mod_id].UE_info;
|
||||
UE_sched_ctrl *ue_sched_ctl = &UE_info->UE_sched_ctrl[ue_id];
|
||||
|
||||
if (ue_sched_ctl->ta_timer == 0) {
|
||||
|
||||
@@ -432,7 +432,7 @@ int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id) {
|
||||
int flexran_get_active_CC(mid_t mod_id, mid_t ue_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.numactiveCCs[ue_id];
|
||||
return RC.mac[mod_id]->UE_info.numactiveCCs[ue_id];
|
||||
}
|
||||
|
||||
uint8_t flexran_get_current_RI(mid_t mod_id, mid_t ue_id, uint8_t cc_id) {
|
||||
@@ -890,13 +890,13 @@ uint8_t flexran_get_rrc_status(mid_t mod_id, rnti_t rnti) {
|
||||
uint64_t flexran_get_ue_aggregated_max_bitrate_dl(mid_t mod_id, mid_t ue_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateDL;
|
||||
return 0; //RC.mac[mod_id]->UE_info.UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateDL;
|
||||
}
|
||||
|
||||
uint64_t flexran_get_ue_aggregated_max_bitrate_ul(mid_t mod_id, mid_t ue_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateUL;
|
||||
return 0; //RC.mac[mod_id]->UE_info.UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateUL;
|
||||
}
|
||||
|
||||
int flexran_get_half_duplex(mid_t mod_id, rnti_t rnti) {
|
||||
@@ -1235,7 +1235,7 @@ uint64_t flexran_get_ue_imsi(mid_t mod_id, rnti_t rnti) {
|
||||
long flexran_get_lcg(mid_t mod_id, mid_t ue_id, mid_t lc_id) {
|
||||
if (!mac_is_present(mod_id)) return 0;
|
||||
|
||||
return RC.mac[mod_id]->UE_list.UE_template[UE_PCCID(mod_id, ue_id)][ue_id].lcgidmap[lc_id];
|
||||
return RC.mac[mod_id]->UE_info.UE_template[UE_PCCID(mod_id, ue_id)][ue_id].lcgidmap[lc_id];
|
||||
}
|
||||
|
||||
/* TODO Navid: needs to be revised */
|
||||
@@ -3016,7 +3016,7 @@ uint32_t flexran_get_rrc_enb_ue_s1ap_id(mid_t mod_id, rnti_t rnti)
|
||||
int flexran_get_ue_dl_slice_id(mid_t mod_id, mid_t ue_id) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
int slice_idx = RC.mac[mod_id]->UE_list.assoc_dl_slice_idx[ue_id];
|
||||
int slice_idx = 0; //RC.mac[mod_id]->UE_info.assoc_dl_slice_idx[ue_id];
|
||||
|
||||
if (slice_idx >= 0 && slice_idx < RC.mac[mod_id]->slice_info.n_dl)
|
||||
return RC.mac[mod_id]->slice_info.dl[slice_idx].id;
|
||||
@@ -3031,13 +3031,13 @@ void flexran_set_ue_dl_slice_idx(mid_t mod_id, mid_t ue_id, int slice_idx) {
|
||||
|
||||
if (!flexran_dl_slice_exists(mod_id, slice_idx)) return;
|
||||
|
||||
RC.mac[mod_id]->UE_list.assoc_dl_slice_idx[ue_id] = slice_idx;
|
||||
//RC.mac[mod_id]->UE_info.assoc_dl_slice_idx[ue_id] = slice_idx;
|
||||
}
|
||||
|
||||
int flexran_get_ue_ul_slice_id(mid_t mod_id, mid_t ue_id) {
|
||||
if (!mac_is_present(mod_id)) return -1;
|
||||
|
||||
int slice_idx = RC.mac[mod_id]->UE_list.assoc_ul_slice_idx[ue_id];
|
||||
int slice_idx = 0; //RC.mac[mod_id]->UE_info.assoc_ul_slice_idx[ue_id];
|
||||
|
||||
if (slice_idx >= 0 && slice_idx < RC.mac[mod_id]->slice_info.n_ul)
|
||||
return RC.mac[mod_id]->slice_info.ul[slice_idx].id;
|
||||
@@ -3052,7 +3052,7 @@ void flexran_set_ue_ul_slice_idx(mid_t mod_id, mid_t ue_id, int slice_idx) {
|
||||
|
||||
if (!flexran_ul_slice_exists(mod_id, slice_idx)) return;
|
||||
|
||||
RC.mac[mod_id]->UE_list.assoc_ul_slice_idx[ue_id] = slice_idx;
|
||||
//RC.mac[mod_id]->UE_info.assoc_ul_slice_idx[ue_id] = slice_idx;
|
||||
}
|
||||
|
||||
int flexran_dl_slice_exists(mid_t mod_id, int slice_idx) {
|
||||
@@ -3103,14 +3103,14 @@ int flexran_remove_dl_slice(mid_t mod_id, int slice_idx) {
|
||||
|
||||
memset(&sli->dl[sli->n_dl], 0, sizeof(sli->dl[sli->n_dl]));
|
||||
/* all UEs that have been in the old slice are put into slice index 0 */
|
||||
int *assoc_list = RC.mac[mod_id]->UE_list.assoc_dl_slice_idx;
|
||||
//int *assoc_list = RC.mac[mod_id]->UE_info.assoc_dl_slice_idx;
|
||||
|
||||
for (int i = 0; i < MAX_MOBILES_PER_ENB; ++i) {
|
||||
if (assoc_list[i] == slice_idx)
|
||||
assoc_list[i] = 0;
|
||||
}
|
||||
//for (int i = 0; i < MAX_MOBILES_PER_ENB; ++i) {
|
||||
// if (assoc_list[i] == slice_idx)
|
||||
// assoc_list[i] = 0;
|
||||
//}
|
||||
|
||||
return sli->n_dl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int flexran_get_num_dl_slices(mid_t mod_id) {
|
||||
@@ -3397,12 +3397,12 @@ int flexran_remove_ul_slice(mid_t mod_id, int slice_idx) {
|
||||
|
||||
memset(&sli->ul[sli->n_ul], 0, sizeof(sli->ul[sli->n_ul]));
|
||||
/* all UEs that have been in the old slice are put into slice index 0 */
|
||||
int *assoc_list = RC.mac[mod_id]->UE_list.assoc_ul_slice_idx;
|
||||
//int *assoc_list = RC.mac[mod_id]->UE_info.assoc_ul_slice_idx;
|
||||
|
||||
for (int i = 0; i < MAX_MOBILES_PER_ENB; ++i) {
|
||||
if (assoc_list[i] == slice_idx)
|
||||
assoc_list[i] = 0;
|
||||
}
|
||||
//for (int i = 0; i < MAX_MOBILES_PER_ENB; ++i) {
|
||||
// if (assoc_list[i] == slice_idx)
|
||||
// assoc_list[i] = 0;
|
||||
//}
|
||||
|
||||
return sli->n_ul;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
#include "f1ap_cu_ue_context_management.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "openair2/LAYER2/MAC/mac_proto.h"
|
||||
#include "rrc_extern.h"
|
||||
#include "rrc_eNB_UE_context.h"
|
||||
#include "rrc_eNB_S1AP.h"
|
||||
|
||||
@@ -697,7 +697,7 @@ int DU_send_UL_RRC_MESSAGE_TRANSFER(instance_t instance,
|
||||
break;
|
||||
}
|
||||
|
||||
UE_sched_ctrl_t *UE_scheduling_control = &(RC.mac[instance]->UE_list.UE_sched_ctrl[UE_id_mac]);
|
||||
UE_sched_ctrl_t *UE_scheduling_control = &(RC.mac[instance]->UE_info.UE_sched_ctrl[UE_id_mac]);
|
||||
|
||||
if (UE_scheduling_control->cdrx_waiting_ack == TRUE) {
|
||||
UE_scheduling_control->cdrx_waiting_ack = FALSE;
|
||||
|
||||
@@ -633,9 +633,9 @@ int DU_handle_UE_CONTEXT_RELEASE_COMMAND(instance_t instance,
|
||||
int UE_out_of_sync = 0;
|
||||
|
||||
for (int n = 0; n < MAX_MOBILES_PER_ENB; ++n) {
|
||||
if (RC.mac[instance]->UE_list.active[n] == TRUE
|
||||
if (RC.mac[instance]->UE_info.active[n] == TRUE
|
||||
&& rnti == UE_RNTI(instance, n)) {
|
||||
UE_out_of_sync = RC.mac[instance]->UE_list.UE_sched_ctrl[n].ul_out_of_sync;
|
||||
UE_out_of_sync = RC.mac[instance]->UE_info.UE_sched_ctrl[n].ul_out_of_sync;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -987,8 +987,6 @@ void NRRCConfig(void) {
|
||||
paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0};
|
||||
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
||||
|
||||
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
|
||||
|
||||
/* get global parameters, defined outside any section in the config file */
|
||||
|
||||
LOG_I(GNB_APP, "Getting GNBSParams\n");
|
||||
|
||||
@@ -782,7 +782,7 @@ int rrc_mac_config_req_eNB(module_id_t Mod_idP,
|
||||
int i;
|
||||
int UE_id = -1;
|
||||
eNB_MAC_INST *eNB = RC.mac[Mod_idP];
|
||||
UE_list_t *UE_list= &eNB->UE_list;
|
||||
UE_info_t *UE_info= &eNB->UE_info;
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_IN);
|
||||
LOG_D(MAC, "RC.mac:%p mib:%p\n", RC.mac, mib);
|
||||
|
||||
@@ -882,6 +882,34 @@ int rrc_mac_config_req_eNB(module_id_t Mod_idP,
|
||||
}
|
||||
}
|
||||
|
||||
if (logicalChannelIdentity > 0) { // is SRB1,2 or DRB
|
||||
if ((UE_id = find_UE_id(Mod_idP, rntiP)) < 0) {
|
||||
LOG_E(MAC,"Configuration received for unknown UE (%x), shouldn't happen\n",rntiP);
|
||||
return(-1);
|
||||
}
|
||||
int idx = -1;
|
||||
UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
|
||||
for (int i = 0; i < sched_ctrl->dl_lc_num; ++i) {
|
||||
if (sched_ctrl->dl_lc_ids[i] == logicalChannelIdentity) {
|
||||
/* TODO this might also mean we have to remove it, not clear */
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (idx < 0) {
|
||||
sched_ctrl->dl_lc_num++;
|
||||
sched_ctrl->dl_lc_ids[sched_ctrl->dl_lc_num-1] = logicalChannelIdentity;
|
||||
sched_ctrl->dl_lc_bytes[sched_ctrl->dl_lc_num-1] = 0;
|
||||
LOG_I(MAC, "UE %d RNTI %x adding LC %ld idx %d to scheduling control (total %d)\n", UE_id, rntiP, logicalChannelIdentity, sched_ctrl->dl_lc_num-1, sched_ctrl->dl_lc_num);
|
||||
if (logicalChannelIdentity == 1) { // if it is SRB1, add SRB2 directly because RRC does not indicate this separately
|
||||
sched_ctrl->dl_lc_num++;
|
||||
sched_ctrl->dl_lc_ids[sched_ctrl->dl_lc_num-1] = 2;
|
||||
sched_ctrl->dl_lc_bytes[sched_ctrl->dl_lc_num-1] = 0;
|
||||
LOG_I(MAC, "UE %d RNTI %x adding LC 2 idx %d to scheduling control (total %d)\n", UE_id, rntiP, sched_ctrl->dl_lc_num-1, sched_ctrl->dl_lc_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters->logicalChannelGroup
|
||||
if (logicalChannelConfig != NULL) { // check for eMTC specific things
|
||||
UE_id = find_UE_id(Mod_idP, rntiP);
|
||||
@@ -892,9 +920,9 @@ int rrc_mac_config_req_eNB(module_id_t Mod_idP,
|
||||
}
|
||||
|
||||
if (logicalChannelConfig) {
|
||||
UE_list->UE_template[CC_idP][UE_id].lcgidmap[logicalChannelIdentity] = *logicalChannelConfig->ul_SpecificParameters->logicalChannelGroup;
|
||||
UE_list->UE_template[CC_idP][UE_id].lcgidpriority[logicalChannelIdentity] = logicalChannelConfig->ul_SpecificParameters->priority;
|
||||
} else UE_list->UE_template[CC_idP][UE_id].lcgidmap[logicalChannelIdentity] = 0;
|
||||
UE_info->UE_template[CC_idP][UE_id].lcgidmap[logicalChannelIdentity] = *logicalChannelConfig->ul_SpecificParameters->logicalChannelGroup;
|
||||
UE_info->UE_template[CC_idP][UE_id].lcgidpriority[logicalChannelIdentity] = logicalChannelConfig->ul_SpecificParameters->priority;
|
||||
} else UE_info->UE_template[CC_idP][UE_id].lcgidmap[logicalChannelIdentity] = 0;
|
||||
}
|
||||
|
||||
if (physicalConfigDedicated != NULL) {
|
||||
@@ -905,7 +933,7 @@ int rrc_mac_config_req_eNB(module_id_t Mod_idP,
|
||||
return(-1);
|
||||
}
|
||||
|
||||
UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated = physicalConfigDedicated;
|
||||
UE_info->UE_template[CC_idP][UE_id].physicalConfigDedicated = physicalConfigDedicated;
|
||||
LOG_I(MAC,"Added physicalConfigDedicated %p for %d.%d\n",physicalConfigDedicated,CC_idP,UE_id);
|
||||
}
|
||||
|
||||
@@ -1048,15 +1076,11 @@ void eNB_Config_Local_DRX(instance_t Mod_id,
|
||||
rrc_mac_drx_config_req_t *rrc_mac_drx_config_req)
|
||||
//-----------------------------------------------------------------------------
|
||||
{
|
||||
UE_list_t *UE_list_mac = NULL;
|
||||
UE_info_t *UE_info_mac = &RC.mac[Mod_id]->UE_info;
|
||||
UE_sched_ctrl_t *UE_scheduling_control = NULL;
|
||||
int UE_id = -1;
|
||||
|
||||
rnti_t rnti = rrc_mac_drx_config_req->rnti;
|
||||
LTE_DRX_Config_t *const drx_Configuration = rrc_mac_drx_config_req->drx_Configuration;
|
||||
|
||||
UE_list_mac = &(RC.mac[Mod_id]->UE_list);
|
||||
UE_id = find_UE_id(Mod_id, rnti);
|
||||
rnti_t rnti = rrc_mac_drx_config_req->rnti;
|
||||
int UE_id = find_UE_id(Mod_id, rnti);
|
||||
|
||||
/* Check UE_id */
|
||||
if (UE_id == -1) {
|
||||
@@ -1065,7 +1089,7 @@ void eNB_Config_Local_DRX(instance_t Mod_id,
|
||||
}
|
||||
|
||||
/* Get struct to modify */
|
||||
UE_scheduling_control = &(UE_list_mac->UE_sched_ctrl[UE_id]);
|
||||
UE_scheduling_control = &(UE_info_mac->UE_sched_ctrl[UE_id]);
|
||||
UE_scheduling_control->cdrx_configured = FALSE; // will be set to true when no error
|
||||
|
||||
/* Check drx_Configuration */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,7 +35,7 @@
|
||||
#include "LAYER2/MAC/mac_extern.h"
|
||||
|
||||
#include "LAYER2/MAC/mac_proto.h"
|
||||
#include "NR_MAC_gNB/mac_proto.h"
|
||||
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "nfapi/oai_integration/vendor_ext.h"
|
||||
#include "common/utils/LOG/vcd_signal_dumper.h"
|
||||
@@ -89,7 +89,7 @@ void schedule_SRS(module_id_t module_idP,
|
||||
const uint16_t deltaTSFCTabType1[15][2] = { {1, 1}, {1, 2}, {2, 2}, {1, 5}, {2, 5}, {4, 5}, {8, 5}, {3, 5}, {12, 5}, {1, 10}, {2, 10}, {4, 10}, {8, 10}, {351, 10}, {383, 10} }; // Table 5.5.3.3-2 3GPP 36.211 FDD
|
||||
const uint16_t deltaTSFCTabType2[14][2] = { {2, 5}, {6, 5}, {10, 5}, {18, 5}, {14, 5}, {22, 5}, {26, 5}, {30, 5}, {70, 10}, {74, 10}, {194, 10}, {326, 10}, {586, 10}, {210, 10} }; // Table 5.5.3.3-2 3GPP 36.211 TDD
|
||||
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
||||
UE_list_t *UE_list = &(eNB->UE_list);
|
||||
UE_info_t *UE_info = &eNB->UE_info;
|
||||
nfapi_ul_config_request_body_t *ul_req = NULL;
|
||||
UE_sched_ctrl_t *UE_scheduling_control = NULL;
|
||||
COMMON_channels_t *cc = eNB->common_channels;
|
||||
@@ -117,7 +117,7 @@ void schedule_SRS(module_id_t module_idP,
|
||||
if ((1 << tmp) & deltaTSFC) {
|
||||
/* This is an SRS subframe, loop over UEs */
|
||||
for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) {
|
||||
if (!UE_list->active[UE_id]) {
|
||||
if (!UE_info->active[UE_id]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -126,14 +126,14 @@ void schedule_SRS(module_id_t module_idP,
|
||||
continue;
|
||||
}
|
||||
|
||||
if(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated == NULL) {
|
||||
if(UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated == NULL) {
|
||||
LOG_E(MAC,"physicalConfigDedicated is null for UE %d\n",UE_id);
|
||||
printf("physicalConfigDedicated is null for UE %d\n",UE_id);
|
||||
return;
|
||||
}
|
||||
|
||||
/* CDRX condition on Active Time and SRS type-0 report (36.321 5.7) */
|
||||
UE_scheduling_control = &(UE_list->UE_sched_ctrl[UE_id]);
|
||||
UE_scheduling_control = &(UE_info->UE_sched_ctrl[UE_id]);
|
||||
|
||||
/* Test if Active Time not running since 6+ subframes */
|
||||
if (UE_scheduling_control->cdrx_configured == TRUE && UE_scheduling_control->in_active_time == FALSE) {
|
||||
@@ -145,7 +145,7 @@ void schedule_SRS(module_id_t module_idP,
|
||||
|
||||
ul_req = &(eNB->UL_req[CC_id].ul_config_request_body);
|
||||
|
||||
if ((soundingRS_UL_ConfigDedicated = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated) != NULL) {
|
||||
if ((soundingRS_UL_ConfigDedicated = UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated) != NULL) {
|
||||
if (soundingRS_UL_ConfigDedicated->present == LTE_SoundingRS_UL_ConfigDedicated_PR_setup) {
|
||||
get_srs_pos(&cc[CC_id],
|
||||
soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex,
|
||||
@@ -161,7 +161,7 @@ void schedule_SRS(module_id_t module_idP,
|
||||
ul_config_pdu->pdu_size = 2 + (uint8_t) (2 + sizeof(nfapi_ul_config_srs_pdu));
|
||||
ul_config_pdu->srs_pdu.srs_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL8_TAG;
|
||||
ul_config_pdu->srs_pdu.srs_pdu_rel8.size = (uint8_t)sizeof(nfapi_ul_config_srs_pdu);
|
||||
ul_config_pdu->srs_pdu.srs_pdu_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti;
|
||||
ul_config_pdu->srs_pdu.srs_pdu_rel8.rnti = UE_info->UE_template[CC_id][UE_id].rnti;
|
||||
ul_config_pdu->srs_pdu.srs_pdu_rel8.srs_bandwidth = soundingRS_UL_ConfigDedicated->choice.setup.srs_Bandwidth;
|
||||
ul_config_pdu->srs_pdu.srs_pdu_rel8.frequency_domain_position = soundingRS_UL_ConfigDedicated->choice.setup.freqDomainPosition;
|
||||
ul_config_pdu->srs_pdu.srs_pdu_rel8.srs_hopping_bandwidth = soundingRS_UL_ConfigDedicated->choice.setup.srs_HoppingBandwidth;;
|
||||
@@ -173,7 +173,7 @@ void schedule_SRS(module_id_t module_idP,
|
||||
ul_req->number_of_pdus++;
|
||||
} // if (((10*frameP+subframeP) % srsPeriodicity) == srsOffset)
|
||||
} // if (soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup)
|
||||
} // if ((soundingRS_UL_ConfigDedicated = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated)!=NULL)
|
||||
} // if ((soundingRS_UL_ConfigDedicated = UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated)!=NULL)
|
||||
} // end for loop on UE_id
|
||||
} // if((1<<tmp) & deltaTSFC)
|
||||
} // SRS config not NULL
|
||||
@@ -196,7 +196,7 @@ void schedule_CSI(module_id_t module_idP,
|
||||
uint16_t N_OFFSET_CQI = 0;
|
||||
struct LTE_CQI_ReportPeriodic *cqi_ReportPeriodic = NULL;
|
||||
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
||||
UE_list_t *UE_list = &eNB->UE_list;
|
||||
UE_info_t *UE_info = &eNB->UE_info;
|
||||
COMMON_channels_t *cc = NULL;
|
||||
nfapi_ul_config_request_body_t *ul_req = NULL;
|
||||
UE_sched_ctrl_t *UE_scheduling_control = NULL;
|
||||
@@ -205,7 +205,7 @@ void schedule_CSI(module_id_t module_idP,
|
||||
cc = &eNB->common_channels[CC_id];
|
||||
|
||||
for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) {
|
||||
if (UE_list->active[UE_id] == FALSE) {
|
||||
if (UE_info->active[UE_id] == FALSE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ void schedule_CSI(module_id_t module_idP,
|
||||
continue;
|
||||
}
|
||||
|
||||
AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL,
|
||||
AssertFatal(UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL,
|
||||
"physicalConfigDedicated is null for UE %d\n",
|
||||
UE_id);
|
||||
/*
|
||||
@@ -222,7 +222,7 @@ void schedule_CSI(module_id_t module_idP,
|
||||
* Here we consider classic periodic reports on PUCCH without PUSCH simultaneous transmission condition.
|
||||
* TODO: add the handling or test on simultaneous PUCCH/PUSCH transmission
|
||||
*/
|
||||
UE_scheduling_control = &(UE_list->UE_sched_ctrl[UE_id]);
|
||||
UE_scheduling_control = &(UE_info->UE_sched_ctrl[UE_id]);
|
||||
|
||||
if (UE_scheduling_control->cdrx_configured == TRUE) {
|
||||
/* Test if CQI masking activated */
|
||||
@@ -246,8 +246,8 @@ void schedule_CSI(module_id_t module_idP,
|
||||
|
||||
ul_req = &(eNB->UL_req[CC_id].ul_config_request_body);
|
||||
|
||||
if (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL) {
|
||||
cqi_ReportPeriodic = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic;
|
||||
if (UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL) {
|
||||
cqi_ReportPeriodic = UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic;
|
||||
|
||||
if (cqi_ReportPeriodic != NULL) {
|
||||
/* Rel8 Periodic CSI (CQI/PMI/RI) reporting */
|
||||
@@ -262,10 +262,10 @@ void schedule_CSI(module_id_t module_idP,
|
||||
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE;
|
||||
ul_config_pdu->pdu_size = 2 + (uint8_t) (2 + sizeof(nfapi_ul_config_uci_cqi_pdu));
|
||||
ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG;
|
||||
ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti;
|
||||
ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_info->UE_template[CC_id][UE_id].rnti;
|
||||
ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG;
|
||||
ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.pucch_index = cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex;
|
||||
ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.dl_cqi_pmi_size = get_rel8_dl_cqi_pmi_size(&UE_list->UE_sched_ctrl[UE_id], CC_id, cc, get_tmode(module_idP, CC_id, UE_id),
|
||||
ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.dl_cqi_pmi_size = get_rel8_dl_cqi_pmi_size(&UE_info->UE_sched_ctrl[UE_id], CC_id, cc, get_tmode(module_idP, CC_id, UE_id),
|
||||
cqi_ReportPeriodic);
|
||||
ul_req->number_of_pdus++;
|
||||
ul_req->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG;
|
||||
@@ -279,7 +279,7 @@ void schedule_CSI(module_id_t module_idP,
|
||||
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE;
|
||||
ul_config_pdu->pdu_size = 2 + (uint8_t) (2 + sizeof(nfapi_ul_config_uci_cqi_pdu));
|
||||
ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG;
|
||||
ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti;
|
||||
ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_info->UE_template[CC_id][UE_id].rnti;
|
||||
ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG;
|
||||
ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.pucch_index = cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex;
|
||||
ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.dl_cqi_pmi_size = (cc->p_eNB == 2) ? 1 : 2;
|
||||
@@ -291,7 +291,7 @@ void schedule_CSI(module_id_t module_idP,
|
||||
} // if CSI Periodic is not release state
|
||||
} // if (cqi_ReportPeriodic != NULL)
|
||||
} // if cqi_ReportConfig != NULL
|
||||
} // for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) {
|
||||
} // for (UE_id=UE_info->head; UE_id>=0; UE_id=UE_info->next[UE_id]) {
|
||||
} // for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ schedule_SR (module_id_t module_idP,
|
||||
int is_harq = 0;
|
||||
int pdu_list_index = 0;
|
||||
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
||||
UE_list_t *UE_list = &eNB->UE_list;
|
||||
UE_info_t *UE_info = &eNB->UE_info;
|
||||
nfapi_ul_config_request_t *ul_req = NULL;
|
||||
nfapi_ul_config_request_body_t *ul_req_body = NULL;
|
||||
LTE_SchedulingRequestConfig_t *SRconfig = NULL;
|
||||
@@ -319,13 +319,13 @@ schedule_SR (module_id_t module_idP,
|
||||
eNB->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP;
|
||||
|
||||
for (int UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) {
|
||||
if (!UE_list->active[UE_id]) {
|
||||
if (!UE_info->active[UE_id]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated == NULL) continue;
|
||||
if (UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated == NULL) continue;
|
||||
|
||||
if ((SRconfig = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig) != NULL) {
|
||||
if ((SRconfig = UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig) != NULL) {
|
||||
if (SRconfig->present == LTE_SchedulingRequestConfig_PR_setup) {
|
||||
if (SRconfig->choice.setup.sr_ConfigIndex <= 4) { // 5 ms SR period
|
||||
if ((subframeP % 5) != SRconfig->choice.setup.sr_ConfigIndex) continue;
|
||||
@@ -337,9 +337,11 @@ schedule_SR (module_id_t module_idP,
|
||||
if ((10 * (frameP & 3) + subframeP) != (SRconfig->choice.setup.sr_ConfigIndex - 35)) continue;
|
||||
} else if (SRconfig->choice.setup.sr_ConfigIndex <= 154) { // 80 ms SR period
|
||||
if ((10 * (frameP & 7) + subframeP) != (SRconfig->choice.setup.sr_ConfigIndex - 75)) continue;
|
||||
} else if (SRconfig->choice.setup.sr_ConfigIndex <= 156) { // 2ms SR period
|
||||
if ((subframeP % 2) != (SRconfig->choice.setup.sr_ConfigIndex - 155)) continue;
|
||||
}
|
||||
} // SRconfig->present == SchedulingRequestConfig_PR_setup)
|
||||
} // SRconfig = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig)!=NULL)
|
||||
} // SRconfig = UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig)!=NULL)
|
||||
|
||||
/* If we get here there is some PUCCH1 reception to schedule for SR */
|
||||
ul_req = &(eNB->UL_req[CC_id]);
|
||||
@@ -354,14 +356,14 @@ schedule_SR (module_id_t module_idP,
|
||||
(ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE) ||
|
||||
(ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE) ||
|
||||
(ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE)) &&
|
||||
(ul_req_body->ul_config_pdu_list[i].ulsch_pdu.ulsch_pdu_rel8.rnti == UE_list->UE_template[CC_id][UE_id].rnti)) {
|
||||
(ul_req_body->ul_config_pdu_list[i].ulsch_pdu.ulsch_pdu_rel8.rnti == UE_info->UE_template[CC_id][UE_id].rnti)) {
|
||||
skip_ue = 1;
|
||||
pdu_list_index = i;
|
||||
break;
|
||||
}
|
||||
/* If there is already an HARQ pdu, convert to SR_HARQ */
|
||||
else if ((ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE) &&
|
||||
(ul_req_body->ul_config_pdu_list[i].uci_harq_pdu.ue_information.ue_information_rel8.rnti == UE_list->UE_template[CC_id][UE_id].rnti)) {
|
||||
(ul_req_body->ul_config_pdu_list[i].uci_harq_pdu.ue_information.ue_information_rel8.rnti == UE_info->UE_template[CC_id][UE_id].rnti)) {
|
||||
is_harq = 1;
|
||||
pdu_list_index = i;
|
||||
break;
|
||||
@@ -375,20 +377,20 @@ schedule_SR (module_id_t module_idP,
|
||||
frameP,
|
||||
subframeP,
|
||||
UE_id,
|
||||
UE_list->UE_template[CC_id][UE_id].rnti,
|
||||
UE_info->UE_template[CC_id][UE_id].rnti,
|
||||
is_harq);
|
||||
|
||||
/* Check Rel10 or Rel8 SR */
|
||||
if ((UE_list-> UE_template[CC_id][UE_id].physicalConfigDedicated->ext2) &&
|
||||
(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020) &&
|
||||
(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020)) {
|
||||
if ((UE_info-> UE_template[CC_id][UE_id].physicalConfigDedicated->ext2) &&
|
||||
(UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020) &&
|
||||
(UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020)) {
|
||||
sr.sr_information_rel10.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL10_TAG;
|
||||
sr.sr_information_rel10.number_of_pucch_resources = 1;
|
||||
sr.sr_information_rel10.pucch_index_p1 = *UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020->sr_PUCCH_ResourceIndexP1_r10;
|
||||
sr.sr_information_rel10.pucch_index_p1 = *UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020->sr_PUCCH_ResourceIndexP1_r10;
|
||||
LOG_D(MAC, "REL10 PUCCH INDEX P1:%d \n", sr.sr_information_rel10.pucch_index_p1);
|
||||
} else {
|
||||
sr.sr_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL8_TAG;
|
||||
sr.sr_information_rel8.pucch_index = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig->choice.setup.sr_PUCCH_ResourceIndex;
|
||||
sr.sr_information_rel8.pucch_index = UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig->choice.setup.sr_PUCCH_ResourceIndex;
|
||||
LOG_D(MAC, "REL8 PUCCH INDEX:%d\n", sr.sr_information_rel8.pucch_index);
|
||||
}
|
||||
|
||||
@@ -401,7 +403,7 @@ schedule_SR (module_id_t module_idP,
|
||||
} else {
|
||||
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].pdu_type = NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE;
|
||||
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG;
|
||||
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti;
|
||||
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.rnti = UE_info->UE_template[CC_id][UE_id].rnti;
|
||||
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel11.tl.tag = 0;
|
||||
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel13.tl.tag = 0;
|
||||
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.sr_information = sr;
|
||||
@@ -416,20 +418,20 @@ schedule_SR (module_id_t module_idP,
|
||||
void
|
||||
check_ul_failure(module_id_t module_idP, int CC_id, int UE_id,
|
||||
frame_t frameP, sub_frame_t subframeP) {
|
||||
UE_list_t *UE_list = &RC.mac[module_idP]->UE_list;
|
||||
UE_info_t *UE_info = &RC.mac[module_idP]->UE_info;
|
||||
nfapi_dl_config_request_t *DL_req = &RC.mac[module_idP]->DL_req[0];
|
||||
uint16_t rnti = UE_RNTI(module_idP, UE_id);
|
||||
COMMON_channels_t *cc = RC.mac[module_idP]->common_channels;
|
||||
|
||||
// check uplink failure
|
||||
if ((UE_list->UE_sched_ctrl[UE_id].ul_failure_timer > 0) &&
|
||||
(UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 0)) {
|
||||
if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer == 1)
|
||||
if ((UE_info->UE_sched_ctrl[UE_id].ul_failure_timer > 0) &&
|
||||
(UE_info->UE_sched_ctrl[UE_id].ul_out_of_sync == 0)) {
|
||||
if (UE_info->UE_sched_ctrl[UE_id].ul_failure_timer == 1)
|
||||
LOG_I(MAC, "UE %d rnti %x: UL Failure timer %d \n", UE_id, rnti,
|
||||
UE_list->UE_sched_ctrl[UE_id].ul_failure_timer);
|
||||
UE_info->UE_sched_ctrl[UE_id].ul_failure_timer);
|
||||
|
||||
if (UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent == 0) {
|
||||
UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 1;
|
||||
if (UE_info->UE_sched_ctrl[UE_id].ra_pdcch_order_sent == 0) {
|
||||
UE_info->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 1;
|
||||
// add a format 1A dci for this UE to request an RA procedure (only one UE per subframe)
|
||||
nfapi_dl_config_request_pdu_t *dl_config_pdu = &DL_req[CC_id].dl_config_request_body.dl_config_pdu_list[DL_req[CC_id].dl_config_request_body.number_pdu];
|
||||
memset((void *) dl_config_pdu, 0,sizeof(nfapi_dl_config_request_pdu_t));
|
||||
@@ -438,7 +440,7 @@ check_ul_failure(module_id_t module_idP, int CC_id, int UE_id,
|
||||
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG;
|
||||
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A;
|
||||
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP, CC_id),
|
||||
UE_list->UE_sched_ctrl[UE_id].
|
||||
UE_info->UE_sched_ctrl[UE_id].
|
||||
dl_cqi[CC_id], format1A);
|
||||
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti;
|
||||
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications
|
||||
@@ -454,22 +456,22 @@ check_ul_failure(module_id_t module_idP, int CC_id, int UE_id,
|
||||
LOG_D(MAC,
|
||||
"UE %d rnti %x: sending PDCCH order for RAPROC (failure timer %d), resource_block_coding %d \n",
|
||||
UE_id, rnti,
|
||||
UE_list->UE_sched_ctrl[UE_id].ul_failure_timer,
|
||||
UE_info->UE_sched_ctrl[UE_id].ul_failure_timer,
|
||||
dl_config_pdu->dci_dl_pdu.
|
||||
dci_dl_pdu_rel8.resource_block_coding);
|
||||
} else { // ra_pdcch_sent==1
|
||||
LOG_D(MAC,
|
||||
"UE %d rnti %x: sent PDCCH order for RAPROC waiting (failure timer %d) \n",
|
||||
UE_id, rnti,
|
||||
UE_list->UE_sched_ctrl[UE_id].ul_failure_timer);
|
||||
UE_info->UE_sched_ctrl[UE_id].ul_failure_timer);
|
||||
|
||||
if ((UE_list->UE_sched_ctrl[UE_id].ul_failure_timer % 80) == 0) UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 0; // resend every 8 frames
|
||||
if ((UE_info->UE_sched_ctrl[UE_id].ul_failure_timer % 80) == 0) UE_info->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 0; // resend every 8 frames
|
||||
}
|
||||
|
||||
UE_list->UE_sched_ctrl[UE_id].ul_failure_timer++;
|
||||
UE_info->UE_sched_ctrl[UE_id].ul_failure_timer++;
|
||||
|
||||
// check threshold
|
||||
if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer > 4000) {
|
||||
if (UE_info->UE_sched_ctrl[UE_id].ul_failure_timer > 4000) {
|
||||
// note: probably ul_failure_timer should be less than UE radio link failure time(see T310/N310/N311)
|
||||
if (NODE_IS_DU(RC.rrc[module_idP]->node_type)) {
|
||||
MessageDef *m = itti_alloc_new_message(TASK_MAC_ENB, F1AP_UE_CONTEXT_RELEASE_REQ);
|
||||
@@ -491,17 +493,17 @@ check_ul_failure(module_id_t module_idP, int CC_id, int UE_id,
|
||||
rnti);
|
||||
}
|
||||
|
||||
UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0;
|
||||
UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 1;
|
||||
UE_info->UE_sched_ctrl[UE_id].ul_failure_timer = 0;
|
||||
UE_info->UE_sched_ctrl[UE_id].ul_out_of_sync = 1;
|
||||
}
|
||||
} // ul_failure_timer>0
|
||||
|
||||
UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer++;
|
||||
UE_info->UE_sched_ctrl[UE_id].uplane_inactivity_timer++;
|
||||
|
||||
if((U_PLANE_INACTIVITY_VALUE != 0) && (UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer > (U_PLANE_INACTIVITY_VALUE * 10))) {
|
||||
if((U_PLANE_INACTIVITY_VALUE != 0) && (UE_info->UE_sched_ctrl[UE_id].uplane_inactivity_timer > (U_PLANE_INACTIVITY_VALUE * 10))) {
|
||||
LOG_D(MAC,"UE %d rnti %x: U-Plane Failure after repeated PDCCH orders: Triggering RRC \n",UE_id,rnti);
|
||||
mac_eNB_rrc_uplane_failure(module_idP,CC_id,frameP,subframeP,rnti);
|
||||
UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0;
|
||||
UE_info->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0;
|
||||
}// time > 60s
|
||||
}
|
||||
|
||||
@@ -565,7 +567,7 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP,
|
||||
int CC_id = 0;
|
||||
int UE_id = -1;
|
||||
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
||||
UE_list_t *UE_list = &(eNB->UE_list);
|
||||
UE_info_t *UE_info = &(eNB->UE_info);
|
||||
COMMON_channels_t *cc = eNB->common_channels;
|
||||
UE_sched_ctrl_t *UE_scheduling_control = NULL;
|
||||
start_meas(&(eNB->eNB_scheduler));
|
||||
@@ -584,16 +586,16 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP,
|
||||
|
||||
/* Refresh UE list based on UEs dropped by PHY in previous subframe */
|
||||
for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) {
|
||||
if (UE_list->active[UE_id]) {
|
||||
if (UE_info->active[UE_id]) {
|
||||
rnti = UE_RNTI(module_idP, UE_id);
|
||||
CC_id = UE_PCCID(module_idP, UE_id);
|
||||
UE_scheduling_control = &(UE_list->UE_sched_ctrl[UE_id]);
|
||||
UE_scheduling_control = &(UE_info->UE_sched_ctrl[UE_id]);
|
||||
|
||||
if (((frameP & 127) == 0) && (subframeP == 0)) {
|
||||
LOG_I(MAC,"UE rnti %x : %s, PHR %d dB DL CQI %d PUSCH SNR %d PUCCH SNR %d\n",
|
||||
rnti,
|
||||
UE_scheduling_control->ul_out_of_sync == 0 ? "in synch" : "out of sync",
|
||||
UE_list->UE_template[CC_id][UE_id].phr_info,
|
||||
UE_info->UE_template[CC_id][UE_id].phr_info,
|
||||
UE_scheduling_control->dl_cqi[CC_id],
|
||||
(5 * UE_scheduling_control->pusch_snr[CC_id] - 640) / 10,
|
||||
(5 * UE_scheduling_control->pucch1_snr[CC_id] - 640) / 10);
|
||||
@@ -601,7 +603,7 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP,
|
||||
|
||||
RC.eNB[module_idP][CC_id]->pusch_stats_bsr[UE_id][(frameP * 10) + subframeP] = -63;
|
||||
|
||||
if (UE_id == UE_list->head) {
|
||||
if (UE_id == UE_info->list.head) {
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR, RC.eNB[module_idP][CC_id]->pusch_stats_bsr[UE_id][(frameP * 10) + subframeP]);
|
||||
}
|
||||
|
||||
@@ -735,7 +737,7 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP,
|
||||
* here for the current subframe. The variable 'UE_scheduling_control->in_active_time' should be updated
|
||||
* ONLY here. The variable can then be used for testing the actual state of the UE for scheduling purpose.
|
||||
*/
|
||||
UE_template = &(UE_list->UE_template[CC_id][UE_id]);
|
||||
UE_template = &(UE_info->UE_template[CC_id][UE_id]);
|
||||
|
||||
/* (a)synchronous HARQ processes handling for Active Time */
|
||||
for (int harq_process_id = 0; harq_process_id < 8; harq_process_id++) {
|
||||
@@ -981,7 +983,9 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP,
|
||||
/* Allocate CCEs for good after scheduling is done */
|
||||
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
|
||||
if (cc[CC_id].tdd_Config == NULL || !(is_UL_sf(&cc[CC_id],subframeP))) {
|
||||
allocate_CCEs(module_idP, CC_id, frameP, subframeP, 2);
|
||||
int rc = allocate_CCEs(module_idP, CC_id, frameP, subframeP, 2);
|
||||
if (rc < 0)
|
||||
LOG_E(MAC, "%s() %4d.%d ERROR ALLOCATING CCEs\n", __func__, frameP, subframeP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -587,7 +587,7 @@ generate_Msg4(module_id_t module_idP,
|
||||
{
|
||||
eNB_MAC_INST *mac = RC.mac[module_idP];
|
||||
COMMON_channels_t *cc = mac->common_channels;
|
||||
UE_list_t *UE_list = &(mac->UE_list);
|
||||
UE_info_t *UE_info = &mac->UE_info;
|
||||
int16_t rrc_sdu_length = 0;
|
||||
uint16_t msg4_padding = 0;
|
||||
uint16_t msg4_post_padding = 0;
|
||||
@@ -831,7 +831,7 @@ generate_Msg4(module_id_t module_idP,
|
||||
dl_req_body->number_pdu++;
|
||||
ra->state = WAITMSG4ACK;
|
||||
lcid = 0;
|
||||
UE_list->UE_sched_ctrl[UE_id].round[CC_idP][ra->harq_pid] = 0;
|
||||
UE_info->UE_sched_ctrl[UE_id].round[CC_idP][ra->harq_pid] = 0;
|
||||
msg4_header = 1 + 6 + 1; // CR header, CR CE, SDU header
|
||||
AssertFatal((ra->msg4_TBsize - ra->msg4_rrc_sdu_length - msg4_header)>=0,
|
||||
"msg4_TBS %d is too small, change mcs to increase by %d bytes\n",ra->msg4_TBsize,ra->msg4_rrc_sdu_length+msg4_header-ra->msg4_TBsize);
|
||||
@@ -848,7 +848,7 @@ generate_Msg4(module_id_t module_idP,
|
||||
module_idP, CC_idP, frameP, subframeP, ra->msg4_TBsize, ra->msg4_rrc_sdu_length, msg4_header, msg4_padding, msg4_post_padding);
|
||||
DevAssert (UE_id != UE_INDEX_INVALID); // FIXME not sure how to gracefully return
|
||||
// CHECK THIS: &cc[CC_idP].CCCH_pdu.payload[0]
|
||||
offset = generate_dlsch_header ((unsigned char *) mac->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char) UE_id].payload[0], 1, //num_sdus
|
||||
offset = generate_dlsch_header ((unsigned char *) mac->UE_info.DLSCH_pdu[CC_idP][0][(unsigned char) UE_id].payload[0], 1, //num_sdus
|
||||
(unsigned short *) &ra->msg4_rrc_sdu_length, //
|
||||
&lcid, // sdu_lcid
|
||||
255, // no drx
|
||||
@@ -856,7 +856,7 @@ generate_Msg4(module_id_t module_idP,
|
||||
ra->cont_res_id, // contention res id
|
||||
msg4_padding, // no padding
|
||||
msg4_post_padding);
|
||||
memcpy ((void *) &mac->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char) UE_id].payload[0][(unsigned char) offset], &cc[CC_idP].CCCH_pdu.payload[0], ra->msg4_rrc_sdu_length);
|
||||
memcpy ((void *) &mac->UE_info.DLSCH_pdu[CC_idP][0][(unsigned char) UE_id].payload[0][(unsigned char) offset], &cc[CC_idP].CCCH_pdu.payload[0], ra->msg4_rrc_sdu_length);
|
||||
// DL request
|
||||
mac->TX_req[CC_idP].sfn_sf = (frameP << 4) + subframeP;
|
||||
TX_req = &mac->TX_req[CC_idP].tx_request_body.tx_pdu_list[mac->TX_req[CC_idP].tx_request_body.number_of_pdus];
|
||||
@@ -864,7 +864,7 @@ generate_Msg4(module_id_t module_idP,
|
||||
TX_req->pdu_index = mac->pdu_index[CC_idP]++;
|
||||
TX_req->num_segments = 1;
|
||||
TX_req->segments[0].segment_length = ra->msg4_TBsize;
|
||||
TX_req->segments[0].segment_data = mac->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char) UE_id].payload[0];
|
||||
TX_req->segments[0].segment_data = mac->UE_info.DLSCH_pdu[CC_idP][0][(unsigned char) UE_id].payload[0];
|
||||
mac->TX_req[CC_idP].tx_request_body.number_of_pdus++;
|
||||
// Program ACK/NAK for Msg4 PDSCH
|
||||
int absSF = (frameP * 10) + subframeP;
|
||||
@@ -899,8 +899,8 @@ generate_Msg4(module_id_t module_idP,
|
||||
|
||||
ul_req_body->number_of_pdus++;
|
||||
T (T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT (module_idP), T_INT (CC_idP), T_INT (ra->rnti), T_INT (frameP), T_INT (subframeP),
|
||||
T_INT (0 /*harq_pid always 0? */ ), T_BUFFER (&mac->UE_list.DLSCH_pdu[CC_idP][0][UE_id].payload[0], ra->msg4_TBsize));
|
||||
trace_pdu (DIRECTION_DOWNLINK, (uint8_t *) mac->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char) UE_id].payload[0],
|
||||
T_INT (0 /*harq_pid always 0? */ ), T_BUFFER (&mac->UE_info.DLSCH_pdu[CC_idP][0][UE_id].payload[0], ra->msg4_TBsize));
|
||||
trace_pdu (DIRECTION_DOWNLINK, (uint8_t *) mac->UE_info.DLSCH_pdu[CC_idP][0][(unsigned char) UE_id].payload[0],
|
||||
ra->msg4_rrc_sdu_length,
|
||||
UE_id, 3, UE_RNTI (module_idP, UE_id),
|
||||
mac->frame, mac->subframe, 0, 0);
|
||||
@@ -963,10 +963,10 @@ generate_Msg4(module_id_t module_idP,
|
||||
1, // tpc, none
|
||||
getRIV(N_RB_DL, first_rb, 4), // resource_block_coding
|
||||
ra->msg4_mcs, // mcs
|
||||
1 - UE_list->UE_template[CC_idP][UE_id].oldNDI[ra->harq_pid],
|
||||
1 - UE_info->UE_template[CC_idP][UE_id].oldNDI[ra->harq_pid],
|
||||
0, // rv
|
||||
0); // vrb_flag
|
||||
UE_list->UE_template[CC_idP][UE_id].oldNDI[ra->harq_pid] = 1 - UE_list->UE_template[CC_idP][UE_id].oldNDI[ra->harq_pid];
|
||||
UE_info->UE_template[CC_idP][UE_id].oldNDI[ra->harq_pid] = 1 - UE_info->UE_template[CC_idP][UE_id].oldNDI[ra->harq_pid];
|
||||
LOG_D(MAC,
|
||||
"Frame %d, subframe %d: Msg4 DCI pdu_num %d (rnti %x,rnti_type %d,harq_pid %d, resource_block_coding (%p) %d\n",
|
||||
frameP, subframeP, dl_req_body->number_pdu,
|
||||
@@ -1000,7 +1000,7 @@ generate_Msg4(module_id_t module_idP,
|
||||
lcid = 0;
|
||||
// put HARQ process round to 0
|
||||
ra->harq_pid = frame_subframe2_dl_harq_pid(cc->tdd_Config,frameP,subframeP);
|
||||
UE_list->UE_sched_ctrl[UE_id].round[CC_idP][ra->harq_pid] = 0;
|
||||
UE_info->UE_sched_ctrl[UE_id].round[CC_idP][ra->harq_pid] = 0;
|
||||
|
||||
if ((ra->msg4_TBsize - rrc_sdu_length - msg4_header) <= 2) {
|
||||
msg4_padding = ra->msg4_TBsize - rrc_sdu_length - msg4_header;
|
||||
@@ -1018,7 +1018,7 @@ generate_Msg4(module_id_t module_idP,
|
||||
DevAssert(UE_id != UE_INDEX_INVALID); // FIXME not sure how to gracefully return
|
||||
// CHECK THIS: &cc[CC_idP].CCCH_pdu.payload[0]
|
||||
int num_sdus = rrc_sdu_length > 0 ? 1 : 0;
|
||||
offset = generate_dlsch_header((unsigned char *) mac->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char) UE_id].payload[0],
|
||||
offset = generate_dlsch_header((unsigned char *) mac->UE_info.DLSCH_pdu[CC_idP][0][(unsigned char) UE_id].payload[0],
|
||||
num_sdus, //num_sdus
|
||||
(unsigned short *) &rrc_sdu_length, //
|
||||
&lcid, // sdu_lcid
|
||||
@@ -1027,10 +1027,14 @@ generate_Msg4(module_id_t module_idP,
|
||||
ra->cont_res_id, // contention res id
|
||||
msg4_padding, // no padding
|
||||
msg4_post_padding);
|
||||
memcpy((void *) &mac->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0][(unsigned char)offset],
|
||||
memcpy((void *) &mac->UE_info.DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0][(unsigned char)offset],
|
||||
&cc[CC_idP].CCCH_pdu.payload[0], rrc_sdu_length);
|
||||
// DLSCH Config
|
||||
fill_nfapi_dlsch_config(mac, dl_req_body, ra->msg4_TBsize, mac->pdu_index[CC_idP], ra->rnti, 2, // resource_allocation_type : format 1A/1B/1D
|
||||
fill_nfapi_dlsch_config(&dl_req_body->dl_config_pdu_list[dl_req_body->number_pdu],
|
||||
ra->msg4_TBsize,
|
||||
mac->pdu_index[CC_idP],
|
||||
ra->rnti,
|
||||
2, // resource_allocation_type : format 1A/1B/1D
|
||||
0, // virtual_resource_block_assignment_flag : localized
|
||||
getRIV(N_RB_DL, first_rb, 4), // resource_block_coding : RIV, 4 PRB
|
||||
2, // modulation: QPSK
|
||||
@@ -1049,6 +1053,7 @@ generate_Msg4(module_id_t module_idP,
|
||||
(cc->p_eNB == 1) ? 1 : 2, // transmission mode
|
||||
1, // num_bf_prb_per_subband
|
||||
1); // num_bf_vector
|
||||
dl_req_body->number_pdu++;
|
||||
LOG_D(MAC,
|
||||
"Filled DLSCH config, pdu number %d, non-dci pdu_index %d\n",
|
||||
dl_req_body->number_pdu, mac->pdu_index[CC_idP]);
|
||||
@@ -1058,7 +1063,7 @@ generate_Msg4(module_id_t module_idP,
|
||||
(frameP * 10) + subframeP,
|
||||
rrc_sdu_length+offset,
|
||||
mac->pdu_index[CC_idP],
|
||||
mac->UE_list.
|
||||
mac->UE_info.
|
||||
DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0]);
|
||||
mac->pdu_index[CC_idP]++;
|
||||
dl_req->sfn_sf = mac->TX_req[CC_idP].sfn_sf;
|
||||
@@ -1074,11 +1079,11 @@ generate_Msg4(module_id_t module_idP,
|
||||
T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP),
|
||||
T_INT(CC_idP), T_INT(ra->rnti), T_INT(frameP),
|
||||
T_INT(subframeP), T_INT(0 /*harq_pid always 0? */ ),
|
||||
T_BUFFER(&mac->UE_list.DLSCH_pdu[CC_idP][0][UE_id].
|
||||
T_BUFFER(&mac->UE_info.DLSCH_pdu[CC_idP][0][UE_id].
|
||||
payload[0], ra->msg4_TBsize));
|
||||
trace_pdu(DIRECTION_DOWNLINK,
|
||||
(uint8_t *) mac->
|
||||
UE_list.DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0],
|
||||
UE_info.DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0],
|
||||
rrc_sdu_length, UE_id, WS_C_RNTI,
|
||||
UE_RNTI(module_idP, UE_id), mac->frame,
|
||||
mac->subframe, 0, 0);
|
||||
@@ -1116,14 +1121,14 @@ check_Msg4_retransmission(module_id_t module_idP, int CC_idP,
|
||||
int first_rb;
|
||||
int N_RB_DL;
|
||||
nfapi_dl_config_request_pdu_t *dl_config_pdu;
|
||||
UE_list_t *UE_list = &mac->UE_list;
|
||||
UE_info_t *UE_info = &mac->UE_info;
|
||||
nfapi_dl_config_request_t *dl_req;
|
||||
nfapi_dl_config_request_body_t *dl_req_body;
|
||||
int round;
|
||||
// check HARQ status and retransmit if necessary
|
||||
UE_id = find_UE_id(module_idP, ra->rnti);
|
||||
AssertFatal(UE_id >= 0, "Can't find UE for t-crnti\n");
|
||||
round = UE_list->UE_sched_ctrl[UE_id].round[CC_idP][ra->harq_pid];
|
||||
round = UE_info->UE_sched_ctrl[UE_id].round[CC_idP][ra->harq_pid];
|
||||
vrb_map = cc[CC_idP].vrb_map;
|
||||
dl_req = &mac->DL_req[CC_idP];
|
||||
dl_req_body = &dl_req->dl_config_request_body;
|
||||
@@ -1156,7 +1161,7 @@ check_Msg4_retransmission(module_id_t module_idP, int CC_idP,
|
||||
1, // tpc, none
|
||||
getRIV(N_RB_DL, first_rb, 4), // resource_block_coding
|
||||
ra->msg4_mcs, // mcs
|
||||
UE_list->UE_template[CC_idP][UE_id].oldNDI[ra->harq_pid],
|
||||
UE_info->UE_template[CC_idP][UE_id].oldNDI[ra->harq_pid],
|
||||
round & 3, // rv
|
||||
0); // vrb_flag
|
||||
|
||||
@@ -1173,7 +1178,8 @@ check_Msg4_retransmission(module_id_t module_idP, int CC_idP,
|
||||
// DLSCH Config
|
||||
//DJP - fix this pdu_index = -1
|
||||
LOG_D(MAC, "check_Msg4_retransmission() before fill_nfapi_dlsch_config() with pdu_index = -1 \n");
|
||||
fill_nfapi_dlsch_config(mac, dl_req_body, ra->msg4_TBsize,
|
||||
fill_nfapi_dlsch_config(&dl_req_body->dl_config_pdu_list[dl_req_body->number_pdu],
|
||||
ra->msg4_TBsize,
|
||||
-1
|
||||
/* retransmission, no pdu_index */
|
||||
, ra->rnti, 2, // resource_allocation_type : format 1A/1B/1D
|
||||
@@ -1195,6 +1201,7 @@ check_Msg4_retransmission(module_id_t module_idP, int CC_idP,
|
||||
(cc->p_eNB == 1) ? 1 : 2, // transmission mode
|
||||
1, // num_bf_prb_per_subband
|
||||
1); // num_bf_vector
|
||||
dl_req_body->number_pdu++;
|
||||
|
||||
if(RC.mac[module_idP]->scheduler_mode == SCHED_MODE_FAIR_RR) {
|
||||
set_dl_ue_select_msg4(CC_idP, 4, UE_id, ra->rnti);
|
||||
@@ -1226,8 +1233,8 @@ check_Msg4_retransmission(module_id_t module_idP, int CC_idP,
|
||||
LOG_D(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:IDLE\n", module_idP, frameP, subframeP);
|
||||
UE_id = find_UE_id(module_idP, ra->rnti);
|
||||
DevAssert(UE_id != -1);
|
||||
mac->UE_list.UE_template[UE_PCCID(module_idP, UE_id)][UE_id].configured = TRUE;
|
||||
mac->UE_list.UE_template[UE_PCCID(module_idP, UE_id)][UE_id].pusch_repetition_levels=ra->pusch_repetition_levels;
|
||||
mac->UE_info.UE_template[UE_PCCID(module_idP, UE_id)][UE_id].configured = TRUE;
|
||||
mac->UE_info.UE_template[UE_PCCID(module_idP, UE_id)][UE_id].pusch_repetition_levels=ra->pusch_repetition_levels;
|
||||
cancel_ra_proc(module_idP, CC_idP, frameP, ra->rnti);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -85,6 +85,30 @@ void dlsch_scheduler_pre_ue_select_fairRR(
|
||||
uint16_t nb_rbs_required[MAX_NUM_CCs][MAX_MOBILES_PER_ENB],
|
||||
DLSCH_UE_SELECT dlsch_ue_select[MAX_NUM_CCs]);
|
||||
|
||||
void dlsch_scheduler_pre_processor_reset_fairRR(
|
||||
module_id_t module_idP,
|
||||
frame_t frameP,
|
||||
sub_frame_t subframeP,
|
||||
int min_rb_unit[NFAPI_CC_MAX],
|
||||
uint16_t nb_rbs_required[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB],
|
||||
uint8_t rballoc_sub[NFAPI_CC_MAX][N_RBG_MAX],
|
||||
uint8_t MIMO_mode_indicator[NFAPI_CC_MAX][N_RBG_MAX]);
|
||||
|
||||
void assign_rbs_required_fairRR(
|
||||
module_id_t Mod_id,
|
||||
frame_t frameP,
|
||||
sub_frame_t subframe,
|
||||
uint16_t nb_rbs_required[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB]);
|
||||
|
||||
void dlsch_scheduler_pre_processor_allocate_fairRR(
|
||||
module_id_t Mod_id,
|
||||
int UE_id,
|
||||
uint8_t CC_id,
|
||||
int N_RBG,
|
||||
uint16_t nb_rbs_required[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB],
|
||||
uint16_t nb_rbs_remaining[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB],
|
||||
uint8_t rballoc_sub[NFAPI_CC_MAX][N_RBG_MAX]);
|
||||
|
||||
void dlsch_scheduler_pre_processor_fairRR (module_id_t Mod_id,
|
||||
frame_t frameP,
|
||||
sub_frame_t subframeP,
|
||||
|
||||
@@ -714,13 +714,11 @@ schedule_MBMS_NFAPI(module_id_t module_idP, uint8_t CC_id, frame_t frameP,
|
||||
mbms_rab_id = cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9;
|
||||
|
||||
rlc_status =
|
||||
mac_rlc_status_ind(module_idP, 0/*0xfffd*/, frameP, subframeP,
|
||||
mac_rlc_status_ind(module_idP, 0xfffd, frameP, subframeP,
|
||||
module_idP, ENB_FLAG_YES, MBMS_FLAG_YES,
|
||||
cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9,
|
||||
//MTCH,
|
||||
TBS - header_len_mcch - header_len_msi -
|
||||
sdu_length_total - header_len_mtch
|
||||
,0, 0
|
||||
0, 0
|
||||
);
|
||||
bytes_in_buffer = rlc_status.bytes_in_buffer;
|
||||
|
||||
@@ -773,7 +771,8 @@ schedule_MBMS_NFAPI(module_id_t module_idP, uint8_t CC_id, frame_t frameP,
|
||||
TBS - header_len_mcch - header_len_msi -
|
||||
sdu_length_total - header_len_mtch, header_len_mtch, rlc_status.bytes_in_buffer);
|
||||
|
||||
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, 0/*0xfffd*/, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_YES,cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9, 0, //not used
|
||||
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, 0xfffd, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_YES,cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9,
|
||||
TBS - header_len_mcch - header_len_msi - sdu_length_total - header_len_mtch,
|
||||
(char *)
|
||||
&mch_buffer[sdu_length_total]
|
||||
,0,
|
||||
@@ -1554,13 +1553,11 @@ schedule_MBMS(module_id_t module_idP, uint8_t CC_id, frame_t frameP,
|
||||
mbms_rab_id = cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9;
|
||||
|
||||
rlc_status =
|
||||
mac_rlc_status_ind(module_idP, 0/*0xfffd*/, frameP, subframeP,
|
||||
mac_rlc_status_ind(module_idP, 0xfffd, frameP, subframeP,
|
||||
module_idP, ENB_FLAG_YES, MBMS_FLAG_YES,
|
||||
cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9,
|
||||
//MTCH,
|
||||
TBS - header_len_mcch - header_len_msi -
|
||||
sdu_length_total - header_len_mtch
|
||||
,0, 0
|
||||
0, 0
|
||||
);
|
||||
bytes_in_buffer = rlc_status.bytes_in_buffer;
|
||||
|
||||
@@ -1579,7 +1576,8 @@ schedule_MBMS(module_id_t module_idP, uint8_t CC_id, frame_t frameP,
|
||||
TBS - header_len_mcch - header_len_msi -
|
||||
sdu_length_total - header_len_mtch, header_len_mtch, rlc_status.bytes_in_buffer);
|
||||
|
||||
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, 0/*0xfffd*/, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_YES,cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9, 0, //not used
|
||||
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, 0xfffd, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_YES,cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9,
|
||||
TBS - header_len_mcch - header_len_msi - sdu_length_total - header_len_mtch,
|
||||
(char *)
|
||||
&mch_buffer[sdu_length_total]
|
||||
,0,
|
||||
|
||||
@@ -133,16 +133,15 @@ schedule_ue_spec_phy_test(
|
||||
/*
|
||||
LOG_D(MAC,"CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n",
|
||||
CC_id, frameP,subframeP,UE_id,
|
||||
rnti,harq_pid,UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]);
|
||||
rnti,harq_pid,UE_info->UE_template[CC_id][UE_id].oldNDI[harq_pid]);
|
||||
|
||||
UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]=1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];
|
||||
UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid] = mcs;
|
||||
UE_list->UE_template[CC_id][UE_id].oldmcs2[harq_pid] = 0;
|
||||
AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated!=NULL,"physicalConfigDedicated is NULL\n");
|
||||
AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated!=NULL,"physicalConfigDedicated->pdsch_ConfigDedicated is NULL\n");
|
||||
UE_info->UE_template[CC_id][UE_id].oldNDI[harq_pid]=1-UE_info->UE_template[CC_id][UE_id].oldNDI[harq_pid];
|
||||
UE_info->UE_template[CC_id][UE_id].oldmcs1[harq_pid] = mcs;
|
||||
UE_info->UE_template[CC_id][UE_id].oldmcs2[harq_pid] = 0;
|
||||
AssertFatal(UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated!=NULL,"physicalConfigDedicated is NULL\n");
|
||||
AssertFatal(UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated!=NULL,"physicalConfigDedicated->pdsch_ConfigDedicated is NULL\n");
|
||||
*/
|
||||
fill_nfapi_dlsch_config(eNB,
|
||||
dl_req,
|
||||
fill_nfapi_dlsch_config(&dl_req->dl_config_pdu_list[dl_req->number_pdu],
|
||||
TBS,
|
||||
eNB->pdu_index[CC_id],
|
||||
rnti,
|
||||
@@ -166,11 +165,12 @@ schedule_ue_spec_phy_test(
|
||||
0, //number of PRBs treated as one subband, not used here
|
||||
0 // number of beamforming vectors, not used here
|
||||
);
|
||||
dl_req->number_pdu++;
|
||||
eNB->TX_req[CC_id].sfn_sf = fill_nfapi_tx_req(&eNB->TX_req[CC_id].tx_request_body,
|
||||
(frameP*10)+subframeP,
|
||||
TBS,
|
||||
eNB->pdu_index[CC_id],
|
||||
eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[0]);
|
||||
eNB->UE_info.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[0]);
|
||||
} else {
|
||||
LOG_W(MAC,"[eNB_scheduler_phytest] DCI allocation infeasible!\n");
|
||||
}
|
||||
@@ -192,7 +192,7 @@ void schedule_ulsch_phy_test(module_id_t module_idP,frame_t frameP,sub_frame_t s
|
||||
int N_RB_UL;
|
||||
eNB_MAC_INST *mac = RC.mac[module_idP];
|
||||
COMMON_channels_t *cc = &mac->common_channels[0];
|
||||
UE_list_t *UE_list=&mac->UE_list;
|
||||
UE_info_t *UE_info=&mac->UE_info;
|
||||
UE_TEMPLATE *UE_template;
|
||||
UE_sched_ctrl_t *UE_sched_ctrl;
|
||||
int sched_frame=frameP;
|
||||
@@ -231,8 +231,8 @@ void schedule_ulsch_phy_test(module_id_t module_idP,frame_t frameP,sub_frame_t s
|
||||
first_rb[CC_id] = 1;
|
||||
// loop over all active UEs
|
||||
// if (eNB_UE_stats->mode == PUSCH) { // ue has a ulsch channel
|
||||
UE_template = &UE_list->UE_template[CC_id][UE_id];
|
||||
UE_sched_ctrl = &UE_list->UE_sched_ctrl[UE_id];
|
||||
UE_template = &UE_info->UE_template[CC_id][UE_id];
|
||||
UE_sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
|
||||
harq_pid = subframe2harqpid(&cc[CC_id],sched_frame,sched_subframe);
|
||||
RC.eNB[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP*10)+subframeP] = UE_template->TBS_UL[harq_pid];
|
||||
//power control
|
||||
@@ -242,15 +242,15 @@ void schedule_ulsch_phy_test(module_id_t module_idP,frame_t frameP,sub_frame_t s
|
||||
// new transmission
|
||||
ndi = 1-UE_template->oldNDI_UL[harq_pid];
|
||||
UE_template->oldNDI_UL[harq_pid]=ndi;
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].snr = snr;
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].target_snr = target_snr;
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1 = mcs;
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].snr = snr;
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].target_snr = target_snr;
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1 = mcs;
|
||||
UE_template->mcs_UL[harq_pid] = mcs;//cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2 = mcs;
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2 = mcs;
|
||||
// buffer_occupancy = UE_template->ul_total_buffer;
|
||||
UE_template->TBS_UL[harq_pid] = get_TBS_UL(mcs,nb_rb);
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx += nb_rb;
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_TBS = get_TBS_UL(mcs,nb_rb);
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx += nb_rb;
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].ulsch_TBS = get_TBS_UL(mcs,nb_rb);
|
||||
// buffer_occupancy -= TBS;
|
||||
// bad indices : 20 (40 PRB), 21 (45 PRB), 22 (48 PRB)
|
||||
//store for possible retransmission
|
||||
|
||||
@@ -1169,14 +1169,14 @@ program_dlsch_acknak(module_id_t module_idP,
|
||||
{
|
||||
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
||||
COMMON_channels_t *cc = eNB->common_channels;
|
||||
UE_list_t *UE_list = &eNB->UE_list;
|
||||
UE_info_t *UE_info = &eNB->UE_info;
|
||||
rnti_t rnti = UE_RNTI(module_idP, UE_idP);
|
||||
nfapi_ul_config_request_body_t *ul_req;
|
||||
nfapi_ul_config_request_pdu_t *ul_config_pdu;
|
||||
int use_simultaneous_pucch_pusch = 0;
|
||||
nfapi_ul_config_ulsch_harq_information *ulsch_harq_information = NULL;
|
||||
nfapi_ul_config_harq_information *harq_information = NULL;
|
||||
struct LTE_PhysicalConfigDedicated__ext2 *ext2 = UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2;
|
||||
struct LTE_PhysicalConfigDedicated__ext2 *ext2 = UE_info->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2;
|
||||
|
||||
if (ext2 &&
|
||||
ext2->pucch_ConfigDedicated_v1020 &&
|
||||
@@ -1363,12 +1363,12 @@ fill_nfapi_ulsch_harq_information(module_id_t module_
|
||||
{
|
||||
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
||||
COMMON_channels_t *cc = &eNB->common_channels[CC_idP];
|
||||
UE_list_t *UE_list = &eNB->UE_list;
|
||||
UE_info_t *UE_info = &eNB->UE_info;
|
||||
int UE_id = find_UE_id(module_idP, rntiP);
|
||||
nfapi_ul_config_ulsch_harq_information_rel10_t *harq_information_rel10 = &harq_information->harq_information_rel10;
|
||||
AssertFatal(UE_id >= 0, "UE_id cannot be found, impossible\n");
|
||||
AssertFatal(UE_list != NULL, "UE_list is null\n");
|
||||
LTE_PhysicalConfigDedicated_t *physicalConfigDedicated = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated;
|
||||
AssertFatal(UE_info != NULL, "UE_info is null\n");
|
||||
LTE_PhysicalConfigDedicated_t *physicalConfigDedicated = UE_info->UE_template[CC_idP][UE_id].physicalConfigDedicated;
|
||||
AssertFatal(physicalConfigDedicated != NULL, "physicalConfigDedicated for rnti %x is null\n",
|
||||
rntiP);
|
||||
struct LTE_PUSCH_ConfigDedicated *puschConfigDedicated = physicalConfigDedicated->pusch_ConfigDedicated;
|
||||
@@ -1468,14 +1468,14 @@ fill_nfapi_harq_information(module_id_t module_idP,
|
||||
{
|
||||
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
||||
COMMON_channels_t *cc = &eNB->common_channels[CC_idP];
|
||||
UE_list_t *UE_list = &eNB->UE_list;
|
||||
UE_info_t *UE_info = &eNB->UE_info;
|
||||
int UE_id = find_UE_id(module_idP,
|
||||
rntiP);
|
||||
AssertFatal(UE_id >= 0, "UE_id cannot be found, impossible\n");
|
||||
AssertFatal(UE_list != NULL, "UE_list is null\n");
|
||||
AssertFatal(UE_info != NULL, "UE_info is null\n");
|
||||
harq_information->harq_information_rel11.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL11_TAG;
|
||||
harq_information->harq_information_rel11.num_ant_ports = 1;
|
||||
LTE_PhysicalConfigDedicated_t *physicalConfigDedicated = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated;
|
||||
LTE_PhysicalConfigDedicated_t *physicalConfigDedicated = UE_info->UE_template[CC_idP][UE_id].physicalConfigDedicated;
|
||||
struct LTE_PUCCH_ConfigDedicated *pucch_ConfigDedicated = NULL;
|
||||
|
||||
if (physicalConfigDedicated != NULL) pucch_ConfigDedicated = physicalConfigDedicated->pucch_ConfigDedicated;
|
||||
@@ -1489,7 +1489,7 @@ fill_nfapi_harq_information(module_id_t module_idP,
|
||||
case 6:
|
||||
case 7:
|
||||
if (cc->tdd_Config != NULL) {
|
||||
// AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated != NULL,
|
||||
// AssertFatal(UE_info->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated != NULL,
|
||||
// "pucch_ConfigDedicated is null for TDD!\n");
|
||||
if (physicalConfigDedicated != NULL && pucch_ConfigDedicated != NULL &&
|
||||
pucch_ConfigDedicated->tdd_AckNackFeedbackMode != NULL &&
|
||||
@@ -1619,15 +1619,14 @@ fill_nfapi_mch_config(nfapi_dl_config_request_body_t *dl_req,
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void
|
||||
fill_nfapi_dlsch_config(eNB_MAC_INST *eNB,
|
||||
nfapi_dl_config_request_body_t *dl_req,
|
||||
fill_nfapi_dlsch_config(nfapi_dl_config_request_pdu_t *dl_config_pdu,
|
||||
uint16_t length,
|
||||
int16_t pdu_index,
|
||||
uint16_t rnti,
|
||||
uint8_t resource_allocation_type,
|
||||
uint8_t
|
||||
virtual_resource_block_assignment_flag,
|
||||
uint16_t resource_block_coding,
|
||||
uint32_t resource_block_coding,
|
||||
uint8_t modulation,
|
||||
uint8_t redundancy_version,
|
||||
uint8_t transport_blocks,
|
||||
@@ -1646,7 +1645,6 @@ fill_nfapi_dlsch_config(eNB_MAC_INST *eNB,
|
||||
uint8_t num_bf_vector)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
nfapi_dl_config_request_pdu_t *dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu];
|
||||
memset((void *) dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t));
|
||||
dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE;
|
||||
dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu));
|
||||
@@ -1673,7 +1671,6 @@ fill_nfapi_dlsch_config(eNB_MAC_INST *eNB,
|
||||
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = transmission_mode;
|
||||
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = num_bf_prb_per_subband;
|
||||
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = num_bf_vector;
|
||||
dl_req->number_pdu++;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1879,8 +1876,7 @@ mpdcch_sf_condition(eNB_MAC_INST *eNB,
|
||||
break;
|
||||
|
||||
case TYPEUESPEC:
|
||||
epdcch_setconfig_r11 =
|
||||
eNB->UE_list.UE_template[CC_id][UE_id].physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11.choice.setup.setConfigToAddModList_r11->list.array[0];
|
||||
epdcch_setconfig_r11 = eNB->UE_info.UE_template[CC_id][UE_id].physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11.choice.setup.setConfigToAddModList_r11->list.array[0];
|
||||
AssertFatal(epdcch_setconfig_r11 != NULL, " epdcch_setconfig_r11 is null for UE specific \n");
|
||||
AssertFatal(epdcch_setconfig_r11->ext2 != NULL, " ext2 doesn't exist in epdcch config ' \n");
|
||||
|
||||
@@ -1988,11 +1984,11 @@ find_UE_id(module_id_t mod_idP,
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
int UE_id;
|
||||
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
|
||||
UE_info_t *UE_info = &RC.mac[mod_idP]->UE_info;
|
||||
|
||||
for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) {
|
||||
if (UE_list->active[UE_id] == TRUE) {
|
||||
if (UE_list->UE_template[UE_PCCID(mod_idP, UE_id)][UE_id].rnti == rntiP) {
|
||||
if (UE_info->active[UE_id] == TRUE) {
|
||||
if (UE_info->UE_template[UE_PCCID(mod_idP, UE_id)][UE_id].rnti == rntiP) {
|
||||
return UE_id;
|
||||
}
|
||||
}
|
||||
@@ -2027,7 +2023,7 @@ find_RA_id(module_id_t mod_idP,
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int
|
||||
UE_num_active_CC(UE_list_t *listP,
|
||||
UE_num_active_CC(UE_info_t *listP,
|
||||
int ue_idP)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
@@ -2040,7 +2036,7 @@ UE_PCCID(module_id_t mod_idP,
|
||||
int ue_idP)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
return (RC.mac[mod_idP]->UE_list.pCC_id[ue_idP]);
|
||||
return (RC.mac[mod_idP]->UE_info.pCC_id[ue_idP]);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -2051,7 +2047,7 @@ UE_RNTI(module_id_t mod_idP,
|
||||
{
|
||||
if (!RC.mac || !RC.mac[mod_idP]) return 0;
|
||||
|
||||
rnti_t rnti = RC.mac[mod_idP]->UE_list.UE_template[UE_PCCID(mod_idP,
|
||||
rnti_t rnti = RC.mac[mod_idP]->UE_info.UE_template[UE_PCCID(mod_idP,
|
||||
ue_idP)][ue_idP].rnti;
|
||||
|
||||
if (rnti > 0) {
|
||||
@@ -2069,7 +2065,7 @@ is_UE_active(module_id_t mod_idP,
|
||||
int ue_idP)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
return (RC.mac[mod_idP]->UE_list.active[ue_idP]);
|
||||
return (RC.mac[mod_idP]->UE_info.active[ue_idP]);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -2122,28 +2118,46 @@ get_aggregation(uint8_t bw_index,
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
* Dump the UL or DL UE_list into LOG_T(MAC)
|
||||
* Dump the UE_list into LOG_T(MAC)
|
||||
*/
|
||||
void
|
||||
dump_ue_list(UE_list_t *listP,
|
||||
int ul_flag)
|
||||
dump_ue_list(UE_list_t *listP) {
|
||||
for (int j = listP->head; j >= 0; j = listP->next[j])
|
||||
LOG_T(MAC, "DL list node %d => %d\n", j, listP->next[j]);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
if (ul_flag == 0) {
|
||||
for (int j = listP->head; j >= 0; j = listP->next[j]) {
|
||||
LOG_T(MAC, "DL list node %d => %d\n",
|
||||
j,
|
||||
listP->next[j]);
|
||||
}
|
||||
/*
|
||||
* Add a UE to UE_list listP
|
||||
*/
|
||||
inline void add_ue_list(UE_list_t *listP, int UE_id) {
|
||||
if (listP->head == -1) {
|
||||
listP->head = UE_id;
|
||||
listP->next[UE_id] = -1;
|
||||
} else {
|
||||
for (int j = listP->head_ul; j >= 0; j = listP->next_ul[j]) {
|
||||
LOG_T(MAC, "UL list node %d => %d\n",
|
||||
j,
|
||||
listP->next_ul[j]);
|
||||
}
|
||||
int i = listP->head;
|
||||
while (listP->next[i] >= 0)
|
||||
i = listP->next[i];
|
||||
listP->next[i] = UE_id;
|
||||
listP->next[UE_id] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
* Remove a UE from the UE_list listP, return the previous element
|
||||
*/
|
||||
inline int remove_ue_list(UE_list_t *listP, int UE_id) {
|
||||
listP->next[UE_id] = -1;
|
||||
if (listP->head == UE_id) {
|
||||
listP->head = listP->next[UE_id];
|
||||
return -1;
|
||||
}
|
||||
|
||||
return;
|
||||
int previous = prev(listP, UE_id);
|
||||
if (previous != -1)
|
||||
listP->next[previous] = listP->next[UE_id];
|
||||
return previous;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -2158,50 +2172,47 @@ add_new_ue(module_id_t mod_idP,
|
||||
{
|
||||
int UE_id;
|
||||
int i, j;
|
||||
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
|
||||
LOG_D(MAC, "[eNB %d, CC_id %d] Adding UE with rnti %x (next avail %d, num_UEs %d)\n",
|
||||
UE_info_t *UE_info = &RC.mac[mod_idP]->UE_info;
|
||||
LOG_D(MAC, "[eNB %d, CC_id %d] Adding UE with rnti %x (prev. num_UEs %d)\n",
|
||||
mod_idP,
|
||||
cc_idP,
|
||||
rntiP,
|
||||
UE_list->avail,
|
||||
UE_list->num_UEs);
|
||||
dump_ue_list(UE_list, 0);
|
||||
UE_info->num_UEs);
|
||||
|
||||
for (i = 0; i < MAX_MOBILES_PER_ENB; i++) {
|
||||
if (UE_list->active[i] == TRUE)
|
||||
if (UE_info->active[i] == TRUE)
|
||||
continue;
|
||||
|
||||
UE_id = i;
|
||||
memset(&UE_list->UE_template[cc_idP][UE_id], 0, sizeof(UE_TEMPLATE));
|
||||
UE_list->UE_template[cc_idP][UE_id].rnti = rntiP;
|
||||
UE_list->UE_template[cc_idP][UE_id].configured = FALSE;
|
||||
UE_list->numactiveCCs[UE_id] = 1;
|
||||
UE_list->numactiveULCCs[UE_id] = 1;
|
||||
UE_list->pCC_id[UE_id] = cc_idP;
|
||||
UE_list->ordered_CCids[0][UE_id] = cc_idP;
|
||||
UE_list->ordered_ULCCids[0][UE_id] = cc_idP;
|
||||
UE_list->num_UEs++;
|
||||
UE_list->active[UE_id] = TRUE;
|
||||
memset(&UE_info->UE_template[cc_idP][UE_id], 0, sizeof(UE_TEMPLATE));
|
||||
UE_info->UE_template[cc_idP][UE_id].rnti = rntiP;
|
||||
UE_info->UE_template[cc_idP][UE_id].configured = FALSE;
|
||||
UE_info->numactiveCCs[UE_id] = 1;
|
||||
UE_info->numactiveULCCs[UE_id] = 1;
|
||||
UE_info->pCC_id[UE_id] = cc_idP;
|
||||
UE_info->ordered_CCids[0][UE_id] = cc_idP;
|
||||
UE_info->ordered_ULCCids[0][UE_id] = cc_idP;
|
||||
UE_info->num_UEs++;
|
||||
UE_info->active[UE_id] = TRUE;
|
||||
add_ue_list(&UE_info->list, UE_id);
|
||||
dump_ue_list(&UE_info->list);
|
||||
if (IS_SOFTMODEM_IQPLAYER)// not specific to record/playback ?
|
||||
UE_list->UE_template[cc_idP][UE_id].pre_assigned_mcs_ul = 0;
|
||||
UE_list->UE_template[cc_idP][UE_id].rach_resource_type = rach_resource_type;
|
||||
memset((void *) &UE_list->UE_sched_ctrl[UE_id],
|
||||
UE_info->UE_template[cc_idP][UE_id].pre_assigned_mcs_ul = 0;
|
||||
UE_info->UE_template[cc_idP][UE_id].rach_resource_type = rach_resource_type;
|
||||
memset((void *) &UE_info->UE_sched_ctrl[UE_id],
|
||||
0,
|
||||
sizeof(UE_sched_ctrl_t));
|
||||
memset((void *) &UE_list->eNB_UE_stats[cc_idP][UE_id],
|
||||
memset((void *) &UE_info->eNB_UE_stats[cc_idP][UE_id],
|
||||
0,
|
||||
sizeof(eNB_UE_STATS));
|
||||
UE_list->UE_sched_ctrl[UE_id].ue_reestablishment_reject_timer = 0;
|
||||
/* default slice in case there was something different */
|
||||
UE_list->assoc_dl_slice_idx[UE_id] = 0;
|
||||
UE_list->assoc_ul_slice_idx[UE_id] = 0;
|
||||
UE_list->UE_sched_ctrl[UE_id].ta_update = 31;
|
||||
UE_info->UE_sched_ctrl[UE_id].ue_reestablishment_reject_timer = 0;
|
||||
UE_info->UE_sched_ctrl[UE_id].ta_update = 31;
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
UE_list->UE_template[cc_idP][UE_id].oldNDI[j] = 0;
|
||||
UE_list->UE_template[cc_idP][UE_id].oldNDI_UL[j] = 0;
|
||||
UE_list->UE_sched_ctrl[UE_id].round[cc_idP][j] = 8;
|
||||
UE_list->UE_sched_ctrl[UE_id].round_UL[cc_idP][j] = 0;
|
||||
UE_info->UE_template[cc_idP][UE_id].oldNDI[j] = 0;
|
||||
UE_info->UE_template[cc_idP][UE_id].oldNDI_UL[j] = 0;
|
||||
UE_info->UE_sched_ctrl[UE_id].round[cc_idP][j] = 8;
|
||||
UE_info->UE_sched_ctrl[UE_id].round_UL[cc_idP][j] = 0;
|
||||
}
|
||||
|
||||
eNB_ulsch_info[mod_idP][cc_idP][UE_id].status = S_UL_WAITING;
|
||||
@@ -2211,15 +2222,11 @@ add_new_ue(module_id_t mod_idP,
|
||||
UE_id,
|
||||
cc_idP,
|
||||
rntiP);
|
||||
dump_ue_list(UE_list,
|
||||
0);
|
||||
return (UE_id);
|
||||
}
|
||||
|
||||
// printf("MAC: cannot add new UE for rnti %x\n", rntiP);
|
||||
LOG_E(MAC, "error in add_new_ue(), could not find space in UE_list, Dumping UE list\n");
|
||||
dump_ue_list(UE_list,
|
||||
0);
|
||||
dump_ue_list(&UE_info->list);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -2232,7 +2239,7 @@ rrc_mac_remove_ue(module_id_t mod_idP,
|
||||
rnti_t rntiP)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
|
||||
UE_info_t *UE_info = &RC.mac[mod_idP]->UE_info;
|
||||
int UE_id = find_UE_id(mod_idP, rntiP);
|
||||
eNB_UE_STATS *ue_stats = NULL;
|
||||
int pCC_id = -1;
|
||||
@@ -2248,37 +2255,14 @@ rrc_mac_remove_ue(module_id_t mod_idP,
|
||||
UE_id,
|
||||
pCC_id,
|
||||
rntiP);
|
||||
dump_ue_list(UE_list, 0); // DL list displayed in LOG_T(MAC)
|
||||
UE_list->active[UE_id] = FALSE;
|
||||
UE_list->num_UEs--;
|
||||
UE_info->active[UE_id] = FALSE;
|
||||
UE_info->num_UEs--;
|
||||
|
||||
/* If present, remove UE from DL list */
|
||||
if (UE_list->head == UE_id) {
|
||||
UE_list->head = UE_list->next[UE_id];
|
||||
} else {
|
||||
int previous = prev(UE_list, UE_id, 0);
|
||||
|
||||
if (previous != -1) {
|
||||
UE_list->next[previous] = UE_list->next[UE_id];
|
||||
}
|
||||
}
|
||||
|
||||
/* If present, remove UE from UL list */
|
||||
if (UE_list->head_ul == UE_id) {
|
||||
UE_list->head_ul = UE_list->next_ul[UE_id];
|
||||
} else {
|
||||
int previous = prev(UE_list, UE_id, 1);
|
||||
|
||||
if (previous != -1) {
|
||||
UE_list->next_ul[previous] = UE_list->next_ul[UE_id];
|
||||
}
|
||||
}
|
||||
remove_ue_list(&UE_info->list, UE_id);
|
||||
|
||||
/* Clear all remaining pending transmissions */
|
||||
memset(&UE_list->UE_template[pCC_id][UE_id],
|
||||
0,
|
||||
sizeof(UE_TEMPLATE));
|
||||
ue_stats = &UE_list->eNB_UE_stats[pCC_id][UE_id];
|
||||
memset(&UE_info->UE_template[pCC_id][UE_id], 0, sizeof(UE_TEMPLATE));
|
||||
ue_stats = &UE_info->eNB_UE_stats[pCC_id][UE_id];
|
||||
ue_stats->total_rbs_used = 0;
|
||||
ue_stats->total_rbs_used_retx = 0;
|
||||
|
||||
@@ -2355,166 +2339,19 @@ rrc_mac_remove_ue(module_id_t mod_idP,
|
||||
/*
|
||||
* Returns the previous UE_id in the scheduling list in UL or DL
|
||||
*/
|
||||
int
|
||||
prev(UE_list_t *listP,
|
||||
int nodeP,
|
||||
int ul_flag)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
if (ul_flag == 0) {
|
||||
if (nodeP == listP->head) {
|
||||
return nodeP;
|
||||
}
|
||||
inline int prev(UE_list_t *listP, int nodeP) {
|
||||
if (nodeP == listP->head)
|
||||
return -1; /* there is no previous of the head */
|
||||
|
||||
for (int j = listP->head; j >= 0; j = listP->next[j]) {
|
||||
if (listP->next[j] == nodeP) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (nodeP == listP->head_ul) {
|
||||
return nodeP;
|
||||
}
|
||||
for (int j = listP->head; j >= 0; j = listP->next[j])
|
||||
if (listP->next[j] == nodeP)
|
||||
return j;
|
||||
|
||||
for (int j = listP->head_ul; j >= 0; j = listP->next_ul[j]) {
|
||||
if (listP->next_ul[j] == nodeP) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG_E(MAC, "error in prev(), could not find previous to %d in UE_list %s, should never happen, Dumping UE list\n",
|
||||
nodeP,
|
||||
(ul_flag == 0) ? "DL" : "UL");
|
||||
dump_ue_list(listP,
|
||||
ul_flag);
|
||||
LOG_E(MAC, "%s(): could not find previous to %d in UE_list\n", __func__, nodeP);
|
||||
dump_ue_list(listP);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void
|
||||
swap_UEs(UE_list_t *listP,
|
||||
int nodeiP,
|
||||
int nodejP,
|
||||
int ul_flag)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
int prev_i, prev_j, next_i, next_j;
|
||||
LOG_T(MAC, "Swapping UE %d,%d\n",
|
||||
nodeiP,
|
||||
nodejP);
|
||||
dump_ue_list(listP,
|
||||
ul_flag);
|
||||
prev_i = prev(listP,
|
||||
nodeiP,
|
||||
ul_flag);
|
||||
prev_j = prev(listP,
|
||||
nodejP,
|
||||
ul_flag);
|
||||
AssertFatal((prev_i >= 0) && (prev_j >= 0), "swap_UEs: problem");
|
||||
|
||||
if (ul_flag == 0) {
|
||||
next_i = listP->next[nodeiP];
|
||||
next_j = listP->next[nodejP];
|
||||
} else {
|
||||
next_i = listP->next_ul[nodeiP];
|
||||
next_j = listP->next_ul[nodejP];
|
||||
}
|
||||
|
||||
LOG_T(MAC, "[%s] next_i %d, next_i, next_j %d, head %d \n",
|
||||
(ul_flag == 0) ? "DL" : "UL",
|
||||
next_i,
|
||||
next_j,
|
||||
listP->head);
|
||||
|
||||
if (ul_flag == 0) {
|
||||
if (next_i == nodejP) { // case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...
|
||||
LOG_T(MAC, "Case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...\n");
|
||||
listP->next[nodeiP] = next_j;
|
||||
listP->next[nodejP] = nodeiP;
|
||||
|
||||
if (nodeiP == listP->head) { // case i j n(j)
|
||||
listP->head = nodejP;
|
||||
} else {
|
||||
listP->next[prev_i] = nodejP;
|
||||
}
|
||||
} else if (next_j == nodeiP) { // case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...
|
||||
LOG_T(MAC, "Case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...\n");
|
||||
listP->next[nodejP] = next_i;
|
||||
listP->next[nodeiP] = nodejP;
|
||||
|
||||
if (nodejP == listP->head) { // case j i n(i)
|
||||
listP->head = nodeiP;
|
||||
} else {
|
||||
listP->next[prev_j] = nodeiP;
|
||||
}
|
||||
} else { // case ... p(i) i n(i) ... p(j) j n(j) ...
|
||||
listP->next[nodejP] = next_i;
|
||||
listP->next[nodeiP] = next_j;
|
||||
|
||||
if (nodeiP == listP->head) {
|
||||
LOG_T(MAC, "changing head to %d\n",
|
||||
nodejP);
|
||||
listP->head = nodejP;
|
||||
listP->next[prev_j] = nodeiP;
|
||||
} else if (nodejP == listP->head) {
|
||||
LOG_D(MAC, "changing head to %d\n",
|
||||
nodeiP);
|
||||
listP->head = nodeiP;
|
||||
listP->next[prev_i] = nodejP;
|
||||
} else {
|
||||
listP->next[prev_i] = nodejP;
|
||||
listP->next[prev_j] = nodeiP;
|
||||
}
|
||||
}
|
||||
} else { // ul_flag
|
||||
if (next_i == nodejP) { // case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...
|
||||
LOG_T(MAC, "[UL] Case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...\n");
|
||||
listP->next_ul[nodeiP] = next_j;
|
||||
listP->next_ul[nodejP] = nodeiP;
|
||||
|
||||
if (nodeiP == listP->head_ul) { // case i j n(j)
|
||||
listP->head_ul = nodejP;
|
||||
} else {
|
||||
listP->next_ul[prev_i] = nodejP;
|
||||
}
|
||||
} else if (next_j == nodeiP) { // case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...
|
||||
LOG_T(MAC, "[UL]Case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...\n");
|
||||
listP->next_ul[nodejP] = next_i;
|
||||
listP->next_ul[nodeiP] = nodejP;
|
||||
|
||||
if (nodejP == listP->head_ul) { // case j i n(i)
|
||||
listP->head_ul = nodeiP;
|
||||
} else {
|
||||
listP->next_ul[prev_j] = nodeiP;
|
||||
}
|
||||
} else { // case ... p(i) i n(i) ... p(j) j n(j) ...
|
||||
listP->next_ul[nodejP] = next_i;
|
||||
listP->next_ul[nodeiP] = next_j;
|
||||
|
||||
if (nodeiP == listP->head_ul) {
|
||||
LOG_T(MAC, "[UL]changing head to %d\n",
|
||||
nodejP);
|
||||
listP->head_ul = nodejP;
|
||||
listP->next_ul[prev_j] = nodeiP;
|
||||
} else if (nodejP == listP->head_ul) {
|
||||
LOG_T(MAC, "[UL]changing head to %d\n",
|
||||
nodeiP);
|
||||
listP->head_ul = nodeiP;
|
||||
listP->next_ul[prev_i] = nodejP;
|
||||
} else {
|
||||
listP->next_ul[prev_i] = nodejP;
|
||||
listP->next_ul[prev_j] = nodeiP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG_T(MAC, "After swap\n");
|
||||
dump_ue_list(listP,
|
||||
ul_flag);
|
||||
return;
|
||||
}
|
||||
|
||||
// This has to be updated to include BSR information
|
||||
//------------------------------------------------------------------------------
|
||||
uint8_t
|
||||
@@ -2523,8 +2360,8 @@ UE_is_to_be_scheduled(module_id_t module_idP,
|
||||
uint8_t UE_id)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
UE_TEMPLATE *UE_template = &RC.mac[module_idP]->UE_list.UE_template[CC_id][UE_id];
|
||||
UE_sched_ctrl_t *UE_sched_ctl = &RC.mac[module_idP]->UE_list.UE_sched_ctrl[UE_id];
|
||||
UE_TEMPLATE *UE_template = &RC.mac[module_idP]->UE_info.UE_template[CC_id][UE_id];
|
||||
UE_sched_ctrl_t *UE_sched_ctl = &RC.mac[module_idP]->UE_info.UE_sched_ctrl[UE_id];
|
||||
int rrc_status;
|
||||
|
||||
// do not schedule UE if UL is not working
|
||||
@@ -2566,7 +2403,7 @@ get_tmode(module_id_t module_idP,
|
||||
{
|
||||
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
||||
COMMON_channels_t *cc = &eNB->common_channels[CC_idP];
|
||||
struct LTE_PhysicalConfigDedicated *physicalConfigDedicated = eNB->UE_list.UE_template[CC_idP][UE_idP].physicalConfigDedicated;
|
||||
struct LTE_PhysicalConfigDedicated *physicalConfigDedicated = eNB->UE_info.UE_template[CC_idP][UE_idP].physicalConfigDedicated;
|
||||
|
||||
if (physicalConfigDedicated == NULL) { // RRCConnectionSetup not received by UE yet
|
||||
AssertFatal(cc->p_eNB <= 2, "p_eNB is %d, should be <2\n",
|
||||
@@ -2776,19 +2613,21 @@ get_min_rb_unit(module_id_t module_id,
|
||||
int N_RB_DL = to_prb(RC.mac[module_id]->common_channels[CC_id].mib->message.dl_Bandwidth);
|
||||
|
||||
switch (N_RB_DL) {
|
||||
case 6: // 1.4 MHz
|
||||
case 6: // 1.4MHz
|
||||
min_rb_unit = 1;
|
||||
break;
|
||||
|
||||
case 25: // 5HMz
|
||||
case 15: // 3MHz
|
||||
case 25: // 5MHz
|
||||
min_rb_unit = 2;
|
||||
break;
|
||||
|
||||
case 50: // 10HMz
|
||||
case 50: // 10MHz
|
||||
min_rb_unit = 3;
|
||||
break;
|
||||
|
||||
case 100: // 20HMz
|
||||
case 75: // 15MHz
|
||||
case 100: // 20MHz
|
||||
min_rb_unit = 4;
|
||||
break;
|
||||
|
||||
@@ -2809,7 +2648,7 @@ uint32_t
|
||||
allocate_prbs_sub(int nb_rb,
|
||||
int N_RB_DL,
|
||||
int N_RBG,
|
||||
uint8_t *rballoc)
|
||||
const uint8_t *rballoc)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
int check = 0; //check1=0,check2=0;
|
||||
@@ -3482,7 +3321,7 @@ try_again:
|
||||
|
||||
if (fCCE == -1) {
|
||||
if (DL_req->number_pdcch_ofdm_symbols == max_symbol) {
|
||||
LOG_I(MAC, "subframe %d: Dropping Allocation for RNTI %x\n",
|
||||
LOG_D(MAC, "subframe %d: Dropping Allocation for RNTI %x\n",
|
||||
subframeP,
|
||||
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.rnti);
|
||||
|
||||
@@ -3671,6 +3510,121 @@ CCE_allocation_infeasible(int module_idP,
|
||||
return res;
|
||||
}
|
||||
|
||||
int CCE_try_allocate_dlsch(int module_id,
|
||||
int CC_id,
|
||||
int subframe,
|
||||
int UE_id,
|
||||
uint8_t dl_cqi) {
|
||||
const rnti_t rnti = RC.mac[module_id]->UE_info.UE_template[CC_id][UE_id].rnti;
|
||||
nfapi_dl_config_request_body_t *DL_req = &RC.mac[module_id]->DL_req[CC_id].dl_config_request_body;
|
||||
|
||||
if (DL_req->number_pdu >= MAX_NUM_DL_PDU) {
|
||||
LOG_W(MAC, "Subframe %d: FAPI DL structure is full, skip scheduling UE %d\n", subframe, rnti);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int aggregation = 2;
|
||||
const uint8_t tm = get_tmode(module_id, CC_id, UE_id);
|
||||
switch (tm) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 7:
|
||||
aggregation = get_aggregation(get_bw_index(module_id, CC_id),
|
||||
dl_cqi,
|
||||
format1);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
aggregation = get_aggregation(get_bw_index(module_id, CC_id),
|
||||
dl_cqi,
|
||||
format2A);
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(0, "Unsupported transmission mode %d\n", tm);
|
||||
break;
|
||||
}
|
||||
|
||||
nfapi_dl_config_request_pdu_t *dl_config_pdu = &DL_req->dl_config_pdu_list[DL_req->number_pdu];
|
||||
memset(dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t));
|
||||
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG;
|
||||
dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE;
|
||||
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti;
|
||||
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1;
|
||||
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = aggregation;
|
||||
DL_req->number_pdu++;
|
||||
LOG_D(MAC, "Subframe %d: Checking CCE feasibility format 1: (%x,%d) \n",
|
||||
subframe, rnti, aggregation);
|
||||
|
||||
if (allocate_CCEs(module_id, CC_id, 0, subframe, 0) < 0) {
|
||||
DL_req->number_pdu--;
|
||||
return -1;
|
||||
}
|
||||
|
||||
DL_req->number_dci++;
|
||||
nfapi_dl_config_request_pdu_t *dl_dlsch_pdu = &DL_req->dl_config_pdu_list[DL_req->number_pdu];
|
||||
dl_dlsch_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE;
|
||||
dl_dlsch_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG;
|
||||
dl_dlsch_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = rnti;
|
||||
DL_req->number_pdu++;
|
||||
|
||||
return DL_req->number_pdu - 2;
|
||||
}
|
||||
|
||||
int CCE_try_allocate_ulsch(int module_id,
|
||||
int CC_id,
|
||||
int subframe,
|
||||
int UE_id,
|
||||
uint8_t dl_cqi) {
|
||||
const rnti_t rnti = RC.mac[module_id]->UE_info.UE_template[CC_id][UE_id].rnti;
|
||||
nfapi_hi_dci0_request_body_t *HI_DCI0_req = &RC.mac[module_id]->HI_DCI0_req[CC_id][subframe].hi_dci0_request_body;
|
||||
|
||||
if (HI_DCI0_req->number_of_dci + HI_DCI0_req->number_of_hi >= MAX_NUM_HI_DCI0_PDU) {
|
||||
LOG_W(MAC, "Subframe %d: FAPI UL structure is full, skip scheduling UE %d\n", subframe, rnti);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int aggregation = 2;
|
||||
const uint8_t tm = get_tmode(module_id, CC_id, UE_id);
|
||||
switch (tm) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 7:
|
||||
aggregation = get_aggregation(get_bw_index(module_id, CC_id),
|
||||
dl_cqi,
|
||||
format1);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
aggregation = get_aggregation(get_bw_index(module_id, CC_id),
|
||||
dl_cqi,
|
||||
format2A);
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(0, "Unsupported transmission mode %d\n", tm);
|
||||
break;
|
||||
}
|
||||
|
||||
const int idx = HI_DCI0_req->number_of_dci + HI_DCI0_req->number_of_hi;
|
||||
nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_pdu_list[idx];
|
||||
memset(hi_dci0_pdu, 0, sizeof(nfapi_hi_dci0_request_pdu_t));
|
||||
hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_DCI_PDU_TYPE;
|
||||
hi_dci0_pdu->dci_pdu.dci_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL8_TAG;
|
||||
hi_dci0_pdu->dci_pdu.dci_pdu_rel8.rnti = rnti;
|
||||
hi_dci0_pdu->dci_pdu.dci_pdu_rel8.aggregation_level = aggregation;
|
||||
HI_DCI0_req->number_of_dci++;
|
||||
LOG_D(MAC, "%s() sf %d: Checking CCE feasibility format 2: RNTI %04x, agg %d\n",
|
||||
__func__, subframe, rnti, aggregation);
|
||||
|
||||
if (allocate_CCEs(module_id, CC_id, 0, subframe, 0) < 0) {
|
||||
HI_DCI0_req->number_of_dci--;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void
|
||||
get_retransmission_timing(LTE_TDD_Config_t *tdd_Config,
|
||||
@@ -3931,15 +3885,15 @@ extract_harq(module_id_t mod_idP,
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
eNB_MAC_INST *eNB = RC.mac[mod_idP];
|
||||
UE_list_t *UE_list = &eNB->UE_list;
|
||||
UE_sched_ctrl_t *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
|
||||
UE_info_t *UE_info = &eNB->UE_info;
|
||||
UE_sched_ctrl_t *sched_ctl = &UE_info->UE_sched_ctrl[UE_id];
|
||||
rnti_t rnti = UE_RNTI(mod_idP, UE_id);
|
||||
COMMON_channels_t *cc = &eNB->common_channels[CC_idP];
|
||||
nfapi_harq_indication_fdd_rel13_t *harq_indication_fdd;
|
||||
nfapi_harq_indication_tdd_rel13_t *harq_indication_tdd;
|
||||
uint16_t num_ack_nak;
|
||||
int numCC = UE_list->numactiveCCs[UE_id];
|
||||
int pCCid = UE_list->pCC_id[UE_id];
|
||||
int numCC = UE_info->numactiveCCs[UE_id];
|
||||
int pCCid = UE_info->pCC_id[UE_id];
|
||||
int spatial_bundling = 0;
|
||||
int tmode[5];
|
||||
int i, j, m;
|
||||
@@ -3947,7 +3901,7 @@ extract_harq(module_id_t mod_idP,
|
||||
sub_frame_t subframe_tx;
|
||||
int frame_tx;
|
||||
uint8_t harq_pid;
|
||||
LTE_PhysicalConfigDedicated_t *physicalConfigDedicated = UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated;
|
||||
LTE_PhysicalConfigDedicated_t *physicalConfigDedicated = UE_info->UE_template[pCCid][UE_id].physicalConfigDedicated;
|
||||
|
||||
if (physicalConfigDedicated != NULL && physicalConfigDedicated->pucch_ConfigDedicated != NULL &&
|
||||
physicalConfigDedicated->ext7 != NULL && physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13 != NULL &&
|
||||
@@ -4081,7 +4035,7 @@ extract_harq(module_id_t mod_idP,
|
||||
sched_ctl->round[CC_idP][harq_pid]);
|
||||
|
||||
// use 1 HARQ proces of BL/CE UE for now
|
||||
if (UE_list->UE_template[pCCid][UE_id].rach_resource_type > 0) harq_pid = 0;
|
||||
if (UE_info->UE_template[pCCid][UE_id].rach_resource_type > 0) harq_pid = 0;
|
||||
|
||||
switch (harq_indication_fdd->mode) {
|
||||
case 0: // Format 1a/b (10.1.2.1)
|
||||
@@ -4567,18 +4521,18 @@ extract_pucch_csi(module_id_t mod_idP,
|
||||
uint8_t length)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
|
||||
UE_sched_ctrl_t *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
|
||||
UE_info_t *UE_info = &RC.mac[mod_idP]->UE_info;
|
||||
UE_sched_ctrl_t *sched_ctl = &UE_info->UE_sched_ctrl[UE_id];
|
||||
COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP];
|
||||
int no_pmi;
|
||||
uint8_t Ltab[6] = { 0, 2, 4, 4, 4, 4 };
|
||||
uint8_t Jtab[6] = { 0, 2, 2, 3, 4, 4 };
|
||||
int feedback_cnt;
|
||||
AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated != NULL, "physicalConfigDedicated is null for UE %d\n",
|
||||
AssertFatal(UE_info->UE_template[CC_idP][UE_id].physicalConfigDedicated != NULL, "physicalConfigDedicated is null for UE %d\n",
|
||||
UE_id);
|
||||
AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL, "cqi_ReportConfig is null for UE %d\n",
|
||||
AssertFatal(UE_info->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL, "cqi_ReportConfig is null for UE %d\n",
|
||||
UE_id);
|
||||
struct LTE_CQI_ReportPeriodic *cqi_ReportPeriodic = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic;
|
||||
struct LTE_CQI_ReportPeriodic *cqi_ReportPeriodic = UE_info->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic;
|
||||
AssertFatal(cqi_ReportPeriodic != NULL, "cqi_ReportPeriodic is null for UE %d\n",
|
||||
UE_id);
|
||||
// determine feedback mode
|
||||
@@ -4678,9 +4632,9 @@ extract_pusch_csi(module_id_t mod_idP,
|
||||
uint8_t length)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
|
||||
UE_info_t *UE_info = &RC.mac[mod_idP]->UE_info;
|
||||
COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP];
|
||||
UE_sched_ctrl_t *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
|
||||
UE_sched_ctrl_t *sched_ctl = &UE_info->UE_sched_ctrl[UE_id];
|
||||
int Ntab[6] = { 0, 4, 7, 9, 10, 13 };
|
||||
int Ntab_uesel[6] = { 0, 8, 13, 17, 19, 25 };
|
||||
int Ltab_uesel[6] = { 0, 6, 9, 13, 15, 18 };
|
||||
@@ -4689,12 +4643,12 @@ extract_pusch_csi(module_id_t mod_idP,
|
||||
int i;
|
||||
uint64_t p = *(uint64_t *) pdu;
|
||||
int curbyte, curbit;
|
||||
AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated != NULL, "physicalConfigDedicated is null for UE %d\n",
|
||||
AssertFatal(UE_info->UE_template[CC_idP][UE_id].physicalConfigDedicated != NULL, "physicalConfigDedicated is null for UE %d\n",
|
||||
UE_id);
|
||||
AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL, "cqi_ReportConfig is null for UE %d\n",
|
||||
AssertFatal(UE_info->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL, "cqi_ReportConfig is null for UE %d\n",
|
||||
UE_id);
|
||||
LTE_CQI_ReportModeAperiodic_t *cqi_ReportModeAperiodic
|
||||
= UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic;
|
||||
= UE_info->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic;
|
||||
AssertFatal(cqi_ReportModeAperiodic != NULL, "cqi_ReportModeAperiodic is null for UE %d\n",
|
||||
UE_id);
|
||||
int N = Ntab[cc->mib->message.dl_Bandwidth];
|
||||
@@ -4964,14 +4918,14 @@ cqi_indication(module_id_t mod_idP,
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
int UE_id = find_UE_id(mod_idP, rntiP);
|
||||
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
|
||||
UE_info_t *UE_info = &RC.mac[mod_idP]->UE_info;
|
||||
|
||||
if (UE_id == -1) {
|
||||
LOG_W(MAC, "cqi_indication: UE %x not found\n", rntiP);
|
||||
return;
|
||||
}
|
||||
|
||||
UE_sched_ctrl_t *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
|
||||
UE_sched_ctrl_t *sched_ctl = &UE_info->UE_sched_ctrl[UE_id];
|
||||
|
||||
if (UE_id >= 0) {
|
||||
LOG_D(MAC,"%s() UE_id:%d channel:%d cqi:%d\n",
|
||||
@@ -5037,11 +4991,11 @@ SR_indication(module_id_t mod_idP,
|
||||
T_INT(subframeP),
|
||||
T_INT(rntiP));
|
||||
int UE_id = find_UE_id(mod_idP, rntiP);
|
||||
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
|
||||
UE_info_t *UE_info = &RC.mac[mod_idP]->UE_info;
|
||||
UE_sched_ctrl_t *UE_scheduling_ctrl = NULL;
|
||||
|
||||
if (UE_id != -1) {
|
||||
UE_scheduling_ctrl = &(UE_list->UE_sched_ctrl[UE_id]);
|
||||
UE_scheduling_ctrl = &(UE_info->UE_sched_ctrl[UE_id]);
|
||||
|
||||
if ((UE_scheduling_ctrl->cdrx_configured == TRUE) &&
|
||||
(UE_scheduling_ctrl->dci0_ongoing_timer > 0) &&
|
||||
@@ -5065,8 +5019,8 @@ SR_indication(module_id_t mod_idP,
|
||||
cc_idP);
|
||||
}
|
||||
|
||||
UE_list->UE_template[cc_idP][UE_id].ul_SR = 1;
|
||||
UE_list->UE_template[cc_idP][UE_id].ul_active = TRUE;
|
||||
UE_info->UE_template[cc_idP][UE_id].ul_SR = 1;
|
||||
UE_info->UE_template[cc_idP][UE_id].ul_active = TRUE;
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION, 1);
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION, 0);
|
||||
}
|
||||
@@ -5093,7 +5047,7 @@ UL_failure_indication(module_id_t mod_idP,
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
int UE_id = find_UE_id(mod_idP, rntiP);
|
||||
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
|
||||
UE_info_t *UE_info = &RC.mac[mod_idP]->UE_info;
|
||||
|
||||
if (UE_id != -1) {
|
||||
LOG_D(MAC, "[eNB %d][UE %d/%x] Frame %d subframeP %d Signaling UL Failure for UE %d on CC_id %d (timer %d)\n",
|
||||
@@ -5104,9 +5058,9 @@ UL_failure_indication(module_id_t mod_idP,
|
||||
subframeP,
|
||||
UE_id,
|
||||
cc_idP,
|
||||
UE_list->UE_sched_ctrl[UE_id].ul_failure_timer);
|
||||
UE_info->UE_sched_ctrl[UE_id].ul_failure_timer);
|
||||
|
||||
if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer == 0) UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 1;
|
||||
if (UE_info->UE_sched_ctrl[UE_id].ul_failure_timer == 0) UE_info->UE_sched_ctrl[UE_id].ul_failure_timer = 1;
|
||||
} else {
|
||||
// AssertFatal(0, "find_UE_id(%u,rnti %d) not found", enb_mod_idP, rntiP);
|
||||
// AssertError(0, 0, "Frame %d: find_UE_id(%u,rnti %d) not found\n", frameP, enb_mod_idP, rntiP);
|
||||
@@ -5169,8 +5123,8 @@ harq_indication(module_id_t mod_idP,
|
||||
return;
|
||||
}
|
||||
|
||||
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
|
||||
UE_sched_ctrl_t *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
|
||||
UE_info_t *UE_info = &RC.mac[mod_idP]->UE_info;
|
||||
UE_sched_ctrl_t *sched_ctl = &UE_info->UE_sched_ctrl[UE_id];
|
||||
COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP];
|
||||
// extract HARQ Information
|
||||
|
||||
@@ -5201,51 +5155,3 @@ harq_indication(module_id_t mod_idP,
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Flexran Slicing functions
|
||||
//------------------------------------------------------------------------------
|
||||
uint16_t
|
||||
nb_rbs_allowed_slice(float rb_percentage,
|
||||
int total_rbs)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
return (uint16_t) floor(rb_percentage * total_rbs);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int
|
||||
ue_dl_slice_membership(module_id_t mod_id,
|
||||
int UE_id,
|
||||
int slice_idx)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
eNB_MAC_INST *eNB = RC.mac[mod_id];
|
||||
|
||||
if (slice_idx < 0 || slice_idx >= eNB->slice_info.n_dl) {
|
||||
LOG_W(MAC, "out of range slice index %d (slice ID %d)\n",
|
||||
slice_idx,
|
||||
eNB->slice_info.dl[slice_idx].id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return eNB->UE_list.active[UE_id] == TRUE && eNB->UE_list.assoc_dl_slice_idx[UE_id] == slice_idx;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int
|
||||
ue_ul_slice_membership(module_id_t mod_id,
|
||||
int UE_id,
|
||||
int slice_idx)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
eNB_MAC_INST *eNB = RC.mac[mod_id];
|
||||
|
||||
if (slice_idx < 0 || slice_idx >= eNB->slice_info.n_ul) {
|
||||
LOG_W(MAC, "out of range slice index %d (slice ID %d)\n",
|
||||
slice_idx,
|
||||
eNB->slice_info.dl[slice_idx].id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return eNB->UE_list.active[UE_id] == TRUE && eNB->UE_list.assoc_ul_slice_idx[UE_id] == slice_idx;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+35
-56
@@ -824,11 +824,16 @@ typedef struct {
|
||||
uint16_t cshift[8]; // num_max_harq
|
||||
|
||||
/// Number of Allocated RBs by the ulsch preprocessor
|
||||
uint8_t pre_allocated_nb_rb_ul[MAX_NUM_SLICES];
|
||||
uint8_t pre_allocated_nb_rb_ul;
|
||||
/// Start of Allocated RBs by the USLCH preprocessor
|
||||
uint8_t pre_first_nb_rb_ul;
|
||||
|
||||
/// index of Allocated RBs by the ulsch preprocessor
|
||||
int8_t pre_allocated_rb_table_index_ul;
|
||||
|
||||
/// index of allocated HI_DCI0
|
||||
int pre_dci_ul_pdu_idx;
|
||||
|
||||
/// total allocated RBs
|
||||
int8_t total_allocated_rbs;
|
||||
|
||||
@@ -852,10 +857,10 @@ typedef struct {
|
||||
|
||||
// Logical channel info for link with RLC
|
||||
|
||||
/// LCGID mapping
|
||||
/// LCGID mapping (UL)
|
||||
long lcgidmap[11];
|
||||
|
||||
///UE logical channel priority
|
||||
///UE logical channel priority (UL)
|
||||
long lcgidpriority[11];
|
||||
|
||||
/// phr information
|
||||
@@ -913,31 +918,12 @@ typedef struct {
|
||||
|
||||
/*! \brief scheduling control information set through an API (not used)*/
|
||||
typedef struct {
|
||||
///UL transmission bandwidth in RBs
|
||||
uint8_t ul_bandwidth[MAX_NUM_LCID];
|
||||
///DL transmission bandwidth in RBs
|
||||
uint8_t dl_bandwidth[MAX_NUM_LCID];
|
||||
|
||||
//To do GBR bearer
|
||||
uint8_t min_ul_bandwidth[MAX_NUM_LCID];
|
||||
|
||||
uint8_t min_dl_bandwidth[MAX_NUM_LCID];
|
||||
|
||||
///aggregated bit rate of non-gbr bearer per UE
|
||||
uint64_t ue_AggregatedMaximumBitrateDL;
|
||||
///aggregated bit rate of non-gbr bearer per UE
|
||||
uint64_t ue_AggregatedMaximumBitrateUL;
|
||||
///CQI scheduling interval in subframes.
|
||||
uint16_t cqiSchedInterval;
|
||||
///Contention resolution timer used during random access
|
||||
uint8_t mac_ContentionResolutionTimer;
|
||||
|
||||
uint16_t max_rbs_allowed_slice[NFAPI_CC_MAX][MAX_NUM_SLICES];
|
||||
uint16_t max_rbs_allowed_slice_uplink[NFAPI_CC_MAX][MAX_NUM_SLICES];
|
||||
|
||||
uint8_t max_mcs[MAX_NUM_LCID];
|
||||
|
||||
uint16_t priority[MAX_NUM_LCID];
|
||||
/// number of active DL LCs
|
||||
uint8_t dl_lc_num;
|
||||
/// order in which DLSCH scheduler should allocate LCs
|
||||
uint8_t dl_lc_ids[MAX_NUM_LCID];
|
||||
/// number of bytes to schedule for each LC
|
||||
uint32_t dl_lc_bytes[MAX_NUM_LCID];
|
||||
|
||||
// resource scheduling information
|
||||
|
||||
@@ -950,6 +936,7 @@ typedef struct {
|
||||
uint8_t dl_pow_off[NFAPI_CC_MAX];
|
||||
uint16_t pre_nb_available_rbs[NFAPI_CC_MAX];
|
||||
unsigned char rballoc_sub_UE[NFAPI_CC_MAX][N_RBG_MAX];
|
||||
int pre_dci_dl_pdu_idx;
|
||||
uint16_t ta_timer;
|
||||
int16_t ta_update;
|
||||
uint16_t ul_consecutive_errors;
|
||||
@@ -1130,7 +1117,15 @@ typedef struct {
|
||||
uint8_t sb_size;
|
||||
uint8_t nb_active_sb;
|
||||
} SBMAP_CONF;
|
||||
/*! \brief UE list used by eNB to order UEs/CC for scheduling*/
|
||||
|
||||
/*! \brief UE_list_t is a "list" of users within UE_info_t. Especial useful in
|
||||
* the scheduler and to keep "classes" of users. */
|
||||
typedef struct {
|
||||
int head;
|
||||
int next[MAX_MOBILES_PER_ENB];
|
||||
} UE_list_t;
|
||||
|
||||
/*! \brief UE info used by eNB to order UEs/CC for scheduling*/
|
||||
typedef struct {
|
||||
|
||||
DLSCH_PDU DLSCH_pdu[NFAPI_CC_MAX][2][MAX_MOBILES_PER_ENB];
|
||||
@@ -1152,21 +1147,13 @@ typedef struct {
|
||||
eNB_UE_STATS eNB_UE_stats[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB];
|
||||
/// scheduling control info
|
||||
UE_sched_ctrl_t UE_sched_ctrl[MAX_MOBILES_PER_ENB];
|
||||
int next[MAX_MOBILES_PER_ENB];
|
||||
int head;
|
||||
int next_ul[MAX_MOBILES_PER_ENB];
|
||||
int head_ul;
|
||||
int avail;
|
||||
UE_list_t list;
|
||||
int num_UEs;
|
||||
boolean_t active[MAX_MOBILES_PER_ENB];
|
||||
|
||||
/// Sorting criteria for the UE list in the MAC preprocessor
|
||||
uint16_t sorting_criteria[MAX_NUM_SLICES][CR_NUM];
|
||||
uint16_t first_rb_offset[NFAPI_CC_MAX][MAX_NUM_SLICES];
|
||||
|
||||
int assoc_dl_slice_idx[MAX_MOBILES_PER_ENB];
|
||||
int assoc_ul_slice_idx[MAX_MOBILES_PER_ENB];
|
||||
} UE_list_t;
|
||||
} UE_info_t;
|
||||
|
||||
/*! \brief deleting control information*/
|
||||
typedef struct {
|
||||
@@ -1184,20 +1171,6 @@ typedef struct {
|
||||
int tail_freelist; ///the tail position of the delete list
|
||||
} UE_free_list_t;
|
||||
|
||||
/// Structure for saving the output of each pre_processor instance
|
||||
typedef struct {
|
||||
uint16_t nb_rbs_required[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB];
|
||||
uint16_t nb_rbs_accounted[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB];
|
||||
uint16_t nb_rbs_remaining[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB];
|
||||
uint8_t slice_allocation_mask[NFAPI_CC_MAX][N_RBG_MAX];
|
||||
uint8_t MIMO_mode_indicator[NFAPI_CC_MAX][N_RBG_MAX];
|
||||
|
||||
uint32_t bytes_lcid[MAX_MOBILES_PER_ENB][MAX_NUM_LCID];
|
||||
uint32_t wb_pmi[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB];
|
||||
uint8_t mcs[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB];
|
||||
|
||||
} pre_processor_results_t;
|
||||
|
||||
/**
|
||||
* slice specific scheduler for the DL
|
||||
*/
|
||||
@@ -1289,12 +1262,18 @@ typedef struct {
|
||||
int n_ul;
|
||||
slice_sched_conf_ul_t ul[MAX_NUM_SLICES];
|
||||
|
||||
pre_processor_results_t pre_processor_results[MAX_NUM_SLICES];
|
||||
|
||||
/// common rb allocation list between slices
|
||||
uint8_t rballoc_sub[NFAPI_CC_MAX][N_RBG_MAX];
|
||||
} slice_info_t;
|
||||
|
||||
/**
|
||||
* describes contiguous RBs
|
||||
*/
|
||||
typedef struct {
|
||||
int start;
|
||||
int length;
|
||||
} contig_rbs_t;
|
||||
|
||||
/*! \brief eNB common channels */
|
||||
typedef struct {
|
||||
int physCellId;
|
||||
@@ -1414,7 +1393,7 @@ typedef struct eNB_MAC_INST_s {
|
||||
nfapi_ue_release_request_t UE_release_req;
|
||||
/// UL handle
|
||||
uint32_t ul_handle;
|
||||
UE_list_t UE_list;
|
||||
UE_info_t UE_info;
|
||||
|
||||
/// slice-related configuration
|
||||
slice_info_t slice_info;
|
||||
|
||||
+37
-116
@@ -122,15 +122,14 @@ void schedule_ulsch(module_id_t module_idP, frame_t frameP,
|
||||
|
||||
/** \brief ULSCH Scheduling per RNTI
|
||||
@param Mod_id Instance ID of eNB
|
||||
@param slice_idx Slice instance index for this eNB
|
||||
@param CC_id The component carrier to schedule
|
||||
@param frame Frame index
|
||||
@param subframe Subframe number on which to act
|
||||
@param sched_subframe Subframe number where PUSCH is transmitted (for DAI lookup)
|
||||
*/
|
||||
void schedule_ulsch_rnti(module_id_t module_idP, int slice_idx, frame_t frameP,
|
||||
void schedule_ulsch_rnti(module_id_t module_idP, int CC_id, frame_t frameP,
|
||||
sub_frame_t subframe,
|
||||
unsigned char sched_subframe,
|
||||
uint16_t *first_rb);
|
||||
unsigned char sched_subframe);
|
||||
|
||||
void schedule_ulsch_rnti_emtc(module_id_t module_idP,
|
||||
frame_t frameP,
|
||||
@@ -138,14 +137,6 @@ void schedule_ulsch_rnti_emtc(module_id_t module_idP,
|
||||
unsigned char sched_subframeP,
|
||||
int *emtc_active);
|
||||
|
||||
/** \brief Second stage of DLSCH scheduling, after schedule_SI, schedule_RA and schedule_dlsch have been called. This routine first allocates random frequency assignments for SI and RA SDUs using distributed VRB allocations and adds the corresponding DCI SDU to the DCI buffer for PHY. It then loops over the UE specific DCIs previously allocated and fills in the remaining DCI fields related to frequency allocation. It assumes localized allocation of type 0 (DCI.rah=0). The allocation is done for tranmission modes 1,2,4.
|
||||
@param Mod_id Instance of eNB
|
||||
@param frame Frame index
|
||||
@param subframe Index of subframe
|
||||
@param mbsfn_flag Indicates that this subframe is for MCH/MCCH
|
||||
*/
|
||||
void fill_DLSCH_dci(module_id_t module_idP,frame_t frameP,sub_frame_t subframe,int *mbsfn_flag);
|
||||
|
||||
/** \brief UE specific DLSCH scheduling. Retrieves next ue to be schduled from round-robin scheduler and gets the appropriate harq_pid for the subframe from PHY. If the process is active and requires a retransmission, it schedules the retransmission with the same PRB count and MCS as the first transmission. Otherwise it consults RLC for DCCH/DTCH SDUs (status with maximum number of available PRBS), builds the MAC header (timing advance sent by default) and copies
|
||||
@param Mod_id Instance ID of eNB
|
||||
@param frame Frame index
|
||||
@@ -156,8 +147,10 @@ void fill_DLSCH_dci(module_id_t module_idP,frame_t frameP,sub_frame_t subframe,i
|
||||
void schedule_dlsch(module_id_t module_idP, frame_t frameP,
|
||||
sub_frame_t subframe, int *mbsfn_flag);
|
||||
|
||||
void schedule_ue_spec(module_id_t module_idP, int slice_idxP,
|
||||
frame_t frameP,sub_frame_t subframe, int *mbsfn_flag);
|
||||
void schedule_ue_spec(module_id_t module_idP,
|
||||
int CC_id,
|
||||
frame_t frameP,
|
||||
sub_frame_t subframe);
|
||||
void schedule_ue_spec_br(module_id_t module_idP,
|
||||
frame_t frameP,
|
||||
sub_frame_t subframeP);
|
||||
@@ -192,7 +185,7 @@ void add_msg3(module_id_t module_idP, int CC_id, RA_t *ra, frame_t frameP,
|
||||
|
||||
//main.c
|
||||
|
||||
void init_UE_list(UE_list_t *UE_list);
|
||||
void init_UE_info(UE_info_t *UE_info);
|
||||
|
||||
void init_slice_info(slice_info_t *sli);
|
||||
|
||||
@@ -231,73 +224,9 @@ void clear_nfapi_information(eNB_MAC_INST *eNB, int CC_idP,
|
||||
|
||||
|
||||
void dlsch_scheduler_pre_processor(module_id_t module_idP,
|
||||
int slice_idxP,
|
||||
int CC_id,
|
||||
frame_t frameP,
|
||||
sub_frame_t subframe,
|
||||
int *mbsfn_flag,
|
||||
uint8_t rballoc_sub[NFAPI_CC_MAX][N_RBG_MAX]);
|
||||
|
||||
void dlsch_scheduler_pre_processor_reset(module_id_t module_idP,
|
||||
int slice_idx,
|
||||
frame_t frameP,
|
||||
sub_frame_t subframeP,
|
||||
int min_rb_unit[NFAPI_CC_MAX],
|
||||
uint16_t nb_rbs_required[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB],
|
||||
uint8_t rballoc_sub[NFAPI_CC_MAX][N_RBG_MAX],
|
||||
uint8_t MIMO_mode_indicator[NFAPI_CC_MAX][N_RBG_MAX],
|
||||
int *mbsfn_flag);
|
||||
|
||||
void dlsch_scheduler_pre_processor_partitioning(module_id_t Mod_id,
|
||||
int slice_idx,
|
||||
const uint8_t rbs_retx[NFAPI_CC_MAX]);
|
||||
|
||||
void dlsch_scheduler_pre_processor_accounting(module_id_t Mod_id,
|
||||
int slice_idx,
|
||||
frame_t frameP,
|
||||
sub_frame_t subframeP,
|
||||
int min_rb_unit[NFAPI_CC_MAX],
|
||||
uint16_t nb_rbs_required[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB],
|
||||
uint16_t nb_rbs_accounted[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB]);
|
||||
|
||||
void dlsch_scheduler_pre_processor_positioning(module_id_t Mod_id,
|
||||
int slice_idx,
|
||||
int min_rb_unit[NFAPI_CC_MAX],
|
||||
uint16_t nb_rbs_required[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB],
|
||||
uint16_t nb_rbs_accounted[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB],
|
||||
uint16_t nb_rbs_remaining[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB],
|
||||
uint8_t rballoc_sub[NFAPI_CC_MAX][N_RBG_MAX],
|
||||
uint8_t MIMO_mode_indicator[NFAPI_CC_MAX][N_RBG_MAX]);
|
||||
|
||||
void dlsch_scheduler_pre_processor_intraslice_sharing(module_id_t Mod_id,
|
||||
int slice_idx,
|
||||
int min_rb_unit[NFAPI_CC_MAX],
|
||||
uint16_t nb_rbs_required[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB],
|
||||
uint16_t nb_rbs_accounted[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB],
|
||||
uint16_t nb_rbs_remaining[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB],
|
||||
uint8_t rballoc_sub[NFAPI_CC_MAX][N_RBG_MAX],
|
||||
uint8_t MIMO_mode_indicator[NFAPI_CC_MAX][N_RBG_MAX]);
|
||||
|
||||
void slice_priority_sort(module_id_t Mod_id, int slice_list[MAX_NUM_SLICES]);
|
||||
|
||||
void dlsch_scheduler_interslice_multiplexing(module_id_t Mod_id,
|
||||
int frameP,
|
||||
sub_frame_t subframeP,
|
||||
uint8_t rballoc_sub[NFAPI_CC_MAX][N_RBG_MAX]);
|
||||
|
||||
void dlsch_scheduler_qos_multiplexing(module_id_t Mod_id,
|
||||
int frameP,
|
||||
sub_frame_t subframeP);
|
||||
|
||||
void dlsch_scheduler_pre_processor_allocate(module_id_t Mod_id,
|
||||
int UE_id,
|
||||
uint8_t CC_id,
|
||||
int N_RBG,
|
||||
int min_rb_unit,
|
||||
uint16_t nb_rbs_required[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB],
|
||||
uint16_t nb_rbs_remaining[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB],
|
||||
uint8_t rballoc_sub[NFAPI_CC_MAX][N_RBG_MAX],
|
||||
uint8_t slice_allocation_mask[NFAPI_CC_MAX][N_RBG_MAX],
|
||||
uint8_t MIMO_mode_indicator[NFAPI_CC_MAX][N_RBG_MAX]);
|
||||
sub_frame_t subframe);
|
||||
|
||||
/* \brief Function to trigger the eNB scheduling procedure. It is called by PHY at the beginning of each subframe, \f$n$\f
|
||||
and generates all DLSCH allocations for subframe \f$n\f$ and ULSCH allocations for subframe \f$n+k$\f.
|
||||
@@ -484,10 +413,23 @@ boolean_t CCE_allocation_infeasible(int module_idP,
|
||||
int common_flag,
|
||||
int subframe,
|
||||
int aggregation, int rnti);
|
||||
/* tries to allocate a CCE. If it succeeds, reserves NFAPI DCI and DLSCH config */
|
||||
int CCE_try_allocate_dlsch(int module_id,
|
||||
int CC_id,
|
||||
int subframe,
|
||||
int UE_id,
|
||||
uint8_t dl_cqi);
|
||||
|
||||
/* tries to allocate a CCE for UL. If it succeeds, reserves the NFAPI DCI */
|
||||
int CCE_try_allocate_ulsch(int module_id,
|
||||
int CC_id,
|
||||
int subframe,
|
||||
int UE_id,
|
||||
uint8_t dl_cqi);
|
||||
|
||||
void set_ue_dai(sub_frame_t subframeP,
|
||||
int UE_id,
|
||||
uint8_t CC_id, uint8_t tdd_config, UE_list_t *UE_list);
|
||||
uint8_t CC_id, uint8_t tdd_config, UE_info_t *UE_info);
|
||||
|
||||
uint8_t frame_subframe2_dl_harq_pid(LTE_TDD_Config_t *tdd_Config, int abs_frameP, sub_frame_t subframeP);
|
||||
/** \brief First stage of PCH Scheduling. Gets a PCH SDU from RRC if available and computes the MCS required to transport it as a function of the SDU length. It assumes a length less than or equal to 64 bytes (MCS 6, 3 PRBs).
|
||||
@@ -510,14 +452,6 @@ uint8_t UE_is_to_be_scheduled(module_id_t module_idP, int CC_id,
|
||||
module_id_t schedule_next_ulue(module_id_t module_idP, int UE_id,
|
||||
sub_frame_t subframe);
|
||||
|
||||
/** \brief Round-robin scheduler for DLSCH traffic.
|
||||
@param Mod_id Instance ID for eNB
|
||||
@param subframe Subframe number on which to act
|
||||
@returns UE index that is to be scheduled if needed/room
|
||||
*/
|
||||
int schedule_next_dlue(module_id_t module_idP, int CC_id,
|
||||
sub_frame_t subframe);
|
||||
|
||||
/* \brief Allocates a set of PRBS for a particular UE. This is a simple function for the moment, later it should process frequency-domain CQI information and/or PMI information. Currently it just returns the first PRBS that are available in the subframe based on the number requested.
|
||||
@param UE_id Index of UE on which to act
|
||||
@param nb_rb Number of PRBs allocated to UE by scheduler
|
||||
@@ -721,13 +655,13 @@ int mac_init(void);
|
||||
int add_new_ue(module_id_t Mod_id, int CC_id, rnti_t rnti, int harq_pid, uint8_t rach_resource_type);
|
||||
int rrc_mac_remove_ue(module_id_t Mod_id, rnti_t rntiP);
|
||||
|
||||
void store_dlsch_buffer(module_id_t Mod_id, int slice_idx, frame_t frameP, sub_frame_t subframeP);
|
||||
void assign_rbs_required(module_id_t Mod_id, int slice_idx, frame_t frameP, sub_frame_t subframe, uint16_t nb_rbs_required[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB], int min_rb_unit[NFAPI_CC_MAX]);
|
||||
void store_dlsch_buffer(module_id_t Mod_id, int CC_id, frame_t frameP, sub_frame_t subframeP);
|
||||
|
||||
void swap_UEs(UE_list_t *listP, int nodeiP, int nodejP, int ul_flag);
|
||||
int prev(UE_list_t *listP, int nodeP, int ul_flag);
|
||||
void dump_ue_list(UE_list_t *listP, int ul_flag);
|
||||
int UE_num_active_CC(UE_list_t *listP, int ue_idP);
|
||||
int prev(UE_list_t *listP, int nodeP);
|
||||
void add_ue_list(UE_list_t *listP, int UE_id);
|
||||
int remove_ue_list(UE_list_t *listP, int UE_id);
|
||||
void dump_ue_list(UE_list_t *listP);
|
||||
int UE_num_active_CC(UE_info_t *listP, int ue_idP);
|
||||
int UE_PCCID(module_id_t mod_idP, int ue_idP);
|
||||
rnti_t UE_RNTI(module_id_t mod_idP, int ue_idP);
|
||||
|
||||
@@ -739,20 +673,14 @@ void set_ul_DAI(int module_idP,
|
||||
int frameP,
|
||||
int subframeP);
|
||||
|
||||
void ulsch_scheduler_pre_processor(module_id_t module_idP, int slice_idx, int frameP,
|
||||
void ulsch_scheduler_pre_processor(module_id_t module_idP,
|
||||
int CC_id,
|
||||
int frameP,
|
||||
sub_frame_t subframeP,
|
||||
int sched_frameP,
|
||||
unsigned char sched_subframeP,
|
||||
uint16_t *first_rb);
|
||||
void store_ulsch_buffer(module_id_t module_idP, int frameP,
|
||||
sub_frame_t subframeP);
|
||||
void assign_max_mcs_min_rb(module_id_t module_idP, int slice_idx, int frameP,
|
||||
sub_frame_t subframeP, uint16_t *first_rb);
|
||||
void adjust_bsr_info(int buffer_occupancy, uint16_t TBS,
|
||||
UE_TEMPLATE *UE_template);
|
||||
unsigned char sched_subframeP);
|
||||
|
||||
int phy_stats_exist(module_id_t Mod_id, int rnti);
|
||||
void sort_UEs(module_id_t Mod_idP, int slice_idx, int frameP, sub_frame_t subframeP);
|
||||
|
||||
/*! \fn UE_L2_state_t ue_scheduler(const module_id_t module_idP,const frame_t frameP, const sub_frame_t subframe, const lte_subframe_t direction,const uint8_t eNB_index)
|
||||
\brief UE scheduler where all the ue background tasks are done. This function performs the following: 1) Trigger PDCP every 5ms 2) Call RRC for link status return to PHY3) Perform SR/BSR procedures for scheduling feedback 4) Perform PHR procedures.
|
||||
@@ -913,8 +841,7 @@ void add_common_dci(DCI_PDU *DCI_pdu,
|
||||
uint8_t ra_flag);
|
||||
*/
|
||||
|
||||
uint32_t allocate_prbs_sub(int nb_rb, int N_RB_DL, int N_RBG,
|
||||
uint8_t *rballoc);
|
||||
uint32_t allocate_prbs_sub(int nb_rb, int N_RB_DL, int N_RBG, const uint8_t *rballoc);
|
||||
|
||||
void update_ul_dci(module_id_t module_idP, uint8_t CC_id, rnti_t rnti,
|
||||
uint8_t dai, sub_frame_t subframe);
|
||||
@@ -1176,14 +1103,13 @@ void program_dlsch_acknak(module_id_t module_idP, int CC_idP, int UE_idP,
|
||||
frame_t frameP, sub_frame_t subframeP,
|
||||
uint8_t cce_idx);
|
||||
|
||||
void fill_nfapi_dlsch_config(eNB_MAC_INST *eNB,
|
||||
nfapi_dl_config_request_body_t *dl_req,
|
||||
void fill_nfapi_dlsch_config(nfapi_dl_config_request_pdu_t *dl_config_pdu,
|
||||
uint16_t length, int16_t pdu_index,
|
||||
uint16_t rnti,
|
||||
uint8_t resource_allocation_type,
|
||||
uint8_t
|
||||
virtual_resource_block_assignment_flag,
|
||||
uint16_t resource_block_coding,
|
||||
uint32_t resource_block_coding,
|
||||
uint8_t modulation,
|
||||
uint8_t redundancy_version,
|
||||
uint8_t transport_blocks,
|
||||
@@ -1277,11 +1203,6 @@ void pre_scd_nb_rbs_required( module_id_t module_idP,
|
||||
uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX]);
|
||||
#endif
|
||||
|
||||
/* Slice related functions */
|
||||
uint16_t nb_rbs_allowed_slice(float rb_percentage, int total_rbs);
|
||||
int ue_dl_slice_membership(module_id_t mod_id, int UE_id, int slice_idx);
|
||||
int ue_ul_slice_membership(module_id_t mod_id, int UE_id, int slice_idx);
|
||||
|
||||
/* DRX Configuration */
|
||||
/* Configure local DRX timers and thresholds in UE context, following the drx_configuration input */
|
||||
void eNB_Config_Local_DRX(instance_t Mod_id, rrc_mac_drx_config_req_t *rrc_mac_drx_config_req);
|
||||
|
||||
+14
-22
@@ -43,26 +43,18 @@
|
||||
|
||||
extern RAN_CONTEXT_t RC;
|
||||
|
||||
void init_UE_list(UE_list_t *UE_list)
|
||||
void init_UE_info(UE_info_t *UE_info)
|
||||
{
|
||||
int list_el;
|
||||
UE_list->num_UEs = 0;
|
||||
UE_list->head = -1;
|
||||
UE_list->head_ul = -1;
|
||||
UE_list->avail = 0;
|
||||
for (list_el = 0; list_el < MAX_MOBILES_PER_ENB - 1; list_el++) {
|
||||
UE_list->next[list_el] = list_el + 1;
|
||||
UE_list->next_ul[list_el] = list_el + 1;
|
||||
}
|
||||
UE_list->next[list_el] = -1;
|
||||
UE_list->next_ul[list_el] = -1;
|
||||
memset(UE_list->DLSCH_pdu, 0, sizeof(UE_list->DLSCH_pdu));
|
||||
memset(UE_list->UE_template, 0, sizeof(UE_list->UE_template));
|
||||
memset(UE_list->eNB_UE_stats, 0, sizeof(UE_list->eNB_UE_stats));
|
||||
memset(UE_list->UE_sched_ctrl, 0, sizeof(UE_list->UE_sched_ctrl));
|
||||
memset(UE_list->active, 0, sizeof(UE_list->active));
|
||||
memset(UE_list->assoc_dl_slice_idx, 0, sizeof(UE_list->assoc_dl_slice_idx));
|
||||
memset(UE_list->assoc_ul_slice_idx, 0, sizeof(UE_list->assoc_ul_slice_idx));
|
||||
UE_info->num_UEs = 0;
|
||||
UE_info->list.head = -1;
|
||||
for (list_el = 0; list_el < MAX_MOBILES_PER_ENB; list_el++)
|
||||
UE_info->list.next[list_el] = -1;
|
||||
memset(UE_info->DLSCH_pdu, 0, sizeof(UE_info->DLSCH_pdu));
|
||||
memset(UE_info->UE_template, 0, sizeof(UE_info->UE_template));
|
||||
memset(UE_info->eNB_UE_stats, 0, sizeof(UE_info->eNB_UE_stats));
|
||||
memset(UE_info->UE_sched_ctrl, 0, sizeof(UE_info->UE_sched_ctrl));
|
||||
memset(UE_info->active, 0, sizeof(UE_info->active));
|
||||
}
|
||||
|
||||
void init_slice_info(slice_info_t *sli)
|
||||
@@ -137,7 +129,7 @@ void mac_top_init_eNB(void)
|
||||
|
||||
mac[i]->if_inst = IF_Module_init(i);
|
||||
|
||||
init_UE_list(&mac[i]->UE_list);
|
||||
init_UE_info(&mac[i]->UE_info);
|
||||
init_slice_info(&mac[i]->slice_info);
|
||||
}
|
||||
|
||||
@@ -163,12 +155,12 @@ void mac_init_cell_params(int Mod_idP, int CC_idP)
|
||||
|
||||
memset(&RC.mac[Mod_idP]->eNB_stats, 0, sizeof(eNB_STATS));
|
||||
UE_template =
|
||||
(UE_TEMPLATE *) & RC.mac[Mod_idP]->UE_list.UE_template[CC_idP][0];
|
||||
(UE_TEMPLATE *) & RC.mac[Mod_idP]->UE_info.UE_template[CC_idP][0];
|
||||
|
||||
for (j = 0; j < MAX_MOBILES_PER_ENB; j++) {
|
||||
UE_template[j].rnti = 0;
|
||||
// initiallize the eNB to UE statistics
|
||||
memset(&RC.mac[Mod_idP]->UE_list.eNB_UE_stats[CC_idP][j], 0,
|
||||
memset(&RC.mac[Mod_idP]->UE_info.eNB_UE_stats[CC_idP][j], 0,
|
||||
sizeof(eNB_UE_STATS));
|
||||
}
|
||||
|
||||
@@ -263,4 +255,4 @@ void *mac_enb_task(void *arg)
|
||||
} // end while
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+725
-1929
File diff suppressed because it is too large
Load Diff
@@ -390,7 +390,7 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP, int CC_id,
|
||||
LOG_USEDINLOG_VAR(mac_rlc_status_resp_t,rlc_status)=mac_rlc_status_ind(module_idP,
|
||||
UE_mac_inst[module_idP].crnti,
|
||||
eNB_indexP, frameP, subframeP,
|
||||
ENB_FLAG_NO, MBMS_FLAG_NO, DCCH, 6,0, 0
|
||||
ENB_FLAG_NO, MBMS_FLAG_NO, DCCH, 0, 0
|
||||
);
|
||||
|
||||
if (UE_mac_inst[module_idP].crnti_before_ho)
|
||||
@@ -406,7 +406,7 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP, int CC_id,
|
||||
module_idP, frameP, rlc_status.bytes_in_buffer,
|
||||
dcch_header_len);
|
||||
|
||||
sdu_lengths = mac_rlc_data_req(module_idP, UE_mac_inst[module_idP].crnti, eNB_indexP, frameP, ENB_FLAG_NO, MBMS_FLAG_NO, DCCH, 6, //not used
|
||||
sdu_lengths = mac_rlc_data_req(module_idP, UE_mac_inst[module_idP].crnti, eNB_indexP, frameP, ENB_FLAG_NO, MBMS_FLAG_NO, DCCH, 6,
|
||||
(char *) &ulsch_buff[0],0,
|
||||
0
|
||||
);
|
||||
|
||||
@@ -1972,6 +1972,10 @@ ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP,
|
||||
subframe, ENB_FLAG_NO,
|
||||
lcid);
|
||||
lcid_buffer_occupancy_new = lcid_buffer_occupancy_old;
|
||||
#if 0
|
||||
/* TODO: those assert crash the L2 simulator with the new RLC.
|
||||
* Are they necessary?
|
||||
*/
|
||||
AssertFatal(lcid_buffer_occupancy_new ==
|
||||
UE_mac_inst[module_idP].
|
||||
scheduling_info.LCID_buffer_remain[lcid],
|
||||
@@ -1990,6 +1994,7 @@ ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP,
|
||||
scheduling_info.BSR_bytes[UE_mac_inst[module_idP].
|
||||
scheduling_info.LCGID
|
||||
[lcid]]);
|
||||
#endif
|
||||
|
||||
//Multiplex all available DCCH RLC PDUs considering to multiplex the last PDU each time for maximize the data
|
||||
//Adjust at the end of the loop
|
||||
@@ -2085,18 +2090,10 @@ ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP,
|
||||
}
|
||||
|
||||
//Update Buffer remain and BSR bytes after transmission
|
||||
AssertFatal(lcid_buffer_occupancy_new <=
|
||||
lcid_buffer_occupancy_old,
|
||||
"MAC UE Tx error : Buffer Occupancy After Tx=%d greater than before=%d BO! for LCID=%d RLC PDU nb=%d Frame %d Subrame %d\n",
|
||||
lcid_buffer_occupancy_new,
|
||||
lcid_buffer_occupancy_old, lcid,
|
||||
lcid_rlc_pdu_count, frameP, subframe);
|
||||
UE_mac_inst[module_idP].scheduling_info.
|
||||
LCID_buffer_remain[lcid] = lcid_buffer_occupancy_new;
|
||||
UE_mac_inst[module_idP].
|
||||
scheduling_info.BSR_bytes[UE_mac_inst[module_idP].
|
||||
scheduling_info.LCGID[lcid]] +=
|
||||
(lcid_buffer_occupancy_new - lcid_buffer_occupancy_old);
|
||||
UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] = lcid_buffer_occupancy_new;
|
||||
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] += (lcid_buffer_occupancy_new - lcid_buffer_occupancy_old);
|
||||
if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] < 0)
|
||||
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] = 0;
|
||||
|
||||
//Update the number of LCGID with data as BSR shall reflect status after BSR transmission
|
||||
if ((num_lcg_id_with_data > 1)
|
||||
@@ -2809,7 +2806,6 @@ update_bsr(module_id_t module_idP, frame_t frameP,
|
||||
|
||||
rlc_status = mac_rlc_status_ind(module_idP, UE_mac_inst[module_idP].crnti,eNB_index,frameP,subframeP,ENB_FLAG_NO,MBMS_FLAG_NO,
|
||||
lcid,
|
||||
0xFFFF, //TBS is not used in RLC at this step, set a special value for debug
|
||||
0, 0
|
||||
);
|
||||
lcid_bytes_in_buffer[lcid] = rlc_status.bytes_in_buffer;
|
||||
@@ -3176,7 +3172,7 @@ SLSCH_t *ue_get_slsch(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_
|
||||
for (int j = 0; j < ue->numCommFlows; j++) {
|
||||
if ((ue->sourceL2Id > 0) && (ue->destinationList[j] >0) ) {
|
||||
rlc_status = mac_rlc_status_ind(module_idP, 0x1234,0,frameP,subframeP,ENB_FLAG_NO,MBMS_FLAG_NO,
|
||||
ue->SL_LCID[i], 0xFFFF, ue->sourceL2Id, ue->destinationList[j]);
|
||||
ue->SL_LCID[i], ue->sourceL2Id, ue->destinationList[j]);
|
||||
|
||||
if (rlc_status.bytes_in_buffer > 2) {
|
||||
LOG_I(MAC,"SFN.SF %d.%d: Scheduling for %d bytes in Sidelink buffer\n",frameP,subframeP,rlc_status.bytes_in_buffer);
|
||||
|
||||
@@ -46,6 +46,7 @@ uint16_t NCS_restricted_TypeB_delta_f_RA_5[14] = {36,57,60,63,65,68,71,77,81,8
|
||||
uint16_t NCS_unrestricted_delta_f_RA_15[16] = {0,2,4,6,8,10,12,13,15,17,19,23,27,34,46,69};
|
||||
|
||||
const char *prachfmt[]={"A1","A2","A3","B1","B2","B3","B4","C0","C2"};
|
||||
const char *prachfmt03[]={"0","1","2","3"};
|
||||
|
||||
uint16_t get_NCS(uint8_t index, uint16_t format0, uint8_t restricted_set_config) {
|
||||
|
||||
@@ -903,7 +904,7 @@ int get_nr_prach_info_from_index(uint8_t index,
|
||||
if ( (frame%x)==y || (frame%x)==y2 ) {
|
||||
slot_60khz = slot >> (mu-2); // in table slots are numbered wrt 60kHz
|
||||
s_map = table_6_3_3_2_4_prachConfig_Index[index][5];
|
||||
if ( (s_map>>slot_60khz)&0x01 ) {
|
||||
if ( ((s_map>>slot_60khz)&0x01) ) {
|
||||
if (mu == 3) {
|
||||
if ( (table_6_3_3_2_4_prachConfig_Index[index][7] == 1) && (slot%2 == 0) )
|
||||
return 0; // no prach in even slots @ 120kHz for 1 prach per 60khz slot
|
||||
@@ -943,7 +944,7 @@ int get_nr_prach_info_from_index(uint8_t index,
|
||||
s_map = table_6_3_3_2_3_prachConfig_Index[index][4];
|
||||
if ( (s_map>>subframe)&0x01 ) {
|
||||
if (mu == 1) {
|
||||
if ( (table_6_3_3_2_3_prachConfig_Index[index][6] == 1) && (slot%2 == 0) )
|
||||
if ( (table_6_3_3_2_3_prachConfig_Index[index][6] <= 1) && (slot%2 == 0) )
|
||||
return 0; // no prach in even slots @ 30kHz for 1 prach per subframe
|
||||
}
|
||||
if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL){
|
||||
@@ -953,9 +954,9 @@ int get_nr_prach_info_from_index(uint8_t index,
|
||||
if (table_6_3_3_2_3_prachConfig_Index[index][1] != -1)
|
||||
format2 = (uint8_t) table_6_3_3_2_3_prachConfig_Index[index][1];
|
||||
*format = ((uint8_t) table_6_3_3_2_3_prachConfig_Index[index][0]) | (format2<<8);
|
||||
LOG_D(MAC,"Frame %d slot %d: Getting PRACH info from index %d absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u \n", frame,
|
||||
LOG_D(MAC,"Frame %d slot %d: Getting PRACH info from index %d (col 6 %d) absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u \n", frame,
|
||||
slot,
|
||||
index,
|
||||
index, table_6_3_3_2_3_prachConfig_Index[index][6],
|
||||
pointa,
|
||||
mu,
|
||||
unpaired,
|
||||
@@ -979,7 +980,7 @@ int get_nr_prach_info_from_index(uint8_t index,
|
||||
s_map = table_6_3_3_2_2_prachConfig_Index[index][4];
|
||||
if ( (s_map>>subframe)&0x01 ) {
|
||||
if (mu == 1) {
|
||||
if ( (table_6_3_3_2_2_prachConfig_Index[index][6] == 1) && (slot%2 == 0) )
|
||||
if ( (table_6_3_3_2_2_prachConfig_Index[index][6] <= 1) && (slot%2 == 0) )
|
||||
return 0; // no prach in even slots @ 30kHz for 1 prach per subframe
|
||||
}
|
||||
if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL){
|
||||
@@ -1064,7 +1065,7 @@ uint8_t compute_nr_root_seq(NR_RACH_ConfigCommon_t *rach_config,
|
||||
uint8_t ncs_index = rach_config->rach_ConfigGeneric.zeroCorrelationZoneConfig;
|
||||
uint16_t format0 = get_format0(config_index, unpaired);
|
||||
uint16_t NCS = get_NCS(ncs_index, format0, rach_config->restrictedSetConfig);
|
||||
uint16_t L_ra = (rach_config->prach_RootSequenceIndex.present) ? 139 : 839;
|
||||
uint16_t L_ra = (rach_config->prach_RootSequenceIndex.present==NR_RACH_ConfigCommon__prach_RootSequenceIndex_PR_l139) ? 139 : 839;
|
||||
uint16_t r,u,index,q,d_u,n_shift_ra,n_shift_ra_bar,d_start;
|
||||
uint32_t w;
|
||||
uint8_t found_preambles = 0;
|
||||
@@ -1419,7 +1420,7 @@ int32_t get_nr_uldl_offset(int nr_bandP)
|
||||
|
||||
void nr_get_tbs_dl(nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu,
|
||||
int x_overhead,
|
||||
uint8_t nodata_dmrs,
|
||||
uint8_t numdmrscdmgroupnodata,
|
||||
uint8_t tb_scaling) {
|
||||
|
||||
LOG_D(MAC, "TBS calculation\n");
|
||||
@@ -1427,10 +1428,14 @@ void nr_get_tbs_dl(nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu,
|
||||
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_rel15 = &pdsch_pdu->pdsch_pdu_rel15;
|
||||
uint16_t N_PRB_oh = x_overhead;
|
||||
uint8_t N_PRB_DMRS;
|
||||
if (nodata_dmrs)
|
||||
N_PRB_DMRS = 12;
|
||||
else
|
||||
N_PRB_DMRS = (pdsch_rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1)?6:4; //This only works for antenna port 1000
|
||||
if (pdsch_rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1) {
|
||||
// if no data in dmrs cdm group is 1 only even REs have no data
|
||||
// if no data in dmrs cdm group is 2 both odd and even REs have no data
|
||||
N_PRB_DMRS = numdmrscdmgroupnodata*6;
|
||||
}
|
||||
else {
|
||||
N_PRB_DMRS = numdmrscdmgroupnodata*4;
|
||||
}
|
||||
uint8_t N_sh_symb = pdsch_rel15->NrOfSymbols;
|
||||
uint8_t Imcs = pdsch_rel15->mcsIndex[0];
|
||||
uint16_t N_RE_prime = NR_NB_SC_PER_RB*N_sh_symb - N_PRB_DMRS - N_PRB_oh;
|
||||
|
||||
@@ -178,6 +178,11 @@ void nr_extract_dci_info(NR_UE_MAC_INST_t *mac,
|
||||
dci_pdu_rel15_t *nr_pdci_info_extracted);
|
||||
|
||||
|
||||
uint8_t
|
||||
nr_ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP,
|
||||
sub_frame_t subframe, uint8_t eNB_index,
|
||||
uint8_t *ulsch_buffer, uint16_t buflen, uint8_t *access_mode) ;
|
||||
|
||||
int set_tdd_config_nr_ue(fapi_nr_config_request_t *cfg, int mu,
|
||||
int nrofDownlinkSlots, int nrofDownlinkSymbols,
|
||||
int nrofUplinkSlots, int nrofUplinkSymbols);
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
//#define ENABLE_MAC_PAYLOAD_DEBUG 1
|
||||
#define DEBUG_EXTRACT_DCI 1
|
||||
|
||||
extern int bwp_id;
|
||||
extern dci_pdu_rel15_t *def_dci_pdu_rel15;
|
||||
|
||||
extern void mac_rlc_data_ind (
|
||||
@@ -478,7 +479,6 @@ int8_t nr_ue_decode_mib(module_id_t module_id,
|
||||
uint32_t number_of_search_space_per_slot=UINT_MAX;
|
||||
uint32_t first_symbol_index=UINT_MAX;
|
||||
uint32_t search_space_duration; // element of search space
|
||||
uint32_t coreset_duration; // element of coreset
|
||||
// 38.213 table 10.1-1
|
||||
|
||||
/// MUX PATTERN 1
|
||||
@@ -614,8 +614,8 @@ int8_t nr_ue_decode_mib(module_id_t module_id,
|
||||
}
|
||||
|
||||
AssertFatal(number_of_search_space_per_slot!=UINT_MAX,"");
|
||||
coreset_duration = num_symbols * number_of_search_space_per_slot;
|
||||
/*
|
||||
uint32_t coreset_duration = num_symbols * number_of_search_space_per_slot;
|
||||
mac->type0_pdcch_dci_config.number_of_candidates[0] = table_38213_10_1_1_c2[0];
|
||||
mac->type0_pdcch_dci_config.number_of_candidates[1] = table_38213_10_1_1_c2[1];
|
||||
mac->type0_pdcch_dci_config.number_of_candidates[2] = table_38213_10_1_1_c2[2]; // CCE aggregation level = 4
|
||||
@@ -2114,6 +2114,8 @@ int nr_ue_process_dci_indication_pdu(module_id_t module_id,int cc_id, int gNB_in
|
||||
|
||||
int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, dci_pdu_rel15_t *dci, uint16_t rnti, uint32_t dci_format){
|
||||
|
||||
int bwp_id = 1;
|
||||
|
||||
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
|
||||
fapi_nr_dl_config_request_t *dl_config = &mac->dl_config_request;
|
||||
fapi_nr_ul_config_request_t *ul_config = &mac->ul_config_request;
|
||||
@@ -2709,17 +2711,10 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, dc
|
||||
if (dci->tpc == 2) dlsch_config_pdu_1_1->accumulated_delta_PUCCH = 1;
|
||||
if (dci->tpc == 3) dlsch_config_pdu_1_1->accumulated_delta_PUCCH = 3;
|
||||
/* PUCCH_RESOURCE_IND */
|
||||
if (dci->pucch_resource_indicator == 0) dlsch_config_pdu_1_1->pucch_resource_id = 0; //pucch-ResourceId obtained from the 1st value of resourceList FIXME!!!
|
||||
if (dci->pucch_resource_indicator == 1) dlsch_config_pdu_1_1->pucch_resource_id = 0; //pucch-ResourceId obtained from the 2nd value of resourceList FIXME!!
|
||||
if (dci->pucch_resource_indicator == 2) dlsch_config_pdu_1_1->pucch_resource_id = 0; //pucch-ResourceId obtained from the 3rd value of resourceList FIXME!!
|
||||
if (dci->pucch_resource_indicator == 3) dlsch_config_pdu_1_1->pucch_resource_id = 0; //pucch-ResourceId obtained from the 4th value of resourceList FIXME!!
|
||||
if (dci->pucch_resource_indicator == 4) dlsch_config_pdu_1_1->pucch_resource_id = 0; //pucch-ResourceId obtained from the 5th value of resourceList FIXME!!
|
||||
if (dci->pucch_resource_indicator == 5) dlsch_config_pdu_1_1->pucch_resource_id = 0; //pucch-ResourceId obtained from the 6th value of resourceList FIXME!!
|
||||
if (dci->pucch_resource_indicator == 6) dlsch_config_pdu_1_1->pucch_resource_id = 0; //pucch-ResourceId obtained from the 7th value of resourceList FIXME!!
|
||||
if (dci->pucch_resource_indicator == 7) dlsch_config_pdu_1_1->pucch_resource_id = 0; //pucch-ResourceId obtained from the 8th value of resourceList FIXME!!
|
||||
dlsch_config_pdu_1_1->pucch_resource_id = dci->pucch_resource_indicator;
|
||||
/* PDSCH_TO_HARQ_FEEDBACK_TIME_IND */
|
||||
// according to TS 38.213 Table 9.2.3-1
|
||||
dlsch_config_pdu_1_1-> pdsch_to_harq_feedback_time_ind = mac->phy_config.config_req.ul_bwp_dedicated.pucch_config_dedicated.dl_data_to_ul_ack[dci->pdsch_to_harq_feedback_timing_indicator.val];
|
||||
dlsch_config_pdu_1_1->pdsch_to_harq_feedback_time_ind = mac->ULbwp[bwp_id-1]->bwp_Dedicated->pucch_Config->choice.setup->dl_DataToUL_ACK->list.array[dci->pdsch_to_harq_feedback_timing_indicator.val][0];
|
||||
/* ANTENNA_PORTS */
|
||||
uint8_t n_codewords = 1; // FIXME!!!
|
||||
if ((mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.dmrs_dl_for_pdsch_mapping_type_a.dmrs_type == 1) &&
|
||||
|
||||
@@ -290,8 +290,7 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigComm
|
||||
scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots,
|
||||
scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSymbols,
|
||||
scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots,
|
||||
scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols
|
||||
);
|
||||
scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols);
|
||||
|
||||
if (return_tdd !=0){
|
||||
LOG_E(PHY,"TDD configuration can not be done\n");
|
||||
|
||||
@@ -305,12 +305,14 @@ void nr_schedule_pucch(int Mod_idP,
|
||||
NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1];
|
||||
nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[Mod_idP]->UL_tti_req[0];
|
||||
|
||||
NR_sched_pucch *curr_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch;
|
||||
NR_sched_pucch *temp_pucch;
|
||||
int release_pucch = 0;
|
||||
NR_sched_pucch *curr_pucch;
|
||||
int nr_ulmix_slots = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots;
|
||||
if (scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols!=0)
|
||||
nr_ulmix_slots++;
|
||||
|
||||
if (curr_pucch != NULL) {
|
||||
if ((frameP == curr_pucch->frame) && (slotP == curr_pucch->ul_slot)) {
|
||||
for (int k=0; k<nr_ulmix_slots; k++) {
|
||||
curr_pucch = &UE_list->UE_sched_ctrl[UE_id].sched_pucch[k];
|
||||
if ((curr_pucch->dai_c > 0) && (frameP == curr_pucch->frame) && (slotP == curr_pucch->ul_slot)) {
|
||||
UL_tti_req->SFN = frameP;
|
||||
UL_tti_req->Slot = slotP;
|
||||
UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE;
|
||||
@@ -321,6 +323,8 @@ void nr_schedule_pucch(int Mod_idP,
|
||||
O_ack = curr_pucch->dai_c;
|
||||
O_uci = O_ack; // for now we are just sending acknacks in pucch
|
||||
|
||||
LOG_I(MAC, "Scheduling pucch reception for frame %d slot %d\n", frameP, slotP);
|
||||
|
||||
nr_configure_pucch(pucch_pdu,
|
||||
scc,
|
||||
ubwp,
|
||||
@@ -329,16 +333,9 @@ void nr_schedule_pucch(int Mod_idP,
|
||||
O_ack,
|
||||
SR_flag);
|
||||
|
||||
release_pucch = 1;
|
||||
curr_pucch->dai_c = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (release_pucch) {
|
||||
temp_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch;
|
||||
UE_list->UE_sched_ctrl[UE_id].sched_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch->next_sched_pucch;
|
||||
free(temp_pucch);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot){
|
||||
@@ -364,7 +361,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
|
||||
int UE_id;
|
||||
uint64_t *dlsch_in_slot_bitmap=NULL;
|
||||
uint64_t *ulsch_in_slot_bitmap=NULL;
|
||||
NR_sched_pucch *pucch_sched = (NR_sched_pucch*) malloc(sizeof(NR_sched_pucch));
|
||||
int pucch_sched;
|
||||
|
||||
UE_id=0;
|
||||
int bwp_id = 1;
|
||||
@@ -376,6 +373,18 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
|
||||
NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
|
||||
int num_slots_per_tdd = (nr_slots_per_frame[*scc->ssbSubcarrierSpacing])>>(7-scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity);
|
||||
|
||||
int nr_ulmix_slots = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots;
|
||||
if (scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols!=0)
|
||||
nr_ulmix_slots++;
|
||||
|
||||
if (slot_txP== 0 && (UE_list->fiveG_connected[UE_id] || get_softmodem_params()->phy_test)) {
|
||||
for (int k=0; k<nr_ulmix_slots; k++) {
|
||||
memset((void *) &UE_list->UE_sched_ctrl[UE_id].sched_pucch[k],
|
||||
0,
|
||||
sizeof(NR_sched_pucch));
|
||||
}
|
||||
}
|
||||
|
||||
start_meas(&RC.nrmac[module_idP]->eNB_scheduler);
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_IN);
|
||||
|
||||
@@ -385,25 +394,23 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
|
||||
RC.nrmac[module_idP]->frame = frame_rxP;
|
||||
RC.nrmac[module_idP]->slot = slot_rxP;
|
||||
|
||||
if (get_softmodem_params()->phy_test) {
|
||||
dlsch_in_slot_bitmap = &RC.nrmac[module_idP]->UE_list.UE_sched_ctrl[UE_id].dlsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains dlsch
|
||||
ulsch_in_slot_bitmap = &RC.nrmac[module_idP]->UE_list.UE_sched_ctrl[UE_id].ulsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains ulsch
|
||||
dlsch_in_slot_bitmap = &RC.nrmac[module_idP]->UE_list.UE_sched_ctrl[UE_id].dlsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains dlsch
|
||||
ulsch_in_slot_bitmap = &RC.nrmac[module_idP]->UE_list.UE_sched_ctrl[UE_id].ulsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains ulsch
|
||||
|
||||
// hardcoding dlsch to be in slot 1
|
||||
if (!(slot_txP%num_slots_per_tdd)) {
|
||||
if(slot_txP==0)
|
||||
*dlsch_in_slot_bitmap = 0x02;
|
||||
else
|
||||
*dlsch_in_slot_bitmap = 0x00;
|
||||
}
|
||||
// hardcoding dlsch to be in slot 1
|
||||
if (!(slot_txP%num_slots_per_tdd)) {
|
||||
if(slot_txP==0)
|
||||
*dlsch_in_slot_bitmap = 0x7e;
|
||||
else
|
||||
*dlsch_in_slot_bitmap = 0x00;
|
||||
}
|
||||
|
||||
// hardcoding ulsch to be in slot 8
|
||||
if (!(slot_rxP%num_slots_per_tdd)) {
|
||||
if(slot_rxP==0)
|
||||
*ulsch_in_slot_bitmap = 0x100;
|
||||
else
|
||||
*ulsch_in_slot_bitmap = 0x00;
|
||||
}
|
||||
// hardcoding ulsch to be in slot 8
|
||||
if (!(slot_rxP%num_slots_per_tdd)) {
|
||||
if(slot_rxP==0)
|
||||
*ulsch_in_slot_bitmap = 0x100;
|
||||
else
|
||||
*ulsch_in_slot_bitmap = 0x00;
|
||||
}
|
||||
|
||||
// Check if there are downlink symbols in the slot,
|
||||
@@ -455,25 +462,18 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
|
||||
|
||||
if (get_softmodem_params()->phy_test == 0)
|
||||
nr_schedule_RA(module_idP, frame_txP, slot_txP);
|
||||
else
|
||||
UE_list->fiveG_connected[UE_id] = true;
|
||||
|
||||
// Phytest scheduling
|
||||
if (get_softmodem_params()->phy_test && (is_xlsch_in_slot(*dlsch_in_slot_bitmap,slot_txP%num_slots_per_tdd))) {
|
||||
nr_update_pucch_scheduling(module_idP, UE_id, frame_txP, slot_txP, num_slots_per_tdd,pucch_sched);
|
||||
nr_schedule_uss_dlsch_phytest(module_idP, frame_txP, slot_txP, pucch_sched, NULL);
|
||||
if (UE_list->fiveG_connected[UE_id] && (is_xlsch_in_slot(*dlsch_in_slot_bitmap,slot_txP%num_slots_per_tdd))) {
|
||||
ue_sched_ctl->current_harq_pid = slot_txP % num_slots_per_tdd;
|
||||
nr_update_pucch_scheduling(module_idP, UE_id, frame_txP, slot_txP, num_slots_per_tdd,&pucch_sched);
|
||||
nr_schedule_uss_dlsch_phytest(module_idP, frame_txP, slot_txP, &UE_list->UE_sched_ctrl[UE_id].sched_pucch[pucch_sched], NULL);
|
||||
// resetting ta flag
|
||||
gNB->ta_len = 0;
|
||||
}
|
||||
|
||||
// Test DL scheduling
|
||||
if (get_softmodem_params()->phy_test == 0 && slot_txP == 1 && UE_list->fiveG_connected[UE_id]) {
|
||||
nr_update_pucch_scheduling(module_idP, UE_id, frame_txP, slot_txP, num_slots_per_tdd,pucch_sched);
|
||||
nr_schedule_uss_dlsch_phytest(module_idP, frame_txP, slot_txP, pucch_sched, NULL);
|
||||
// resetting ta flag
|
||||
gNB->ta_len = 0;
|
||||
//UE_list->fiveG_connected[UE_id] = false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Allocate CCEs for good after scheduling is done
|
||||
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++)
|
||||
@@ -485,6 +485,8 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
|
||||
if (is_nr_UL_slot(cc->ServingCellConfigCommon,slot_rxP)) {
|
||||
|
||||
if (get_softmodem_params()->phy_test == 0) {
|
||||
if (UE_list->fiveG_connected[UE_id])
|
||||
nr_schedule_pucch(module_idP, UE_id, frame_rxP, slot_rxP);
|
||||
schedule_nr_prach(module_idP, (frame_rxP+1)&1023, slot_rxP);
|
||||
nr_schedule_reception_msg3(module_idP, 0, frame_rxP, slot_rxP);
|
||||
}
|
||||
|
||||
@@ -698,7 +698,7 @@ void nr_generate_Msg2(module_id_t module_idP,
|
||||
LOG_D(MAC,"[gNB %d][RAPROC] Frame %d, Subframe %d: RA state %d\n", module_idP, frameP, slotP, ra->state);
|
||||
|
||||
x_Overhead = 0;
|
||||
nr_get_tbs_dl(&dl_tti_pdsch_pdu->pdsch_pdu, x_Overhead, 1, dci_pdu_rel15[0].tb_scaling);
|
||||
nr_get_tbs_dl(&dl_tti_pdsch_pdu->pdsch_pdu, x_Overhead, pdsch_pdu_rel15->numDmrsCdmGrpsNoData, dci_pdu_rel15[0].tb_scaling);
|
||||
|
||||
// DL TX request
|
||||
tx_req->PDU_length = pdsch_pdu_rel15->TBSize[0];
|
||||
|
||||
@@ -309,11 +309,12 @@ int configure_fapi_dl_pdu(int Mod_idP,
|
||||
|
||||
pdsch_pdu_rel15->NrOfCodewords = 1;
|
||||
int mcs = (mcsIndex!=NULL) ? *mcsIndex : 9;
|
||||
int current_harq_pid = UE_list->UE_sched_ctrl[UE_id].current_harq_pid;
|
||||
pdsch_pdu_rel15->targetCodeRate[0] = nr_get_code_rate_dl(mcs,0);
|
||||
pdsch_pdu_rel15->qamModOrder[0] = 2;
|
||||
pdsch_pdu_rel15->mcsIndex[0] = mcs;
|
||||
pdsch_pdu_rel15->mcsTable[0] = 0;
|
||||
pdsch_pdu_rel15->rvIndex[0] = 0;
|
||||
pdsch_pdu_rel15->rvIndex[0] = UE_list->UE_sched_ctrl[UE_id].harq_processes[current_harq_pid].round;
|
||||
pdsch_pdu_rel15->dataScramblingId = *scc->physCellId;
|
||||
pdsch_pdu_rel15->nrOfLayers = 1;
|
||||
pdsch_pdu_rel15->transmissionScheme = 0;
|
||||
@@ -363,21 +364,24 @@ int configure_fapi_dl_pdu(int Mod_idP,
|
||||
dci_pdu_rel15[0].time_domain_assignment.val = time_domain_assignment; // row index used here instead of SLIV;
|
||||
// mcs ndi and rv
|
||||
dci_pdu_rel15[0].mcs = pdsch_pdu_rel15->mcsIndex[0];
|
||||
dci_pdu_rel15[0].ndi = 1;
|
||||
dci_pdu_rel15[0].rv = 0;
|
||||
dci_pdu_rel15[0].rv = pdsch_pdu_rel15->rvIndex[0];
|
||||
// harq pid
|
||||
dci_pdu_rel15[0].harq_pid = 0;
|
||||
dci_pdu_rel15[0].harq_pid = current_harq_pid;
|
||||
dci_pdu_rel15[0].ndi = UE_list->UE_sched_ctrl[UE_id].harq_processes[current_harq_pid].ndi;
|
||||
// DAI
|
||||
dci_pdu_rel15[0].dai[0].val = (pucch_sched->dai_c-1)&3;
|
||||
|
||||
// TPC for PUCCH
|
||||
dci_pdu_rel15[0].tpc = 1; // table 7.2.1-1 in 38.213
|
||||
// PUCCH resource indicator
|
||||
dci_pdu_rel15[0].pucch_resource_indicator = pucch_sched->resource_indicator;
|
||||
// PDSCH to HARQ TI
|
||||
dci_pdu_rel15[0].pdsch_to_harq_feedback_timing_indicator.val = pucch_sched->timing_indicator;
|
||||
UE_list->UE_sched_ctrl[UE_id].harq_processes[current_harq_pid].feedback_slot = pucch_sched->ul_slot;
|
||||
UE_list->UE_sched_ctrl[UE_id].harq_processes[current_harq_pid].is_waiting = 1;
|
||||
// antenna ports
|
||||
dci_pdu_rel15[0].antenna_ports.val = 0; // nb of cdm groups w/o data 1 and dmrs port 0
|
||||
|
||||
|
||||
LOG_I(MAC, "[gNB scheduler phytest] DCI type 1 payload: freq_alloc %d (%d,%d,%d), time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d\n",
|
||||
dci_pdu_rel15[0].frequency_domain_assignment.val,
|
||||
pdsch_pdu_rel15->rbStart,
|
||||
@@ -409,7 +413,7 @@ int configure_fapi_dl_pdu(int Mod_idP,
|
||||
}
|
||||
}
|
||||
AssertFatal(found==1,"Couldn't find an adequate searchspace\n");
|
||||
|
||||
|
||||
int ret = nr_configure_pdcch(nr_mac,
|
||||
pdcch_pdu_rel15,
|
||||
UE_list->rnti[UE_id],
|
||||
@@ -444,7 +448,7 @@ int configure_fapi_dl_pdu(int Mod_idP,
|
||||
pdcch_pdu_rel15->DurationSymbols);
|
||||
|
||||
int x_Overhead = 0; // should be 0 for initialBWP
|
||||
nr_get_tbs_dl(&dl_tti_pdsch_pdu->pdsch_pdu, x_Overhead,1,0);
|
||||
nr_get_tbs_dl(&dl_tti_pdsch_pdu->pdsch_pdu,x_Overhead,pdsch_pdu_rel15->numDmrsCdmGrpsNoData,0);
|
||||
|
||||
// Hardcode it for now
|
||||
TBS = dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15.TBSize[0];
|
||||
@@ -595,7 +599,6 @@ void nr_schedule_uss_dlsch_phytest(module_id_t module_idP,
|
||||
ENB_FLAG_YES,
|
||||
MBMS_FLAG_NO,
|
||||
lcid,
|
||||
TBS_bytes - ta_len - header_length_total - sdu_length_total - 3,
|
||||
0,
|
||||
0);
|
||||
|
||||
@@ -612,7 +615,7 @@ void nr_schedule_uss_dlsch_phytest(module_id_t module_idP,
|
||||
ENB_FLAG_YES,
|
||||
MBMS_FLAG_NO,
|
||||
lcid,
|
||||
TBS_bytes,
|
||||
TBS_bytes - ta_len - header_length_total - sdu_length_total - 3,
|
||||
(char *)&mac_sdus[sdu_length_total],
|
||||
0,
|
||||
0);
|
||||
@@ -798,7 +801,7 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP,
|
||||
pusch_pdu->dmrs_config_type = 0; //dmrs-type 1 (the one with a single DMRS symbol in the beginning)
|
||||
pusch_pdu->ul_dmrs_scrambling_id = 0; //If provided and the PUSCH is not a msg3 PUSCH, otherwise, L2 should set this to physical cell id.
|
||||
pusch_pdu->scid = 0; //DMRS sequence initialization [TS38.211, sec 6.4.1.1.1]. Should match what is sent in DCI 0_1, otherwise set to 0.
|
||||
//pusch_pdu->num_dmrs_cdm_grps_no_data;
|
||||
pusch_pdu->num_dmrs_cdm_grps_no_data = 1;
|
||||
//pusch_pdu->dmrs_ports; //DMRS ports. [TS38.212 7.3.1.1.2] provides description between DCI 0-1 content and DMRS ports. Bitmap occupying the 11 LSBs with: bit 0: antenna port 1000 bit 11: antenna port 1011 and for each bit 0: DMRS port not used 1: DMRS port used
|
||||
//Pusch Allocation in frequency domain [TS38.214, sec 6.1.2.2]
|
||||
pusch_pdu->resource_alloc = 1; //type 1
|
||||
@@ -817,17 +820,24 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP,
|
||||
pusch_pdu->pusch_data.harq_process_id = 0;
|
||||
pusch_pdu->pusch_data.new_data_indicator = 0;
|
||||
|
||||
uint8_t no_data_in_dmrs = 1; // temp implementation
|
||||
uint8_t num_dmrs_symb = 0;
|
||||
|
||||
for(int dmrs_counter = pusch_pdu->start_symbol_index; dmrs_counter < pusch_pdu->start_symbol_index + pusch_pdu->nr_of_symbols; dmrs_counter++)
|
||||
num_dmrs_symb += ((pusch_pdu->ul_dmrs_symb_pos >> dmrs_counter) & 1);
|
||||
|
||||
uint8_t N_PRB_DMRS;
|
||||
if (pusch_pdu->dmrs_config_type == 0) {
|
||||
N_PRB_DMRS = pusch_pdu->num_dmrs_cdm_grps_no_data*6;
|
||||
}
|
||||
else {
|
||||
N_PRB_DMRS = pusch_pdu->num_dmrs_cdm_grps_no_data*4;
|
||||
}
|
||||
|
||||
pusch_pdu->pusch_data.tb_size = nr_compute_tbs(pusch_pdu->qam_mod_order,
|
||||
pusch_pdu->target_code_rate,
|
||||
pusch_pdu->rb_size,
|
||||
pusch_pdu->nr_of_symbols,
|
||||
( no_data_in_dmrs ? 12 : ((pusch_pdu->dmrs_config_type == pusch_dmrs_type1) ? 6 : 4) ) * num_dmrs_symb,
|
||||
N_PRB_DMRS * num_dmrs_symb,
|
||||
0, //nb_rb_oh
|
||||
0,
|
||||
pusch_pdu->nrOfLayers)>>3;
|
||||
|
||||
@@ -1330,6 +1330,11 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP){
|
||||
int UE_id;
|
||||
int i;
|
||||
NR_UE_list_t *UE_list = &RC.nrmac[mod_idP]->UE_list;
|
||||
NR_COMMON_channels_t *cc = RC.nrmac[mod_idP]->common_channels;
|
||||
NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
|
||||
int num_slots_ul = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots;
|
||||
if (scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols>0)
|
||||
num_slots_ul++;
|
||||
LOG_I(MAC, "[gNB %d] Adding UE with rnti %x (next avail %d, num_UEs %d)\n",
|
||||
mod_idP,
|
||||
rntiP,
|
||||
@@ -1348,6 +1353,7 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP){
|
||||
memset((void *) &UE_list->UE_sched_ctrl[UE_id],
|
||||
0,
|
||||
sizeof(NR_UE_sched_ctrl_t));
|
||||
UE_list->UE_sched_ctrl[UE_id].sched_pucch = (NR_sched_pucch *)malloc(num_slots_ul*sizeof(NR_sched_pucch));
|
||||
LOG_I(MAC, "gNB %d] Add NR UE_id %d : rnti %x\n",
|
||||
mod_idP,
|
||||
UE_id,
|
||||
@@ -1420,15 +1426,14 @@ void nr_update_pucch_scheduling(int Mod_idP,
|
||||
frame_t frameP,
|
||||
sub_frame_t slotP,
|
||||
int slots_per_tdd,
|
||||
NR_sched_pucch *sched_pucch) {
|
||||
int *pucch_id) {
|
||||
|
||||
NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon;
|
||||
NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list;
|
||||
int first_ul_slot_tdd,k;
|
||||
NR_sched_pucch *curr_pucch;
|
||||
int first_ul_slot_tdd,k,i;
|
||||
uint8_t pdsch_to_harq_feedback[8];
|
||||
int found = 0;
|
||||
int i = 0;
|
||||
int nr_ulmix_slots = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots;
|
||||
if (scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols!=0)
|
||||
nr_ulmix_slots++;
|
||||
@@ -1437,100 +1442,35 @@ void nr_update_pucch_scheduling(int Mod_idP,
|
||||
NR_SearchSpace__searchSpaceType_PR ss_type = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
|
||||
get_pdsch_to_harq_feedback(Mod_idP,UE_id,ss_type,pdsch_to_harq_feedback);
|
||||
|
||||
// if the list of pucch to be scheduled is empty
|
||||
if (UE_list->UE_sched_ctrl[UE_id].sched_pucch == NULL) {
|
||||
sched_pucch->frame = frameP;
|
||||
sched_pucch->next_sched_pucch = NULL;
|
||||
sched_pucch->dai_c = 1;
|
||||
sched_pucch->resource_indicator = 0; // in phytest with only 1 UE we are using just the 1st resource
|
||||
if ( nr_ulmix_slots > 0 ) {
|
||||
// for each possible ul or mixed slot
|
||||
for (k=0; k<nr_ulmix_slots; k++) {
|
||||
curr_pucch = &UE_list->UE_sched_ctrl[UE_id].sched_pucch[k];
|
||||
// if there is free room in current pucch structure
|
||||
if (curr_pucch->dai_c<MAX_ACK_BITS) {
|
||||
curr_pucch->frame = frameP;
|
||||
curr_pucch->dai_c++;
|
||||
curr_pucch->resource_indicator = 0; // in phytest with only 1 UE we are using just the 1st resource
|
||||
// first pucch occasion in first UL or MIXED slot
|
||||
first_ul_slot_tdd = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots;
|
||||
for (k=0; k<nr_ulmix_slots; k++) { // for each possible UL or mixed slot
|
||||
while (i<8 && found == 0) { // look if timing indicator is among allowed values
|
||||
if (pdsch_to_harq_feedback[i]==(first_ul_slot_tdd+k)-(slotP % slots_per_tdd))
|
||||
found = 1;
|
||||
if (found == 0) i++;
|
||||
}
|
||||
if (found == 1) break;
|
||||
}
|
||||
if (found == 1) {
|
||||
// computing slot in which pucch is scheduled
|
||||
sched_pucch->ul_slot = first_ul_slot_tdd + k + (slotP - (slotP % slots_per_tdd));
|
||||
sched_pucch->timing_indicator = pdsch_to_harq_feedback[i];
|
||||
}
|
||||
else
|
||||
AssertFatal(1==0,"No Uplink slot available in accordance to allowed timing indicator\n");
|
||||
}
|
||||
else
|
||||
AssertFatal(1==0,"No Uplink Slots in this Frame\n");
|
||||
|
||||
UE_list->UE_sched_ctrl[UE_id].sched_pucch = sched_pucch;
|
||||
}
|
||||
else { // to be tested
|
||||
curr_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch;
|
||||
if (curr_pucch->dai_c<MAX_ACK_BITS) { // we are scheduling at most MAX_UCI_BITS harq-ack in the same pucch
|
||||
while (i<8 && found == 0) { // look if timing indicator is among allowed values for current pucch
|
||||
if (pdsch_to_harq_feedback[i]==(curr_pucch->ul_slot % slots_per_tdd)-(slotP % slots_per_tdd))
|
||||
i = 0;
|
||||
while (i<8 && found == 0) { // look if timing indicator is among allowed values
|
||||
if (pdsch_to_harq_feedback[i]==(first_ul_slot_tdd+k)-(slotP % slots_per_tdd))
|
||||
found = 1;
|
||||
if (found == 0) i++;
|
||||
}
|
||||
if (found == 1) { // scheduling this harq-ack in current pucch
|
||||
sched_pucch = curr_pucch;
|
||||
sched_pucch->dai_c = 1 + sched_pucch->dai_c;
|
||||
sched_pucch->timing_indicator = pdsch_to_harq_feedback[i];
|
||||
}
|
||||
}
|
||||
if (curr_pucch->dai_c==MAX_ACK_BITS || found == 0) { // if current pucch is full or no timing indicator allowed
|
||||
// look for pucch occasions in other UL of mixed slots
|
||||
for (k=scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots; k<slots_per_tdd; k++) { // for each possible UL or mixed slot
|
||||
if (k!=(curr_pucch->ul_slot % slots_per_tdd)) { // skip current scheduled slot (already checked)
|
||||
i = 0;
|
||||
while (i<8 && found == 0) { // look if timing indicator is among allowed values
|
||||
if (pdsch_to_harq_feedback[i]==k-(slotP % slots_per_tdd))
|
||||
found = 1;
|
||||
if (found == 0) i++;
|
||||
}
|
||||
if (found == 1) {
|
||||
if (k<(curr_pucch->ul_slot % slots_per_tdd)) { // we need to add a pucch occasion before current pucch
|
||||
sched_pucch->frame = frameP;
|
||||
sched_pucch->ul_slot = k + (slotP - (slotP % slots_per_tdd));
|
||||
sched_pucch->next_sched_pucch = curr_pucch;
|
||||
sched_pucch->dai_c = 1;
|
||||
sched_pucch->resource_indicator = 0; // in phytest with only 1 UE we are using just the 1st resource
|
||||
sched_pucch->timing_indicator = pdsch_to_harq_feedback[i];
|
||||
UE_list->UE_sched_ctrl[UE_id].sched_pucch = sched_pucch;
|
||||
}
|
||||
else {
|
||||
while (curr_pucch->next_sched_pucch != NULL && k!=(curr_pucch->ul_slot % slots_per_tdd))
|
||||
curr_pucch = curr_pucch->next_sched_pucch;
|
||||
if (curr_pucch == NULL) { // creating a new item in the list
|
||||
sched_pucch->frame = frameP;
|
||||
sched_pucch->next_sched_pucch = NULL;
|
||||
sched_pucch->dai_c = 1;
|
||||
sched_pucch->timing_indicator = pdsch_to_harq_feedback[i];
|
||||
sched_pucch->resource_indicator = 0; // in phytest with only 1 UE we are using just the 1st resource
|
||||
sched_pucch->ul_slot = k + (slotP - (slotP % slots_per_tdd));
|
||||
curr_pucch->next_sched_pucch = (NR_sched_pucch*) malloc(sizeof(NR_sched_pucch));
|
||||
curr_pucch->next_sched_pucch = sched_pucch;
|
||||
}
|
||||
else {
|
||||
if (curr_pucch->dai_c==MAX_ACK_BITS)
|
||||
found = 0; // if pucch at index k is already full we have to find a new one in a following occasion
|
||||
else { // scheduling this harq-ack in current pucch
|
||||
sched_pucch = curr_pucch;
|
||||
sched_pucch->dai_c = 1 + sched_pucch->dai_c;
|
||||
sched_pucch->timing_indicator = pdsch_to_harq_feedback[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found == 1) {
|
||||
// computing slot in which pucch is scheduled
|
||||
curr_pucch->ul_slot = first_ul_slot_tdd + k + (slotP - (slotP % slots_per_tdd));
|
||||
curr_pucch->timing_indicator = i; // index in the list of timing indicators
|
||||
*pucch_id = k;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
AssertFatal(1==0,"No Uplink slot available in accordance to allowed timing indicator\n");
|
||||
}
|
||||
|
||||
|
||||
void find_monitoring_periodicity_offset_common(NR_SearchSpace_t *ss,
|
||||
uint16_t *slot_period,
|
||||
uint16_t *offset) {
|
||||
|
||||
@@ -157,7 +157,7 @@ void nr_update_pucch_scheduling(int Mod_idP,
|
||||
frame_t frameP,
|
||||
sub_frame_t slotP,
|
||||
int slots_per_tdd,
|
||||
NR_sched_pucch *sched_pucch);
|
||||
int *pucch_id);
|
||||
|
||||
void get_pdsch_to_harq_feedback(int Mod_idP,
|
||||
int UE_id,
|
||||
@@ -226,7 +226,7 @@ int to_absslot(nfapi_nr_config_request_scf_t *cfg,int frame,int slot);
|
||||
|
||||
void nr_get_tbs_dl(nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu,
|
||||
int x_overhead,
|
||||
uint8_t nodata_dmrs,
|
||||
uint8_t numdmrscdmgroupnodata,
|
||||
uint8_t tb_scaling);
|
||||
/** \brief Computes Q based on I_MCS PDSCH and table_idx for downlink. Implements MCS Tables from 38.214. */
|
||||
uint8_t nr_get_Qm_dl(uint8_t Imcs, uint8_t table_idx);
|
||||
|
||||
@@ -114,6 +114,11 @@ void mac_top_init_gNB(void)
|
||||
UE_list->next[list_el] = list_el + 1;
|
||||
UE_list->next_ul[list_el] = list_el + 1;
|
||||
UE_list->active[list_el] = FALSE;
|
||||
for (int list_harq = 0; list_harq < NR_MAX_NB_HARQ_PROCESSES; list_harq++) {
|
||||
UE_list->UE_sched_ctrl[list_el].harq_processes[list_harq].round = 0;
|
||||
UE_list->UE_sched_ctrl[list_el].harq_processes[list_harq].ndi = 0;
|
||||
UE_list->UE_sched_ctrl[list_el].harq_processes[list_harq].is_waiting = 0;
|
||||
}
|
||||
}
|
||||
|
||||
UE_list->next[list_el] = -1;
|
||||
|
||||
@@ -185,9 +185,15 @@ typedef struct NR_sched_pucch {
|
||||
uint8_t dai_c;
|
||||
uint8_t timing_indicator;
|
||||
uint8_t resource_indicator;
|
||||
struct NR_sched_pucch *next_sched_pucch;
|
||||
} NR_sched_pucch;
|
||||
|
||||
typedef struct NR_UE_harq {
|
||||
uint8_t is_waiting;
|
||||
uint8_t ndi;
|
||||
uint8_t round;
|
||||
uint16_t feedback_slot;
|
||||
} NR_UE_harq_t;
|
||||
|
||||
/*! \brief scheduling control information set through an API */
|
||||
typedef struct {
|
||||
uint64_t dlsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains dlsch
|
||||
@@ -195,6 +201,8 @@ typedef struct {
|
||||
NR_sched_pucch *sched_pucch;
|
||||
uint16_t ta_timer;
|
||||
int16_t ta_update;
|
||||
uint8_t current_harq_pid;
|
||||
NR_UE_harq_t harq_processes[NR_MAX_NB_HARQ_PROCESSES];
|
||||
} NR_UE_sched_ctrl_t;
|
||||
|
||||
typedef struct NR_preamble_ue {
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file enb_agent.h
|
||||
* \brief top level enb agent receive thread and itti task
|
||||
|
||||
@@ -1,32 +1,23 @@
|
||||
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file proto_agent.h
|
||||
* \brief top level protocol agent
|
||||
|
||||
@@ -1,32 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "proto_agent_async.h"
|
||||
#include "proto_agent_defs.h"
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file enb_agent_async.h
|
||||
* \brief channel implementation for async interface
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file proto_agent_common.c
|
||||
* \brief common primitives for all agents
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file enb_agent_common.h
|
||||
* \brief common message primitves and utilities
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2016 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file enb_agent_defs.h
|
||||
* \brief enb agent common definitions
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file enb_agent_handler.c
|
||||
* \brief enb agent tx and rx message handler
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2016 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file enb_agent_net_comm.c
|
||||
* \brief enb agent network interface abstraction
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2016 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file enb_agent_net_comm.h
|
||||
* \brief enb agent network interface abstraction
|
||||
|
||||
@@ -459,7 +459,6 @@ struct mac_status_resp
|
||||
rlc_am_mac_status_indication (
|
||||
const protocol_ctxt_t *const ctxt_pP,
|
||||
void *const rlc_pP,
|
||||
const uint16_t tb_sizeP,
|
||||
struct mac_status_ind tx_statusP,
|
||||
const eNB_flag_t enb_flagP) {
|
||||
struct mac_status_resp status_resp;
|
||||
@@ -491,10 +490,6 @@ rlc_am_mac_status_indication (
|
||||
|
||||
rlc->last_absolute_subframe_status_indication = PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP);
|
||||
|
||||
if (tb_sizeP > 0) {
|
||||
rlc->nb_bytes_requested_by_mac = tb_sizeP;
|
||||
}
|
||||
|
||||
status_resp.buffer_occupancy_in_bytes = rlc_am_get_buffer_occupancy_in_bytes(ctxt_pP, rlc);
|
||||
|
||||
// For eNB scheduler : Add Max RLC header size for new PDU
|
||||
@@ -549,8 +544,7 @@ rlc_am_mac_status_indication (
|
||||
NULL,0,
|
||||
MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" STATUS-IND %u",
|
||||
MSC_AS_TIME_ARGS(ctxt_pP),
|
||||
PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, rlc),
|
||||
tb_sizeP);
|
||||
PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, rlc));
|
||||
MSC_LOG_TX_MESSAGE(
|
||||
(ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE,
|
||||
(ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_MAC_ENB:MSC_MAC_UE,
|
||||
@@ -565,26 +559,14 @@ rlc_am_mac_status_indication (
|
||||
}
|
||||
|
||||
if (LOG_DEBUGFLAG(DEBUG_RLC)) {
|
||||
if (tb_sizeP > 0) {
|
||||
LOG_UI(RLC, PROTOCOL_RLC_AM_CTXT_FMT" MAC_STATUS_INDICATION (DATA) %d bytes -> %d bytes\n",
|
||||
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc),
|
||||
tb_sizeP,
|
||||
status_resp.buffer_occupancy_in_bytes);
|
||||
}
|
||||
LOG_UI(RLC, PROTOCOL_RLC_AM_CTXT_FMT" MAC_STATUS_INDICATION (DATA) -> %d bytes\n",
|
||||
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc),
|
||||
status_resp.buffer_occupancy_in_bytes);
|
||||
}
|
||||
|
||||
return status_resp;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_am_set_nb_bytes_requested_by_mac (
|
||||
void *const rlc_pP,
|
||||
const tb_size_t tb_sizeP
|
||||
) {
|
||||
((rlc_am_entity_t *) rlc_pP)->nb_bytes_requested_by_mac = tb_sizeP;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
struct mac_data_req
|
||||
rlc_am_mac_data_request (
|
||||
|
||||
@@ -255,23 +255,15 @@ rlc_am_get_pdus (
|
||||
*/
|
||||
void rlc_am_rx (const protocol_ctxt_t* const ctxtP,void * const rlc_pP, struct mac_data_ind);
|
||||
|
||||
/*! \fn struct mac_status_resp rlc_am_mac_status_indication (const protocol_ctxt_t* const ctxtP,void * const rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP,const eNB_flag_t enb_flagP)
|
||||
/*! \fn struct mac_status_resp rlc_am_mac_status_indication (const protocol_ctxt_t* const ctxtP,void * const rlc_pP, struct mac_status_ind tx_statusP,const eNB_flag_t enb_flagP)
|
||||
* \brief Request the maximum number of bytes that can be served by RLC instance to MAC and fix the amount of bytes requested by MAC for next RLC transmission.
|
||||
* \param[in] ctxt_pP Running context.
|
||||
* \param[in] rlc_pP RLC AM protocol instance pointer.
|
||||
* \param[in] tbs_sizeP Number of bytes requested by MAC for next transmission.
|
||||
* \param[in] tx_statusP Transmission status given by MAC on previous MAC transmission of the PDU.
|
||||
* \param[in] enb_flagP eNB or UE flag indication.
|
||||
* \return The maximum number of bytes that can be served by RLC instance to MAC.
|
||||
*/
|
||||
struct mac_status_resp rlc_am_mac_status_indication (const protocol_ctxt_t* const ctxtP, void * const rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP,const eNB_flag_t enb_flagP);
|
||||
|
||||
/*! \fn void rlc_am_set_nb_bytes_requested_by_mac (void * const rlc_pP,const tb_size_t tb_sizeP)
|
||||
* \brief Set available TBS for RLC Tx just before am_mac_data_request. Used for UE only.
|
||||
* \param[in] rlc_pP RLC AM protocol instance pointer.
|
||||
* \param[in] tb_sizeP Available Tx Transport Block size in bytes.
|
||||
*/
|
||||
void rlc_am_set_nb_bytes_requested_by_mac (void * const rlc_pP,const tb_size_t tb_sizeP);
|
||||
struct mac_status_resp rlc_am_mac_status_indication (const protocol_ctxt_t* const ctxtP, void * const rlc_pP, struct mac_status_ind tx_statusP,const eNB_flag_t enb_flagP);
|
||||
|
||||
/*! \fn struct mac_data_req rlc_am_mac_data_request (const protocol_ctxt_t* const ctxtP,void * const rlc_pP,const eNB_flag_t enb_flagP)
|
||||
* \brief Gives PDUs to lower layer MAC.
|
||||
|
||||
@@ -151,13 +151,10 @@ struct mac_status_resp
|
||||
rlc_tm_mac_status_indication (
|
||||
const protocol_ctxt_t* const ctxt_pP,
|
||||
void * const rlc_pP,
|
||||
const tb_size_t tb_sizeP,
|
||||
struct mac_status_ind tx_statusP)
|
||||
{
|
||||
struct mac_status_resp status_resp;
|
||||
|
||||
((rlc_tm_entity_t *) rlc_pP)->rlc_pdu_size = tb_sizeP;
|
||||
|
||||
status_resp.buffer_occupancy_in_bytes = ((rlc_tm_entity_t *) rlc_pP)->buffer_occupancy;
|
||||
status_resp.buffer_occupancy_in_pdus = status_resp.buffer_occupancy_in_bytes / ((rlc_tm_entity_t *) rlc_pP)->rlc_pdu_size;
|
||||
status_resp.rlc_info.rlc_protocol_state = ((rlc_tm_entity_t *) rlc_pP)->protocol_state;
|
||||
|
||||
@@ -88,11 +88,10 @@ void rlc_tm_rx (
|
||||
struct mac_data_ind data_indP);
|
||||
|
||||
|
||||
/*! \fn struct mac_status_resp rlc_tm_mac_status_indication (const protocol_ctxt_t* const ctxt_pP, void * const rlcP, const uint16_t tbs_sizeP, struct mac_status_ind tx_statusP)
|
||||
/*! \fn struct mac_status_resp rlc_tm_mac_status_indication (const protocol_ctxt_t* const ctxt_pP, void * const rlcP, struct mac_status_ind tx_statusP)
|
||||
* \brief Request the maximum number of bytes that can be served by RLC instance to MAC and fix the amount of bytes requested by MAC for next RLC transmission.
|
||||
* \param[in] ctxtP Running context.
|
||||
* \param[in] rlcP RLC TM protocol instance pointer.
|
||||
* \param[in] tbs_sizeP Number of bytes requested by MAC for next transmission.
|
||||
* \param[in] tx_statusP Transmission status given by MAC on previous MAC transmission of the PDU.
|
||||
* \return The maximum number of bytes that can be served by RLC instance to MAC.
|
||||
*/
|
||||
@@ -100,7 +99,6 @@ struct mac_status_resp
|
||||
rlc_tm_mac_status_indication (
|
||||
const protocol_ctxt_t* const ctxt_pP,
|
||||
void * const rlc_pP,
|
||||
const tb_size_t tb_sizeP,
|
||||
struct mac_status_ind tx_statusP);
|
||||
|
||||
|
||||
|
||||
@@ -370,7 +370,7 @@ rlc_um_rx (const protocol_ctxt_t *const ctxt_pP, void *argP, struct mac_data_ind
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
struct mac_status_resp
|
||||
rlc_um_mac_status_indication (const protocol_ctxt_t *const ctxt_pP, void *rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP,const eNB_flag_t enb_flagP) {
|
||||
rlc_um_mac_status_indication (const protocol_ctxt_t *const ctxt_pP, void *rlc_pP, struct mac_status_ind tx_statusP,const eNB_flag_t enb_flagP) {
|
||||
struct mac_status_resp status_resp;
|
||||
uint16_t sdu_size = 0;
|
||||
uint16_t sdu_remaining_size = 0;
|
||||
@@ -386,7 +386,6 @@ rlc_um_mac_status_indication (const protocol_ctxt_t *const ctxt_pP, void *rlc_pP
|
||||
if (rlc_pP) {
|
||||
status_resp.rlc_info.rlc_protocol_state = rlc_p->protocol_state;
|
||||
rlc_um_check_timer_dar_time_out(ctxt_pP, rlc_p);
|
||||
rlc_p->nb_bytes_requested_by_mac = tbs_sizeP;
|
||||
status_resp.buffer_occupancy_in_bytes = rlc_um_get_buffer_occupancy (rlc_p);
|
||||
|
||||
if ((status_resp.buffer_occupancy_in_bytes > 0) && ((mb_p = list_get_head(&rlc_p->input_sdus)) != NULL)) {
|
||||
@@ -416,9 +415,8 @@ rlc_um_mac_status_indication (const protocol_ctxt_t *const ctxt_pP, void *rlc_pP
|
||||
|
||||
if (LOG_DEBUGFLAG(DEBUG_RLC)) {
|
||||
if (( rlc_p->rb_id > 0) && (status_resp.buffer_occupancy_in_bytes > 0)) {
|
||||
LOG_UI(RLC, PROTOCOL_RLC_UM_CTXT_FMT"MAC_STATUS_INDICATION (DATA) %d bytes requested -> %d bytes available\n",
|
||||
LOG_UI(RLC, PROTOCOL_RLC_UM_CTXT_FMT"MAC_STATUS_INDICATION (DATA) -> %d bytes available\n",
|
||||
PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_p),
|
||||
tbs_sizeP,
|
||||
status_resp.buffer_occupancy_in_bytes);
|
||||
|
||||
if ((tx_statusP.tx_status == MAC_TX_STATUS_SUCCESSFUL) && (tx_statusP.no_pdu)) {
|
||||
@@ -441,15 +439,6 @@ rlc_um_mac_status_indication (const protocol_ctxt_t *const ctxt_pP, void *rlc_pP
|
||||
return status_resp;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
rlc_um_set_nb_bytes_requested_by_mac (
|
||||
void *rlc_pP,
|
||||
const tb_size_t tb_sizeP
|
||||
) {
|
||||
((rlc_um_entity_t *) rlc_pP)->nb_bytes_requested_by_mac = tb_sizeP;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
struct mac_data_req
|
||||
rlc_um_mac_data_request (const protocol_ctxt_t *const ctxt_pP, void *rlc_pP,const eNB_flag_t enb_flagP) {
|
||||
|
||||
@@ -160,27 +160,15 @@ rlc_um_get_pdus (const protocol_ctxt_t* const ctxt_pP, void *argP);
|
||||
*/
|
||||
void
|
||||
rlc_um_rx (const protocol_ctxt_t* const ctxt_pP, void *argP, struct mac_data_ind data_indP);
|
||||
/*! \fn struct mac_status_resp rlc_um_mac_status_indication (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP)
|
||||
/*! \fn struct mac_status_resp rlc_um_mac_status_indication (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP, struct mac_status_ind tx_statusP)
|
||||
* \brief Request the maximum number of bytes that can be served by RLC instance to MAC and fix the amount of bytes requested by MAC for next RLC transmission.
|
||||
* \param[in] ctxt_pP Running context.
|
||||
* \param[in] rlc_pP RLC UM protocol instance pointer.
|
||||
* \param[in] tbs_sizeP Number of bytes requested by MAC for next transmission.
|
||||
* \param[in] tx_statusP Transmission status given by MAC on previous MAC transmission of the PDU.
|
||||
* \return The maximum number of bytes that can be served by RLC instance to MAC.
|
||||
*/
|
||||
struct mac_status_resp
|
||||
rlc_um_mac_status_indication (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP,const eNB_flag_t enb_flagP);
|
||||
|
||||
/*! \fn void rlc_um_set_nb_bytes_requested_by_mac (rlc_um_entity_t * const rlc_pP, const tb_size_t tb_sizeP)
|
||||
* \brief Set available TBS size for MAC Tx.
|
||||
* \param[in] rlc_pP RLC UM protocol instance pointer.
|
||||
* \param[in] tb_sizeP remaining TBS in bytes.
|
||||
*/
|
||||
void
|
||||
rlc_um_set_nb_bytes_requested_by_mac (
|
||||
void * rlc_pP,
|
||||
const tb_size_t tb_sizeP
|
||||
);
|
||||
rlc_um_mac_status_indication (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP, struct mac_status_ind tx_statusP,const eNB_flag_t enb_flagP);
|
||||
|
||||
/*! \fn struct mac_data_req rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP,const eNB_flag_t enb_flagP)
|
||||
* \brief Gives PDUs to lower layer MAC.
|
||||
|
||||
@@ -137,7 +137,7 @@ void (*rlc_rrc_data_ind)(
|
||||
const protocol_ctxt_t *const ctxtP,
|
||||
const rb_id_t rb_idP,
|
||||
const sdu_size_t sdu_sizeP,
|
||||
const uint8_t *const sduP);
|
||||
const uint8_t *const sduP) __attribute__ ((aligned(32)));
|
||||
|
||||
void (*rlc_rrc_data_conf)(
|
||||
const protocol_ctxt_t *const ctxtP,
|
||||
@@ -250,7 +250,7 @@ logical_chan_id_t rlc_mbms_rbid2lcid_eNB[MAX_eNB][NB_RB_MBMS_MAX];
|
||||
(((hash_key_t)(sESSION_ID)) << 37) | \
|
||||
(((hash_key_t)(0x0000000000000001)) << 63))
|
||||
|
||||
hash_table_t *rlc_coll_p;
|
||||
hash_table_t *rlc_coll_p __attribute__ ((aligned(32)));
|
||||
|
||||
/*! \fn tbs_size_t mac_rlc_serialize_tb (char* bufferP, list_t transport_blocksP)
|
||||
* \brief Serialize a list of transport blocks coming from RLC in order to be processed by MAC.
|
||||
@@ -391,7 +391,7 @@ void rrc_rlc_register_rrc (rrc_data_ind_cb_t rrc_data_indP, rrc_data_conf_cb_t r
|
||||
* \param [in] eNB_flagP Flag to indicate eNB (1) or UE (0)
|
||||
* \param [in] MBMS_flagP Flag to indicate whether this is the MBMS service (1) or not (0)
|
||||
* \param [in] rb_idP Radio bearer identifier.
|
||||
* \param [in] tb_sizeP Available Tx TBS in bytes. For UE only.
|
||||
* \param [in] tb_sizeP Requested Tx TBS in bytes.
|
||||
* \param [in,out] bufferP Memory area to fill with the bytes requested by MAC.
|
||||
* \return A status about the processing, OK or error code.
|
||||
*/
|
||||
@@ -416,7 +416,7 @@ tbs_size_t mac_rlc_data_req (const module_id_t, const rnti_t, con
|
||||
void mac_rlc_data_ind (const module_id_t, const rnti_t, const eNB_index_t,const frame_t, const eNB_flag_t, const MBMS_flag_t, logical_chan_id_t, char *, tb_size_t, num_tb_t,
|
||||
crc_t * );
|
||||
|
||||
/*! \fn mac_rlc_status_resp_t mac_rlc_status_ind (const module_id_t mod_idP, const rnti_t rntiP, const frame_t frameP, const sub_frame_t subframeP, const eNB_flag_t eNB_flagP, const MBMS_flag_t MBMS_flagP, logical_chan_id_t rb_idP, tb_size_t tb_sizeP)
|
||||
/*! \fn mac_rlc_status_resp_t mac_rlc_status_ind (const module_id_t mod_idP, const rnti_t rntiP, const frame_t frameP, const sub_frame_t subframeP, const eNB_flag_t eNB_flagP, const MBMS_flag_t MBMS_flagP, logical_chan_id_t rb_idP)
|
||||
* \brief Interface with MAC layer, request and set the number of bytes scheduled for transmission by the RLC instance corresponding to the radio bearer identifier.
|
||||
* \param[in] mod_idP Virtualized module identifier.
|
||||
* \param[in] rntiP UE identifier.
|
||||
@@ -425,10 +425,9 @@ void mac_rlc_data_ind (const module_id_t, const rnti_t, con
|
||||
* \param[in] eNB_flagP Flag to indicate eNB operation (1 true, 0 false)
|
||||
* \param[in] MBMS_flagP Flag to indicate whether this is the MBMS service (1) or not (0)
|
||||
* \param[in] rb_idP Radio bearer identifier.
|
||||
* \param[in] tb_sizeP Size of a transport block set in bytes.
|
||||
* \return The maximum number of bytes that the RLC instance can send in the next transmission sequence.
|
||||
*/
|
||||
mac_rlc_status_resp_t mac_rlc_status_ind (const module_id_t, const rnti_t, const eNB_index_t, const frame_t, const sub_frame_t, const eNB_flag_t, const MBMS_flag_t, logical_chan_id_t, tb_size_t
|
||||
mac_rlc_status_resp_t mac_rlc_status_ind (const module_id_t, const rnti_t, const eNB_index_t, const frame_t, const sub_frame_t, const eNB_flag_t, const MBMS_flag_t, logical_chan_id_t
|
||||
,const uint32_t sourceL2Id
|
||||
,const uint32_t destinationL2Id
|
||||
);
|
||||
|
||||
@@ -191,20 +191,19 @@ tbs_size_t mac_rlc_data_req(
|
||||
case RLC_MODE_AM:
|
||||
rlc_am_mui.rrc_mui_num = 0;
|
||||
|
||||
if (!enb_flagP) rlc_am_set_nb_bytes_requested_by_mac(&rlc_union_p->rlc.am,tb_sizeP);
|
||||
|
||||
((rlc_am_entity_t *) &rlc_union_p->rlc.am)->nb_bytes_requested_by_mac = tb_sizeP;
|
||||
data_request = rlc_am_mac_data_request(&ctxt, &rlc_union_p->rlc.am,enb_flagP);
|
||||
ret_tb_size =mac_rlc_serialize_tb(buffer_pP, data_request.data);
|
||||
break;
|
||||
|
||||
case RLC_MODE_UM:
|
||||
if (!enb_flagP) rlc_um_set_nb_bytes_requested_by_mac(&rlc_union_p->rlc.um,tb_sizeP);
|
||||
|
||||
((rlc_um_entity_t *) &rlc_union_p->rlc.um)->nb_bytes_requested_by_mac = tb_sizeP;
|
||||
data_request = rlc_um_mac_data_request(&ctxt, &rlc_union_p->rlc.um,enb_flagP);
|
||||
ret_tb_size = mac_rlc_serialize_tb(buffer_pP, data_request.data);
|
||||
break;
|
||||
|
||||
case RLC_MODE_TM:
|
||||
((rlc_tm_entity_t *) &rlc_union_p->rlc.tm)->rlc_pdu_size = tb_sizeP;
|
||||
data_request = rlc_tm_mac_data_request(&ctxt, &rlc_union_p->rlc.tm);
|
||||
ret_tb_size = mac_rlc_serialize_tb(buffer_pP, data_request.data);
|
||||
break;
|
||||
@@ -317,7 +316,6 @@ mac_rlc_status_resp_t mac_rlc_status_ind(
|
||||
const eNB_flag_t enb_flagP,
|
||||
const MBMS_flag_t MBMS_flagP,
|
||||
const logical_chan_id_t channel_idP,
|
||||
const tb_size_t tb_sizeP,
|
||||
const uint32_t sourceL2Id,
|
||||
const uint32_t destinationL2Id
|
||||
) {
|
||||
@@ -370,7 +368,7 @@ mac_rlc_status_resp_t mac_rlc_status_ind(
|
||||
break;
|
||||
|
||||
case RLC_MODE_AM:
|
||||
status_resp = rlc_am_mac_status_indication(&ctxt, &rlc_union_p->rlc.am, tb_sizeP, tx_status,enb_flagP);
|
||||
status_resp = rlc_am_mac_status_indication(&ctxt, &rlc_union_p->rlc.am, tx_status,enb_flagP);
|
||||
mac_rlc_status_resp.bytes_in_buffer = status_resp.buffer_occupancy_in_bytes;
|
||||
mac_rlc_status_resp.head_sdu_creation_time = status_resp.head_sdu_creation_time;
|
||||
mac_rlc_status_resp.head_sdu_remaining_size_to_send = status_resp.head_sdu_remaining_size_to_send;
|
||||
@@ -379,7 +377,7 @@ mac_rlc_status_resp_t mac_rlc_status_ind(
|
||||
break;
|
||||
|
||||
case RLC_MODE_UM:
|
||||
status_resp = rlc_um_mac_status_indication(&ctxt, &rlc_union_p->rlc.um, tb_sizeP, tx_status, enb_flagP);
|
||||
status_resp = rlc_um_mac_status_indication(&ctxt, &rlc_union_p->rlc.um, tx_status, enb_flagP);
|
||||
mac_rlc_status_resp.bytes_in_buffer = status_resp.buffer_occupancy_in_bytes;
|
||||
mac_rlc_status_resp.pdus_in_buffer = status_resp.buffer_occupancy_in_pdus;
|
||||
mac_rlc_status_resp.head_sdu_creation_time = status_resp.head_sdu_creation_time;
|
||||
@@ -389,7 +387,7 @@ mac_rlc_status_resp_t mac_rlc_status_ind(
|
||||
break;
|
||||
|
||||
case RLC_MODE_TM:
|
||||
status_resp = rlc_tm_mac_status_indication(&ctxt, &rlc_union_p->rlc.tm, tb_sizeP, tx_status);
|
||||
status_resp = rlc_tm_mac_status_indication(&ctxt, &rlc_union_p->rlc.tm, tx_status);
|
||||
mac_rlc_status_resp.bytes_in_buffer = status_resp.buffer_occupancy_in_bytes;
|
||||
mac_rlc_status_resp.pdus_in_buffer = status_resp.buffer_occupancy_in_pdus;
|
||||
// return mac_rlc_status_resp;
|
||||
|
||||
@@ -114,7 +114,6 @@ tbs_size_t mac_rlc_data_req(
|
||||
int ret;
|
||||
nr_rlc_ue_t *ue;
|
||||
nr_rlc_entity_t *rb;
|
||||
int is_enb;
|
||||
int maxsize;
|
||||
|
||||
nr_rlc_manager_lock(nr_rlc_ue_manager);
|
||||
@@ -128,12 +127,7 @@ tbs_size_t mac_rlc_data_req(
|
||||
|
||||
if (rb != NULL) {
|
||||
rb->set_time(rb, nr_rlc_current_time);
|
||||
/* UE does not seem to use saved_status_ind_tb_size */
|
||||
is_enb = nr_rlc_manager_get_enb_flag(nr_rlc_ue_manager);
|
||||
if (is_enb)
|
||||
maxsize = ue->saved_status_ind_tb_size[channel_idP - 1];
|
||||
else
|
||||
maxsize = tb_sizeP;
|
||||
maxsize = tb_sizeP;
|
||||
ret = rb->generate_pdu(rb, buffer_pP, maxsize);
|
||||
} else {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal: data req for unknown RB\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
@@ -159,7 +153,6 @@ mac_rlc_status_resp_t mac_rlc_status_ind(
|
||||
const eNB_flag_t enb_flagP,
|
||||
const MBMS_flag_t MBMS_flagP,
|
||||
const logical_chan_id_t channel_idP,
|
||||
const tb_size_t tb_sizeP,
|
||||
const uint32_t sourceL2Id,
|
||||
const uint32_t destinationL2Id
|
||||
)
|
||||
@@ -196,7 +189,6 @@ mac_rlc_status_resp_t mac_rlc_status_ind(
|
||||
ret.bytes_in_buffer = buf_stat.status_size
|
||||
+ buf_stat.retx_size
|
||||
+ buf_stat.tx_size;
|
||||
ue->saved_status_ind_tb_size[channel_idP - 1] = tb_sizeP;
|
||||
} else {
|
||||
ret.bytes_in_buffer = 0;
|
||||
}
|
||||
|
||||
@@ -28,10 +28,6 @@ typedef void nr_rlc_ue_manager_t;
|
||||
|
||||
typedef struct nr_rlc_ue_t {
|
||||
int rnti;
|
||||
/* due to openair calling status_ind/data_req, we need to keep this.
|
||||
* To be considered 'hackish'.
|
||||
*/
|
||||
int saved_status_ind_tb_size[2+5];
|
||||
nr_rlc_entity_t *srb[2];
|
||||
nr_rlc_entity_t *drb[5];
|
||||
} nr_rlc_ue_t;
|
||||
|
||||
@@ -91,12 +91,12 @@ int dump_eNB_l2_stats(char *buffer, int length) {
|
||||
number_of_cards=NB_eNB_INST;
|
||||
#endif
|
||||
eNB_MAC_INST *eNB;
|
||||
UE_list_t *UE_list;
|
||||
UE_info_t *UE_info;
|
||||
|
||||
for (eNB_id=0; eNB_id<number_of_cards; eNB_id++) {
|
||||
/* reset the values */
|
||||
eNB = RC.mac[eNB_id];
|
||||
UE_list = &eNB->UE_list;
|
||||
UE_info = &eNB->UE_info;
|
||||
|
||||
for (CC_id=0 ; CC_id < MAX_NUM_CCs; CC_id++) {
|
||||
eNB->eNB_stats[CC_id].dlsch_bitrate= 0;
|
||||
@@ -141,76 +141,76 @@ int dump_eNB_l2_stats(char *buffer, int length) {
|
||||
|
||||
len += sprintf(&buffer[len],"\n");
|
||||
|
||||
for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) {
|
||||
for (i=0; i<UE_list->numactiveCCs[UE_id]; i++) {
|
||||
CC_id=UE_list->ordered_CCids[i][UE_id];
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_bitrate=((UE_list->eNB_UE_stats[CC_id][UE_id].TBS*8)/((eNB->frame + 1)*10));
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].total_dlsch_bitrate= ((UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes*8)/((eNB->frame + 1)*10));
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].total_overhead_bytes+= UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes;
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].avg_overhead_bytes=((UE_list->eNB_UE_stats[CC_id][UE_id].total_overhead_bytes*8)/((eNB->frame + 1)*10));
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_bitrate=((UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_TBS*8)/((eNB->frame + 1)*10));
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].total_ulsch_bitrate= ((UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes_rx*8)/((eNB->frame + 1)*10));
|
||||
for (UE_id=UE_info->list.head; UE_id>=0; UE_id=UE_info->list.next[UE_id]) {
|
||||
for (i=0; i<UE_info->numactiveCCs[UE_id]; i++) {
|
||||
CC_id=UE_info->ordered_CCids[i][UE_id];
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].dlsch_bitrate=((UE_info->eNB_UE_stats[CC_id][UE_id].TBS*8)/((eNB->frame + 1)*10));
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].total_dlsch_bitrate= ((UE_info->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes*8)/((eNB->frame + 1)*10));
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].total_overhead_bytes+= UE_info->eNB_UE_stats[CC_id][UE_id].overhead_bytes;
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].avg_overhead_bytes=((UE_info->eNB_UE_stats[CC_id][UE_id].total_overhead_bytes*8)/((eNB->frame + 1)*10));
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].ulsch_bitrate=((UE_info->eNB_UE_stats[CC_id][UE_id].ulsch_TBS*8)/((eNB->frame + 1)*10));
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].total_ulsch_bitrate= ((UE_info->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes_rx*8)/((eNB->frame + 1)*10));
|
||||
len += sprintf(&buffer[len],"[MAC] UE %d (DLSCH),status %s, RNTI %x : CQI %d, MCS1 %d, MCS2 %d, RB (tx %d, retx %d, total %d), ncce (tx %d, retx %d) \n",
|
||||
UE_id,
|
||||
map_int_to_str(rrc_status_names, UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status),
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].crnti,
|
||||
UE_list->UE_sched_ctrl[UE_id].dl_cqi[CC_id],
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].ncce_used,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].ncce_used_retx
|
||||
map_int_to_str(rrc_status_names, UE_info->eNB_UE_stats[CC_id][UE_id].rrc_status),
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].crnti,
|
||||
UE_info->UE_sched_ctrl[UE_id].dl_cqi[CC_id],
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].rbs_used,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].rbs_used_retx,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].total_rbs_used,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].ncce_used,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].ncce_used_retx
|
||||
);
|
||||
len += sprintf(&buffer[len],
|
||||
"[MAC] DLSCH bitrate (TTI %d, avg %d), Transmitted bytes "
|
||||
"(TTI %d, total %"PRIu64"), Total Transmitted PDU %d, Overhead "
|
||||
"(TTI %"PRIu64", total %"PRIu64", avg %"PRIu64")\n",
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_bitrate,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].total_dlsch_bitrate,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].TBS,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].total_overhead_bytes,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].avg_overhead_bytes
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].dlsch_bitrate,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].total_dlsch_bitrate,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].TBS,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].total_num_pdus,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].overhead_bytes,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].total_overhead_bytes,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].avg_overhead_bytes
|
||||
);
|
||||
len += sprintf(&buffer[len],"[MAC] UE %d (ULSCH), Status %s, Failute timer %d, RNTI %x : snr (%d, target %d), MCS (pre %d, post %d), RB (rx %d, retx %d, total %d), Current TBS %d \n",
|
||||
UE_id,
|
||||
map_int_to_str(rrc_status_names, UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status),
|
||||
UE_list->UE_sched_ctrl[UE_id].ul_failure_timer,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].crnti,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].snr,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].target_snr,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_rx,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx_rx,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_TBS
|
||||
map_int_to_str(rrc_status_names, UE_info->eNB_UE_stats[CC_id][UE_id].rrc_status),
|
||||
UE_info->UE_sched_ctrl[UE_id].ul_failure_timer,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].crnti,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].snr,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].target_snr,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].rbs_used_rx,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].rbs_used_retx_rx,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].ulsch_TBS
|
||||
);
|
||||
len += sprintf(&buffer[len],
|
||||
"[MAC] ULSCH bitrate (TTI %d, avg %d), received bytes (total %"PRIu64"),"
|
||||
"Total received PDU %d, Total errors %d\n",
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_bitrate,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].total_ulsch_bitrate,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes_rx,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus_rx,
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].num_errors_rx);
|
||||
len+= sprintf(&buffer[len],"[MAC] Received PHR PH = %d (db)\n", UE_list->UE_template[CC_id][UE_id].phr_info);
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].ulsch_bitrate,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].total_ulsch_bitrate,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes_rx,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].total_num_pdus_rx,
|
||||
UE_info->eNB_UE_stats[CC_id][UE_id].num_errors_rx);
|
||||
len+= sprintf(&buffer[len],"[MAC] Received PHR PH = %d (db)\n", UE_info->UE_template[CC_id][UE_id].phr_info);
|
||||
len+= sprintf(&buffer[len],"[MAC] Estimated size LCGID[0][1][2][3] = %u %u %u %u\n",
|
||||
UE_list->UE_template[CC_id][UE_id].ul_buffer_info[LCGID0],
|
||||
UE_list->UE_template[CC_id][UE_id].ul_buffer_info[LCGID1],
|
||||
UE_list->UE_template[CC_id][UE_id].ul_buffer_info[LCGID2],
|
||||
UE_list->UE_template[CC_id][UE_id].ul_buffer_info[LCGID3]
|
||||
UE_info->UE_template[CC_id][UE_id].ul_buffer_info[LCGID0],
|
||||
UE_info->UE_template[CC_id][UE_id].ul_buffer_info[LCGID1],
|
||||
UE_info->UE_template[CC_id][UE_id].ul_buffer_info[LCGID2],
|
||||
UE_info->UE_template[CC_id][UE_id].ul_buffer_info[LCGID3]
|
||||
);
|
||||
}
|
||||
|
||||
PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt,
|
||||
eNB_id,
|
||||
ENB_FLAG_YES,
|
||||
UE_list->eNB_UE_stats[0][UE_id].crnti,//UE_PCCID(eNB_id,UE_id)][UE_id].crnti,
|
||||
UE_info->eNB_UE_stats[0][UE_id].crnti,//UE_PCCID(eNB_id,UE_id)][UE_id].crnti,
|
||||
eNB->frame,
|
||||
eNB->subframe,
|
||||
eNB_id);
|
||||
@@ -509,7 +509,7 @@ int openair2_stats_read(char *buffer, char **my_buffer, off_t off, int length) {
|
||||
for(i=1; i<=NB_CNX_CH; i++) {
|
||||
if (CH_mac_inst[Mod_id].Dcch_lchan[i].Active==1) {
|
||||
len+=sprintf(&buffer[len],"\nMR index %u: DL SINR (feedback) %d dB, CQI: %s\n\n",
|
||||
i,//CH_rrc_inst[Mod_id].Info.UE_list[i].L2_id[0],
|
||||
i,//CH_rrc_inst[Mod_id].Info.UE_info[i].L2_id[0],
|
||||
CH_mac_inst[Mod_id].Def_meas[i].Wideband_sinr,
|
||||
print_cqi(CH_mac_inst[Mod_id].Def_meas[i].cqi));
|
||||
len+=sprintf(&buffer[len],
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
RLC AM
|
||||
======
|
||||
|
||||
- 36.322 5.4 Re-establishment procedure
|
||||
when possible, reassemble RLC SDUs from any byte segments of AMD PDUs
|
||||
with SN < VR(MR) in the receiving side, remove RLC headers when doing
|
||||
so and deliver all reassembled RLC SDUs to upper layer in ascending order
|
||||
of the RLC SN, if not delivered before;
|
||||
|
||||
- 36.322 5.2.3 Status reporting
|
||||
delay triggering the STATUS report until x < VR(MS) or x >= VR(MR)
|
||||
|
||||
- 36.322 5.1.3.2.3 Actions when a RLC data PDU is placed in the reception
|
||||
buffer
|
||||
[...] and in-sequence byte segments of the AMD PDU with SN = VR(R) [...]
|
||||
|
||||
- use SOstart/SOend in NACK reporting, do not NACK full PDU if
|
||||
parts of it have been received
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "rlc.h"
|
||||
|
||||
int decode_t_reordering(int v)
|
||||
{
|
||||
static int tab[32] = {
|
||||
0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85,
|
||||
90, 95, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 1600
|
||||
};
|
||||
|
||||
if (v < 0 || v > 31) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return tab[v];
|
||||
}
|
||||
|
||||
int decode_t_status_prohibit(int v)
|
||||
{
|
||||
static int tab[62] = {
|
||||
0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90,
|
||||
95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165,
|
||||
170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230, 235, 240,
|
||||
245, 250, 300, 350, 400, 450, 500, 800, 1000, 1200, 1600, 2000, 2400
|
||||
};
|
||||
|
||||
if (v < 0 || v > 61) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return tab[v];
|
||||
}
|
||||
|
||||
int decode_t_poll_retransmit(int v)
|
||||
{
|
||||
static int tab[59] = {
|
||||
5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95,
|
||||
100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 170,
|
||||
175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230, 235, 240, 245,
|
||||
250, 300, 350, 400, 450, 500, 800, 1000, 2000, 4000
|
||||
};
|
||||
|
||||
if (v < 0 || v > 58) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return tab[v];
|
||||
}
|
||||
|
||||
int decode_poll_pdu(int v)
|
||||
{
|
||||
static int tab[8] = {
|
||||
4, 8, 16, 32, 64, 128, 256, -1 /* -1 means infinity */
|
||||
};
|
||||
|
||||
if (v < 0 || v > 7) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return tab[v];
|
||||
}
|
||||
|
||||
int decode_poll_byte(int v)
|
||||
{
|
||||
static int tab[15] = {
|
||||
25, 50, 75, 100, 125, 250, 375, 500, 750, 1000, 1250, 1500, 2000, 3000,
|
||||
-1 /* -1 means infinity */
|
||||
};
|
||||
|
||||
if (v < 0 || v > 14) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (tab[v] == -1) return -1;
|
||||
return tab[v] * 1024;
|
||||
}
|
||||
|
||||
int decode_max_retx_threshold(int v)
|
||||
{
|
||||
static int tab[8] = {
|
||||
1, 2, 3, 4, 6, 8, 16, 32
|
||||
};
|
||||
|
||||
if (v < 0 || v > 7) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return tab[v];
|
||||
}
|
||||
|
||||
int decode_sn_field_length(int v)
|
||||
{
|
||||
static int tab[2] = {
|
||||
5, 10
|
||||
};
|
||||
|
||||
if (v < 0 || v > 1) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return tab[v];
|
||||
}
|
||||
@@ -19,3 +19,15 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef _ASN1_UTILS_H_
|
||||
#define _ASN1_UTILS_H_
|
||||
|
||||
int decode_t_reordering(int v);
|
||||
int decode_t_status_prohibit(int v);
|
||||
int decode_t_poll_retransmit(int v);
|
||||
int decode_poll_pdu(int v);
|
||||
int decode_poll_byte(int v);
|
||||
int decode_max_retx_threshold(int v);
|
||||
int decode_sn_field_length(int v);
|
||||
|
||||
#endif /* _ASN1_UTILS_H_ */
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "rlc_entity.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "rlc_entity_am.h"
|
||||
#include "rlc_entity_um.h"
|
||||
|
||||
#include "LOG/log.h"
|
||||
|
||||
rlc_entity_t *new_rlc_entity_am(
|
||||
int rx_maxsize,
|
||||
int tx_maxsize,
|
||||
void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity,
|
||||
char *buf, int size),
|
||||
void *deliver_sdu_data,
|
||||
void (*sdu_successful_delivery)(void *sdu_successful_delivery_data,
|
||||
struct rlc_entity_t *entity,
|
||||
int sdu_id),
|
||||
void *sdu_successful_delivery_data,
|
||||
void (*max_retx_reached)(void *max_retx_reached_data,
|
||||
struct rlc_entity_t *entity),
|
||||
void *max_retx_reached_data,
|
||||
int t_reordering,
|
||||
int t_status_prohibit,
|
||||
int t_poll_retransmit,
|
||||
int poll_pdu,
|
||||
int poll_byte,
|
||||
int max_retx_threshold)
|
||||
{
|
||||
rlc_entity_am_t *ret;
|
||||
|
||||
ret = calloc(1, sizeof(rlc_entity_am_t));
|
||||
if (ret == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret->common.recv_pdu = rlc_entity_am_recv_pdu;
|
||||
ret->common.buffer_status = rlc_entity_am_buffer_status;
|
||||
ret->common.generate_pdu = rlc_entity_am_generate_pdu;
|
||||
|
||||
ret->common.recv_sdu = rlc_entity_am_recv_sdu;
|
||||
|
||||
ret->common.set_time = rlc_entity_am_set_time;
|
||||
|
||||
ret->common.discard_sdu = rlc_entity_am_discard_sdu;
|
||||
|
||||
ret->common.reestablishment = rlc_entity_am_reestablishment;
|
||||
|
||||
ret->common.delete = rlc_entity_am_delete;
|
||||
|
||||
ret->common.deliver_sdu = deliver_sdu;
|
||||
ret->common.deliver_sdu_data = deliver_sdu_data;
|
||||
|
||||
ret->common.sdu_successful_delivery = sdu_successful_delivery;
|
||||
ret->common.sdu_successful_delivery_data = sdu_successful_delivery_data;
|
||||
|
||||
ret->common.max_retx_reached = max_retx_reached;
|
||||
ret->common.max_retx_reached_data = max_retx_reached_data;
|
||||
|
||||
ret->rx_maxsize = rx_maxsize;
|
||||
ret->tx_maxsize = tx_maxsize;
|
||||
ret->t_reordering = t_reordering;
|
||||
ret->t_status_prohibit = t_status_prohibit;
|
||||
ret->t_poll_retransmit = t_poll_retransmit;
|
||||
ret->poll_pdu = poll_pdu;
|
||||
ret->poll_byte = poll_byte;
|
||||
ret->max_retx_threshold = max_retx_threshold;
|
||||
|
||||
return (rlc_entity_t *)ret;
|
||||
}
|
||||
|
||||
rlc_entity_t *new_rlc_entity_um(
|
||||
int rx_maxsize,
|
||||
int tx_maxsize,
|
||||
void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity,
|
||||
char *buf, int size),
|
||||
void *deliver_sdu_data,
|
||||
int t_reordering,
|
||||
int sn_field_length)
|
||||
{
|
||||
rlc_entity_um_t *ret;
|
||||
|
||||
ret = calloc(1, sizeof(rlc_entity_um_t));
|
||||
if (ret == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret->common.recv_pdu = rlc_entity_um_recv_pdu;
|
||||
ret->common.buffer_status = rlc_entity_um_buffer_status;
|
||||
ret->common.generate_pdu = rlc_entity_um_generate_pdu;
|
||||
|
||||
ret->common.recv_sdu = rlc_entity_um_recv_sdu;
|
||||
|
||||
ret->common.set_time = rlc_entity_um_set_time;
|
||||
|
||||
ret->common.discard_sdu = rlc_entity_um_discard_sdu;
|
||||
|
||||
ret->common.reestablishment = rlc_entity_um_reestablishment;
|
||||
|
||||
ret->common.delete = rlc_entity_um_delete;
|
||||
|
||||
ret->common.deliver_sdu = deliver_sdu;
|
||||
ret->common.deliver_sdu_data = deliver_sdu_data;
|
||||
|
||||
ret->sn_field_length = sn_field_length;
|
||||
ret->rx_maxsize = rx_maxsize;
|
||||
ret->tx_maxsize = tx_maxsize;
|
||||
ret->t_reordering = t_reordering;
|
||||
|
||||
if (sn_field_length == 5)
|
||||
ret->sn_modulus = 32;
|
||||
else if (sn_field_length == 10)
|
||||
ret->sn_modulus = 1024;
|
||||
else {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
ret->window_size = ret->sn_modulus / 2;
|
||||
|
||||
return (rlc_entity_t *)ret;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef _RLC_ENTITY_H_
|
||||
#define _RLC_ENTITY_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define SDU_MAX 16000 /* maximum PDCP SDU size is 8188, let's take more */
|
||||
|
||||
typedef struct {
|
||||
int status_size;
|
||||
int tx_size;
|
||||
int retx_size;
|
||||
} rlc_entity_buffer_status_t;
|
||||
|
||||
typedef struct rlc_entity_t {
|
||||
/* functions provided by the RLC module */
|
||||
void (*recv_pdu)(struct rlc_entity_t *entity, char *buffer, int size);
|
||||
rlc_entity_buffer_status_t (*buffer_status)(
|
||||
struct rlc_entity_t *entity, int maxsize);
|
||||
int (*generate_pdu)(struct rlc_entity_t *entity, char *buffer, int size);
|
||||
|
||||
void (*recv_sdu)(struct rlc_entity_t *entity, char *buffer, int size,
|
||||
int sdu_id);
|
||||
|
||||
void (*set_time)(struct rlc_entity_t *entity, uint64_t now);
|
||||
|
||||
void (*discard_sdu)(struct rlc_entity_t *entity, int sdu_id);
|
||||
|
||||
void (*reestablishment)(struct rlc_entity_t *entity);
|
||||
|
||||
void (*delete)(struct rlc_entity_t *entity);
|
||||
|
||||
/* callbacks provided to the RLC module */
|
||||
void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity,
|
||||
char *buf, int size);
|
||||
void *deliver_sdu_data;
|
||||
|
||||
void (*sdu_successful_delivery)(void *sdu_successful_delivery_data,
|
||||
struct rlc_entity_t *entity,
|
||||
int sdu_id);
|
||||
void *sdu_successful_delivery_data;
|
||||
|
||||
void (*max_retx_reached)(void *max_retx_reached_data,
|
||||
struct rlc_entity_t *entity);
|
||||
void *max_retx_reached_data;
|
||||
} rlc_entity_t;
|
||||
|
||||
rlc_entity_t *new_rlc_entity_am(
|
||||
int rx_maxsize,
|
||||
int tx_maxsize,
|
||||
void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity,
|
||||
char *buf, int size),
|
||||
void *deliver_sdu_data,
|
||||
void (*sdu_successful_delivery)(void *sdu_successful_delivery_data,
|
||||
struct rlc_entity_t *entity,
|
||||
int sdu_id),
|
||||
void *sdu_successful_delivery_data,
|
||||
void (*max_retx_reached)(void *max_retx_reached_data,
|
||||
struct rlc_entity_t *entity),
|
||||
void *max_retx_reached_data,
|
||||
int t_reordering,
|
||||
int t_status_prohibit,
|
||||
int t_poll_retransmit,
|
||||
int poll_pdu,
|
||||
int poll_byte,
|
||||
int max_retx_threshold);
|
||||
|
||||
rlc_entity_t *new_rlc_entity_um(
|
||||
int rx_maxsize,
|
||||
int tx_maxsize,
|
||||
void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity,
|
||||
char *buf, int size),
|
||||
void *deliver_sdu_data,
|
||||
int t_reordering,
|
||||
int sn_field_length);
|
||||
|
||||
#endif /* _RLC_ENTITY_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef _RLC_ENTITY_AM_H_
|
||||
#define _RLC_ENTITY_AM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rlc_entity.h"
|
||||
#include "rlc_pdu.h"
|
||||
#include "rlc_sdu.h"
|
||||
|
||||
/*
|
||||
* Here comes some documentation to understand the reassembly
|
||||
* logic in the code and the fields in the structure rlc_am_reassemble_t.
|
||||
*
|
||||
* Inside RLC, we deal with SDUs, PDUs and PDU segments.
|
||||
* SDUs are packets coming from upper layer.
|
||||
* A PDU is made of a header and a payload.
|
||||
* In the payload there are SDUs.
|
||||
* First SDU and last SDU in a PDU may be incomplete.
|
||||
* PDU segments exist in case of retransmissions when the MAC
|
||||
* layer asks for less data than previously, in which case
|
||||
* only part of the previous PDU is sent.
|
||||
*
|
||||
* This is PDU data (just bytes):
|
||||
* ---------------------------------------------------------
|
||||
* | PDU data |
|
||||
* ---------------------------------------------------------
|
||||
* It contains SDUs, like:
|
||||
* ---------------------------------------------------------
|
||||
* | SDU 1 | SDU 2 | [...] | SDU n |
|
||||
* ---------------------------------------------------------
|
||||
* SDU 1 may be only the end of an SDU from which previous bytes were
|
||||
* transmitted in previous PDUs.
|
||||
* SDU n may be only the start of an SDU, that is more bytes from
|
||||
* this SDU may be sent in successive PDUs.
|
||||
*
|
||||
* At front of the PDU data, we have a header:
|
||||
* --------------- ---------------------------------------------------------
|
||||
* | PDU header | | SDU 1 | SDU 2 | [...] | SDU n |
|
||||
* --------------- ---------------------------------------------------------
|
||||
* PDU header describes PDU data (most notably lengths).
|
||||
*
|
||||
* A PDU segment is a part of a PDU. For example, from this PDU data:
|
||||
* ---------------------------------------------------------
|
||||
* | SDU 1 | SDU 2 | [...] | SDU n |
|
||||
* ---------------------------------------------------------
|
||||
* We can extract the following PDU segment (data part only):
|
||||
* ----------------------
|
||||
* | PDU segment data |
|
||||
* ----------------------
|
||||
* This PDU segment would contain the end of SDU 2 above and some SDUs up to,
|
||||
* let's say SDU x (x is 5 below).
|
||||
*
|
||||
* In front of a transmitted PDU segment, we have a header,
|
||||
* containing the important variable 'so' (segment offset) that gives
|
||||
* the index of the first byte of the segment in the original PDU.
|
||||
* -------------- ----------------------
|
||||
* | seg. header| | PDU segment data |
|
||||
* -------------- ----------------------
|
||||
*
|
||||
* Let's now explain the data structure rlc_am_reassemble_t.
|
||||
*
|
||||
* In the structure rlc_am_reassemble_t, the fields fi, e, sn and so
|
||||
* are coming from the PDU segment header and the semantics is the
|
||||
* one of the RLC specs.
|
||||
*
|
||||
* The currently processed PDU segment is stored in 'start'.
|
||||
* We have 'start->s->data_offset' and 'start->s->size'.
|
||||
* start->s->data_offset is the index of the start of the data in the
|
||||
* PDU segment. That is if the header is of length 3 bytes
|
||||
* then start->s->data_offset is 3.
|
||||
* start->s->size is the total length of the PDU segment,
|
||||
* including header.
|
||||
* The size of actual data bytes in the PDU segment is thus
|
||||
* start->s->size - start->s->data_offset.
|
||||
*
|
||||
* The field sdu_len is the length of the current SDU being
|
||||
* processed.
|
||||
*
|
||||
* The field sdu_offset is the starting point of the
|
||||
* current SDU being processed (starting from beginning
|
||||
* of PDU segment, including header).
|
||||
*
|
||||
* The field data_pos is the current read pointer. 0 points to
|
||||
* the beginning of the PDU segment (including header).
|
||||
*
|
||||
* The field pdu_byte points to the current byte in the original
|
||||
* PDU (not the PDU segment). It starts at 0 when we start
|
||||
* processing a new PDU (when a new 'sn' is seen) and always
|
||||
* increases after each byte processed. This is tha variable
|
||||
* that is used to know if the next PDU segment will be used
|
||||
* or not and if yes, starting from which data byte (see
|
||||
* function rlc_am_reassemble_next_segment).
|
||||
*
|
||||
* 'so' is important and points to the byte in the original PDU
|
||||
* that is the first byte of the PDU segment.
|
||||
*
|
||||
* For example, let's take this PDU segment data from above:
|
||||
* ----------------------
|
||||
* | PDU segment data |
|
||||
* ----------------------
|
||||
* Let's say it is decomposed as:
|
||||
* ----------------------
|
||||
* |222|33|4444|55555555|
|
||||
* ----------------------
|
||||
* It contains SDUs 2, 3, 4, and 5.
|
||||
* SDU 2 is 3 bytes, SDU 3 is 2 bytes, SDU 4 is 4 bytes, SDU 5 is 8 bytes.
|
||||
*
|
||||
* Let's suppose that the original PDU starts with:
|
||||
* ----------------
|
||||
* |1111111|222222|
|
||||
* ----------------
|
||||
*
|
||||
* (In this example, in the PDU segment, SDU 2 is not full,
|
||||
* we only have its end.)
|
||||
*
|
||||
* Then 'so' is 13 (SDU 1 is 7 bytes, head of SDU 2 is 6 bytes).
|
||||
*
|
||||
* Let's continue with our PDU segment data.
|
||||
* Let's say we are current processing SDU 4.
|
||||
* Let's say the read pointer (variable 'data_pos') is there:
|
||||
* ----------------------
|
||||
* |222|33|4444|55555555|
|
||||
* ----------------------
|
||||
* ^
|
||||
* read pointer (data_pos)
|
||||
*
|
||||
* Then:
|
||||
* - sdu_len is 4
|
||||
* - sdu_offset is 5 + [PDU segment header length]
|
||||
* (it points to the beginning of SDU 4, starting
|
||||
* from the head of the PDU segment, that is
|
||||
* 3 bytes for SDU 2, 2 bytes for SDU 3, and the
|
||||
* PDU segment header length)
|
||||
* - start->s->data_offset is [PDU segment header length]
|
||||
* - pdu_byte is 20
|
||||
* (13 bytes from beginning of original PDU,
|
||||
* 3 bytes for SDU 2, 2 bytes for SDU 3, then 2 bytes for SDU 4)
|
||||
* - data_pos = read pointer = 7 + [PDU segment header length]
|
||||
*
|
||||
* To finish this description, in the code, a PDU is simply
|
||||
* seen as a PDU segment with 'so' = 0 (and is_last == 1 (lsf in the specs),
|
||||
* but this variable is not used by the reassembly logic).
|
||||
*
|
||||
* And for [PDU segment header length] we use start->s->data_offset.
|
||||
*
|
||||
* To recap, here is an illustration of the various variables
|
||||
* and what starting point they use. In the figures, the start
|
||||
* of the variable name is aligned to the byte it refers to.
|
||||
* + is used to show the starting point.
|
||||
*
|
||||
* Let's put the PDU segment back into the original PDU.
|
||||
* And let's show the values for when the read pointer
|
||||
* is on the second byte of SDU 4 (as above).
|
||||
*
|
||||
* +++++++++++++++ so
|
||||
* +++++++++++++++++++++++ pdu_byte
|
||||
* ---------------------------------------------------------
|
||||
* | SDU 1| SDU 2..222|33|4444|55555555| [...] | SDU n |
|
||||
* ---------------------------------------------------------
|
||||
*
|
||||
* And now the PDU segment with header.
|
||||
*
|
||||
*
|
||||
* ++++ sdu_len
|
||||
* ++++++++++++++++++++++ sdu_offset
|
||||
* +++++++++++++++++++++++ data_pos
|
||||
* +++++++++++++++ start->s->data_offset
|
||||
* +++++++++++++++++++++++++++++++++++++ start->s->size
|
||||
* -------------- ----------------------
|
||||
* | seg. header| |222|33|4444|55555555|
|
||||
* -------------- ----------------------
|
||||
*
|
||||
* We see three case for the starting point:
|
||||
* - start of original PDU (without any header)
|
||||
* - start of header of current PDU segment
|
||||
* - start of current SDU (for sdu_len)
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
rlc_rx_pdu_segment_t *start; /* start of list */
|
||||
rlc_rx_pdu_segment_t *end; /* end of list (last element) */
|
||||
int pos; /* byte to get from current buffer */
|
||||
char sdu[SDU_MAX]; /* sdu is reassembled here */
|
||||
int sdu_pos; /* next byte to put in sdu */
|
||||
|
||||
/* decoder of current PDU */
|
||||
rlc_pdu_decoder_t dec;
|
||||
int fi;
|
||||
int e;
|
||||
int sn;
|
||||
int so;
|
||||
int sdu_len;
|
||||
int sdu_offset;
|
||||
int data_pos;
|
||||
int pdu_byte;
|
||||
} rlc_am_reassemble_t;
|
||||
|
||||
typedef struct {
|
||||
rlc_entity_t common;
|
||||
|
||||
/* configuration */
|
||||
int t_reordering;
|
||||
int t_status_prohibit;
|
||||
int t_poll_retransmit;
|
||||
int poll_pdu; /* -1 means infinity */
|
||||
int poll_byte; /* -1 means infinity */
|
||||
int max_retx_threshold;
|
||||
|
||||
/* runtime rx */
|
||||
int vr_r;
|
||||
int vr_x;
|
||||
int vr_ms;
|
||||
int vr_h;
|
||||
|
||||
int status_triggered;
|
||||
|
||||
/* runtime tx */
|
||||
int vt_a;
|
||||
int vt_s;
|
||||
int poll_sn;
|
||||
int pdu_without_poll;
|
||||
int byte_without_poll;
|
||||
int force_poll;
|
||||
|
||||
/* set to the latest know time by the user of the module. Unit: ms */
|
||||
uint64_t t_current;
|
||||
|
||||
/* timers (stores the TTI of activation, 0 means not active) */
|
||||
uint64_t t_reordering_start;
|
||||
uint64_t t_status_prohibit_start;
|
||||
uint64_t t_poll_retransmit_start;
|
||||
|
||||
/* rx management */
|
||||
rlc_rx_pdu_segment_t *rx_list;
|
||||
int rx_size;
|
||||
int rx_maxsize;
|
||||
|
||||
/* reassembly management */
|
||||
rlc_am_reassemble_t reassemble;
|
||||
|
||||
/* tx management */
|
||||
rlc_sdu_t *tx_list;
|
||||
rlc_sdu_t *tx_end;
|
||||
int tx_size;
|
||||
int tx_maxsize;
|
||||
|
||||
rlc_tx_pdu_segment_t *wait_list;
|
||||
rlc_tx_pdu_segment_t *retransmit_list;
|
||||
|
||||
rlc_tx_pdu_segment_t *ack_list;
|
||||
} rlc_entity_am_t;
|
||||
|
||||
void rlc_entity_am_recv_sdu(rlc_entity_t *entity, char *buffer, int size,
|
||||
int sdu_id);
|
||||
void rlc_entity_am_recv_pdu(rlc_entity_t *entity, char *buffer, int size);
|
||||
rlc_entity_buffer_status_t rlc_entity_am_buffer_status(
|
||||
rlc_entity_t *entity, int maxsize);
|
||||
int rlc_entity_am_generate_pdu(rlc_entity_t *entity, char *buffer, int size);
|
||||
void rlc_entity_am_set_time(rlc_entity_t *entity, uint64_t now);
|
||||
void rlc_entity_am_discard_sdu(rlc_entity_t *entity, int sdu_id);
|
||||
void rlc_entity_am_reestablishment(rlc_entity_t *entity);
|
||||
void rlc_entity_am_delete(rlc_entity_t *entity);
|
||||
|
||||
#endif /* _RLC_ENTITY_AM_H_ */
|
||||
@@ -0,0 +1,708 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "rlc_entity_um.h"
|
||||
#include "rlc_pdu.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "LOG/log.h"
|
||||
|
||||
/*************************************************************************/
|
||||
/* PDU RX functions */
|
||||
/*************************************************************************/
|
||||
|
||||
static int modulus_rx(rlc_entity_um_t *entity, int a)
|
||||
{
|
||||
/* as per 36.322 7.1, modulus base is vr(uh)-window_size and modulus is
|
||||
* 2^sn_field_length (which is 'sn_modulus' in rlc_entity_um_t)
|
||||
*/
|
||||
int r = a - (entity->vr_uh - entity->window_size);
|
||||
if (r < 0) r += entity->sn_modulus;
|
||||
return r % entity->sn_modulus;
|
||||
}
|
||||
|
||||
static int sn_compare_rx(void *_entity, int a, int b)
|
||||
{
|
||||
rlc_entity_um_t *entity = _entity;
|
||||
return modulus_rx(entity, a) - modulus_rx(entity, b);
|
||||
}
|
||||
|
||||
static int sn_in_recv_window(void *_entity, int sn)
|
||||
{
|
||||
rlc_entity_um_t *entity = _entity;
|
||||
int mod_sn = modulus_rx(entity, sn);
|
||||
/* we simplify (VR(UH) - UM_Window_Size) <= SN < VR(UH), base is
|
||||
* (VR(UH) - UM_Window_Size) and VR(UH) = base + window_size
|
||||
*/
|
||||
return mod_sn < entity->window_size;
|
||||
}
|
||||
|
||||
/* return 1 if a PDU with SN == 'sn' is in the rx list, 0 otherwise */
|
||||
static int rlc_um_pdu_received(rlc_entity_um_t *entity, int sn)
|
||||
{
|
||||
rlc_rx_pdu_segment_t *cur = entity->rx_list;
|
||||
while (cur != NULL) {
|
||||
if (cur->sn == sn)
|
||||
return 1;
|
||||
cur = cur->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int less_than_vr_ur(rlc_entity_um_t *entity, int sn)
|
||||
{
|
||||
return sn_compare_rx(entity, sn, entity->vr_ur) < 0;
|
||||
}
|
||||
|
||||
static int outside_of_reordering_window(rlc_entity_um_t *entity, int sn)
|
||||
{
|
||||
return !sn_in_recv_window(entity, sn);
|
||||
}
|
||||
|
||||
static int less_than_vr_uh(rlc_entity_um_t *entity, int sn)
|
||||
{
|
||||
return sn_compare_rx(entity, sn, entity->vr_uh) < 0;
|
||||
}
|
||||
|
||||
static void rlc_um_reassemble_pdu(rlc_entity_um_t *entity,
|
||||
rlc_rx_pdu_segment_t *pdu)
|
||||
{
|
||||
rlc_um_reassemble_t *r = &entity->reassemble;
|
||||
|
||||
int fi;
|
||||
int e;
|
||||
int sn;
|
||||
int data_pos;
|
||||
int sdu_len;
|
||||
int sdu_offset;
|
||||
|
||||
sdu_offset = pdu->data_offset;
|
||||
|
||||
rlc_pdu_decoder_init(&r->dec, pdu->data, pdu->size);
|
||||
|
||||
if (entity->sn_field_length == 10)
|
||||
rlc_pdu_decoder_get_bits(&r->dec, 3);
|
||||
|
||||
fi = rlc_pdu_decoder_get_bits(&r->dec, 2);
|
||||
e = rlc_pdu_decoder_get_bits(&r->dec, 1);
|
||||
sn = rlc_pdu_decoder_get_bits(&r->dec, entity->sn_field_length);
|
||||
|
||||
if (e) {
|
||||
e = rlc_pdu_decoder_get_bits(&r->dec, 1);
|
||||
sdu_len = rlc_pdu_decoder_get_bits(&r->dec, 11);
|
||||
} else
|
||||
sdu_len = pdu->size - sdu_offset;
|
||||
|
||||
/* discard current SDU being reassembled if bad SN or bad FI */
|
||||
if (sn != (r->sn + 1) % entity->sn_modulus ||
|
||||
!(fi & 0x02)) {
|
||||
if (r->sdu_pos)
|
||||
LOG_D(RLC, "%s:%d:%s: warning: discard partially reassembled SDU\n",
|
||||
__FILE__, __LINE__, __FUNCTION__);
|
||||
r->sdu_pos = 0;
|
||||
}
|
||||
|
||||
/* if the head of the SDU is missing, still process the PDU
|
||||
* but remember to discard the reassembled SDU later on (the
|
||||
* head has not been received).
|
||||
* The head is missing if sdu_pos == 0 and fi says the PDU does not
|
||||
* start an SDU.
|
||||
*/
|
||||
if (r->sdu_pos == 0 && (fi & 0x02))
|
||||
r->sdu_head_missing = 1;
|
||||
|
||||
r->sn = sn;
|
||||
data_pos = pdu->data_offset;
|
||||
|
||||
while (1) {
|
||||
if (r->sdu_pos >= SDU_MAX) {
|
||||
/* TODO: proper error handling (discard PDUs with current sn from
|
||||
* reassembly queue? something else?)
|
||||
*/
|
||||
LOG_E(RLC, "%s:%d:%s: bad RLC PDU\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
r->sdu[r->sdu_pos] = pdu->data[data_pos];
|
||||
r->sdu_pos++;
|
||||
data_pos++;
|
||||
if (data_pos == sdu_offset + sdu_len) {
|
||||
/* all bytes of SDU are consumed, check if SDU is fully there.
|
||||
* It is if the data pointer is not at the end of the PDU segment
|
||||
* or if 'fi' & 1 == 0
|
||||
*/
|
||||
if (data_pos != pdu->size || (fi & 1) == 0) {
|
||||
/* time to discard the SDU if we didn't receive the head */
|
||||
if (r->sdu_head_missing) {
|
||||
LOG_D(RLC, "%s:%d:%s: warning: discard SDU, head not received\n",
|
||||
__FILE__, __LINE__, __FUNCTION__);
|
||||
r->sdu_head_missing = 0;
|
||||
} else {
|
||||
/* SDU is full - deliver to higher layer */
|
||||
entity->common.deliver_sdu(entity->common.deliver_sdu_data,
|
||||
(rlc_entity_t *)entity,
|
||||
r->sdu, r->sdu_pos);
|
||||
}
|
||||
r->sdu_pos = 0;
|
||||
}
|
||||
/* done with PDU? */
|
||||
if (data_pos == pdu->size)
|
||||
break;
|
||||
/* not at the end of PDU, process next SDU */
|
||||
sdu_offset += sdu_len;
|
||||
if (e) {
|
||||
e = rlc_pdu_decoder_get_bits(&r->dec, 1);
|
||||
sdu_len = rlc_pdu_decoder_get_bits(&r->dec, 11);
|
||||
} else
|
||||
sdu_len = pdu->size - sdu_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rlc_um_reassemble(rlc_entity_um_t *entity,
|
||||
int (*check_sn)(rlc_entity_um_t *entity, int sn))
|
||||
{
|
||||
rlc_rx_pdu_segment_t *cur;
|
||||
|
||||
/* process all PDUs from head of rx list until all is processed or
|
||||
* the SN is not valid anymore with respect to 'check_sn'
|
||||
*/
|
||||
while (entity->rx_list != NULL && check_sn(entity, entity->rx_list->sn)) {
|
||||
cur = entity->rx_list;
|
||||
rlc_um_reassemble_pdu(entity, cur);
|
||||
entity->rx_size -= cur->size;
|
||||
entity->rx_list = cur->next;
|
||||
rlc_rx_free_pdu_segment(cur);
|
||||
}
|
||||
}
|
||||
|
||||
static void rlc_um_reception_actions(rlc_entity_um_t *entity,
|
||||
rlc_rx_pdu_segment_t *pdu_segment)
|
||||
{
|
||||
if (!sn_in_recv_window(entity, pdu_segment->sn)) {
|
||||
entity->vr_uh = (pdu_segment->sn + 1) % entity->sn_modulus;
|
||||
rlc_um_reassemble(entity, outside_of_reordering_window);
|
||||
if (!sn_in_recv_window(entity, entity->vr_ur))
|
||||
entity->vr_ur = (entity->vr_uh - entity->window_size
|
||||
+ entity->sn_modulus) % entity->sn_modulus;
|
||||
}
|
||||
|
||||
if (rlc_um_pdu_received(entity, entity->vr_ur)) {
|
||||
do {
|
||||
entity->vr_ur = (entity->vr_ur + 1) % entity->sn_modulus;
|
||||
} while (rlc_um_pdu_received(entity, entity->vr_ur));
|
||||
rlc_um_reassemble(entity, less_than_vr_ur);
|
||||
}
|
||||
|
||||
if (entity->t_reordering_start) {
|
||||
if (sn_compare_rx(entity, entity->vr_ux, entity->vr_ur) <= 0 ||
|
||||
(!sn_in_recv_window(entity, entity->vr_ux) &&
|
||||
entity->vr_ux != entity->vr_uh))
|
||||
entity->t_reordering_start = 0;
|
||||
}
|
||||
|
||||
if (entity->t_reordering_start == 0) {
|
||||
if (sn_compare_rx(entity, entity->vr_uh, entity->vr_ur) > 0) {
|
||||
entity->t_reordering_start = entity->t_current;
|
||||
entity->vr_ux = entity->vr_uh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rlc_entity_um_recv_pdu(rlc_entity_t *_entity, char *buffer, int size)
|
||||
{
|
||||
#define R(d) do { if (rlc_pdu_decoder_in_error(&d)) goto err; } while (0)
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
rlc_pdu_decoder_t decoder;
|
||||
rlc_pdu_decoder_t data_decoder;
|
||||
|
||||
int e;
|
||||
int sn;
|
||||
|
||||
int data_e;
|
||||
int data_li;
|
||||
|
||||
int packet_count;
|
||||
int data_size;
|
||||
int data_start;
|
||||
int indicated_data_size;
|
||||
|
||||
rlc_rx_pdu_segment_t *pdu_segment;
|
||||
|
||||
rlc_pdu_decoder_init(&decoder, buffer, size);
|
||||
|
||||
if (entity->sn_field_length == 10) {
|
||||
rlc_pdu_decoder_get_bits(&decoder, 3); R(decoder); /* R1 */
|
||||
}
|
||||
|
||||
rlc_pdu_decoder_get_bits(&decoder, 2); R(decoder); /* FI */
|
||||
e = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder);
|
||||
sn = rlc_pdu_decoder_get_bits(&decoder, entity->sn_field_length); R(decoder);
|
||||
|
||||
/* dicard PDU if rx buffer is full */
|
||||
if (entity->rx_size + size > entity->rx_maxsize) {
|
||||
LOG_D(RLC, "%s:%d:%s: warning: discard PDU, RX buffer full\n",
|
||||
__FILE__, __LINE__, __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* discard according to 36.322 5.1.2.2.2 */
|
||||
if ((sn_compare_rx(entity, entity->vr_ur, sn) < 0 &&
|
||||
sn_compare_rx(entity, sn, entity->vr_uh) < 0 &&
|
||||
rlc_um_pdu_received(entity, sn)) ||
|
||||
(sn_compare_rx(entity, entity->vr_uh - entity->window_size, sn) <= 0 &&
|
||||
sn_compare_rx(entity, sn, entity->vr_ur) < 0)) {
|
||||
LOG_D(RLC, "%s:%d:%s: warning: discard PDU (sn %d vr(ur) %d vr(uh) %d)\n",
|
||||
__FILE__, __LINE__, __FUNCTION__,
|
||||
sn, entity->vr_ur, entity->vr_uh);
|
||||
return;
|
||||
}
|
||||
|
||||
packet_count = 1;
|
||||
|
||||
/* go to start of data */
|
||||
indicated_data_size = 0;
|
||||
data_decoder = decoder;
|
||||
data_e = e;
|
||||
while (data_e) {
|
||||
data_e = rlc_pdu_decoder_get_bits(&data_decoder, 1); R(data_decoder);
|
||||
data_li = rlc_pdu_decoder_get_bits(&data_decoder, 11); R(data_decoder);
|
||||
if (data_li == 0) {
|
||||
LOG_D(RLC, "%s:%d:%s: warning: discard PDU, li == 0\n",
|
||||
__FILE__, __LINE__, __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
indicated_data_size += data_li;
|
||||
packet_count++;
|
||||
}
|
||||
rlc_pdu_decoder_align(&data_decoder);
|
||||
|
||||
data_start = data_decoder.byte;
|
||||
data_size = size - data_start;
|
||||
|
||||
if (data_size <= 0) {
|
||||
LOG_D(RLC, "%s:%d:%s: warning: discard PDU, wrong data size (sum of LI %d data size %d)\n",
|
||||
__FILE__, __LINE__, __FUNCTION__,
|
||||
indicated_data_size, data_size);
|
||||
return;
|
||||
}
|
||||
if (indicated_data_size >= data_size) {
|
||||
LOG_D(RLC, "%s:%d:%s: warning: discard PDU, bad LIs (sum of LI %d data size %d)\n",
|
||||
__FILE__, __LINE__, __FUNCTION__,
|
||||
indicated_data_size, data_size);
|
||||
return;
|
||||
}
|
||||
|
||||
/* put in pdu reception list */
|
||||
entity->rx_size += size;
|
||||
pdu_segment = rlc_rx_new_pdu_segment(sn, 0, size, 1, buffer, data_start);
|
||||
entity->rx_list = rlc_rx_pdu_segment_list_add(sn_compare_rx, entity,
|
||||
entity->rx_list, pdu_segment);
|
||||
|
||||
/* do reception actions (36.322 5.1.2.2.3) */
|
||||
rlc_um_reception_actions(entity, pdu_segment);
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
LOG_D(RLC, "%s:%d:%s: error decoding PDU, discarding\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
#undef R
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* TX functions */
|
||||
/*************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
int sdu_count;
|
||||
int data_size;
|
||||
int header_size;
|
||||
int last_sdu_is_full;
|
||||
int first_sdu_length;
|
||||
} tx_pdu_size_t;
|
||||
|
||||
static int header_size(int sn_field_length, int sdu_count)
|
||||
{
|
||||
int bits = 8 + 8 * (sn_field_length == 10) + 12 * (sdu_count - 1);
|
||||
/* padding if we have to */
|
||||
return (bits + 7) / 8;
|
||||
}
|
||||
|
||||
static tx_pdu_size_t tx_pdu_size(rlc_entity_um_t *entity, int maxsize)
|
||||
{
|
||||
tx_pdu_size_t ret;
|
||||
int sdu_count;
|
||||
int sdu_size;
|
||||
int pdu_data_size;
|
||||
rlc_sdu_t *sdu;
|
||||
|
||||
ret.sdu_count = 0;
|
||||
ret.data_size = 0;
|
||||
ret.header_size = 0;
|
||||
ret.last_sdu_is_full = 1;
|
||||
ret.first_sdu_length = 0;
|
||||
|
||||
/* TX PDU - let's make the biggest PDU we can with the SDUs we have */
|
||||
sdu_count = 0;
|
||||
pdu_data_size = 0;
|
||||
sdu = entity->tx_list;
|
||||
while (sdu != NULL) {
|
||||
int new_header_size = header_size(entity->sn_field_length, sdu_count+1);
|
||||
/* if we cannot put new header + at least 1 byte of data then over */
|
||||
if (new_header_size + pdu_data_size >= maxsize)
|
||||
break;
|
||||
sdu_count++;
|
||||
/* only include the bytes of this SDU not included in PDUs already */
|
||||
sdu_size = sdu->size - sdu->next_byte;
|
||||
/* don't feed more than 'maxsize' bytes */
|
||||
if (new_header_size + pdu_data_size + sdu_size > maxsize) {
|
||||
sdu_size = maxsize - new_header_size - pdu_data_size;
|
||||
ret.last_sdu_is_full = 0;
|
||||
}
|
||||
if (sdu_count == 1)
|
||||
ret.first_sdu_length = sdu_size;
|
||||
pdu_data_size += sdu_size;
|
||||
/* if we put more than 2^11-1 bytes then the LI field cannot be used,
|
||||
* so this is the last SDU we can put
|
||||
*/
|
||||
if (sdu_size > 2047)
|
||||
break;
|
||||
sdu = sdu->next;
|
||||
}
|
||||
|
||||
if (sdu_count) {
|
||||
ret.sdu_count = sdu_count;
|
||||
ret.data_size = pdu_data_size;
|
||||
ret.header_size = header_size(entity->sn_field_length, sdu_count);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rlc_entity_buffer_status_t rlc_entity_um_buffer_status(
|
||||
rlc_entity_t *_entity, int maxsize)
|
||||
{
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
rlc_entity_buffer_status_t ret;
|
||||
tx_pdu_size_t tx_size;
|
||||
|
||||
ret.status_size = 0;
|
||||
|
||||
/* todo: if an SDU has size >2047 in the tx list then processing
|
||||
* stops and computed size will not be accurate. Change the computation
|
||||
* to be more accurate (if needed).
|
||||
*/
|
||||
tx_size = tx_pdu_size(entity, maxsize);
|
||||
ret.tx_size = tx_size.data_size + tx_size.header_size;
|
||||
|
||||
ret.retx_size = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rlc_entity_um_generate_pdu(rlc_entity_t *_entity, char *buffer, int size)
|
||||
{
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
tx_pdu_size_t pdu_size;
|
||||
rlc_sdu_t *sdu;
|
||||
int i;
|
||||
int cursize;
|
||||
int first_sdu_full;
|
||||
int last_sdu_full;
|
||||
rlc_pdu_encoder_t encoder;
|
||||
int fi;
|
||||
int e;
|
||||
int li;
|
||||
char *out;
|
||||
int outpos;
|
||||
int first_sdu_start_byte;
|
||||
int sdu_start_byte;
|
||||
|
||||
pdu_size = tx_pdu_size(entity, size);
|
||||
if (pdu_size.sdu_count == 0)
|
||||
return 0;
|
||||
|
||||
sdu = entity->tx_list;
|
||||
|
||||
first_sdu_start_byte = sdu->next_byte;
|
||||
|
||||
/* reserve SDU bytes */
|
||||
cursize = 0;
|
||||
for (i = 0; i < pdu_size.sdu_count; i++, sdu = sdu->next) {
|
||||
int sdu_size = sdu->size - sdu->next_byte;
|
||||
if (cursize + sdu_size > pdu_size.data_size)
|
||||
sdu_size = pdu_size.data_size - cursize;
|
||||
sdu->next_byte += sdu_size;
|
||||
cursize += sdu_size;
|
||||
}
|
||||
|
||||
first_sdu_full = first_sdu_start_byte == 0;
|
||||
last_sdu_full = pdu_size.last_sdu_is_full;
|
||||
|
||||
/* generate header */
|
||||
rlc_pdu_encoder_init(&encoder, buffer, size);
|
||||
|
||||
if (entity->sn_field_length == 10)
|
||||
rlc_pdu_encoder_put_bits(&encoder, 0, 3); /* R1 */
|
||||
|
||||
fi = 0;
|
||||
if (!first_sdu_full)
|
||||
fi |= 0x02;
|
||||
if (!last_sdu_full)
|
||||
fi |= 0x01;
|
||||
rlc_pdu_encoder_put_bits(&encoder, fi, 2); /* FI */
|
||||
|
||||
/* see the AM code to understand the logic for Es and LIs */
|
||||
if (pdu_size.sdu_count >= 2)
|
||||
e = 1;
|
||||
else
|
||||
e = 0;
|
||||
rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */
|
||||
|
||||
if (entity->sn_field_length == 10)
|
||||
rlc_pdu_encoder_put_bits(&encoder, entity->vt_us, 10); /* SN */
|
||||
else
|
||||
rlc_pdu_encoder_put_bits(&encoder, entity->vt_us, 5); /* SN */
|
||||
|
||||
/* put LIs */
|
||||
sdu = entity->tx_list;
|
||||
/* first SDU */
|
||||
li = pdu_size.first_sdu_length;
|
||||
/* put E+LI only if at least 2 SDUs */
|
||||
if (pdu_size.sdu_count >= 2) {
|
||||
/* E is 1 if at least 3 SDUs */
|
||||
if (pdu_size.sdu_count >= 3)
|
||||
e = 1;
|
||||
else
|
||||
e = 0;
|
||||
rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */
|
||||
rlc_pdu_encoder_put_bits(&encoder, li, 11); /* LI */
|
||||
}
|
||||
/* next SDUs, but not the last (no LI for the last) */
|
||||
sdu = sdu->next;
|
||||
for (i = 2; i < pdu_size.sdu_count; i++, sdu = sdu->next) {
|
||||
if (i != pdu_size.sdu_count - 1)
|
||||
e = 1;
|
||||
else
|
||||
e = 0;
|
||||
li = sdu->size;
|
||||
rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */
|
||||
rlc_pdu_encoder_put_bits(&encoder, li, 11); /* LI */
|
||||
}
|
||||
|
||||
rlc_pdu_encoder_align(&encoder);
|
||||
|
||||
/* generate data */
|
||||
out = buffer + pdu_size.header_size;
|
||||
sdu = entity->tx_list;
|
||||
sdu_start_byte = first_sdu_start_byte;
|
||||
outpos = 0;
|
||||
for (i = 0; i < pdu_size.sdu_count; i++, sdu = sdu->next) {
|
||||
li = sdu->size - sdu_start_byte;
|
||||
if (outpos + li >= pdu_size.data_size)
|
||||
li = pdu_size.data_size - outpos;
|
||||
memcpy(out+outpos, sdu->data + sdu_start_byte, li);
|
||||
outpos += li;
|
||||
sdu_start_byte = 0;
|
||||
}
|
||||
|
||||
/* cleanup sdu list */
|
||||
while (entity->tx_list != NULL &&
|
||||
entity->tx_list->size == entity->tx_list->next_byte) {
|
||||
rlc_sdu_t *c = entity->tx_list;
|
||||
/* release SDU bytes */
|
||||
entity->tx_size -= c->size;
|
||||
entity->tx_list = c->next;
|
||||
rlc_free_sdu(c);
|
||||
}
|
||||
if (entity->tx_list == NULL)
|
||||
entity->tx_end = NULL;
|
||||
|
||||
/* update VT(US) */
|
||||
entity->vt_us = (entity->vt_us + 1) % entity->sn_modulus;
|
||||
|
||||
return pdu_size.header_size + pdu_size.data_size;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* SDU RX functions */
|
||||
/*************************************************************************/
|
||||
|
||||
void rlc_entity_um_recv_sdu(rlc_entity_t *_entity, char *buffer, int size,
|
||||
int sdu_id)
|
||||
{
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
rlc_sdu_t *sdu;
|
||||
|
||||
if (size > SDU_MAX) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal: SDU size too big (%d bytes)\n",
|
||||
__FILE__, __LINE__, __FUNCTION__, size);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (entity->tx_size + size > entity->tx_maxsize) {
|
||||
LOG_D(RLC, "%s:%d:%s: warning: SDU rejected, SDU buffer full\n",
|
||||
__FILE__, __LINE__, __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
entity->tx_size += size;
|
||||
|
||||
sdu = rlc_new_sdu(buffer, size, sdu_id);
|
||||
rlc_sdu_list_add(&entity->tx_list, &entity->tx_end, sdu);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* time/timers */
|
||||
/*************************************************************************/
|
||||
|
||||
static void check_t_reordering(rlc_entity_um_t *entity)
|
||||
{
|
||||
int sn;
|
||||
|
||||
/* is t_reordering running and if yes has it expired? */
|
||||
if (entity->t_reordering_start == 0 ||
|
||||
entity->t_current <= entity->t_reordering_start + entity->t_reordering)
|
||||
return;
|
||||
|
||||
/* stop timer */
|
||||
entity->t_reordering_start = 0;
|
||||
|
||||
LOG_D(RLC, "%s:%d:%s: t_reordering expired\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
/* update VR(UR) to first SN >= VR(UX) of PDU not received
|
||||
*/
|
||||
sn = entity->vr_ux;
|
||||
while (rlc_um_pdu_received(entity, sn))
|
||||
sn = (sn + 1) % entity->sn_modulus;
|
||||
entity->vr_ur = sn;
|
||||
|
||||
rlc_um_reassemble(entity, less_than_vr_ur);
|
||||
|
||||
if (sn_compare_rx(entity, entity->vr_uh, entity->vr_ur) > 0) {
|
||||
entity->t_reordering_start = entity->t_current;
|
||||
entity->vr_ux = entity->vr_uh;
|
||||
}
|
||||
}
|
||||
|
||||
void rlc_entity_um_set_time(rlc_entity_t *_entity, uint64_t now)
|
||||
{
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
|
||||
entity->t_current = now;
|
||||
|
||||
check_t_reordering(entity);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* discard/re-establishment/delete */
|
||||
/*************************************************************************/
|
||||
|
||||
void rlc_entity_um_discard_sdu(rlc_entity_t *_entity, int sdu_id)
|
||||
{
|
||||
/* implements 36.322 5.3 */
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
rlc_sdu_t head;
|
||||
rlc_sdu_t *cur;
|
||||
rlc_sdu_t *prev;
|
||||
|
||||
head.next = entity->tx_list;
|
||||
cur = entity->tx_list;
|
||||
prev = &head;
|
||||
|
||||
while (cur != NULL && cur->upper_layer_id != sdu_id) {
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
/* if sdu_id not found or some bytes have already been 'PDU-ized'
|
||||
* then do nothing
|
||||
*/
|
||||
if (cur == NULL || cur->next_byte != 0)
|
||||
return;
|
||||
|
||||
/* remove SDU from tx_list */
|
||||
prev->next = cur->next;
|
||||
entity->tx_list = head.next;
|
||||
if (entity->tx_end == cur) {
|
||||
if (prev != &head)
|
||||
entity->tx_end = prev;
|
||||
else
|
||||
entity->tx_end = NULL;
|
||||
}
|
||||
|
||||
rlc_free_sdu(cur);
|
||||
}
|
||||
|
||||
static void clear_entity(rlc_entity_um_t *entity)
|
||||
{
|
||||
rlc_rx_pdu_segment_t *cur_rx;
|
||||
rlc_sdu_t *cur_tx;
|
||||
|
||||
entity->vr_ur = 0;
|
||||
entity->vr_ux = 0;
|
||||
entity->vr_uh = 0;
|
||||
|
||||
entity->vt_us = 0;
|
||||
|
||||
entity->t_current = 0;
|
||||
|
||||
entity->t_reordering_start = 0;
|
||||
|
||||
cur_rx = entity->rx_list;
|
||||
while (cur_rx != NULL) {
|
||||
rlc_rx_pdu_segment_t *p = cur_rx;
|
||||
cur_rx = cur_rx->next;
|
||||
rlc_rx_free_pdu_segment(p);
|
||||
}
|
||||
entity->rx_list = NULL;
|
||||
entity->rx_size = 0;
|
||||
|
||||
memset(&entity->reassemble, 0, sizeof(rlc_um_reassemble_t));
|
||||
|
||||
cur_tx = entity->tx_list;
|
||||
while (cur_tx != NULL) {
|
||||
rlc_sdu_t *p = cur_tx;
|
||||
cur_tx = cur_tx->next;
|
||||
rlc_free_sdu(p);
|
||||
}
|
||||
entity->tx_list = NULL;
|
||||
entity->tx_end = NULL;
|
||||
entity->tx_size = 0;
|
||||
}
|
||||
|
||||
void rlc_entity_um_reestablishment(rlc_entity_t *_entity)
|
||||
{
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
|
||||
rlc_um_reassemble(entity, less_than_vr_uh);
|
||||
|
||||
clear_entity(entity);
|
||||
}
|
||||
|
||||
void rlc_entity_um_delete(rlc_entity_t *_entity)
|
||||
{
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
clear_entity(entity);
|
||||
free(entity);
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef _RLC_ENTITY_UM_H_
|
||||
#define _RLC_ENTITY_UM_H_
|
||||
|
||||
#include "rlc_entity.h"
|
||||
#include "rlc_pdu.h"
|
||||
#include "rlc_sdu.h"
|
||||
|
||||
typedef struct {
|
||||
char sdu[SDU_MAX]; /* sdu is reassembled here */
|
||||
int sdu_pos; /* next byte to put in sdu */
|
||||
|
||||
/* decoder of current PDU */
|
||||
rlc_pdu_decoder_t dec;
|
||||
int sn;
|
||||
|
||||
int sdu_head_missing;
|
||||
} rlc_um_reassemble_t;
|
||||
|
||||
typedef struct {
|
||||
rlc_entity_t common;
|
||||
|
||||
/* configuration */
|
||||
int t_reordering;
|
||||
int sn_field_length;
|
||||
|
||||
int sn_modulus; /* 1024 for sn_field_length == 10, 32 for 5 */
|
||||
int window_size; /* 512 for sn_field_length == 10, 16 for 5 */
|
||||
|
||||
/* runtime rx */
|
||||
int vr_ur;
|
||||
int vr_ux;
|
||||
int vr_uh;
|
||||
|
||||
/* runtime tx */
|
||||
int vt_us;
|
||||
|
||||
/* set to the latest know time by the user of the module. Unit: ms */
|
||||
uint64_t t_current;
|
||||
|
||||
/* timers (stores the TTI of activation, 0 means not active) */
|
||||
uint64_t t_reordering_start;
|
||||
|
||||
/* rx management */
|
||||
rlc_rx_pdu_segment_t *rx_list;
|
||||
int rx_size;
|
||||
int rx_maxsize;
|
||||
|
||||
/* reassembly management */
|
||||
rlc_um_reassemble_t reassemble;
|
||||
|
||||
/* tx management */
|
||||
rlc_sdu_t *tx_list;
|
||||
rlc_sdu_t *tx_end;
|
||||
int tx_size;
|
||||
int tx_maxsize;
|
||||
} rlc_entity_um_t;
|
||||
|
||||
void rlc_entity_um_recv_sdu(rlc_entity_t *_entity, char *buffer, int size,
|
||||
int sdu_id);
|
||||
void rlc_entity_um_recv_pdu(rlc_entity_t *entity, char *buffer, int size);
|
||||
rlc_entity_buffer_status_t rlc_entity_um_buffer_status(
|
||||
rlc_entity_t *entity, int maxsize);
|
||||
int rlc_entity_um_generate_pdu(rlc_entity_t *_entity, char *buffer, int size);
|
||||
void rlc_entity_um_set_time(rlc_entity_t *entity, uint64_t now);
|
||||
void rlc_entity_um_discard_sdu(rlc_entity_t *entity, int sdu_id);
|
||||
void rlc_entity_um_reestablishment(rlc_entity_t *entity);
|
||||
void rlc_entity_um_delete(rlc_entity_t *entity);
|
||||
|
||||
#endif /* _RLC_ENTITY_UM_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "rlc_pdu.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "LOG/log.h"
|
||||
|
||||
/**************************************************************************/
|
||||
/* RX PDU segment and segment list */
|
||||
/**************************************************************************/
|
||||
|
||||
rlc_rx_pdu_segment_t *rlc_rx_new_pdu_segment(int sn, int so, int size,
|
||||
int is_last, char *data, int data_offset)
|
||||
{
|
||||
rlc_rx_pdu_segment_t *ret = malloc(sizeof(rlc_rx_pdu_segment_t));
|
||||
if (ret == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
ret->sn = sn;
|
||||
ret->so = so;
|
||||
ret->size = size;
|
||||
ret->is_last = is_last;
|
||||
ret->next = NULL;
|
||||
|
||||
ret->data = malloc(size);
|
||||
if (ret->data == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memcpy(ret->data, data, size);
|
||||
|
||||
ret->data_offset = data_offset;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rlc_rx_free_pdu_segment(rlc_rx_pdu_segment_t *pdu_segment)
|
||||
{
|
||||
free(pdu_segment->data);
|
||||
free(pdu_segment);
|
||||
}
|
||||
|
||||
rlc_rx_pdu_segment_t *rlc_rx_pdu_segment_list_add(
|
||||
int (*sn_compare)(void *, int, int), void *sn_compare_data,
|
||||
rlc_rx_pdu_segment_t *list, rlc_rx_pdu_segment_t *pdu_segment)
|
||||
{
|
||||
rlc_rx_pdu_segment_t head;
|
||||
rlc_rx_pdu_segment_t *cur;
|
||||
rlc_rx_pdu_segment_t *prev;
|
||||
|
||||
head.next = list;
|
||||
cur = list;
|
||||
prev = &head;
|
||||
|
||||
/* order is by 'sn', if 'sn' is the same then order is by 'so' */
|
||||
while (cur != NULL) {
|
||||
/* check if 'pdu_segment' is before 'cur' in the list */
|
||||
if (sn_compare(sn_compare_data, cur->sn, pdu_segment->sn) > 0 ||
|
||||
(cur->sn == pdu_segment->sn && cur->so > pdu_segment->so)) {
|
||||
break;
|
||||
}
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
prev->next = pdu_segment;
|
||||
pdu_segment->next = cur;
|
||||
return head.next;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/* TX PDU management */
|
||||
/**************************************************************************/
|
||||
|
||||
rlc_tx_pdu_segment_t *rlc_tx_new_pdu(void)
|
||||
{
|
||||
rlc_tx_pdu_segment_t *ret = calloc(1, sizeof(rlc_tx_pdu_segment_t));
|
||||
if (ret == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
ret->retx_count = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rlc_tx_free_pdu(rlc_tx_pdu_segment_t *pdu)
|
||||
{
|
||||
free(pdu);
|
||||
}
|
||||
|
||||
rlc_tx_pdu_segment_t *rlc_tx_pdu_list_append(rlc_tx_pdu_segment_t *list,
|
||||
rlc_tx_pdu_segment_t *pdu)
|
||||
{
|
||||
rlc_tx_pdu_segment_t head;
|
||||
rlc_tx_pdu_segment_t *cur;
|
||||
|
||||
head.next = list;
|
||||
|
||||
cur = &head;
|
||||
while (cur->next != NULL) {
|
||||
cur = cur->next;
|
||||
}
|
||||
cur->next = pdu;
|
||||
|
||||
return head.next;
|
||||
}
|
||||
|
||||
rlc_tx_pdu_segment_t *rlc_tx_pdu_list_add(
|
||||
int (*sn_compare)(void *, int, int), void *sn_compare_data,
|
||||
rlc_tx_pdu_segment_t *list, rlc_tx_pdu_segment_t *pdu_segment)
|
||||
{
|
||||
rlc_tx_pdu_segment_t head;
|
||||
rlc_tx_pdu_segment_t *cur;
|
||||
rlc_tx_pdu_segment_t *prev;
|
||||
|
||||
head.next = list;
|
||||
cur = list;
|
||||
prev = &head;
|
||||
|
||||
/* order is by 'sn', if 'sn' is the same then order is by 'so' */
|
||||
while (cur != NULL) {
|
||||
/* check if 'pdu_segment' is before 'cur' in the list */
|
||||
if (sn_compare(sn_compare_data, cur->sn, pdu_segment->sn) > 0 ||
|
||||
(cur->sn == pdu_segment->sn && cur->so > pdu_segment->so)) {
|
||||
break;
|
||||
}
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
prev->next = pdu_segment;
|
||||
pdu_segment->next = cur;
|
||||
return head.next;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/* PDU decoder */
|
||||
/**************************************************************************/
|
||||
|
||||
void rlc_pdu_decoder_init(rlc_pdu_decoder_t *decoder, char *buffer, int size)
|
||||
{
|
||||
decoder->error = 0;
|
||||
decoder->byte = 0;
|
||||
decoder->bit = 0;
|
||||
decoder->buffer = buffer;
|
||||
decoder->size = size;
|
||||
}
|
||||
|
||||
static int get_bit(rlc_pdu_decoder_t *decoder)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (decoder->byte >= decoder->size) {
|
||||
decoder->error = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = (decoder->buffer[decoder->byte] >> (7 - decoder->bit)) & 1;
|
||||
|
||||
decoder->bit++;
|
||||
if (decoder->bit == 8) {
|
||||
decoder->bit = 0;
|
||||
decoder->byte++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rlc_pdu_decoder_get_bits(rlc_pdu_decoder_t *decoder, int count)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
if (count > 31) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret <<= 1;
|
||||
ret |= get_bit(decoder);
|
||||
if (decoder->error) return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rlc_pdu_decoder_align(rlc_pdu_decoder_t *decoder)
|
||||
{
|
||||
if (decoder->bit) {
|
||||
decoder->bit = 0;
|
||||
decoder->byte++;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/* PDU encoder */
|
||||
/**************************************************************************/
|
||||
|
||||
void rlc_pdu_encoder_init(rlc_pdu_encoder_t *encoder, char *buffer, int size)
|
||||
{
|
||||
encoder->byte = 0;
|
||||
encoder->bit = 0;
|
||||
encoder->buffer = buffer;
|
||||
encoder->size = size;
|
||||
}
|
||||
|
||||
static void put_bit(rlc_pdu_encoder_t *encoder, int bit)
|
||||
{
|
||||
if (encoder->byte == encoder->size) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal, buffer full\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
encoder->buffer[encoder->byte] <<= 1;
|
||||
if (bit)
|
||||
encoder->buffer[encoder->byte] |= 1;
|
||||
|
||||
encoder->bit++;
|
||||
if (encoder->bit == 8) {
|
||||
encoder->bit = 0;
|
||||
encoder->byte++;
|
||||
}
|
||||
}
|
||||
|
||||
void rlc_pdu_encoder_put_bits(rlc_pdu_encoder_t *encoder, int value, int count)
|
||||
{
|
||||
int i;
|
||||
int x;
|
||||
|
||||
if (count > 31) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
x = 1 << (count - 1);
|
||||
for (i = 0; i < count; i++, x >>= 1)
|
||||
put_bit(encoder, value & x);
|
||||
}
|
||||
|
||||
void rlc_pdu_encoder_align(rlc_pdu_encoder_t *encoder)
|
||||
{
|
||||
while (encoder->bit)
|
||||
put_bit(encoder, 0);
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef _RLC_PDU_H_
|
||||
#define _RLC_PDU_H_
|
||||
|
||||
/**************************************************************************/
|
||||
/* RX PDU segment and segment list */
|
||||
/**************************************************************************/
|
||||
|
||||
typedef struct rlc_rx_pdu_segment_t {
|
||||
int sn;
|
||||
int so;
|
||||
int size;
|
||||
int is_last;
|
||||
char *data;
|
||||
int data_offset;
|
||||
struct rlc_rx_pdu_segment_t *next;
|
||||
} rlc_rx_pdu_segment_t;
|
||||
|
||||
rlc_rx_pdu_segment_t *rlc_rx_new_pdu_segment(int sn, int so, int size,
|
||||
int is_last, char *data, int data_offset);
|
||||
|
||||
void rlc_rx_free_pdu_segment(rlc_rx_pdu_segment_t *pdu_segment);
|
||||
|
||||
rlc_rx_pdu_segment_t *rlc_rx_pdu_segment_list_add(
|
||||
int (*sn_compare)(void *, int, int), void *sn_compare_data,
|
||||
rlc_rx_pdu_segment_t *list, rlc_rx_pdu_segment_t *pdu_segment);
|
||||
|
||||
/**************************************************************************/
|
||||
/* TX PDU management */
|
||||
/**************************************************************************/
|
||||
|
||||
typedef struct rlc_tx_pdu_segment_t {
|
||||
int sn;
|
||||
void *start_sdu; /* real type is rlc_sdu_t * */
|
||||
int sdu_start_byte; /* starting byte in 'start_sdu' */
|
||||
int so; /* starting byte of the segment in full PDU */
|
||||
int data_size; /* number of data bytes (exclude header) */
|
||||
int is_segment;
|
||||
int is_last;
|
||||
int retx_count;
|
||||
struct rlc_tx_pdu_segment_t *next;
|
||||
} rlc_tx_pdu_segment_t;
|
||||
|
||||
rlc_tx_pdu_segment_t *rlc_tx_new_pdu(void);
|
||||
void rlc_tx_free_pdu(rlc_tx_pdu_segment_t *pdu);
|
||||
rlc_tx_pdu_segment_t *rlc_tx_pdu_list_append(rlc_tx_pdu_segment_t *list,
|
||||
rlc_tx_pdu_segment_t *pdu);
|
||||
rlc_tx_pdu_segment_t *rlc_tx_pdu_list_add(
|
||||
int (*sn_compare)(void *, int, int), void *sn_compare_data,
|
||||
rlc_tx_pdu_segment_t *list, rlc_tx_pdu_segment_t *pdu_segment);
|
||||
|
||||
/**************************************************************************/
|
||||
/* PDU decoder */
|
||||
/**************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
int error;
|
||||
int byte; /* next byte to decode */
|
||||
int bit; /* next bit in next byte to decode */
|
||||
char *buffer;
|
||||
int size;
|
||||
} rlc_pdu_decoder_t;
|
||||
|
||||
void rlc_pdu_decoder_init(rlc_pdu_decoder_t *decoder, char *buffer, int size);
|
||||
|
||||
#define rlc_pdu_decoder_in_error(d) ((d)->error == 1)
|
||||
|
||||
int rlc_pdu_decoder_get_bits(rlc_pdu_decoder_t *decoder, int count);
|
||||
|
||||
void rlc_pdu_decoder_align(rlc_pdu_decoder_t *decoder);
|
||||
|
||||
/**************************************************************************/
|
||||
/* PDU encoder */
|
||||
/**************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
int byte; /* next byte to encode */
|
||||
int bit; /* next bit in next byte to encode */
|
||||
char *buffer;
|
||||
int size;
|
||||
} rlc_pdu_encoder_t;
|
||||
|
||||
void rlc_pdu_encoder_init(rlc_pdu_encoder_t *encoder, char *buffer, int size);
|
||||
|
||||
void rlc_pdu_encoder_put_bits(rlc_pdu_encoder_t *encoder, int value, int count);
|
||||
|
||||
void rlc_pdu_encoder_align(rlc_pdu_encoder_t *encoder);
|
||||
|
||||
#endif /* _RLC_PDU_H_ */
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "rlc_sdu.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "LOG/log.h"
|
||||
|
||||
rlc_sdu_t *rlc_new_sdu(char *buffer, int size, int upper_layer_id)
|
||||
{
|
||||
rlc_sdu_t *ret = calloc(1, sizeof(rlc_sdu_t));
|
||||
if (ret == NULL)
|
||||
goto oom;
|
||||
|
||||
ret->upper_layer_id = upper_layer_id;
|
||||
|
||||
ret->data = malloc(size);
|
||||
if (ret->data == NULL)
|
||||
goto oom;
|
||||
|
||||
memcpy(ret->data, buffer, size);
|
||||
|
||||
ret->size = size;
|
||||
|
||||
return ret;
|
||||
|
||||
oom:
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void rlc_free_sdu(rlc_sdu_t *sdu)
|
||||
{
|
||||
free(sdu->data);
|
||||
free(sdu);
|
||||
}
|
||||
|
||||
void rlc_sdu_list_add(rlc_sdu_t **list, rlc_sdu_t **end, rlc_sdu_t *sdu)
|
||||
{
|
||||
if (*list == NULL) {
|
||||
*list = sdu;
|
||||
*end = sdu;
|
||||
return;
|
||||
}
|
||||
|
||||
(*end)->next = sdu;
|
||||
*end = sdu;
|
||||
}
|
||||
@@ -19,20 +19,21 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/***************************************************************************
|
||||
mem_pool.h - description
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
#ifndef _RLC_SDU_H_
|
||||
#define _RLC_SDU_H_
|
||||
|
||||
typedef struct rlc_sdu_t {
|
||||
int upper_layer_id;
|
||||
char *data;
|
||||
int size;
|
||||
/* next_byte indicates the starting byte to use to construct a new PDU */
|
||||
int next_byte;
|
||||
int acked_bytes;
|
||||
struct rlc_sdu_t *next;
|
||||
} rlc_sdu_t;
|
||||
|
||||
***************************************************************************/
|
||||
#ifndef __MEM_POOL_H__
|
||||
# define __MEM_POOL_H__
|
||||
rlc_sdu_t *rlc_new_sdu(char *buffer, int size, int upper_layer_id);
|
||||
void rlc_free_sdu(rlc_sdu_t *sdu);
|
||||
void rlc_sdu_list_add(rlc_sdu_t **list, rlc_sdu_t **end, rlc_sdu_t *sdu);
|
||||
|
||||
# include "list.h"
|
||||
# include "mem_block.h"
|
||||
|
||||
|
||||
#endif
|
||||
#endif /* _RLC_SDU_H_ */
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "rlc_ue_manager.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "LOG/log.h"
|
||||
|
||||
typedef struct {
|
||||
pthread_mutex_t lock;
|
||||
rlc_ue_t **ue_list;
|
||||
int ue_count;
|
||||
int enb_flag;
|
||||
} rlc_ue_manager_internal_t;
|
||||
|
||||
rlc_ue_manager_t *new_rlc_ue_manager(int enb_flag)
|
||||
{
|
||||
rlc_ue_manager_internal_t *ret;
|
||||
|
||||
ret = calloc(1, sizeof(rlc_ue_manager_internal_t));
|
||||
if (ret == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pthread_mutex_init(&ret->lock, NULL)) abort();
|
||||
ret->enb_flag = enb_flag;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rlc_manager_get_enb_flag(rlc_ue_manager_t *_m)
|
||||
{
|
||||
rlc_ue_manager_internal_t *m = _m;
|
||||
return m->enb_flag;
|
||||
}
|
||||
|
||||
void rlc_manager_lock(rlc_ue_manager_t *_m)
|
||||
{
|
||||
rlc_ue_manager_internal_t *m = _m;
|
||||
if (pthread_mutex_lock(&m->lock)) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void rlc_manager_unlock(rlc_ue_manager_t *_m)
|
||||
{
|
||||
rlc_ue_manager_internal_t *m = _m;
|
||||
if (pthread_mutex_unlock(&m->lock)) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* must be called with lock acquired */
|
||||
rlc_ue_t *rlc_manager_get_ue(rlc_ue_manager_t *_m, int rnti)
|
||||
{
|
||||
/* TODO: optimze */
|
||||
rlc_ue_manager_internal_t *m = _m;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < m->ue_count; i++)
|
||||
if (m->ue_list[i]->rnti == rnti)
|
||||
return m->ue_list[i];
|
||||
|
||||
LOG_D(RLC, "%s:%d:%s: new UE %d\n", __FILE__, __LINE__, __FUNCTION__, rnti);
|
||||
|
||||
m->ue_count++;
|
||||
m->ue_list = realloc(m->ue_list, sizeof(rlc_ue_t *) * m->ue_count);
|
||||
if (m->ue_list == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
m->ue_list[m->ue_count-1] = calloc(1, sizeof(rlc_ue_t));
|
||||
if (m->ue_list[m->ue_count-1] == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
m->ue_list[m->ue_count-1]->rnti = rnti;
|
||||
|
||||
return m->ue_list[m->ue_count-1];
|
||||
}
|
||||
|
||||
/* must be called with lock acquired */
|
||||
void rlc_manager_remove_ue(rlc_ue_manager_t *_m, int rnti)
|
||||
{
|
||||
rlc_ue_manager_internal_t *m = _m;
|
||||
rlc_ue_t *ue;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (i = 0; i < m->ue_count; i++)
|
||||
if (m->ue_list[i]->rnti == rnti)
|
||||
break;
|
||||
|
||||
if (i == m->ue_count) {
|
||||
LOG_D(RLC, "%s:%d:%s: warning: ue %d not found\n",
|
||||
__FILE__, __LINE__, __FUNCTION__,
|
||||
rnti);
|
||||
return;
|
||||
}
|
||||
|
||||
ue = m->ue_list[i];
|
||||
|
||||
for (j = 0; j < 2; j++)
|
||||
if (ue->srb[j] != NULL)
|
||||
ue->srb[j]->delete(ue->srb[j]);
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
if (ue->drb[j] != NULL)
|
||||
ue->drb[j]->delete(ue->drb[j]);
|
||||
|
||||
free(ue);
|
||||
|
||||
m->ue_count--;
|
||||
if (m->ue_count == 0) {
|
||||
free(m->ue_list);
|
||||
m->ue_list = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
memmove(&m->ue_list[i], &m->ue_list[i+1],
|
||||
(m->ue_count - i) * sizeof(rlc_ue_t *));
|
||||
m->ue_list = realloc(m->ue_list, m->ue_count * sizeof(rlc_ue_t *));
|
||||
if (m->ue_list == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* must be called with lock acquired */
|
||||
void rlc_ue_add_srb_rlc_entity(rlc_ue_t *ue, int srb_id, rlc_entity_t *entity)
|
||||
{
|
||||
if (srb_id < 1 || srb_id > 2) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal, bad srb id\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
srb_id--;
|
||||
|
||||
if (ue->srb[srb_id] != NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal, srb already present\n",
|
||||
__FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ue->srb[srb_id] = entity;
|
||||
}
|
||||
|
||||
/* must be called with lock acquired */
|
||||
void rlc_ue_add_drb_rlc_entity(rlc_ue_t *ue, int drb_id, rlc_entity_t *entity)
|
||||
{
|
||||
if (drb_id < 1 || drb_id > 5) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal, bad drb id\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
drb_id--;
|
||||
|
||||
if (ue->drb[drb_id] != NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal, drb already present\n",
|
||||
__FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ue->drb[drb_id] = entity;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef _RLC_UE_MANAGER_H_
|
||||
#define _RLC_UE_MANAGER_H_
|
||||
|
||||
#include "rlc_entity.h"
|
||||
|
||||
typedef void rlc_ue_manager_t;
|
||||
|
||||
typedef struct rlc_ue_t {
|
||||
int rnti;
|
||||
int module_id; /* necesarry for the L2 simulator - not clean, to revise */
|
||||
rlc_entity_t *srb[2];
|
||||
rlc_entity_t *drb[5];
|
||||
} rlc_ue_t;
|
||||
|
||||
/***********************************************************************/
|
||||
/* manager functions */
|
||||
/***********************************************************************/
|
||||
|
||||
rlc_ue_manager_t *new_rlc_ue_manager(int enb_flag);
|
||||
|
||||
int rlc_manager_get_enb_flag(rlc_ue_manager_t *m);
|
||||
|
||||
void rlc_manager_lock(rlc_ue_manager_t *m);
|
||||
void rlc_manager_unlock(rlc_ue_manager_t *m);
|
||||
|
||||
rlc_ue_t *rlc_manager_get_ue(rlc_ue_manager_t *m, int rnti);
|
||||
void rlc_manager_remove_ue(rlc_ue_manager_t *m, int rnti);
|
||||
|
||||
/***********************************************************************/
|
||||
/* ue functions */
|
||||
/***********************************************************************/
|
||||
|
||||
void rlc_ue_add_srb_rlc_entity(rlc_ue_t *ue, int srb_id, rlc_entity_t *entity);
|
||||
void rlc_ue_add_drb_rlc_entity(rlc_ue_t *ue, int drb_id, rlc_entity_t *entity);
|
||||
|
||||
#endif /* _RLC_UE_MANAGER_H_ */
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef _LOG_H_
|
||||
#define _LOG_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define LOG_E(x, ...) printf(__VA_ARGS__)
|
||||
#define LOG_D(x, ...) printf(__VA_ARGS__)
|
||||
#define LOG_W(x, ...) printf(__VA_ARGS__)
|
||||
|
||||
#endif /* _LOG_H_ */
|
||||
@@ -0,0 +1,32 @@
|
||||
CC=gcc
|
||||
CFLAGS=-Wall -g --coverage -I.
|
||||
|
||||
LIB=rlc_entity.o rlc_entity_am.o rlc_entity_um.o rlc_pdu.o rlc_sdu.o
|
||||
|
||||
tests:
|
||||
@./run_tests.sh
|
||||
|
||||
all: clean_run $(TEST).run
|
||||
|
||||
%.run: $(TEST).bin
|
||||
#valgrind ./$(TEST).bin > $(TEST).run_pre 2> $(TEST).valgrind
|
||||
./$(TEST).bin > $(TEST).run_pre
|
||||
grep ^TEST $(TEST).run_pre > $(TEST).run
|
||||
gunzip -c $(TEST).txt.gz > $(TEST).txt
|
||||
diff -q $(TEST).txt $(TEST).run
|
||||
|
||||
$(TEST).bin: $(TEST).o $(LIB)
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
%.o: ../%.c
|
||||
$(CC) $(CFLAGS) -I.. -c -o $@ $<
|
||||
|
||||
$(TEST).o: test.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $< -DTEST='"$(TEST).h"'
|
||||
|
||||
clean_run:
|
||||
rm -f $(TEST).run $(TEST).bin $(TEST).o
|
||||
|
||||
clean:
|
||||
rm -f *.o *.bin *.run *.run_pre *.gcov *.gcda *.gcno test*.txt a.out \
|
||||
*.valgrind
|
||||
@@ -0,0 +1,38 @@
|
||||
To run tests, simply type: make
|
||||
|
||||
Each test is made of:
|
||||
testXX.h definition of the test
|
||||
testXX.txt.gz compressed expected output of the test
|
||||
|
||||
At runtime, we generate:
|
||||
testXX.run actual output of the test
|
||||
|
||||
test.c is the test driving program.
|
||||
|
||||
Only the output lines of the test program starting with "TEST" are
|
||||
stored into testXX.txt and testXX.run.
|
||||
|
||||
A test is considered a success if testXX.txt and testXX.run are equal.
|
||||
|
||||
Only failed tests are reported.
|
||||
|
||||
How to define a new test?
|
||||
|
||||
1 - get the ID
|
||||
|
||||
Look in the file run_tests.sh, the variable test_count gives you
|
||||
the number of existing tests. The ID of your test has to be
|
||||
test_count + 1.
|
||||
|
||||
2 - create files
|
||||
|
||||
Create the file test<ID>.h containing the test, then generate test<ID>.run
|
||||
by running 'make all TEST=test<ID>' and copy test<ID>.run to test<ID>.txt.
|
||||
Then compress this file (gzip -9 test<ID>.txt). Be sure that the output
|
||||
is correct, of course.
|
||||
|
||||
For the file names, replace <ID> by the actual number of the test.
|
||||
For example, if your test ID is 47, then name the files test47.h and
|
||||
test47.txt. And run 'make all TEST=test47' to generate test47.run.
|
||||
|
||||
The available instructions for a test are described at the top of test.c.
|
||||
@@ -0,0 +1,29 @@
|
||||
/* gcc -Wall make_pdu.c -I.. ../rlc_pdu.c */
|
||||
|
||||
#include "rlc_pdu.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char out[100];
|
||||
rlc_pdu_encoder_t e;
|
||||
int i;
|
||||
|
||||
rlc_pdu_encoder_init(&e, out, 100);
|
||||
|
||||
rlc_pdu_encoder_put_bits(&e, 0, 1); // D/C
|
||||
rlc_pdu_encoder_put_bits(&e, 0, 3); // CPT
|
||||
rlc_pdu_encoder_put_bits(&e, 0, 10); // ack_sn
|
||||
rlc_pdu_encoder_put_bits(&e, 1, 1); // e1
|
||||
rlc_pdu_encoder_put_bits(&e, 10, 10); // nack_sn
|
||||
rlc_pdu_encoder_put_bits(&e, 0, 1); // e1
|
||||
rlc_pdu_encoder_put_bits(&e, 0, 1); // e2
|
||||
|
||||
rlc_pdu_encoder_align(&e);
|
||||
|
||||
for (i = 0; i < e.byte; i++) printf(" %2.2x", (unsigned char)e.buffer[i]);
|
||||
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_count=45
|
||||
|
||||
for i in `seq $test_count`
|
||||
do
|
||||
make all TEST=test$i >/dev/null 2>/dev/null
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
echo TEST $i FAILURE
|
||||
fi
|
||||
done
|
||||
@@ -0,0 +1,433 @@
|
||||
#include "../rlc_entity.h"
|
||||
#include "../rlc_entity_am.h"
|
||||
#include "../rlc_entity_um.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* ENB_AM <rx_maxsize> <tx_maxsize> <t_reordering> <t_status_prohibit>
|
||||
* <t_poll_retransmit> <poll_pdu> <poll_byte> <max_retx_threshold>
|
||||
* create the eNB RLC AM entity with given parameters
|
||||
*
|
||||
* UE_AM <rx_maxsize> <tx_maxsize> <t_reordering> <t_status_prohibit>
|
||||
* <t_poll_retransmit> <poll_pdu> <poll_byte> <max_retx_threshold>
|
||||
* create the UE RLC AM entity with given parameters
|
||||
*
|
||||
* ENB_UM <rx_maxsize> <tx_maxsize> <t_reordering> <sn_field_length>
|
||||
* create the eNB RLC UM entity with given parameters
|
||||
*
|
||||
* UE_UM <rx_maxsize> <tx_maxsize> <t_reordering> <sn_field_length>
|
||||
* create the UE RLC UM entity with given parameters
|
||||
*
|
||||
* TIME <time>
|
||||
* following actions to be performed at time <time>
|
||||
* <time> starts at 1
|
||||
* You must end your test definition with a line 'TIME, -1'.
|
||||
*
|
||||
* ENB_SDU <id> <size>
|
||||
* send an SDU to eNB with id <i> and size <size>
|
||||
* the SDU is [00 01 ... ff 01 ...]
|
||||
* (ie. start byte is 00 then we increment for each byte, loop if needed)
|
||||
*
|
||||
* UE_SDU <id> <size>
|
||||
* same as ENB_SDU but the SDU is sent to the UE
|
||||
*
|
||||
* ENB_PDU <size> <'size' bytes>
|
||||
* send a custom PDU from eNB to UE (eNB does not see this PDU at all)
|
||||
*
|
||||
* UE_PDU <size> <'size' bytes>
|
||||
* send a custom PDU from UE to eNB (UE does not see this PDU at all)
|
||||
*
|
||||
* ENB_PDU_SIZE <size>
|
||||
* set 'enb_pdu_size'
|
||||
*
|
||||
* UE_PDU_SIZE <size>
|
||||
* set 'ue_pdu_size'
|
||||
*
|
||||
* ENB_RECV_FAILS <fails>
|
||||
* set the 'enb_recv_fails' flag to <fails>
|
||||
* (1: recv will fail, 0: recv will succeed)
|
||||
*
|
||||
* UE_RECV_FAILS <fails>
|
||||
* same as ENB_RECV_FAILS but for 'ue_recv_fails'
|
||||
*
|
||||
* MUST_FAIL
|
||||
* to be used as first command after the first TIME to indicate
|
||||
* that the test must fail (ie. exit with non zero, crash not allowed)
|
||||
*
|
||||
* ENB_BUFFER_STATUS
|
||||
* call buffer_status for eNB and print result
|
||||
*
|
||||
* UE_BUFFER_STATUS
|
||||
* call buffer_status for UE and print result
|
||||
*
|
||||
* ENB_DISCARD_SDU <sdu ID>
|
||||
* discards given SDU
|
||||
*
|
||||
* UE_DISCARD_SDU <sdu ID>
|
||||
* discards given SDU
|
||||
*
|
||||
* RE_ESTABLISH
|
||||
* re-establish both eNB and UE
|
||||
*/
|
||||
|
||||
enum action {
|
||||
ENB_AM, UE_AM,
|
||||
ENB_UM, UE_UM,
|
||||
TIME, ENB_SDU, UE_SDU, ENB_PDU, UE_PDU,
|
||||
ENB_PDU_SIZE, UE_PDU_SIZE,
|
||||
ENB_RECV_FAILS, UE_RECV_FAILS,
|
||||
MUST_FAIL,
|
||||
ENB_BUFFER_STATUS, UE_BUFFER_STATUS,
|
||||
ENB_DISCARD_SDU, UE_DISCARD_SDU,
|
||||
RE_ESTABLISH
|
||||
};
|
||||
|
||||
int test[] = {
|
||||
/* TEST is defined at compilation time */
|
||||
#include TEST
|
||||
};
|
||||
|
||||
void deliver_sdu_enb_am(void *deliver_sdu_data, struct rlc_entity_t *_entity,
|
||||
char *buf, int size)
|
||||
{
|
||||
rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity;
|
||||
printf("TEST: ENB: %"PRIu64": deliver SDU size %d [",
|
||||
entity->t_current, size);
|
||||
for (int i = 0; i < size; i++) printf(" %2.2x", (unsigned char)buf[i]);
|
||||
printf("]\n");
|
||||
}
|
||||
|
||||
void deliver_sdu_enb_um(void *deliver_sdu_data, struct rlc_entity_t *_entity,
|
||||
char *buf, int size)
|
||||
{
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
printf("TEST: ENB: %"PRIu64": deliver SDU size %d [",
|
||||
entity->t_current, size);
|
||||
for (int i = 0; i < size; i++) printf(" %2.2x", (unsigned char)buf[i]);
|
||||
printf("]\n");
|
||||
}
|
||||
|
||||
void successful_delivery_enb(void *successful_delivery_data,
|
||||
rlc_entity_t *_entity, int sdu_id)
|
||||
{
|
||||
rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity;
|
||||
printf("TEST: ENB: %"PRIu64": SDU %d was successfully delivered.\n",
|
||||
entity->t_current, sdu_id);
|
||||
}
|
||||
|
||||
void max_retx_reached_enb(void *max_retx_reached_data, rlc_entity_t *_entity)
|
||||
{
|
||||
rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity;
|
||||
printf("TEST: ENB: %"PRIu64": max RETX reached! radio link failure!\n",
|
||||
entity->t_current);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void deliver_sdu_ue_am(void *deliver_sdu_data, struct rlc_entity_t *_entity,
|
||||
char *buf, int size)
|
||||
{
|
||||
rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity;
|
||||
printf("TEST: UE: %"PRIu64": deliver SDU size %d [",
|
||||
entity->t_current, size);
|
||||
for (int i = 0; i < size; i++) printf(" %2.2x", (unsigned char)buf[i]);
|
||||
printf("]\n");
|
||||
}
|
||||
|
||||
void deliver_sdu_ue_um(void *deliver_sdu_data, struct rlc_entity_t *_entity,
|
||||
char *buf, int size)
|
||||
{
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
printf("TEST: UE: %"PRIu64": deliver SDU size %d [",
|
||||
entity->t_current, size);
|
||||
for (int i = 0; i < size; i++) printf(" %2.2x", (unsigned char)buf[i]);
|
||||
printf("]\n");
|
||||
}
|
||||
|
||||
void successful_delivery_ue(void *successful_delivery_data,
|
||||
rlc_entity_t *_entity, int sdu_id)
|
||||
{
|
||||
rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity;
|
||||
printf("TEST: UE: %"PRIu64": SDU %d was successfully delivered.\n",
|
||||
entity->t_current, sdu_id);
|
||||
}
|
||||
|
||||
void max_retx_reached_ue(void *max_retx_reached_data, rlc_entity_t *_entity)
|
||||
{
|
||||
rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity;
|
||||
printf("TEST: UE: %"PRIu64", max RETX reached! radio link failure!\n",
|
||||
entity->t_current);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int test_main(void)
|
||||
{
|
||||
rlc_entity_t *enb = NULL;
|
||||
rlc_entity_t *ue = NULL;
|
||||
int i;
|
||||
int k;
|
||||
char *sdu;
|
||||
char *pdu;
|
||||
rlc_entity_buffer_status_t buffer_status;
|
||||
int enb_do_buffer_status = 0;
|
||||
int ue_do_buffer_status = 0;
|
||||
int size;
|
||||
int pos;
|
||||
int next_byte_enb = 0;
|
||||
int next_byte_ue = 0;
|
||||
int enb_recv_fails = 0;
|
||||
int ue_recv_fails = 0;
|
||||
int enb_pdu_size = 1000;
|
||||
int ue_pdu_size = 1000;
|
||||
|
||||
sdu = malloc(16001);
|
||||
pdu = malloc(3000);
|
||||
if (sdu == NULL || pdu == NULL) {
|
||||
printf("out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < 16001; i++)
|
||||
sdu[i] = i & 255;
|
||||
|
||||
pos = 0;
|
||||
if (test[pos] != TIME) {
|
||||
printf("%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 1; i < 1000; i++) {
|
||||
if (i == test[pos+1]) {
|
||||
pos += 2;
|
||||
while (test[pos] != TIME)
|
||||
switch (test[pos]) {
|
||||
default: printf("fatal: unknown action\n"); exit(1);
|
||||
case ENB_AM:
|
||||
enb = new_rlc_entity_am(test[pos+1], test[pos+2],
|
||||
deliver_sdu_enb_am, NULL,
|
||||
successful_delivery_enb, NULL,
|
||||
max_retx_reached_enb, NULL,
|
||||
test[pos+3], test[pos+4], test[pos+5],
|
||||
test[pos+6], test[pos+7], test[pos+8]);
|
||||
pos += 9;
|
||||
break;
|
||||
case UE_AM:
|
||||
ue = new_rlc_entity_am(test[pos+1], test[pos+2],
|
||||
deliver_sdu_ue_am, NULL,
|
||||
successful_delivery_ue, NULL,
|
||||
max_retx_reached_ue, NULL,
|
||||
test[pos+3], test[pos+4], test[pos+5],
|
||||
test[pos+6], test[pos+7], test[pos+8]);
|
||||
pos += 9;
|
||||
break;
|
||||
case ENB_UM:
|
||||
enb = new_rlc_entity_um(test[pos+1], test[pos+2],
|
||||
deliver_sdu_enb_um, NULL,
|
||||
test[pos+3], test[pos+4]);
|
||||
pos += 5;
|
||||
break;
|
||||
case UE_UM:
|
||||
ue = new_rlc_entity_um(test[pos+1], test[pos+2],
|
||||
deliver_sdu_ue_um, NULL,
|
||||
test[pos+3], test[pos+4]);
|
||||
pos += 5;
|
||||
break;
|
||||
case ENB_SDU:
|
||||
for (k = 0; k < test[pos+2]; k++, next_byte_enb++)
|
||||
sdu[k] = next_byte_enb;
|
||||
printf("TEST: ENB: %d: recv_sdu (id %d): size %d: [",
|
||||
i, test[pos+1], test[pos+2]);
|
||||
for (k = 0; k < test[pos+2]; k++)
|
||||
printf(" %2.2x", (unsigned char)sdu[k]);
|
||||
printf("]\n");
|
||||
enb->recv_sdu(enb, sdu, test[pos+2], test[pos+1]);
|
||||
pos += 3;
|
||||
break;
|
||||
case UE_SDU:
|
||||
for (k = 0; k < test[pos+2]; k++, next_byte_ue++)
|
||||
sdu[k] = next_byte_ue;
|
||||
printf("TEST: UE: %d: recv_sdu (id %d): size %d: [",
|
||||
i, test[pos+1], test[pos+2]);
|
||||
for (k = 0; k < test[pos+2]; k++)
|
||||
printf(" %2.2x", (unsigned char)sdu[k]);
|
||||
printf("]\n");
|
||||
ue->recv_sdu(ue, sdu, test[pos+2], test[pos+1]);
|
||||
pos += 3;
|
||||
break;
|
||||
case ENB_PDU:
|
||||
for (k = 0; k < test[pos+1]; k++)
|
||||
pdu[k] = test[pos+2+k];
|
||||
printf("TEST: ENB: %d: custom PDU: size %d: [", i, test[pos+1]);
|
||||
for (k = 0; k < test[pos+1]; k++) printf(" %2.2x", (unsigned char)pdu[k]);
|
||||
printf("]\n");
|
||||
if (!ue_recv_fails)
|
||||
ue->recv_pdu(ue, pdu, test[pos+1]);
|
||||
pos += 2 + test[pos+1];
|
||||
break;
|
||||
case UE_PDU:
|
||||
for (k = 0; k < test[pos+1]; k++)
|
||||
pdu[k] = test[pos+2+k];
|
||||
printf("TEST: UE: %d: custom PDU: size %d: [", i, test[pos+1]);
|
||||
for (k = 0; k < test[pos+1]; k++) printf(" %2.2x", (unsigned char)pdu[k]);
|
||||
printf("]\n");
|
||||
if (!enb_recv_fails)
|
||||
enb->recv_pdu(enb, pdu, test[pos+1]);
|
||||
pos += 2 + test[pos+1];
|
||||
break;
|
||||
case ENB_PDU_SIZE:
|
||||
enb_pdu_size = test[pos+1];
|
||||
pos += 2;
|
||||
break;
|
||||
case UE_PDU_SIZE:
|
||||
ue_pdu_size = test[pos+1];
|
||||
pos += 2;
|
||||
break;
|
||||
case ENB_RECV_FAILS:
|
||||
enb_recv_fails = test[pos+1];
|
||||
pos += 2;
|
||||
break;
|
||||
case UE_RECV_FAILS:
|
||||
ue_recv_fails = test[pos+1];
|
||||
pos += 2;
|
||||
break;
|
||||
case MUST_FAIL:
|
||||
/* do nothing, only used by caller */
|
||||
pos++;
|
||||
break;
|
||||
case ENB_BUFFER_STATUS:
|
||||
enb_do_buffer_status = 1;
|
||||
pos++;
|
||||
break;
|
||||
case UE_BUFFER_STATUS:
|
||||
ue_do_buffer_status = 1;
|
||||
pos++;
|
||||
break;
|
||||
case ENB_DISCARD_SDU:
|
||||
printf("TEST: ENB: %d: discard SDU %d\n", i, test[pos+1]);
|
||||
enb->discard_sdu(enb, test[pos+1]);
|
||||
pos += 2;
|
||||
break;
|
||||
case UE_DISCARD_SDU:
|
||||
printf("TEST: UE: %d: discard SDU %d\n", i, test[pos+1]);
|
||||
ue->discard_sdu(ue, test[pos+1]);
|
||||
pos += 2;
|
||||
break;
|
||||
case RE_ESTABLISH:
|
||||
printf("TEST: %d: re-establish eNB and UE\n", i);
|
||||
enb->reestablishment(enb);
|
||||
ue->reestablishment(ue);
|
||||
pos++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
enb->set_time(enb, i);
|
||||
ue->set_time(ue, i);
|
||||
|
||||
if (enb_do_buffer_status) {
|
||||
enb_do_buffer_status = 0;
|
||||
buffer_status = enb->buffer_status(enb, enb_pdu_size);
|
||||
printf("TEST: ENB: %d: buffer_status: status_size %d tx_size %d retx_size %d\n",
|
||||
i,
|
||||
buffer_status.status_size,
|
||||
buffer_status.tx_size,
|
||||
buffer_status.retx_size);
|
||||
}
|
||||
|
||||
size = enb->generate_pdu(enb, pdu, enb_pdu_size);
|
||||
if (size) {
|
||||
printf("TEST: ENB: %d: generate_pdu: size %d: [", i, size);
|
||||
for (k = 0; k < size; k++) printf(" %2.2x", (unsigned char)pdu[k]);
|
||||
printf("]\n");
|
||||
if (!ue_recv_fails)
|
||||
ue->recv_pdu(ue, pdu, size);
|
||||
}
|
||||
|
||||
if (ue_do_buffer_status) {
|
||||
ue_do_buffer_status = 0;
|
||||
buffer_status = ue->buffer_status(ue, ue_pdu_size);
|
||||
printf("TEST: UE: %d: buffer_status: status_size %d tx_size %d retx_size %d\n",
|
||||
i,
|
||||
buffer_status.status_size,
|
||||
buffer_status.tx_size,
|
||||
buffer_status.retx_size);
|
||||
}
|
||||
|
||||
size = ue->generate_pdu(ue, pdu, ue_pdu_size);
|
||||
if (size) {
|
||||
printf("TEST: UE: %d: generate_pdu: size %d: [", i, size);
|
||||
for (k = 0; k < size; k++) printf(" %2.2x", (unsigned char)pdu[k]);
|
||||
printf("]\n");
|
||||
if (!enb_recv_fails)
|
||||
enb->recv_pdu(enb, pdu, size);
|
||||
}
|
||||
}
|
||||
|
||||
enb->delete(enb);
|
||||
ue->delete(ue);
|
||||
|
||||
free(sdu);
|
||||
free(pdu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf("options:\n");
|
||||
printf(" -no-fork\n");
|
||||
printf(" don't fork (to ease debugging with gdb)\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int n, char **v)
|
||||
{
|
||||
int must_fail = 0;
|
||||
int son;
|
||||
int status;
|
||||
int i;
|
||||
int no_fork = 0;
|
||||
|
||||
for (i = 1; i < n; i++) {
|
||||
if (!strcmp(v[i], "-no-fork")) { no_fork = 1; continue; }
|
||||
usage();
|
||||
}
|
||||
|
||||
if (test[2] == MUST_FAIL)
|
||||
must_fail = 1;
|
||||
|
||||
if (no_fork) return test_main();
|
||||
|
||||
son = fork();
|
||||
if (son == -1) {
|
||||
perror("fork");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (son == 0)
|
||||
return test_main();
|
||||
|
||||
if (wait(&status) == -1) {
|
||||
perror("wait");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* child must quit properly */
|
||||
if (!WIFEXITED(status))
|
||||
return 1;
|
||||
|
||||
/* child must fail if expected to */
|
||||
if (must_fail && WEXITSTATUS(status) == 0)
|
||||
return 1;
|
||||
|
||||
/* child must not fail if not expected to */
|
||||
if (!must_fail && WEXITSTATUS(status))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* basic am test:
|
||||
* at time 1, eNB receives an SDU of 10 bytes
|
||||
* at time 10, UE receives an SDU of 5 bytes
|
||||
*/
|
||||
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 10,
|
||||
UE_BUFFER_STATUS,
|
||||
TIME, 10,
|
||||
UE_SDU, 0, 5,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* rlc am test resegmentation of PDU segment with several SDUs
|
||||
* eNB sends 3 SDUs [1..10] [11.20] [21..30], not received
|
||||
* eNB retx with smaller PDUs, not received
|
||||
* eNB retx with still smaller PDUs, not received
|
||||
* then reception on, all passes
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_RECV_FAILS, 1,
|
||||
ENB_RECV_FAILS, 1,
|
||||
ENB_SDU, 0, 10,
|
||||
ENB_SDU, 1, 10,
|
||||
ENB_SDU, 2, 10,
|
||||
TIME, 2,
|
||||
ENB_PDU_SIZE, 25,
|
||||
TIME, 48,
|
||||
ENB_PDU_SIZE, 15,
|
||||
TIME, 100,
|
||||
UE_RECV_FAILS, 0,
|
||||
ENB_RECV_FAILS, 0,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* rlc am test function rlc_am_reassemble_next_segment
|
||||
* in r->pdu_byte >= r->so + (r->sdu_offset - r->start->data_offset)
|
||||
* + r->sdu_len
|
||||
* when case 'if (r->e)' is false
|
||||
* eNB sends 3 SDUs [1..10] [11.20] [21..30], not received
|
||||
* eNB retx with smaller PDUs, not received
|
||||
* eNB retx with still smaller PDUs, not received
|
||||
* then UE reception on
|
||||
* then custom PDUs, first a small part of head of original PDU
|
||||
* then a bigger part, covering the first part
|
||||
* so that the beginning of this part triggers the 'while'
|
||||
* then eNB reception on, all passes
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_RECV_FAILS, 1,
|
||||
ENB_RECV_FAILS, 1,
|
||||
ENB_SDU, 0, 10,
|
||||
ENB_SDU, 1, 10,
|
||||
ENB_SDU, 2, 10,
|
||||
TIME, 2,
|
||||
ENB_PDU_SIZE, 25,
|
||||
TIME, 48,
|
||||
ENB_PDU_SIZE, 15,
|
||||
TIME, 95,
|
||||
ENB_BUFFER_STATUS,
|
||||
TIME, 99,
|
||||
UE_RECV_FAILS, 0,
|
||||
ENB_PDU, 14, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
|
||||
ENB_PDU, 25, 0xec, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
|
||||
TIME, 100,
|
||||
ENB_RECV_FAILS, 0,
|
||||
TIME, 134,
|
||||
UE_BUFFER_STATUS,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* rlc am test function rlc_am_reassemble_next_segment
|
||||
* in r->pdu_byte >= r->so + (r->sdu_offset - r->start->data_offset)
|
||||
* + r->sdu_len
|
||||
* when case 'if (r->e)' is true
|
||||
* eNB sends 4 SDUs [1..5] [6..10] [11.20] [21..30], not received
|
||||
* eNB retx with smaller PDUs, not received
|
||||
* eNB retx with still smaller PDUs, not received
|
||||
* then UE reception on
|
||||
* then custom PDUs, first a small part of head of original PDU
|
||||
* then a bigger part, covering the first part
|
||||
* so that the beginning of this part triggers the 'while'
|
||||
* then eNB reception on, all passes
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_RECV_FAILS, 1,
|
||||
ENB_RECV_FAILS, 1,
|
||||
ENB_SDU, 0, 5,
|
||||
ENB_SDU, 1, 5,
|
||||
ENB_SDU, 2, 10,
|
||||
ENB_SDU, 3, 10,
|
||||
TIME, 2,
|
||||
ENB_PDU_SIZE, 25,
|
||||
TIME, 48,
|
||||
ENB_PDU_SIZE, 15,
|
||||
TIME, 99,
|
||||
UE_RECV_FAILS, 0,
|
||||
ENB_PDU, 15, 0xec, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
ENB_PDU, 25, 0xec, 0x00, 0x00, 0x00, 0x80, 0x50, 0x05, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
|
||||
TIME, 100,
|
||||
ENB_RECV_FAILS, 0,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* rlc am test function process_received_ack with something in
|
||||
* the retransmit_list to put in the ack_list
|
||||
* eNB sends 4 PDUs, not received
|
||||
* eNB retransmits 4th PDU, received, ACKed with NACKs for PDU 1, 2, 3
|
||||
* UE receives custom PDU for 1, 2, 3, 4 (they are not sent by eNB)
|
||||
* (4 resent to have the P bit set)
|
||||
* UE sends ACK for all, eNB puts from retransmit_list to ack_list
|
||||
*
|
||||
* Maybe not very realistic (custom PDUs).
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_RECV_FAILS, 1,
|
||||
ENB_RECV_FAILS, 1,
|
||||
ENB_PDU_SIZE, 12,
|
||||
ENB_SDU, 0, 10,
|
||||
ENB_SDU, 1, 10,
|
||||
ENB_SDU, 2, 10,
|
||||
ENB_SDU, 3, 10,
|
||||
TIME, 10,
|
||||
UE_RECV_FAILS, 0,
|
||||
ENB_RECV_FAILS, 0,
|
||||
TIME, 87,
|
||||
ENB_PDU, 12, 0x80, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
|
||||
ENB_PDU, 12, 0x80, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
|
||||
ENB_PDU, 12, 0x80, 0x02, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
|
||||
ENB_PDU, 12, 0xa0, 0x03, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* rlc am test max_retx_reached
|
||||
* eNB sends PDU, never received
|
||||
*/
|
||||
TIME, 1,
|
||||
MUST_FAIL,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_RECV_FAILS, 1,
|
||||
ENB_RECV_FAILS, 1,
|
||||
ENB_SDU, 0, 10,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* rlc am test so_overlap
|
||||
* eNB sends PDU, not received
|
||||
* then PDU is segmented in 3 parts, part 1 & 3 not received,
|
||||
* then we generate a fake control PDU from UE to eNB that
|
||||
* contains NACK with so_start/so_end being inside part 2.
|
||||
*
|
||||
* code to generate fake control PDU:
|
||||
* rlc_pdu_encoder_init(&e, out, 100);
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // D/C
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 3); // CPT
|
||||
* rlc_pdu_encoder_put_bits(&e, 2, 10); // ack_sn
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 1); // e1
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 10); // nack_sn
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // e1
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 1); // e2
|
||||
* rlc_pdu_encoder_put_bits(&e, 14, 15); // so_start
|
||||
* rlc_pdu_encoder_put_bits(&e, 16, 15); // so_end
|
||||
* rlc_pdu_encoder_align(&e);
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 8,
|
||||
ENB_RECV_FAILS, 1,
|
||||
TIME, 2,
|
||||
UE_RECV_FAILS, 1,
|
||||
ENB_SDU, 1, 30,
|
||||
TIME, 20,
|
||||
ENB_PDU_SIZE, 14,
|
||||
TIME, 48,
|
||||
UE_RECV_FAILS, 0,
|
||||
TIME, 49,
|
||||
UE_RECV_FAILS, 1,
|
||||
TIME, 50,
|
||||
UE_RECV_FAILS, 0,
|
||||
TIME, 60,
|
||||
ENB_RECV_FAILS, 0,
|
||||
UE_PDU, 8, 0x00, 0x0a, 0x00, 0xa0, 0x03, 0x80, 0x08, 0x00,
|
||||
TIME, 70,
|
||||
UE_RECV_FAILS, 0,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* rlc am test process_received_nack
|
||||
* Same events as for test15 except the fake control PDU
|
||||
* does not ACK anything (ack_sn = 0) so that PDU in the
|
||||
* wait_list are not transfered into the ack_list and
|
||||
* we cover the case:
|
||||
* } else {
|
||||
* prev = cur;
|
||||
* cur = cur->next;
|
||||
* }
|
||||
* for the wait_list case.
|
||||
*
|
||||
* code to generate fake control PDU:
|
||||
* rlc_pdu_encoder_init(&e, out, 100);
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // D/C
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 3); // CPT
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 10); // ack_sn
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 1); // e1
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 10); // nack_sn
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // e1
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 1); // e2
|
||||
* rlc_pdu_encoder_put_bits(&e, 14, 15); // so_start
|
||||
* rlc_pdu_encoder_put_bits(&e, 16, 15); // so_end
|
||||
* rlc_pdu_encoder_align(&e);
|
||||
*/
|
||||
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 8,
|
||||
ENB_RECV_FAILS, 1,
|
||||
TIME, 2,
|
||||
UE_RECV_FAILS, 1,
|
||||
ENB_SDU, 1, 30,
|
||||
TIME, 20,
|
||||
ENB_PDU_SIZE, 14,
|
||||
TIME, 48,
|
||||
UE_RECV_FAILS, 0,
|
||||
TIME, 49,
|
||||
UE_RECV_FAILS, 1,
|
||||
TIME, 50,
|
||||
UE_RECV_FAILS, 0,
|
||||
TIME, 60,
|
||||
ENB_RECV_FAILS, 0,
|
||||
UE_PDU, 8, 0x00, 0x02, 0x00, 0xa0, 0x03, 0x80, 0x08, 0x00,
|
||||
TIME, 70,
|
||||
UE_RECV_FAILS, 0,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* rlc am test function process_received_nack
|
||||
* case 'check that VT(A) <= sn < VT(S)'
|
||||
* eNB sends PDU, not received, resends segmented
|
||||
* we generate a fake control PDU containing nack_sn == 10,
|
||||
* to fail the 'check ...' and cover the return.
|
||||
*
|
||||
* code to generate fake control PDU:
|
||||
* rlc_pdu_encoder_init(&e, out, 100);
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // D/C
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 3); // CPT
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 10); // ack_sn
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 1); // e1
|
||||
* rlc_pdu_encoder_put_bits(&e, 10, 10); // nack_sn
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // e1
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // e2
|
||||
* rlc_pdu_encoder_align(&e);
|
||||
*/
|
||||
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 30,
|
||||
ENB_RECV_FAILS, 1,
|
||||
TIME, 20,
|
||||
ENB_PDU_SIZE, 14,
|
||||
TIME, 60,
|
||||
ENB_RECV_FAILS, 0,
|
||||
UE_PDU, 4, 0x00, 0x02, 0x05, 0x00,
|
||||
TIME, -1
|
||||
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user