Files
openairinterface5g/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
T
Robert Schmidt 0b91791f67 Use (std) bool instead of custom bool types
OAI is riddled with boolean_t, FALSE, TRUE, etc. This makes no sense, as
there is a standard bool type, and could lead to nasty bugs if a
definition of a bool is non-standard (0 == false, true == !false). This
commit removes all non-standard bools in the whole project.
2022-06-27 10:07:48 +02:00

5190 lines
185 KiB
C

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