diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index f4fe8587cd8494f01bf3be90cd4f66e712d312ac..0ea5823e6b048358e1043b336f280406b805215e 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -80,6 +80,91 @@ #if FAPI +/* global variables to deal with TPC command - we send one only once per frame maximum */ +static long global_subframe; /* global subframe - incremented at each TTI */ +static long ue_last_pucch_tpc[NUMBER_OF_UE_MAX]; /* last global subframe where a PUCCH TPC was sent to the UE */ +static long ue_last_pusch_tpc[NUMBER_OF_UE_MAX]; /* last global subframe where a PUSCH TPC was sent to the UE */ + +static void fapi_dl_tpc(int module_id, int CC_id, struct DlDciListElement_s *dci) +{ + int UE_id = find_UE_id(module_id, dci->rnti); + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + int32_t normalized_rx_power; + int32_t target_rx_power; + static int tpc_accumulated = 0; + + if (UE_id == -1) { printf("%s:%d: rnti %x not found\n", __FILE__, __LINE__, dci->rnti); abort(); } + + // this assumes accumulated tpc + // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out + if (global_subframe < ue_last_pucch_tpc[UE_id] + 10) { +printf("TPC PUCCH global sf %ld (%ld/%ld) UE %x: no TPC, last one is too recent (accumulated %d)\n", global_subframe, global_subframe/10, global_subframe%10, dci->rnti, tpc_accumulated); + dci->tpc = 0; + return; + } + + eNB_UE_stats = mac_xface->get_eNB_UE_stats(module_id, CC_id, dci->rnti); + if (eNB_UE_stats == NULL) { printf("%s:%d: stats for rnti %x not found\n", __FILE__, __LINE__, dci->rnti); abort(); } + normalized_rx_power = eNB_UE_stats->Po_PUCCH_dBm; + target_rx_power = mac_xface->get_target_pucch_rx_power(module_id, CC_id) + 20; + + if (eNB_UE_stats->Po_PUCCH_update == 1) { + eNB_UE_stats->Po_PUCCH_update = 0; + + ue_last_pucch_tpc[UE_id] = global_subframe; + + if (normalized_rx_power > target_rx_power + 1) { + dci->tpc = -1; + tpc_accumulated--; + } else if (normalized_rx_power < target_rx_power - 1) { + dci->tpc = 1; + tpc_accumulated++; + } else { + dci->tpc = 0; + } + } +printf("TPC PUCCH global sf %ld (%ld/%ld) UE %x: TPC %d (accumulated %d)\n", global_subframe, global_subframe/10, global_subframe%10, dci->rnti, dci->tpc, tpc_accumulated); +} + +static void fapi_ul_tpc(int module_id, int CC_id, struct UlDciListElement_s *dci) +{ + int UE_id = find_UE_id(module_id, dci->rnti); + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + int32_t normalized_rx_power; + int32_t target_rx_power; + static int tpc_accumulated = 0; + + if (UE_id == -1) { printf("%s:%d: rnti %x not found\n", __FILE__, __LINE__, dci->rnti); abort(); } + + // this assumes accumulated tpc + // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out + if (global_subframe < ue_last_pusch_tpc[UE_id] + 10) { +printf("TPC PUSCH global sf %ld (%ld/%ld) UE %x: no TPC, last one is too recent (accumulated %d)\n", global_subframe, global_subframe/10, global_subframe%10, dci->rnti, tpc_accumulated); + dci->tpc = 0; + return; + } + + eNB_UE_stats = mac_xface->get_eNB_UE_stats(module_id, CC_id, dci->rnti); + if (eNB_UE_stats == NULL) { printf("%s:%d: stats for rnti %x not found\n", __FILE__, __LINE__, dci->rnti); abort(); } + normalized_rx_power = eNB_UE_stats->UL_rssi[0]; + target_rx_power = mac_xface->get_target_pusch_rx_power(module_id, CC_id); + + if (normalized_rx_power > target_rx_power + 1) { + dci->tpc = -1; + tpc_accumulated--; + } else if (normalized_rx_power < target_rx_power - 1) { + dci->tpc = 1; + tpc_accumulated++; + } else { + dci->tpc = 0; + } + + if (dci->tpc != 0) { + ue_last_pusch_tpc[UE_id] = global_subframe; + } +printf("TPC PUSCH global sf %ld (%ld/%ld) UE %x: TPC %d (accumulated %d)\n", global_subframe, global_subframe/10, global_subframe%10, dci->rnti, dci->tpc, tpc_accumulated); +} + /* this structure is used to store downlink ack/nack information * to be sent to FAPI by SchedDlTriggerReq */ @@ -192,7 +277,11 @@ static void fapi_convert_dl_1A_5MHz_FDD(struct DlDciListElement_s *dci, DCI_ALLO d->harq_pid = dci->harqProcess; d->ndi = dci->ndi[0]; /* TODO: take care of transport block index */ d->rv = dci->rv[0]; /* TODO: take care of transport block index */ - d->TPC = dci->tpc; + d->TPC = dci->tpc == -1 ? 0 : /* see 36.213 table 5.1.2.1-1 */ + dci->tpc == 0 ? 1 : + dci->tpc == 1 ? 2 : + dci->tpc == 3 ? 3 : + (printf("%s:%d: error\n", __FUNCTION__, __LINE__), abort(), 0); d->padding = 0; a->dci_length = sizeof_DCI1A_5MHz_FDD_t; @@ -225,15 +314,25 @@ static void fapi_convert_dl_1_5MHz_FDD(struct DlDciListElement_s *dci, DCI_ALLOC d->harq_pid = dci->harqProcess; d->ndi = dci->ndi[0]; /* TODO: take care of transport block index */ d->rv = dci->rv[0]; /* TODO: take care of transport block index */ - d->TPC = dci->tpc; + d->TPC = dci->tpc == -1 ? 0 : /* see 36.213 table 5.1.2.1-1 */ + dci->tpc == 0 ? 1 : + dci->tpc == 1 ? 2 : + dci->tpc == 3 ? 3 : + (printf("%s:%d: error (dci->tpc = %d)\n", __FUNCTION__, __LINE__, dci->tpc), abort(), 0); d->dummy = 0; a->dci_length = sizeof_DCI1_5MHz_FDD_t; a->format = format1; } -static void fapi_convert_dl_dci(struct DlDciListElement_s *dci, DCI_ALLOC_t *a) +static void fapi_convert_dl_dci(int module_id, int CC_id, + struct DlDciListElement_s *dci, DCI_ALLOC_t *a) { + /* set TPC in the DCI */ + /* TODO: remove it if/when the scheduler does it */ + if (dci->rnti != 0) + fapi_dl_tpc(module_id, CC_id, dci); + /* 5MHz FDD supposed, not checked */ switch (dci->format) { case ONE_A: @@ -264,7 +363,11 @@ static void fapi_convert_ul_5MHz_FDD(module_id_t module_idP, int CC_id, d->rballoc = mac_xface->computeRIV(PHY_vars_eNB_g[module_idP][CC_id]->lte_frame_parms.N_RB_DL, dci->rbStart, dci->rbLen); d->mcs = dci->mcs; d->ndi = dci->ndi; - d->TPC = dci->tpc; + d->TPC = dci->tpc == -1 ? 0 : /* see 36.213 table 5.1.1.1-2, accumulated case supposed */ + dci->tpc == 0 ? 1 : + dci->tpc == 1 ? 2 : + dci->tpc == 3 ? 3 : + (printf("%s:%d: error (tpc = %d)\n", __FUNCTION__, __LINE__, dci->tpc), abort(), 0); d->cshift = dci->n2Dmrs; d->cqi_req = dci->cqiRequest; d->padding = 0; @@ -276,6 +379,10 @@ static void fapi_convert_ul_5MHz_FDD(module_id_t module_idP, int CC_id, static void fapi_convert_ul_dci(module_id_t module_idP, int CC_id, struct UlDciListElement_s *dci, DCI_ALLOC_t *a) { + /* set TPC in the DCI */ + /* TODO: remove it if/when the scheduler does it */ + fapi_ul_tpc(module_idP, CC_id, dci); + /* 5MHz FDD supposed, not checked */ fapi_convert_ul_5MHz_FDD(module_idP, CC_id, dci, a); @@ -303,7 +410,7 @@ static void fapi_schedule_SI(module_id_t module_idP, int CC_id, frame_t frameP, /* we can increment Num_common_dci or Num_ue_spec_dci, there is no difference */ dci_pdu->Num_common_dci++; - fapi_convert_dl_dci(dci, a); + fapi_convert_dl_dci(module_idP, CC_id, dci, a); /* bug in libscheduler.a? rnti is 0 */ a->rnti = SI_RNTI; @@ -346,7 +453,7 @@ static void fapi_schedule_RAR(int module_idP, int CC_id, frame_t frameP, /* we can increment Num_common_dci or Num_ue_spec_dci, there is no difference */ dci_pdu->Num_common_dci++; - fapi_convert_dl_dci(dci, a); + fapi_convert_dl_dci(module_idP, CC_id, dci, a); a->ra_flag = 1; /* bug in libscheduler.a? rnti is 0 */ @@ -427,7 +534,7 @@ static void fapi_schedule_RA_Msg4(int module_idP, int CC_id, int RA, /* we can increment Num_common_dci or Num_ue_spec_dci, there is no difference */ dci_pdu->Num_common_dci++; - fapi_convert_dl_dci(dci, a); + fapi_convert_dl_dci(module_idP, CC_id, dci, a); } /* returns 1 if the given LCID has a MAC header of fixed size (for DL-SCH) */ @@ -465,7 +572,7 @@ static void fapi_schedule_ue(int module_id, int CC_id, int frame, int subframe, /* we can increment Num_common_dci or Num_ue_spec_dci, there is no difference */ dci_pdu->Num_common_dci++; - fapi_convert_dl_dci(&d->dci, a); + fapi_convert_dl_dci(module_id, CC_id, &d->dci, a); printf("RUN fapi_schedule_ue\n"); if (d->nr_rlcPDU_List[0] != 1) { printf("%s:%d:%s: TODO\n", __FILE__, __LINE__, __FUNCTION__); abort(); } @@ -885,6 +992,8 @@ printf(" RECAP %i rnti %x format %d dci pdu %s\n", i, binary(*(uint32_t *)eNB_mac_inst[0].common_channels[0].DCI_pdu.dci_alloc[i].dci_pdu) ); } + + global_subframe++; } #else /* FAPI */