In TDD mode, CQI requests are not possible in special subframes (at
least for some TDD configurations, see 36.213 7.2.3 that says "a
DL subframe is valid if it does not contain a DwPTS field if the
length is less than 7680 Ts").
In the code, we simply disable CQI requests in special subframes,
no matter what the length of DwPTS.
A problem can arise if the DCI0 for a given UE are sent only in
those special subframes. In this case the UE will never report
CQI and the eNB will use low MCS for this UE, impacting performances.
Another, related, problem is when there are several UEs. There again
one UE might always get its DCI0 in special subframes and thus never
report CQI. There again, performance issues.
This commit is an attempt to improve the situation.
It does two things.
1 - tag the UE as schedulable in the function UE_is_to_be_scheduled
if the cqi_req_timer is expired
2 - use cqi_req_timer as a criterium when ordering UEs for UL scheduling
The value chosen for the expiration of the cqi_req_timer in
UE_is_to_be_scheduled is quite high (300) because as the code is
today we may overschedule the UE for short bursts until we receive
a CQI from the UE. [TODO: fix the code properly to avoid this behavior.]
Note: the fairRR scheduler has not been analyzed and this commit may
not fix anything in case the fairRR scheduler is used.
5264 lines
184 KiB
C
5264 lines
184 KiB
C
/*
|
|
* 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_scheduler_primitives.c
|
|
* \brief primitives used by eNB for BCH, RACH, ULSCH, DLSCH scheduling
|
|
* \author Navid Nikaein and Raymond Knopp
|
|
* \date 2010 - 2014
|
|
* \email: navid.nikaein@eurecom.fr
|
|
* \version 1.0
|
|
* @ingroup _mac
|
|
|
|
*/
|
|
|
|
#include "assertions.h"
|
|
|
|
#include "LAYER2/MAC/mac.h"
|
|
#include "LAYER2/MAC/mac_extern.h"
|
|
|
|
#include "LAYER2/MAC/mac_proto.h"
|
|
#include "common/utils/LOG/log.h"
|
|
#include "nfapi/oai_integration/vendor_ext.h"
|
|
#include "common/utils/LOG/vcd_signal_dumper.h"
|
|
#include "UTIL/OPT/opt.h"
|
|
#include "OCG.h"
|
|
#include "OCG_extern.h"
|
|
|
|
#include "RRC/LTE/rrc_extern.h"
|
|
#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
|
|
|
|
//#include "LAYER2/MAC/pre_processor.c"
|
|
#include "pdcp.h"
|
|
|
|
#if defined(ENABLE_ITTI)
|
|
#include "intertask_interface.h"
|
|
#endif
|
|
|
|
#include "T.h"
|
|
|
|
#define ENABLE_MAC_PAYLOAD_DEBUG
|
|
#define DEBUG_eNB_SCHEDULER 1
|
|
extern uint16_t frame_cnt;
|
|
|
|
#include "common/ran_context.h"
|
|
#include "SCHED/sched_common.h"
|
|
|
|
extern RAN_CONTEXT_t RC;
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
choose(int n,
|
|
int k)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int res = 1;
|
|
int res2 = 1;
|
|
int i;
|
|
|
|
if (k > n)
|
|
return (0);
|
|
|
|
if (n == k)
|
|
return (1);
|
|
|
|
for (i = n; i > k; i--)
|
|
res *= i;
|
|
|
|
for (i = 2; i <= (n - k); i++)
|
|
res2 *= i;
|
|
|
|
return (res / res2);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Patented algorithm from Yang et al, US Patent 2009, "Channel Quality Indexing and Reverse Indexing"
|
|
void reverse_index(int N,
|
|
int M,
|
|
int r,
|
|
int *v)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int BaseValue = 0;
|
|
int IncreaseValue, ThresholdValue;
|
|
int sumV;
|
|
int i;
|
|
r = choose(N, M) - 1 - r;
|
|
memset((void *) v, 0, M * sizeof(int));
|
|
sumV = 0;
|
|
i = M;
|
|
|
|
while (i > 0 && r > 0) {
|
|
IncreaseValue = choose(N - M + 1 - sumV - v[i - 1] + i - 2,
|
|
i - 1);
|
|
ThresholdValue = BaseValue + IncreaseValue;
|
|
|
|
if (r >= ThresholdValue) {
|
|
v[i - 1]++;
|
|
BaseValue = ThresholdValue;
|
|
} else {
|
|
r -= BaseValue;
|
|
sumV += v[--i];
|
|
BaseValue = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
to_prb(int dl_Bandwidth)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int prbmap[6] = { 6, 15, 25, 50, 75, 100 };
|
|
AssertFatal(dl_Bandwidth < 6, "dl_Bandwidth is 0..5\n");
|
|
return (prbmap[dl_Bandwidth]);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
to_rbg(int dl_Bandwidth)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int rbgmap[6] = { 6, 8, 13, 17, 19, 25 };
|
|
AssertFatal(dl_Bandwidth < 6, "dl_Bandwidth is 0..5\n");
|
|
return (rbgmap[dl_Bandwidth]);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
get_phich_resource_times6(COMMON_channels_t *cc)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int phichmap[4] = { 1, 3, 6, 12 };
|
|
AssertFatal(cc != NULL, "cc is null\n");
|
|
AssertFatal(cc->mib != NULL, "cc->mib is null\n");
|
|
int phich_Resource = (int) cc->mib->message.phich_Config.phich_Resource;
|
|
AssertFatal(phich_Resource >= 0 && phich_Resource < 4, "phich_Resource %d not in 0..3\n",
|
|
phich_Resource);
|
|
return (phichmap[phich_Resource]);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint16_t
|
|
mac_computeRIV(uint16_t N_RB_DL,
|
|
uint16_t RBstart,
|
|
uint16_t Lcrbs)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
if (Lcrbs <= (1 + (N_RB_DL >> 1))) {
|
|
return (N_RB_DL * (Lcrbs - 1)) + RBstart;
|
|
}
|
|
|
|
return (N_RB_DL * (N_RB_DL + 1 - Lcrbs)) + (N_RB_DL - 1 - RBstart);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint8_t
|
|
getQm(uint8_t mcs)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
if (mcs < 10) return (2);
|
|
else if (mcs < 17) return (4);
|
|
|
|
return (6);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
get_Msg3alloc(COMMON_channels_t *cc,
|
|
sub_frame_t current_subframe,
|
|
frame_t current_frame,
|
|
frame_t *frame,
|
|
sub_frame_t *subframe)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
// Fill in other TDD Configuration!!!!
|
|
int subframeAssignment;
|
|
|
|
if (cc->tdd_Config == NULL) { // FDD
|
|
*subframe = current_subframe + 6;
|
|
|
|
if (*subframe > 9) {
|
|
*subframe = *subframe - 10;
|
|
*frame = (current_frame + 1) & 1023;
|
|
} else {
|
|
*frame = current_frame;
|
|
}
|
|
} else { // TDD
|
|
subframeAssignment = (int) cc->tdd_Config->subframeAssignment;
|
|
|
|
if (subframeAssignment == 1) {
|
|
switch (current_subframe) {
|
|
case 0:
|
|
*subframe = 7;
|
|
*frame = current_frame;
|
|
break;
|
|
|
|
case 4:
|
|
*subframe = 2;
|
|
*frame = (current_frame + 1) & 1023;
|
|
break;
|
|
|
|
case 5:
|
|
*subframe = 2;
|
|
*frame = (current_frame + 1) & 1023;
|
|
break;
|
|
|
|
case 9:
|
|
*subframe = 7;
|
|
*frame = (current_frame + 1) & 1023;
|
|
break;
|
|
}
|
|
} else if (subframeAssignment == 3) {
|
|
switch (current_subframe) {
|
|
case 0:
|
|
case 5:
|
|
case 6:
|
|
*subframe = 2;
|
|
*frame = (current_frame + 1) & 1023;
|
|
break;
|
|
|
|
case 7:
|
|
*subframe = 3;
|
|
*frame = (current_frame + 1) & 1023;
|
|
break;
|
|
|
|
case 8:
|
|
*subframe = 4;
|
|
*frame = (current_frame + 1) & 1023;
|
|
break;
|
|
|
|
case 9:
|
|
*subframe = 2;
|
|
*frame = (current_frame + 2) & 1023;
|
|
break;
|
|
}
|
|
} else if (subframeAssignment == 4) {
|
|
switch (current_subframe) {
|
|
case 0:
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
*subframe = 2;
|
|
*frame = (current_frame + 1) & 1023;
|
|
break;
|
|
|
|
case 7:
|
|
*subframe = 3;
|
|
*frame = (current_frame + 1) & 1023;
|
|
break;
|
|
|
|
case 8:
|
|
case 9:
|
|
*subframe = 2;
|
|
*frame = (current_frame + 2) & 1023;
|
|
break;
|
|
}
|
|
} else if (subframeAssignment == 5) {
|
|
switch (current_subframe) {
|
|
case 0:
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
*subframe = 2;
|
|
*frame = (current_frame + 1) & 1023;
|
|
break;
|
|
|
|
case 7:
|
|
case 8:
|
|
case 9:
|
|
*subframe = 2;
|
|
*frame = (current_frame + 2) & 1023;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
get_Msg3allocret(COMMON_channels_t *cc,
|
|
sub_frame_t current_subframe,
|
|
frame_t current_frame,
|
|
frame_t *frame,
|
|
sub_frame_t *subframe)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int subframeAssignment;
|
|
|
|
if (cc->tdd_Config == NULL) { //FDD
|
|
/* always retransmit in n+8 */
|
|
*subframe = current_subframe + 8;
|
|
|
|
if (*subframe > 9) {
|
|
*subframe = *subframe - 10;
|
|
*frame = (current_frame + 1) & 1023;
|
|
} else {
|
|
*frame = current_frame;
|
|
}
|
|
} else {
|
|
subframeAssignment = (int) cc->tdd_Config->subframeAssignment;
|
|
|
|
if (subframeAssignment == 1) {
|
|
// original PUSCH in 2, PHICH in 6 (S), ret in 2
|
|
// original PUSCH in 3, PHICH in 9, ret in 3
|
|
// original PUSCH in 7, PHICH in 1 (S), ret in 7
|
|
// original PUSCH in 8, PHICH in 4, ret in 8
|
|
*frame = (current_frame + 1) & 1023;
|
|
} else if (subframeAssignment == 3) {
|
|
// original PUSCH in 2, PHICH in 8, ret in 2 next frame
|
|
// original PUSCH in 3, PHICH in 9, ret in 3 next frame
|
|
// original PUSCH in 4, PHICH in 0, ret in 4 next frame
|
|
*frame = (current_frame + 1) & 1023;
|
|
} else if (subframeAssignment == 4) {
|
|
// original PUSCH in 2, PHICH in 8, ret in 2 next frame
|
|
// original PUSCH in 3, PHICH in 9, ret in 3 next frame
|
|
*frame = (current_frame + 1) & 1023;
|
|
} else if (subframeAssignment == 5) {
|
|
// original PUSCH in 2, PHICH in 8, ret in 2 next frame
|
|
*frame = (current_frame + 1) & 1023;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint8_t
|
|
subframe2harqpid(COMMON_channels_t *cc,
|
|
frame_t frame,
|
|
sub_frame_t subframe)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
AssertFatal(cc != NULL, "cc is null\n");
|
|
|
|
uint8_t ret = 255;
|
|
|
|
if (cc->tdd_Config == NULL) { // FDD
|
|
ret = (((frame << 1) + subframe) & 7);
|
|
} else {
|
|
switch (cc->tdd_Config->subframeAssignment) {
|
|
case 1:
|
|
if (subframe == 2 || subframe == 3 || subframe == 7 || subframe == 8) {
|
|
switch (subframe) {
|
|
case 2:
|
|
case 3:
|
|
ret = (subframe - 2);
|
|
break;
|
|
|
|
case 7:
|
|
case 8:
|
|
ret = (subframe - 5);
|
|
break;
|
|
|
|
default:
|
|
AssertFatal(1 == 0, "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
|
|
subframe,
|
|
(int) cc->tdd_Config->subframeAssignment);
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
AssertFatal(subframe == 2 || subframe == 7, "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
|
|
subframe,
|
|
(int) cc->tdd_Config->subframeAssignment);
|
|
ret = (subframe / 7);
|
|
break;
|
|
|
|
case 3:
|
|
AssertFatal(subframe > 1 && subframe < 5, "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
|
|
subframe,
|
|
(int) cc->tdd_Config->subframeAssignment);
|
|
ret = (subframe - 2);
|
|
break;
|
|
|
|
case 4:
|
|
AssertFatal(subframe > 1 && subframe < 4, "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
|
|
subframe,
|
|
(int) cc->tdd_Config->subframeAssignment);
|
|
ret = (subframe - 2);
|
|
break;
|
|
|
|
case 5:
|
|
AssertFatal(subframe == 2, "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
|
|
subframe,
|
|
(int) cc->tdd_Config->subframeAssignment);
|
|
ret = (subframe - 2);
|
|
break;
|
|
|
|
default:
|
|
AssertFatal(1 == 0, "subframe2_harq_pid, Unsupported TDD mode %d\n",
|
|
(int) cc->tdd_Config->subframeAssignment);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint8_t
|
|
get_Msg3harqpid(COMMON_channels_t *cc,
|
|
frame_t frame,
|
|
sub_frame_t current_subframe)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
uint8_t ul_subframe = 0;
|
|
uint32_t ul_frame = 0;
|
|
|
|
if (cc->tdd_Config == NULL) { // FDD
|
|
ul_subframe = (current_subframe > 3) ? (current_subframe - 4) : (current_subframe + 6);
|
|
ul_frame = (current_subframe > 3) ? ((frame + 1) & 1023) : frame;
|
|
} else {
|
|
switch (cc->tdd_Config->subframeAssignment) {
|
|
case 1:
|
|
switch (current_subframe) {
|
|
case 9:
|
|
case 0:
|
|
ul_subframe = 7;
|
|
break;
|
|
|
|
case 5:
|
|
case 7:
|
|
ul_subframe = 2;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
switch (current_subframe) {
|
|
case 0:
|
|
case 5:
|
|
case 6:
|
|
ul_subframe = 2;
|
|
break;
|
|
|
|
case 7:
|
|
ul_subframe = 3;
|
|
break;
|
|
|
|
case 8:
|
|
ul_subframe = 4;
|
|
break;
|
|
|
|
case 9:
|
|
ul_subframe = 2;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case 4:
|
|
switch (current_subframe) {
|
|
case 0:
|
|
case 5:
|
|
case 6:
|
|
case 8:
|
|
case 9:
|
|
ul_subframe = 2;
|
|
break;
|
|
|
|
case 7:
|
|
ul_subframe = 3;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case 5:
|
|
ul_subframe = 2;
|
|
break;
|
|
|
|
default:
|
|
LOG_E(PHY, "get_Msg3_harq_pid: Unsupported TDD configuration %d\n",
|
|
(int) cc->tdd_Config->subframeAssignment);
|
|
AssertFatal(1 == 0, "get_Msg3_harq_pid: Unsupported TDD configuration");
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (subframe2harqpid(cc,
|
|
ul_frame,
|
|
ul_subframe));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint32_t
|
|
pdcchalloc2ulframe(COMMON_channels_t *ccP,
|
|
uint32_t frame,
|
|
uint8_t n)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
uint32_t ul_frame = (frame + (n >= 6 ? 1 : 0));
|
|
|
|
if (ccP->tdd_Config) {
|
|
if (ccP->tdd_Config->subframeAssignment == 1) {
|
|
if (n == 1 || n == 6) {
|
|
ul_frame = (frame + (n == 1 ? 0 : 1));
|
|
}
|
|
} else if (ccP->tdd_Config->subframeAssignment == 6) {
|
|
if (n == 0 || n == 1 || n == 5 || n == 6) {
|
|
ul_frame = (frame + (n >= 5 ? 1 : 0));
|
|
} else if (n == 9) {
|
|
ul_frame = (frame + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
LOG_D(PHY, "frame %d subframe %d: PUSCH frame = %d\n",
|
|
frame,
|
|
n,
|
|
ul_frame);
|
|
return ul_frame;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint8_t
|
|
pdcchalloc2ulsubframe(COMMON_channels_t *ccP,
|
|
uint8_t n)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
uint8_t ul_subframe;
|
|
|
|
if (ccP->tdd_Config && ccP->tdd_Config->subframeAssignment == 1 && (n == 1 || n == 6)) // tdd_config 0,1 SF 1,5
|
|
ul_subframe = ((n + 6) % 10);
|
|
else if (ccP->tdd_Config && ccP->tdd_Config->subframeAssignment == 6 && (n == 0 || n == 1 || n == 5 || n == 6))
|
|
ul_subframe = ((n + 7) % 10);
|
|
else if (ccP->tdd_Config && ccP->tdd_Config->subframeAssignment == 6 && n == 9) // tdd_config 6 SF 9
|
|
ul_subframe = ((n + 5) % 10);
|
|
else
|
|
ul_subframe = ((n + 4) % 10);
|
|
|
|
LOG_D(PHY, "subframe %d: PUSCH subframe = %d\n",
|
|
n,
|
|
ul_subframe);
|
|
return ul_subframe;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
is_UL_sf(COMMON_channels_t *ccP,
|
|
sub_frame_t subframeP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
// if FDD return dummy value
|
|
if (ccP->tdd_Config == NULL)
|
|
return 0;
|
|
|
|
switch (ccP->tdd_Config->subframeAssignment) {
|
|
case 1:
|
|
switch (subframeP) {
|
|
case 0:
|
|
case 4:
|
|
case 5:
|
|
case 9:
|
|
return 0;
|
|
|
|
case 2:
|
|
case 3:
|
|
case 7:
|
|
case 8:
|
|
return 1;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
if (subframeP <= 1 || subframeP >= 5)
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
case 4:
|
|
if (subframeP <= 1 || subframeP >= 4)
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
case 5:
|
|
if (subframeP <= 1 || subframeP >= 3)
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
default:
|
|
AssertFatal(1 == 0, "subframe %d Unsupported TDD configuration %d\n",
|
|
subframeP,
|
|
(int) ccP->tdd_Config->subframeAssignment);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
is_S_sf(COMMON_channels_t *ccP,
|
|
sub_frame_t subframeP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
// if FDD return dummy value
|
|
if (ccP->tdd_Config == NULL)
|
|
return 0;
|
|
|
|
switch (subframeP) {
|
|
case 1:
|
|
return 1;
|
|
|
|
case 6:
|
|
if (ccP->tdd_Config->subframeAssignment == 0 || ccP->tdd_Config->subframeAssignment == 1 ||
|
|
ccP->tdd_Config->subframeAssignment == 2 || ccP->tdd_Config->subframeAssignment == 6)
|
|
return 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint8_t
|
|
ul_subframe2_k_phich(COMMON_channels_t *cc,
|
|
sub_frame_t ul_subframe)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
if(cc->tdd_Config) { //TODO fill other tdd config
|
|
switch(cc->tdd_Config->subframeAssignment) {
|
|
case 0:
|
|
break;
|
|
|
|
case 1:
|
|
if(ul_subframe == 2 || ul_subframe == 7)
|
|
return 4;
|
|
else if(ul_subframe == 3 || ul_subframe == 8)
|
|
return 6;
|
|
|
|
return 255;
|
|
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 4; //idk sf_ahead?
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint16_t
|
|
get_pucch1_absSF(COMMON_channels_t *cc,
|
|
uint16_t dlsch_absSF)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
uint16_t sf, f, nextf;
|
|
LTE_TDD_Config_t *tdd_Config = cc->tdd_Config;
|
|
|
|
if (tdd_Config == NULL) { //FDD n+4
|
|
return (dlsch_absSF + 4) % 10240;
|
|
}
|
|
|
|
sf = dlsch_absSF % 10;
|
|
f = dlsch_absSF / 10;
|
|
nextf = (f + 1) & 1023;
|
|
|
|
switch (tdd_Config->subframeAssignment) {
|
|
case 0:
|
|
if (sf == 0 || sf == 5)
|
|
return ((10 * f) + sf + 4) % 10240; // ACK/NAK in SF 4,9 same frame
|
|
|
|
if (sf == 6)
|
|
return ((10 * nextf) + 2) % 10240; // ACK/NAK in SF 2 next frame
|
|
|
|
if (sf == 1)
|
|
return ((10 * f) + 7) % 10240; // ACK/NAK in SF 7 same frame
|
|
|
|
break;
|
|
|
|
case 1:
|
|
if (sf == 5 || sf == 6)
|
|
return ((10 * nextf) + 2) % 10240; // ACK/NAK in SF 2 next frame
|
|
|
|
if (sf == 9)
|
|
return ((10 * nextf) + 3) % 10240; // ACK/NAK in SF 3 next frame
|
|
|
|
if ((sf == 0) || (sf == 1))
|
|
return ((10 * f) + 7) % 10240; // ACK/NAK in SF 7 same frame
|
|
|
|
if (sf == 4)
|
|
return ((10 * f) + 8) % 10240; // ACK/NAK in SF 8 same frame
|
|
|
|
break;
|
|
|
|
case 2:
|
|
if (sf == 4 || sf == 5 || sf == 6 || sf == 8)
|
|
return ((10 * nextf) + 2) % 10240; // ACK/NAK in SF 2 next frame
|
|
|
|
if (sf == 9)
|
|
return ((10 * nextf) + 7) % 10240; // ACK/NAK in SF 7 next frame
|
|
|
|
if (sf == 0 || sf == 1 || sf == 3)
|
|
return ((10 * f) + 7)% 10240; // ACK/NAK in SF 7 same frame
|
|
|
|
break;
|
|
|
|
case 3:
|
|
if (sf == 5 || sf == 6 || sf == 7 || sf == 8 || sf == 9)
|
|
return ((10 * nextf) + ((sf - 1) >> 1)) % 10240; // ACK/NAK in 2,3,4 resp. next frame
|
|
|
|
if (sf == 1)
|
|
return ((10 * nextf) + 2) % 10240; // ACK/NAK in 2 next frame
|
|
|
|
if (sf == 0)
|
|
return ((10 * f) + 4) % 10240; // ACK/NAK in 4 same frame
|
|
|
|
break;
|
|
|
|
case 4:
|
|
if (sf == 6 || sf == 7 || sf == 8 || sf == 9)
|
|
return ((10 * nextf) + 3) % 10240; // ACK/NAK in SF 3 next frame
|
|
else if (sf == 0 || sf == 1 || sf == 4 || sf == 5)
|
|
return ((10 * nextf) + 2) % 10240; // ACK/NAK in SF 2 next frame
|
|
|
|
break;
|
|
|
|
case 5:
|
|
if (sf == 0 || sf == 1 || sf == 3 || sf == 4 || sf == 5 || sf == 6 || sf == 7 || sf == 8)
|
|
return ((10 * nextf) + 2) % 10240; // ACK/NAK in SF 3 next frame
|
|
|
|
if (sf == 9)
|
|
return ((10 * (1 + nextf)) + 2) % 10240; // ACK/NAK in SF 2 next frame
|
|
|
|
break;
|
|
|
|
case 6:
|
|
if (sf == 5 || sf == 6)
|
|
return ((10 * f) + sf + 7) % 10240; // ACK/NAK in SF 2,3 next frame
|
|
|
|
if (sf == 9)
|
|
return ((10 * nextf) + 4) % 10240; // ACK/NAK in SF 4 next frame
|
|
|
|
if (sf == 1 || sf == 0)
|
|
return ((10 * f) + sf + 7) % 10240; // ACK/NAK in SF 7 same frame
|
|
|
|
break;
|
|
|
|
default:
|
|
AssertFatal(1 == 0, "Illegal TDD subframe Assigment %ld\n",
|
|
tdd_Config->subframeAssignment);
|
|
return 0;
|
|
}
|
|
|
|
AssertFatal(1 == 0, "Shouldn't get here\n");
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
get_srs_pos(COMMON_channels_t *cc,
|
|
uint16_t isrs,
|
|
uint16_t *psrsPeriodicity,
|
|
uint16_t *psrsOffset)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
if (cc->tdd_Config) { // TDD
|
|
AssertFatal(isrs >= 10, "2 ms SRS periodicity not supported");
|
|
|
|
if (isrs > 9 && isrs < 15) {
|
|
*psrsPeriodicity = 5;
|
|
*psrsOffset = isrs - 10;
|
|
} else if (isrs > 14 && isrs < 25) {
|
|
*psrsPeriodicity = 10;
|
|
*psrsOffset = isrs - 15;
|
|
} else if (isrs > 24 && isrs < 45) {
|
|
*psrsPeriodicity = 20;
|
|
*psrsOffset = isrs - 25;
|
|
} else if (isrs > 44 && isrs < 85) {
|
|
*psrsPeriodicity = 40;
|
|
*psrsOffset = isrs - 45;
|
|
} else if (isrs > 84 && isrs < 165) {
|
|
*psrsPeriodicity = 80;
|
|
*psrsOffset = isrs - 85;
|
|
} else if (isrs > 164 && isrs < 325) {
|
|
*psrsPeriodicity = 160;
|
|
*psrsOffset = isrs - 165;
|
|
} else if (isrs > 324 && isrs < 645) {
|
|
*psrsPeriodicity = 320;
|
|
*psrsOffset = isrs - 325;
|
|
}
|
|
|
|
AssertFatal(isrs <= 644, "Isrs out of range %d>644\n", isrs);
|
|
} // TDD
|
|
else { // FDD
|
|
if (isrs < 2) {
|
|
*psrsPeriodicity = 2;
|
|
*psrsOffset = isrs;
|
|
} else if (isrs > 1 && isrs < 7) {
|
|
*psrsPeriodicity = 5;
|
|
*psrsOffset = isrs - 2;
|
|
} else if (isrs > 6 && isrs < 17) {
|
|
*psrsPeriodicity = 10;
|
|
*psrsOffset = isrs - 7;
|
|
} else if (isrs > 16 && isrs < 37) {
|
|
*psrsPeriodicity = 20;
|
|
*psrsOffset = isrs - 17;
|
|
} else if (isrs > 36 && isrs < 77) {
|
|
*psrsPeriodicity = 40;
|
|
*psrsOffset = isrs - 37;
|
|
} else if (isrs > 76 && isrs < 157) {
|
|
*psrsPeriodicity = 80;
|
|
*psrsOffset = isrs - 77;
|
|
} else if (isrs > 156 && isrs < 317) {
|
|
*psrsPeriodicity = 160;
|
|
*psrsOffset = isrs - 157;
|
|
} else if (isrs > 316 && isrs < 637) {
|
|
*psrsPeriodicity = 320;
|
|
*psrsOffset = isrs - 317;
|
|
}
|
|
|
|
AssertFatal(isrs <= 636, "Isrs out of range %d>636\n", isrs);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/*
|
|
* Get some CSI (CQI/PMI/RI) parameters for SFN and subframe number calculation
|
|
* with periodic report.
|
|
*/
|
|
void
|
|
get_csi_params(COMMON_channels_t *cc,
|
|
struct LTE_CQI_ReportPeriodic *cqi_ReportPeriodic,
|
|
uint16_t *Npd,
|
|
uint16_t *N_OFFSET_CQI,
|
|
int *H)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
AssertFatal(cqi_ReportPeriodic != NULL, "cqi_ReportPeriodic is null!\n");
|
|
uint16_t cqi_PMI_ConfigIndex = cqi_ReportPeriodic->choice.setup.cqi_pmi_ConfigIndex;
|
|
uint8_t Jtab[6] = { 0, 2, 2, 3, 4, 4 };
|
|
|
|
if (cc->tdd_Config == NULL) { //FDD
|
|
if (cqi_PMI_ConfigIndex <= 1) { // 2 ms CQI_PMI period
|
|
*Npd = 2;
|
|
*N_OFFSET_CQI = cqi_PMI_ConfigIndex;
|
|
} else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period
|
|
*Npd = 5;
|
|
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 2;
|
|
} else if (cqi_PMI_ConfigIndex <= 16) { // 10ms CQI_PMI period
|
|
*Npd = 10;
|
|
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 7;
|
|
} else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period
|
|
*Npd = 20;
|
|
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 17;
|
|
} else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period
|
|
*Npd = 40;
|
|
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 37;
|
|
} else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period
|
|
*Npd = 80;
|
|
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 77;
|
|
} else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period
|
|
*Npd = 160;
|
|
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 157;
|
|
} else if (cqi_PMI_ConfigIndex > 317) {
|
|
|
|
if (cqi_PMI_ConfigIndex <= 349) { // 32 ms CQI_PMI period
|
|
*Npd = 32;
|
|
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 318;
|
|
} else if (cqi_PMI_ConfigIndex <= 413) { // 64 ms CQI_PMI period
|
|
*Npd = 64;
|
|
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 350;
|
|
} else if (cqi_PMI_ConfigIndex <= 541) { // 128 ms CQI_PMI period
|
|
*Npd = 128;
|
|
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 414;
|
|
}
|
|
|
|
}
|
|
|
|
} else { // TDD
|
|
if (cqi_PMI_ConfigIndex == 0) { // all UL subframes
|
|
*Npd = 1;
|
|
*N_OFFSET_CQI = 0;
|
|
} else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period
|
|
*Npd = 5;
|
|
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 1;
|
|
} else if (cqi_PMI_ConfigIndex <= 16) { // 10ms CQI_PMI period
|
|
*Npd = 10;
|
|
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 6;
|
|
} else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period
|
|
*Npd = 20;
|
|
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 16;
|
|
} else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period
|
|
*Npd = 40;
|
|
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 36;
|
|
} else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period
|
|
*Npd = 80;
|
|
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 76;
|
|
} else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period
|
|
*Npd = 160;
|
|
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 156;
|
|
}
|
|
}
|
|
|
|
// get H
|
|
if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == LTE_CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) {
|
|
*H = 1 + (Jtab[cc->mib->message.dl_Bandwidth] * cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.choice.subbandCQI.k);
|
|
} else {
|
|
*H = 1;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint8_t
|
|
get_dl_cqi_pmi_size_pusch(COMMON_channels_t *cc,
|
|
uint8_t tmode,
|
|
uint8_t ri,
|
|
LTE_CQI_ReportModeAperiodic_t *cqi_ReportModeAperiodic)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int Ntab[6] = { 0, 4, 7, 9, 10, 13 };
|
|
int N = Ntab[cc->mib->message.dl_Bandwidth];
|
|
int Ltab_uesel[6] = { 0, 6, 9, 13, 15, 18 };
|
|
int L = Ltab_uesel[cc->mib->message.dl_Bandwidth];
|
|
AssertFatal(cqi_ReportModeAperiodic != NULL, "cqi_ReportPeriodic is null!\n");
|
|
|
|
switch (*cqi_ReportModeAperiodic) {
|
|
case LTE_CQI_ReportModeAperiodic_rm12:
|
|
AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 || tmode == 10, "Illegal TM (%d) for CQI_ReportModeAperiodic_rm12\n",
|
|
tmode);
|
|
AssertFatal(cc->p_eNB <= 4, "only up to 4 antenna ports supported here\n");
|
|
|
|
if (ri == 1 && cc->p_eNB == 2)
|
|
return (4 + (N << 1));
|
|
|
|
if (ri == 2 && cc->p_eNB == 2)
|
|
return (8 + N);
|
|
|
|
if (ri == 1 && cc->p_eNB == 4)
|
|
return (4 + (N << 2));
|
|
|
|
if (ri > 1 && cc->p_eNB == 4)
|
|
return (8 + (N << 2));
|
|
|
|
break;
|
|
|
|
case LTE_CQI_ReportModeAperiodic_rm20:
|
|
// Table 5.2.2.6.3-1 (36.212)
|
|
AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 || tmode == 7 || tmode == 9 || tmode == 10, "Illegal TM (%d) for CQI_ReportModeAperiodic_rm20\n",
|
|
tmode);
|
|
AssertFatal(tmode != 9 && tmode != 10, "TM9/10 will be handled later for CQI_ReportModeAperiodic_rm20\n");
|
|
return (4 + 2 + L);
|
|
|
|
case LTE_CQI_ReportModeAperiodic_rm22:
|
|
// Table 5.2.2.6.3-2 (36.212)
|
|
AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 || tmode == 10, "Illegal TM (%d) for CQI_ReportModeAperiodic_rm22\n",
|
|
tmode);
|
|
AssertFatal(tmode != 9 && tmode != 10, "TM9/10 will be handled later for CQI_ReportModeAperiodic_rm22\n");
|
|
|
|
if (ri == 1 && cc->p_eNB == 2)
|
|
return (4 + 2 + 0 + 0 + L + 4);
|
|
|
|
if (ri == 2 && cc->p_eNB == 2)
|
|
return (4 + 2 + 4 + 2 + L + 2);
|
|
|
|
if (ri == 1 && cc->p_eNB == 4)
|
|
return (4 + 2 + 0 + 0 + L + 8);
|
|
|
|
if (ri >= 2 && cc->p_eNB == 4)
|
|
return (4 + 2 + 4 + 2 + L + 8);
|
|
|
|
break;
|
|
|
|
case LTE_CQI_ReportModeAperiodic_rm30:
|
|
// Table 5.2.2.6.2-1 (36.212)
|
|
AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 || tmode == 7 || tmode == 8 || tmode == 9 || tmode == 10,
|
|
"Illegal TM (%d) for CQI_ReportModeAperiodic_rm30\n",
|
|
tmode);
|
|
AssertFatal(tmode != 8 && tmode != 9 && tmode != 10, "TM8/9/10 will be handled later for CQI_ReportModeAperiodic_rm30\n");
|
|
return (4 + (N << 1));
|
|
|
|
case LTE_CQI_ReportModeAperiodic_rm31:
|
|
// Table 5.2.2.6.2-2 (36.212)
|
|
AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 || tmode == 10, "Illegal TM (%d) for CQI_ReportModeAperiodic_rm31\n",
|
|
tmode);
|
|
AssertFatal(tmode != 8 && tmode != 9 && tmode != 10, "TM8/9/10 will be handled later for CQI_ReportModeAperiodic_rm31\n");
|
|
|
|
if (ri == 1 && cc->p_eNB == 2)
|
|
return (4 + (N << 1) + 0 + 0 + 2);
|
|
|
|
if (ri == 2 && cc->p_eNB == 2)
|
|
return (4 + (N << 1) + 4 + (N << 1) + 1);
|
|
|
|
if (ri == 1 && cc->p_eNB == 4)
|
|
return (4 + (N << 1) + 0 + 0 + 4);
|
|
|
|
if (ri >= 2 && cc->p_eNB == 4)
|
|
return (4 + (N << 1) + 4 + (N << 1) + 4);
|
|
|
|
break;
|
|
#if (LTE_RRC_VERSION >= MAKE_VERSION(12, 5, 0))
|
|
|
|
case LTE_CQI_ReportModeAperiodic_rm32_v1250:
|
|
AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 || tmode == 10, "Illegal TM (%d) for CQI_ReportModeAperiodic_rm32\n",
|
|
tmode);
|
|
AssertFatal(1 == 0, "CQI_ReportModeAperiodic_rm32_v1250 not supported yet\n");
|
|
break;
|
|
|
|
case LTE_CQI_ReportModeAperiodic_rm10_v1310:
|
|
|
|
// Table 5.2.2.6.1-1F/G (36.212)
|
|
if (ri == 1)
|
|
return 4; // F
|
|
|
|
return 7; // G
|
|
|
|
case LTE_CQI_ReportModeAperiodic_rm11_v1310:
|
|
// Table 5.2.2.6.1-1H (36.212)
|
|
AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 || tmode == 10, "Illegal TM (%d) for CQI_ReportModeAperiodic_rm11\n",
|
|
tmode);
|
|
AssertFatal(cc->p_eNB <= 4, "only up to 4 antenna ports supported here\n");
|
|
|
|
if (ri == 1 && cc->p_eNB == 2)
|
|
return (4 + 0 + 2);
|
|
|
|
if (ri == 2 && cc->p_eNB == 2)
|
|
return (4 + 4 + 1);
|
|
|
|
if (ri == 1 && cc->p_eNB == 4)
|
|
return (4 + 0 + 4);
|
|
|
|
if (ri > 1 && cc->p_eNB == 4)
|
|
return (4 + 4 + 4);
|
|
|
|
break;
|
|
#endif /* #if (LTE_RRC_VERSION >= MAKE_VERSION(12, 5, 0)) */
|
|
}
|
|
|
|
AssertFatal(1 == 0, "Shouldn't get here\n");
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint8_t
|
|
get_rel8_dl_cqi_pmi_size(UE_sched_ctrl_t *sched_ctl,
|
|
int CC_idP,
|
|
COMMON_channels_t *cc,
|
|
uint8_t tmode,
|
|
struct LTE_CQI_ReportPeriodic *cqi_ReportPeriodic)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int no_pmi = 0;
|
|
// Ltab[6] = {0,log2(15/4/2),log2(25/4/2),log2(50/6/3),log2(75/8/4),log2(100/8/4)};
|
|
uint8_t Ltab[6] = { 0, 1, 2, 2, 2, 2 };
|
|
uint8_t ri = sched_ctl->periodic_ri_received[CC_idP];
|
|
AssertFatal(cqi_ReportPeriodic != NULL, "cqi_ReportPeriodic is null!\n");
|
|
AssertFatal(cqi_ReportPeriodic->present != LTE_CQI_ReportPeriodic_PR_NOTHING, "cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_NOTHING!\n");
|
|
AssertFatal(cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present != LTE_CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING,
|
|
"cqi_ReportPeriodic->cqi_FormatIndicatorPeriodic.choice.setup.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING!\n");
|
|
|
|
switch (tmode) {
|
|
case 1:
|
|
case 2:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
no_pmi = 1;
|
|
break;
|
|
|
|
default:
|
|
no_pmi = 0;
|
|
break;
|
|
}
|
|
|
|
if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == LTE_CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_widebandCQI ||
|
|
sched_ctl->feedback_cnt[CC_idP] == 0) {
|
|
// send wideband report every opportunity if wideband reporting mode is selected, else every H opportunities
|
|
if (no_pmi == 1) return 4;
|
|
|
|
if (cc->p_eNB == 2 && ri == 1) return 6;
|
|
|
|
if (cc->p_eNB == 2 && ri == 2) return 8;
|
|
|
|
if (cc->p_eNB == 4 && ri == 1) return 8;
|
|
|
|
if (cc->p_eNB == 4 && ri == 2) return 11;
|
|
|
|
AssertFatal(1 == 0, "illegal combination p %d, ri %d, no_pmi %d\n",
|
|
cc->p_eNB,
|
|
ri,
|
|
no_pmi);
|
|
} else if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == LTE_CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) {
|
|
if (no_pmi == 1 || ri == 1) return (4 + Ltab[cc->mib->message.dl_Bandwidth]);
|
|
|
|
return (7 + Ltab[cc->mib->message.dl_Bandwidth]);
|
|
}
|
|
|
|
AssertFatal(1 == 0, "Shouldn't get here : cqi_ReportPeriodic->present %d\n",
|
|
cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present);
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
fill_nfapi_dl_dci_1A(nfapi_dl_config_request_pdu_t *dl_config_pdu,
|
|
uint8_t aggregation_level,
|
|
uint16_t rnti,
|
|
uint8_t rnti_type,
|
|
uint8_t harq_process,
|
|
uint8_t tpc,
|
|
uint16_t resource_block_coding,
|
|
uint8_t mcs,
|
|
uint8_t ndi,
|
|
uint8_t rv,
|
|
uint8_t vrb_flag)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
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.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 = aggregation_level;
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti;
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = rnti_type;
|
|
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_process;
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = tpc;
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = resource_block_coding;
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs;
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = ndi;
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = rv;
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = vrb_flag;
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
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)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
|
COMMON_channels_t *cc = eNB->common_channels;
|
|
UE_list_t *UE_list = &eNB->UE_list;
|
|
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;
|
|
#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 2, 0))
|
|
struct LTE_PhysicalConfigDedicated__ext2 *ext2 = UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2;
|
|
|
|
if (ext2 &&
|
|
ext2->pucch_ConfigDedicated_v1020 &&
|
|
ext2->pucch_ConfigDedicated_v1020->simultaneousPUCCH_PUSCH_r10 &&
|
|
*ext2->pucch_ConfigDedicated_v1020->simultaneousPUCCH_PUSCH_r10 == LTE_PUCCH_ConfigDedicated_v1020__simultaneousPUCCH_PUSCH_r10_true)
|
|
use_simultaneous_pucch_pusch = 1;
|
|
|
|
#endif
|
|
// pucch1 and pusch feedback is similar, namely in n+k subframes from now
|
|
// This is used in the following "if/else" condition to check if there isn't or is already an UL grant in n+k
|
|
int16_t ul_absSF = get_pucch1_absSF(&cc[CC_idP],
|
|
subframeP + (10 * frameP));
|
|
|
|
if ((ul_config_pdu = has_ul_grant(module_idP,
|
|
CC_idP,
|
|
ul_absSF,
|
|
rnti)) == NULL) {
|
|
// no UL grant so
|
|
// Program ACK/NAK alone Format 1a/b or 3
|
|
ul_req = &eNB->UL_req_tmp[CC_idP][ul_absSF % 10].ul_config_request_body;
|
|
ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus];
|
|
// Do PUCCH
|
|
fill_nfapi_uci_acknak(module_idP,
|
|
CC_idP,
|
|
rnti,
|
|
subframeP + (10 * frameP),
|
|
cce_idx);
|
|
} else {
|
|
/* there is already an existing UL grant so update it if needed
|
|
* on top of some other UL resource (PUSCH,combined SR/CQI/HARQ on PUCCH, etc)
|
|
*/
|
|
switch (ul_config_pdu->pdu_type) {
|
|
/* [ulsch] to [ulsch + harq] or [ulsch + harq on pucch] */
|
|
case NFAPI_UL_CONFIG_ULSCH_PDU_TYPE:
|
|
if (use_simultaneous_pucch_pusch == 1) {
|
|
// Convert it to an NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE
|
|
harq_information = &ul_config_pdu->ulsch_uci_harq_pdu.harq_information;
|
|
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE;
|
|
LOG_D(MAC, "Frame %d, Subframe %d: Switched UCI HARQ to ULSCH UCI HARQ\n",
|
|
frameP,
|
|
subframeP);
|
|
} else {
|
|
// Convert it to an NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE
|
|
ulsch_harq_information = &ul_config_pdu->ulsch_harq_pdu.harq_information;
|
|
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE;
|
|
ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.tl.tag
|
|
= NFAPI_UL_CONFIG_REQUEST_INITIAL_TRANSMISSION_PARAMETERS_REL8_TAG;
|
|
ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.n_srs_initial = 0; // last symbol not punctured
|
|
ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.initial_number_of_resource_blocks
|
|
= ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks; // we don't change the number of resource blocks across retransmissions yet
|
|
LOG_D(MAC,"Frame %d, Subframe %d: Switched UCI HARQ to ULSCH HARQ\n",
|
|
frameP,
|
|
subframeP);
|
|
}
|
|
|
|
break;
|
|
|
|
case NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE:
|
|
AssertFatal(use_simultaneous_pucch_pusch == 0, "Cannot be NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE, simultaneous_pucch_pusch is active");
|
|
break;
|
|
|
|
case NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE:
|
|
AssertFatal(use_simultaneous_pucch_pusch == 1, "Cannot be NFAPI_UL_CONFIG_ULSCH_UCI_PDU_TYPE, simultaneous_pucch_pusch is inactive\n");
|
|
break;
|
|
|
|
/* [ulsch + cqi] to [ulsch + cqi + harq] */
|
|
|
|
case NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE:
|
|
// Convert it to an NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE
|
|
ulsch_harq_information = &ul_config_pdu->ulsch_cqi_harq_ri_pdu.harq_information;
|
|
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE;
|
|
/* TODO: check this - when converting from nfapi_ul_config_ulsch_cqi_ri_pdu to
|
|
* nfapi_ul_config_ulsch_cqi_harq_ri_pdu, shouldn't we copy initial_transmission_parameters
|
|
* from the one to the other?
|
|
* Those two types are not compatible. 'initial_transmission_parameters' is not at the
|
|
* place in both.
|
|
*/
|
|
ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.tl.tag
|
|
= NFAPI_UL_CONFIG_REQUEST_INITIAL_TRANSMISSION_PARAMETERS_REL8_TAG;
|
|
ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.n_srs_initial = 0; // last symbol not punctured
|
|
ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.initial_number_of_resource_blocks
|
|
= ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks; // we don't change the number of resource blocks across retransmissions yet
|
|
break;
|
|
|
|
case NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE:
|
|
AssertFatal(use_simultaneous_pucch_pusch == 0, "Cannot be NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE, simultaneous_pucch_pusch is active\n");
|
|
break;
|
|
|
|
/* [ulsch + cqi on pucch] to [ulsch + cqi on pucch + harq on pucch] */
|
|
|
|
case NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE:
|
|
// convert it to an NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE
|
|
harq_information = &ul_config_pdu->ulsch_csi_uci_harq_pdu.harq_information;
|
|
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE;
|
|
break;
|
|
|
|
case NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE:
|
|
AssertFatal(use_simultaneous_pucch_pusch == 1, "Cannot be NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE, simultaneous_pucch_pusch is inactive\n");
|
|
break;
|
|
|
|
/* [sr] to [sr + harq] */
|
|
|
|
case NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE:
|
|
// convert to NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE
|
|
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE;
|
|
harq_information = &ul_config_pdu->uci_sr_harq_pdu.harq_information;
|
|
break;
|
|
|
|
case NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE:
|
|
/* nothing to do */
|
|
break;
|
|
|
|
/* [cqi] to [cqi + harq] */
|
|
case NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE:
|
|
// convert to NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE
|
|
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE;
|
|
harq_information = &ul_config_pdu->uci_cqi_harq_pdu.harq_information;
|
|
break;
|
|
|
|
case NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE:
|
|
/* nothing to do */
|
|
break;
|
|
|
|
/* [cqi + sr] to [cqr + sr + harq] */
|
|
case NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE:
|
|
// convert to NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE
|
|
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE;
|
|
harq_information = &ul_config_pdu->uci_cqi_sr_harq_pdu.harq_information;
|
|
break;
|
|
|
|
case NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE:
|
|
/* nothing to do */
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ulsch_harq_information) {
|
|
fill_nfapi_ulsch_harq_information(module_idP,
|
|
CC_idP,
|
|
rnti,
|
|
ulsch_harq_information,
|
|
subframeP);
|
|
}
|
|
|
|
if (harq_information) {
|
|
fill_nfapi_harq_information(module_idP,
|
|
CC_idP,
|
|
rnti,
|
|
harq_information,
|
|
cce_idx);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint8_t
|
|
get_V_UL_DAI(module_id_t module_idP,
|
|
int CC_idP,
|
|
uint16_t rntiP,
|
|
sub_frame_t subframeP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
nfapi_hi_dci0_request_body_t *HI_DCI0_req = &RC.mac[module_idP]->HI_DCI0_req[CC_idP][subframeP].hi_dci0_request_body;
|
|
nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_pdu_list[0];
|
|
|
|
for (int i = 0; i < HI_DCI0_req->number_of_dci; i++) {
|
|
if (hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE &&
|
|
hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti == rntiP) {
|
|
return hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.dl_assignment_index;
|
|
}
|
|
}
|
|
|
|
return 4; // this is rule from Section 7.3 in 36.213
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
fill_nfapi_ulsch_harq_information(module_id_t module_idP,
|
|
int CC_idP,
|
|
uint16_t rntiP,
|
|
nfapi_ul_config_ulsch_harq_information *harq_information,
|
|
sub_frame_t subframeP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
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;
|
|
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(physicalConfigDedicated != NULL, "physicalConfigDedicated for rnti %x is null\n",
|
|
rntiP);
|
|
struct LTE_PUSCH_ConfigDedicated *puschConfigDedicated = physicalConfigDedicated->pusch_ConfigDedicated;
|
|
AssertFatal(puschConfigDedicated != NULL, "physicalConfigDedicated->puschConfigDedicated for rnti %x is null\n",
|
|
rntiP);
|
|
#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 2, 0))
|
|
/* if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext2) puschConfigDedicated_v1020 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext2->pusch_ConfigDedicated_v1020;
|
|
#endif
|
|
#if (LTE_RRC_VERSION >= MAKE_VERSION(11, 3, 0))
|
|
if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext4) puschConfigDedicated_v1130 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext4->pusch_ConfigDedicated_v1130;
|
|
#endif
|
|
#if (LTE_RRC_VERSION >= MAKE_VERSION(12, 5, 0))
|
|
if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext5) puschConfigDedicated_v1250 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext5->pusch_ConfigDedicated_v1250;
|
|
#endif
|
|
*/
|
|
#endif
|
|
harq_information_rel10->delta_offset_harq = puschConfigDedicated->betaOffset_ACK_Index;
|
|
harq_information_rel10->tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_HARQ_INFORMATION_REL10_TAG;
|
|
struct LTE_PUCCH_ConfigDedicated *pucch_ConfigDedicated = physicalConfigDedicated->pucch_ConfigDedicated;
|
|
AssertFatal(pucch_ConfigDedicated != NULL, "pucch_ConfigDedicated is null!\n");
|
|
|
|
if (pucch_ConfigDedicated->tdd_AckNackFeedbackMode != NULL &&
|
|
*pucch_ConfigDedicated->tdd_AckNackFeedbackMode == LTE_PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing)
|
|
harq_information_rel10->ack_nack_mode = 1; // multiplexing
|
|
else
|
|
harq_information_rel10->ack_nack_mode = 0; // bundling
|
|
|
|
switch (get_tmode(module_idP, CC_idP, UE_id)) {
|
|
case 1:
|
|
case 2:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
if (cc->tdd_Config == NULL) // FDD
|
|
harq_information_rel10->harq_size = 1;
|
|
else {
|
|
if (harq_information_rel10->ack_nack_mode == 1)
|
|
harq_information_rel10->harq_size = get_V_UL_DAI(module_idP,
|
|
CC_idP,
|
|
rntiP,
|
|
subframeP);
|
|
else
|
|
harq_information_rel10->harq_size = 1;
|
|
}
|
|
break;
|
|
|
|
default: // for any other TM we need 2 bits harq
|
|
if (cc->tdd_Config == NULL) {
|
|
harq_information_rel10->harq_size = 2;
|
|
} else {
|
|
if (harq_information_rel10->ack_nack_mode == 1)
|
|
harq_information_rel10->harq_size = get_V_UL_DAI(module_idP,
|
|
CC_idP,
|
|
rntiP,
|
|
subframeP);
|
|
else
|
|
harq_information_rel10->harq_size = 2;
|
|
}
|
|
break;
|
|
} // get Tmode
|
|
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint8_t
|
|
Np[6][4] = {
|
|
{0, 1, 3, 5},
|
|
{0, 3, 8, 13},
|
|
{0, 5, 13, 22},
|
|
{0, 11, 27, 44},
|
|
{0, 16, 41, 66},
|
|
{0, 22, 55, 88}
|
|
};
|
|
//------------------------------------------------------------------------------
|
|
|
|
// This is part of the PUCCH allocation procedure (see Section 10.1 36.213)
|
|
//------------------------------------------------------------------------------
|
|
uint16_t
|
|
getNp(int dl_Bandwidth,
|
|
uint8_t nCCE,
|
|
uint8_t plus1)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
AssertFatal(dl_Bandwidth < 6, "dl_Bandwidth %d>5\n", dl_Bandwidth);
|
|
|
|
if (nCCE >= Np[dl_Bandwidth][2]) {
|
|
return(Np[dl_Bandwidth][2+plus1]);
|
|
}
|
|
|
|
if (nCCE >= Np[dl_Bandwidth][1]) {
|
|
return(Np[dl_Bandwidth][1+plus1]);
|
|
}
|
|
|
|
return(Np[dl_Bandwidth][0+plus1]);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
fill_nfapi_harq_information(module_id_t module_idP,
|
|
int CC_idP,
|
|
uint16_t rntiP,
|
|
nfapi_ul_config_harq_information *harq_information,
|
|
uint8_t cce_idxP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
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;
|
|
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");
|
|
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;
|
|
struct LTE_PUCCH_ConfigDedicated *pucch_ConfigDedicated = NULL;
|
|
|
|
if (physicalConfigDedicated != NULL) pucch_ConfigDedicated = physicalConfigDedicated->pucch_ConfigDedicated;
|
|
|
|
switch (get_tmode(module_idP,
|
|
CC_idP,
|
|
UE_id)) {
|
|
case 1:
|
|
case 2:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
if (cc->tdd_Config != NULL) {
|
|
// AssertFatal(UE_list->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 &&
|
|
*pucch_ConfigDedicated->tdd_AckNackFeedbackMode == LTE_PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing) {
|
|
harq_information->harq_information_rel10_tdd.harq_size = 2; // 2-bit ACK/NAK
|
|
harq_information->harq_information_rel10_tdd.ack_nack_mode = 1; // multiplexing
|
|
} else {
|
|
harq_information->harq_information_rel10_tdd.harq_size = 1; // 1-bit ACK/NAK
|
|
harq_information->harq_information_rel10_tdd.ack_nack_mode = 0; // bundling
|
|
}
|
|
|
|
harq_information->harq_information_rel10_tdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL10_TDD_TAG;
|
|
harq_information->harq_information_rel10_tdd.n_pucch_1_0
|
|
= getNp(cc->mib->message.dl_Bandwidth, cce_idxP, 0) + cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + cce_idxP;
|
|
harq_information->harq_information_rel10_tdd.number_of_pucch_resources = 1;
|
|
} else {
|
|
harq_information->harq_information_rel9_fdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL9_FDD_TAG;
|
|
harq_information->harq_information_rel9_fdd.number_of_pucch_resources = 1;
|
|
harq_information->harq_information_rel9_fdd.harq_size = 1; // 1-bit ACK/NAK
|
|
harq_information->harq_information_rel9_fdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + cce_idxP;
|
|
}
|
|
|
|
break;
|
|
|
|
default: // for any other TM we need 2 bits harq
|
|
if (cc->tdd_Config != NULL) {
|
|
AssertFatal(pucch_ConfigDedicated != NULL, "pucch_ConfigDedicated is null for TDD!\n");
|
|
|
|
if (pucch_ConfigDedicated->tdd_AckNackFeedbackMode != NULL &&
|
|
*pucch_ConfigDedicated->tdd_AckNackFeedbackMode == LTE_PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing) {
|
|
harq_information->harq_information_rel10_tdd.ack_nack_mode = 1; // multiplexing
|
|
} else {
|
|
harq_information->harq_information_rel10_tdd.ack_nack_mode = 0; // bundling
|
|
}
|
|
|
|
harq_information->harq_information_rel10_tdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL10_TDD_TAG;
|
|
harq_information->harq_information_rel10_tdd.harq_size = 2;
|
|
harq_information->harq_information_rel10_tdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + cce_idxP;
|
|
harq_information->harq_information_rel10_tdd.number_of_pucch_resources = 1;
|
|
} else {
|
|
harq_information->harq_information_rel9_fdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL9_FDD_TAG;
|
|
harq_information->harq_information_rel9_fdd.number_of_pucch_resources = 1;
|
|
harq_information->harq_information_rel9_fdd.ack_nack_mode = 0; // 1a/b
|
|
harq_information->harq_information_rel9_fdd.harq_size = 2;
|
|
harq_information->harq_information_rel9_fdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + cce_idxP;
|
|
}
|
|
|
|
break;
|
|
} // get Tmode
|
|
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint16_t
|
|
fill_nfapi_uci_acknak(module_id_t module_idP,
|
|
int CC_idP,
|
|
uint16_t rntiP,
|
|
uint16_t absSFP,
|
|
uint8_t cce_idxP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
|
COMMON_channels_t *cc = &eNB->common_channels[CC_idP];
|
|
int ackNAK_absSF = get_pucch1_absSF(cc, absSFP);
|
|
nfapi_ul_config_request_t *ul_req = &eNB->UL_req_tmp[CC_idP][ackNAK_absSF % 10];
|
|
nfapi_ul_config_request_body_t *ul_req_body = &ul_req->ul_config_request_body;
|
|
nfapi_ul_config_request_pdu_t *ul_config_pdu = &ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus];
|
|
memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t));
|
|
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE;
|
|
ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_uci_harq_pdu));
|
|
ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG;
|
|
ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.handle = 0; // don't know how to use this
|
|
ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.rnti = rntiP;
|
|
fill_nfapi_harq_information(module_idP,
|
|
CC_idP,
|
|
rntiP,
|
|
&ul_config_pdu->uci_harq_pdu.harq_information,
|
|
cce_idxP);
|
|
LOG_D(MAC, "Filled in UCI HARQ request for rnti %x SF %d.%d acknakSF %d.%d, cce_idxP %d-> n1_pucch %d\n",
|
|
rntiP,
|
|
absSFP / 10,
|
|
absSFP % 10,
|
|
ackNAK_absSF / 10,
|
|
ackNAK_absSF % 10,
|
|
cce_idxP,
|
|
ul_config_pdu->uci_harq_pdu.harq_information.harq_information_rel9_fdd.n_pucch_1_0);
|
|
ul_req_body->number_of_pdus++;
|
|
ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG;
|
|
ul_req->header.message_id = NFAPI_UL_CONFIG_REQUEST;
|
|
ul_req->sfn_sf = (ackNAK_absSF/10) << 4 | ackNAK_absSF%10;
|
|
|
|
return (((ackNAK_absSF / 10) << 4) + (ackNAK_absSF % 10));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
fill_nfapi_dlsch_config(eNB_MAC_INST *eNB,
|
|
nfapi_dl_config_request_body_t *dl_req,
|
|
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,
|
|
uint8_t modulation,
|
|
uint8_t redundancy_version,
|
|
uint8_t transport_blocks,
|
|
uint8_t transport_block_to_codeword_swap_flag,
|
|
uint8_t transmission_scheme,
|
|
uint8_t number_of_layers,
|
|
uint8_t number_of_subbands,
|
|
// uint8_t codebook_index,
|
|
uint8_t ue_category_capacity,
|
|
uint8_t pa,
|
|
uint8_t delta_power_offset_index,
|
|
uint8_t ngap,
|
|
uint8_t nprb,
|
|
uint8_t transmission_mode,
|
|
uint8_t num_bf_prb_per_subband,
|
|
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));
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = length;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = pdu_index;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = rnti;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = resource_allocation_type;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = virtual_resource_block_assignment_flag;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = resource_block_coding;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = modulation;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = redundancy_version;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = transport_blocks;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = transport_block_to_codeword_swap_flag;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = transmission_scheme;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = number_of_layers;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = number_of_subbands;
|
|
// dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = codebook_index;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = ue_category_capacity;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = pa;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = delta_power_offset_index;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = ngap;
|
|
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = nprb;
|
|
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;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint16_t
|
|
fill_nfapi_tx_req(nfapi_tx_request_body_t *tx_req_body,
|
|
uint16_t absSF,
|
|
uint16_t pdu_length,
|
|
int16_t pdu_index,
|
|
uint8_t *pdu)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
nfapi_tx_request_pdu_t *TX_req = &tx_req_body->tx_pdu_list[tx_req_body->number_of_pdus];
|
|
LOG_D(MAC, "Filling TX_req %d for pdu length %d\n",
|
|
tx_req_body->number_of_pdus,
|
|
pdu_length);
|
|
TX_req->pdu_length = pdu_length;
|
|
TX_req->pdu_index = pdu_index;
|
|
TX_req->num_segments = 1;
|
|
TX_req->segments[0].segment_length = pdu_length;
|
|
TX_req->segments[0].segment_data = pdu;
|
|
tx_req_body->tl.tag = NFAPI_TX_REQUEST_BODY_TAG;
|
|
tx_req_body->number_of_pdus++;
|
|
return (((absSF / 10) << 4) + (absSF % 10));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
fill_nfapi_ulsch_config_request_rel8(nfapi_ul_config_request_pdu_t *ul_config_pdu,
|
|
uint8_t cqi_req,
|
|
COMMON_channels_t *cc,
|
|
struct LTE_PhysicalConfigDedicated *physicalConfigDedicated,
|
|
uint8_t tmode,
|
|
uint32_t handle,
|
|
uint16_t rnti,
|
|
uint8_t resource_block_start,
|
|
uint8_t number_of_resource_blocks,
|
|
uint8_t mcs,
|
|
uint8_t cyclic_shift_2_for_drms,
|
|
uint8_t frequency_hopping_enabled_flag,
|
|
uint8_t frequency_hopping_bits,
|
|
uint8_t new_data_indication,
|
|
uint8_t redundancy_version,
|
|
uint8_t harq_process_number,
|
|
uint8_t ul_tx_mode,
|
|
uint8_t current_tx_nb,
|
|
uint8_t n_srs,
|
|
uint16_t size)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
uint8_t ri_size = 0;
|
|
memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t));
|
|
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE;
|
|
ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_pdu));
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL8_TAG;
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = handle;
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = rnti;
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = resource_block_start;
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks = number_of_resource_blocks;
|
|
|
|
if (mcs < 11) ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 2;
|
|
else if (mcs < 21) ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 4;
|
|
else if(mcs < 29) ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 6;
|
|
else ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 0;
|
|
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.cyclic_shift_2_for_drms = cyclic_shift_2_for_drms;
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_enabled_flag = frequency_hopping_enabled_flag;
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_bits = frequency_hopping_bits;
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.new_data_indication = new_data_indication;
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.redundancy_version = redundancy_version;
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.harq_process_number = harq_process_number;
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.ul_tx_mode = ul_tx_mode;
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.current_tx_nb = current_tx_nb;
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.n_srs = n_srs;
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = size;
|
|
|
|
if (cqi_req == 1) {
|
|
// Add CQI portion
|
|
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE;
|
|
ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_cqi_ri_pdu));
|
|
ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL9_TAG;
|
|
ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.report_type = 1;
|
|
ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.number_of_cc = 1;
|
|
LOG_D(MAC, "report_type %d\n",
|
|
ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.report_type);
|
|
|
|
if (cc->p_eNB <= 2 && (tmode == 3 || tmode == 4 || tmode == 8 || tmode == 9 || tmode == 10)) ri_size = 1;
|
|
else if (cc->p_eNB <= 2) ri_size = 0;
|
|
else if (cc->p_eNB == 4) ri_size = 2;
|
|
|
|
ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = ri_size;
|
|
AssertFatal(physicalConfigDedicated->cqi_ReportConfig != NULL,"physicalConfigDedicated->cqi_ReportConfig is null!\n");
|
|
AssertFatal(physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic != NULL,"physicalConfigDedicated->cqi_ReportModeAperiodic is null!\n");
|
|
AssertFatal(physicalConfigDedicated->pusch_ConfigDedicated != NULL,"physicalConfigDedicated->puschConfigDedicated is null!\n");
|
|
nfapi_ul_config_cqi_ri_information_rel9_t *ri_information = &ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9;
|
|
int max_ri = (1 << ri_information->aperiodic_cqi_pmi_ri_report.cc[0].ri_size);
|
|
|
|
for (int ri = 0; ri < max_ri; ri++) {
|
|
ri_information->aperiodic_cqi_pmi_ri_report.cc[0].dl_cqi_pmi_size[ri]
|
|
= get_dl_cqi_pmi_size_pusch(cc,
|
|
tmode,
|
|
1 + ri,
|
|
physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic);
|
|
}
|
|
|
|
ri_information->delta_offset_cqi = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_CQI_Index;
|
|
ri_information->delta_offset_ri = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_RI_Index;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#if (LTE_RRC_VERSION >= MAKE_VERSION(13, 0, 0))
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
fill_nfapi_ulsch_config_request_emtc(nfapi_ul_config_request_pdu_t *ul_config_pdu,
|
|
uint8_t ue_type,
|
|
uint16_t total_number_of_repetitions,
|
|
uint16_t repetition_number,
|
|
uint16_t initial_transmission_sf_io)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
// Re13 fields
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL13_TAG;
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.ue_type = ue_type;
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.total_number_of_repetitions = total_number_of_repetitions;
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.repetition_number = repetition_number;
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.initial_transmission_sf_io = initial_transmission_sf_io;
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
get_numnarrowbands(long dl_Bandwidth)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int nb_tab[6] = { 1, 2, 4, 8, 12, 16 };
|
|
AssertFatal(dl_Bandwidth < 7 || dl_Bandwidth >= 0, "dl_Bandwidth not in [0..6]\n");
|
|
return (nb_tab[dl_Bandwidth]);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
get_numnarrowbandbits(long dl_Bandwidth)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int nbbits_tab[6] = { 0, 1, 2, 3, 4, 4 };
|
|
AssertFatal(dl_Bandwidth < 7 || dl_Bandwidth >= 0, "dl_Bandwidth not in [0..6]\n");
|
|
return (nbbits_tab[dl_Bandwidth]);
|
|
}
|
|
|
|
//This implements the frame/subframe condition for first subframe of MPDCCH transmission (Section 9.1.5 36.213, Rel 13/14)
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
startSF_fdd_RA_times2[8] = { 2, 3, 4, 5, 8, 10, 16, 20 };
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
startSF_tdd_RA[7] = { 1, 2, 4, 5, 8, 10, 20 };
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
mpdcch_sf_condition(eNB_MAC_INST *eNB,
|
|
int CC_id,
|
|
frame_t frameP,
|
|
sub_frame_t subframeP,
|
|
int rmax,
|
|
MPDCCH_TYPES_t mpdcch_type,
|
|
int UE_id)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
struct LTE_PRACH_ConfigSIB_v1310 *ext4_prach = eNB->common_channels[CC_id].radioResourceConfigCommon_BR-> ext4->prach_ConfigCommon_v1310;
|
|
int T;
|
|
LTE_EPDCCH_SetConfig_r11_t *epdcch_setconfig_r11;
|
|
|
|
switch (mpdcch_type) {
|
|
case TYPE0:
|
|
AssertFatal(1 == 0, "MPDCCH Type 0 not handled yet\n");
|
|
break;
|
|
|
|
case TYPE1:
|
|
AssertFatal(1 == 0, "MPDCCH Type 1 not handled yet\n");
|
|
break;
|
|
|
|
case TYPE1A:
|
|
AssertFatal(1 == 0, "MPDCCH Type 1A not handled yet\n");
|
|
break;
|
|
|
|
case TYPE2: // RAR
|
|
AssertFatal(ext4_prach->mpdcch_startSF_CSS_RA_r13 != NULL, "mpdcch_startSF_CSS_RA_r13 is null\n");
|
|
AssertFatal(rmax > 0, "rmax is 0!\b");
|
|
|
|
if (eNB->common_channels[CC_id].tdd_Config == NULL) //FDD
|
|
T = (rmax * startSF_fdd_RA_times2[ext4_prach->mpdcch_startSF_CSS_RA_r13->choice.fdd_r13]) >> 1;
|
|
else //TDD
|
|
T = rmax * startSF_tdd_RA[ext4_prach->mpdcch_startSF_CSS_RA_r13->choice.tdd_r13];
|
|
|
|
break;
|
|
|
|
case TYPE2A:
|
|
AssertFatal(1 == 0, "MPDCCH Type 2A not handled yet\n");
|
|
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];
|
|
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");
|
|
|
|
if (eNB->common_channels[CC_id].tdd_Config == NULL) //FDD
|
|
T = (rmax * startSF_fdd_RA_times2[epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_StartSF_UESS_r13.choice.fdd_r13]) >> 1;
|
|
else //TDD
|
|
T = rmax * startSF_tdd_RA[epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_StartSF_UESS_r13.choice.tdd_r13];
|
|
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
AssertFatal(T > 0, "T is 0!\n");
|
|
|
|
if (((10 * frameP) + subframeP) % T == 0) return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
narrowband_to_first_rb(COMMON_channels_t *cc,
|
|
int nb_index)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
switch (cc->mib->message.dl_Bandwidth) {
|
|
case 0: // 6 PRBs, N_NB=1, i_0=0
|
|
return 0;
|
|
|
|
case 3: // 50 PRBs, N_NB=8, i_0=1
|
|
return (1 + (6 * nb_index));
|
|
|
|
case 5: // 100 PRBs, N_NB=16, i_0=2
|
|
return (2 + (6 * nb_index));
|
|
|
|
case 1: // 15 PRBs N_NB=2, i_0=1
|
|
if (nb_index > 0)
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
case 2: // 25 PRBs, N_NB=4, i_0=0
|
|
if (nb_index > 1)
|
|
return (1 + (6 * nb_index));
|
|
|
|
return ((6 * nb_index));
|
|
|
|
case 4: // 75 PRBs, N_NB=12, i_0=1
|
|
if (nb_index > 5)
|
|
return (2 + (6 * nb_index));
|
|
|
|
return (1 + (6 * nb_index));
|
|
|
|
default:
|
|
AssertFatal(1 == 0, "Impossible dl_Bandwidth %d\n",
|
|
(int) cc->mib->message.dl_Bandwidth);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
init_ue_sched_info(void)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
module_id_t i, j, k;
|
|
|
|
for (i = 0; i < NUMBER_OF_eNB_MAX; i++) {
|
|
for (k = 0; k < MAX_NUM_CCs; k++) {
|
|
for (j = 0; j < MAX_MOBILES_PER_ENB; j++) {
|
|
// init DL
|
|
eNB_dlsch_info[i][k][j].weight = 0;
|
|
eNB_dlsch_info[i][k][j].subframe = 0;
|
|
eNB_dlsch_info[i][k][j].serving_num = 0;
|
|
eNB_dlsch_info[i][k][j].status = S_DL_NONE;
|
|
// init UL
|
|
eNB_ulsch_info[i][k][j].subframe = 0;
|
|
eNB_ulsch_info[i][k][j].serving_num = 0;
|
|
eNB_ulsch_info[i][k][j].status = S_UL_NONE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
unsigned char
|
|
get_ue_weight(module_id_t module_idP,
|
|
int CC_idP,
|
|
int ue_idP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
return (eNB_dlsch_info[module_idP][CC_idP][ue_idP].weight);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
find_UE_id(module_id_t mod_idP,
|
|
rnti_t rntiP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int UE_id;
|
|
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
|
|
|
|
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) {
|
|
return UE_id;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
find_RA_id(module_id_t mod_idP,
|
|
int CC_idP,
|
|
rnti_t rntiP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int RA_id;
|
|
AssertFatal(RC.mac[mod_idP], "RC.mac[%d] is null\n", mod_idP);
|
|
RA_t *ra = (RA_t *) &RC.mac[mod_idP]->common_channels[CC_idP].ra[0];
|
|
|
|
for (RA_id = 0; RA_id < NB_RA_PROC_MAX; RA_id++) {
|
|
LOG_D(MAC, "Checking RA_id %d for %x : state %d\n",
|
|
RA_id,
|
|
rntiP,
|
|
ra[RA_id].state);
|
|
|
|
if (ra[RA_id].state != IDLE && ra[RA_id].rnti == rntiP)
|
|
return RA_id;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
UE_num_active_CC(UE_list_t *listP,
|
|
int ue_idP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
return (listP->numactiveCCs[ue_idP]);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
UE_PCCID(module_id_t mod_idP,
|
|
int ue_idP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
return (RC.mac[mod_idP]->UE_list.pCC_id[ue_idP]);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
rnti_t
|
|
UE_RNTI(module_id_t mod_idP,
|
|
int ue_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,
|
|
ue_idP)][ue_idP].rnti;
|
|
|
|
if (rnti > 0) {
|
|
return (rnti);
|
|
}
|
|
|
|
//LOG_D(MAC, "[eNB %d] Couldn't find RNTI for UE %d\n", mod_idP, ue_idP);
|
|
//display_backtrace();
|
|
return (NOT_A_RNTI);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
boolean_t
|
|
is_UE_active(module_id_t mod_idP,
|
|
int ue_idP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
return (RC.mac[mod_idP]->UE_list.active[ue_idP]);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
unsigned char
|
|
get_aggregation(uint8_t bw_index,
|
|
uint8_t cqi,
|
|
uint8_t dci_fmt)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
unsigned char aggregation = 3;
|
|
|
|
switch (dci_fmt) {
|
|
case format0:
|
|
aggregation = cqi2fmt0_agg[bw_index][cqi];
|
|
break;
|
|
|
|
case format1:
|
|
case format1A:
|
|
case format1B:
|
|
case format1D:
|
|
aggregation = cqi2fmt1x_agg[bw_index][cqi];
|
|
break;
|
|
|
|
case format2:
|
|
case format2A:
|
|
case format2B:
|
|
case format2C:
|
|
case format2D:
|
|
aggregation = cqi2fmt2x_agg[bw_index][cqi];
|
|
break;
|
|
|
|
case format1C:
|
|
case format1E_2A_M10PRB:
|
|
case format3:
|
|
case format3A:
|
|
case format4:
|
|
default:
|
|
LOG_W(MAC, "unsupported DCI format %d\n",
|
|
dci_fmt);
|
|
break;
|
|
}
|
|
|
|
LOG_D(MAC, "Aggregation level %d (cqi %d, bw_index %d, format %d)\n",
|
|
1 << aggregation,
|
|
cqi,
|
|
bw_index,
|
|
dci_fmt);
|
|
return 1 << aggregation;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/*
|
|
* Dump the UL or DL UE_list into LOG_T(MAC)
|
|
*/
|
|
void
|
|
dump_ue_list(UE_list_t *listP,
|
|
int ul_flag)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
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]);
|
|
}
|
|
} 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]);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
add_new_ue(module_id_t mod_idP,
|
|
int cc_idP,
|
|
rnti_t rntiP,
|
|
int harq_pidP
|
|
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
|
|
, uint8_t rach_resource_type
|
|
#endif
|
|
)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
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",
|
|
mod_idP,
|
|
cc_idP,
|
|
rntiP,
|
|
UE_list->avail,
|
|
UE_list->num_UEs);
|
|
dump_ue_list(UE_list, 0);
|
|
|
|
for (i = 0; i < MAX_MOBILES_PER_ENB; i++) {
|
|
if (UE_list->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;
|
|
#if defined(USRP_REC_PLAY) // not specific to record/playback ?
|
|
UE_list->UE_template[cc_idP][UE_id].pre_assigned_mcs_ul = 0;
|
|
#endif
|
|
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
|
|
UE_list->UE_template[cc_idP][UE_id].rach_resource_type = rach_resource_type;
|
|
#endif
|
|
memset((void *) &UE_list->UE_sched_ctrl[UE_id],
|
|
0,
|
|
sizeof(UE_sched_ctrl_t));
|
|
memset((void *) &UE_list->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;
|
|
|
|
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;
|
|
}
|
|
|
|
eNB_ulsch_info[mod_idP][cc_idP][UE_id].status = S_UL_WAITING;
|
|
eNB_dlsch_info[mod_idP][cc_idP][UE_id].status = S_DL_WAITING;
|
|
LOG_D(MAC, "[eNB %d] Add UE_id %d on Primary CC_id %d: rnti %x\n",
|
|
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);
|
|
return -1;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/*
|
|
* Remove MAC context of UE
|
|
*/
|
|
int
|
|
rrc_mac_remove_ue(module_id_t mod_idP,
|
|
rnti_t rntiP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
|
|
int UE_id = find_UE_id(mod_idP, rntiP);
|
|
eNB_UE_STATS *ue_stats = NULL;
|
|
int pCC_id = -1;
|
|
|
|
if (UE_id == -1) {
|
|
LOG_W(MAC,"rrc_mac_remove_ue: UE %x not found\n",
|
|
rntiP);
|
|
return 0;
|
|
}
|
|
|
|
pCC_id = UE_PCCID(mod_idP, UE_id);
|
|
|
|
LOG_I(MAC,"Removing UE %d from Primary CC_id %d (rnti %x)\n",
|
|
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--;
|
|
|
|
/* 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];
|
|
}
|
|
}
|
|
|
|
/* 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];
|
|
ue_stats->total_rbs_used = 0;
|
|
ue_stats->total_rbs_used_retx = 0;
|
|
|
|
for (int j = 0; j < NB_RB_MAX; j++ ) {
|
|
ue_stats->num_pdu_tx[j] = 0;
|
|
ue_stats->num_bytes_tx[j] = 0;
|
|
}
|
|
|
|
ue_stats->num_retransmission = 0;
|
|
ue_stats->total_sdu_bytes = 0;
|
|
ue_stats->total_pdu_bytes = 0;
|
|
ue_stats->total_num_pdus = 0;
|
|
ue_stats->total_rbs_used_rx = 0;
|
|
|
|
for (int j = 0; j < NB_RB_MAX; j++ ) {
|
|
ue_stats->num_pdu_rx[j] = 0;
|
|
ue_stats->num_bytes_rx[j] = 0;
|
|
}
|
|
|
|
ue_stats->num_errors_rx = 0;
|
|
ue_stats->total_pdu_bytes_rx = 0;
|
|
ue_stats->total_num_pdus_rx = 0;
|
|
ue_stats->total_num_errors_rx = 0;
|
|
|
|
eNB_ulsch_info[mod_idP][pCC_id][UE_id].rnti = NOT_A_RNTI;
|
|
eNB_ulsch_info[mod_idP][pCC_id][UE_id].status = S_UL_NONE;
|
|
eNB_ulsch_info[mod_idP][pCC_id][UE_id].serving_num = 0;
|
|
|
|
eNB_dlsch_info[mod_idP][pCC_id][UE_id].rnti = NOT_A_RNTI;
|
|
eNB_dlsch_info[mod_idP][pCC_id][UE_id].status = S_DL_NONE;
|
|
eNB_dlsch_info[mod_idP][pCC_id][UE_id].serving_num = 0;
|
|
|
|
// check if this has an RA process active
|
|
if (find_RA_id(mod_idP,
|
|
pCC_id,
|
|
rntiP) != -1) {
|
|
cancel_ra_proc(mod_idP,
|
|
pCC_id,
|
|
0,
|
|
rntiP);
|
|
}
|
|
|
|
if(rrc_release_info.num_UEs > 0){
|
|
while(pthread_mutex_trylock(&rrc_release_freelist)) {
|
|
/* spin... */
|
|
}
|
|
uint16_t release_total = 0;
|
|
|
|
for (uint16_t release_num = 0; release_num < NUMBER_OF_UE_MAX; release_num++) {
|
|
if (rrc_release_info.RRC_release_ctrl[release_num].flag > 0) {
|
|
release_total++;
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
if (rrc_release_info.RRC_release_ctrl[release_num].rnti == rntiP) {
|
|
rrc_release_info.RRC_release_ctrl[release_num].flag = 0;
|
|
rrc_release_info.num_UEs--;
|
|
release_total--;
|
|
}
|
|
|
|
if (release_total >= rrc_release_info.num_UEs) {
|
|
break;
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&rrc_release_freelist);
|
|
}
|
|
|
|
pthread_mutex_unlock(&rrc_release_freelist);
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/*
|
|
* 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;
|
|
}
|
|
|
|
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_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);
|
|
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
|
|
UE_is_to_be_scheduled(module_id_t module_idP,
|
|
int CC_id,
|
|
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];
|
|
int rrc_status;
|
|
|
|
// do not schedule UE if UL is not working
|
|
if (UE_sched_ctl->ul_failure_timer > 0 || UE_sched_ctl->ul_out_of_sync > 0)
|
|
return 0;
|
|
|
|
rnti_t ue_rnti = UE_RNTI(module_idP, UE_id);
|
|
|
|
LOG_D(MAC, "[eNB %d][PUSCH] Checking UL requirements UE %d/%x\n",
|
|
module_idP,
|
|
UE_id,
|
|
ue_rnti);
|
|
|
|
rrc_status = mac_eNB_get_rrc_status(module_idP, ue_rnti);
|
|
|
|
if (UE_template->scheduled_ul_bytes < UE_template->estimated_ul_buffer ||
|
|
UE_template->ul_SR > 0 || // uplink scheduling request
|
|
(UE_sched_ctl->ul_inactivity_timer > 19 && UE_sched_ctl->ul_scheduled == 0) || // every 2 frames when RRC_CONNECTED
|
|
(UE_sched_ctl->ul_inactivity_timer > 10 &&
|
|
UE_sched_ctl->ul_scheduled == 0 && rrc_status < RRC_CONNECTED) || // every Frame when not RRC_CONNECTED
|
|
(UE_sched_ctl->cqi_req_timer > 300 && rrc_status >= RRC_CONNECTED)) { // cqi req timer expired long ago (do not put too low value)
|
|
LOG_D(MAC, "[eNB %d][PUSCH] UE %d/%x should be scheduled (BSR0 estimated size %d, SR %d)\n",
|
|
module_idP,
|
|
UE_id,
|
|
ue_rnti,
|
|
UE_template->ul_buffer_info[LCGID0],
|
|
UE_template->ul_SR);
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint8_t
|
|
get_tmode(module_id_t module_idP,
|
|
int CC_idP,
|
|
int UE_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;
|
|
|
|
if (physicalConfigDedicated == NULL) { // RRCConnectionSetup not received by UE yet
|
|
AssertFatal(cc->p_eNB <= 2, "p_eNB is %d, should be <2\n",
|
|
cc->p_eNB);
|
|
return (cc->p_eNB);
|
|
}
|
|
|
|
AssertFatal(physicalConfigDedicated->antennaInfo != NULL,
|
|
"antennaInfo (mod_id %d) is null for CCId %d, UEid %d, physicalConfigDedicated %p\n",
|
|
module_idP,
|
|
CC_idP,
|
|
UE_idP,
|
|
physicalConfigDedicated);
|
|
AssertFatal(physicalConfigDedicated->antennaInfo->present != LTE_PhysicalConfigDedicated__antennaInfo_PR_NOTHING,
|
|
"antennaInfo (mod_id %d, CC_id %d) is set to NOTHING\n",
|
|
module_idP,
|
|
CC_idP);
|
|
|
|
if (physicalConfigDedicated->antennaInfo->present == LTE_PhysicalConfigDedicated__antennaInfo_PR_explicitValue) {
|
|
return (1 + physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode);
|
|
}
|
|
|
|
if (physicalConfigDedicated->antennaInfo->present == LTE_PhysicalConfigDedicated__antennaInfo_PR_defaultValue) {
|
|
AssertFatal(cc->p_eNB <= 2, "p_eNB is %d, should be <2\n",
|
|
cc->p_eNB);
|
|
return (cc->p_eNB);
|
|
}
|
|
|
|
AssertFatal(1 == 0, "Shouldn't be here\n");
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int8_t
|
|
get_ULharq(module_id_t module_idP,
|
|
int CC_idP,
|
|
uint16_t frameP,
|
|
uint8_t subframeP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int8_t ret = -1;
|
|
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
|
COMMON_channels_t *cc = &eNB->common_channels[CC_idP];
|
|
|
|
if (cc->tdd_Config == NULL) { // FDD
|
|
ret = (((frameP << 1) + subframeP) & 7);
|
|
} else {
|
|
switch (cc->tdd_Config->subframeAssignment) {
|
|
case 1:
|
|
switch (subframeP) {
|
|
case 2:
|
|
case 3:
|
|
ret = (subframeP - 2);
|
|
break;
|
|
|
|
case 7:
|
|
case 8:
|
|
ret = (subframeP - 5);
|
|
break;
|
|
|
|
default:
|
|
AssertFatal(1 == 0, "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
|
|
subframeP,
|
|
(int) cc->tdd_Config->subframeAssignment);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
AssertFatal((subframeP == 2) || (subframeP == 7), "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
|
|
subframeP,
|
|
(int) cc->tdd_Config->subframeAssignment);
|
|
ret = (subframeP / 7);
|
|
break;
|
|
|
|
case 3:
|
|
AssertFatal((subframeP > 1) && (subframeP < 5), "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
|
|
subframeP,
|
|
(int) cc->tdd_Config->subframeAssignment);
|
|
ret = (subframeP - 2);
|
|
break;
|
|
|
|
case 4:
|
|
AssertFatal((subframeP > 1) && (subframeP < 4), "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
|
|
subframeP,
|
|
(int) cc->tdd_Config->subframeAssignment);
|
|
ret = (subframeP - 2);
|
|
break;
|
|
|
|
case 5:
|
|
AssertFatal(subframeP == 2, "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
|
|
subframeP,
|
|
(int) cc->tdd_Config->subframeAssignment);
|
|
ret = (subframeP - 2);
|
|
break;
|
|
|
|
default:
|
|
AssertFatal(1 == 0, "subframe2_harq_pid, Unsupported TDD mode %d\n",
|
|
(int) cc->tdd_Config->subframeAssignment);
|
|
break;
|
|
}
|
|
}
|
|
|
|
AssertFatal(ret != -1, "invalid harq_pid(%d) at SFN/SF = %d/%d\n", (int8_t) ret,
|
|
frameP,
|
|
subframeP);
|
|
return ret;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint16_t
|
|
getRIV(uint16_t N_RB_DL,
|
|
uint16_t RBstart,
|
|
uint16_t Lcrbs)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
uint16_t RIV;
|
|
|
|
if (Lcrbs <= (1 + (N_RB_DL >> 1)))
|
|
RIV = (N_RB_DL * (Lcrbs - 1)) + RBstart;
|
|
else
|
|
RIV = (N_RB_DL * (N_RB_DL + 1 - Lcrbs)) + (N_RB_DL - 1 - RBstart);
|
|
|
|
return RIV;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint32_t
|
|
allocate_prbs(int UE_id,
|
|
unsigned char nb_rb,
|
|
int N_RB_DL,
|
|
uint32_t *rballoc)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int i;
|
|
uint32_t rballoc_dci = 0;
|
|
unsigned char nb_rb_alloc = 0;
|
|
|
|
for (i = 0; i < (N_RB_DL - 2); i += 2) {
|
|
if (((*rballoc >> i) & 3) == 0) {
|
|
*rballoc |= (3 << i);
|
|
rballoc_dci |= (1 << ((12 - i) >> 1));
|
|
nb_rb_alloc += 2;
|
|
}
|
|
|
|
if (nb_rb_alloc == nb_rb) {
|
|
return (rballoc_dci);
|
|
}
|
|
}
|
|
|
|
if ((N_RB_DL & 1) == 1) {
|
|
if ((*rballoc >> (N_RB_DL - 1) & 1) == 0) {
|
|
*rballoc |= (1 << (N_RB_DL - 1));
|
|
rballoc_dci |= 1;
|
|
}
|
|
}
|
|
|
|
return (rballoc_dci);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
get_bw_index(module_id_t module_id,
|
|
uint8_t CC_id)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int bw_index = 0;
|
|
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
|
|
bw_index = 0;
|
|
break;
|
|
|
|
case 25: // 5HMz
|
|
bw_index = 1;
|
|
break;
|
|
|
|
case 50: // 10HMz
|
|
bw_index = 2;
|
|
break;
|
|
|
|
case 100: // 20HMz
|
|
bw_index = 3;
|
|
break;
|
|
|
|
default:
|
|
bw_index = 1;
|
|
LOG_W(MAC, "[eNB %d] N_RB_DL %d unknown for CC_id %d, setting bw_index to 1\n",
|
|
module_id,
|
|
N_RB_DL,
|
|
CC_id);
|
|
break;
|
|
}
|
|
|
|
return bw_index;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
get_min_rb_unit(module_id_t module_id,
|
|
uint8_t CC_id)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int min_rb_unit = 0;
|
|
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
|
|
min_rb_unit = 1;
|
|
break;
|
|
|
|
case 25: // 5HMz
|
|
min_rb_unit = 2;
|
|
break;
|
|
|
|
case 50: // 10HMz
|
|
min_rb_unit = 3;
|
|
break;
|
|
|
|
case 100: // 20HMz
|
|
min_rb_unit = 4;
|
|
break;
|
|
|
|
default:
|
|
min_rb_unit = 2;
|
|
LOG_W(MAC, "[eNB %d] N_DL_RB %d unknown for CC_id %d, setting min_rb_unit to 2\n",
|
|
module_id,
|
|
N_RB_DL,
|
|
CC_id);
|
|
break;
|
|
}
|
|
|
|
return min_rb_unit;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint32_t
|
|
allocate_prbs_sub(int nb_rb,
|
|
int N_RB_DL,
|
|
int N_RBG,
|
|
uint8_t *rballoc)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int check = 0; //check1=0,check2=0;
|
|
uint32_t rballoc_dci = 0;
|
|
//uint8_t number_of_subbands=13;
|
|
LOG_T(MAC, "*****Check1RBALLOC****: %d%d%d%d (nb_rb %d,N_RBG %d)\n",
|
|
rballoc[3],
|
|
rballoc[2],
|
|
rballoc[1],
|
|
rballoc[0],
|
|
nb_rb,
|
|
N_RBG);
|
|
|
|
while (nb_rb > 0 && check < N_RBG) {
|
|
//printf("rballoc[%d] %d\n",check,rballoc[check]);
|
|
if (rballoc[check] == 1) {
|
|
rballoc_dci |= (1 << ((N_RBG - 1) - check));
|
|
|
|
switch (N_RB_DL) {
|
|
case 6:
|
|
nb_rb--;
|
|
break;
|
|
|
|
case 25:
|
|
if ((check == N_RBG - 1)) {
|
|
nb_rb--;
|
|
} else {
|
|
nb_rb -= 2;
|
|
}
|
|
|
|
break;
|
|
|
|
case 50:
|
|
if ((check == N_RBG - 1)) {
|
|
nb_rb -= 2;
|
|
} else {
|
|
nb_rb -= 3;
|
|
}
|
|
|
|
break;
|
|
|
|
case 100:
|
|
nb_rb -= 4;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// printf("rb_alloc %x\n",rballoc_dci);
|
|
check++;
|
|
// check1 = check1+2;
|
|
}
|
|
|
|
// rballoc_dci = (rballoc_dci)&(0x1fff);
|
|
LOG_T(MAC, "*********RBALLOC : %x\n",
|
|
rballoc_dci);
|
|
// exit(-1);
|
|
return rballoc_dci;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
get_subbandsize(uint8_t dl_Bandwidth)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
uint8_t ss[6] = { 6, 4, 4, 6, 8, 8 };
|
|
AssertFatal(dl_Bandwidth < 6, "dl_Bandwidth %d is out of bounds\n",
|
|
dl_Bandwidth);
|
|
return (ss[dl_Bandwidth]);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
get_nb_subband(int N_RB_DL)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int nb_sb = 0;
|
|
|
|
switch (N_RB_DL) {
|
|
case 6:
|
|
nb_sb = 0;
|
|
break;
|
|
|
|
case 15:
|
|
nb_sb = 4; // sb_size =4
|
|
break;
|
|
|
|
case 25:
|
|
nb_sb = 7; // sb_size =4, 1 sb with 1PRB, 6 with 2 RBG, each has 2 PRBs
|
|
break;
|
|
|
|
case 50: // sb_size =6
|
|
nb_sb = 9;
|
|
break;
|
|
|
|
case 75: // sb_size =8
|
|
nb_sb = 10;
|
|
break;
|
|
|
|
case 100: // sb_size =8 , 1 sb with 1 RBG + 12 sb with 2RBG, each RBG has 4 PRBs
|
|
nb_sb = 13;
|
|
break;
|
|
|
|
default:
|
|
nb_sb = 0;
|
|
break;
|
|
}
|
|
|
|
return nb_sb;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
init_CCE_table(int *CCE_table)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
memset(CCE_table, 0, 800 * sizeof(int));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
get_nCCE_offset(int *CCE_table,
|
|
const unsigned char L,
|
|
const int nCCE,
|
|
const int common_dci,
|
|
const unsigned short rnti,
|
|
const unsigned char subframe)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int search_space_free, m, nb_candidates = 0, l, i;
|
|
unsigned int Yk;
|
|
|
|
/*
|
|
printf("CCE Allocation: ");
|
|
for (i=0;i<nCCE;i++)
|
|
printf("%d.",CCE_table[i]);
|
|
printf("\n");
|
|
*/
|
|
if (common_dci == 1) {
|
|
// check CCE(0 ... L-1)
|
|
nb_candidates = (L == 4) ? 4 : 2;
|
|
nb_candidates = min(nb_candidates, nCCE / L);
|
|
|
|
// printf("Common DCI nb_candidates %d, L %d\n",nb_candidates,L);
|
|
|
|
for (m = nb_candidates - 1; m >= 0; m--) {
|
|
search_space_free = 1;
|
|
|
|
for (l = 0; l < L; l++) {
|
|
// printf("CCE_table[%d] %d\n",(m*L)+l,CCE_table[(m*L)+l]);
|
|
if (CCE_table[(m * L) + l] == 1) {
|
|
search_space_free = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (search_space_free == 1) {
|
|
// printf("returning %d\n",m*L);
|
|
for (l = 0; l < L; l++) {
|
|
CCE_table[(m * L) + l] = 1;
|
|
}
|
|
|
|
return (m * L);
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// Find first available in ue specific search space
|
|
// according to procedure in Section 9.1.1 of 36.213 (v. 8.6)
|
|
// compute Yk
|
|
Yk = (unsigned int) rnti;
|
|
|
|
for (i = 0; i <= subframe; i++) {
|
|
Yk = (Yk * 39827) % 65537;
|
|
}
|
|
|
|
Yk = Yk % (nCCE / L);
|
|
|
|
switch (L) {
|
|
case 1:
|
|
case 2:
|
|
nb_candidates = 6;
|
|
break;
|
|
|
|
case 4:
|
|
case 8:
|
|
nb_candidates = 2;
|
|
break;
|
|
|
|
default:
|
|
DevParam(L,
|
|
nCCE,
|
|
rnti);
|
|
break;
|
|
}
|
|
|
|
LOG_D(MAC, "rnti %x, Yk = %d, nCCE %d (nCCE/L %d),nb_cand %d\n",
|
|
rnti,
|
|
Yk,
|
|
nCCE,
|
|
nCCE / L,
|
|
nb_candidates);
|
|
|
|
for (m = 0; m < nb_candidates; m++) {
|
|
search_space_free = 1;
|
|
|
|
for (l = 0; l < L; l++) {
|
|
int cce = (((Yk + m) % (nCCE / L)) * L) + l;
|
|
|
|
if (cce >= nCCE || CCE_table[cce] == 1) {
|
|
search_space_free = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (search_space_free == 1) {
|
|
for (l = 0; l < L; l++) {
|
|
CCE_table[(((Yk + m) % (nCCE / L)) * L) + l] = 1;
|
|
}
|
|
|
|
return (((Yk + m) % (nCCE / L)) * L);
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
dump_CCE_table(int *CCE_table,
|
|
const int nCCE,
|
|
const unsigned short rnti,
|
|
const int subframe,
|
|
int L)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int nb_candidates = 0, i;
|
|
unsigned int Yk;
|
|
printf("CCE 0: ");
|
|
|
|
for (i = 0; i < nCCE; i++) {
|
|
printf("%1d.", CCE_table[i]);
|
|
|
|
if ((i & 7) == 7)
|
|
printf("\n CCE %d: ",
|
|
i);
|
|
}
|
|
|
|
Yk = (unsigned int) rnti;
|
|
|
|
for (i = 0; i <= subframe; i++) {
|
|
Yk = (Yk * 39827) % 65537;
|
|
}
|
|
|
|
Yk = Yk % (nCCE / L);
|
|
|
|
switch (L) {
|
|
case 1:
|
|
case 2:
|
|
nb_candidates = 6;
|
|
break;
|
|
|
|
case 4:
|
|
case 8:
|
|
nb_candidates = 2;
|
|
break;
|
|
|
|
default:
|
|
DevParam(L, nCCE, rnti);
|
|
break;
|
|
}
|
|
|
|
LOG_I(PHY, "rnti %x, Yk*L = %u, nCCE %d (nCCE/L %d),nb_cand*L %d\n",
|
|
rnti,
|
|
Yk * L,
|
|
nCCE,
|
|
nCCE / L,
|
|
nb_candidates * L);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint16_t
|
|
getnquad(COMMON_channels_t *cc,
|
|
uint8_t num_pdcch_symbols,
|
|
uint8_t mi)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
uint16_t Nreg = 0;
|
|
AssertFatal(cc != NULL, "cc is null\n");
|
|
AssertFatal(cc->mib != NULL, "cc->mib is null\n");
|
|
int N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth);
|
|
int phich_resource = get_phich_resource_times6(cc);
|
|
uint8_t Ngroup_PHICH = (phich_resource * N_RB_DL) / 48;
|
|
|
|
if (((phich_resource * N_RB_DL) % 48) > 0) {
|
|
Ngroup_PHICH++;
|
|
}
|
|
|
|
if (cc->Ncp == 1) {
|
|
Ngroup_PHICH <<= 1;
|
|
}
|
|
|
|
Ngroup_PHICH *= mi;
|
|
|
|
if (num_pdcch_symbols > 0 && num_pdcch_symbols < 4)
|
|
switch (N_RB_DL) {
|
|
case 6:
|
|
Nreg = 12 + (num_pdcch_symbols - 1) * 18;
|
|
break;
|
|
|
|
case 25:
|
|
Nreg = 50 + (num_pdcch_symbols - 1) * 75;
|
|
break;
|
|
|
|
case 50:
|
|
Nreg = 100 + (num_pdcch_symbols - 1) * 150;
|
|
break;
|
|
|
|
case 100:
|
|
Nreg = 200 + (num_pdcch_symbols - 1) * 300;
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
// printf("Nreg %d (%d)\n",Nreg,Nreg - 4 - (3*Ngroup_PHICH));
|
|
return (Nreg - 4 - (3 * Ngroup_PHICH));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint16_t
|
|
getnCCE(COMMON_channels_t *cc,
|
|
uint8_t num_pdcch_symbols,
|
|
uint8_t mi)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
AssertFatal(cc != NULL, "cc is null\n");
|
|
return (getnquad(cc,
|
|
num_pdcch_symbols,
|
|
mi) / 9);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint8_t
|
|
getmi(COMMON_channels_t *cc,
|
|
int subframe)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
AssertFatal(cc != NULL, "cc is null\n");
|
|
|
|
// for FDD
|
|
if (cc->tdd_Config == NULL) // FDD
|
|
return 1;
|
|
|
|
// for TDD
|
|
switch (cc->tdd_Config->subframeAssignment) {
|
|
case 0:
|
|
if (subframe == 0 || subframe == 5) {
|
|
return 2;
|
|
}
|
|
|
|
return 1;
|
|
|
|
case 1:
|
|
if (subframe == 0 || subframe == 5) {
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
|
|
case 2:
|
|
if (subframe == 3 || subframe == 8) {
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
|
|
case 3:
|
|
if (subframe == 0 || subframe == 8 || subframe == 9) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
|
|
case 4:
|
|
if (subframe == 8 || subframe == 9) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
|
|
case 5:
|
|
if (subframe == 8) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
|
|
case 6:
|
|
return 1;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint16_t
|
|
get_nCCE_max(COMMON_channels_t *cc,
|
|
int num_pdcch_symbols,
|
|
int subframe)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
AssertFatal(cc != NULL, "cc is null\n");
|
|
return (getnCCE(cc,
|
|
num_pdcch_symbols,
|
|
getmi(cc,
|
|
subframe)));
|
|
}
|
|
|
|
// Allocate the CCEs
|
|
//------------------------------------------------------------------------------
|
|
int
|
|
allocate_CCEs(int module_idP,
|
|
int CC_idP,
|
|
frame_t frameP,
|
|
sub_frame_t subframeP,
|
|
int test_onlyP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
|
int *CCE_table = eNB->CCE_table[CC_idP];
|
|
nfapi_dl_config_request_body_t *DL_req = &eNB->DL_req[CC_idP].dl_config_request_body;
|
|
nfapi_hi_dci0_request_body_t *HI_DCI0_req = &eNB->HI_DCI0_req[CC_idP][subframeP].hi_dci0_request_body;
|
|
nfapi_dl_config_request_pdu_t *dl_config_pdu = &DL_req->dl_config_pdu_list[0];
|
|
nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_pdu_list[0];
|
|
COMMON_channels_t *cc = &eNB->common_channels[CC_idP];
|
|
int nCCE_max = get_nCCE_max(cc, 1, subframeP);
|
|
int fCCE;
|
|
int i, j, idci;
|
|
int nCCE = 0;
|
|
int max_symbol;
|
|
int ackNAK_absSF = get_pucch1_absSF(cc, (frameP*10+subframeP));
|
|
nfapi_dl_config_request_pdu_t *dl_config_pduLoop;
|
|
nfapi_hi_dci0_request_pdu_t *hi_dci0_pduLoop;
|
|
|
|
if (cc->tdd_Config!=NULL && is_S_sf(cc,subframeP) > 0)
|
|
max_symbol = 2;
|
|
else
|
|
max_symbol = 3;
|
|
|
|
nfapi_ul_config_request_body_t *ul_req = &eNB->UL_req_tmp[CC_idP][ackNAK_absSF % 10].ul_config_request_body;
|
|
LOG_D(MAC, "Allocate CCEs subframe %d, test %d : (DL PDU %d, DL DCI %d, UL %d)\n",
|
|
subframeP,
|
|
test_onlyP,
|
|
DL_req->number_pdu,
|
|
DL_req->number_dci,
|
|
HI_DCI0_req->number_of_dci);
|
|
DL_req->number_pdcch_ofdm_symbols = 1;
|
|
try_again:
|
|
init_CCE_table(CCE_table);
|
|
nCCE = 0;
|
|
|
|
for (i = 0, idci = 0; i < DL_req->number_pdu; i++) {
|
|
dl_config_pduLoop = &dl_config_pdu[i];
|
|
|
|
// allocate DL common DCIs first
|
|
if (dl_config_pduLoop->pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE &&
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type == 2) {
|
|
LOG_D(MAC, "Trying to allocate COMMON DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n",
|
|
idci,
|
|
DL_req->number_dci + HI_DCI0_req->number_of_dci,
|
|
DL_req->number_dci,
|
|
HI_DCI0_req->number_of_dci,
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.rnti,
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,
|
|
nCCE,
|
|
nCCE_max,
|
|
DL_req->number_pdcch_ofdm_symbols);
|
|
|
|
if (nCCE + (dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level) > nCCE_max) {
|
|
if (DL_req->number_pdcch_ofdm_symbols == max_symbol)
|
|
return -1;
|
|
|
|
LOG_D(MAC, "Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n",
|
|
DL_req->number_pdcch_ofdm_symbols);
|
|
DL_req->number_pdcch_ofdm_symbols++;
|
|
nCCE_max = get_nCCE_max(cc, DL_req->number_pdcch_ofdm_symbols, subframeP);
|
|
goto try_again;
|
|
}
|
|
|
|
// number of CCEs left can potentially hold this allocation
|
|
fCCE = get_nCCE_offset(CCE_table,
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,
|
|
nCCE_max,
|
|
1,
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.rnti,
|
|
subframeP);
|
|
|
|
if (fCCE == -1) {
|
|
if (DL_req->number_pdcch_ofdm_symbols == max_symbol) {
|
|
LOG_D(MAC, "subframe %d: Dropping Allocation for RNTI %x\n",
|
|
subframeP,
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.rnti);
|
|
|
|
for (j = 0; j <= i; j++) {
|
|
dl_config_pduLoop = &dl_config_pdu[j];
|
|
|
|
if (dl_config_pduLoop->pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)
|
|
LOG_D(MAC, "DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n",
|
|
j,
|
|
DL_req->number_dci + HI_DCI0_req->number_of_dci,
|
|
DL_req->number_dci,
|
|
HI_DCI0_req->number_of_dci,
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.rnti,
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.dci_format,
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,
|
|
nCCE, nCCE_max, DL_req->number_pdcch_ofdm_symbols);
|
|
}
|
|
|
|
//dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<<dci_alloc->L);
|
|
return -1;
|
|
}
|
|
|
|
LOG_D(MAC, "Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n",
|
|
DL_req->number_pdcch_ofdm_symbols);
|
|
DL_req->number_pdcch_ofdm_symbols++;
|
|
nCCE_max = get_nCCE_max(cc, DL_req->number_pdcch_ofdm_symbols, subframeP);
|
|
goto try_again;
|
|
} // fCCE==-1
|
|
|
|
// the allocation is feasible, rnti rule passes
|
|
nCCE += dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level;
|
|
LOG_D(MAC, "Allocating at nCCE %d\n", fCCE);
|
|
|
|
if ((test_onlyP%2) == 0) {
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.cce_idx = fCCE;
|
|
LOG_D(MAC, "Allocate COMMON DCI CCEs subframe %d, test %d => L %d fCCE %d\n",
|
|
subframeP,
|
|
test_onlyP,
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,
|
|
fCCE);
|
|
}
|
|
|
|
idci++;
|
|
}
|
|
} // for i = 0 ... num_DL_DCIs
|
|
|
|
// now try to allocate UL DCIs
|
|
for (i = 0; i < HI_DCI0_req->number_of_dci + HI_DCI0_req->number_of_hi; i++) {
|
|
hi_dci0_pduLoop = &hi_dci0_pdu[i];
|
|
|
|
// allocate UL DCIs
|
|
if (hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) {
|
|
LOG_D(MAC, "Trying to allocate format 0 DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n",
|
|
idci,
|
|
DL_req->number_dci + HI_DCI0_req->number_of_dci,
|
|
DL_req->number_dci,
|
|
HI_DCI0_req->number_of_dci,
|
|
hi_dci0_pduLoop->dci_pdu.dci_pdu_rel8.rnti,
|
|
hi_dci0_pduLoop->dci_pdu.dci_pdu_rel8.aggregation_level,
|
|
nCCE, nCCE_max,
|
|
DL_req->number_pdcch_ofdm_symbols);
|
|
|
|
if (nCCE + hi_dci0_pduLoop->dci_pdu.dci_pdu_rel8.aggregation_level > nCCE_max) {
|
|
if (DL_req->number_pdcch_ofdm_symbols == max_symbol)
|
|
return -1;
|
|
|
|
LOG_D(MAC, "Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n",
|
|
DL_req->number_pdcch_ofdm_symbols);
|
|
DL_req->number_pdcch_ofdm_symbols++;
|
|
nCCE_max = get_nCCE_max(cc, DL_req->number_pdcch_ofdm_symbols, subframeP);
|
|
goto try_again;
|
|
}
|
|
|
|
// number of CCEs left can potentially hold this allocation
|
|
fCCE = get_nCCE_offset(CCE_table,
|
|
hi_dci0_pduLoop->dci_pdu.dci_pdu_rel8.aggregation_level,
|
|
nCCE_max,
|
|
0,
|
|
hi_dci0_pduLoop->dci_pdu.dci_pdu_rel8.rnti,
|
|
subframeP);
|
|
|
|
if (fCCE == -1) {
|
|
if (DL_req->number_pdcch_ofdm_symbols == max_symbol) {
|
|
LOG_D(MAC, "subframe %d: Dropping Allocation for RNTI %x\n",
|
|
subframeP,
|
|
hi_dci0_pduLoop->dci_pdu.dci_pdu_rel8.rnti);
|
|
|
|
for (j = 0; j <= i; j++) {
|
|
hi_dci0_pduLoop = &hi_dci0_pdu[j];
|
|
|
|
if (hi_dci0_pdu[j].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE)
|
|
LOG_D(MAC, "DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n",
|
|
j,
|
|
DL_req->number_dci + HI_DCI0_req->number_of_dci,
|
|
DL_req->number_dci,
|
|
HI_DCI0_req->number_of_dci,
|
|
hi_dci0_pduLoop->dci_pdu.dci_pdu_rel8.rnti,
|
|
hi_dci0_pduLoop->dci_pdu.dci_pdu_rel8.dci_format,
|
|
hi_dci0_pduLoop->dci_pdu.dci_pdu_rel8.aggregation_level,
|
|
nCCE, nCCE_max, DL_req->number_pdcch_ofdm_symbols);
|
|
}
|
|
|
|
//dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<<dci_alloc->L);
|
|
return -1;
|
|
}
|
|
|
|
LOG_D(MAC, "Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n",
|
|
DL_req->number_pdcch_ofdm_symbols);
|
|
DL_req->number_pdcch_ofdm_symbols++;
|
|
nCCE_max = get_nCCE_max(cc, DL_req->number_pdcch_ofdm_symbols, subframeP);
|
|
goto try_again;
|
|
} // fCCE==-1
|
|
|
|
// the allocation is feasible, rnti rule passes
|
|
nCCE += hi_dci0_pduLoop->dci_pdu.dci_pdu_rel8.aggregation_level;
|
|
LOG_D(MAC, "Allocating at nCCE %d\n",
|
|
fCCE);
|
|
|
|
if ((test_onlyP%2) == 0) {
|
|
hi_dci0_pduLoop->dci_pdu.dci_pdu_rel8.cce_index = fCCE;
|
|
LOG_D(MAC, "Allocate CCEs subframe %d, test %d\n",
|
|
subframeP,
|
|
test_onlyP);
|
|
}
|
|
|
|
idci++;
|
|
}
|
|
} // for i = 0 ... num_UL_DCIs
|
|
|
|
for (i = 0; i < DL_req->number_pdu; i++) {
|
|
dl_config_pduLoop = &dl_config_pdu[i];
|
|
|
|
// allocate DL UE specific DCIs
|
|
if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)
|
|
&& (dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type == 1)) {
|
|
LOG_D(MAC, "Trying to allocate DL UE-SPECIFIC DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n",
|
|
idci,
|
|
DL_req->number_dci + HI_DCI0_req->number_of_dci,
|
|
DL_req->number_dci, HI_DCI0_req->number_of_dci,
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.rnti,
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,
|
|
nCCE,
|
|
nCCE_max,
|
|
DL_req->number_pdcch_ofdm_symbols);
|
|
|
|
if (nCCE + (dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level) > nCCE_max) {
|
|
if (DL_req->number_pdcch_ofdm_symbols == max_symbol)
|
|
return -1;
|
|
|
|
LOG_D(MAC, "Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n",
|
|
DL_req->number_pdcch_ofdm_symbols);
|
|
DL_req->number_pdcch_ofdm_symbols++;
|
|
nCCE_max = get_nCCE_max(cc, DL_req->number_pdcch_ofdm_symbols, subframeP);
|
|
goto try_again;
|
|
}
|
|
|
|
// number of CCEs left can potentially hold this allocation
|
|
fCCE = get_nCCE_offset(CCE_table,
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,
|
|
nCCE_max,
|
|
0,
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.rnti,
|
|
subframeP);
|
|
|
|
if (fCCE == -1) {
|
|
if (DL_req->number_pdcch_ofdm_symbols == max_symbol) {
|
|
LOG_I(MAC, "subframe %d: Dropping Allocation for RNTI %x\n",
|
|
subframeP,
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.rnti);
|
|
|
|
for (j = 0; j <= i; j++) {
|
|
dl_config_pduLoop = &dl_config_pdu[j];
|
|
|
|
if (dl_config_pduLoop->pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)
|
|
LOG_D(MAC, "DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n",
|
|
j,
|
|
DL_req->number_dci + HI_DCI0_req->number_of_dci,
|
|
DL_req->number_dci,
|
|
HI_DCI0_req->number_of_dci,
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.rnti,
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.dci_format,
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,
|
|
nCCE,
|
|
nCCE_max,
|
|
DL_req->number_pdcch_ofdm_symbols);
|
|
}
|
|
|
|
//dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<<dci_alloc->L);
|
|
return -1;
|
|
}
|
|
|
|
LOG_D(MAC, "Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n",
|
|
DL_req->number_pdcch_ofdm_symbols);
|
|
DL_req->number_pdcch_ofdm_symbols++;
|
|
nCCE_max = get_nCCE_max(cc, DL_req->number_pdcch_ofdm_symbols, subframeP);
|
|
goto try_again;
|
|
} // fCCE==-1
|
|
|
|
// the allocation is feasible, rnti rule passes
|
|
nCCE += dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level;
|
|
LOG_D(MAC, "Allocating at nCCE %d\n",
|
|
fCCE);
|
|
|
|
if ((test_onlyP%2) == 0) {
|
|
dl_config_pduLoop->dci_dl_pdu.dci_dl_pdu_rel8.cce_idx = fCCE;
|
|
LOG_D(MAC, "Allocate CCEs subframe %d, test %d\n",
|
|
subframeP,
|
|
test_onlyP);
|
|
}
|
|
|
|
if ((test_onlyP/2) == 1) {
|
|
for(int ack_int = 0; ack_int < ul_req->number_of_pdus; ack_int++) {
|
|
if(((ul_req->ul_config_pdu_list[ack_int].pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE) ||
|
|
(ul_req->ul_config_pdu_list[ack_int].pdu_type == NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE)) &&
|
|
(ul_req->ul_config_pdu_list[ack_int].uci_harq_pdu.ue_information.ue_information_rel8.rnti == dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti)) {
|
|
if (cc->tdd_Config==NULL)
|
|
ul_req->ul_config_pdu_list[ack_int].uci_harq_pdu.harq_information.harq_information_rel9_fdd.n_pucch_1_0 =
|
|
cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + fCCE;
|
|
else
|
|
ul_req->ul_config_pdu_list[ack_int].uci_harq_pdu.harq_information.harq_information_rel10_tdd.n_pucch_1_0 =
|
|
cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + fCCE + getNp(cc->mib->message.dl_Bandwidth,fCCE,0) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
idci++;
|
|
}
|
|
} // for i = 0 ... num_DL_DCIs
|
|
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
nfapi_ul_config_request_pdu_t *
|
|
has_ul_grant(module_id_t module_idP,
|
|
int CC_idP,
|
|
uint16_t absSFP,
|
|
uint16_t rnti)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
nfapi_ul_config_request_body_t *ul_req = &RC.mac[module_idP]->UL_req_tmp[CC_idP][absSFP % 10].ul_config_request_body;
|
|
nfapi_ul_config_request_pdu_t *ul_config_pdu = &ul_req->ul_config_pdu_list[0];
|
|
uint8_t pdu_type;
|
|
LOG_D(MAC, "Checking for rnti %x UL grant in subframeP %d (num pdu %d)\n",
|
|
rnti,
|
|
absSFP % 10,
|
|
ul_req->number_of_pdus);
|
|
|
|
for (int i = 0; i < ul_req->number_of_pdus; i++, ul_config_pdu++) {
|
|
pdu_type = ul_config_pdu->pdu_type;
|
|
LOG_D(MAC, "PDU %d : type %d,rnti %x\n",
|
|
i,
|
|
pdu_type,
|
|
rnti);
|
|
|
|
if (pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE && ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)
|
|
return ul_config_pdu;
|
|
|
|
if (pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE && ul_config_pdu->ulsch_cqi_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)
|
|
return ul_config_pdu;
|
|
|
|
if (pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE && ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)
|
|
return ul_config_pdu;
|
|
|
|
if (pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE && ul_config_pdu->ulsch_cqi_harq_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)
|
|
return ul_config_pdu;
|
|
|
|
if (pdu_type == NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE && ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti == rnti)
|
|
return ul_config_pdu;
|
|
|
|
if (pdu_type == NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE && ul_config_pdu->uci_sr_pdu.ue_information.ue_information_rel8.rnti == rnti)
|
|
return ul_config_pdu;
|
|
|
|
if (pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE && ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.rnti == rnti)
|
|
return ul_config_pdu;
|
|
|
|
if (pdu_type == NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE && ul_config_pdu->uci_sr_harq_pdu.ue_information.ue_information_rel8.rnti == rnti)
|
|
return ul_config_pdu;
|
|
|
|
if (pdu_type == NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE && ul_config_pdu->uci_cqi_harq_pdu.ue_information.ue_information_rel8.rnti == rnti)
|
|
return ul_config_pdu;
|
|
|
|
if (pdu_type == NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE && ul_config_pdu->uci_cqi_sr_pdu.ue_information.ue_information_rel8.rnti == rnti)
|
|
return ul_config_pdu;
|
|
|
|
if (pdu_type == NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE && ul_config_pdu->uci_cqi_sr_harq_pdu.ue_information.ue_information_rel8.rnti == rnti)
|
|
return ul_config_pdu;
|
|
|
|
if (pdu_type == NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE && ul_config_pdu->ulsch_uci_csi_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)
|
|
return ul_config_pdu;
|
|
|
|
if (pdu_type == NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE && ul_config_pdu->ulsch_uci_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)
|
|
return ul_config_pdu;
|
|
|
|
if (pdu_type == NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE && ul_config_pdu->ulsch_csi_uci_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)
|
|
return ul_config_pdu;
|
|
}
|
|
|
|
return (NULL); // no ul grant at all for this UE
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
boolean_t
|
|
CCE_allocation_infeasible(int module_idP,
|
|
int CC_idP,
|
|
int format_flag,
|
|
int subframe,
|
|
int aggregation,
|
|
int rnti)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
nfapi_dl_config_request_body_t *DL_req = &RC.mac[module_idP]->DL_req[CC_idP].dl_config_request_body;
|
|
nfapi_dl_config_request_pdu_t *dl_config_pdu = &DL_req->dl_config_pdu_list[DL_req->number_pdu];
|
|
nfapi_hi_dci0_request_body_t *HI_DCI0_req = &RC.mac[module_idP]->HI_DCI0_req[CC_idP][subframe].hi_dci0_request_body;
|
|
nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_pdu_list[HI_DCI0_req->number_of_dci + HI_DCI0_req->number_of_hi];
|
|
boolean_t res = TRUE;
|
|
|
|
if (format_flag != 2) { // DL DCI
|
|
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);
|
|
} else {
|
|
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 = (format_flag == 0) ? 2 : 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 %d : (%x,%d) \n",
|
|
subframe, format_flag, rnti, aggregation);
|
|
|
|
if (allocate_CCEs(module_idP, CC_idP, 0, subframe, 0) != -1)
|
|
res = FALSE;
|
|
|
|
DL_req->number_pdu--;
|
|
}
|
|
} else { // ue-specific UL DCI
|
|
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);
|
|
} else {
|
|
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++;
|
|
|
|
if (allocate_CCEs(module_idP, CC_idP, 0, subframe, 0) != -1)
|
|
res = FALSE;
|
|
|
|
HI_DCI0_req->number_of_dci--;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
get_retransmission_timing(LTE_TDD_Config_t *tdd_Config,
|
|
frame_t *frameP,
|
|
sub_frame_t *subframeP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
if (tdd_Config == NULL) {
|
|
if (*subframeP > 1) {
|
|
*frameP = (*frameP + 1) % 1024;
|
|
}
|
|
|
|
*subframeP = (*subframeP + 8) % 10;
|
|
} else {
|
|
switch (tdd_Config->subframeAssignment) { //TODO fill in other TDD configs
|
|
default:
|
|
printf("%s:%d: TODO\n",
|
|
__FILE__,
|
|
__LINE__);
|
|
abort();
|
|
break;
|
|
|
|
case 1:
|
|
if (*subframeP == 0 || *subframeP == 5) {
|
|
*subframeP += 19;
|
|
*frameP = (*frameP + (*subframeP / 10)) % 1024;
|
|
*subframeP %= 10;
|
|
} else if (*subframeP == 4 || *subframeP == 9) {
|
|
*subframeP += 16;
|
|
*frameP = (*frameP + (*subframeP / 10)) % 1024;
|
|
*subframeP %= 10;
|
|
} else {
|
|
AssertFatal(2 == 1, "Illegal dl subframe %d for tdd config %ld\n",
|
|
*subframeP,
|
|
tdd_Config->subframeAssignment);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint8_t
|
|
get_dl_subframe_count(int tdd_config_sfa,
|
|
sub_frame_t subframeP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
uint8_t tdd1[10] = {1, -1, -1, -1, 2, 3, -1, -1, -1, 4}; // special subframes 1,6 are excluded
|
|
|
|
switch (tdd_config_sfa) {// TODO fill in other tdd configs
|
|
case 1:
|
|
return tdd1[subframeP];
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint8_t
|
|
frame_subframe2_dl_harq_pid(LTE_TDD_Config_t *tdd_Config,
|
|
int abs_frameP,
|
|
sub_frame_t subframeP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int harq_pid;
|
|
uint8_t count;
|
|
|
|
if (tdd_Config) {
|
|
switch(tdd_Config->subframeAssignment) { //TODO fill in other tdd config
|
|
case 1:
|
|
count = get_dl_subframe_count(tdd_Config->subframeAssignment,
|
|
subframeP);
|
|
harq_pid = (((frame_cnt * 1024 + abs_frameP) * 4) - 1 + count) % 7;//4 dl subframe in a frame
|
|
|
|
if (harq_pid < 0) {
|
|
harq_pid += 7;
|
|
}
|
|
|
|
LOG_D(MAC,"[frame_subframe2_dl_harq_pid] (%d,%d) calculate harq_pid ((( %d * 1024 + %d) *4) - 1 + %d) = %d \n",
|
|
(abs_frameP + 1024) % 1024,
|
|
subframeP,
|
|
frame_cnt,
|
|
abs_frameP,
|
|
count,
|
|
harq_pid);
|
|
return harq_pid;
|
|
}
|
|
} else {
|
|
return ((abs_frameP * 10) + subframeP) & 7;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
unsigned char
|
|
ul_ACK_subframe2M(LTE_TDD_Config_t *tdd_Config,
|
|
unsigned char subframe)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
if (tdd_Config == NULL) {
|
|
return 1;
|
|
}
|
|
|
|
switch (tdd_Config->subframeAssignment) {
|
|
case 1:
|
|
return 1; // don't ACK special subframe for now
|
|
|
|
/*
|
|
if (subframe == 2) { // ACK subframes 5 and 6
|
|
return(2);
|
|
} else if (subframe == 3) { // ACK subframe 9
|
|
return(1); // To be updated
|
|
} else if (subframe == 7) { // ACK subframes 0 and 1
|
|
return(2); // To be updated
|
|
} else if (subframe == 8) { // ACK subframe 4
|
|
return(1); // To be updated
|
|
} else {
|
|
AssertFatal(1==0,"illegal subframe %d for tdd_config %ld\n",
|
|
subframe,tdd_Config->subframeAssignment);
|
|
}
|
|
break;
|
|
*/
|
|
case 3:
|
|
if (subframe == 2) { // ACK subframes 5 and 6
|
|
return 2; // should be 3
|
|
}
|
|
|
|
if (subframe == 3) { // ACK subframes 7 and 8
|
|
return 2; // To be updated
|
|
}
|
|
|
|
if (subframe == 4) { // ACK subframes 9 and 0
|
|
return 2;
|
|
}
|
|
|
|
AssertFatal(1==0,"illegal subframe %d for tdd_config %ld\n",
|
|
subframe,
|
|
tdd_Config->subframeAssignment);
|
|
break;
|
|
|
|
case 4:
|
|
if (subframe == 2) { // ACK subframes 0,4 and 5
|
|
return 3; // should be 4
|
|
}
|
|
|
|
if (subframe == 3) { // ACK subframes 6,7,8 and 9
|
|
return 4;
|
|
}
|
|
|
|
AssertFatal(1==0,"illegal subframe %d for tdd_config %ld\n",
|
|
subframe,
|
|
tdd_Config->subframeAssignment);
|
|
break;
|
|
|
|
case 5:
|
|
if (subframe == 2) { // ACK subframes 0,3,4,5,6,7,8 and 9
|
|
return 8; // should be 3
|
|
}
|
|
|
|
AssertFatal(1==0,"illegal subframe %d for tdd_config %ld\n",
|
|
subframe,
|
|
tdd_Config->subframeAssignment);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
unsigned char
|
|
ul_ACK_subframe2dl_subframe(LTE_TDD_Config_t *tdd_Config,
|
|
unsigned char subframe,
|
|
unsigned char ACK_index)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
if (tdd_Config == NULL) {
|
|
return ((subframe < 4) ? subframe + 6 : subframe - 4);
|
|
}
|
|
|
|
switch (tdd_Config->subframeAssignment) {
|
|
case 3:
|
|
if (subframe == 2) { // ACK subframes 5 and 6
|
|
if (ACK_index == 2) return 1;
|
|
|
|
return (5 + ACK_index);
|
|
}
|
|
|
|
if (subframe == 3) { // ACK subframes 7 and 8
|
|
return (7 + ACK_index); // To be updated
|
|
}
|
|
|
|
if (subframe == 4) { // ACK subframes 9 and 0
|
|
return ((9 + ACK_index) % 10);
|
|
}
|
|
|
|
AssertFatal(1==0, "illegal subframe %d for tdd_config->subframeAssignment %ld\n",
|
|
subframe,
|
|
tdd_Config->subframeAssignment);
|
|
break;
|
|
|
|
case 4:
|
|
if (subframe == 2) { // ACK subframes 0, 4 and 5
|
|
//if (ACK_index==2)
|
|
// return(1); TBC
|
|
if (ACK_index == 2) return 0;
|
|
|
|
return (4 + ACK_index);
|
|
}
|
|
|
|
if (subframe == 3) { // ACK subframes 6, 7 8 and 9
|
|
return (6 + ACK_index); // To be updated
|
|
}
|
|
|
|
AssertFatal(1 == 0, "illegal subframe %d for tdd_config %ld\n",
|
|
subframe,
|
|
tdd_Config->subframeAssignment);
|
|
break;
|
|
|
|
case 1:
|
|
if (subframe == 2) { // ACK subframes 5 and 6
|
|
return (5 + ACK_index);
|
|
}
|
|
|
|
if (subframe == 3) { // ACK subframe 9
|
|
return 9; // To be updated
|
|
}
|
|
|
|
if (subframe == 7) { // ACK subframes 0 and 1
|
|
return ACK_index; // To be updated
|
|
}
|
|
|
|
if (subframe == 8) { // ACK subframe 4
|
|
return 4; // To be updated
|
|
}
|
|
|
|
AssertFatal(1 == 0, "illegal subframe %d for tdd_config %ld\n",
|
|
subframe,
|
|
tdd_Config->subframeAssignment);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
extract_harq(module_id_t mod_idP,
|
|
int CC_idP,
|
|
int UE_id,
|
|
frame_t frameP,
|
|
sub_frame_t subframeP,
|
|
void *harq_indication,
|
|
int format)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
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];
|
|
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 spatial_bundling = 0;
|
|
int tmode[5];
|
|
int i, j, m;
|
|
uint8_t *pdu;
|
|
sub_frame_t subframe_tx;
|
|
int frame_tx;
|
|
uint8_t harq_pid;
|
|
#if (LTE_RRC_VERSION >= MAKE_VERSION(13, 0, 0))
|
|
LTE_PhysicalConfigDedicated_t *physicalConfigDedicated = UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated;
|
|
|
|
if (physicalConfigDedicated != NULL && physicalConfigDedicated->pucch_ConfigDedicated != NULL &&
|
|
physicalConfigDedicated->ext7 != NULL && physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13 != NULL &&
|
|
((physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13->spatialBundlingPUCCH_r13 && format == 0) ||
|
|
(physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13->spatialBundlingPUSCH_r13 && format == 1))) {
|
|
spatial_bundling = 1;
|
|
}
|
|
|
|
#endif
|
|
|
|
for (i = 0; i < numCC; i++) {
|
|
tmode[i] = get_tmode(mod_idP,
|
|
i,
|
|
UE_id);
|
|
}
|
|
|
|
if (cc->tdd_Config) {
|
|
harq_indication_tdd = (nfapi_harq_indication_tdd_rel13_t *) harq_indication;
|
|
// pdu = &harq_indication_tdd->harq_tb_n[0];
|
|
num_ack_nak = harq_indication_tdd->number_of_ack_nack;
|
|
|
|
switch (harq_indication_tdd->mode) {
|
|
case 0: // Format 1a/b bundling
|
|
AssertFatal(numCC == 1, "numCC %d > 1, should not be using Format1a/b\n",
|
|
numCC);
|
|
int M = ul_ACK_subframe2M(cc->tdd_Config,
|
|
subframeP);
|
|
|
|
for (m=0; m<M; m++) {
|
|
subframe_tx = ul_ACK_subframe2dl_subframe(cc->tdd_Config,
|
|
subframeP,
|
|
m);
|
|
|
|
if (frameP==1023&&subframeP>5) frame_tx=-1;
|
|
else frame_tx = subframeP < 4 ? frameP -1 : frameP;
|
|
|
|
harq_pid = frame_subframe2_dl_harq_pid(cc->tdd_Config,
|
|
frame_tx,
|
|
subframe_tx);
|
|
RA_t *ra = &eNB->common_channels[CC_idP].ra[0];
|
|
|
|
if(num_ack_nak == 1) {
|
|
if (harq_indication_tdd->harq_data[0].bundling.value_0 == 1) { //ack
|
|
sched_ctl->round[CC_idP][harq_pid] = 8; // release HARQ process
|
|
sched_ctl->tbcnt[CC_idP][harq_pid] = 0;
|
|
LOG_D(MAC, "frame %d subframe %d Acking (%d,%d) harq_pid %d round %d\n",
|
|
frameP,
|
|
subframeP,
|
|
frame_tx,
|
|
subframe_tx,
|
|
harq_pid,
|
|
sched_ctl->round[CC_idP][harq_pid]);
|
|
} else { //nack
|
|
if (sched_ctl->round[CC_idP][harq_pid] < 8) sched_ctl->round[CC_idP][harq_pid]++;
|
|
|
|
if (sched_ctl->round[CC_idP][harq_pid] == 4) {
|
|
sched_ctl->round[CC_idP][harq_pid] = 8; // release HARQ process
|
|
sched_ctl->tbcnt[CC_idP][harq_pid] = 0;
|
|
}
|
|
|
|
LOG_D(MAC,"frame %d subframe %d Nacking (%d,%d) harq_pid %d round %d\n",
|
|
frameP,
|
|
subframeP,
|
|
frame_tx,
|
|
subframe_tx,
|
|
harq_pid,
|
|
sched_ctl->round[CC_idP][harq_pid]);
|
|
|
|
if (sched_ctl->round[CC_idP][harq_pid] == 8) {
|
|
for (uint8_t ra_i = 0; ra_i < NB_RA_PROC_MAX; ra_i++) {
|
|
if (ra[ra_i].rnti == rnti && ra[ra_i].state == WAITMSG4ACK) {
|
|
//Msg NACK num to MAC ,remove UE
|
|
// add UE info to freeList
|
|
LOG_I(RRC, "put UE %x into freeList\n",
|
|
rnti);
|
|
put_UE_in_freelist(mod_idP,
|
|
rnti,
|
|
1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (uint8_t ra_i = 0; ra_i < NB_RA_PROC_MAX; ra_i++) {
|
|
if (ra[ra_i].rnti == rnti && ra[ra_i].state == MSGCRNTI_ACK && ra[ra_i].crnti_harq_pid == harq_pid) {
|
|
LOG_D(MAC,"CRNTI Reconfiguration: ACK %d rnti %x round %d frame %d subframe %d \n",
|
|
harq_indication_tdd->harq_data[0].bundling.value_0,
|
|
rnti,
|
|
sched_ctl->round[CC_idP][harq_pid],
|
|
frameP,
|
|
subframeP);
|
|
|
|
if (num_ack_nak == 1 && harq_indication_tdd->harq_data[0].bundling.value_0 == 1) {
|
|
cancel_ra_proc(mod_idP,
|
|
CC_idP,
|
|
frameP,
|
|
ra[ra_i].rnti);
|
|
} else {
|
|
if(sched_ctl->round[CC_idP][harq_pid] == 7) {
|
|
cancel_ra_proc(mod_idP,
|
|
CC_idP,
|
|
frameP,
|
|
ra[ra_i].rnti);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 1: // Channel Selection
|
|
case 2: // Format 3
|
|
case 3: // Format 4
|
|
case 4: // Format 5
|
|
break;
|
|
}
|
|
} else {
|
|
harq_indication_fdd = (nfapi_harq_indication_fdd_rel13_t *) harq_indication;
|
|
num_ack_nak = harq_indication_fdd->number_of_ack_nack;
|
|
pdu = &harq_indication_fdd->harq_tb_n[0];
|
|
harq_pid = ((10 * frameP) + subframeP + 10236) & 7;
|
|
LOG_D(MAC, "frame %d subframe %d harq_pid %d mode %d tmode[0] %d num_ack_nak %d round %d\n",
|
|
frameP,
|
|
subframeP,
|
|
harq_pid,
|
|
harq_indication_fdd->mode,
|
|
tmode[0],
|
|
num_ack_nak,
|
|
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;
|
|
|
|
switch (harq_indication_fdd->mode) {
|
|
case 0: // Format 1a/b (10.1.2.1)
|
|
AssertFatal(numCC == 1, "numCC %d > 1, should not be using Format1a/b\n",
|
|
numCC);
|
|
|
|
if (tmode[0] == 1 || tmode[0] == 2 || tmode[0] == 5 || tmode[0] == 6 || tmode[0] == 7) { // NOTE: have to handle the case of TM9-10 with 1 antenna port
|
|
// single ACK/NAK bit
|
|
AssertFatal(num_ack_nak == 1, "num_ack_nak %d > 1 for 1 CC and single-layer transmission frame:%d subframe:%d\n",
|
|
num_ack_nak,
|
|
frameP,
|
|
subframeP);
|
|
|
|
// In case of nFAPI, sometimes timing of eNB and UE become different.
|
|
// So if nfapi_mode == 2(VNF), this function don't check assertion to avoid process exit.
|
|
if (NFAPI_MODE != NFAPI_MODE_VNF) {
|
|
AssertFatal(sched_ctl->round[CC_idP][harq_pid] < 8, "Got ACK/NAK for inactive harq_pid %d for UE %d/%x\n",
|
|
harq_pid,
|
|
UE_id,
|
|
rnti);
|
|
} else {
|
|
if (sched_ctl->round[CC_idP][harq_pid] == 8) {
|
|
LOG_E(MAC,"Got ACK/NAK for inactive harq_pid %d for UE %d/%x\n",
|
|
harq_pid,
|
|
UE_id,
|
|
rnti);
|
|
return;
|
|
}
|
|
}
|
|
|
|
AssertFatal(pdu[0] == 1 || pdu[0] == 2 || pdu[0] == 4, "Received ACK/NAK %d which is not 1 or 2 for harq_pid %d from UE %d/%x\n",
|
|
pdu[0],
|
|
harq_pid,
|
|
UE_id,
|
|
rnti);
|
|
LOG_D(MAC, "Received %d for harq_pid %d\n",
|
|
pdu[0],
|
|
harq_pid);
|
|
RA_t *ra = &eNB->common_channels[CC_idP].ra[0];
|
|
|
|
for (uint8_t ra_i = 0; ra_i < NB_RA_PROC_MAX; ra_i++) {
|
|
if (ra[ra_i].rnti == rnti && ra[ra_i].state == MSGCRNTI_ACK && ra[ra_i].crnti_harq_pid == harq_pid) {
|
|
LOG_D(MAC,"CRNTI Reconfiguration: ACK %d rnti %x round %d frame %d subframe %d \n",
|
|
pdu[0],
|
|
rnti,
|
|
sched_ctl->round[CC_idP][harq_pid],
|
|
frameP,
|
|
subframeP);
|
|
|
|
if (pdu[0] == 1) {
|
|
cancel_ra_proc(mod_idP,
|
|
CC_idP,
|
|
frameP,
|
|
ra[ra_i].rnti);
|
|
} else {
|
|
if (sched_ctl->round[CC_idP][harq_pid] == 7) {
|
|
cancel_ra_proc(mod_idP,
|
|
CC_idP,
|
|
frameP,
|
|
ra[ra_i].rnti);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
LOG_D(MAC, "In extract_harq(): pdu[0] = %d for harq_pid = %d\n", pdu[0], harq_pid);
|
|
|
|
if (pdu[0] == 1) { // ACK
|
|
sched_ctl->round[CC_idP][harq_pid] = 8; // release HARQ process
|
|
sched_ctl->tbcnt[CC_idP][harq_pid] = 0;
|
|
|
|
/* CDRX: PUCCH gives an ACK, so reset corresponding HARQ RTT */
|
|
sched_ctl->harq_rtt_timer[CC_idP][harq_pid] = 0;
|
|
|
|
} else if (pdu[0] == 2 || pdu[0] == 4) { // NAK (treat DTX as NAK)
|
|
sched_ctl->round[CC_idP][harq_pid]++; // increment round
|
|
|
|
if (sched_ctl->round[CC_idP][harq_pid] == 4) {
|
|
sched_ctl->round[CC_idP][harq_pid] = 8; // release HARQ process
|
|
sched_ctl->tbcnt[CC_idP][harq_pid] = 0;
|
|
|
|
/* CDRX: PUCCH gives an NACK and max number of repetitions reached so reset corresponding HARQ RTT */
|
|
sched_ctl->harq_rtt_timer[CC_idP][harq_pid] = 0;
|
|
}
|
|
|
|
if (sched_ctl->round[CC_idP][harq_pid] == 8) {
|
|
for (uint8_t ra_i = 0; ra_i < NB_RA_PROC_MAX; ra_i++) {
|
|
if((ra[ra_i].rnti == rnti) && (ra[ra_i].state == WAITMSG4ACK)) {
|
|
// Msg NACK num to MAC ,remove UE
|
|
// add UE info to freeList
|
|
LOG_I(RRC, "put UE %x into freeList\n",
|
|
rnti);
|
|
put_UE_in_freelist(mod_idP,
|
|
rnti,
|
|
1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// one or two ACK/NAK bits
|
|
AssertFatal(num_ack_nak <= 2, "num_ack_nak %d > 2 for 1 CC and TM3/4/8/9/10\n",
|
|
num_ack_nak);
|
|
|
|
if (num_ack_nak == 2 && sched_ctl->round[CC_idP][harq_pid] < 8 && sched_ctl->tbcnt[CC_idP][harq_pid] == 1 && pdu[0] == 1 && pdu[1] == 1) {
|
|
sched_ctl->round[CC_idP][harq_pid] = 8;
|
|
sched_ctl->tbcnt[CC_idP][harq_pid] = 0;
|
|
|
|
/* CDRX: PUCCH gives an ACK, so reset corresponding HARQ RTT */
|
|
sched_ctl->harq_rtt_timer[CC_idP][harq_pid] = 0;
|
|
}
|
|
|
|
if ((num_ack_nak == 2)
|
|
&& (sched_ctl->round[CC_idP][harq_pid] < 8)
|
|
&& (sched_ctl->tbcnt[CC_idP][harq_pid] == 1)
|
|
&& (pdu[0] == 2) && (pdu[1] == 2)) {
|
|
sched_ctl->round[CC_idP][harq_pid]++;
|
|
|
|
if (sched_ctl->round[CC_idP][harq_pid] == 4) {
|
|
sched_ctl->round[CC_idP][harq_pid] = 8; // release HARQ process
|
|
sched_ctl->tbcnt[CC_idP][harq_pid] = 0;
|
|
|
|
/* CDRX: PUCCH gives an NACK and max number of repetitions reached so reset corresponding HARQ RTT */
|
|
sched_ctl->harq_rtt_timer[CC_idP][harq_pid] = 0;
|
|
}
|
|
} else if (((num_ack_nak == 2)
|
|
&& (sched_ctl->round[CC_idP][harq_pid] < 8)
|
|
&& (sched_ctl->tbcnt[0][harq_pid] == 2)
|
|
&& (pdu[0] == 1) && (pdu[1] == 2))
|
|
|| ((num_ack_nak == 2)
|
|
&& (sched_ctl->round[CC_idP][harq_pid] < 8)
|
|
&& (sched_ctl->tbcnt[CC_idP][harq_pid] == 2)
|
|
&& (pdu[0] == 2) && (pdu[1] == 1))) {
|
|
sched_ctl->round[CC_idP][harq_pid]++;
|
|
sched_ctl->tbcnt[CC_idP][harq_pid] = 1;
|
|
|
|
if (sched_ctl->round[CC_idP][harq_pid] == 4) {
|
|
sched_ctl->round[CC_idP][harq_pid] = 8; // release HARQ process
|
|
sched_ctl->tbcnt[CC_idP][harq_pid] = 0; /* TODO: do we have to set it to 0? */
|
|
|
|
/* CDRX: PUCCH gives an NACK and max number of repetitions reached so reset corresponding HARQ RTT */
|
|
sched_ctl->harq_rtt_timer[CC_idP][harq_pid] = 0;
|
|
}
|
|
} else if ((num_ack_nak == 2)
|
|
&& (sched_ctl->round[CC_idP][harq_pid] < 8)
|
|
&& (sched_ctl->tbcnt[CC_idP][harq_pid] == 2)
|
|
&& (pdu[0] == 2) && (pdu[1] == 2)) {
|
|
sched_ctl->round[CC_idP][harq_pid]++;
|
|
|
|
if (sched_ctl->round[CC_idP][harq_pid] == 4) {
|
|
sched_ctl->round[CC_idP][harq_pid] = 8; // release HARQ process
|
|
sched_ctl->tbcnt[CC_idP][harq_pid] = 0;
|
|
|
|
/* CDRX: PUCCH gives an NACK and max number of repetitions reached so reset corresponding HARQ RTT */
|
|
sched_ctl->harq_rtt_timer[CC_idP][harq_pid] = 0;
|
|
}
|
|
} else
|
|
AssertFatal(1 == 0, "Illegal ACK/NAK/round combination (%d,%d,%d,%d,%d) for harq_pid %d, UE %d/%x\n",
|
|
num_ack_nak,
|
|
sched_ctl->round[CC_idP][harq_pid],
|
|
sched_ctl->round[CC_idP][harq_pid],
|
|
pdu[0],
|
|
pdu[1],
|
|
harq_pid,
|
|
UE_id,
|
|
rnti);
|
|
}
|
|
|
|
break;
|
|
|
|
case 1: // FDD Channel Selection (10.1.2.2.1), must be received for 2 serving cells
|
|
AssertFatal(numCC == 2, "Should not receive harq indication with channel selection with %d active CCs\n",
|
|
numCC);
|
|
|
|
if ((num_ack_nak == 2)
|
|
&& (sched_ctl->round[pCCid][harq_pid] < 8)
|
|
&& (sched_ctl->round[1 - pCCid][harq_pid] < 8)
|
|
&& (sched_ctl->tbcnt[pCCid][harq_pid] == 1)
|
|
&& (sched_ctl->tbcnt[1 - pCCid][harq_pid] == 1)) {
|
|
AssertFatal(pdu[0] <= 3, "pdu[0] %d is not ACK/NAK/DTX\n",
|
|
pdu[0]);
|
|
AssertFatal(pdu[1] <= 3, "pdu[1] %d is not ACK/NAK/DTX\n",
|
|
pdu[1]);
|
|
|
|
if (pdu[0] == 1)
|
|
sched_ctl->round[pCCid][harq_pid] = 8;
|
|
else {
|
|
sched_ctl->round[pCCid][harq_pid]++;
|
|
|
|
if (sched_ctl->round[pCCid][harq_pid] == 4)
|
|
sched_ctl->round[pCCid][harq_pid] = 8;
|
|
}
|
|
|
|
if (pdu[1] == 1)
|
|
sched_ctl->round[1 - pCCid][harq_pid] = 8;
|
|
else {
|
|
sched_ctl->round[1 - pCCid][harq_pid]++;
|
|
|
|
if (sched_ctl->round[1 - pCCid][harq_pid] == 4)
|
|
sched_ctl->round[1 - pCCid][harq_pid] = 8;
|
|
}
|
|
} // A=2
|
|
else if ((num_ack_nak == 3)
|
|
&& (sched_ctl->round[pCCid][harq_pid] < 8)
|
|
&& (sched_ctl->tbcnt[pCCid][harq_pid] == 2)
|
|
&& (sched_ctl->round[1 - pCCid][harq_pid] < 8)
|
|
&& (sched_ctl->tbcnt[1 - pCCid][harq_pid] == 1)) {
|
|
AssertFatal(pdu[0] <= 3, "pdu[0] %d is not ACK/NAK/DTX\n",
|
|
pdu[0]);
|
|
AssertFatal(pdu[1] <= 3, "pdu[1] %d is not ACK/NAK/DTX\n",
|
|
pdu[1]);
|
|
AssertFatal(pdu[2] <= 3, "pdu[2] %d is not ACK/NAK/DTX\n",
|
|
pdu[2]);
|
|
AssertFatal(sched_ctl->tbcnt[pCCid][harq_pid] == 2, "sched_ctl->tbcnt[%d][%d] != 2 for UE %d/%x\n",
|
|
pCCid,
|
|
harq_pid,
|
|
UE_id,
|
|
rnti);
|
|
AssertFatal(sched_ctl->tbcnt[1 - pCCid][harq_pid] == 1, "sched_ctl->tbcnt[%d][%d] != 1 for UE %d/%x\n",
|
|
1 - pCCid,
|
|
harq_pid,
|
|
UE_id,
|
|
rnti);
|
|
|
|
if (pdu[0] == 1 && pdu[1] == 1) { // both ACK
|
|
sched_ctl->round[pCCid][harq_pid] = 8;
|
|
sched_ctl->tbcnt[pCCid][harq_pid] = 0;
|
|
} else if ((pdu[0] == 2 && pdu[1] == 1) || (pdu[0] == 1 && pdu[1] == 2)) {
|
|
sched_ctl->round[pCCid][harq_pid]++;
|
|
sched_ctl->tbcnt[pCCid][harq_pid] = 1;
|
|
|
|
if (sched_ctl->round[pCCid][harq_pid] == 4) {
|
|
sched_ctl->round[pCCid][harq_pid] = 8;
|
|
sched_ctl->tbcnt[pCCid][harq_pid] = 0; /* TODO: do we have to set it to 0? */
|
|
}
|
|
} else {
|
|
sched_ctl->round[pCCid][harq_pid]++;
|
|
|
|
if (sched_ctl->round[pCCid][harq_pid] == 4) {
|
|
sched_ctl->round[pCCid][harq_pid] = 8;
|
|
sched_ctl->tbcnt[pCCid][harq_pid] = 0;
|
|
}
|
|
}
|
|
|
|
if (pdu[2] == 1) sched_ctl->round[1 - pCCid][harq_pid] = 8;
|
|
else {
|
|
sched_ctl->round[1 - pCCid][harq_pid]++;
|
|
|
|
if (sched_ctl->round[1 - pCCid][harq_pid] == 4) {
|
|
sched_ctl->round[1 - pCCid][harq_pid] = 8;
|
|
}
|
|
}
|
|
} // A=3 primary cell has 2 TBs
|
|
else if ((num_ack_nak == 3)
|
|
&& (sched_ctl->round[1 - pCCid][harq_pid] < 8)
|
|
&& (sched_ctl->round[pCCid][harq_pid] < 8)
|
|
&& (sched_ctl->tbcnt[1 - pCCid][harq_pid] == 2)
|
|
&& (sched_ctl->tbcnt[pCCid][harq_pid] == 1)) {
|
|
AssertFatal(pdu[0] <= 3, "pdu[0] %d is not ACK/NAK/DTX\n",
|
|
pdu[0]);
|
|
AssertFatal(pdu[1] <= 3, "pdu[1] %d is not ACK/NAK/DTX\n",
|
|
pdu[1]);
|
|
AssertFatal(pdu[2] <= 3, "pdu[2] %d is not ACK/NAK/DTX\n",
|
|
pdu[2]);
|
|
AssertFatal(sched_ctl->tbcnt[1 - pCCid][harq_pid] == 2, "sched_ctl->tbcnt[%d][%d] != 2 for UE %d/%x\n",
|
|
1 - pCCid,
|
|
harq_pid,
|
|
UE_id,
|
|
rnti);
|
|
AssertFatal(sched_ctl->tbcnt[pCCid][harq_pid] == 1, "sched_ctl->tbcnt[%d][%d] != 1 for UE %d/%x\n",
|
|
pCCid,
|
|
harq_pid,
|
|
UE_id,
|
|
rnti);
|
|
|
|
if (pdu[0] == 1 && pdu[1] == 1) { // both ACK
|
|
sched_ctl->round[1 - pCCid][harq_pid] = 8;
|
|
sched_ctl->tbcnt[1 - pCCid][harq_pid] = 0;
|
|
} else if ((pdu[0] >= 2 && pdu[1] == 1) || (pdu[0] == 1 && pdu[1] >= 2)) { // one ACK
|
|
sched_ctl->round[1 - pCCid][harq_pid]++;
|
|
sched_ctl->tbcnt[1 - pCCid][harq_pid] = 1;
|
|
|
|
if (sched_ctl->round[1 - pCCid][harq_pid] == 4) {
|
|
sched_ctl->round[1 - pCCid][harq_pid] = 8;
|
|
sched_ctl->tbcnt[1 - pCCid][harq_pid] = 0;
|
|
}
|
|
} else { // both NAK/DTX
|
|
sched_ctl->round[1 - pCCid][harq_pid]++;
|
|
|
|
if (sched_ctl->round[1 - pCCid][harq_pid] == 4) {
|
|
sched_ctl->round[1 - pCCid][harq_pid] = 8;
|
|
sched_ctl->tbcnt[1 - pCCid][harq_pid] = 0;
|
|
}
|
|
}
|
|
|
|
if (pdu[2] == 1) sched_ctl->round[pCCid][harq_pid] = 8;
|
|
else {
|
|
sched_ctl->round[pCCid][harq_pid]++;
|
|
|
|
if (sched_ctl->round[pCCid][harq_pid] == 4) {
|
|
sched_ctl->round[pCCid][harq_pid] = 8;
|
|
}
|
|
}
|
|
} // A=3 secondary cell has 2 TBs
|
|
|
|
#if MAX_NUM_CCs>1
|
|
else if ((num_ack_nak == 4)
|
|
&& (sched_ctl->round[0][harq_pid] < 8)
|
|
&& (sched_ctl->round[1][harq_pid] < 8)
|
|
&& (sched_ctl->tbcnt[1 - pCCid][harq_pid] == 2)
|
|
&& (sched_ctl->tbcnt[pCCid][harq_pid] == 2)) {
|
|
AssertFatal(pdu[0] <= 3, "pdu[0] %d is not ACK/NAK/DTX\n",
|
|
pdu[0]);
|
|
AssertFatal(pdu[1] <= 3, "pdu[1] %d is not ACK/NAK/DTX\n",
|
|
pdu[1]);
|
|
AssertFatal(pdu[2] <= 3, "pdu[2] %d is not ACK/NAK/DTX\n",
|
|
pdu[2]);
|
|
AssertFatal(pdu[3] <= 3, "pdu[3] %d is not ACK/NAK/DTX\n",
|
|
pdu[3]);
|
|
AssertFatal(sched_ctl->tbcnt[0][harq_pid] == 2, "sched_ctl->tbcnt[0][%d] != 2 for UE %d/%x\n",
|
|
harq_pid,
|
|
UE_id,
|
|
rnti);
|
|
AssertFatal(sched_ctl->tbcnt[1][harq_pid] == 2, "sched_ctl->tbcnt[1][%d] != 2 for UE %d/%x\n",
|
|
harq_pid,
|
|
UE_id,
|
|
rnti);
|
|
|
|
if (pdu[0] == 1 && pdu[1] == 1) { // both ACK
|
|
sched_ctl->round[0][harq_pid] = 8;
|
|
sched_ctl->tbcnt[0][harq_pid] = 0;
|
|
} else if ((pdu[0] >= 2 && pdu[1] == 1) || (pdu[0] == 1 && pdu[1] >= 2)) { // one ACK
|
|
sched_ctl->round[0][harq_pid]++;
|
|
sched_ctl->tbcnt[0][harq_pid] = 1;
|
|
|
|
if (sched_ctl->round[0][harq_pid] == 4) {
|
|
sched_ctl->round[0][harq_pid] = 8;
|
|
sched_ctl->tbcnt[0][harq_pid] = 0;
|
|
}
|
|
} else { // both NAK/DTX
|
|
sched_ctl->round[0][harq_pid]++;
|
|
|
|
if (sched_ctl->round[0][harq_pid] == 4) {
|
|
sched_ctl->round[0][harq_pid] = 8;
|
|
sched_ctl->tbcnt[0][harq_pid] = 0;
|
|
}
|
|
}
|
|
|
|
if (pdu[2] == 1 && pdu[3] == 1) { // both ACK
|
|
sched_ctl->round[1][harq_pid] = 8;
|
|
sched_ctl->tbcnt[1][harq_pid] = 0;
|
|
} else if ((pdu[2] >= 2 && pdu[3] == 1) || (pdu[2] == 1 && pdu[3] >= 2)) { // one ACK
|
|
sched_ctl->round[1][harq_pid]++;
|
|
sched_ctl->tbcnt[1][harq_pid] = 1;
|
|
|
|
if (sched_ctl->round[1][harq_pid] == 4) {
|
|
sched_ctl->round[1][harq_pid] = 8;
|
|
sched_ctl->tbcnt[1][harq_pid] = 0;
|
|
}
|
|
} else { // both NAK/DTX
|
|
sched_ctl->round[1][harq_pid]++;
|
|
|
|
if (sched_ctl->round[1][harq_pid] == 4) {
|
|
sched_ctl->round[1][harq_pid] = 8;
|
|
sched_ctl->tbcnt[1][harq_pid] = 0;
|
|
}
|
|
}
|
|
} // A=4 both serving cells have 2 TBs
|
|
|
|
#endif
|
|
break;
|
|
|
|
case 2: // Format 3
|
|
AssertFatal(numCC > 2, "Should not receive harq indication with FDD format 3 with %d < 3 active CCs\n",
|
|
numCC);
|
|
|
|
for (i = 0, j = 0; i < numCC; i++) {
|
|
if (sched_ctl->round[i][harq_pid] < 8) {
|
|
if (tmode[i] == 1 || tmode[i] == 2 || tmode[0] == 5 || tmode[0] == 6 || tmode[0] == 7) {
|
|
if (pdu[j] == 1) {
|
|
sched_ctl->round[i][harq_pid] = 8;
|
|
sched_ctl->tbcnt[i][harq_pid] = 0;
|
|
} else if (pdu[j] == 2) {
|
|
sched_ctl->round[i][harq_pid]++;
|
|
|
|
if (sched_ctl->round[i][harq_pid] == 4) {
|
|
sched_ctl->round[i][harq_pid] = 8;
|
|
sched_ctl->tbcnt[i][harq_pid] = 0;
|
|
}
|
|
} else
|
|
AssertFatal(1 == 0, "Illegal harq_ack value for CC %d harq_pid %d (%d) UE %d/%x\n",
|
|
i,
|
|
harq_pid,
|
|
pdu[j],
|
|
UE_id,
|
|
rnti);
|
|
|
|
j++;
|
|
} else if (spatial_bundling == 0) {
|
|
if (sched_ctl->tbcnt[i][harq_pid] == 2 && pdu[j] == 1 && pdu[j + 1] == 1) {
|
|
sched_ctl->round[i][harq_pid] = 8;
|
|
sched_ctl->tbcnt[i][harq_pid] = 0;
|
|
} else if (sched_ctl->tbcnt[i][harq_pid] == 2 && pdu[j] == 1 && pdu[j + 1] == 2) {
|
|
sched_ctl->round[i][harq_pid]++;
|
|
sched_ctl->tbcnt[i][harq_pid] = 1;
|
|
|
|
if (sched_ctl->round[i][harq_pid] == 4) {
|
|
sched_ctl->round[i][harq_pid] = 8;
|
|
sched_ctl->tbcnt[i][harq_pid] = 0;
|
|
}
|
|
} else if (sched_ctl->tbcnt[i][harq_pid] == 2 && pdu[j] == 2 && pdu[j + 1] == 1) {
|
|
sched_ctl->round[i][harq_pid]++;
|
|
sched_ctl->tbcnt[i][harq_pid] = 1;
|
|
|
|
if (sched_ctl->round[i][harq_pid] == 4) {
|
|
sched_ctl->round[i][harq_pid] = 8;
|
|
sched_ctl->tbcnt[i][harq_pid] = 0;
|
|
}
|
|
} else if (sched_ctl->tbcnt[i][harq_pid] == 2 && pdu[j] == 2 && pdu[j + 1] == 2) {
|
|
sched_ctl->round[i][harq_pid]++;
|
|
|
|
if (sched_ctl->round[i][harq_pid] == 4) {
|
|
sched_ctl->round[i][harq_pid] = 8;
|
|
sched_ctl->tbcnt[i][harq_pid] = 0;
|
|
}
|
|
} else
|
|
AssertFatal(1 == 0, "Illegal combination for CC %d harq_pid %d (%d,%d,%d) UE %d/%x\n",
|
|
i,
|
|
harq_pid,
|
|
sched_ctl->tbcnt[i][harq_pid],
|
|
pdu[j],
|
|
pdu[j + 1],
|
|
UE_id,
|
|
rnti);
|
|
|
|
j += 2;
|
|
} else if (spatial_bundling == 1) {
|
|
if (pdu[j] == 1) {
|
|
sched_ctl->round[i][harq_pid] = 8;
|
|
sched_ctl->tbcnt[i][harq_pid] = 0;
|
|
} else if (pdu[j] == 2) {
|
|
sched_ctl->round[i][harq_pid]++;
|
|
|
|
if (sched_ctl->round[i][harq_pid] == 4) {
|
|
sched_ctl->round[i][harq_pid] = 8;
|
|
sched_ctl->tbcnt[i][harq_pid] = 0;
|
|
}
|
|
} else {
|
|
AssertFatal(1 == 0, "Illegal hack_nak value %d for CC %d harq_pid %d UE %d/%x\n",
|
|
pdu[j],
|
|
i,
|
|
harq_pid,
|
|
UE_id,
|
|
rnti);
|
|
}
|
|
|
|
j++;
|
|
} else {
|
|
AssertFatal(1 == 0, "Illegal value for spatial_bundling %d\n",
|
|
spatial_bundling);
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 3: // Format 4
|
|
AssertFatal(1 == 0, "Should not receive harq indication with Format 4\n");
|
|
break;
|
|
|
|
case 4: // Format 5
|
|
AssertFatal(1 == 0, "Should not receive harq indication with Format 5\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
extract_pucch_csi(module_id_t mod_idP,
|
|
int CC_idP,
|
|
int UE_id,
|
|
frame_t frameP,
|
|
sub_frame_t subframeP,
|
|
uint8_t *pdu,
|
|
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];
|
|
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",
|
|
UE_id);
|
|
AssertFatal(UE_list->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;
|
|
AssertFatal(cqi_ReportPeriodic != NULL, "cqi_ReportPeriodic is null for UE %d\n",
|
|
UE_id);
|
|
// determine feedback mode
|
|
AssertFatal(cqi_ReportPeriodic->present != LTE_CQI_ReportPeriodic_PR_NOTHING, "cqi_ReportPeriodic->present == LTE_CQI_ReportPeriodic_PR_NOTHING!\n");
|
|
AssertFatal(cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present != LTE_CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING,
|
|
"cqi_ReportPeriodic->cqi_FormatIndicatorPeriodic.choice.setup.present == LTE_CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING!\n");
|
|
uint16_t Npd, N_OFFSET_CQI;
|
|
int H, K, bandwidth_part, L, Lmask;
|
|
int ri = sched_ctl->periodic_ri_received[CC_idP];
|
|
get_csi_params(cc,
|
|
cqi_ReportPeriodic,
|
|
&Npd,
|
|
&N_OFFSET_CQI,
|
|
&H);
|
|
K = (H - 1) / Jtab[cc->mib->message.dl_Bandwidth];
|
|
L = Ltab[cc->mib->message.dl_Bandwidth];
|
|
Lmask = L - 1;
|
|
feedback_cnt = (((frameP * 10) + subframeP) / Npd) % H;
|
|
|
|
if (feedback_cnt > 0) bandwidth_part = (feedback_cnt - 1) % K;
|
|
else bandwidth_part = 0;
|
|
|
|
switch (get_tmode(mod_idP,
|
|
CC_idP,
|
|
UE_id)) {
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 7:
|
|
no_pmi = 1;
|
|
break;
|
|
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
no_pmi = 0;
|
|
break;
|
|
|
|
default:
|
|
// note: need to check TM8-10 without PMI/RI or with 1 antenna port (see Section 5.2.3.3.1 from 36.213)
|
|
no_pmi = 0;
|
|
break;
|
|
}
|
|
|
|
if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == LTE_CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_widebandCQI ||
|
|
feedback_cnt == 0) {
|
|
// Note: This implements only Tables: 5.3.3.1-1,5.3.3.1-1A and 5.3.3.1-2 from 36.213 (1,2,4 antenna ports Wideband CQI/PMI)
|
|
if (no_pmi == 1) { // get spatial_diffcqi if needed
|
|
sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF;
|
|
sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = (pdu[0] >> 4) & 7;
|
|
} else if (cc->p_eNB == 2 && ri == 1) {
|
|
// p=2 Rank 1 wideband CQI/PMI 6 bits
|
|
sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF;
|
|
sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0] >> 4) & 3;
|
|
} else if (cc->p_eNB == 2 && ri > 1) {
|
|
// p=2 Rank 2 wideband CQI/PMI 8 bits
|
|
sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF;
|
|
sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = (pdu[0] >> 4) & 7;
|
|
sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0] >> 7) & 1;
|
|
} else if (cc->p_eNB == 4 && ri == 1) {
|
|
// p=4 Rank 1 wideband CQI/PMI 8 bits
|
|
sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF;
|
|
sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0] >> 4) & 0x0F;
|
|
} else if (cc->p_eNB == 4 && ri > 1) {
|
|
// p=4 Rank 2 wideband CQI/PMI 11 bits
|
|
sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF;
|
|
sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = (pdu[0] >> 4) & 7;
|
|
sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0] >> 7) & 0xF;
|
|
} else
|
|
AssertFatal(1 == 0, "illegal combination p %d, ri %d, no_pmi %d\n",
|
|
cc->p_eNB,
|
|
ri,
|
|
no_pmi);
|
|
} else if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == LTE_CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) {
|
|
// This is Table 5.2.3.3.2-2 for 36.213
|
|
if (ri == 1) {
|
|
//4+Ltab[cc->mib->message.dl_Bandwidth] bits
|
|
sched_ctl->periodic_subband_cqi[CC_idP][(bandwidth_part * L) +((pdu[0] >> 4) & Lmask)] = pdu[0] & 0xF;
|
|
} else if (ri > 1) {
|
|
//7+Ltab[cc->mib->message.dl_Bandwidth] bits;
|
|
sched_ctl->periodic_subband_spatial_diffcqi[CC_idP][(bandwidth_part * L) + ((pdu[0] >> 7) & Lmask)] = (pdu[0] >> 4) & 7;
|
|
sched_ctl->periodic_subband_cqi[CC_idP][(bandwidth_part * L) + ((pdu[0] >> 7) & Lmask)] = pdu[0] & 0xF;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
extract_pusch_csi(module_id_t mod_idP,
|
|
int CC_idP,
|
|
int UE_id,
|
|
frame_t frameP,
|
|
sub_frame_t subframeP,
|
|
uint8_t *pdu,
|
|
uint8_t length)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
|
|
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];
|
|
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 };
|
|
int Mtab_uesel[6] = { 0, 1, 3, 5, 6, 6 };
|
|
int v[6];
|
|
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",
|
|
UE_id);
|
|
AssertFatal(UE_list->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;
|
|
AssertFatal(cqi_ReportModeAperiodic != NULL, "cqi_ReportModeAperiodic is null for UE %d\n",
|
|
UE_id);
|
|
int N = Ntab[cc->mib->message.dl_Bandwidth];
|
|
int tmode = get_tmode(mod_idP, CC_idP, UE_id);
|
|
int ri = sched_ctl->aperiodic_ri_received[CC_idP];
|
|
int r, diffcqi0 = 0, diffcqi1 = 0, pmi_uesel = 0;
|
|
int bw = cc->mib->message.dl_Bandwidth;
|
|
int m;
|
|
|
|
switch (*cqi_ReportModeAperiodic) {
|
|
case LTE_CQI_ReportModeAperiodic_rm12:
|
|
AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n");
|
|
// wideband multiple PMI (TM4/6), Table 5.2.2.6.1-1 (for TM4/6)
|
|
AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 || tmode == 10, "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm12\n",
|
|
tmode);
|
|
|
|
if (tmode <= 6) { //Table 5.2.2.6.1-1 36.213
|
|
if (ri == 1 && cc->p_eNB == 2) {
|
|
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F);
|
|
p >>= 4;
|
|
|
|
for (i = 0; i < N; i++) {
|
|
sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t) (p & 0x03);
|
|
p >>= 2;
|
|
}
|
|
}
|
|
|
|
if (ri == 2 && cc->p_eNB == 2) {
|
|
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F);
|
|
p >>= 4;
|
|
sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t) (p & 0x0F);
|
|
p >>= 4;
|
|
|
|
for (i = 0; i < N; i++) {
|
|
sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t) (p & 0x01);
|
|
p >>= 1;
|
|
}
|
|
}
|
|
|
|
if (ri == 1 && cc->p_eNB == 4) {
|
|
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F);
|
|
p >>= 4;
|
|
|
|
for (i = 0; i < N; i++) {
|
|
sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t) (p & 0x03);
|
|
p >>= 4;
|
|
}
|
|
}
|
|
|
|
if (ri == 2 && cc->p_eNB == 4) {
|
|
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F);
|
|
p >>= 4;
|
|
sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t) (p & 0x0F);
|
|
p >>= 4;
|
|
|
|
for (i = 0; i < N; i++) {
|
|
sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t) (p & 0x01);
|
|
p >>= 4;
|
|
}
|
|
}
|
|
} // if (tmode <= 6) { //Table 5.2.2.6.1-1 36.213
|
|
else {
|
|
AssertFatal(1 == 0, "support for TM 8-10 to be done\n");
|
|
}
|
|
|
|
break;
|
|
|
|
case LTE_CQI_ReportModeAperiodic_rm20:
|
|
AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n");
|
|
// UE-selected subband CQI no PMI (TM1/2/3/7) , Table 5.2.2.6.3-1 from 36.213
|
|
AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 || tmode == 7, "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm20\n",
|
|
tmode);
|
|
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F);
|
|
p >>= 4;
|
|
diffcqi0 = (uint8_t) (p & 0x03);
|
|
p >>= 2;
|
|
r = (uint8_t) (p & ((1 >> Ltab_uesel[bw]) - 1));
|
|
reverse_index(Ntab_uesel[bw],
|
|
Mtab_uesel[bw],
|
|
r,
|
|
v);
|
|
|
|
for (m = 0; m < Mtab_uesel[bw]; m++) {
|
|
sched_ctl->aperiodic_subband_diffcqi0[CC_idP][v[m]] = diffcqi0;
|
|
}
|
|
|
|
break;
|
|
|
|
case LTE_CQI_ReportModeAperiodic_rm22:
|
|
AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n");
|
|
// UE-selected subband CQI multiple PMI (TM4/6) Table 5.2.2.6.3-2 from 36.213
|
|
AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 || tmode == 10, "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm22\n",
|
|
tmode);
|
|
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F);
|
|
p >>= 4;
|
|
diffcqi0 = (uint8_t) (p & 0x03);
|
|
p >>= 2;
|
|
|
|
if (ri > 1) {
|
|
sched_ctl->aperiodic_wideband_cqi1[CC_idP] =
|
|
(uint8_t) (p & 0x0F);
|
|
p >>= 4;
|
|
diffcqi1 = (uint8_t) (p & 0x03);
|
|
p >>= 2;
|
|
}
|
|
|
|
r = (uint8_t) (p & ((1 >> Ltab_uesel[bw]) - 1));
|
|
p >>= Ltab_uesel[bw];
|
|
reverse_index(Ntab_uesel[bw],
|
|
Mtab_uesel[bw],
|
|
r,
|
|
v);
|
|
|
|
if (ri == 1 && cc->p_eNB == 2) {
|
|
pmi_uesel = p & 0x3;
|
|
p >>= 2;
|
|
sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x3;
|
|
} else if (ri == 2 && cc->p_eNB == 2) {
|
|
pmi_uesel = p & 0x1;
|
|
p >>= 1;
|
|
sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x1;
|
|
} else if (cc->p_eNB == 4) {
|
|
pmi_uesel = p & 0x0F;
|
|
p >>= 4;
|
|
sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x0F;
|
|
}
|
|
|
|
for (m = 0; m < Mtab_uesel[bw]; m++) {
|
|
sched_ctl->aperiodic_subband_diffcqi0[CC_idP][v[m]] = diffcqi0;
|
|
|
|
if (ri > 1) sched_ctl->aperiodic_subband_diffcqi1[CC_idP][v[m]] = diffcqi1;
|
|
|
|
sched_ctl->aperiodic_subband_pmi[CC_idP][v[m]] = pmi_uesel;
|
|
}
|
|
|
|
break;
|
|
|
|
case LTE_CQI_ReportModeAperiodic_rm30:
|
|
//subband CQI no PMI (TM1/2/3/7)
|
|
AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 || tmode == 7, "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm30\n",
|
|
tmode);
|
|
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = pdu[0] >> 4;
|
|
curbyte = 0;
|
|
curbit = 3;
|
|
|
|
for (i = 0; i < N; i++) {
|
|
sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] =
|
|
(pdu[curbyte] >> (curbit - 1)) & 0x03;
|
|
curbit -= 2;
|
|
|
|
if (curbit < 0) {
|
|
curbit = 7;
|
|
curbyte++;
|
|
}
|
|
}
|
|
|
|
sched_ctl->dl_cqi[CC_idP] = sched_ctl->aperiodic_wideband_cqi0[CC_idP];
|
|
break;
|
|
|
|
case LTE_CQI_ReportModeAperiodic_rm31:
|
|
AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n");
|
|
//subband CQI single PMI (TM4/5/6)
|
|
AssertFatal(tmode == 4 || tmode == 5 || tmode == 6 || tmode == 8 || tmode == 9 || tmode == 10,
|
|
"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm31\n",
|
|
tmode);
|
|
|
|
if (ri == 1 && cc->p_eNB == 2) {
|
|
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F);
|
|
p >>= 4;
|
|
|
|
for (i = 0; i < N; i++) {
|
|
sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] = (uint8_t) (p & 0x03);
|
|
p >>= 2;
|
|
}
|
|
|
|
sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x03;
|
|
}
|
|
|
|
if (ri == 2 && cc->p_eNB == 2) {
|
|
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F);
|
|
p >>= 4;
|
|
|
|
for (i = 0; i < N; i++) {
|
|
sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t) (p & 0x01);
|
|
p >>= 1;
|
|
}
|
|
|
|
sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t) (p & 0x0F);
|
|
p >>= 4;
|
|
|
|
for (i = 0; i < N; i++) {
|
|
sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t) (p & 0x01);
|
|
p >>= 1;
|
|
}
|
|
|
|
sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x01;
|
|
}
|
|
|
|
if (ri == 1 && cc->p_eNB == 4) {
|
|
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F);
|
|
p >>= 4;
|
|
|
|
for (i = 0; i < N; i++) {
|
|
sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] = (uint8_t) (p & 0x03);
|
|
p >>= 2;
|
|
}
|
|
|
|
sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x0F;
|
|
}
|
|
|
|
if (ri > 1 && cc->p_eNB == 4) { // Note : 64 bits for 20 MHz
|
|
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F);
|
|
p >>= 4;
|
|
|
|
for (i = 0; i < N; i++) {
|
|
sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t) (p & 0x01);
|
|
p >>= 1;
|
|
}
|
|
|
|
sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t) (p & 0x0F);
|
|
p >>= 4;
|
|
|
|
for (i = 0; i < N; i++) {
|
|
sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t) (p & 0x01);
|
|
p >>= 2;
|
|
}
|
|
|
|
sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x0F;
|
|
}
|
|
|
|
break;
|
|
#if (LTE_RRC_VERSION >= MAKE_VERSION(12, 5, 0))
|
|
|
|
case LTE_CQI_ReportModeAperiodic_rm32_v1250:
|
|
AssertFatal(tmode == 4 || tmode == 5 || tmode == 6 || tmode == 8 || tmode == 9 || tmode == 10,
|
|
"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm32\n",
|
|
tmode);
|
|
AssertFatal(1 == 0, "CQI_ReportModeAperiodic_rm32 to be done\n");
|
|
break;
|
|
#endif
|
|
#if (LTE_RRC_VERSION >= MAKE_VERSION(13, 1, 0))
|
|
|
|
case LTE_CQI_ReportModeAperiodic_rm10_v1310:
|
|
AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 || tmode == 7, "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm10\n",
|
|
tmode);
|
|
AssertFatal(1 == 0, "CQI_ReportModeAperiodic_rm10 to be done\n");
|
|
break;
|
|
|
|
case LTE_CQI_ReportModeAperiodic_rm11_v1310:
|
|
AssertFatal(tmode == 4 || tmode == 5 || tmode == 6 || tmode == 8 || tmode == 9 || tmode == 10,
|
|
"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm11\n",
|
|
tmode);
|
|
AssertFatal(1 == 0, "CQI_ReportModeAperiodic_rm11 to be done\n");
|
|
break;
|
|
#endif /* #if (LTE_RRC_VERSION >= MAKE_VERSION(13, 1, 0)) */
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
cqi_indication(module_id_t mod_idP,
|
|
int CC_idP,
|
|
frame_t frameP,
|
|
sub_frame_t subframeP,
|
|
rnti_t rntiP,
|
|
nfapi_cqi_indication_rel9_t *rel9,
|
|
uint8_t *pdu,
|
|
nfapi_ul_cqi_information_t *ul_cqi_information)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int UE_id = find_UE_id(mod_idP, rntiP);
|
|
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
|
|
|
|
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];
|
|
|
|
if (UE_id >= 0) {
|
|
LOG_D(MAC,"%s() UE_id:%d channel:%d cqi:%d\n",
|
|
__FUNCTION__,
|
|
UE_id,
|
|
ul_cqi_information->channel,
|
|
ul_cqi_information->ul_cqi);
|
|
|
|
if (ul_cqi_information->channel == 0) { // PUCCH
|
|
// extract pucch csi information before changing RI information
|
|
extract_pucch_csi(mod_idP,
|
|
CC_idP,
|
|
UE_id,
|
|
frameP,
|
|
subframeP,
|
|
pdu, rel9->length);
|
|
memcpy((void *) sched_ctl->periodic_ri_received,
|
|
(void *) rel9->ri,
|
|
rel9->number_of_cc_reported);
|
|
// SNR for PUCCH2
|
|
sched_ctl->pucch2_snr[CC_idP] = ul_cqi_information->ul_cqi;
|
|
} else { //PUSCH
|
|
memcpy((void *) sched_ctl->aperiodic_ri_received,
|
|
(void *) rel9->ri,
|
|
rel9->number_of_cc_reported);
|
|
extract_pusch_csi(mod_idP,
|
|
CC_idP,
|
|
UE_id,
|
|
frameP,
|
|
subframeP,
|
|
pdu,
|
|
rel9->length);
|
|
LOG_D(MAC,"Frame %d Subframe %d update CQI:%d\n",
|
|
frameP,
|
|
subframeP,
|
|
sched_ctl->dl_cqi[CC_idP]);
|
|
sched_ctl->cqi_req_flag &= (~(1 << subframeP));
|
|
sched_ctl->cqi_received = 1;
|
|
}
|
|
|
|
// timing advance
|
|
sched_ctl->timing_advance = rel9->timing_advance;
|
|
sched_ctl->timing_advance_r9 = rel9->timing_advance_r9;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
SR_indication(module_id_t mod_idP,
|
|
int cc_idP,
|
|
frame_t frameP,
|
|
sub_frame_t subframeP,
|
|
rnti_t rntiP,
|
|
uint8_t ul_cqi)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
T(T_ENB_MAC_SCHEDULING_REQUEST,
|
|
T_INT(mod_idP),
|
|
T_INT(cc_idP),
|
|
T_INT(frameP),
|
|
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_sched_ctrl_t *UE_scheduling_ctrl = NULL;
|
|
|
|
if (UE_id != -1) {
|
|
UE_scheduling_ctrl = &(UE_list->UE_sched_ctrl[UE_id]);
|
|
|
|
if ((UE_scheduling_ctrl->cdrx_configured == TRUE) &&
|
|
(UE_scheduling_ctrl->dci0_ongoing_timer > 0) &&
|
|
(UE_scheduling_ctrl->dci0_ongoing_timer < 8)) {
|
|
LOG_D(MAC, "[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d on CC_id %d. \
|
|
The SR is not set do to ongoing DCI0 with CDRX activated\n",
|
|
mod_idP,
|
|
rntiP,
|
|
frameP,
|
|
subframeP,
|
|
UE_id,
|
|
cc_idP);
|
|
} else {
|
|
if (mac_eNB_get_rrc_status(mod_idP, UE_RNTI(mod_idP, UE_id)) < RRC_CONNECTED) {
|
|
LOG_D(MAC, "[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d on CC_id %d\n",
|
|
mod_idP,
|
|
rntiP,
|
|
frameP,
|
|
subframeP,
|
|
UE_id,
|
|
cc_idP);
|
|
}
|
|
UE_list->UE_template[cc_idP][UE_id].ul_SR = 1;
|
|
UE_list->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);
|
|
}
|
|
} else {
|
|
LOG_D(MAC, "[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d (unknown UE_id) on CC_id %d\n",
|
|
mod_idP,
|
|
rntiP,
|
|
frameP,
|
|
subframeP,
|
|
UE_id,
|
|
cc_idP);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
UL_failure_indication(module_id_t mod_idP,
|
|
int cc_idP,
|
|
frame_t frameP,
|
|
rnti_t rntiP,
|
|
sub_frame_t subframeP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int UE_id = find_UE_id(mod_idP, rntiP);
|
|
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
|
|
|
|
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",
|
|
mod_idP,
|
|
UE_id,
|
|
rntiP,
|
|
frameP,
|
|
subframeP,
|
|
UE_id,
|
|
cc_idP,
|
|
UE_list->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;
|
|
} 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);
|
|
LOG_W(MAC, "[eNB %d][SR %x] Frame %d subframeP %d Signaling UL Failure for UE %d (unknown UEid) on CC_id %d\n",
|
|
mod_idP,
|
|
rntiP,
|
|
frameP,
|
|
subframeP,
|
|
UE_id,
|
|
cc_idP);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
static int
|
|
nack_or_dtx_reported(COMMON_channels_t *cc,
|
|
nfapi_harq_indication_pdu_t *harq_pdu)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int i;
|
|
|
|
if (cc->tdd_Config) {
|
|
nfapi_harq_indication_tdd_rel13_t *hi = &harq_pdu->harq_indication_tdd_rel13;
|
|
|
|
for (i = 0; i < hi->number_of_ack_nack; i++) {
|
|
if (hi->harq_data[i].bundling.value_0 != 1) //only bundling is used for tdd for now
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
nfapi_harq_indication_fdd_rel13_t *hi = &harq_pdu->harq_indication_fdd_rel13;
|
|
|
|
for (i = 0; i < hi->number_of_ack_nack; i++) {
|
|
if (hi->harq_tb_n[i] != 1)
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
harq_indication(module_id_t mod_idP,
|
|
int CC_idP,
|
|
frame_t frameP,
|
|
sub_frame_t subframeP,
|
|
nfapi_harq_indication_pdu_t *harq_pdu)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
rnti_t rnti = harq_pdu->rx_ue_information.rnti;
|
|
uint8_t ul_cqi = harq_pdu->ul_cqi_information.ul_cqi;
|
|
uint8_t channel = harq_pdu->ul_cqi_information.channel;
|
|
int UE_id = find_UE_id(mod_idP, rnti);
|
|
|
|
if (UE_id == -1) {
|
|
LOG_W(MAC, "harq_indication: UE %x not found\n",
|
|
rnti);
|
|
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];
|
|
COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP];
|
|
// extract HARQ Information
|
|
|
|
if (cc->tdd_Config) {
|
|
extract_harq(mod_idP,
|
|
CC_idP,
|
|
UE_id,
|
|
frameP,
|
|
subframeP,
|
|
(void *) &harq_pdu->harq_indication_tdd_rel13,
|
|
channel);
|
|
} else {
|
|
extract_harq(mod_idP,
|
|
CC_idP,
|
|
UE_id,
|
|
frameP,
|
|
subframeP,
|
|
(void *) &harq_pdu->harq_indication_fdd_rel13,
|
|
channel);
|
|
}
|
|
|
|
/* don't care about cqi reporting if NACK/DTX is there */
|
|
if (channel == 0 && !nack_or_dtx_reported(cc,
|
|
harq_pdu)) {
|
|
sched_ctl->pucch1_snr[CC_idP] = ul_cqi;
|
|
sched_ctl->pucch1_cqi_update[CC_idP] = 1;
|
|
}
|
|
|
|
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;
|
|
}
|