4475 lines
136 KiB
C
4475 lines
136 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 "PHY/defs.h"
|
|
#include "PHY/extern.h"
|
|
|
|
#include "SCHED/defs.h"
|
|
#include "SCHED/extern.h"
|
|
|
|
#include "LAYER2/MAC/defs.h"
|
|
#include "LAYER2/MAC/extern.h"
|
|
|
|
#include "LAYER2/MAC/proto.h"
|
|
#include "UTIL/LOG/log.h"
|
|
#include "UTIL/LOG/vcd_signal_dumper.h"
|
|
#include "UTIL/OPT/opt.h"
|
|
#include "OCG.h"
|
|
#include "OCG_extern.h"
|
|
|
|
#include "RRC/LITE/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
|
|
|
|
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 = r - BaseValue;
|
|
sumV += v[i - 1];
|
|
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");
|
|
AssertFatal((cc->mib->message.phich_Config.phich_Resource >= 0) &&
|
|
(cc->mib->message.phich_Config.phich_Resource < 4),
|
|
"phich_Resource %d not in 0..3\n",
|
|
(int) cc->mib->message.phich_Config.phich_Resource);
|
|
|
|
return (phichmap[cc->mib->message.phich_Config.phich_Resource]);
|
|
}
|
|
|
|
uint16_t mac_computeRIV(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);
|
|
}
|
|
|
|
uint8_t getQm(uint8_t mcs)
|
|
{
|
|
if (mcs < 10)
|
|
return (2);
|
|
else if (mcs < 17)
|
|
return (4);
|
|
else
|
|
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!!!!
|
|
|
|
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
|
|
if (cc->tdd_Config->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 (cc->tdd_Config->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 (cc->tdd_Config->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 (cc->tdd_Config->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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
get_Msg3allocret(COMMON_channels_t * cc,
|
|
sub_frame_t current_subframe,
|
|
frame_t current_frame,
|
|
frame_t * frame, sub_frame_t * subframe)
|
|
{
|
|
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 {
|
|
if (cc->tdd_Config->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 (cc->tdd_Config->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 (cc->tdd_Config->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 (cc->tdd_Config->subframeAssignment == 5) {
|
|
// original PUSCH in 2, PHICH in 8, ret in 2 next frame
|
|
*frame = (current_frame + 1) & 1023;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t
|
|
subframe2harqpid(COMMON_channels_t * cc, frame_t frame,
|
|
sub_frame_t subframe)
|
|
{
|
|
uint8_t ret = 255;
|
|
|
|
AssertFatal(cc != NULL, "cc is null\n");
|
|
|
|
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);
|
|
}
|
|
}
|
|
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;
|
|
|
|
if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 1) && ((n == 1) || (n == 6))) // tdd_config 0,1 SF 1,5
|
|
ul_frame = (frame + (n == 1 ? 0 : 1));
|
|
else if ((ccP->tdd_Config) &&
|
|
(ccP->tdd_Config->subframeAssignment == 6) &&
|
|
((n == 0) || (n == 1) || (n == 5) || (n == 6)))
|
|
ul_frame = (frame + (n >= 5 ? 1 : 0));
|
|
else if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 6) && (n == 9)) // tdd_config 6 SF 9
|
|
ul_frame = (frame + 1);
|
|
else
|
|
ul_frame = (frame + (n >= 6 ? 1 : 0));
|
|
|
|
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);
|
|
break;
|
|
|
|
case 2:
|
|
case 3:
|
|
case 7:
|
|
case 8:
|
|
return (1);
|
|
break;
|
|
|
|
default:
|
|
return (0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
if ((subframeP <= 1) || (subframeP >= 5))
|
|
return (0);
|
|
else if ((subframeP > 1) && (subframeP < 5))
|
|
return (1);
|
|
else
|
|
AssertFatal(1 == 0, "Unknown subframe number\n");
|
|
break;
|
|
|
|
case 4:
|
|
if ((subframeP <= 1) || (subframeP >= 4))
|
|
return (0);
|
|
else if ((subframeP > 1) && (subframeP < 4))
|
|
return (1);
|
|
else
|
|
AssertFatal(1 == 0, "Unknown subframe number\n");
|
|
break;
|
|
|
|
case 5:
|
|
if ((subframeP <= 1) || (subframeP >= 3))
|
|
return (0);
|
|
else if ((subframeP > 1) && (subframeP < 3))
|
|
return (1);
|
|
else
|
|
AssertFatal(1 == 0, "Unknown subframe number\n");
|
|
break;
|
|
|
|
default:
|
|
AssertFatal(1 == 0,
|
|
"subframe %d Unsupported TDD configuration %d\n",
|
|
subframeP, (int) ccP->tdd_Config->subframeAssignment);
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint16_t get_pucch1_absSF(COMMON_channels_t * cc, uint16_t dlsch_absSF)
|
|
{
|
|
uint16_t sf, f, nextf;
|
|
|
|
if (cc->tdd_Config == NULL) { //FDD n+4
|
|
return ((dlsch_absSF + 4) % 10240);
|
|
} else {
|
|
sf = dlsch_absSF % 10;
|
|
f = dlsch_absSF / 10;
|
|
nextf = (f + 1) & 1023;
|
|
|
|
switch (cc->tdd_Config->subframeAssignment) {
|
|
case 0:
|
|
AssertFatal(1 == 0, "SFA 0 to be filled in now, :-)\n");
|
|
break;
|
|
case 1:
|
|
if ((sf == 5) || (sf == 6))
|
|
return ((10 * nextf) + 2); // ACK/NAK in SF 2 next frame
|
|
else if (sf == 9)
|
|
return ((10 * nextf) + 3); // ACK/NAK in SF 3 next frame
|
|
else if ((sf == 0) || (sf == 1))
|
|
return ((10 * f) + 2); // ACK/NAK in SF 7 same frame
|
|
else
|
|
AssertFatal(1 == 0,
|
|
"Impossible dlsch subframe %d for TDD configuration 3\n",
|
|
sf);
|
|
break;
|
|
case 2:
|
|
if ((sf == 4) || (sf == 5) || (sf == 6) || (sf == 8))
|
|
return ((10 * nextf) + 2); // ACK/NAK in SF 2 next frame
|
|
else if (sf == 9)
|
|
return ((10 * nextf) + 7); // ACK/NAK in SF 7 next frame
|
|
else if ((sf == 0) || (sf == 1) || (sf == 3))
|
|
return ((10 * f) + 7); // ACK/NAK in SF 7 same frame
|
|
else
|
|
AssertFatal(1 == 0,
|
|
"Impossible dlsch subframe %d for TDD configuration 3\n",
|
|
sf);
|
|
break;
|
|
case 3:
|
|
if ((sf == 5) || (sf == 6) || (sf == 7) || (sf == 8)
|
|
|| (sf == 9))
|
|
return ((10 * nextf) + (sf >> 1)); // ACK/NAK in 2,3,4 resp. next frame
|
|
else if (sf == 1)
|
|
return ((10 * nextf) + 2); // ACK/NAK in 2 next frame
|
|
else if (sf == 0)
|
|
return ((10 * f) + 4); // ACK/NAK in 4 same frame
|
|
else
|
|
AssertFatal(1 == 0,
|
|
"Impossible dlsch subframe %d for TDD configuration 3\n",
|
|
sf);
|
|
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
|
|
else
|
|
AssertFatal(1 == 0,
|
|
"Impossible dlsch subframe %d for TDD configuration 4\n",
|
|
sf);
|
|
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
|
|
else if (sf == 9)
|
|
return (((10 * (1 + nextf)) + 2) % 10240); // ACK/NAK in SF 2 next frame
|
|
else
|
|
AssertFatal(1 == 0,
|
|
"Impossible dlsch subframe %d for TDD configuration 5\n",
|
|
sf);
|
|
break;
|
|
case 6:
|
|
AssertFatal(1 == 0, "SFA 6 To be filled in now, :-)\n");
|
|
break;
|
|
default:
|
|
AssertFatal(1 == 0, "Illegal TDD subframe Assigment %d\n",
|
|
(int) cc->tdd_Config->subframeAssignment);
|
|
break;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
if ((isrs > 14) && (isrs < 25)) {
|
|
*psrsPeriodicity = 10;
|
|
*psrsOffset = isrs - 15;
|
|
}
|
|
if ((isrs > 24) && (isrs < 45)) {
|
|
*psrsPeriodicity = 20;
|
|
*psrsOffset = isrs - 25;
|
|
}
|
|
if ((isrs > 44) && (isrs < 85)) {
|
|
*psrsPeriodicity = 40;
|
|
*psrsOffset = isrs - 45;
|
|
}
|
|
if ((isrs > 84) && (isrs < 165)) {
|
|
*psrsPeriodicity = 80;
|
|
*psrsOffset = isrs - 85;
|
|
}
|
|
if ((isrs > 164) && (isrs < 325)) {
|
|
*psrsPeriodicity = 160;
|
|
*psrsOffset = isrs - 165;
|
|
}
|
|
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;
|
|
}
|
|
if ((isrs > 1) && (isrs < 7)) {
|
|
*psrsPeriodicity = 5;
|
|
*psrsOffset = isrs - 2;
|
|
}
|
|
if ((isrs > 6) && (isrs < 17)) {
|
|
*psrsPeriodicity = 10;
|
|
*psrsOffset = isrs - 7;
|
|
}
|
|
if ((isrs > 16) && (isrs < 37)) {
|
|
*psrsPeriodicity = 20;
|
|
*psrsOffset = isrs - 17;
|
|
}
|
|
if ((isrs > 36) && (isrs < 77)) {
|
|
*psrsPeriodicity = 40;
|
|
*psrsOffset = isrs - 37;
|
|
}
|
|
if ((isrs > 76) && (isrs < 157)) {
|
|
*psrsPeriodicity = 80;
|
|
*psrsOffset = isrs - 77;
|
|
}
|
|
if ((isrs > 156) && (isrs < 317)) {
|
|
*psrsPeriodicity = 160;
|
|
*psrsOffset = isrs - 157;
|
|
}
|
|
if ((isrs > 316) && (isrs < 637)) {
|
|
*psrsPeriodicity = 320;
|
|
*psrsOffset = isrs - 317;
|
|
}
|
|
AssertFatal(isrs <= 636, "Isrs out of range %d>636\n", isrs);
|
|
}
|
|
}
|
|
|
|
void
|
|
get_csi_params(COMMON_channels_t * cc,
|
|
struct CQI_ReportPeriodic *cqi_ReportPeriodic,
|
|
uint16_t * Npd, uint16_t * N_OFFSET_CQI, int *H)
|
|
{
|
|
uint16_t cqi_PMI_ConfigIndex =
|
|
cqi_ReportPeriodic->choice.setup.cqi_pmi_ConfigIndex;
|
|
uint8_t Jtab[6] = { 0, 2, 2, 3, 4, 4 };
|
|
|
|
AssertFatal(cqi_ReportPeriodic != NULL,
|
|
"cqi_ReportPeriodic is null!\n");
|
|
|
|
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 ==
|
|
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;
|
|
}
|
|
|
|
uint8_t
|
|
get_dl_cqi_pmi_size_pusch(COMMON_channels_t * cc, uint8_t tmode,
|
|
uint8_t ri,
|
|
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 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));
|
|
else if (ri == 2 && cc->p_eNB == 2)
|
|
return (8 + N);
|
|
else if (ri == 1 && cc->p_eNB == 4)
|
|
return (4 + (N << 2));
|
|
else if (ri > 1 && cc->p_eNB == 4)
|
|
return (8 + (N << 2));
|
|
break;
|
|
case 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);
|
|
break;
|
|
case 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 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));
|
|
break;
|
|
case 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);
|
|
else if (ri == 2 && cc->p_eNB == 2)
|
|
return (4 + (N << 1) + 4 + (N << 1) + 1);
|
|
else if (ri == 1 && cc->p_eNB == 4)
|
|
return (4 + (N << 1) + 0 + 0 + 4);
|
|
else if (ri >= 2 && cc->p_eNB == 4)
|
|
return (4 + (N << 1) + 4 + (N << 1) + 4);
|
|
break;
|
|
case 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 CQI_ReportModeAperiodic_rm10_v1310:
|
|
// Table 5.2.2.6.1-1F/G (36.212)
|
|
if (ri == 1)
|
|
return (4); // F
|
|
else
|
|
return (7); // G
|
|
break;
|
|
case 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);
|
|
else if (ri == 2 && cc->p_eNB == 2)
|
|
return (4 + 4 + 1);
|
|
else if (ri == 1 && cc->p_eNB == 4)
|
|
return (4 + 0 + 4);
|
|
else if (ri > 1 && cc->p_eNB == 4)
|
|
return (4 + 4 + 4);
|
|
|
|
break;
|
|
}
|
|
AssertFatal(1 == 0, "Shouldn't get here\n");
|
|
return (0);
|
|
}
|
|
|
|
uint8_t
|
|
get_rel8_dl_cqi_pmi_size(UE_sched_ctrl * sched_ctl, int CC_idP,
|
|
COMMON_channels_t * cc, uint8_t tmode,
|
|
struct 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 !=
|
|
CQI_ReportPeriodic_PR_NOTHING,
|
|
"cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_NOTHING!\n");
|
|
AssertFatal(cqi_ReportPeriodic->choice.
|
|
setup.cqi_FormatIndicatorPeriodic.present !=
|
|
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;
|
|
}
|
|
|
|
if ((cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.
|
|
present ==
|
|
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);
|
|
else if ((cc->p_eNB == 2) && (ri == 1))
|
|
return (6);
|
|
else if ((cc->p_eNB == 2) && (ri == 2))
|
|
return (8);
|
|
else if ((cc->p_eNB == 4) && (ri == 1))
|
|
return (8);
|
|
else if ((cc->p_eNB == 4) && (ri == 2))
|
|
return (11);
|
|
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 ==
|
|
CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI)
|
|
{
|
|
if ((no_pmi == 1) || ri == 1)
|
|
return (4 + Ltab[cc->mib->message.dl_Bandwidth]);
|
|
else
|
|
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);
|
|
}
|
|
|
|
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.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; // no 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;
|
|
}
|
|
|
|
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 defined(Rel10) || defined(Rel14)
|
|
|
|
if ((UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->
|
|
ext2)
|
|
&& (UE_list->UE_template[CC_idP][UE_idP].
|
|
physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020)
|
|
&& (UE_list->UE_template[CC_idP][UE_idP].
|
|
physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020->
|
|
simultaneousPUCCH_PUSCH_r10)
|
|
&& (*UE_list->UE_template[CC_idP][UE_idP].
|
|
physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020->
|
|
simultaneousPUCCH_PUSCH_r10 ==
|
|
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 =
|
|
&RC.mac[module_idP]->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, (frameP * 10) + subframeP, 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.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 == 1,
|
|
"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 == 0,
|
|
"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.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);
|
|
|
|
if (harq_information)
|
|
fill_nfapi_harq_information(module_idP, CC_idP,
|
|
rnti,
|
|
(frameP * 10) + subframeP,
|
|
harq_information, cce_idx);
|
|
}
|
|
|
|
uint8_t get_V_UL_DAI(module_id_t module_idP, int CC_idP, uint16_t rntiP)
|
|
{
|
|
nfapi_hi_dci0_request_body_t *HI_DCI0_req =
|
|
&RC.mac[module_idP]->HI_DCI0_req[CC_idP].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)
|
|
{
|
|
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);
|
|
|
|
PUSCH_ConfigDedicated_t *puschConfigDedicated;
|
|
// PUSCH_ConfigDedicated_v1020_t *puschConfigDedicated_v1020;
|
|
// PUSCH_ConfigDedicated_v1130_t *puschConfigDedicated_v1130;
|
|
// PUSCH_ConfigDedicated_v1250_t *puschConfigDedicated_v1250;
|
|
|
|
AssertFatal(UE_id >= 0, "UE_id cannot be found, impossible\n");
|
|
AssertFatal(UE_list != NULL, "UE_list is null\n");
|
|
AssertFatal(UE_list->UE_template[CC_idP][UE_id].
|
|
physicalConfigDedicated != NULL,
|
|
"physicalConfigDedicated for rnti %x is null\n", rntiP);
|
|
AssertFatal((puschConfigDedicated = (PUSCH_ConfigDedicated_t *)
|
|
UE_list->UE_template[CC_idP][UE_id].
|
|
physicalConfigDedicated->pusch_ConfigDedicated) != NULL,
|
|
"physicalConfigDedicated->puschConfigDedicated for rnti %x is null\n",
|
|
rntiP);
|
|
#if defined(Rel14) || defined(Rel14)
|
|
/* 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
|
|
#ifdef Rel14
|
|
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;
|
|
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
|
|
harq_information->harq_information_rel10.delta_offset_harq =
|
|
puschConfigDedicated->betaOffset_ACK_Index;
|
|
AssertFatal(UE_list->
|
|
UE_template[CC_idP][UE_id].physicalConfigDedicated->
|
|
pucch_ConfigDedicated != NULL,
|
|
"pucch_ConfigDedicated is null!\n");
|
|
if ((UE_list->UE_template[CC_idP][UE_id].
|
|
physicalConfigDedicated->pucch_ConfigDedicated->
|
|
tdd_AckNackFeedbackMode != NULL)
|
|
&& (*UE_list->UE_template[CC_idP][UE_id].
|
|
physicalConfigDedicated->pucch_ConfigDedicated->
|
|
tdd_AckNackFeedbackMode ==
|
|
PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing))
|
|
harq_information->harq_information_rel10.ack_nack_mode = 1; // multiplexing
|
|
else
|
|
harq_information->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->harq_information_rel10.harq_size = 1;
|
|
else {
|
|
if (harq_information->harq_information_rel10.ack_nack_mode ==
|
|
1)
|
|
harq_information->harq_information_rel10.harq_size =
|
|
get_V_UL_DAI(module_idP, CC_idP, rntiP);
|
|
else
|
|
harq_information->harq_information_rel10.harq_size = 1;
|
|
}
|
|
break;
|
|
default: // for any other TM we need 2 bits harq
|
|
if (cc->tdd_Config == NULL) {
|
|
harq_information->harq_information_rel10.harq_size = 2;
|
|
} else {
|
|
if (harq_information->harq_information_rel10.ack_nack_mode ==
|
|
1)
|
|
harq_information->harq_information_rel10.harq_size =
|
|
get_V_UL_DAI(module_idP, CC_idP, rntiP);
|
|
else
|
|
harq_information->harq_information_rel10.harq_size = 2;
|
|
}
|
|
break;
|
|
} // get Tmode
|
|
}
|
|
|
|
void
|
|
fill_nfapi_harq_information(module_id_t module_idP,
|
|
int CC_idP,
|
|
uint16_t rntiP,
|
|
uint16_t absSFP,
|
|
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");
|
|
#if 0
|
|
/* TODO: revisit, don't use Assert, it's perfectly possible to
|
|
* have physicalConfigDedicated NULL here
|
|
*/
|
|
AssertFatal(UE_list->UE_template[CC_idP][UE_id].
|
|
physicalConfigDedicated != NULL,
|
|
"physicalConfigDedicated for rnti %x is null\n", rntiP);
|
|
#endif
|
|
|
|
harq_information->harq_information_rel11.num_ant_ports = 1;
|
|
|
|
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 ((UE_list->
|
|
UE_template[CC_idP][UE_id].physicalConfigDedicated->
|
|
pucch_ConfigDedicated->tdd_AckNackFeedbackMode != NULL)
|
|
&& (*UE_list->
|
|
UE_template[CC_idP][UE_id].physicalConfigDedicated->
|
|
pucch_ConfigDedicated->tdd_AckNackFeedbackMode ==
|
|
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.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.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(UE_list->
|
|
UE_template[CC_idP]
|
|
[UE_id].physicalConfigDedicated->
|
|
pucch_ConfigDedicated != NULL,
|
|
"pucch_ConfigDedicated is null for TDD!\n");
|
|
if ((UE_list->
|
|
UE_template[CC_idP][UE_id].physicalConfigDedicated->
|
|
pucch_ConfigDedicated->tdd_AckNackFeedbackMode != NULL)
|
|
&& (*UE_list->
|
|
UE_template[CC_idP][UE_id].physicalConfigDedicated->
|
|
pucch_ConfigDedicated->tdd_AckNackFeedbackMode ==
|
|
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.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.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
|
|
}
|
|
|
|
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_body_t *ul_req =
|
|
&eNB->UL_req_tmp[CC_idP][ackNAK_absSF % 10].ul_config_request_body;
|
|
nfapi_ul_config_request_pdu_t *ul_config_pdu =
|
|
&ul_req->ul_config_pdu_list[ul_req->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.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,
|
|
absSFP,
|
|
&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->number_of_pdus++;
|
|
|
|
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.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++;
|
|
}
|
|
|
|
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->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 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)
|
|
{
|
|
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.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
|
|
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 6;
|
|
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.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))
|
|
ul_config_pdu->ulsch_cqi_ri_pdu.
|
|
cqi_ri_information.cqi_ri_information_rel9.
|
|
aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 1;
|
|
else if (cc->p_eNB <= 2)
|
|
ul_config_pdu->ulsch_cqi_ri_pdu.
|
|
cqi_ri_information.cqi_ri_information_rel9.
|
|
aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 0;
|
|
else if (cc->p_eNB == 4)
|
|
ul_config_pdu->ulsch_cqi_ri_pdu.
|
|
cqi_ri_information.cqi_ri_information_rel9.
|
|
aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 2;
|
|
|
|
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");
|
|
|
|
for (int ri = 0;
|
|
ri <
|
|
(1 << ul_config_pdu->ulsch_cqi_ri_pdu.
|
|
cqi_ri_information.cqi_ri_information_rel9.
|
|
aperiodic_cqi_pmi_ri_report.cc[0].ri_size); ri++)
|
|
ul_config_pdu->ulsch_cqi_ri_pdu.
|
|
cqi_ri_information.cqi_ri_information_rel9.
|
|
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);
|
|
|
|
ul_config_pdu->ulsch_cqi_ri_pdu.
|
|
cqi_ri_information.cqi_ri_information_rel9.delta_offset_cqi =
|
|
physicalConfigDedicated->pusch_ConfigDedicated->
|
|
betaOffset_CQI_Index;
|
|
ul_config_pdu->ulsch_cqi_ri_pdu.
|
|
cqi_ri_information.cqi_ri_information_rel9.delta_offset_ri =
|
|
physicalConfigDedicated->pusch_ConfigDedicated->
|
|
betaOffset_RI_Index;
|
|
}
|
|
}
|
|
|
|
#ifdef Rel14
|
|
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.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;
|
|
}
|
|
|
|
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 PRACH_ConfigSIB_v1310 *ext4_prach =
|
|
eNB->common_channels[CC_id].radioResourceConfigCommon_BR->
|
|
ext4->prach_ConfigCommon_v1310;
|
|
|
|
int T;
|
|
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);
|
|
else
|
|
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);
|
|
break;
|
|
case 3: // 50 PRBs, N_NB=8, i_0=1
|
|
return ((int) (1 + (6 * nb_index)));
|
|
break;
|
|
case 5: // 100 PRBs, N_NB=16, i_0=2
|
|
return ((int) (2 + (6 * nb_index)));
|
|
break;
|
|
case 1: // 15 PRBs N_NB=2, i_0=1
|
|
if (nb_index > 0)
|
|
return (1);
|
|
else
|
|
return (0);
|
|
break;
|
|
case 2: // 25 PRBs, N_NB=4, i_0=0
|
|
if (nb_index > 1)
|
|
return (1 + (6 * nb_index));
|
|
else
|
|
return ((6 * nb_index));
|
|
break;
|
|
case 4: // 75 PRBs, N_NB=12, i_0=1
|
|
if (nb_index > 5)
|
|
return (2 + (6 * nb_index));
|
|
else
|
|
return (1 + (6 * nb_index));
|
|
break;
|
|
default:
|
|
AssertFatal(1 == 0, "Impossible dl_Bandwidth %d\n",
|
|
(int) cc->mib->message.dl_Bandwidth);
|
|
break;
|
|
}
|
|
}
|
|
#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 < NUMBER_OF_UE_MAX; 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
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 < NUMBER_OF_UE_MAX; UE_id++) {
|
|
if (UE_list->active[UE_id] != TRUE)
|
|
continue;
|
|
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)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
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]);
|
|
}
|
|
|
|
/*
|
|
uint8_t find_active_UEs(module_id_t module_idP,int CC_id){
|
|
|
|
module_id_t ue_mod_id = 0;
|
|
rnti_t rnti = 0;
|
|
uint8_t nb_active_ue = 0;
|
|
|
|
for (ue_mod_id=0;ue_mod_id<NUMBER_OF_UE_MAX;ue_mod_id++) {
|
|
|
|
if (((rnti=eNB_mac_inst[module_idP][CC_id].UE_template[ue_mod_id].rnti) !=0)&&(eNB_mac_inst[module_idP][CC_id].UE_template[ue_mod_id].ul_active==TRUE)){
|
|
|
|
if (mac_xface->get_eNB_UE_stats(module_idP,rnti) != NULL){ // check at the phy enb_ue state for this rnti
|
|
nb_active_ue++;
|
|
}
|
|
else { // this ue is removed at the phy => remove it at the mac as well
|
|
mac_remove_ue(module_idP, CC_id, ue_mod_id);
|
|
}
|
|
}
|
|
}
|
|
return(nb_active_ue);
|
|
}
|
|
*/
|
|
|
|
|
|
// get aggregation (L) form phy for a give UE
|
|
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);
|
|
}
|
|
|
|
LOG_D(MAC, "Aggregation level %d (cqi %d, bw_index %d, format %d)\n",
|
|
1 << aggregation, cqi, bw_index, dci_fmt);
|
|
|
|
return 1 << aggregation;
|
|
}
|
|
|
|
void dump_ue_list(UE_list_t * listP, int ul_flag)
|
|
{
|
|
int j;
|
|
|
|
if (ul_flag == 0) {
|
|
for (j = listP->head; j >= 0; j = listP->next[j]) {
|
|
LOG_T(MAC, "node %d => %d\n", j, listP->next[j]);
|
|
}
|
|
} else {
|
|
for (j = listP->head_ul; j >= 0; j = listP->next_ul[j]) {
|
|
LOG_T(MAC, "node %d => %d\n", j, listP->next_ul[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
int add_new_ue(module_id_t mod_idP, int cc_idP, rnti_t rntiP, int harq_pidP
|
|
#ifdef Rel14
|
|
, 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 < NUMBER_OF_UE_MAX; 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
|
|
|
|
#ifdef Rel14
|
|
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));
|
|
memset((void *) &UE_list->eNB_UE_stats[cc_idP][UE_id], 0,
|
|
sizeof(eNB_UE_STATS));
|
|
|
|
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] = (j == 0) ? 1 : 0; // 1 because first transmission is with format1A (Msg4) for harq_pid 0
|
|
UE_list->UE_template[cc_idP][UE_id].oldNDI_UL[j] = (j == harq_pidP) ? 0 : 1; // 1st transmission is with Msg3;
|
|
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);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int rrc_mac_remove_ue(module_id_t mod_idP, rnti_t rntiP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int i;
|
|
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
|
|
int UE_id = find_UE_id(mod_idP, rntiP);
|
|
int pCC_id;
|
|
|
|
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);
|
|
|
|
UE_list->active[UE_id] = FALSE;
|
|
UE_list->num_UEs--;
|
|
|
|
if (UE_list->head == UE_id)
|
|
UE_list->head = UE_list->next[UE_id];
|
|
else
|
|
UE_list->next[prev(UE_list, UE_id, 0)] = UE_list->next[UE_id];
|
|
if (UE_list->head_ul == UE_id)
|
|
UE_list->head_ul = UE_list->next_ul[UE_id];
|
|
else
|
|
UE_list->next_ul[prev(UE_list, UE_id, 0)] =
|
|
UE_list->next_ul[UE_id];
|
|
|
|
// clear all remaining pending transmissions
|
|
UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID0] = 0;
|
|
UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID1] = 0;
|
|
UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID2] = 0;
|
|
UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID3] = 0;
|
|
|
|
UE_list->UE_template[pCC_id][UE_id].ul_SR = 0;
|
|
UE_list->UE_template[pCC_id][UE_id].rnti = NOT_A_RNTI;
|
|
UE_list->UE_template[pCC_id][UE_id].ul_active = FALSE;
|
|
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_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;
|
|
|
|
// check if this has an RA process active
|
|
RA_t *ra;
|
|
for (i = 0; i < NB_RA_PROC_MAX; i++) {
|
|
ra = (RA_t *) & RC.mac[mod_idP]->common_channels[pCC_id].ra[i];
|
|
if (ra->rnti == rntiP) {
|
|
ra->state = IDLE;
|
|
ra->timing_offset = 0;
|
|
ra->RRC_timer = 20;
|
|
ra->rnti = 0;
|
|
//break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int prev(UE_list_t * listP, int nodeP, int ul_flag)
|
|
{
|
|
int j;
|
|
|
|
if (ul_flag == 0) {
|
|
if (nodeP == listP->head) {
|
|
return (nodeP);
|
|
}
|
|
|
|
for (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 (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);
|
|
}
|
|
|
|
/*
|
|
#if defined(Rel10) || defined(Rel14)
|
|
unsigned char generate_mch_header( unsigned char *mac_header,
|
|
unsigned char num_sdus,
|
|
unsigned short *sdu_lengths,
|
|
unsigned char *sdu_lcids,
|
|
unsigned char msi,
|
|
unsigned char short_padding,
|
|
unsigned short post_padding) {
|
|
|
|
SCH_SUBHEADER_FIXED *mac_header_ptr = (SCH_SUBHEADER_FIXED *)mac_header;
|
|
uint8_t first_element=0,last_size=0,i;
|
|
uint8_t mac_header_control_elements[2*num_sdus],*ce_ptr;
|
|
|
|
ce_ptr = &mac_header_control_elements[0];
|
|
|
|
if ((short_padding == 1) || (short_padding == 2)) {
|
|
mac_header_ptr->R = 0;
|
|
mac_header_ptr->E = 0;
|
|
mac_header_ptr->LCID = SHORT_PADDING;
|
|
first_element=1;
|
|
last_size=1;
|
|
}
|
|
if (short_padding == 2) {
|
|
mac_header_ptr->E = 1;
|
|
mac_header_ptr++;
|
|
mac_header_ptr->R = 0;
|
|
mac_header_ptr->E = 0;
|
|
mac_header_ptr->LCID = SHORT_PADDING;
|
|
last_size=1;
|
|
}
|
|
|
|
// SUBHEADER for MSI CE
|
|
if (msi != 0) {// there is MSI MAC Control Element
|
|
if (first_element>0) {
|
|
mac_header_ptr->E = 1;
|
|
mac_header_ptr+=last_size;
|
|
}
|
|
else {
|
|
first_element = 1;
|
|
}
|
|
if (num_sdus*2 < 128) {
|
|
((SCH_SUBHEADER_SHORT *)mac_header_ptr)->R = 0;
|
|
((SCH_SUBHEADER_SHORT *)mac_header_ptr)->E = 0;
|
|
((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F = 0;
|
|
((SCH_SUBHEADER_SHORT *)mac_header_ptr)->LCID = MCH_SCHDL_INFO;
|
|
((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L = num_sdus*2;
|
|
last_size=2;
|
|
}
|
|
else {
|
|
((SCH_SUBHEADER_LONG *)mac_header_ptr)->R = 0;
|
|
((SCH_SUBHEADER_LONG *)mac_header_ptr)->E = 0;
|
|
((SCH_SUBHEADER_LONG *)mac_header_ptr)->F = 1;
|
|
((SCH_SUBHEADER_LONG *)mac_header_ptr)->LCID = MCH_SCHDL_INFO;
|
|
((SCH_SUBHEADER_LONG *)mac_header_ptr)->L = (num_sdus*2)&0x7fff;
|
|
last_size=3;
|
|
}
|
|
// Create the MSI MAC Control Element here
|
|
}
|
|
|
|
// SUBHEADER for MAC SDU (MCCH+MTCHs)
|
|
for (i=0;i<num_sdus;i++) {
|
|
if (first_element>0) {
|
|
mac_header_ptr->E = 1;
|
|
mac_header_ptr+=last_size;
|
|
}
|
|
else {
|
|
first_element = 1;
|
|
}
|
|
if (sdu_lengths[i] < 128) {
|
|
((SCH_SUBHEADER_SHORT *)mac_header_ptr)->R = 0;
|
|
((SCH_SUBHEADER_SHORT *)mac_header_ptr)->E = 0;
|
|
((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F = 0;
|
|
((SCH_SUBHEADER_SHORT *)mac_header_ptr)->LCID = sdu_lcids[i];
|
|
((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L = (unsigned char)sdu_lengths[i];
|
|
last_size=2;
|
|
}
|
|
else {
|
|
((SCH_SUBHEADER_LONG *)mac_header_ptr)->R = 0;
|
|
((SCH_SUBHEADER_LONG *)mac_header_ptr)->E = 0;
|
|
((SCH_SUBHEADER_LONG *)mac_header_ptr)->F = 1;
|
|
((SCH_SUBHEADER_LONG *)mac_header_ptr)->LCID = sdu_lcids[i];
|
|
((SCH_SUBHEADER_LONG *)mac_header_ptr)->L = (unsigned short) sdu_lengths[i]&0x7fff;
|
|
last_size=3;
|
|
}
|
|
}
|
|
|
|
if (post_padding>0) {// we have lots of padding at the end of the packet
|
|
mac_header_ptr->E = 1;
|
|
mac_header_ptr+=last_size;
|
|
// add a padding element
|
|
mac_header_ptr->R = 0;
|
|
mac_header_ptr->E = 0;
|
|
mac_header_ptr->LCID = SHORT_PADDING;
|
|
mac_header_ptr++;
|
|
}
|
|
else { // no end of packet padding
|
|
// last SDU subhead is of fixed type (sdu length implicitly to be computed at UE)
|
|
mac_header_ptr++;
|
|
}
|
|
|
|
// Copy MSI Control Element to the end of the MAC Header if it presents
|
|
if ((ce_ptr-mac_header_control_elements) > 0) {
|
|
// printf("Copying %d bytes for control elements\n",ce_ptr-mac_header_control_elements);
|
|
memcpy((void*)mac_header_ptr,mac_header_control_elements,ce_ptr-mac_header_control_elements);
|
|
mac_header_ptr+=(unsigned char)(ce_ptr-mac_header_control_elements);
|
|
}
|
|
|
|
return((unsigned char*)mac_header_ptr - mac_header);
|
|
}
|
|
#endif
|
|
*/
|
|
|
|
// 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 *UE_sched_ctl =
|
|
&RC.mac[module_idP]->UE_list.UE_sched_ctrl[UE_id];
|
|
|
|
// do not schedule UE if UL is not working
|
|
if (UE_sched_ctl->ul_failure_timer > 0)
|
|
return (0);
|
|
if (UE_sched_ctl->ul_out_of_sync > 0)
|
|
return (0);
|
|
|
|
LOG_D(MAC, "[eNB %d][PUSCH] Checking UL requirements UE %d/%x\n",
|
|
module_idP, UE_id, UE_RNTI(module_idP, UE_id));
|
|
|
|
if ((UE_template->bsr_info[LCGID0] > 0) || (UE_template->bsr_info[LCGID1] > 0) || (UE_template->bsr_info[LCGID2] > 0) || (UE_template->bsr_info[LCGID3] > 0) || (UE_template->ul_SR > 0) || // uplink scheduling request
|
|
((UE_sched_ctl->ul_inactivity_timer > 20) && (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) && (mac_eNB_get_rrc_status(module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED))) // every Frame when not RRC_CONNECTED
|
|
{
|
|
LOG_D(MAC,
|
|
"[eNB %d][PUSCH] UE %d/%x should be scheduled (BSR0 %d,SR %d)\n",
|
|
module_idP, UE_id, UE_RNTI(module_idP, UE_id),
|
|
UE_template->bsr_info[LCGID0], UE_template->ul_SR);
|
|
return (1);
|
|
} else {
|
|
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 PhysicalConfigDedicated *physicalConfigDedicated =
|
|
eNB->UE_list.physicalConfigDedicated[CC_idP][UE_idP];
|
|
|
|
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);
|
|
} else {
|
|
AssertFatal(physicalConfigDedicated->antennaInfo != NULL,
|
|
"antennaInfo is null for CCId %d, UEid %d\n", CC_idP,
|
|
UE_idP);
|
|
|
|
AssertFatal(physicalConfigDedicated->antennaInfo->present !=
|
|
PhysicalConfigDedicated__antennaInfo_PR_NOTHING,
|
|
"antennaInfo (mod_id %d, CC_id %d) is set to NOTHING\n",
|
|
module_idP, CC_idP);
|
|
|
|
if (physicalConfigDedicated->antennaInfo->present ==
|
|
PhysicalConfigDedicated__antennaInfo_PR_explicitValue) {
|
|
return (physicalConfigDedicated->antennaInfo->
|
|
choice.explicitValue.transmissionMode);
|
|
} else if (physicalConfigDedicated->antennaInfo->present ==
|
|
PhysicalConfigDedicated__antennaInfo_PR_defaultValue) {
|
|
AssertFatal(cc->p_eNB <= 2, "p_eNB is %d, should be <2\n",
|
|
cc->p_eNB);
|
|
return (cc->p_eNB);
|
|
} else
|
|
AssertFatal(1 == 0, "Shouldn't be here\n");
|
|
}
|
|
}
|
|
|
|
int8_t
|
|
get_ULharq(module_id_t module_idP, int CC_idP, uint16_t frameP,
|
|
uint8_t subframeP)
|
|
{
|
|
uint8_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:
|
|
if ((subframeP == 2) ||
|
|
(subframeP == 3) || (subframeP == 7) || (subframeP == 8))
|
|
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 = check + 1;
|
|
// 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
|
|
|
|
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 module_idP, int CC_idP)
|
|
{
|
|
memset(RC.mac[module_idP]->CCE_table[CC_idP], 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);
|
|
|
|
} else { // 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;
|
|
}
|
|
|
|
printf("rnti %x, Yk*L = %d, 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);
|
|
else
|
|
return (1);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
if ((subframe == 0) || (subframe == 5))
|
|
return (0);
|
|
else
|
|
return (1);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
if ((subframe == 3) || (subframe == 8))
|
|
return (1);
|
|
else
|
|
return (0);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
if ((subframe == 0) || (subframe == 8) || (subframe == 9))
|
|
return (1);
|
|
else
|
|
return (0);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
if ((subframe == 8) || (subframe == 9))
|
|
return (1);
|
|
else
|
|
return (0);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
if (subframe == 8)
|
|
return (1);
|
|
else
|
|
return (0);
|
|
|
|
break;
|
|
|
|
case 6:
|
|
return (1);
|
|
break;
|
|
|
|
default:
|
|
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)
|
|
{
|
|
int *CCE_table = RC.mac[module_idP]->CCE_table[CC_idP];
|
|
nfapi_dl_config_request_body_t *DL_req =
|
|
&RC.mac[module_idP]->DL_req[CC_idP].dl_config_request_body;
|
|
nfapi_hi_dci0_request_body_t *HI_DCI0_req =
|
|
&RC.mac[module_idP]->HI_DCI0_req[CC_idP].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];
|
|
int nCCE_max =
|
|
get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP], 1,
|
|
subframeP);
|
|
int fCCE;
|
|
int i, j, idci;
|
|
int nCCE = 0;
|
|
|
|
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
|
COMMON_channels_t *cc = &eNB->common_channels[CC_idP];
|
|
int ackNAK_absSF = get_pucch1_absSF(cc, (frameP*10+subframeP));
|
|
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(module_idP, CC_idP);
|
|
nCCE = 0;
|
|
|
|
for (i = 0, idci = 0; i < DL_req->number_pdu; i++) {
|
|
// allocate DL common DCIs first
|
|
if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)
|
|
&& (dl_config_pdu[i].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_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti,
|
|
dl_config_pdu[i].dci_dl_pdu.
|
|
dci_dl_pdu_rel8.aggregation_level, nCCE, nCCE_max,
|
|
DL_req->number_pdcch_ofdm_symbols);
|
|
|
|
if (nCCE +
|
|
(dl_config_pdu[i].dci_dl_pdu.
|
|
dci_dl_pdu_rel8.aggregation_level) > nCCE_max) {
|
|
if (DL_req->number_pdcch_ofdm_symbols == 3)
|
|
goto failed;
|
|
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(&RC.mac[module_idP]->
|
|
common_channels[CC_idP],
|
|
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_pdu[i].
|
|
dci_dl_pdu.dci_dl_pdu_rel8.
|
|
aggregation_level, nCCE_max, 1,
|
|
dl_config_pdu[i].
|
|
dci_dl_pdu.dci_dl_pdu_rel8.rnti,
|
|
subframeP);
|
|
if (fCCE == -1) {
|
|
if (DL_req->number_pdcch_ofdm_symbols == 3) {
|
|
LOG_D(MAC,
|
|
"subframe %d: Dropping Allocation for RNTI %x\n",
|
|
subframeP,
|
|
dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.
|
|
rnti);
|
|
for (j = 0; j <= i; j++) {
|
|
if (dl_config_pdu[j].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_pdu[j].
|
|
dci_dl_pdu.dci_dl_pdu_rel8.rnti,
|
|
dl_config_pdu[j].
|
|
dci_dl_pdu.dci_dl_pdu_rel8.dci_format,
|
|
dl_config_pdu[j].
|
|
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);
|
|
goto failed;
|
|
}
|
|
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(&RC.mac[module_idP]->
|
|
common_channels[CC_idP],
|
|
DL_req->number_pdcch_ofdm_symbols,
|
|
subframeP);
|
|
goto try_again;
|
|
} // fCCE==-1
|
|
|
|
// the allocation is feasible, rnti rule passes
|
|
nCCE +=
|
|
dl_config_pdu[i].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_pdu[i].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_pdu[i].dci_dl_pdu.
|
|
dci_dl_pdu_rel8.aggregation_level, fCCE);
|
|
}
|
|
idci++;
|
|
}
|
|
} // for i = 0 ... num_DL_DCIs
|
|
|
|
// no try to allocate UL DCIs
|
|
for (i = 0; i < HI_DCI0_req->number_of_dci + HI_DCI0_req->number_of_hi;
|
|
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_pdu[i].dci_pdu.dci_pdu_rel8.rnti,
|
|
hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level,
|
|
nCCE, nCCE_max, DL_req->number_pdcch_ofdm_symbols);
|
|
|
|
if (nCCE +
|
|
(hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level) >
|
|
nCCE_max) {
|
|
if (DL_req->number_pdcch_ofdm_symbols == 3)
|
|
goto failed;
|
|
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(&RC.mac[module_idP]->
|
|
common_channels[CC_idP],
|
|
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_pdu[i].dci_pdu.
|
|
dci_pdu_rel8.aggregation_level,
|
|
nCCE_max, 0,
|
|
hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.
|
|
rnti, subframeP);
|
|
if (fCCE == -1) {
|
|
if (DL_req->number_pdcch_ofdm_symbols == 3) {
|
|
LOG_D(MAC,
|
|
"subframe %d: Dropping Allocation for RNTI %x\n",
|
|
subframeP,
|
|
hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti);
|
|
for (j = 0; j <= i; 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_pdu[j].dci_pdu.dci_pdu_rel8.rnti,
|
|
hi_dci0_pdu[j].dci_pdu.dci_pdu_rel8.
|
|
dci_format,
|
|
hi_dci0_pdu[j].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);
|
|
goto failed;
|
|
}
|
|
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(&RC.mac[module_idP]->
|
|
common_channels[CC_idP],
|
|
DL_req->number_pdcch_ofdm_symbols,
|
|
subframeP);
|
|
goto try_again;
|
|
} // fCCE==-1
|
|
|
|
// the allocation is feasible, rnti rule passes
|
|
nCCE += hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level;
|
|
LOG_D(MAC, "Allocating at nCCE %d\n", fCCE);
|
|
if ((test_onlyP%2) == 0) {
|
|
hi_dci0_pdu[i].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++) {
|
|
// allocate DL UE specific DCIs
|
|
if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)
|
|
&& (dl_config_pdu[i].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_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti,
|
|
dl_config_pdu[i].dci_dl_pdu.
|
|
dci_dl_pdu_rel8.aggregation_level, nCCE, nCCE_max,
|
|
DL_req->number_pdcch_ofdm_symbols);
|
|
|
|
if (nCCE +
|
|
(dl_config_pdu[i].dci_dl_pdu.
|
|
dci_dl_pdu_rel8.aggregation_level) > nCCE_max) {
|
|
if (DL_req->number_pdcch_ofdm_symbols == 3)
|
|
goto failed;
|
|
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(&RC.mac[module_idP]->
|
|
common_channels[CC_idP],
|
|
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_pdu[i].
|
|
dci_dl_pdu.dci_dl_pdu_rel8.
|
|
aggregation_level, nCCE_max, 0,
|
|
dl_config_pdu[i].
|
|
dci_dl_pdu.dci_dl_pdu_rel8.rnti,
|
|
subframeP);
|
|
if (fCCE == -1) {
|
|
if (DL_req->number_pdcch_ofdm_symbols == 3) {
|
|
LOG_I(MAC,
|
|
"subframe %d: Dropping Allocation for RNTI %x\n",
|
|
subframeP,
|
|
dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.
|
|
rnti);
|
|
for (j = 0; j <= i; j++) {
|
|
if (dl_config_pdu[j].pdu_type ==
|
|
NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)
|
|
LOG_I(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_pdu[j].
|
|
dci_dl_pdu.dci_dl_pdu_rel8.rnti,
|
|
dl_config_pdu[j].
|
|
dci_dl_pdu.dci_dl_pdu_rel8.dci_format,
|
|
dl_config_pdu[j].
|
|
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);
|
|
goto failed;
|
|
}
|
|
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(&RC.mac[module_idP]->
|
|
common_channels[CC_idP],
|
|
DL_req->number_pdcch_ofdm_symbols,
|
|
subframeP);
|
|
goto try_again;
|
|
} // fCCE==-1
|
|
|
|
// the allocation is feasible, rnti rule passes
|
|
nCCE +=
|
|
dl_config_pdu[i].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_pdu[i].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)){
|
|
ul_req->ul_config_pdu_list[ack_int].uci_harq_pdu.harq_information.harq_information_rel9_fdd.n_pucch_1_0 = fCCE;
|
|
}
|
|
}
|
|
}
|
|
idci++;
|
|
}
|
|
} // for i = 0 ... num_DL_DCIs
|
|
|
|
return 0;
|
|
|
|
failed:
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
uint8_t get_ul_req_index(module_id_t module_idP, int CC_idP, sub_frame_t subframeP)
|
|
{
|
|
if (RC.mac[module_idP]->common_channels[CC_idP].tdd_Config == NULL)
|
|
return(0);
|
|
|
|
switch (RC.mac[module_idP]->common_channels[CC_idP].tdd_Config->subframeAssignment) {
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
case 6:
|
|
return(0);
|
|
case 3:
|
|
// 1,5,6 -> 2, prog. 8, buffer 0
|
|
// 7,8 -> 3, prog. 9, buffer 1
|
|
// 9,0 -> 4, prog. 0, buffer 0
|
|
if ((subframeP == 7) || (subframeP == 8)) return(1);
|
|
else return(0);
|
|
case 4:
|
|
// 0,1,4,5 -> 2, prog. 8, buffer 0
|
|
// 6,7,8,9 -> 3, prog. 9, buffer 1
|
|
if (subframeP<6) return(0);
|
|
else return(1);
|
|
return(1);
|
|
break;
|
|
case 5:
|
|
// 9(-1),0,1,3,4,5,6,7,8,9 -> 2, prog 8, buffer 0
|
|
return(0);
|
|
break;
|
|
default:
|
|
AssertFatal(1==0,"Should not get here, why is tdd_Config->subframeAssignment = %d\n",(int)RC.mac[module_idP]->common_channels[CC_idP].tdd_Config->subframeAssignment);
|
|
break;
|
|
}
|
|
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;
|
|
nfapi_ul_config_request_pdu_t *ul_config_pdu;
|
|
|
|
ul_req =
|
|
&RC.mac[module_idP]->UL_req_tmp[CC_idP][absSFP %
|
|
10].ul_config_request_body;
|
|
ul_config_pdu = &ul_req->ul_config_pdu_list[0];
|
|
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++) {
|
|
LOG_D(MAC, "PDU %d : type %d,rnti %x\n", i,
|
|
ul_config_pdu[i].pdu_type, rnti);
|
|
if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE)
|
|
&& (ul_config_pdu[i].ulsch_pdu.ulsch_pdu_rel8.rnti == rnti))
|
|
return (&ul_config_pdu[i]);
|
|
if ((ul_config_pdu[i].pdu_type ==
|
|
NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE)
|
|
&& (ul_config_pdu[i].ulsch_cqi_ri_pdu.ulsch_pdu.
|
|
ulsch_pdu_rel8.rnti == rnti))
|
|
return (&ul_config_pdu[i]);
|
|
if ((ul_config_pdu[i].pdu_type ==
|
|
NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE)
|
|
&& (ul_config_pdu[i].ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.
|
|
rnti == rnti))
|
|
return (&ul_config_pdu[i]);
|
|
if ((ul_config_pdu[i].pdu_type ==
|
|
NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE)
|
|
&& (ul_config_pdu[i].ulsch_cqi_harq_ri_pdu.
|
|
ulsch_pdu.ulsch_pdu_rel8.rnti == rnti))
|
|
return (&ul_config_pdu[i]);
|
|
|
|
if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE)
|
|
&& (ul_config_pdu[i].uci_cqi_pdu.
|
|
ue_information.ue_information_rel8.rnti == rnti))
|
|
return (&ul_config_pdu[i]);
|
|
if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE)
|
|
&& (ul_config_pdu[i].uci_sr_pdu.
|
|
ue_information.ue_information_rel8.rnti == rnti))
|
|
return (&ul_config_pdu[i]);
|
|
if ((ul_config_pdu[i].pdu_type ==
|
|
NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE)
|
|
&& (ul_config_pdu[i].uci_harq_pdu.
|
|
ue_information.ue_information_rel8.rnti == rnti))
|
|
return (&ul_config_pdu[i]);
|
|
if ((ul_config_pdu[i].pdu_type ==
|
|
NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE)
|
|
&& (ul_config_pdu[i].uci_sr_harq_pdu.
|
|
ue_information.ue_information_rel8.rnti == rnti))
|
|
return (&ul_config_pdu[i]);
|
|
if ((ul_config_pdu[i].pdu_type ==
|
|
NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE)
|
|
&& (ul_config_pdu[i].uci_cqi_harq_pdu.
|
|
ue_information.ue_information_rel8.rnti == rnti))
|
|
return (&ul_config_pdu[i]);
|
|
if ((ul_config_pdu[i].pdu_type ==
|
|
NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE)
|
|
&& (ul_config_pdu[i].uci_cqi_sr_pdu.
|
|
ue_information.ue_information_rel8.rnti == rnti))
|
|
return (&ul_config_pdu[i]);
|
|
if ((ul_config_pdu[i].pdu_type ==
|
|
NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE)
|
|
&& (ul_config_pdu[i].uci_cqi_sr_harq_pdu.
|
|
ue_information.ue_information_rel8.rnti == rnti))
|
|
return (&ul_config_pdu[i]);
|
|
|
|
if ((ul_config_pdu[i].pdu_type ==
|
|
NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE)
|
|
&& (ul_config_pdu[i].ulsch_uci_csi_pdu.
|
|
ulsch_pdu.ulsch_pdu_rel8.rnti == rnti))
|
|
return (&ul_config_pdu[i]);
|
|
if ((ul_config_pdu[i].pdu_type ==
|
|
NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE)
|
|
&& (ul_config_pdu[i].ulsch_uci_harq_pdu.
|
|
ulsch_pdu.ulsch_pdu_rel8.rnti == rnti))
|
|
return (&ul_config_pdu[i]);
|
|
if ((ul_config_pdu[i].pdu_type ==
|
|
NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE)
|
|
&& (ul_config_pdu[i].ulsch_csi_uci_harq_pdu.
|
|
ulsch_pdu.ulsch_pdu_rel8.rnti == rnti))
|
|
return (&ul_config_pdu[i]);
|
|
}
|
|
|
|
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].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];
|
|
int ret;
|
|
boolean_t res = FALSE;
|
|
|
|
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->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) (%x,%d,%d)\n",
|
|
subframe, format_flag, rnti, aggregation,
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti,
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.
|
|
aggregation_level,
|
|
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type);
|
|
ret = allocate_CCEs(module_idP, CC_idP, 0, subframe, 0);
|
|
if (ret == -1)
|
|
res = TRUE;
|
|
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.rnti = rnti;
|
|
hi_dci0_pdu->dci_pdu.dci_pdu_rel8.aggregation_level =
|
|
aggregation;
|
|
HI_DCI0_req->number_of_dci++;
|
|
ret = allocate_CCEs(module_idP, CC_idP, 0, subframe, 0);
|
|
if (ret == -1)
|
|
res = TRUE;
|
|
HI_DCI0_req->number_of_dci--;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
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)
|
|
{
|
|
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
|
|
UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
|
|
rnti_t rnti = UE_RNTI(mod_idP, UE_id);
|
|
COMMON_channels_t *cc = &RC.mac[mod_idP]->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;
|
|
uint8_t *pdu;
|
|
|
|
#ifdef Rel14
|
|
if (UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated != NULL &&
|
|
UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->pucch_ConfigDedicated != NULL &&
|
|
(UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7)
|
|
&& (UE_list->UE_template[pCCid][UE_id].
|
|
physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13)
|
|
&&
|
|
(((UE_list->UE_template[pCCid][UE_id].
|
|
physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13->
|
|
spatialBundlingPUCCH_r13)
|
|
&& (format == 0))
|
|
||
|
|
((UE_list->UE_template[pCCid][UE_id].
|
|
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
|
|
AssertFatal(numCC == 1,
|
|
"numCC %d > 1, should not be using Format1a/b\n",
|
|
numCC);
|
|
break;
|
|
case 1: // Channel Selection
|
|
break;
|
|
case 2: // Format 3
|
|
break;
|
|
case 3: // Format 4
|
|
break;
|
|
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];
|
|
|
|
uint8_t harq_pid = ((10 * frameP) + subframeP + 10236) & 7;
|
|
|
|
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\n",
|
|
num_ack_nak);
|
|
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);
|
|
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);
|
|
|
|
if (pdu[0] == 1) { // ACK
|
|
sched_ctl->round[CC_idP][harq_pid] = 8; // release HARQ process
|
|
sched_ctl->tbcnt[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
|
|
} 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;
|
|
}
|
|
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]++;
|
|
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;
|
|
} 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]++;
|
|
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 (pdu[1] == 1)
|
|
sched_ctl->round[1 - pCCid][harq_pid] = 8;
|
|
else
|
|
sched_ctl->round[1 - pCCid][harq_pid]++;
|
|
} // 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;
|
|
} else
|
|
sched_ctl->round[pCCid][harq_pid]++;
|
|
|
|
if (pdu[2] == 1)
|
|
sched_ctl->round[1 - pCCid][harq_pid] = 8;
|
|
else
|
|
sched_ctl->round[1 - pCCid][harq_pid]++;
|
|
} // 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;
|
|
} else // both NAK/DTX
|
|
sched_ctl->round[1 - pCCid][harq_pid]++;
|
|
|
|
if (pdu[2] == 1)
|
|
sched_ctl->round[pCCid][harq_pid] = 8;
|
|
else
|
|
sched_ctl->round[pCCid][harq_pid]++;
|
|
} // 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;
|
|
} else // both NAK/DTX
|
|
sched_ctl->round[0][harq_pid]++;
|
|
|
|
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;
|
|
} else // both NAK/DTX
|
|
sched_ctl->round[1][harq_pid]++;
|
|
} // 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]++;
|
|
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;
|
|
} 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;
|
|
} else if ((sched_ctl->tbcnt[i][harq_pid] == 2)
|
|
&& (pdu[j] == 2) && (pdu[j + 1] == 2)) {
|
|
sched_ctl->round[i][harq_pid]++;
|
|
} 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]++;
|
|
} 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
|
|
COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP];
|
|
struct CQI_ReportPeriodic *cqi_ReportPeriodic;
|
|
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);
|
|
AssertFatal((cqi_ReportPeriodic =
|
|
UE_list->
|
|
UE_template[CC_idP][UE_id].physicalConfigDedicated->
|
|
cqi_ReportConfig->cqi_ReportPeriodic) != NULL,
|
|
"cqi_ReportPeriodic is null for UE %d\n", UE_id);
|
|
|
|
// determine feedback mode
|
|
AssertFatal(cqi_ReportPeriodic->present !=
|
|
CQI_ReportPeriodic_PR_NOTHING,
|
|
"cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_NOTHING!\n");
|
|
AssertFatal(cqi_ReportPeriodic->choice.
|
|
setup.cqi_FormatIndicatorPeriodic.present !=
|
|
CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING,
|
|
"cqi_ReportPeriodic->cqi_FormatIndicatorPeriodic.choice.setup.present == 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;
|
|
}
|
|
|
|
if ((cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.
|
|
present ==
|
|
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 ==
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 *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;
|
|
CQI_ReportModeAperiodic_t *cqi_ReportModeAperiodic;
|
|
|
|
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);
|
|
AssertFatal((cqi_ReportModeAperiodic =
|
|
UE_list->
|
|
UE_template[CC_idP][UE_id].physicalConfigDedicated->
|
|
cqi_ReportConfig->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 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 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 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 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 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;
|
|
case 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;
|
|
case 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 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;
|
|
}
|
|
}
|
|
|
|
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 *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
|
|
|
|
if (UE_id >= 0) {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
// timing advance
|
|
sched_ctl->timing_advance = rel9->timing_advance;
|
|
sched_ctl->timing_advance_r9 = rel9->timing_advance_r9;
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
if (UE_id != -1) {
|
|
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);
|
|
|
|
#if 0
|
|
UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
|
|
|
|
/* for the moment don't use ul_cqi from SR, value is too different from harq */
|
|
sched_ctl->pucch1_snr[cc_idP] = ul_cqi;
|
|
sched_ctl->pucch1_cqi_update[cc_idP] = 1;
|
|
#endif
|
|
|
|
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 {
|
|
// 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_D(MAC,
|
|
"[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d (unknown UEid) on CC_id %d\n",
|
|
mod_idP, rntiP, frameP, subframeP, UE_id, cc_idP);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
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 *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
|
|
COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP];
|
|
// extract HARQ Information
|
|
LOG_D(MAC,
|
|
"Frame %d, subframe %d: Received harq indication (%d) from UE %d/%x, ul_cqi %d\n",
|
|
frameP, subframeP, channel, UE_id, rnti, ul_cqi);
|
|
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);
|
|
if (channel == 0) {
|
|
sched_ctl->pucch1_snr[CC_idP] = ul_cqi;
|
|
sched_ctl->pucch1_cqi_update[CC_idP] = 1;
|
|
}
|
|
}
|