|
|
|
@@ -411,6 +411,955 @@ set_ul_DAI(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// changes to pre-processor for eMTC
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
void
|
|
|
|
|
schedule_ue_spec_br(
|
|
|
|
|
module_id_t module_idP,
|
|
|
|
|
frame_t frameP,
|
|
|
|
|
sub_frame_t subframeP,
|
|
|
|
|
int* mbsfn_flag
|
|
|
|
|
)
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
uint8_t CC_id;
|
|
|
|
|
int UE_id;
|
|
|
|
|
unsigned char aggregation;
|
|
|
|
|
mac_rlc_status_resp_t rlc_status;
|
|
|
|
|
unsigned char header_len_dcch = 0, header_len_dcch_tmp = 0;
|
|
|
|
|
unsigned char header_len_dtch = 0, header_len_dtch_tmp = 0, header_len_dtch_last = 0;
|
|
|
|
|
unsigned char ta_len = 0;
|
|
|
|
|
unsigned char sdu_lcids[NB_RB_MAX], lcid, offset, num_sdus = 0;
|
|
|
|
|
uint16_t nb_rb, nb_rb_temp, nb_available_rb;
|
|
|
|
|
uint16_t TBS, j, sdu_lengths[NB_RB_MAX], rnti, padding = 0, post_padding = 0;
|
|
|
|
|
unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES];
|
|
|
|
|
unsigned char round = 0;
|
|
|
|
|
unsigned char harq_pid = 0;
|
|
|
|
|
eNB_UE_STATS *eNB_UE_stats = NULL;
|
|
|
|
|
uint16_t sdu_length_total = 0;
|
|
|
|
|
|
|
|
|
|
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
|
|
|
|
COMMON_channels_t *cc = eNB->common_channels;
|
|
|
|
|
UE_list_t *UE_list = &eNB->UE_list;
|
|
|
|
|
int continue_flag = 0;
|
|
|
|
|
int32_t normalized_rx_power, target_rx_power;
|
|
|
|
|
int32_t tpc = 1;
|
|
|
|
|
static int32_t tpc_accumulated = 0;
|
|
|
|
|
UE_sched_ctrl *ue_sched_ctl;
|
|
|
|
|
int mcs;
|
|
|
|
|
int i;
|
|
|
|
|
int min_rb_unit[MAX_NUM_CCs];
|
|
|
|
|
int N_RB_DL[MAX_NUM_CCs];
|
|
|
|
|
int total_nb_available_rb[MAX_NUM_CCs];
|
|
|
|
|
int N_RBG[MAX_NUM_CCs];
|
|
|
|
|
nfapi_dl_config_request_body_t *dl_req;
|
|
|
|
|
nfapi_dl_config_request_pdu_t *dl_config_pdu;
|
|
|
|
|
nfapi_tx_request_pdu_t *TX_req;
|
|
|
|
|
int tdd_sfa;
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
if (UE_list->head == -1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
uint8_t *vrb_map;
|
|
|
|
|
int first_rb;
|
|
|
|
|
start_meas(&eNB->schedule_dlsch);
|
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_IN);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// for TDD: check that we have to act here, otherwise return
|
|
|
|
|
//if (cc[0].tdd_Config) {
|
|
|
|
|
// tdd_sfa = cc[0].tdd_Config->subframeAssignment;
|
|
|
|
|
// switch (subframeP) {
|
|
|
|
|
// case 0:
|
|
|
|
|
// // always continue
|
|
|
|
|
// break;
|
|
|
|
|
// case 1:
|
|
|
|
|
// return;
|
|
|
|
|
// break;
|
|
|
|
|
// case 2:
|
|
|
|
|
// return;
|
|
|
|
|
// break;
|
|
|
|
|
// case 3:
|
|
|
|
|
// if ((tdd_sfa != 2) && (tdd_sfa != 5)) return;
|
|
|
|
|
// break;
|
|
|
|
|
// case 4:
|
|
|
|
|
// if ((tdd_sfa != 1) && (tdd_sfa != 2) && (tdd_sfa != 4) && (tdd_sfa != 5)) return;
|
|
|
|
|
// break;
|
|
|
|
|
// case 5:
|
|
|
|
|
// break;
|
|
|
|
|
// case 6:
|
|
|
|
|
// case 7:
|
|
|
|
|
// if ((tdd_sfa != 1) && (tdd_sfa != 2) && (tdd_sfa != 4) && (tdd_sfa != 5)) return;
|
|
|
|
|
// break;
|
|
|
|
|
// case 8:
|
|
|
|
|
// if ((tdd_sfa != 2) && (tdd_sfa != 3) && (tdd_sfa != 4) && (tdd_sfa != 5)) return;
|
|
|
|
|
// break;
|
|
|
|
|
// case 9:
|
|
|
|
|
// if ((tdd_sfa != 1) && (tdd_sfa != 3) && (tdd_sfa != 4) && (tdd_sfa != 6)) return;
|
|
|
|
|
// break;
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
//}
|
|
|
|
|
//weight = get_ue_weight(module_idP,UE_id);
|
|
|
|
|
aggregation = 2;
|
|
|
|
|
for (CC_id = 0; CC_id<MAX_NUM_CCs; CC_id++) {
|
|
|
|
|
N_RB_DL[CC_id] = to_prb(cc[CC_id].mib->message.dl_Bandwidth);
|
|
|
|
|
min_rb_unit[CC_id] = get_min_rb_unit(module_idP, CC_id);
|
|
|
|
|
// get number of PRBs less those used by common channels
|
|
|
|
|
total_nb_available_rb[CC_id] = N_RB_DL[CC_id];
|
|
|
|
|
for (i = 0; i<N_RB_DL[CC_id]; i++)
|
|
|
|
|
if (cc[CC_id].vrb_map[i] != 0)
|
|
|
|
|
total_nb_available_rb[CC_id]--;
|
|
|
|
|
|
|
|
|
|
N_RBG[CC_id] = to_rbg(cc[CC_id].mib->message.dl_Bandwidth);
|
|
|
|
|
|
|
|
|
|
// store the global enb stats:
|
|
|
|
|
eNB->eNB_stats[CC_id].num_dlactive_UEs = UE_list->num_UEs;
|
|
|
|
|
eNB->eNB_stats[CC_id].available_prbs = total_nb_available_rb[CC_id];
|
|
|
|
|
eNB->eNB_stats[CC_id].total_available_prbs += total_nb_available_rb[CC_id];
|
|
|
|
|
eNB->eNB_stats[CC_id].dlsch_bytes_tx = 0;
|
|
|
|
|
eNB->eNB_stats[CC_id].dlsch_pdus_tx = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// CALLING Pre_Processor for downlink scheduling (Returns estimation of RBs required by each UE and the allocation on sub-band)
|
|
|
|
|
|
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_IN);
|
|
|
|
|
/*start_meas(&eNB->schedule_dlsch_preprocessor);
|
|
|
|
|
dlsch_scheduler_pre_processor(module_idP,
|
|
|
|
|
frameP,
|
|
|
|
|
subframeP,
|
|
|
|
|
N_RBG,
|
|
|
|
|
mbsfn_flag);
|
|
|
|
|
stop_meas(&eNB->schedule_dlsch_preprocessor);*/
|
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_OUT);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (CC_id = 0; CC_id<MAX_NUM_CCs; CC_id++)
|
|
|
|
|
{
|
|
|
|
|
vrb_map = cc[CC_id].vrb_map;
|
|
|
|
|
|
|
|
|
|
LOG_D(MAC, "doing schedule_ue_spec for CC_id %d\n", CC_id);
|
|
|
|
|
|
|
|
|
|
dl_req = &eNB->DL_req[CC_id].dl_config_request_body;
|
|
|
|
|
|
|
|
|
|
if (mbsfn_flag[CC_id]>0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
for (UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id])
|
|
|
|
|
{
|
|
|
|
|
first_rb = 0;
|
|
|
|
|
vrb_map[first_rb] = 1;
|
|
|
|
|
vrb_map[first_rb + 1] = 1;
|
|
|
|
|
vrb_map[first_rb + 2] = 1;
|
|
|
|
|
vrb_map[first_rb + 3] = 1;
|
|
|
|
|
vrb_map[first_rb + 4] = 1;
|
|
|
|
|
vrb_map[first_rb + 5] = 1;
|
|
|
|
|
|
|
|
|
|
continue_flag = 0; // reset the flag to allow allocation for the remaining UEs
|
|
|
|
|
rnti = UE_RNTI(module_idP, UE_id);
|
|
|
|
|
eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id];
|
|
|
|
|
ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (rnti == NOT_A_RNTI) {
|
|
|
|
|
LOG_D(MAC, "Cannot find rnti for UE_id %d (num_UEs %d)\n", UE_id, UE_list->num_UEs);
|
|
|
|
|
continue_flag = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (eNB_UE_stats == NULL) {
|
|
|
|
|
LOG_D(MAC, "[eNB] Cannot find eNB_UE_stats\n");
|
|
|
|
|
continue_flag = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//if (continue_flag != 1) {
|
|
|
|
|
// switch (get_tmode(module_idP, CC_id, UE_id)) {
|
|
|
|
|
// case 1:
|
|
|
|
|
// case 2:
|
|
|
|
|
// case 7:
|
|
|
|
|
// aggregation = get_aggregation(get_bw_index(module_idP, CC_id),
|
|
|
|
|
// eNB_UE_stats->dl_cqi,
|
|
|
|
|
// format1);
|
|
|
|
|
// break;
|
|
|
|
|
// case 3:
|
|
|
|
|
// aggregation = get_aggregation(get_bw_index(module_idP, CC_id),
|
|
|
|
|
// eNB_UE_stats->dl_cqi,
|
|
|
|
|
// format2A);
|
|
|
|
|
// break;
|
|
|
|
|
// default:
|
|
|
|
|
// LOG_W(MAC, "Unsupported transmission mode %d\n", get_tmode(module_idP, CC_id, UE_id));
|
|
|
|
|
// aggregation = 2;
|
|
|
|
|
// }
|
|
|
|
|
//} /* if (continue_flag != 1 */
|
|
|
|
|
|
|
|
|
|
if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated
|
|
|
|
|
CCE_allocation_infeasible(module_idP, CC_id, 0, subframeP, aggregation, rnti)
|
|
|
|
|
) {
|
|
|
|
|
LOG_D(MAC, "[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n",
|
|
|
|
|
module_idP, frameP, UE_id, CC_id);
|
|
|
|
|
continue_flag = 1; //to next user (there might be rbs availiable for other UEs in TM5
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//if (cc[CC_id].tdd_Config != NULL) { //TDD
|
|
|
|
|
// set_ue_dai(subframeP,
|
|
|
|
|
// UE_id,
|
|
|
|
|
// CC_id,
|
|
|
|
|
// cc[CC_id].tdd_Config->subframeAssignment,
|
|
|
|
|
// UE_list);
|
|
|
|
|
// // update UL DAI after DLSCH scheduling
|
|
|
|
|
// set_ul_DAI(module_idP, UE_id, CC_id, frameP, subframeP);
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
/*if (continue_flag == 1) {
|
|
|
|
|
add_ue_dlsch_info(module_idP,
|
|
|
|
|
CC_id,
|
|
|
|
|
UE_id,
|
|
|
|
|
subframeP,
|
|
|
|
|
S_DL_NONE);
|
|
|
|
|
continue;
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
nb_available_rb = 6; // to be checked
|
|
|
|
|
harq_pid = ue_sched_ctl->harq_pid[CC_id];
|
|
|
|
|
round = ue_sched_ctl->round[CC_id];
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].crnti = rnti;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status = mac_eNB_get_rrc_status(module_idP, rnti);
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].harq_round = round;
|
|
|
|
|
|
|
|
|
|
sdu_length_total = 0;
|
|
|
|
|
num_sdus = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
DevCheck(((eNB_UE_stats->dl_cqi < MIN_CQI_VALUE) || (eNB_UE_stats->dl_cqi > MAX_CQI_VALUE)),
|
|
|
|
|
eNB_UE_stats->dl_cqi, MIN_CQI_VALUE, MAX_CQI_VALUE);
|
|
|
|
|
*/
|
|
|
|
|
eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->dl_cqi]; //to be checked
|
|
|
|
|
eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, 15);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// store stats
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi = eNB_UE_stats->dl_cqi;
|
|
|
|
|
|
|
|
|
|
// initializing the rb allocation indicator for each UE
|
|
|
|
|
//to be checked
|
|
|
|
|
for (j = 0; j<N_RBG[CC_id]; j++) {
|
|
|
|
|
UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_D(MAC, "[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n",
|
|
|
|
|
module_idP, frameP, UE_id, CC_id, rnti, harq_pid, round, nb_available_rb,
|
|
|
|
|
eNB_UE_stats->dl_cqi, eNB_UE_stats->dlsch_mcs1,
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* process retransmission */
|
|
|
|
|
|
|
|
|
|
if (round > 0) {
|
|
|
|
|
// get freq_allocation
|
|
|
|
|
nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid];
|
|
|
|
|
|
|
|
|
|
if (nb_rb <= nb_available_rb) {
|
|
|
|
|
if (cc[CC_id].tdd_Config != NULL) {
|
|
|
|
|
UE_list->UE_template[CC_id][UE_id].DAI++;
|
|
|
|
|
update_ul_dci(module_idP, CC_id, rnti, UE_list->UE_template[CC_id][UE_id].DAI);
|
|
|
|
|
LOG_D(MAC, "DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n", CC_id, subframeP, UE_id, UE_list->UE_template[CC_id][UE_id].DAI);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) {
|
|
|
|
|
for (j = 0; j<N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band
|
|
|
|
|
UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
nb_rb_temp = nb_rb;
|
|
|
|
|
j = 0;
|
|
|
|
|
|
|
|
|
|
while ((nb_rb_temp > 0) && (j<N_RBG[CC_id])) {
|
|
|
|
|
if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) {
|
|
|
|
|
UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j];
|
|
|
|
|
|
|
|
|
|
if ((j == N_RBG[CC_id] - 1) &&
|
|
|
|
|
((N_RB_DL[CC_id] == 25) ||
|
|
|
|
|
(N_RB_DL[CC_id] == 50))) {
|
|
|
|
|
nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id] + 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
j = j + 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nb_available_rb -= nb_rb;
|
|
|
|
|
/*
|
|
|
|
|
eNB->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb;
|
|
|
|
|
eNB->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id];
|
|
|
|
|
|
|
|
|
|
for(j=0; j<N_RBG[CC_id]; j++) {
|
|
|
|
|
eNB->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j];
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
switch (get_tmode(module_idP, CC_id, UE_id)) {
|
|
|
|
|
case 1:
|
|
|
|
|
case 2:
|
|
|
|
|
case 7:
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// rmax from SIB2 information
|
|
|
|
|
rmax = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->mpdcch_NumRepetition_RA_r13;
|
|
|
|
|
// choose r3 by default for RAR (Table 9.1.5-5)
|
|
|
|
|
rep = 2;
|
|
|
|
|
// get actual repetition count from Table 9.1.5-3
|
|
|
|
|
reps = (rmax <= 8) ? (1 << rep) : (rmax >> (3 - rep));
|
|
|
|
|
// get narrowband according to higher-layer config
|
|
|
|
|
num_nb = p[RA_template->rach_resource_type - 1]->mpdcch_NarrowbandsToMonitor_r13.list.count;
|
|
|
|
|
RA_template->msg2_narrowband = *p[RA_template->rach_resource_type - 1]->mpdcch_NarrowbandsToMonitor_r13.list.array[RA_template->preamble_index%num_nb];
|
|
|
|
|
first_rb = RA_template->msg2_narrowband * 6;
|
|
|
|
|
|
|
|
|
|
if ((RA_template->msg2_mpdcch_repetition_cnt == 0) &&
|
|
|
|
|
(mpdcch_sf_condition(eNB, CC_idP, frameP, subframeP, rmax, TYPE2)>0)) {
|
|
|
|
|
// MPDCCH configuration for RAR
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
memset((void*)dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t));
|
|
|
|
|
dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE;
|
|
|
|
|
dl_config_pdu->pdu_size = (uint8_t)(2 + sizeof(nfapi_dl_config_mpdcch_pdu));
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_format = (RA_template->rach_resource_type > 1) ? 11 : 10;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band = RA_template->msg2_narrowband;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_prb_pairs = 6;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_assignment = 0; // Note: this can be dynamic
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_tansmission_type = 1; // imposed (9.1.5 in 213) for Type 2 Common search space
|
|
|
|
|
AssertFatal(cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 != NULL,
|
|
|
|
|
"cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 is null\n");
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.start_symbol = cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ecce_index = 0; // Note: this should be dynamic
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.aggregation_level = 16; // OK for CEModeA r1-3 (9.1.5-1b) or CEModeB r1-4
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti_type = 2; // RA-RNTI
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti = RA_template->RA_rnti;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ce_mode = (RA_template->rach_resource_type < 3) ? 1 : 2;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.drms_scrambling_init = cc[CC_idP].physCellId;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.initial_transmission_sf_io = (frameP * 10) + subframeP;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.transmission_power = 6000; // 0dB
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_coding = getRIV(6, 0, 6); // Note: still to be checked if it should not be (getRIV(N_RB_DL,first_rb,6)) : Check nFAPI specifications and what is done L1 with this parameter
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mcs = 4; // adjust according to size of RAR, 208 bits with N1A_PRB=3
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pdsch_reptition_levels = 4; // fix to 4 for now
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.redundancy_version = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.new_data_indicator = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_process = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi_length = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi_flag = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_resource_offset = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_subframe_repetition_number = rep;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpc = 1;// N1A_PRB=3 (36.212); => 208 bits for mcs=4, choose mcs according t message size TBD
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index_length = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.allocate_prach_flag = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.preamble_index = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.prach_mask_index = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.starting_ce_level = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.srs_request = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity_flag = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.frequency_hopping_enabled_flag = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.paging_direct_indication_differentiation_flag = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.direct_indication = 0;
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.total_dci_length_including_padding = 0; // this is not needed by OAI L1, but should be filled in
|
|
|
|
|
dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_tx_antenna_ports = 1;
|
|
|
|
|
RA_template->msg2_mpdcch_repetition_cnt++;
|
|
|
|
|
dl_req->number_pdu++;
|
|
|
|
|
|
|
|
|
|
} //repetition_count==0 && SF condition met
|
|
|
|
|
else if (RA_template->msg2_mpdcch_repetition_cnt>0) { // we're in a stream of repetitions
|
|
|
|
|
RA_template->msg2_mpdcch_repetition_cnt++;
|
|
|
|
|
if (RA_template->msg2_mpdcch_repetition_cnt == reps) { // this is the last mpdcch repetition
|
|
|
|
|
if (cc[CC_idP].tdd_Config == NULL) { // FDD case
|
|
|
|
|
// wait 2 subframes for PDSCH transmission
|
|
|
|
|
if (subframeP>7) RA_template->Msg2_frame = (frameP + 1) & 1023;
|
|
|
|
|
else RA_template->Msg2_frame = frameP;
|
|
|
|
|
RA_template->Msg2_subframe = (subframeP + 2) % 10; // +2 is the "n+x" from Section 7.1.11 in 36.213
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
AssertFatal(1 == 0, "TDD case not done yet\n");
|
|
|
|
|
}
|
|
|
|
|
} // mpdcch_repetition_count == reps
|
|
|
|
|
if ((RA_template->Msg2_frame == frameP) && (RA_template->Msg2_subframe == subframeP)) {
|
|
|
|
|
// Program PDSCH
|
|
|
|
|
RA_template->generate_rar = 0;
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_idP];
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = RA_template->RA_rnti;
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 6);
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = 0;
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1;// first block
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0;
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB == 1) ? 0 : 1;
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1;
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1;
|
|
|
|
|
// dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ;
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1;
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0;
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0;
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB == 1) ? 1 : 2;
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1;
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1;
|
|
|
|
|
// dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ;
|
|
|
|
|
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = (RA_template->rach_resource_type < 3) ? 1 : 2;;
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not SI message
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = (10 * frameP) + subframeP;
|
|
|
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.drms_table_flag = 0;
|
|
|
|
|
dl_req->number_pdu++;
|
|
|
|
|
|
|
|
|
|
// Program UL processing for Msg3, same as regular LTE
|
|
|
|
|
get_Msg3alloc(&cc[CC_idP], subframeP, frameP, &RA_template->Msg3_frame, &RA_template->Msg3_subframe);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fill_rar_br(eNB, CC_idP, RA_template, frameP, subframeP, cc[CC_idP].RAR_pdu.payload, RA_template->rach_resource_type - 1);
|
|
|
|
|
// DL request
|
|
|
|
|
eNB->TX_req[CC_idP].sfn_sf = (frameP << 3) + subframeP;
|
|
|
|
|
TX_req = &eNB->TX_req[CC_idP].tx_request_body.tx_pdu_list[eNB->TX_req[CC_idP].tx_request_body.number_of_pdus];
|
|
|
|
|
TX_req->pdu_length = 7; // This should be changed if we have more than 1 preamble
|
|
|
|
|
TX_req->pdu_index = eNB->pdu_index[CC_idP]++;
|
|
|
|
|
TX_req->num_segments = 1;
|
|
|
|
|
TX_req->segments[0].segment_length = 7;
|
|
|
|
|
TX_req->segments[0].segment_data = cc[CC_idP].RAR_pdu.payload;
|
|
|
|
|
eNB->TX_req[CC_idP].tx_request_body.number_of_pdus++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*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_DCI_DL_PDU_TYPE;
|
|
|
|
|
dl_config_pdu->pdu_size = (uint8_t)(2 + sizeof(nfapi_dl_config_dci_dl_pdu));
|
|
|
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1;
|
|
|
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP, CC_id), eNB_UE_stats->dl_cqi, format1);
|
|
|
|
|
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
|
|
|
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power
|
|
|
|
|
|
|
|
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = harq_pid;
|
|
|
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // dont adjust power when retransmitting
|
|
|
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];
|
|
|
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid];
|
|
|
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = round & 3;*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!CCE_allocation_infeasible(module_idP, CC_id, 0, subframeP,
|
|
|
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,
|
|
|
|
|
rnti)) {
|
|
|
|
|
dl_req->number_dci++;
|
|
|
|
|
dl_req->number_pdu++;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// No TX request for retransmission (check if null request for FAPI)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
add_ue_dlsch_info(module_idP,
|
|
|
|
|
CC_id,
|
|
|
|
|
UE_id,
|
|
|
|
|
subframeP,
|
|
|
|
|
S_DL_SCHEDULED);
|
|
|
|
|
|
|
|
|
|
//eNB_UE_stats->dlsch_trials[round]++;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission += 1;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx = nb_rb;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx += nb_rb;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = eNB_UE_stats->dlsch_mcs1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
LOG_D(MAC, "[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n",
|
|
|
|
|
module_idP, frameP, CC_id, UE_id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else { /* This is a potentially new SDU opportunity */
|
|
|
|
|
|
|
|
|
|
rlc_status.bytes_in_buffer = 0;
|
|
|
|
|
// Now check RLC information to compute number of required RBs
|
|
|
|
|
// get maximum TBS size for RLC request
|
|
|
|
|
//to be checked
|
|
|
|
|
TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_available_rb);
|
|
|
|
|
// check first for RLC data on DCCH
|
|
|
|
|
// add the length for all the control elements (timing adv, drx, etc) : header + payload
|
|
|
|
|
|
|
|
|
|
ta_len = (ue_sched_ctl->ta_update != 0) ? 2 : 0;
|
|
|
|
|
|
|
|
|
|
header_len_dcch = 2; // 2 bytes DCCH SDU subheader
|
|
|
|
|
|
|
|
|
|
if (TBS - ta_len - header_len_dcch > 0) {
|
|
|
|
|
rlc_status = mac_rlc_status_ind(
|
|
|
|
|
module_idP,
|
|
|
|
|
rnti,
|
|
|
|
|
module_idP,
|
|
|
|
|
frameP,
|
|
|
|
|
subframeP,
|
|
|
|
|
ENB_FLAG_YES,
|
|
|
|
|
MBMS_FLAG_NO,
|
|
|
|
|
DCCH,
|
|
|
|
|
(TBS - ta_len - header_len_dcch)); // transport block set size
|
|
|
|
|
|
|
|
|
|
sdu_lengths[0] = 0;
|
|
|
|
|
|
|
|
|
|
if (rlc_status.bytes_in_buffer > 0) { // There is DCCH to transmit
|
|
|
|
|
LOG_D(MAC, "[eNB %d] Frame %d, DL-DCCH->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
|
|
|
|
|
module_idP, frameP, CC_id, TBS - header_len_dcch);
|
|
|
|
|
sdu_lengths[0] = mac_rlc_data_req(
|
|
|
|
|
module_idP,
|
|
|
|
|
rnti,
|
|
|
|
|
module_idP,
|
|
|
|
|
frameP,
|
|
|
|
|
ENB_FLAG_YES,
|
|
|
|
|
MBMS_FLAG_NO,
|
|
|
|
|
DCCH,
|
|
|
|
|
TBS, //not used
|
|
|
|
|
(char *)&dlsch_buffer[0]);
|
|
|
|
|
|
|
|
|
|
T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP),
|
|
|
|
|
T_INT(harq_pid), T_INT(DCCH), T_INT(sdu_lengths[0]));
|
|
|
|
|
|
|
|
|
|
LOG_D(MAC, "[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n", module_idP, CC_id, sdu_lengths[0]);
|
|
|
|
|
sdu_length_total = sdu_lengths[0];
|
|
|
|
|
sdu_lcids[0] = DCCH;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH] += 1;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH] += sdu_lengths[0];
|
|
|
|
|
num_sdus = 1;
|
|
|
|
|
#ifdef DEBUG_eNB_SCHEDULER
|
|
|
|
|
LOG_T(MAC, "[eNB %d][DCCH] CC_id %d Got %d bytes :", module_idP, CC_id, sdu_lengths[0]);
|
|
|
|
|
|
|
|
|
|
for (j = 0; j<sdu_lengths[0]; j++) {
|
|
|
|
|
LOG_T(MAC, "%x ", dlsch_buffer[j]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_T(MAC, "\n");
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
header_len_dcch = 0;
|
|
|
|
|
sdu_length_total = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check for DCCH1 and update header information (assume 2 byte sub-header)
|
|
|
|
|
if (TBS - ta_len - header_len_dcch - sdu_length_total > 0) {
|
|
|
|
|
rlc_status = mac_rlc_status_ind(
|
|
|
|
|
module_idP,
|
|
|
|
|
rnti,
|
|
|
|
|
module_idP,
|
|
|
|
|
frameP,
|
|
|
|
|
subframeP,
|
|
|
|
|
ENB_FLAG_YES,
|
|
|
|
|
MBMS_FLAG_NO,
|
|
|
|
|
DCCH + 1,
|
|
|
|
|
(TBS - ta_len - header_len_dcch - sdu_length_total)); // transport block set size less allocations for timing advance and
|
|
|
|
|
// DCCH SDU
|
|
|
|
|
sdu_lengths[num_sdus] = 0;
|
|
|
|
|
|
|
|
|
|
if (rlc_status.bytes_in_buffer > 0) {
|
|
|
|
|
LOG_I(MAC, "[eNB %d], Frame %d, DCCH1->DLSCH, CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
|
|
|
|
|
module_idP, frameP, CC_id, TBS - header_len_dcch - sdu_length_total);
|
|
|
|
|
sdu_lengths[num_sdus] += mac_rlc_data_req(
|
|
|
|
|
module_idP,
|
|
|
|
|
rnti,
|
|
|
|
|
module_idP,
|
|
|
|
|
frameP,
|
|
|
|
|
ENB_FLAG_YES,
|
|
|
|
|
MBMS_FLAG_NO,
|
|
|
|
|
DCCH + 1,
|
|
|
|
|
TBS, //not used
|
|
|
|
|
(char *)&dlsch_buffer[sdu_length_total]);
|
|
|
|
|
|
|
|
|
|
T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP),
|
|
|
|
|
T_INT(harq_pid), T_INT(DCCH + 1), T_INT(sdu_lengths[num_sdus]));
|
|
|
|
|
|
|
|
|
|
sdu_lcids[num_sdus] = DCCH1;
|
|
|
|
|
sdu_length_total += sdu_lengths[num_sdus];
|
|
|
|
|
header_len_dcch += 2;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH1] += 1;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH1] += sdu_lengths[num_sdus];
|
|
|
|
|
num_sdus++;
|
|
|
|
|
#ifdef DEBUG_eNB_SCHEDULER
|
|
|
|
|
LOG_T(MAC, "[eNB %d][DCCH1] CC_id %d Got %d bytes :", module_idP, CC_id, sdu_lengths[num_sdus]);
|
|
|
|
|
|
|
|
|
|
for (j = 0; j<sdu_lengths[num_sdus]; j++) {
|
|
|
|
|
LOG_T(MAC, "%x ", dlsch_buffer[j]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_T(MAC, "\n");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// assume the max dtch header size, and adjust it later
|
|
|
|
|
header_len_dtch = 0;
|
|
|
|
|
header_len_dtch_last = 0; // the header length of the last mac sdu
|
|
|
|
|
// lcid has to be sorted before the actual allocation (similar struct as ue_list).
|
|
|
|
|
for (lcid = NB_RB_MAX - 1; lcid >= DTCH; lcid--) {
|
|
|
|
|
// TBD: check if the lcid is active
|
|
|
|
|
|
|
|
|
|
header_len_dtch += 3;
|
|
|
|
|
header_len_dtch_last = 3;
|
|
|
|
|
LOG_D(MAC, "[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n",
|
|
|
|
|
module_idP, frameP, lcid, TBS,
|
|
|
|
|
TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch);
|
|
|
|
|
|
|
|
|
|
if (TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch > 0) { // NN: > 2 ?
|
|
|
|
|
rlc_status = mac_rlc_status_ind(module_idP,
|
|
|
|
|
rnti,
|
|
|
|
|
module_idP,
|
|
|
|
|
frameP,
|
|
|
|
|
subframeP,
|
|
|
|
|
ENB_FLAG_YES,
|
|
|
|
|
MBMS_FLAG_NO,
|
|
|
|
|
lcid,
|
|
|
|
|
TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (rlc_status.bytes_in_buffer > 0) {
|
|
|
|
|
|
|
|
|
|
LOG_D(MAC, "[eNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d)\n",
|
|
|
|
|
module_idP, frameP, TBS - header_len_dcch - sdu_length_total - header_len_dtch, lcid, header_len_dtch);
|
|
|
|
|
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,
|
|
|
|
|
rnti,
|
|
|
|
|
module_idP,
|
|
|
|
|
frameP,
|
|
|
|
|
ENB_FLAG_YES,
|
|
|
|
|
MBMS_FLAG_NO,
|
|
|
|
|
lcid,
|
|
|
|
|
TBS, //not used
|
|
|
|
|
(char*)&dlsch_buffer[sdu_length_total]);
|
|
|
|
|
T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP),
|
|
|
|
|
T_INT(harq_pid), T_INT(lcid), T_INT(sdu_lengths[num_sdus]));
|
|
|
|
|
|
|
|
|
|
LOG_D(MAC, "[eNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n", module_idP, sdu_lengths[num_sdus], lcid);
|
|
|
|
|
sdu_lcids[num_sdus] = lcid;
|
|
|
|
|
sdu_length_total += sdu_lengths[num_sdus];
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid] += 1;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[lcid] += sdu_lengths[num_sdus];
|
|
|
|
|
if (sdu_lengths[num_sdus] < 128) {
|
|
|
|
|
header_len_dtch--;
|
|
|
|
|
header_len_dtch_last--;
|
|
|
|
|
}
|
|
|
|
|
num_sdus++;
|
|
|
|
|
} // no data for this LCID
|
|
|
|
|
else {
|
|
|
|
|
header_len_dtch -= 3;
|
|
|
|
|
}
|
|
|
|
|
} // no TBS left
|
|
|
|
|
else {
|
|
|
|
|
header_len_dtch -= 3;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (header_len_dtch == 0)
|
|
|
|
|
header_len_dtch_last = 0;
|
|
|
|
|
// there is at least one SDU
|
|
|
|
|
// if (num_sdus > 0 ){
|
|
|
|
|
if ((sdu_length_total + header_len_dcch + header_len_dtch)> 0) {
|
|
|
|
|
|
|
|
|
|
// Now compute number of required RBs for total sdu length
|
|
|
|
|
// Assume RAH format 2
|
|
|
|
|
// adjust header lengths
|
|
|
|
|
header_len_dcch_tmp = header_len_dcch;
|
|
|
|
|
header_len_dtch_tmp = header_len_dtch;
|
|
|
|
|
if (header_len_dtch == 0) {
|
|
|
|
|
header_len_dcch = (header_len_dcch >0) ? 1 : 0;//header_len_dcch; // remove length field
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
header_len_dtch_last -= 1; // now use it to find how many bytes has to be removed for the last MAC SDU
|
|
|
|
|
header_len_dtch = (header_len_dtch > 0) ? header_len_dtch - header_len_dtch_last : header_len_dtch; // remove length field for the last SDU
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mcs = eNB_UE_stats->dlsch_mcs1;
|
|
|
|
|
|
|
|
|
|
if (mcs == 0) {
|
|
|
|
|
nb_rb = 4; // don't let the TBS get too small
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
nb_rb = min_rb_unit[CC_id];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TBS = get_TBS_DL(mcs, nb_rb);
|
|
|
|
|
|
|
|
|
|
while (TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) {
|
|
|
|
|
nb_rb += min_rb_unit[CC_id]; //
|
|
|
|
|
|
|
|
|
|
if (nb_rb>nb_available_rb) { // if we've gone beyond the maximum number of RBs
|
|
|
|
|
// (can happen if N_RB_DL is odd)
|
|
|
|
|
TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_available_rb);
|
|
|
|
|
nb_rb = nb_available_rb;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_rb);
|
|
|
|
|
}
|
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
|
// alter the allocation of the emtc UE here
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
|
if (nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) {
|
|
|
|
|
for (j = 0; j<N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band
|
|
|
|
|
UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
nb_rb_temp = nb_rb;
|
|
|
|
|
j = 0;
|
|
|
|
|
|
|
|
|
|
while ((nb_rb_temp > 0) && (j<N_RBG[CC_id])) {
|
|
|
|
|
if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) {
|
|
|
|
|
UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j];
|
|
|
|
|
|
|
|
|
|
if ((j == N_RBG[CC_id] - 1) &&
|
|
|
|
|
((N_RB_DL[CC_id] == 25) ||
|
|
|
|
|
(N_RB_DL[CC_id] == 50))) {
|
|
|
|
|
nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id] + 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
j = j + 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
///////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// decrease mcs until TBS falls below required length
|
|
|
|
|
while ((TBS > (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (mcs>0)) {
|
|
|
|
|
mcs--;
|
|
|
|
|
TBS = get_TBS_DL(mcs, nb_rb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if we have decreased too much or we don't have enough RBs, increase MCS
|
|
|
|
|
while ((TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (((ue_sched_ctl->dl_pow_off[CC_id]>0) && (mcs<28))
|
|
|
|
|
|| ((ue_sched_ctl->dl_pow_off[CC_id] == 0) && (mcs <= 15)))) {
|
|
|
|
|
mcs++;
|
|
|
|
|
TBS = get_TBS_DL(mcs, nb_rb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_D(MAC, "dlsch_mcs before and after the rate matching = (%d, %d)\n", eNB_UE_stats->dlsch_mcs1, mcs);
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_eNB_SCHEDULER
|
|
|
|
|
LOG_D(MAC, "[eNB %d] CC_id %d Generated DLSCH header (mcs %d, TBS %d, nb_rb %d)\n",
|
|
|
|
|
module_idP, CC_id, mcs, TBS, nb_rb);
|
|
|
|
|
// msg("[MAC][eNB ] Reminder of DLSCH with random data %d %d %d %d \n",
|
|
|
|
|
// TBS, sdu_length_total, offset, TBS-sdu_length_total-offset);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2) {
|
|
|
|
|
padding = (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len);
|
|
|
|
|
post_padding = 0;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
padding = 0;
|
|
|
|
|
|
|
|
|
|
// adjust the header len
|
|
|
|
|
if (header_len_dtch == 0) {
|
|
|
|
|
header_len_dcch = header_len_dcch_tmp;
|
|
|
|
|
}
|
|
|
|
|
else { //if (( header_len_dcch==0)&&((header_len_dtch==1)||(header_len_dtch==2)))
|
|
|
|
|
header_len_dtch = header_len_dtch_tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len; // 1 is for the postpadding header
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
offset = generate_dlsch_header((unsigned char*)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0],
|
|
|
|
|
num_sdus, //num_sdus
|
|
|
|
|
sdu_lengths, //
|
|
|
|
|
sdu_lcids,
|
|
|
|
|
255, // no drx
|
|
|
|
|
ue_sched_ctl->ta_update, // timing advance
|
|
|
|
|
NULL, // contention res id
|
|
|
|
|
padding,
|
|
|
|
|
post_padding);
|
|
|
|
|
|
|
|
|
|
//#ifdef DEBUG_eNB_SCHEDULER
|
|
|
|
|
if (ue_sched_ctl->ta_update) {
|
|
|
|
|
LOG_I(MAC,
|
|
|
|
|
"[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_dcch %d, header_dtch %d\n",
|
|
|
|
|
module_idP, frameP, UE_id, CC_id, sdu_length_total, num_sdus, sdu_lengths[0], sdu_lcids[0], offset,
|
|
|
|
|
ue_sched_ctl->ta_update, padding, post_padding, mcs, TBS, nb_rb, header_len_dcch, header_len_dtch);
|
|
|
|
|
}
|
|
|
|
|
//#endif
|
|
|
|
|
#ifdef DEBUG_eNB_SCHEDULER
|
|
|
|
|
LOG_T(MAC, "[eNB %d] First 16 bytes of DLSCH : \n");
|
|
|
|
|
|
|
|
|
|
for (i = 0; i<16; i++) {
|
|
|
|
|
LOG_T(MAC, "%x.", dlsch_buffer[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_T(MAC, "\n");
|
|
|
|
|
#endif
|
|
|
|
|
// cycle through SDUs and place in dlsch_buffer
|
|
|
|
|
memcpy(&UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset], dlsch_buffer, sdu_length_total);
|
|
|
|
|
// memcpy(RC.mac[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]);
|
|
|
|
|
|
|
|
|
|
// fill remainder of DLSCH with random data
|
|
|
|
|
for (j = 0; j<(TBS - sdu_length_total - offset); j++) {
|
|
|
|
|
UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset + sdu_length_total + j] = (char)(taus() & 0xff);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (opt_enabled == 1) {
|
|
|
|
|
trace_pdu(1, (uint8_t *)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0],
|
|
|
|
|
TBS, module_idP, 3, UE_RNTI(module_idP, UE_id),
|
|
|
|
|
eNB->frame, eNB->subframe, 0, 0);
|
|
|
|
|
LOG_D(OPT, "[eNB %d][DLSCH] CC_id %d Frame %d rnti %x with size %d\n",
|
|
|
|
|
module_idP, CC_id, frameP, UE_RNTI(module_idP, UE_id), TBS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP),
|
|
|
|
|
T_INT(harq_pid), T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], TBS));
|
|
|
|
|
|
|
|
|
|
UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb;
|
|
|
|
|
|
|
|
|
|
add_ue_dlsch_info(module_idP,
|
|
|
|
|
CC_id,
|
|
|
|
|
UE_id,
|
|
|
|
|
subframeP,
|
|
|
|
|
S_DL_SCHEDULED);
|
|
|
|
|
// store stats
|
|
|
|
|
eNB->eNB_stats[CC_id].dlsch_bytes_tx += sdu_length_total;
|
|
|
|
|
eNB->eNB_stats[CC_id].dlsch_pdus_tx += 1;
|
|
|
|
|
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = mcs;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS;
|
|
|
|
|
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes = TBS - sdu_length_total;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes += sdu_length_total;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes += TBS;
|
|
|
|
|
UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus += 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// do PUCCH power control
|
|
|
|
|
// this is the normalized RX power
|
|
|
|
|
eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id];
|
|
|
|
|
normalized_rx_power = eNB_UE_stats->Po_PUCCH_dBm;
|
|
|
|
|
target_rx_power = get_target_pucch_rx_power(module_idP, CC_id) + 20;
|
|
|
|
|
|
|
|
|
|
// this assumes accumulated tpc
|
|
|
|
|
// make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out
|
|
|
|
|
int32_t framex10psubframe = UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame * 10 + UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe;
|
|
|
|
|
if (((framex10psubframe + 10) <= (frameP * 10 + subframeP)) || //normal case
|
|
|
|
|
((framex10psubframe>(frameP * 10 + subframeP)) && (((10240 - framex10psubframe + frameP * 10 + subframeP) >= 10)))) //frame wrap-around
|
|
|
|
|
if (eNB_UE_stats->Po_PUCCH_update == 1) {
|
|
|
|
|
eNB_UE_stats->Po_PUCCH_update = 0;
|
|
|
|
|
|
|
|
|
|
UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame = frameP;
|
|
|
|
|
UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe = subframeP;
|
|
|
|
|
|
|
|
|
|
if (normalized_rx_power>(target_rx_power + 1)) {
|
|
|
|
|
tpc = 0; //-1
|
|
|
|
|
tpc_accumulated--;
|
|
|
|
|
}
|
|
|
|
|
else if (normalized_rx_power<(target_rx_power - 1)) {
|
|
|
|
|
tpc = 2; //+1
|
|
|
|
|
tpc_accumulated++;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
tpc = 1; //0
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
LOG_I(MAC,"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n",
|
|
|
|
|
module_idP,frameP, subframeP,harq_pid,tpc,
|
|
|
|
|
tpc_accumulated,normalized_rx_power,target_rx_power);*/
|
|
|
|
|
|
|
|
|
|
} // Po_PUCCH has been updated
|
|
|
|
|
else {
|
|
|
|
|
tpc = 1; //0
|
|
|
|
|
} // time to do TPC update
|
|
|
|
|
else {
|
|
|
|
|
tpc = 1; //0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//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_DCI_DL_PDU_TYPE;
|
|
|
|
|
//dl_config_pdu->pdu_size = (uint8_t)(2 + sizeof(nfapi_dl_config_dci_dl_pdu));
|
|
|
|
|
//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1;
|
|
|
|
|
//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP, CC_id), eNB_UE_stats->dl_cqi, format1);
|
|
|
|
|
//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
|
|
|
|
|
//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power
|
|
|
|
|
|
|
|
|
|
//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = harq_pid;
|
|
|
|
|
//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = tpc; // dont adjust power when retransmitting
|
|
|
|
|
//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];
|
|
|
|
|
//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs;
|
|
|
|
|
//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = 0;
|
|
|
|
|
////deactivate second codeword
|
|
|
|
|
//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_2 = 0;
|
|
|
|
|
//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_2 = 1;
|
|
|
|
|
//
|
|
|
|
|
dl_req->number_dci++;
|
|
|
|
|
dl_req->number_pdu++;
|
|
|
|
|
|
|
|
|
|
// Toggle NDI for next time
|
|
|
|
|
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,
|
|
|
|
|
UE_list->UE_template[CC_id][UE_id].rnti, harq_pid, UE_list->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;
|
|
|
|
|
|
|
|
|
|
eNB->TX_req[CC_id].sfn_sf = (frameP << 3) + subframeP;
|
|
|
|
|
TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus];
|
|
|
|
|
TX_req->pdu_length = TBS;
|
|
|
|
|
TX_req->pdu_index = eNB->pdu_index[CC_id]++;
|
|
|
|
|
TX_req->num_segments = 1;
|
|
|
|
|
TX_req->segments[0].segment_length = TBS;
|
|
|
|
|
TX_req->segments[0].segment_data = eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[harq_pid];
|
|
|
|
|
eNB->TX_req[CC_id].tx_request_body.number_of_pdus++;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else { // There is no data from RLC or MAC header, so don't schedule
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // UE_id loop
|
|
|
|
|
} // CC_id loop
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fill_DLSCH_dci(module_idP, frameP, subframeP, mbsfn_flag);
|
|
|
|
|
|
|
|
|
|
stop_meas(&eNB->schedule_dlsch);
|
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_OUT);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
void
|
|
|
|
|