Files
openairinterface5g/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
T
Bi-Ruei, Chiu 5c23af773a Compare version number using MAKE_VERSION macro to provide better SW configuration:
1. Previous SW configuration for different RRC version relies on whether macro Rel10,
   Rel14 defined or not by checking #ifdef Rel14 or #if defined(Rel10) || defined(R14).
   Whenever there is a newer RRC version, e.g. Rel15, it will be very a tedious and
   error-prone job to add defined(Rel15) in every place.

2. Some RRC messages are defined in release 13 instead of release 14, NB-IoT
   feature is one of such example. Our code shall reflect this fact instead of using
   an afterward version number in software configuration.

3. Some RRC messages or some fields of certain RRC messages are added in the middle
   a release, e.g. SystemInformationBlockType1_v1310_IEs_t defined in RRC 13.1.0
   and RRC 9.2.0 made some changes to SIB12 and SIB13 so we have sib12_v920 and
   sib13_v920 fields in SIB12 and SIB13's struct.
   We need a finer grain of control when using ASN1 from different RRC version.

4. S1AP also has this problem that it use UPDATE_RELEASE_9 and UPDATE_RELEASE_10 to
   differentiate between various S1AP version.

This commit propose using MAKE_VERSION(x,y,z) to designate the version number and
modify current conditional compilation accordingly.

Note: 2018/04/16, Modified based on Cedric's comment.
2018-04-16 12:32:29 +02:00

4159 lines
141 KiB
C

/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file eNB_scheduler_primitives.c
* \brief primitives used by eNB for BCH, RACH, ULSCH, DLSCH scheduling
* \author Navid Nikaein and Raymond Knopp
* \date 2010 - 2014
* \email: navid.nikaein@eurecom.fr
* \version 1.0
* @ingroup _mac
*/
#include "assertions.h"
#include "PHY/defs.h"
#include "PHY/extern.h"
#include "SCHED/defs.h"
#include "SCHED/extern.h"
#include "LAYER2/MAC/defs.h"
#include "LAYER2/MAC/extern.h"
#include "LAYER2/MAC/proto.h"
#include "UTIL/LOG/log.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h"
#include "OCG.h"
#include "OCG_extern.h"
#include "RRC/LITE/extern.h"
#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
//#include "LAYER2/MAC/pre_processor.c"
#include "pdcp.h"
#if defined(ENABLE_ITTI)
#include "intertask_interface.h"
#endif
#include "T.h"
#define ENABLE_MAC_PAYLOAD_DEBUG
#define DEBUG_eNB_SCHEDULER 1
extern int n_active_slices;
int choose(int n, int k)
{
int res = 1;
int res2 = 1;
int i;
if (k > n)
return (0);
if (n == k)
return (1);
for (i = n; i > k; i--)
res *= i;
for (i = 2; i <= (n - k); i++)
res2 *= i;
return (res / res2);
}
// Patented algorithm from Yang et al, US Patent 2009, "Channel Quality Indexing and Reverse Indexing"
void reverse_index(int N, int M, int r, int *v)
{
int BaseValue = 0;
int IncreaseValue, ThresholdValue;
int sumV;
int i;
r = choose(N, M) - 1 - r;
memset((void *) v, 0, M * sizeof(int));
sumV = 0;
i = M;
while (i > 0 && r > 0) {
IncreaseValue = choose(N - M + 1 - sumV - v[i - 1] + i - 2, i - 1);
ThresholdValue = BaseValue + IncreaseValue;
if (r >= ThresholdValue) {
v[i - 1]++;
BaseValue = ThresholdValue;
} else {
r = r - BaseValue;
sumV += v[i - 1];
i--;
BaseValue = 0;
}
}
}
int to_prb(int dl_Bandwidth)
{
int prbmap[6] = { 6, 15, 25, 50, 75, 100 };
AssertFatal(dl_Bandwidth < 6, "dl_Bandwidth is 0..5\n");
return (prbmap[dl_Bandwidth]);
}
int to_rbg(int dl_Bandwidth)
{
int rbgmap[6] = { 6, 8, 13, 17, 19, 25 };
AssertFatal(dl_Bandwidth < 6, "dl_Bandwidth is 0..5\n");
return (rbgmap[dl_Bandwidth]);
}
int get_phich_resource_times6(COMMON_channels_t * cc)
{
int phichmap[4] = { 1, 3, 6, 12 };
AssertFatal(cc != NULL, "cc is null\n");
AssertFatal(cc->mib != NULL, "cc->mib is null\n");
AssertFatal((cc->mib->message.phich_Config.phich_Resource >= 0) &&
(cc->mib->message.phich_Config.phich_Resource < 4),
"phich_Resource %d not in 0..3\n",
(int) cc->mib->message.phich_Config.phich_Resource);
return (phichmap[cc->mib->message.phich_Config.phich_Resource]);
}
uint16_t mac_computeRIV(uint16_t N_RB_DL, uint16_t RBstart, uint16_t Lcrbs)
{
uint16_t RIV;
if (Lcrbs <= (1 + (N_RB_DL >> 1))) RIV = (N_RB_DL * (Lcrbs - 1)) + RBstart;
else RIV = (N_RB_DL * (N_RB_DL + 1 - Lcrbs)) + (N_RB_DL - 1 - RBstart);
return (RIV);
}
uint8_t getQm(uint8_t mcs)
{
if (mcs < 10) return (2);
else if (mcs < 17) return (4);
else return (6);
}
void
get_Msg3alloc(COMMON_channels_t *cc,
sub_frame_t current_subframe,
frame_t current_frame,
frame_t *frame,
sub_frame_t *subframe)
{
// Fill in other TDD Configuration!!!!
if (cc->tdd_Config == NULL) { // FDD
*subframe = current_subframe + 6;
if (*subframe > 9) {
*subframe = *subframe - 10;
*frame = (current_frame + 1) & 1023;
} else {
*frame = current_frame;
}
} else { // TDD
if (cc->tdd_Config->subframeAssignment == 1) {
switch (current_subframe) {
case 0:
*subframe = 7;
*frame = current_frame;
break;
case 4:
*subframe = 2;
*frame = (current_frame + 1) & 1023;
break;
case 5:
*subframe = 2;
*frame = (current_frame + 1) & 1023;
break;
case 9:
*subframe = 7;
*frame = (current_frame + 1) & 1023;
break;
}
} else if (cc->tdd_Config->subframeAssignment == 3) {
switch (current_subframe) {
case 0:
case 5:
case 6:
*subframe = 2;
*frame = (current_frame + 1) & 1023;
break;
case 7:
*subframe = 3;
*frame = (current_frame + 1) & 1023;
break;
case 8:
*subframe = 4;
*frame = (current_frame + 1) & 1023;
break;
case 9:
*subframe = 2;
*frame = (current_frame + 2) & 1023;
break;
}
} else if (cc->tdd_Config->subframeAssignment == 4) {
switch (current_subframe) {
case 0:
case 4:
case 5:
case 6:
*subframe = 2;
*frame = (current_frame + 1) & 1023;
break;
case 7:
*subframe = 3;
*frame = (current_frame + 1) & 1023;
break;
case 8:
case 9:
*subframe = 2;
*frame = (current_frame + 2) & 1023;
break;
}
} else if (cc->tdd_Config->subframeAssignment == 5) {
switch (current_subframe) {
case 0:
case 4:
case 5:
case 6:
*subframe = 2;
*frame = (current_frame + 1) & 1023;
break;
case 7:
case 8:
case 9:
*subframe = 2;
*frame = (current_frame + 2) & 1023;
break;
}
}
}
}
void
get_Msg3allocret(COMMON_channels_t * cc,
sub_frame_t current_subframe,
frame_t current_frame,
frame_t * frame, sub_frame_t * subframe)
{
if (cc->tdd_Config == NULL) { //FDD
/* always retransmit in n+8 */
*subframe = current_subframe + 8;
if (*subframe > 9) {
*subframe = *subframe - 10;
*frame = (current_frame + 1) & 1023;
} else {
*frame = current_frame;
}
} else {
if (cc->tdd_Config->subframeAssignment == 1) {
// original PUSCH in 2, PHICH in 6 (S), ret in 2
// original PUSCH in 3, PHICH in 9, ret in 3
// original PUSCH in 7, PHICH in 1 (S), ret in 7
// original PUSCH in 8, PHICH in 4, ret in 8
*frame = (current_frame + 1) & 1023;
} else if (cc->tdd_Config->subframeAssignment == 3) {
// original PUSCH in 2, PHICH in 8, ret in 2 next frame
// original PUSCH in 3, PHICH in 9, ret in 3 next frame
// original PUSCH in 4, PHICH in 0, ret in 4 next frame
*frame = (current_frame + 1) & 1023;
} else if (cc->tdd_Config->subframeAssignment == 4) {
// original PUSCH in 2, PHICH in 8, ret in 2 next frame
// original PUSCH in 3, PHICH in 9, ret in 3 next frame
*frame = (current_frame + 1) & 1023;
} else if (cc->tdd_Config->subframeAssignment == 5) {
// original PUSCH in 2, PHICH in 8, ret in 2 next frame
*frame = (current_frame + 1) & 1023;
}
}
}
uint8_t
subframe2harqpid(COMMON_channels_t * cc, frame_t frame,
sub_frame_t subframe)
{
uint8_t ret = 255;
AssertFatal(cc != NULL, "cc is null\n");
if (cc->tdd_Config == NULL) { // FDD
ret = (((frame << 1) + subframe) & 7);
} else {
switch (cc->tdd_Config->subframeAssignment) {
case 1:
if ((subframe == 2) ||
(subframe == 3) || (subframe == 7) || (subframe == 8))
switch (subframe) {
case 2:
case 3:
ret = (subframe - 2);
break;
case 7:
case 8:
ret = (subframe - 5);
break;
default:
AssertFatal(1 == 0,
"subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
subframe,
(int) cc->tdd_Config->subframeAssignment);
break;
}
break;
case 2:
AssertFatal((subframe == 2) || (subframe == 7),
"subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
subframe,
(int) cc->tdd_Config->subframeAssignment);
ret = (subframe / 7);
break;
case 3:
AssertFatal((subframe > 1) && (subframe < 5),
"subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
subframe,
(int) cc->tdd_Config->subframeAssignment);
ret = (subframe - 2);
break;
case 4:
AssertFatal((subframe > 1) && (subframe < 4),
"subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
subframe,
(int) cc->tdd_Config->subframeAssignment);
ret = (subframe - 2);
break;
case 5:
AssertFatal(subframe == 2,
"subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
subframe,
(int) cc->tdd_Config->subframeAssignment);
ret = (subframe - 2);
break;
default:
AssertFatal(1 == 0,
"subframe2_harq_pid, Unsupported TDD mode %d\n",
(int) cc->tdd_Config->subframeAssignment);
}
}
return ret;
}
uint8_t
get_Msg3harqpid(COMMON_channels_t * cc,
frame_t frame, sub_frame_t current_subframe)
{
uint8_t ul_subframe = 0;
uint32_t ul_frame = 0;
if (cc->tdd_Config == NULL) { // FDD
ul_subframe =
(current_subframe >
3) ? (current_subframe - 4) : (current_subframe + 6);
ul_frame = (current_subframe > 3) ? ((frame + 1) & 1023) : frame;
} else {
switch (cc->tdd_Config->subframeAssignment) {
case 1:
switch (current_subframe) {
case 9:
case 0:
ul_subframe = 7;
break;
case 5:
case 7:
ul_subframe = 2;
break;
}
break;
case 3:
switch (current_subframe) {
case 0:
case 5:
case 6:
ul_subframe = 2;
break;
case 7:
ul_subframe = 3;
break;
case 8:
ul_subframe = 4;
break;
case 9:
ul_subframe = 2;
break;
}
break;
case 4:
switch (current_subframe) {
case 0:
case 5:
case 6:
case 8:
case 9:
ul_subframe = 2;
break;
case 7:
ul_subframe = 3;
break;
}
break;
case 5:
ul_subframe = 2;
break;
default:
LOG_E(PHY,
"get_Msg3_harq_pid: Unsupported TDD configuration %d\n",
(int) cc->tdd_Config->subframeAssignment);
AssertFatal(1 == 0,
"get_Msg3_harq_pid: Unsupported TDD configuration");
break;
}
}
return (subframe2harqpid(cc, ul_frame, ul_subframe));
}
uint32_t
pdcchalloc2ulframe(COMMON_channels_t * ccP, uint32_t frame, uint8_t n)
{
uint32_t ul_frame;
if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 1) && ((n == 1) || (n == 6))) // tdd_config 0,1 SF 1,5
ul_frame = (frame + (n == 1 ? 0 : 1));
else if ((ccP->tdd_Config) &&
(ccP->tdd_Config->subframeAssignment == 6) &&
((n == 0) || (n == 1) || (n == 5) || (n == 6)))
ul_frame = (frame + (n >= 5 ? 1 : 0));
else if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 6) && (n == 9)) // tdd_config 6 SF 9
ul_frame = (frame + 1);
else
ul_frame = (frame + (n >= 6 ? 1 : 0));
LOG_D(PHY, "frame %d subframe %d: PUSCH frame = %d\n", frame, n,
ul_frame);
return ul_frame;
}
uint8_t pdcchalloc2ulsubframe(COMMON_channels_t * ccP, uint8_t n)
{
uint8_t ul_subframe;
if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 1) && ((n == 1) || (n == 6))) // tdd_config 0,1 SF 1,5
ul_subframe = ((n + 6) % 10);
else if ((ccP->tdd_Config) &&
(ccP->tdd_Config->subframeAssignment == 6) &&
((n == 0) || (n == 1) || (n == 5) || (n == 6)))
ul_subframe = ((n + 7) % 10);
else if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 6) && (n == 9)) // tdd_config 6 SF 9
ul_subframe = ((n + 5) % 10);
else
ul_subframe = ((n + 4) % 10);
LOG_D(PHY, "subframe %d: PUSCH subframe = %d\n", n, ul_subframe);
return ul_subframe;
}
int is_UL_sf(COMMON_channels_t * ccP, sub_frame_t subframeP)
{
// if FDD return dummy value
if (ccP->tdd_Config == NULL)
return (0);
switch (ccP->tdd_Config->subframeAssignment) {
case 1:
switch (subframeP) {
case 0:
case 4:
case 5:
case 9:
return (0);
break;
case 2:
case 3:
case 7:
case 8:
return (1);
break;
default:
return (0);
break;
}
break;
case 3:
if ((subframeP <= 1) || (subframeP >= 5))
return (0);
else if ((subframeP > 1) && (subframeP < 5))
return (1);
else
AssertFatal(1 == 0, "Unknown subframe number\n");
break;
case 4:
if ((subframeP <= 1) || (subframeP >= 4))
return (0);
else if ((subframeP > 1) && (subframeP < 4))
return (1);
else
AssertFatal(1 == 0, "Unknown subframe number\n");
break;
case 5:
if ((subframeP <= 1) || (subframeP >= 3))
return (0);
else if ((subframeP > 1) && (subframeP < 3))
return (1);
else
AssertFatal(1 == 0, "Unknown subframe number\n");
break;
default:
AssertFatal(1 == 0,
"subframe %d Unsupported TDD configuration %d\n",
subframeP, (int) ccP->tdd_Config->subframeAssignment);
break;
}
}
uint16_t get_pucch1_absSF(COMMON_channels_t * cc, uint16_t dlsch_absSF)
{
uint16_t sf, f, nextf;
if (cc->tdd_Config == NULL) { //FDD n+4
return ((dlsch_absSF + 4) % 10240);
} else {
sf = dlsch_absSF % 10;
f = dlsch_absSF / 10;
nextf = (f + 1) & 1023;
switch (cc->tdd_Config->subframeAssignment) {
case 0:
AssertFatal(1 == 0, "SFA 0 to be filled in now, :-)\n");
break;
case 1:
if ((sf == 5) || (sf == 6))
return ((10 * nextf) + 2); // ACK/NAK in SF 2 next frame
else if (sf == 9)
return ((10 * nextf) + 3); // ACK/NAK in SF 3 next frame
else if ((sf == 0) || (sf == 1))
return ((10 * f) + 2); // ACK/NAK in SF 7 same frame
else
AssertFatal(1 == 0,
"Impossible dlsch subframe %d for TDD configuration 3\n",
sf);
break;
case 2:
if ((sf == 4) || (sf == 5) || (sf == 6) || (sf == 8))
return ((10 * nextf) + 2); // ACK/NAK in SF 2 next frame
else if (sf == 9)
return ((10 * nextf) + 7); // ACK/NAK in SF 7 next frame
else if ((sf == 0) || (sf == 1) || (sf == 3))
return ((10 * f) + 7); // ACK/NAK in SF 7 same frame
else
AssertFatal(1 == 0,
"Impossible dlsch subframe %d for TDD configuration 3\n",
sf);
break;
case 3:
if ((sf == 5) || (sf == 6) || (sf == 7) || (sf == 8)
|| (sf == 9))
return ((10 * nextf) + (sf >> 1)); // ACK/NAK in 2,3,4 resp. next frame
else if (sf == 1)
return ((10 * nextf) + 2); // ACK/NAK in 2 next frame
else if (sf == 0)
return ((10 * f) + 4); // ACK/NAK in 4 same frame
else
AssertFatal(1 == 0,
"Impossible dlsch subframe %d for TDD configuration 3\n",
sf);
break;
case 4:
if ((sf == 6) || (sf == 7) || (sf == 8) || (sf == 9))
return (((10 * nextf) + 3) % 10240); // ACK/NAK in SF 3 next frame
else if ((sf == 0) || (sf == 1) || (sf == 4) || (sf == 5))
return (((10 * nextf) + 2) % 10240); // ACK/NAK in SF 2 next frame
else
AssertFatal(1 == 0,
"Impossible dlsch subframe %d for TDD configuration 4\n",
sf);
break;
case 5:
if ((sf == 0) || (sf == 1) || (sf == 3) || (sf == 4)
|| (sf == 5) || (sf == 6) || (sf == 7) || (sf == 8))
return (((10 * nextf) + 2) % 10240); // ACK/NAK in SF 3 next frame
else if (sf == 9)
return (((10 * (1 + nextf)) + 2) % 10240); // ACK/NAK in SF 2 next frame
else
AssertFatal(1 == 0,
"Impossible dlsch subframe %d for TDD configuration 5\n",
sf);
break;
case 6:
AssertFatal(1 == 0, "SFA 6 To be filled in now, :-)\n");
break;
default:
AssertFatal(1 == 0, "Illegal TDD subframe Assigment %d\n",
(int) cc->tdd_Config->subframeAssignment);
break;
}
}
AssertFatal(1 == 0, "Shouldn't get here\n");
}
void
get_srs_pos(COMMON_channels_t * cc, uint16_t isrs,
uint16_t * psrsPeriodicity, uint16_t * psrsOffset)
{
if (cc->tdd_Config) { // TDD
AssertFatal(isrs >= 10, "2 ms SRS periodicity not supported");
if ((isrs > 9) && (isrs < 15)) {
*psrsPeriodicity = 5;
*psrsOffset = isrs - 10;
}
if ((isrs > 14) && (isrs < 25)) {
*psrsPeriodicity = 10;
*psrsOffset = isrs - 15;
}
if ((isrs > 24) && (isrs < 45)) {
*psrsPeriodicity = 20;
*psrsOffset = isrs - 25;
}
if ((isrs > 44) && (isrs < 85)) {
*psrsPeriodicity = 40;
*psrsOffset = isrs - 45;
}
if ((isrs > 84) && (isrs < 165)) {
*psrsPeriodicity = 80;
*psrsOffset = isrs - 85;
}
if ((isrs > 164) && (isrs < 325)) {
*psrsPeriodicity = 160;
*psrsOffset = isrs - 165;
}
if ((isrs > 324) && (isrs < 645)) {
*psrsPeriodicity = 320;
*psrsOffset = isrs - 325;
}
AssertFatal(isrs <= 644, "Isrs out of range %d>644\n", isrs);
} // TDD
else { // FDD
if (isrs < 2) {
*psrsPeriodicity = 2;
*psrsOffset = isrs;
}
if ((isrs > 1) && (isrs < 7)) {
*psrsPeriodicity = 5;
*psrsOffset = isrs - 2;
}
if ((isrs > 6) && (isrs < 17)) {
*psrsPeriodicity = 10;
*psrsOffset = isrs - 7;
}
if ((isrs > 16) && (isrs < 37)) {
*psrsPeriodicity = 20;
*psrsOffset = isrs - 17;
}
if ((isrs > 36) && (isrs < 77)) {
*psrsPeriodicity = 40;
*psrsOffset = isrs - 37;
}
if ((isrs > 76) && (isrs < 157)) {
*psrsPeriodicity = 80;
*psrsOffset = isrs - 77;
}
if ((isrs > 156) && (isrs < 317)) {
*psrsPeriodicity = 160;
*psrsOffset = isrs - 157;
}
if ((isrs > 316) && (isrs < 637)) {
*psrsPeriodicity = 320;
*psrsOffset = isrs - 317;
}
AssertFatal(isrs <= 636, "Isrs out of range %d>636\n", isrs);
}
}
void
get_csi_params(COMMON_channels_t * cc,
struct CQI_ReportPeriodic *cqi_ReportPeriodic,
uint16_t * Npd, uint16_t * N_OFFSET_CQI, int *H)
{
uint16_t cqi_PMI_ConfigIndex =
cqi_ReportPeriodic->choice.setup.cqi_pmi_ConfigIndex;
uint8_t Jtab[6] = { 0, 2, 2, 3, 4, 4 };
AssertFatal(cqi_ReportPeriodic != NULL,
"cqi_ReportPeriodic is null!\n");
if (cc->tdd_Config == NULL) { //FDD
if (cqi_PMI_ConfigIndex <= 1) { // 2 ms CQI_PMI period
*Npd = 2;
*N_OFFSET_CQI = cqi_PMI_ConfigIndex;
} else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period
*Npd = 5;
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 2;
} else if (cqi_PMI_ConfigIndex <= 16) { // 10ms CQI_PMI period
*Npd = 10;
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 7;
} else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period
*Npd = 20;
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 17;
} else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period
*Npd = 40;
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 37;
} else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period
*Npd = 80;
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 77;
} else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period
*Npd = 160;
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 157;
} else if (cqi_PMI_ConfigIndex > 317) {
if (cqi_PMI_ConfigIndex <= 349) { // 32 ms CQI_PMI period
*Npd = 32;
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 318;
} else if (cqi_PMI_ConfigIndex <= 413) { // 64 ms CQI_PMI period
*Npd = 64;
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 350;
} else if (cqi_PMI_ConfigIndex <= 541) { // 128 ms CQI_PMI period
*Npd = 128;
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 414;
}
}
} else { // TDD
if (cqi_PMI_ConfigIndex == 0) { // all UL subframes
*Npd = 1;
*N_OFFSET_CQI = 0;
} else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period
*Npd = 5;
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 1;
} else if (cqi_PMI_ConfigIndex <= 16) { // 10ms CQI_PMI period
*Npd = 10;
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 6;
} else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period
*Npd = 20;
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 16;
} else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period
*Npd = 40;
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 36;
} else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period
*Npd = 80;
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 76;
} else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period
*Npd = 160;
*N_OFFSET_CQI = cqi_PMI_ConfigIndex - 156;
}
}
// get H
if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.
present ==
CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI)
*H = 1 +
(Jtab[cc->mib->message.dl_Bandwidth] *
cqi_ReportPeriodic->choice.setup.
cqi_FormatIndicatorPeriodic.choice.subbandCQI.k);
else
*H = 1;
}
uint8_t
get_dl_cqi_pmi_size_pusch(COMMON_channels_t * cc, uint8_t tmode,
uint8_t ri,
CQI_ReportModeAperiodic_t *
cqi_ReportModeAperiodic)
{
int Ntab[6] = { 0, 4, 7, 9, 10, 13 };
int N = Ntab[cc->mib->message.dl_Bandwidth];
int Ltab_uesel[6] = { 0, 6, 9, 13, 15, 18 };
int L = Ltab_uesel[cc->mib->message.dl_Bandwidth];
AssertFatal(cqi_ReportModeAperiodic != NULL,
"cqi_ReportPeriodic is null!\n");
switch (*cqi_ReportModeAperiodic) {
case CQI_ReportModeAperiodic_rm12:
AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9
|| tmode == 10,
"Illegal TM (%d) for CQI_ReportModeAperiodic_rm12\n",
tmode);
AssertFatal(cc->p_eNB <= 4,
"only up to 4 antenna ports supported here\n");
if (ri == 1 && cc->p_eNB == 2)
return (4 + (N << 1));
else if (ri == 2 && cc->p_eNB == 2)
return (8 + N);
else if (ri == 1 && cc->p_eNB == 4)
return (4 + (N << 2));
else if (ri > 1 && cc->p_eNB == 4)
return (8 + (N << 2));
break;
case CQI_ReportModeAperiodic_rm20:
// Table 5.2.2.6.3-1 (36.212)
AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 || tmode == 7
|| tmode == 9
|| tmode == 10,
"Illegal TM (%d) for CQI_ReportModeAperiodic_rm20\n",
tmode);
AssertFatal(tmode != 9
&& tmode != 10,
"TM9/10 will be handled later for CQI_ReportModeAperiodic_rm20\n");
return (4 + 2 + L);
break;
case CQI_ReportModeAperiodic_rm22:
// Table 5.2.2.6.3-2 (36.212)
AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9
|| tmode == 10,
"Illegal TM (%d) for CQI_ReportModeAperiodic_rm22\n",
tmode);
AssertFatal(tmode != 9
&& tmode != 10,
"TM9/10 will be handled later for CQI_ReportModeAperiodic_rm22\n");
if (ri == 1 && cc->p_eNB == 2)
return (4 + 2 + 0 + 0 + L + 4);
if (ri == 2 && cc->p_eNB == 2)
return (4 + 2 + 4 + 2 + L + 2);
if (ri == 1 && cc->p_eNB == 4)
return (4 + 2 + 0 + 0 + L + 8);
if (ri >= 2 && cc->p_eNB == 4)
return (4 + 2 + 4 + 2 + L + 8);
break;
case CQI_ReportModeAperiodic_rm30:
// Table 5.2.2.6.2-1 (36.212)
AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 || tmode == 7
|| tmode == 8 || tmode == 9
|| tmode == 10,
"Illegal TM (%d) for CQI_ReportModeAperiodic_rm30\n",
tmode);
AssertFatal(tmode != 8 && tmode != 9
&& tmode != 10,
"TM8/9/10 will be handled later for CQI_ReportModeAperiodic_rm30\n");
return (4 + (N << 1));
break;
case CQI_ReportModeAperiodic_rm31:
// Table 5.2.2.6.2-2 (36.212)
AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9
|| tmode == 10,
"Illegal TM (%d) for CQI_ReportModeAperiodic_rm31\n",
tmode);
AssertFatal(tmode != 8 && tmode != 9
&& tmode != 10,
"TM8/9/10 will be handled later for CQI_ReportModeAperiodic_rm31\n");
if (ri == 1 && cc->p_eNB == 2)
return (4 + (N << 1) + 0 + 0 + 2);
else if (ri == 2 && cc->p_eNB == 2)
return (4 + (N << 1) + 4 + (N << 1) + 1);
else if (ri == 1 && cc->p_eNB == 4)
return (4 + (N << 1) + 0 + 0 + 4);
else if (ri >= 2 && cc->p_eNB == 4)
return (4 + (N << 1) + 4 + (N << 1) + 4);
break;
#if (RRC_VERSION >= MAKE_VERSION(12, 5, 0))
case CQI_ReportModeAperiodic_rm32_v1250:
AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9
|| tmode == 10,
"Illegal TM (%d) for CQI_ReportModeAperiodic_rm32\n",
tmode);
AssertFatal(1 == 0,
"CQI_ReportModeAperiodic_rm32_v1250 not supported yet\n");
break;
case CQI_ReportModeAperiodic_rm10_v1310:
// Table 5.2.2.6.1-1F/G (36.212)
if (ri == 1)
return (4); // F
else
return (7); // G
break;
case CQI_ReportModeAperiodic_rm11_v1310:
// Table 5.2.2.6.1-1H (36.212)
AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9
|| tmode == 10,
"Illegal TM (%d) for CQI_ReportModeAperiodic_rm11\n",
tmode);
AssertFatal(cc->p_eNB <= 4,
"only up to 4 antenna ports supported here\n");
if (ri == 1 && cc->p_eNB == 2)
return (4 + 0 + 2);
else if (ri == 2 && cc->p_eNB == 2)
return (4 + 4 + 1);
else if (ri == 1 && cc->p_eNB == 4)
return (4 + 0 + 4);
else if (ri > 1 && cc->p_eNB == 4)
return (4 + 4 + 4);
break;
#endif /* #if (RRC_VERSION >= MAKE_VERSION(12, 5, 0)) */
}
AssertFatal(1 == 0, "Shouldn't get here\n");
return (0);
}
uint8_t
get_rel8_dl_cqi_pmi_size(UE_sched_ctrl * sched_ctl, int CC_idP,
COMMON_channels_t * cc, uint8_t tmode,
struct CQI_ReportPeriodic * cqi_ReportPeriodic)
{
int no_pmi = 0;
// Ltab[6] = {0,log2(15/4/2),log2(25/4/2),log2(50/6/3),log2(75/8/4),log2(100/8/4)};
uint8_t Ltab[6] = { 0, 1, 2, 2, 2, 2 };
uint8_t ri = sched_ctl->periodic_ri_received[CC_idP];
AssertFatal(cqi_ReportPeriodic != NULL,
"cqi_ReportPeriodic is null!\n");
AssertFatal(cqi_ReportPeriodic->present != CQI_ReportPeriodic_PR_NOTHING,
"cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_NOTHING!\n");
AssertFatal(cqi_ReportPeriodic->choice.
setup.cqi_FormatIndicatorPeriodic.present != CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING,
"cqi_ReportPeriodic->cqi_FormatIndicatorPeriodic.choice.setup.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING!\n");
switch (tmode) {
case 1:
case 2:
case 5:
case 6:
case 7:
no_pmi = 1;
break;
default:
no_pmi = 0;
}
if ((cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_widebandCQI)
|| (sched_ctl->feedback_cnt[CC_idP] == 0)) {
// send wideband report every opportunity if wideband reporting mode is selected, else every H opportunities
if (no_pmi == 1) return (4);
else if ((cc->p_eNB == 2) && (ri == 1)) return (6);
else if ((cc->p_eNB == 2) && (ri == 2)) return (8);
else if ((cc->p_eNB == 4) && (ri == 1)) return (8);
else if ((cc->p_eNB == 4) && (ri == 2)) return (11);
else
AssertFatal(1 == 0,
"illegal combination p %d, ri %d, no_pmi %d\n",
cc->p_eNB, ri, no_pmi);
} else if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) {
if ((no_pmi == 1) || ri == 1) return (4 + Ltab[cc->mib->message.dl_Bandwidth]);
else return (7 + Ltab[cc->mib->message.dl_Bandwidth]);
}
AssertFatal(1 == 0,
"Shouldn't get here : cqi_ReportPeriodic->present %d\n",
cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present);
}
void
fill_nfapi_dl_dci_1A(nfapi_dl_config_request_pdu_t *dl_config_pdu,
uint8_t aggregation_level,
uint16_t rnti,
uint8_t rnti_type,
uint8_t harq_process,
uint8_t tpc,
uint16_t resource_block_coding,
uint8_t mcs,
uint8_t ndi,
uint8_t rv,
uint8_t vrb_flag)
{
memset((void *) dl_config_pdu, 0,
sizeof(nfapi_dl_config_request_pdu_t));
dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE;
dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu));
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.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;
}
void
program_dlsch_acknak(module_id_t module_idP, int CC_idP, int UE_idP,
frame_t frameP, sub_frame_t subframeP,
uint8_t cce_idx)
{
eNB_MAC_INST *eNB = RC.mac[module_idP];
COMMON_channels_t *cc = eNB->common_channels;
UE_list_t *UE_list = &eNB->UE_list;
rnti_t rnti = UE_RNTI(module_idP, UE_idP);
nfapi_ul_config_request_body_t *ul_req;
nfapi_ul_config_request_pdu_t *ul_config_pdu;
int use_simultaneous_pucch_pusch = 0;
nfapi_ul_config_ulsch_harq_information *ulsch_harq_information = NULL;
nfapi_ul_config_harq_information *harq_information = NULL;
#if (RRC_VERSION >= MAKE_VERSION(10, 2, 0))
if ((UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2)
&& (UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020)
&& (UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020->simultaneousPUCCH_PUSCH_r10)
&& (*UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020->simultaneousPUCCH_PUSCH_r10 == PUCCH_ConfigDedicated_v1020__simultaneousPUCCH_PUSCH_r10_true))
use_simultaneous_pucch_pusch = 1;
#endif
// pucch1 and pusch feedback is similar, namely in n+k subframes from now
// This is used in the following "if/else" condition to check if there isn't or is already an UL grant in n+k
int16_t ul_absSF = get_pucch1_absSF(&cc[CC_idP], subframeP + (10 * frameP));
if ((ul_config_pdu = has_ul_grant(module_idP, CC_idP,ul_absSF, rnti)) == NULL) {
// no UL grant so
// Program ACK/NAK alone Format 1a/b or 3
ul_req = &RC.mac[module_idP]->UL_req_tmp[CC_idP][ul_absSF %10].ul_config_request_body;
ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus];
// Do PUCCH
fill_nfapi_uci_acknak(module_idP,
CC_idP,
rnti, (frameP * 10) + subframeP, cce_idx);
} else {
/* there is already an existing UL grant so update it if needed
* on top of some other UL resource (PUSCH,combined SR/CQI/HARQ on PUCCH, etc)
*/
switch (ul_config_pdu->pdu_type) {
/* [ulsch] to [ulsch + harq] or [ulsch + harq on pucch] */
case NFAPI_UL_CONFIG_ULSCH_PDU_TYPE:
if (use_simultaneous_pucch_pusch == 1) {
// Convert it to an NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE
harq_information = &ul_config_pdu->ulsch_uci_harq_pdu.harq_information;
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE;
LOG_D(MAC,
"Frame %d, Subframe %d: Switched UCI HARQ to ULSCH UCI HARQ\n",
frameP, subframeP);
} else {
// Convert it to an NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE
ulsch_harq_information = &ul_config_pdu->ulsch_harq_pdu.harq_information;
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE;
ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.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 == 1,
"Cannot be NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE, simultaneous_pucch_pusch is active");
break;
case NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE:
AssertFatal(use_simultaneous_pucch_pusch == 0,
"Cannot be NFAPI_UL_CONFIG_ULSCH_UCI_PDU_TYPE, simultaneous_pucch_pusch is inactive\n");
break;
/* [ulsch + cqi] to [ulsch + cqi + harq] */
case NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE:
// Convert it to an NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE
ulsch_harq_information = &ul_config_pdu->ulsch_cqi_harq_ri_pdu.harq_information;
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE;
/* TODO: check this - when converting from nfapi_ul_config_ulsch_cqi_ri_pdu to
* nfapi_ul_config_ulsch_cqi_harq_ri_pdu, shouldn't we copy initial_transmission_parameters
* from the one to the other?
* Those two types are not compatible. 'initial_transmission_parameters' is not at the
* place in both.
*/
ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.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);
if (harq_information) fill_nfapi_harq_information(module_idP, CC_idP,
rnti,
(frameP * 10) + subframeP,
harq_information, cce_idx);
}
uint8_t get_V_UL_DAI(module_id_t module_idP, int CC_idP, uint16_t rntiP)
{
nfapi_hi_dci0_request_body_t *HI_DCI0_req = &RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body;
nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_pdu_list[0];
for (int i = 0; i < HI_DCI0_req->number_of_dci; i++) {
if ((hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) &&
(hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti == rntiP))
return (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.dl_assignment_index);
}
return (4); // this is rule from Section 7.3 in 36.213
}
void
fill_nfapi_ulsch_harq_information(module_id_t module_idP,
int CC_idP,
uint16_t rntiP,
nfapi_ul_config_ulsch_harq_information *harq_information)
{
eNB_MAC_INST *eNB = RC.mac[module_idP];
COMMON_channels_t *cc = &eNB->common_channels[CC_idP];
UE_list_t *UE_list = &eNB->UE_list;
int UE_id = find_UE_id(module_idP, rntiP);
PUSCH_ConfigDedicated_t *puschConfigDedicated;
// PUSCH_ConfigDedicated_v1020_t *puschConfigDedicated_v1020;
// PUSCH_ConfigDedicated_v1130_t *puschConfigDedicated_v1130;
// PUSCH_ConfigDedicated_v1250_t *puschConfigDedicated_v1250;
AssertFatal(UE_id >= 0, "UE_id cannot be found, impossible\n");
AssertFatal(UE_list != NULL, "UE_list is null\n");
AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated != NULL,
"physicalConfigDedicated for rnti %x is null\n", rntiP);
AssertFatal((puschConfigDedicated = (PUSCH_ConfigDedicated_t *)
UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pusch_ConfigDedicated) != NULL,
"physicalConfigDedicated->puschConfigDedicated for rnti %x is null\n",
rntiP);
#if (RRC_VERSION >= MAKE_VERSION(10, 2, 0))
/* if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext2) puschConfigDedicated_v1020 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext2->pusch_ConfigDedicated_v1020;
#endif
#if (RRC_VERSION >= MAKE_VERSION(11, 3, 0))
if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext4) puschConfigDedicated_v1130 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext4->pusch_ConfigDedicated_v1130;
#endif
#if (RRC_VERSION >= MAKE_VERSION(12, 5, 0))
if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext5) puschConfigDedicated_v1250 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext5->pusch_ConfigDedicated_v1250;
#endif
*/
#endif
harq_information->harq_information_rel10.delta_offset_harq = puschConfigDedicated->betaOffset_ACK_Index;
AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated != NULL,
"pucch_ConfigDedicated is null!\n");
if ((UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode != NULL)
&& (*UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode == PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing))
harq_information->harq_information_rel10.ack_nack_mode = 1; // multiplexing
else
harq_information->harq_information_rel10.ack_nack_mode = 0; // bundling
switch (get_tmode(module_idP, CC_idP, UE_id)) {
case 1:
case 2:
case 5:
case 6:
case 7:
if (cc->tdd_Config == NULL) // FDD
harq_information->harq_information_rel10.harq_size = 1;
else {
if (harq_information->harq_information_rel10.ack_nack_mode == 1)
harq_information->harq_information_rel10.harq_size = get_V_UL_DAI(module_idP, CC_idP, rntiP);
else
harq_information->harq_information_rel10.harq_size = 1;
}
break;
default: // for any other TM we need 2 bits harq
if (cc->tdd_Config == NULL) {
harq_information->harq_information_rel10.harq_size = 2;
} else {
if (harq_information->harq_information_rel10.ack_nack_mode == 1)
harq_information->harq_information_rel10.harq_size = get_V_UL_DAI(module_idP, CC_idP, rntiP);
else
harq_information->harq_information_rel10.harq_size = 2;
}
break;
} // get Tmode
}
void
fill_nfapi_harq_information(module_id_t module_idP,
int CC_idP,
uint16_t rntiP,
uint16_t absSFP,
nfapi_ul_config_harq_information *harq_information,
uint8_t cce_idxP)
{
eNB_MAC_INST *eNB = RC.mac[module_idP];
COMMON_channels_t *cc = &eNB->common_channels[CC_idP];
UE_list_t *UE_list = &eNB->UE_list;
int UE_id = find_UE_id(module_idP, rntiP);
AssertFatal(UE_id >= 0, "UE_id cannot be found, impossible\n");
AssertFatal(UE_list != NULL, "UE_list is null\n");
#if 0
/* TODO: revisit, don't use Assert, it's perfectly possible to
* have physicalConfigDedicated NULL here
*/
AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated != NULL,
"physicalConfigDedicated for rnti %x is null\n", rntiP);
#endif
harq_information->harq_information_rel11.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL11_TAG;
harq_information->harq_information_rel11.num_ant_ports = 1;
switch (get_tmode(module_idP, CC_idP, UE_id)) {
case 1:
case 2:
case 5:
case 6:
case 7:
if (cc->tdd_Config != NULL) {
AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated != NULL,
"pucch_ConfigDedicated is null for TDD!\n");
if ((UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode != NULL)
&& (*UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode == PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing))
{
harq_information->harq_information_rel10_tdd.harq_size = 2; // 2-bit ACK/NAK
harq_information->harq_information_rel10_tdd.ack_nack_mode = 1; // multiplexing
} else {
harq_information->harq_information_rel10_tdd.harq_size = 1; // 1-bit ACK/NAK
harq_information->harq_information_rel10_tdd.ack_nack_mode = 0; // bundling
}
harq_information->harq_information_rel10_tdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL10_TDD_TAG;
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.harq_size = 1; // 1-bit ACK/NAK
harq_information->harq_information_rel9_fdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + cce_idxP;
}
break;
default: // for any other TM we need 2 bits harq
if (cc->tdd_Config != NULL) {
AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated != NULL,
"pucch_ConfigDedicated is null for TDD!\n");
if ((UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode != NULL)
&& (*UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode == PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing)) {
harq_information->harq_information_rel10_tdd.ack_nack_mode = 1; // multiplexing
} else {
harq_information->harq_information_rel10_tdd.ack_nack_mode = 0; // bundling
}
harq_information->harq_information_rel10_tdd.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
}
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,
absSFP,
&ul_config_pdu->uci_harq_pdu.harq_information, cce_idxP);
LOG_D(MAC,
"Filled in UCI HARQ request for rnti %x SF %d.%d acknakSF %d.%d, cce_idxP %d-> n1_pucch %d\n",
rntiP, absSFP / 10, absSFP % 10, ackNAK_absSF / 10,
ackNAK_absSF % 10, cce_idxP,
ul_config_pdu->uci_harq_pdu.
harq_information.harq_information_rel9_fdd.n_pucch_1_0);
ul_req_body->number_of_pdus++;
ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG;
ul_req->header.message_id = NFAPI_UL_CONFIG_REQUEST;
ul_req->sfn_sf = (ackNAK_absSF/10) << 4 | ackNAK_absSF%10;
return (((ackNAK_absSF / 10) << 4) + (ackNAK_absSF % 10));
}
void
fill_nfapi_dlsch_config(eNB_MAC_INST * eNB,
nfapi_dl_config_request_body_t * dl_req,
uint16_t length,
uint16_t pdu_index,
uint16_t rnti,
uint8_t resource_allocation_type,
uint8_t
virtual_resource_block_assignment_flag,
uint16_t resource_block_coding,
uint8_t modulation,
uint8_t redundancy_version,
uint8_t transport_blocks,
uint8_t transport_block_to_codeword_swap_flag,
uint8_t transmission_scheme,
uint8_t number_of_layers,
uint8_t number_of_subbands,
// uint8_t codebook_index,
uint8_t ue_category_capacity,
uint8_t pa,
uint8_t delta_power_offset_index,
uint8_t ngap,
uint8_t nprb,
uint8_t transmission_mode,
uint8_t num_bf_prb_per_subband,
uint8_t num_bf_vector)
{
nfapi_dl_config_request_pdu_t *dl_config_pdu =
&dl_req->dl_config_pdu_list[dl_req->number_pdu];
memset((void *) dl_config_pdu, 0,
sizeof(nfapi_dl_config_request_pdu_t));
dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE;
dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu));
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = length;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = pdu_index;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = rnti;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = resource_allocation_type;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = virtual_resource_block_assignment_flag;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = resource_block_coding;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = modulation;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = redundancy_version;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = transport_blocks;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = transport_block_to_codeword_swap_flag;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = transmission_scheme;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = number_of_layers;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = number_of_subbands;
// dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = codebook_index;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = ue_category_capacity;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = pa;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = delta_power_offset_index;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = ngap;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = nprb;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = transmission_mode;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = num_bf_prb_per_subband;
dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = num_bf_vector;
dl_req->number_pdu++;
}
uint16_t
fill_nfapi_tx_req(nfapi_tx_request_body_t *tx_req_body,
uint16_t absSF,
uint16_t pdu_length,
uint16_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 PhysicalConfigDedicated *physicalConfigDedicated,
uint8_t tmode,
uint32_t handle,
uint16_t rnti,
uint8_t resource_block_start,
uint8_t number_of_resource_blocks,
uint8_t mcs,
uint8_t cyclic_shift_2_for_drms,
uint8_t frequency_hopping_enabled_flag,
uint8_t frequency_hopping_bits,
uint8_t new_data_indication,
uint8_t redundancy_version,
uint8_t harq_process_number,
uint8_t ul_tx_mode,
uint8_t current_tx_nb,
uint8_t n_srs,
uint16_t size)
{
memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t));
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE;
ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_pdu));
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.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 ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 6;
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.cyclic_shift_2_for_drms = cyclic_shift_2_for_drms;
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_enabled_flag = frequency_hopping_enabled_flag;
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_bits = frequency_hopping_bits;
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.new_data_indication = new_data_indication;
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.redundancy_version = redundancy_version;
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.harq_process_number = harq_process_number;
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.ul_tx_mode = ul_tx_mode;
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.current_tx_nb = current_tx_nb;
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.n_srs = n_srs;
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = size;
if (cqi_req == 1) {
// Add CQI portion
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE;
ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_cqi_ri_pdu));
ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.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))
ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 1;
else if (cc->p_eNB <= 2) ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 0;
else if (cc->p_eNB == 4) ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 2;
AssertFatal(physicalConfigDedicated->cqi_ReportConfig != NULL,"physicalConfigDedicated->cqi_ReportConfig is null!\n");
AssertFatal(physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic != NULL,"physicalConfigDedicated->cqi_ReportModeAperiodic is null!\n");
AssertFatal(physicalConfigDedicated->pusch_ConfigDedicated != NULL,"physicalConfigDedicated->puschConfigDedicated is null!\n");
for (int ri = 0;
ri < (1 << ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size);
ri++)
ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].dl_cqi_pmi_size[ri] = get_dl_cqi_pmi_size_pusch(cc,tmode,1 + ri,physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic);
ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.delta_offset_cqi = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_CQI_Index;
ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.delta_offset_ri = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_RI_Index;
}
}
#if (RRC_VERSION >= MAKE_VERSION(13, 0, 0))
void
fill_nfapi_ulsch_config_request_emtc(nfapi_ul_config_request_pdu_t *
ul_config_pdu, uint8_t ue_type,
uint16_t
total_number_of_repetitions,
uint16_t repetition_number,
uint16_t initial_transmission_sf_io)
{
// Re13 fields
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL13_TAG;
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.ue_type = ue_type;
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.total_number_of_repetitions = total_number_of_repetitions;
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.repetition_number = repetition_number;
ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.initial_transmission_sf_io = initial_transmission_sf_io;
}
int get_numnarrowbands(long dl_Bandwidth)
{
int nb_tab[6] = { 1, 2, 4, 8, 12, 16 };
AssertFatal(dl_Bandwidth < 7 || dl_Bandwidth >= 0, "dl_Bandwidth not in [0..6]\n");
return (nb_tab[dl_Bandwidth]);
}
int get_numnarrowbandbits(long dl_Bandwidth)
{
int nbbits_tab[6] = { 0, 1, 2, 3, 4, 4 };
AssertFatal(dl_Bandwidth < 7 || dl_Bandwidth >= 0, "dl_Bandwidth not in [0..6]\n");
return (nbbits_tab[dl_Bandwidth]);
}
//This implements the frame/subframe condition for first subframe of MPDCCH transmission (Section 9.1.5 36.213, Rel 13/14)
int startSF_fdd_RA_times2[8] = { 2, 3, 4, 5, 8, 10, 16, 20 };
int startSF_tdd_RA[7] = { 1, 2, 4, 5, 8, 10, 20 };
int
mpdcch_sf_condition(eNB_MAC_INST * eNB, int CC_id, frame_t frameP,
sub_frame_t subframeP, int rmax,
MPDCCH_TYPES_t mpdcch_type, int UE_id)
{
struct PRACH_ConfigSIB_v1310 *ext4_prach =
eNB->common_channels[CC_id].radioResourceConfigCommon_BR->
ext4->prach_ConfigCommon_v1310;
int T;
EPDCCH_SetConfig_r11_t *epdcch_setconfig_r11;
switch (mpdcch_type) {
case TYPE0:
AssertFatal(1 == 0, "MPDCCH Type 0 not handled yet\n");
break;
case TYPE1:
AssertFatal(1 == 0, "MPDCCH Type 1 not handled yet\n");
break;
case TYPE1A:
AssertFatal(1 == 0, "MPDCCH Type 1A not handled yet\n");
break;
case TYPE2: // RAR
AssertFatal(ext4_prach->mpdcch_startSF_CSS_RA_r13 != NULL,
"mpdcch_startSF_CSS_RA_r13 is null\n");
AssertFatal(rmax > 0, "rmax is 0!\b");
if (eNB->common_channels[CC_id].tdd_Config == NULL) //FDD
T = rmax *startSF_fdd_RA_times2[ext4_prach->
mpdcch_startSF_CSS_RA_r13->
choice.fdd_r13] >> 1;
else //TDD
T = rmax *startSF_tdd_RA[ext4_prach->
mpdcch_startSF_CSS_RA_r13->choice.tdd_r13];
break;
case TYPE2A:
AssertFatal(1 == 0, "MPDCCH Type 2A not handled yet\n");
break;
case TYPEUESPEC:
epdcch_setconfig_r11 =
eNB->UE_list.UE_template[CC_id][UE_id].physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11.choice.setup.setConfigToAddModList_r11->list.array[0];
AssertFatal(epdcch_setconfig_r11 != NULL,
" epdcch_setconfig_r11 is null for UE specific \n");
AssertFatal(epdcch_setconfig_r11->ext2 != NULL,
" ext2 doesn't exist in epdcch config ' \n");
if (eNB->common_channels[CC_id].tdd_Config == NULL) //FDD
T = rmax *startSF_fdd_RA_times2[epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_StartSF_UESS_r13.choice.fdd_r13] >> 1;
else //TDD
T = rmax *startSF_tdd_RA[epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_StartSF_UESS_r13.choice.tdd_r13];
break;
default:
return (0);
}
AssertFatal(T > 0, "T is 0!\n");
if (((10 * frameP) + subframeP) % T == 0) return (1);
else return (0);
}
int narrowband_to_first_rb(COMMON_channels_t * cc, int nb_index)
{
switch (cc->mib->message.dl_Bandwidth) {
case 0: // 6 PRBs, N_NB=1, i_0=0
return (0);
break;
case 3: // 50 PRBs, N_NB=8, i_0=1
return ((int) (1 + (6 * nb_index)));
break;
case 5: // 100 PRBs, N_NB=16, i_0=2
return ((int) (2 + (6 * nb_index)));
break;
case 1: // 15 PRBs N_NB=2, i_0=1
if (nb_index > 0)
return (1);
else
return (0);
break;
case 2: // 25 PRBs, N_NB=4, i_0=0
if (nb_index > 1)
return (1 + (6 * nb_index));
else
return ((6 * nb_index));
break;
case 4: // 75 PRBs, N_NB=12, i_0=1
if (nb_index > 5)
return (2 + (6 * nb_index));
else
return (1 + (6 * nb_index));
break;
default:
AssertFatal(1 == 0, "Impossible dl_Bandwidth %d\n",
(int) cc->mib->message.dl_Bandwidth);
break;
}
}
#endif
//------------------------------------------------------------------------------
void init_ue_sched_info(void)
//------------------------------------------------------------------------------
{
module_id_t i, j, k;
for (i = 0; i < NUMBER_OF_eNB_MAX; i++) {
for (k = 0; k < MAX_NUM_CCs; k++) {
for (j = 0; j < NUMBER_OF_UE_MAX; j++) {
// init DL
eNB_dlsch_info[i][k][j].weight = 0;
eNB_dlsch_info[i][k][j].subframe = 0;
eNB_dlsch_info[i][k][j].serving_num = 0;
eNB_dlsch_info[i][k][j].status = S_DL_NONE;
// init UL
eNB_ulsch_info[i][k][j].subframe = 0;
eNB_ulsch_info[i][k][j].serving_num = 0;
eNB_ulsch_info[i][k][j].status = S_UL_NONE;
}
}
}
}
//------------------------------------------------------------------------------
unsigned char get_ue_weight(module_id_t module_idP, int CC_idP, int ue_idP)
//------------------------------------------------------------------------------
{
return (eNB_dlsch_info[module_idP][CC_idP][ue_idP].weight);
}
//------------------------------------------------------------------------------
int find_UE_id(module_id_t mod_idP, rnti_t rntiP)
//------------------------------------------------------------------------------
{
int UE_id;
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) {
if (UE_list->active[UE_id] != TRUE)
continue;
if (UE_list->UE_template[UE_PCCID(mod_idP, UE_id)][UE_id].rnti ==
rntiP) {
return (UE_id);
}
}
return (-1);
}
//------------------------------------------------------------------------------
int find_RA_id(module_id_t mod_idP, int CC_idP, rnti_t rntiP)
//------------------------------------------------------------------------------
{
int RA_id;
AssertFatal(RC.mac[mod_idP], "RC.mac[%d] is null\n", mod_idP);
RA_t *ra = (RA_t *) & RC.mac[mod_idP]->common_channels[CC_idP].ra[0];
for (RA_id = 0; RA_id < NB_RA_PROC_MAX; RA_id++) {
LOG_D(MAC,
"Checking RA_id %d for %x : state %d\n",
RA_id, rntiP, ra[RA_id].state);
if (ra[RA_id].state != IDLE &&
ra[RA_id].rnti == rntiP)
return (RA_id);
}
return (-1);
}
//------------------------------------------------------------------------------
int UE_num_active_CC(UE_list_t * listP, int ue_idP)
//------------------------------------------------------------------------------
{
return (listP->numactiveCCs[ue_idP]);
}
//------------------------------------------------------------------------------
int UE_PCCID(module_id_t mod_idP, int ue_idP)
//------------------------------------------------------------------------------
{
if (!RC.mac || !RC.mac[mod_idP]) return 0;
return (RC.mac[mod_idP]->UE_list.pCC_id[ue_idP]);
}
//------------------------------------------------------------------------------
rnti_t UE_RNTI(module_id_t mod_idP, int ue_idP)
//------------------------------------------------------------------------------
{
if (!RC.mac || !RC.mac[mod_idP]) return 0;
rnti_t rnti =
RC.mac[mod_idP]->
UE_list.UE_template[UE_PCCID(mod_idP, ue_idP)][ue_idP].rnti;
if (rnti > 0) {
return (rnti);
}
LOG_D(MAC, "[eNB %d] Couldn't find RNTI for UE %d\n", mod_idP, ue_idP);
//display_backtrace();
return (NOT_A_RNTI);
}
//------------------------------------------------------------------------------
boolean_t is_UE_active(module_id_t mod_idP, int ue_idP)
//------------------------------------------------------------------------------
{
if (!RC.mac || !RC.mac[mod_idP]) return 0;
return (RC.mac[mod_idP]->UE_list.active[ue_idP]);
}
unsigned char
get_aggregation(uint8_t bw_index, uint8_t cqi, uint8_t dci_fmt)
{
unsigned char aggregation = 3;
switch (dci_fmt) {
case format0:
aggregation = cqi2fmt0_agg[bw_index][cqi];
break;
case format1:
case format1A:
case format1B:
case format1D:
aggregation = cqi2fmt1x_agg[bw_index][cqi];
break;
case format2:
case format2A:
case format2B:
case format2C:
case format2D:
aggregation = cqi2fmt2x_agg[bw_index][cqi];
break;
case format1C:
case format1E_2A_M10PRB:
case format3:
case format3A:
case format4:
default:
LOG_W(MAC, "unsupported DCI format %d\n", dci_fmt);
}
LOG_D(MAC, "Aggregation level %d (cqi %d, bw_index %d, format %d)\n", 1 << aggregation, cqi, bw_index, dci_fmt);
return 1 << aggregation;
}
void dump_ue_list(UE_list_t * listP, int ul_flag)
{
int j;
if (ul_flag == 0) {
for (j = listP->head; j >= 0; j = listP->next[j]) {
LOG_T(MAC, "node %d => %d\n", j, listP->next[j]);
}
} else {
for (j = listP->head_ul; j >= 0; j = listP->next_ul[j]) {
LOG_T(MAC, "node %d => %d\n", j, listP->next_ul[j]);
}
}
}
int add_new_ue(module_id_t mod_idP, int cc_idP, rnti_t rntiP, int harq_pidP
#if (RRC_VERSION >= MAKE_VERSION(14, 0, 0))
, uint8_t rach_resource_type
#endif
)
{
int UE_id;
int i, j;
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
LOG_D(MAC,
"[eNB %d, CC_id %d] Adding UE with rnti %x (next avail %d, num_UEs %d)\n",
mod_idP, cc_idP, rntiP, UE_list->avail, UE_list->num_UEs);
dump_ue_list(UE_list, 0);
for (i = 0; i < NUMBER_OF_UE_MAX; i++) {
if (UE_list->active[i] == TRUE)
continue;
UE_id = i;
memset(&UE_list->UE_template[cc_idP][UE_id], 0,
sizeof(UE_TEMPLATE));
UE_list->UE_template[cc_idP][UE_id].rnti = rntiP;
UE_list->UE_template[cc_idP][UE_id].configured = FALSE;
UE_list->numactiveCCs[UE_id] = 1;
UE_list->numactiveULCCs[UE_id] = 1;
UE_list->pCC_id[UE_id] = cc_idP;
UE_list->ordered_CCids[0][UE_id] = cc_idP;
UE_list->ordered_ULCCids[0][UE_id] = cc_idP;
UE_list->num_UEs++;
UE_list->active[UE_id] = TRUE;
#if defined(USRP_REC_PLAY) // not specific to record/playback ?
UE_list->UE_template[cc_idP][UE_id].pre_assigned_mcs_ul = 0;
#endif
#if (RRC_VERSION >= MAKE_VERSION(14, 0, 0))
UE_list->UE_template[cc_idP][UE_id].rach_resource_type =
rach_resource_type;
#endif
memset((void *) &UE_list->UE_sched_ctrl[UE_id], 0,
sizeof(UE_sched_ctrl));
memset((void *) &UE_list->eNB_UE_stats[cc_idP][UE_id], 0,
sizeof(eNB_UE_STATS));
UE_list->UE_sched_ctrl[UE_id].ue_reestablishment_reject_timer = 0;
UE_list->UE_sched_ctrl[UE_id].ta_update = 31;
for (j = 0; j < 8; j++) {
UE_list->UE_template[cc_idP][UE_id].oldNDI[j] = (j == 0) ? 1 : 0; // 1 because first transmission is with format1A (Msg4) for harq_pid 0
UE_list->UE_template[cc_idP][UE_id].oldNDI_UL[j] = (j == harq_pidP) ? 0 : 1; // 1st transmission is with Msg3;
UE_list->UE_sched_ctrl[UE_id].round[cc_idP][j] = 8;
UE_list->UE_sched_ctrl[UE_id].round_UL[cc_idP][j] = 0;
}
eNB_ulsch_info[mod_idP][cc_idP][UE_id].status = S_UL_WAITING;
eNB_dlsch_info[mod_idP][cc_idP][UE_id].status = S_DL_WAITING;
LOG_D(MAC, "[eNB %d] Add UE_id %d on Primary CC_id %d: rnti %x\n",
mod_idP, UE_id, cc_idP, rntiP);
dump_ue_list(UE_list, 0);
return (UE_id);
}
printf("MAC: cannot add new UE for rnti %x\n", rntiP);
LOG_E(MAC,
"error in add_new_ue(), could not find space in UE_list, Dumping UE list\n");
dump_ue_list(UE_list, 0);
return (-1);
}
//------------------------------------------------------------------------------
int rrc_mac_remove_ue(module_id_t mod_idP, rnti_t rntiP)
//------------------------------------------------------------------------------
{
int i;
int j;
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
int UE_id = find_UE_id(mod_idP,rntiP);
int pCC_id;
if (UE_id == -1) {
LOG_W(MAC,"rrc_mac_remove_ue: UE %x not found\n", rntiP);
return 0;
}
pCC_id = UE_PCCID(mod_idP,UE_id);
LOG_I(MAC,"Removing UE %d from Primary CC_id %d (rnti %x)\n",UE_id,pCC_id, rntiP);
dump_ue_list(UE_list,0);
UE_list->active[UE_id] = FALSE;
UE_list->num_UEs--;
if (UE_list->head == UE_id) UE_list->head=UE_list->next[UE_id];
else UE_list->next[prev(UE_list,UE_id,0)]=UE_list->next[UE_id];
if (UE_list->head_ul == UE_id) UE_list->head_ul=UE_list->next_ul[UE_id];
else UE_list->next_ul[prev(UE_list,UE_id,0)]=UE_list->next_ul[UE_id];
// clear all remaining pending transmissions
/* UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID0] = 0;
UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID1] = 0;
UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID2] = 0;
UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID3] = 0;
UE_list->UE_template[pCC_id][UE_id].ul_SR = 0;
UE_list->UE_template[pCC_id][UE_id].rnti = NOT_A_RNTI;
UE_list->UE_template[pCC_id][UE_id].ul_active = FALSE;
*/
memset (&UE_list->UE_template[pCC_id][UE_id],0,sizeof(UE_TEMPLATE));
UE_list->eNB_UE_stats[pCC_id][UE_id].total_rbs_used = 0;
UE_list->eNB_UE_stats[pCC_id][UE_id].total_rbs_used_retx = 0;
for ( j = 0; j < NB_RB_MAX; j++ ) {
UE_list->eNB_UE_stats[pCC_id][UE_id].num_pdu_tx[j] = 0;
UE_list->eNB_UE_stats[pCC_id][UE_id].num_bytes_tx[j] = 0;
}
UE_list->eNB_UE_stats[pCC_id][UE_id].num_retransmission = 0;
UE_list->eNB_UE_stats[pCC_id][UE_id].total_sdu_bytes = 0;
UE_list->eNB_UE_stats[pCC_id][UE_id].total_pdu_bytes = 0;
UE_list->eNB_UE_stats[pCC_id][UE_id].total_num_pdus = 0;
UE_list->eNB_UE_stats[pCC_id][UE_id].total_rbs_used_rx = 0;
for ( j = 0; j < NB_RB_MAX; j++ ) {
UE_list->eNB_UE_stats[pCC_id][UE_id].num_pdu_rx[j] = 0;
UE_list->eNB_UE_stats[pCC_id][UE_id].num_bytes_rx[j] = 0;
}
UE_list->eNB_UE_stats[pCC_id][UE_id].num_errors_rx = 0;
UE_list->eNB_UE_stats[pCC_id][UE_id].total_pdu_bytes_rx = 0;
UE_list->eNB_UE_stats[pCC_id][UE_id].total_num_pdus_rx = 0;
UE_list->eNB_UE_stats[pCC_id][UE_id].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_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_ulsch_info[mod_idP][pCC_id][UE_id].serving_num = 0;
eNB_dlsch_info[mod_idP][pCC_id][UE_id].serving_num = 0;
// check if this has an RA process active
RA_t *ra;
for (i = 0; i < NB_RA_PROC_MAX; i++) {
ra = (RA_t *) & RC.mac[mod_idP]->common_channels[pCC_id].ra[i];
if (ra->rnti == rntiP) {
ra->state = IDLE;
ra->timing_offset = 0;
ra->RRC_timer = 20;
ra->rnti = 0;
//break;
}
}
return 0;
}
int prev(UE_list_t * listP, int nodeP, int ul_flag)
{
int j;
if (ul_flag == 0) {
if (nodeP == listP->head) {
return (nodeP);
}
for (j = listP->head; j >= 0; j = listP->next[j]) {
if (listP->next[j] == nodeP) {
return (j);
}
}
} else {
if (nodeP == listP->head_ul) {
return (nodeP);
}
for (j = listP->head_ul; j >= 0; j = listP->next_ul[j]) {
if (listP->next_ul[j] == nodeP) {
return (j);
}
}
}
LOG_E(MAC,
"error in prev(), could not find previous to %d in UE_list %s, should never happen, Dumping UE list\n",
nodeP, (ul_flag == 0) ? "DL" : "UL");
dump_ue_list(listP, ul_flag);
return (-1);
}
void swap_UEs(UE_list_t * listP, int nodeiP, int nodejP, int ul_flag)
{
int prev_i, prev_j, next_i, next_j;
LOG_T(MAC, "Swapping UE %d,%d\n", nodeiP, nodejP);
dump_ue_list(listP, ul_flag);
prev_i = prev(listP, nodeiP, ul_flag);
prev_j = prev(listP, nodejP, ul_flag);
AssertFatal((prev_i >= 0) && (prev_j >= 0), "swap_UEs: problem");
if (ul_flag == 0) {
next_i = listP->next[nodeiP];
next_j = listP->next[nodejP];
} else {
next_i = listP->next_ul[nodeiP];
next_j = listP->next_ul[nodejP];
}
LOG_T(MAC, "[%s] next_i %d, next_i, next_j %d, head %d \n",
(ul_flag == 0) ? "DL" : "UL", next_i, next_j, listP->head);
if (ul_flag == 0) {
if (next_i == nodejP) { // case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...
LOG_T(MAC,
"Case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...\n");
listP->next[nodeiP] = next_j;
listP->next[nodejP] = nodeiP;
if (nodeiP == listP->head) { // case i j n(j)
listP->head = nodejP;
} else {
listP->next[prev_i] = nodejP;
}
} else if (next_j == nodeiP) { // case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...
LOG_T(MAC,
"Case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...\n");
listP->next[nodejP] = next_i;
listP->next[nodeiP] = nodejP;
if (nodejP == listP->head) { // case j i n(i)
listP->head = nodeiP;
} else {
listP->next[prev_j] = nodeiP;
}
} else { // case ... p(i) i n(i) ... p(j) j n(j) ...
listP->next[nodejP] = next_i;
listP->next[nodeiP] = next_j;
if (nodeiP == listP->head) {
LOG_T(MAC, "changing head to %d\n", nodejP);
listP->head = nodejP;
listP->next[prev_j] = nodeiP;
} else if (nodejP == listP->head) {
LOG_D(MAC, "changing head to %d\n", nodeiP);
listP->head = nodeiP;
listP->next[prev_i] = nodejP;
} else {
listP->next[prev_i] = nodejP;
listP->next[prev_j] = nodeiP;
}
}
} else { // ul_flag
if (next_i == nodejP) { // case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...
LOG_T(MAC,
"[UL] Case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...\n");
listP->next_ul[nodeiP] = next_j;
listP->next_ul[nodejP] = nodeiP;
if (nodeiP == listP->head_ul) { // case i j n(j)
listP->head_ul = nodejP;
} else {
listP->next_ul[prev_i] = nodejP;
}
} else if (next_j == nodeiP) { // case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...
LOG_T(MAC,
"[UL]Case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...\n");
listP->next_ul[nodejP] = next_i;
listP->next_ul[nodeiP] = nodejP;
if (nodejP == listP->head_ul) { // case j i n(i)
listP->head_ul = nodeiP;
} else {
listP->next_ul[prev_j] = nodeiP;
}
} else { // case ... p(i) i n(i) ... p(j) j n(j) ...
listP->next_ul[nodejP] = next_i;
listP->next_ul[nodeiP] = next_j;
if (nodeiP == listP->head_ul) {
LOG_T(MAC, "[UL]changing head to %d\n", nodejP);
listP->head_ul = nodejP;
listP->next_ul[prev_j] = nodeiP;
} else if (nodejP == listP->head_ul) {
LOG_T(MAC, "[UL]changing head to %d\n", nodeiP);
listP->head_ul = nodeiP;
listP->next_ul[prev_i] = nodejP;
} else {
listP->next_ul[prev_i] = nodejP;
listP->next_ul[prev_j] = nodeiP;
}
}
}
LOG_T(MAC, "After swap\n");
dump_ue_list(listP, ul_flag);
}
// This has to be updated to include BSR information
uint8_t
UE_is_to_be_scheduled(module_id_t module_idP, int CC_id, uint8_t UE_id)
{
UE_TEMPLATE *UE_template =
&RC.mac[module_idP]->UE_list.UE_template[CC_id][UE_id];
UE_sched_ctrl *UE_sched_ctl =
&RC.mac[module_idP]->UE_list.UE_sched_ctrl[UE_id];
// do not schedule UE if UL is not working
if (UE_sched_ctl->ul_failure_timer > 0)
return (0);
if (UE_sched_ctl->ul_out_of_sync > 0)
return (0);
LOG_D(MAC, "[eNB %d][PUSCH] Checking UL requirements UE %d/%x\n",
module_idP, UE_id, UE_RNTI(module_idP, UE_id));
if ((UE_template->scheduled_ul_bytes < UE_template->estimated_ul_buffer) ||
(UE_template->ul_SR > 0) || // uplink scheduling request
((UE_sched_ctl->ul_inactivity_timer > 20) && (UE_sched_ctl->ul_scheduled == 0)) || // every 2 frames when RRC_CONNECTED
((UE_sched_ctl->ul_inactivity_timer > 10) && (UE_sched_ctl->ul_scheduled == 0) && (mac_eNB_get_rrc_status(module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED))) // every Frame when not RRC_CONNECTED
{
LOG_D(MAC,
"[eNB %d][PUSCH] UE %d/%x should be scheduled (BSR0 estimated size %d, SR %d)\n",
module_idP, UE_id, UE_RNTI(module_idP, UE_id),
UE_template->ul_buffer_info[LCGID0], UE_template->ul_SR);
return (1);
} else {
return (0);
}
}
uint8_t get_tmode(module_id_t module_idP, int CC_idP, int UE_idP)
{
eNB_MAC_INST *eNB = RC.mac[module_idP];
COMMON_channels_t *cc = &eNB->common_channels[CC_idP];
struct PhysicalConfigDedicated *physicalConfigDedicated =
eNB->UE_list.physicalConfigDedicated[CC_idP][UE_idP];
if (physicalConfigDedicated == NULL) { // RRCConnectionSetup not received by UE yet
AssertFatal(cc->p_eNB <= 2, "p_eNB is %d, should be <2\n",
cc->p_eNB);
return (cc->p_eNB);
} else {
AssertFatal(physicalConfigDedicated->antennaInfo != NULL,
"antennaInfo is null for CCId %d, UEid %d\n", CC_idP,
UE_idP);
AssertFatal(physicalConfigDedicated->antennaInfo->present !=
PhysicalConfigDedicated__antennaInfo_PR_NOTHING,
"antennaInfo (mod_id %d, CC_id %d) is set to NOTHING\n",
module_idP, CC_idP);
if (physicalConfigDedicated->antennaInfo->present ==
PhysicalConfigDedicated__antennaInfo_PR_explicitValue) {
return (physicalConfigDedicated->antennaInfo->
choice.explicitValue.transmissionMode);
} else if (physicalConfigDedicated->antennaInfo->present ==
PhysicalConfigDedicated__antennaInfo_PR_defaultValue) {
AssertFatal(cc->p_eNB <= 2, "p_eNB is %d, should be <2\n",
cc->p_eNB);
return (cc->p_eNB);
} else
AssertFatal(1 == 0, "Shouldn't be here\n");
}
}
int8_t
get_ULharq(module_id_t module_idP, int CC_idP, uint16_t frameP,
uint8_t subframeP)
{
uint8_t ret = -1;
eNB_MAC_INST *eNB = RC.mac[module_idP];
COMMON_channels_t *cc = &eNB->common_channels[CC_idP];
if (cc->tdd_Config == NULL) { // FDD
ret = (((frameP << 1) + subframeP) & 7);
} else {
switch (cc->tdd_Config->subframeAssignment) {
case 1:
if ((subframeP == 2) ||
(subframeP == 3) || (subframeP == 7) || (subframeP == 8))
switch (subframeP) {
case 2:
case 3:
ret = (subframeP - 2);
break;
case 7:
case 8:
ret = (subframeP - 5);
break;
default:
AssertFatal(1 == 0,
"subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
subframeP,
(int) cc->tdd_Config->subframeAssignment);
break;
}
break;
case 2:
AssertFatal((subframeP == 2) || (subframeP == 7),
"subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
subframeP,
(int) cc->tdd_Config->subframeAssignment);
ret = (subframeP / 7);
break;
case 3:
AssertFatal((subframeP > 1) && (subframeP < 5),
"subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
subframeP,
(int) cc->tdd_Config->subframeAssignment);
ret = (subframeP - 2);
break;
case 4:
AssertFatal((subframeP > 1) && (subframeP < 4),
"subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
subframeP,
(int) cc->tdd_Config->subframeAssignment);
ret = (subframeP - 2);
break;
case 5:
AssertFatal(subframeP == 2,
"subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",
subframeP,
(int) cc->tdd_Config->subframeAssignment);
ret = (subframeP - 2);
break;
default:
AssertFatal(1 == 0,
"subframe2_harq_pid, Unsupported TDD mode %d\n",
(int) cc->tdd_Config->subframeAssignment);
break;
}
}
AssertFatal(ret != -1,
"invalid harq_pid(%d) at SFN/SF = %d/%d\n", (int8_t) ret,
frameP, subframeP);
return ret;
}
uint16_t getRIV(uint16_t N_RB_DL, uint16_t RBstart, uint16_t Lcrbs)
{
uint16_t RIV;
if (Lcrbs <= (1 + (N_RB_DL >> 1)))
RIV = (N_RB_DL * (Lcrbs - 1)) + RBstart;
else
RIV = (N_RB_DL * (N_RB_DL + 1 - Lcrbs)) + (N_RB_DL - 1 - RBstart);
return (RIV);
}
uint32_t
allocate_prbs(int UE_id, unsigned char nb_rb, int N_RB_DL,
uint32_t * rballoc)
{
int i;
uint32_t rballoc_dci = 0;
unsigned char nb_rb_alloc = 0;
for (i = 0; i < (N_RB_DL - 2); i += 2) {
if (((*rballoc >> i) & 3) == 0) {
*rballoc |= (3 << i);
rballoc_dci |= (1 << ((12 - i) >> 1));
nb_rb_alloc += 2;
}
if (nb_rb_alloc == nb_rb) {
return (rballoc_dci);
}
}
if ((N_RB_DL & 1) == 1) {
if ((*rballoc >> (N_RB_DL - 1) & 1) == 0) {
*rballoc |= (1 << (N_RB_DL - 1));
rballoc_dci |= 1;
}
}
return (rballoc_dci);
}
int get_bw_index(module_id_t module_id, uint8_t CC_id)
{
int bw_index = 0;
int N_RB_DL =
to_prb(RC.mac[module_id]->common_channels[CC_id].mib->
message.dl_Bandwidth);
switch (N_RB_DL) {
case 6: // 1.4 MHz
bw_index = 0;
break;
case 25: // 5HMz
bw_index = 1;
break;
case 50: // 10HMz
bw_index = 2;
break;
case 100: // 20HMz
bw_index = 3;
break;
default:
bw_index = 1;
LOG_W(MAC,
"[eNB %d] N_RB_DL %d unknown for CC_id %d, setting bw_index to 1\n",
module_id, N_RB_DL, CC_id);
break;
}
return bw_index;
}
int get_min_rb_unit(module_id_t module_id, uint8_t CC_id)
{
int min_rb_unit = 0;
int N_RB_DL =
to_prb(RC.mac[module_id]->common_channels[CC_id].mib->
message.dl_Bandwidth);
switch (N_RB_DL) {
case 6: // 1.4 MHz
min_rb_unit = 1;
break;
case 25: // 5HMz
min_rb_unit = 2;
break;
case 50: // 10HMz
min_rb_unit = 3;
break;
case 100: // 20HMz
min_rb_unit = 4;
break;
default:
min_rb_unit = 2;
LOG_W(MAC,
"[eNB %d] N_DL_RB %d unknown for CC_id %d, setting min_rb_unit to 2\n",
module_id, N_RB_DL, CC_id);
break;
}
return min_rb_unit;
}
uint32_t
allocate_prbs_sub(int nb_rb, int N_RB_DL, int N_RBG, uint8_t * rballoc)
{
int check = 0; //check1=0,check2=0;
uint32_t rballoc_dci = 0;
//uint8_t number_of_subbands=13;
LOG_T(MAC, "*****Check1RBALLOC****: %d%d%d%d (nb_rb %d,N_RBG %d)\n",
rballoc[3], rballoc[2], rballoc[1], rballoc[0], nb_rb, N_RBG);
while ((nb_rb > 0) && (check < N_RBG)) {
//printf("rballoc[%d] %d\n",check,rballoc[check]);
if (rballoc[check] == 1) {
rballoc_dci |= (1 << ((N_RBG - 1) - check));
switch (N_RB_DL) {
case 6:
nb_rb--;
break;
case 25:
if ((check == N_RBG - 1)) {
nb_rb--;
} else {
nb_rb -= 2;
}
break;
case 50:
if ((check == N_RBG - 1)) {
nb_rb -= 2;
} else {
nb_rb -= 3;
}
break;
case 100:
nb_rb -= 4;
break;
}
}
// printf("rb_alloc %x\n",rballoc_dci);
check = check + 1;
// check1 = check1+2;
}
// rballoc_dci = (rballoc_dci)&(0x1fff);
LOG_T(MAC, "*********RBALLOC : %x\n", rballoc_dci);
// exit(-1);
return (rballoc_dci);
}
int get_subbandsize(uint8_t dl_Bandwidth)
{
uint8_t ss[6] = { 6, 4, 4, 6, 8, 8 };
AssertFatal(dl_Bandwidth < 6, "dl_Bandwidth %d is out of bounds\n",
dl_Bandwidth);
return (ss[dl_Bandwidth]);
}
int get_nb_subband(int N_RB_DL)
{
int nb_sb = 0;
switch (N_RB_DL) {
case 6:
nb_sb = 0;
break;
case 15:
nb_sb = 4; // sb_size =4
case 25:
nb_sb = 7; // sb_size =4, 1 sb with 1PRB, 6 with 2 RBG, each has 2 PRBs
break;
case 50: // sb_size =6
nb_sb = 9;
break;
case 75: // sb_size =8
nb_sb = 10;
break;
case 100: // sb_size =8 , 1 sb with 1 RBG + 12 sb with 2RBG, each RBG has 4 PRBs
nb_sb = 13;
break;
default:
nb_sb = 0;
break;
}
return nb_sb;
}
void init_CCE_table(int module_idP, int CC_idP)
{
memset(RC.mac[module_idP]->CCE_table[CC_idP], 0, 800 * sizeof(int));
}
int
get_nCCE_offset(int *CCE_table,
const unsigned char L,
const int nCCE,
const int common_dci,
const unsigned short rnti, const unsigned char subframe)
{
int search_space_free, m, nb_candidates = 0, l, i;
unsigned int Yk;
/*
printf("CCE Allocation: ");
for (i=0;i<nCCE;i++)
printf("%d.",CCE_table[i]);
printf("\n");
*/
if (common_dci == 1) {
// check CCE(0 ... L-1)
nb_candidates = (L == 4) ? 4 : 2;
nb_candidates = min(nb_candidates, nCCE / L);
// printf("Common DCI nb_candidates %d, L %d\n",nb_candidates,L);
for (m = nb_candidates - 1; m >= 0; m--) {
search_space_free = 1;
for (l = 0; l < L; l++) {
// printf("CCE_table[%d] %d\n",(m*L)+l,CCE_table[(m*L)+l]);
if (CCE_table[(m * L) + l] == 1) {
search_space_free = 0;
break;
}
}
if (search_space_free == 1) {
// printf("returning %d\n",m*L);
for (l = 0; l < L; l++)
CCE_table[(m * L) + l] = 1;
return (m * L);
}
}
return (-1);
} else { // Find first available in ue specific search space
// according to procedure in Section 9.1.1 of 36.213 (v. 8.6)
// compute Yk
Yk = (unsigned int) rnti;
for (i = 0; i <= subframe; i++)
Yk = (Yk * 39827) % 65537;
Yk = Yk % (nCCE / L);
switch (L) {
case 1:
case 2:
nb_candidates = 6;
break;
case 4:
case 8:
nb_candidates = 2;
break;
default:
DevParam(L, nCCE, rnti);
break;
}
LOG_D(MAC, "rnti %x, Yk = %d, nCCE %d (nCCE/L %d),nb_cand %d\n",
rnti, Yk, nCCE, nCCE / L, nb_candidates);
for (m = 0; m < nb_candidates; m++) {
search_space_free = 1;
for (l = 0; l < L; l++) {
int cce = (((Yk + m) % (nCCE / L)) * L) + l;
if (cce >= nCCE || CCE_table[cce] == 1) {
search_space_free = 0;
break;
}
}
if (search_space_free == 1) {
for (l = 0; l < L; l++)
CCE_table[(((Yk + m) % (nCCE / L)) * L) + l] = 1;
return (((Yk + m) % (nCCE / L)) * L);
}
}
return (-1);
}
}
void
dump_CCE_table(int *CCE_table, const int nCCE,
const unsigned short rnti, const int subframe, int L)
{
int nb_candidates = 0, i;
unsigned int Yk;
printf("CCE 0: ");
for (i = 0; i < nCCE; i++) {
printf("%1d.", CCE_table[i]);
if ((i & 7) == 7)
printf("\n CCE %d: ", i);
}
Yk = (unsigned int) rnti;
for (i = 0; i <= subframe; i++)
Yk = (Yk * 39827) % 65537;
Yk = Yk % (nCCE / L);
switch (L) {
case 1:
case 2:
nb_candidates = 6;
break;
case 4:
case 8:
nb_candidates = 2;
break;
default:
DevParam(L, nCCE, rnti);
break;
}
printf("rnti %x, Yk*L = %d, nCCE %d (nCCE/L %d),nb_cand*L %d\n", rnti,
Yk * L, nCCE, nCCE / L, nb_candidates * L);
}
uint16_t
getnquad(COMMON_channels_t * cc, uint8_t num_pdcch_symbols, uint8_t mi)
{
uint16_t Nreg = 0;
AssertFatal(cc != NULL, "cc is null\n");
AssertFatal(cc->mib != NULL, "cc->mib is null\n");
int N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth);
int phich_resource = get_phich_resource_times6(cc);
uint8_t Ngroup_PHICH = (phich_resource * N_RB_DL) / 48;
if (((phich_resource * N_RB_DL) % 48) > 0)
Ngroup_PHICH++;
if (cc->Ncp == 1) {
Ngroup_PHICH <<= 1;
}
Ngroup_PHICH *= mi;
if ((num_pdcch_symbols > 0) && (num_pdcch_symbols < 4))
switch (N_RB_DL) {
case 6:
Nreg = 12 + (num_pdcch_symbols - 1) * 18;
break;
case 25:
Nreg = 50 + (num_pdcch_symbols - 1) * 75;
break;
case 50:
Nreg = 100 + (num_pdcch_symbols - 1) * 150;
break;
case 100:
Nreg = 200 + (num_pdcch_symbols - 1) * 300;
break;
default:
return (0);
}
// printf("Nreg %d (%d)\n",Nreg,Nreg - 4 - (3*Ngroup_PHICH));
return (Nreg - 4 - (3 * Ngroup_PHICH));
}
uint16_t
getnCCE(COMMON_channels_t * cc, uint8_t num_pdcch_symbols, uint8_t mi)
{
AssertFatal(cc != NULL, "cc is null\n");
return (getnquad(cc, num_pdcch_symbols, mi) / 9);
}
uint8_t getmi(COMMON_channels_t * cc, int subframe)
{
AssertFatal(cc != NULL, "cc is null\n");
// for FDD
if (cc->tdd_Config == NULL) // FDD
return 1;
// for TDD
switch (cc->tdd_Config->subframeAssignment) {
case 0:
if ((subframe == 0) || (subframe == 5))
return (2);
else
return (1);
break;
case 1:
if ((subframe == 0) || (subframe == 5))
return (0);
else
return (1);
break;
case 2:
if ((subframe == 3) || (subframe == 8))
return (1);
else
return (0);
break;
case 3:
if ((subframe == 0) || (subframe == 8) || (subframe == 9))
return (1);
else
return (0);
break;
case 4:
if ((subframe == 8) || (subframe == 9))
return (1);
else
return (0);
break;
case 5:
if (subframe == 8)
return (1);
else
return (0);
break;
case 6:
return (1);
break;
default:
return (0);
}
}
uint16_t
get_nCCE_max(COMMON_channels_t * cc, int num_pdcch_symbols, int subframe)
{
AssertFatal(cc != NULL, "cc is null\n");
return (getnCCE(cc, num_pdcch_symbols, getmi(cc, subframe)));
}
// Allocate the CCEs
int
allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP)
{
int *CCE_table = RC.mac[module_idP]->CCE_table[CC_idP];
nfapi_dl_config_request_body_t *DL_req =
&RC.mac[module_idP]->DL_req[CC_idP].dl_config_request_body;
nfapi_hi_dci0_request_body_t *HI_DCI0_req =
&RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body;
nfapi_dl_config_request_pdu_t *dl_config_pdu =
&DL_req->dl_config_pdu_list[0];
nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu =
&HI_DCI0_req->hi_dci0_pdu_list[0];
int nCCE_max =
get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP], 1,
subframeP);
int fCCE;
int i, j, idci;
int nCCE = 0;
LOG_D(MAC,
"Allocate CCEs subframe %d, test %d : (DL PDU %d, DL DCI %d, UL %d)\n",
subframeP, test_onlyP, DL_req->number_pdu, DL_req->number_dci,
HI_DCI0_req->number_of_dci);
DL_req->number_pdcch_ofdm_symbols = 1;
try_again:
init_CCE_table(module_idP, CC_idP);
nCCE = 0;
for (i = 0, idci = 0; i < DL_req->number_pdu; i++) {
// allocate DL common DCIs first
if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)
&& (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type ==
2)) {
LOG_D(MAC,
"Trying to allocate COMMON DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n",
idci, DL_req->number_dci + HI_DCI0_req->number_of_dci,
DL_req->number_dci, HI_DCI0_req->number_of_dci,
dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti,
dl_config_pdu[i].dci_dl_pdu.
dci_dl_pdu_rel8.aggregation_level, nCCE, nCCE_max,
DL_req->number_pdcch_ofdm_symbols);
if (nCCE +
(dl_config_pdu[i].dci_dl_pdu.
dci_dl_pdu_rel8.aggregation_level) > nCCE_max) {
if (DL_req->number_pdcch_ofdm_symbols == 3)
goto failed;
LOG_D(MAC,
"Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n",
DL_req->number_pdcch_ofdm_symbols);
DL_req->number_pdcch_ofdm_symbols++;
nCCE_max =
get_nCCE_max(&RC.mac[module_idP]->
common_channels[CC_idP],
DL_req->number_pdcch_ofdm_symbols,
subframeP);
goto try_again;
}
// number of CCEs left can potentially hold this allocation
fCCE = get_nCCE_offset(CCE_table,
dl_config_pdu[i].
dci_dl_pdu.dci_dl_pdu_rel8.
aggregation_level, nCCE_max, 1,
dl_config_pdu[i].
dci_dl_pdu.dci_dl_pdu_rel8.rnti,
subframeP);
if (fCCE == -1) {
if (DL_req->number_pdcch_ofdm_symbols == 3) {
LOG_D(MAC,
"subframe %d: Dropping Allocation for RNTI %x\n",
subframeP,
dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.
rnti);
for (j = 0; j <= i; j++) {
if (dl_config_pdu[j].pdu_type ==
NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)
LOG_D(MAC,
"DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n",
j,
DL_req->number_dci +
HI_DCI0_req->number_of_dci,
DL_req->number_dci,
HI_DCI0_req->number_of_dci,
dl_config_pdu[j].
dci_dl_pdu.dci_dl_pdu_rel8.rnti,
dl_config_pdu[j].
dci_dl_pdu.dci_dl_pdu_rel8.dci_format,
dl_config_pdu[j].
dci_dl_pdu.dci_dl_pdu_rel8.
aggregation_level, nCCE, nCCE_max,
DL_req->number_pdcch_ofdm_symbols);
}
//dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<<dci_alloc->L);
goto failed;
}
LOG_D(MAC,
"Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n",
DL_req->number_pdcch_ofdm_symbols);
DL_req->number_pdcch_ofdm_symbols++;
nCCE_max = get_nCCE_max(&RC.mac[module_idP]->
common_channels[CC_idP],
DL_req->number_pdcch_ofdm_symbols,
subframeP);
goto try_again;
} // fCCE==-1
// the allocation is feasible, rnti rule passes
nCCE += dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level;
LOG_D(MAC, "Allocating at nCCE %d\n", fCCE);
if (test_onlyP == 0) {
dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.cce_idx = fCCE;
LOG_D(MAC,
"Allocate COMMON DCI CCEs subframe %d, test %d => L %d fCCE %d\n",
subframeP, test_onlyP,
dl_config_pdu[i].dci_dl_pdu.
dci_dl_pdu_rel8.aggregation_level, fCCE);
}
idci++;
}
} // for i = 0 ... num_DL_DCIs
// no try to allocate UL DCIs
for (i = 0; i < HI_DCI0_req->number_of_dci + HI_DCI0_req->number_of_hi;
i++) {
// allocate UL DCIs
if (hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) {
LOG_D(MAC,
"Trying to allocate format 0 DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n",
idci, DL_req->number_dci + HI_DCI0_req->number_of_dci,
DL_req->number_dci, HI_DCI0_req->number_of_dci,
hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti,
hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level,
nCCE, nCCE_max, DL_req->number_pdcch_ofdm_symbols);
if (nCCE + (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level) > nCCE_max) {
if (DL_req->number_pdcch_ofdm_symbols == 3)
goto failed;
LOG_D(MAC,
"Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n",
DL_req->number_pdcch_ofdm_symbols);
DL_req->number_pdcch_ofdm_symbols++;
nCCE_max =
get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],
DL_req->number_pdcch_ofdm_symbols,
subframeP);
goto try_again;
}
// number of CCEs left can potentially hold this allocation
fCCE = get_nCCE_offset(CCE_table,
hi_dci0_pdu[i].dci_pdu.
dci_pdu_rel8.aggregation_level,
nCCE_max, 0,
hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.
rnti, subframeP);
if (fCCE == -1) {
if (DL_req->number_pdcch_ofdm_symbols == 3) {
LOG_D(MAC,
"subframe %d: Dropping Allocation for RNTI %x\n",
subframeP,
hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti);
for (j = 0; j <= i; j++) {
if (hi_dci0_pdu[j].pdu_type ==
NFAPI_HI_DCI0_DCI_PDU_TYPE)
LOG_D(MAC,
"DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n",
j,
DL_req->number_dci + HI_DCI0_req->number_of_dci,
DL_req->number_dci,
HI_DCI0_req->number_of_dci,
hi_dci0_pdu[j].dci_pdu.dci_pdu_rel8.rnti,
hi_dci0_pdu[j].dci_pdu.dci_pdu_rel8.
dci_format,
hi_dci0_pdu[j].dci_pdu.
dci_pdu_rel8.aggregation_level, nCCE,
nCCE_max,
DL_req->number_pdcch_ofdm_symbols);
}
//dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<<dci_alloc->L);
goto failed;
}
LOG_D(MAC,
"Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n",
DL_req->number_pdcch_ofdm_symbols);
DL_req->number_pdcch_ofdm_symbols++;
nCCE_max =
get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],
DL_req->number_pdcch_ofdm_symbols,
subframeP);
goto try_again;
} // fCCE==-1
// the allocation is feasible, rnti rule passes
nCCE += hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level;
LOG_D(MAC, "Allocating at nCCE %d\n", fCCE);
if (test_onlyP == 0) {
hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.cce_index = fCCE;
LOG_D(MAC, "Allocate CCEs subframe %d, test %d\n",
subframeP, test_onlyP);
}
idci++;
}
} // for i = 0 ... num_UL_DCIs
for (i = 0; i < DL_req->number_pdu; i++) {
// allocate DL UE specific DCIs
if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)
&& (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type ==
1)) {
LOG_D(MAC,
"Trying to allocate DL UE-SPECIFIC DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n",
idci, DL_req->number_dci + HI_DCI0_req->number_of_dci,
DL_req->number_dci, HI_DCI0_req->number_of_dci,
dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti,
dl_config_pdu[i].dci_dl_pdu.
dci_dl_pdu_rel8.aggregation_level, nCCE, nCCE_max,
DL_req->number_pdcch_ofdm_symbols);
if (nCCE + (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level) > nCCE_max) {
if (DL_req->number_pdcch_ofdm_symbols == 3)
goto failed;
LOG_D(MAC,
"Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n",
DL_req->number_pdcch_ofdm_symbols);
DL_req->number_pdcch_ofdm_symbols++;
nCCE_max = get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],
DL_req->number_pdcch_ofdm_symbols,
subframeP);
goto try_again;
}
// number of CCEs left can potentially hold this allocation
fCCE = get_nCCE_offset(CCE_table,
dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, nCCE_max, 0,
dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti,
subframeP);
if (fCCE == -1) {
if (DL_req->number_pdcch_ofdm_symbols == 3) {
LOG_I(MAC,
"subframe %d: Dropping Allocation for RNTI %x\n",
subframeP,
dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.
rnti);
for (j = 0; j <= i; j++) {
if (dl_config_pdu[j].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)
LOG_I(MAC,
"DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n",
j,
DL_req->number_dci + HI_DCI0_req->number_of_dci,
DL_req->number_dci,
HI_DCI0_req->number_of_dci,
dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8.rnti,
dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8.dci_format,
dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8.
aggregation_level,
nCCE,
nCCE_max,
DL_req->number_pdcch_ofdm_symbols);
}
//dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<<dci_alloc->L);
goto failed;
}
LOG_D(MAC,
"Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n",
DL_req->number_pdcch_ofdm_symbols);
DL_req->number_pdcch_ofdm_symbols++;
nCCE_max =
get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],
DL_req->number_pdcch_ofdm_symbols,
subframeP);
goto try_again;
} // fCCE==-1
// the allocation is feasible, rnti rule passes
nCCE += dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level;
LOG_D(MAC, "Allocating at nCCE %d\n", fCCE);
if (test_onlyP == 0) {
dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.cce_idx = fCCE;
LOG_D(MAC, "Allocate CCEs subframe %d, test %d\n",
subframeP, test_onlyP);
}
idci++;
}
} // for i = 0 ... num_DL_DCIs
return 0;
failed:
return -1;
}
nfapi_ul_config_request_pdu_t *has_ul_grant(module_id_t module_idP,
int CC_idP, uint16_t absSFP,
uint16_t rnti)
{
nfapi_ul_config_request_body_t *ul_req;
nfapi_ul_config_request_pdu_t *ul_config_pdu;
ul_req = &RC.mac[module_idP]->UL_req_tmp[CC_idP][absSFP % 10].ul_config_request_body;
ul_config_pdu = &ul_req->ul_config_pdu_list[0];
LOG_D(MAC,
"Checking for rnti %x UL grant in subframeP %d (num pdu %d)\n",
rnti, absSFP % 10, ul_req->number_of_pdus);
for (int i = 0; i < ul_req->number_of_pdus; i++) {
LOG_D(MAC, "PDU %d : type %d,rnti %x\n", i,ul_config_pdu[i].pdu_type, rnti);
if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE)
&& (ul_config_pdu[i].ulsch_pdu.ulsch_pdu_rel8.rnti == rnti))
return (&ul_config_pdu[i]);
if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE)
&& (ul_config_pdu[i].ulsch_cqi_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti))
return (&ul_config_pdu[i]);
if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE)
&& (ul_config_pdu[i].ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti))
return (&ul_config_pdu[i]);
if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE)
&& (ul_config_pdu[i].ulsch_cqi_harq_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti))
return (&ul_config_pdu[i]);
if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE)
&& (ul_config_pdu[i].uci_cqi_pdu.ue_information.ue_information_rel8.rnti == rnti))
return (&ul_config_pdu[i]);
if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE)
&& (ul_config_pdu[i].uci_sr_pdu.ue_information.ue_information_rel8.rnti == rnti))
return (&ul_config_pdu[i]);
if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE)
&& (ul_config_pdu[i].uci_harq_pdu.ue_information.ue_information_rel8.rnti == rnti))
return (&ul_config_pdu[i]);
if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE)
&& (ul_config_pdu[i].uci_sr_harq_pdu.ue_information.ue_information_rel8.rnti == rnti))
return (&ul_config_pdu[i]);
if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE)
&& (ul_config_pdu[i].uci_cqi_harq_pdu.ue_information.ue_information_rel8.rnti == rnti))
return (&ul_config_pdu[i]);
if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE)
&& (ul_config_pdu[i].uci_cqi_sr_pdu.ue_information.ue_information_rel8.rnti == rnti))
return (&ul_config_pdu[i]);
if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE)
&& (ul_config_pdu[i].uci_cqi_sr_harq_pdu.ue_information.ue_information_rel8.rnti == rnti))
return (&ul_config_pdu[i]);
if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE)
&& (ul_config_pdu[i].ulsch_uci_csi_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti))
return (&ul_config_pdu[i]);
if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE)
&& (ul_config_pdu[i].ulsch_uci_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti))
return (&ul_config_pdu[i]);
if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE)
&& (ul_config_pdu[i].ulsch_csi_uci_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti))
return (&ul_config_pdu[i]);
}
return (NULL); // no ul grant at all for this UE
}
boolean_t
CCE_allocation_infeasible(int module_idP,
int CC_idP,
int format_flag,
int subframe, int aggregation, int rnti)
{
nfapi_dl_config_request_body_t *DL_req = &RC.mac[module_idP]->DL_req[CC_idP].dl_config_request_body;
nfapi_dl_config_request_pdu_t *dl_config_pdu = &DL_req->dl_config_pdu_list[DL_req->number_pdu];
nfapi_hi_dci0_request_body_t *HI_DCI0_req = &RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body;
nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_pdu_list[HI_DCI0_req->number_of_dci + HI_DCI0_req->number_of_hi];
int ret;
boolean_t res = FALSE;
if (format_flag != 2) { // DL DCI
if (DL_req->number_pdu == MAX_NUM_DL_PDU) {
LOG_W(MAC,
"Subframe %d: FAPI DL structure is full, skip scheduling UE %d\n",
subframe, rnti);
} else {
dl_config_pdu->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) (%x,%d,%d)\n",
subframe, format_flag, rnti, aggregation,
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti,
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.
aggregation_level,
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type);
ret = allocate_CCEs(module_idP, CC_idP, subframe, 0);
if (ret == -1) res = TRUE;
DL_req->number_pdu--;
}
} else { // ue-specific UL DCI
if (HI_DCI0_req->number_of_dci + HI_DCI0_req->number_of_hi == MAX_NUM_HI_DCI0_PDU) {
LOG_W(MAC,
"Subframe %d: FAPI UL structure is full, skip scheduling UE %d\n",
subframe, rnti);
} else {
hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_DCI_PDU_TYPE;
hi_dci0_pdu->dci_pdu.dci_pdu_rel8.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++;
ret = allocate_CCEs(module_idP, CC_idP, subframe, 0);
if (ret == -1) res = TRUE;
HI_DCI0_req->number_of_dci--;
}
}
return res;
}
void
extract_harq(module_id_t mod_idP, int CC_idP, int UE_id,
frame_t frameP, sub_frame_t subframeP,
void *harq_indication, int format)
{
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
rnti_t rnti = UE_RNTI(mod_idP, UE_id);
COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP];
nfapi_harq_indication_fdd_rel13_t *harq_indication_fdd;
nfapi_harq_indication_tdd_rel13_t *harq_indication_tdd;
uint16_t num_ack_nak;
int numCC = UE_list->numactiveCCs[UE_id];
int pCCid = UE_list->pCC_id[UE_id];
int spatial_bundling = 0;
int tmode[5];
int i, j;
uint8_t *pdu;
#if (RRC_VERSION >= MAKE_VERSION(13, 0, 0))
if (UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated != NULL &&
UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->pucch_ConfigDedicated != NULL &&
(UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7)
&& (UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13)
&& (((UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13->spatialBundlingPUCCH_r13) && (format == 0))
|| ((UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13->spatialBundlingPUSCH_r13)
&& (format == 1))))
spatial_bundling = 1;
#endif
for (i = 0; i < numCC; i++)
tmode[i] = get_tmode(mod_idP, i, UE_id);
if (cc->tdd_Config) {
harq_indication_tdd = (nfapi_harq_indication_tdd_rel13_t *) harq_indication;
// pdu = &harq_indication_tdd->harq_tb_n[0];
num_ack_nak = harq_indication_tdd->number_of_ack_nack;
switch (harq_indication_tdd->mode) {
case 0: // Format 1a/b
AssertFatal(numCC == 1,
"numCC %d > 1, should not be using Format1a/b\n",
numCC);
break;
case 1: // Channel Selection
break;
case 2: // Format 3
break;
case 3: // Format 4
break;
case 4: // Format 5
break;
}
} else {
harq_indication_fdd = (nfapi_harq_indication_fdd_rel13_t *) harq_indication;
num_ack_nak = harq_indication_fdd->number_of_ack_nack;
pdu = &harq_indication_fdd->harq_tb_n[0];
uint8_t harq_pid = ((10 * frameP) + subframeP + 10236) & 7;
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]);
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);
AssertFatal(sched_ctl->round[CC_idP][harq_pid] < 8,
"Got ACK/NAK for inactive harq_pid %d for UE %d/%x\n",
harq_pid, UE_id, rnti);
AssertFatal(pdu[0] == 1 || pdu[0] == 2
|| pdu[0] == 4,
"Received ACK/NAK %d which is not 1 or 2 for harq_pid %d from UE %d/%x\n",
pdu[0], harq_pid, UE_id, rnti);
LOG_D(MAC, "Received %d for harq_pid %d\n", pdu[0],
harq_pid);
if (pdu[0] == 1) { // ACK
sched_ctl->round[CC_idP][harq_pid] = 8; // release HARQ process
sched_ctl->tbcnt[CC_idP][harq_pid] = 0;
} else if (pdu[0] == 2 || pdu[0] == 4) { // NAK (treat DTX as NAK)
sched_ctl->round[CC_idP][harq_pid]++; // increment round
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;
}
}
} else {
// one or two ACK/NAK bits
AssertFatal(num_ack_nak <= 2,
"num_ack_nak %d > 2 for 1 CC and TM3/4/8/9/10\n",
num_ack_nak);
if ((num_ack_nak == 2)
&& (sched_ctl->round[CC_idP][harq_pid] < 8)
&& (sched_ctl->tbcnt[CC_idP][harq_pid] == 1)
&& (pdu[0] == 1) && (pdu[1] == 1)) {
sched_ctl->round[CC_idP][harq_pid] = 8;
sched_ctl->tbcnt[CC_idP][harq_pid] = 0;
}
if ((num_ack_nak == 2)
&& (sched_ctl->round[CC_idP][harq_pid] < 8)
&& (sched_ctl->tbcnt[CC_idP][harq_pid] == 1)
&& (pdu[0] == 2) && (pdu[1] == 2)) {
sched_ctl->round[CC_idP][harq_pid]++;
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;
}
}
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? */
}
} 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;
}
}
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;
}
}
}
void
extract_pucch_csi(module_id_t mod_idP, int CC_idP, int UE_id,
frame_t frameP, sub_frame_t subframeP,
uint8_t * pdu, uint8_t length)
{
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP];
struct CQI_ReportPeriodic *cqi_ReportPeriodic;
int no_pmi;
uint8_t Ltab[6] = { 0, 2, 4, 4, 4, 4 };
uint8_t Jtab[6] = { 0, 2, 2, 3, 4, 4 };
int feedback_cnt;
AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated != NULL,
"physicalConfigDedicated is null for UE %d\n", UE_id);
AssertFatal(UE_list->
UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL,
"cqi_ReportConfig is null for UE %d\n", UE_id);
AssertFatal((cqi_ReportPeriodic = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic) != NULL,
"cqi_ReportPeriodic is null for UE %d\n", UE_id);
// determine feedback mode
AssertFatal(cqi_ReportPeriodic->present != CQI_ReportPeriodic_PR_NOTHING,
"cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_NOTHING!\n");
AssertFatal(cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present != CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING,
"cqi_ReportPeriodic->cqi_FormatIndicatorPeriodic.choice.setup.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING!\n");
uint16_t Npd, N_OFFSET_CQI;
int H, K, bandwidth_part, L, Lmask;
int ri = sched_ctl->periodic_ri_received[CC_idP];
get_csi_params(cc, cqi_ReportPeriodic, &Npd, &N_OFFSET_CQI, &H);
K = (H - 1) / Jtab[cc->mib->message.dl_Bandwidth];
L = Ltab[cc->mib->message.dl_Bandwidth];
Lmask = L - 1;
feedback_cnt = (((frameP * 10) + subframeP) / Npd) % H;
if (feedback_cnt > 0)
bandwidth_part = (feedback_cnt - 1) % K;
else
bandwidth_part = 0;
switch (get_tmode(mod_idP, CC_idP, UE_id)) {
case 1:
case 2:
case 3:
case 7:
no_pmi = 1;
break;
case 4:
case 5:
case 6:
no_pmi = 0;
break;
default:
// note: need to check TM8-10 without PMI/RI or with 1 antenna port (see Section 5.2.3.3.1 from 36.213)
no_pmi = 0;
}
if ((cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_widebandCQI)
|| (feedback_cnt == 0)) {
// Note: This implements only Tables: 5.3.3.1-1,5.3.3.1-1A and 5.3.3.1-2 from 36.213 (1,2,4 antenna ports Wideband CQI/PMI)
if (no_pmi == 1) { // get spatial_diffcqi if needed
sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF;
sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] =
(pdu[0] >> 4) & 7;
} else if ((cc->p_eNB == 2) && (ri == 1)) {
// p=2 Rank 1 wideband CQI/PMI 6 bits
sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF;
sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0] >> 4) & 3;
} else if ((cc->p_eNB == 2) && (ri > 1)) {
// p=2 Rank 2 wideband CQI/PMI 8 bits
sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF;
sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] =
(pdu[0] >> 4) & 7;
sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0] >> 7) & 1;
} else if ((cc->p_eNB == 4) && (ri == 1)) {
// p=4 Rank 1 wideband CQI/PMI 8 bits
sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF;
sched_ctl->periodic_wideband_pmi[CC_idP] =
(pdu[0] >> 4) & 0x0F;
} else if ((cc->p_eNB == 4) && (ri > 1)) {
// p=4 Rank 2 wideband CQI/PMI 11 bits
sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF;
sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] =
(pdu[0] >> 4) & 7;
sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0] >> 7) & 0xF;
} else
AssertFatal(1 == 0,
"illegal combination p %d, ri %d, no_pmi %d\n",
cc->p_eNB, ri, no_pmi);
} else if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI)
{
// This is Table 5.2.3.3.2-2 for 36.213
if (ri == 1) {
//4+Ltab[cc->mib->message.dl_Bandwidth] bits
sched_ctl->periodic_subband_cqi[CC_idP][(bandwidth_part * L) +((pdu[0] >> 4) & Lmask)] = pdu[0] & 0xF;
} else if (ri > 1) {
//7+Ltab[cc->mib->message.dl_Bandwidth] bits;
sched_ctl->periodic_subband_spatial_diffcqi[CC_idP][(bandwidth_part * L) + ((pdu[0] >> 7) & Lmask)] = (pdu[0] >> 4) & 7;
sched_ctl->periodic_subband_cqi[CC_idP][(bandwidth_part * L) + ((pdu[0] >> 7) & Lmask)] =
pdu[0] & 0xF;
}
}
}
void
extract_pusch_csi(module_id_t mod_idP, int CC_idP, int UE_id,
frame_t frameP, sub_frame_t subframeP,
uint8_t * pdu, uint8_t length)
{
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP];
UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
int Ntab[6] = { 0, 4, 7, 9, 10, 13 };
int Ntab_uesel[6] = { 0, 8, 13, 17, 19, 25 };
int Ltab_uesel[6] = { 0, 6, 9, 13, 15, 18 };
int Mtab_uesel[6] = { 0, 1, 3, 5, 6, 6 };
int v[6];
int i;
uint64_t p = *(uint64_t *) pdu;
int curbyte, curbit;
CQI_ReportModeAperiodic_t *cqi_ReportModeAperiodic;
AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated != NULL,
"physicalConfigDedicated is null for UE %d\n", UE_id);
AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL,
"cqi_ReportConfig is null for UE %d\n", UE_id);
AssertFatal((cqi_ReportModeAperiodic = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic) != NULL,
"cqi_ReportModeAperiodic is null for UE %d\n", UE_id);
int N = Ntab[cc->mib->message.dl_Bandwidth];
int tmode = get_tmode(mod_idP, CC_idP, UE_id);
int ri = sched_ctl->aperiodic_ri_received[CC_idP];
int r, diffcqi0 = 0, diffcqi1 = 0, pmi_uesel = 0;
int bw = cc->mib->message.dl_Bandwidth;
int m;
switch (*cqi_ReportModeAperiodic) {
case CQI_ReportModeAperiodic_rm12:
AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n");
// wideband multiple PMI (TM4/6), Table 5.2.2.6.1-1 (for TM4/6)
AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 || tmode == 10,
"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm12\n",
tmode);
if (tmode <= 6) { //Table 5.2.2.6.1-1 36.213
if ((ri == 1) && (cc->p_eNB == 2)) {
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F);
p >>= 4;
for (i = 0; i < N; i++) {
sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t) (p & 0x03);
p >>= 2;
}
}
if ((ri == 2) && (cc->p_eNB == 2)) {
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F);
p >>= 4;
sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t) (p & 0x0F);
p >>= 4;
for (i = 0; i < N; i++) {
sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t) (p & 0x01);
p >>= 1;
}
}
if ((ri == 1) && (cc->p_eNB == 4)) {
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F);
p >>= 4;
for (i = 0; i < N; i++) {
sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t) (p & 0x03);
p >>= 4;
}
}
if ((ri == 2) && (cc->p_eNB == 4)) {
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F);
p >>= 4;
sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t) (p & 0x0F);
p >>= 4;
for (i = 0; i < N; i++) {
sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t) (p & 0x01);
p >>= 4;
}
}
} // if (tmode <= 6) { //Table 5.2.2.6.1-1 36.213
else {
AssertFatal(1 == 0, "support for TM 8-10 to be done\n");
}
break;
case CQI_ReportModeAperiodic_rm20:
AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n");
// UE-selected subband CQI no PMI (TM1/2/3/7) , Table 5.2.2.6.3-1 from 36.213
AssertFatal(tmode == 1 || tmode == 2 || tmode == 3
|| tmode == 7,
"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm20\n",
tmode);
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F);
p >>= 4;
diffcqi0 = (uint8_t) (p & 0x03);
p >>= 2;
r = (uint8_t) (p & ((1 >> Ltab_uesel[bw]) - 1));
reverse_index(Ntab_uesel[bw], Mtab_uesel[bw], r, v);
for (m = 0; m < Mtab_uesel[bw]; m++)
sched_ctl->aperiodic_subband_diffcqi0[CC_idP][v[m]] = diffcqi0;
break;
case CQI_ReportModeAperiodic_rm22:
AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n");
// UE-selected subband CQI multiple PMI (TM4/6) Table 5.2.2.6.3-2 from 36.213
AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9
|| tmode == 10,
"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm22\n",
tmode);
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F);
p >>= 4;
diffcqi0 = (uint8_t) (p & 0x03);
p >>= 2;
if (ri > 1) {
sched_ctl->aperiodic_wideband_cqi1[CC_idP] =
(uint8_t) (p & 0x0F);
p >>= 4;
diffcqi1 = (uint8_t) (p & 0x03);
p >>= 2;
}
r = (uint8_t) (p & ((1 >> Ltab_uesel[bw]) - 1));
p >>= Ltab_uesel[bw];
reverse_index(Ntab_uesel[bw], Mtab_uesel[bw], r, v);
if ((ri == 1) && (cc->p_eNB == 2)) {
pmi_uesel = p & 0x3;
p >>= 2;
sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x3;
} else if ((ri == 2) && (cc->p_eNB == 2)) {
pmi_uesel = p & 0x1;
p >>= 1;
sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x1;
} else if (cc->p_eNB == 4) {
pmi_uesel = p & 0x0F;
p >>= 4;
sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x0F;
}
for (m = 0; m < Mtab_uesel[bw]; m++) {
sched_ctl->aperiodic_subband_diffcqi0[CC_idP][v[m]] = diffcqi0;
if (ri > 1)
sched_ctl->aperiodic_subband_diffcqi1[CC_idP][v[m]] =
diffcqi1;
sched_ctl->aperiodic_subband_pmi[CC_idP][v[m]] = pmi_uesel;
}
break;
case CQI_ReportModeAperiodic_rm30:
//subband CQI no PMI (TM1/2/3/7)
AssertFatal(tmode == 1 || tmode == 2 || tmode == 3
|| tmode == 7,
"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm30\n",
tmode);
sched_ctl->aperiodic_wideband_cqi0[CC_idP] = pdu[0] >> 4;
curbyte = 0;
curbit = 3;
for (i = 0; i < N; i++) {
sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] =
(pdu[curbyte] >> (curbit - 1)) & 0x03;
curbit -= 2;
if (curbit < 0) {
curbit = 7;
curbyte++;
}
}
sched_ctl->dl_cqi[CC_idP] =
sched_ctl->aperiodic_wideband_cqi0[CC_idP];
break;
case CQI_ReportModeAperiodic_rm31:
AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n");
//subband CQI single PMI (TM4/5/6)
AssertFatal(tmode == 4 || tmode == 5 || tmode == 6 || tmode == 8
|| tmode == 9
|| tmode == 10,
"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm31\n",
tmode);
if ((ri == 1) && (cc->p_eNB == 2)) {
sched_ctl->aperiodic_wideband_cqi0[CC_idP] =
(uint8_t) (p & 0x0F);
p >>= 4;
for (i = 0; i < N; i++) {
sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] =
(uint8_t) (p & 0x03);
p >>= 2;
}
sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x03;
}
if ((ri == 2) && (cc->p_eNB == 2)) {
sched_ctl->aperiodic_wideband_cqi0[CC_idP] =
(uint8_t) (p & 0x0F);
p >>= 4;
for (i = 0; i < N; i++) {
sched_ctl->aperiodic_subband_pmi[CC_idP][i] =
(uint8_t) (p & 0x01);
p >>= 1;
}
sched_ctl->aperiodic_wideband_cqi1[CC_idP] =
(uint8_t) (p & 0x0F);
p >>= 4;
for (i = 0; i < N; i++) {
sched_ctl->aperiodic_subband_pmi[CC_idP][i] =
(uint8_t) (p & 0x01);
p >>= 1;
}
sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x01;
}
if ((ri == 1) && (cc->p_eNB == 4)) {
sched_ctl->aperiodic_wideband_cqi0[CC_idP] =
(uint8_t) (p & 0x0F);
p >>= 4;
for (i = 0; i < N; i++) {
sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] =
(uint8_t) (p & 0x03);
p >>= 2;
}
sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x0F;
}
if ((ri > 1) && (cc->p_eNB == 4)) { // Note : 64 bits for 20 MHz
sched_ctl->aperiodic_wideband_cqi0[CC_idP] =
(uint8_t) (p & 0x0F);
p >>= 4;
for (i = 0; i < N; i++) {
sched_ctl->aperiodic_subband_pmi[CC_idP][i] =
(uint8_t) (p & 0x01);
p >>= 1;
}
sched_ctl->aperiodic_wideband_cqi1[CC_idP] =
(uint8_t) (p & 0x0F);
p >>= 4;
for (i = 0; i < N; i++) {
sched_ctl->aperiodic_subband_pmi[CC_idP][i] =
(uint8_t) (p & 0x01);
p >>= 2;
}
sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x0F;
}
break;
#if (RRC_VERSION >= MAKE_VERSION(12, 5, 0))
case CQI_ReportModeAperiodic_rm32_v1250:
AssertFatal(tmode == 4 || tmode == 5 || tmode == 6 || tmode == 8
|| tmode == 9
|| tmode == 10,
"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm32\n",
tmode);
AssertFatal(1 == 0, "CQI_ReportModeAperiodic_rm32 to be done\n");
break;
#endif
#if (RRC_VERSION >= MAKE_VERSION(13, 1, 0))
case CQI_ReportModeAperiodic_rm10_v1310:
AssertFatal(tmode == 1 || tmode == 2 || tmode == 3
|| tmode == 7,
"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm10\n",
tmode);
AssertFatal(1 == 0, "CQI_ReportModeAperiodic_rm10 to be done\n");
break;
case CQI_ReportModeAperiodic_rm11_v1310:
AssertFatal(tmode == 4 || tmode == 5 || tmode == 6 || tmode == 8
|| tmode == 9
|| tmode == 10,
"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm11\n",
tmode);
AssertFatal(1 == 0, "CQI_ReportModeAperiodic_rm11 to be done\n");
break;
#endif /* #if (RRC_VERSION >= MAKE_VERSION(13, 1, 0)) */
}
}
void
cqi_indication(module_id_t mod_idP, int CC_idP, frame_t frameP,
sub_frame_t subframeP, rnti_t rntiP,
nfapi_cqi_indication_rel9_t * rel9, uint8_t * pdu,
nfapi_ul_cqi_information_t * ul_cqi_information)
{
int UE_id = find_UE_id(mod_idP, rntiP);
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
if (UE_id == -1) {
LOG_W(MAC, "cqi_indication: UE %x not found\n", rntiP);
return;
}
UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
if (UE_id >= 0) {
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);
}
// timing advance
sched_ctl->timing_advance = rel9->timing_advance;
sched_ctl->timing_advance_r9 = rel9->timing_advance_r9;
}
}
void
SR_indication(module_id_t mod_idP, int cc_idP, frame_t frameP,
sub_frame_t subframeP, rnti_t rntiP, uint8_t ul_cqi)
{
T(T_ENB_MAC_SCHEDULING_REQUEST, T_INT(mod_idP), T_INT(cc_idP),
T_INT(frameP), T_INT(subframeP), T_INT(rntiP));
int UE_id = find_UE_id(mod_idP, rntiP);
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
if (UE_id != -1) {
if (mac_eNB_get_rrc_status(mod_idP, UE_RNTI(mod_idP, UE_id)) <
RRC_CONNECTED)
LOG_D(MAC,
"[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d on CC_id %d\n",
mod_idP, rntiP, frameP, subframeP, UE_id, cc_idP);
#if 0
UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
/* for the moment don't use ul_cqi from SR, value is too different from harq */
sched_ctl->pucch1_snr[cc_idP] = ul_cqi;
sched_ctl->pucch1_cqi_update[cc_idP] = 1;
#endif
UE_list->UE_template[cc_idP][UE_id].ul_SR = 1;
UE_list->UE_template[cc_idP][UE_id].ul_active = TRUE;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME
(VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION, 1);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME
(VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION, 0);
} else {
// AssertFatal(0, "find_UE_id(%u,rnti %d) not found", enb_mod_idP, rntiP);
// AssertError(0, 0, "Frame %d: find_UE_id(%u,rnti %d) not found\n", frameP, enb_mod_idP, rntiP);
LOG_D(MAC,
"[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d (unknown UEid) on CC_id %d\n",
mod_idP, rntiP, frameP, subframeP, UE_id, cc_idP);
}
}
void
UL_failure_indication(module_id_t mod_idP, int cc_idP, frame_t frameP,
rnti_t rntiP, sub_frame_t subframeP)
{
int UE_id = find_UE_id(mod_idP, rntiP);
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
if (UE_id != -1) {
LOG_D(MAC,
"[eNB %d][UE %d/%x] Frame %d subframeP %d Signaling UL Failure for UE %d on CC_id %d (timer %d)\n",
mod_idP, UE_id, rntiP, frameP, subframeP, UE_id, cc_idP,
UE_list->UE_sched_ctrl[UE_id].ul_failure_timer);
if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer == 0)
UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 1;
} else {
// AssertFatal(0, "find_UE_id(%u,rnti %d) not found", enb_mod_idP, rntiP);
// AssertError(0, 0, "Frame %d: find_UE_id(%u,rnti %d) not found\n", frameP, enb_mod_idP, rntiP);
LOG_W(MAC,
"[eNB %d][SR %x] Frame %d subframeP %d Signaling UL Failure for UE %d (unknown UEid) on CC_id %d\n",
mod_idP, rntiP, frameP, subframeP, UE_id, cc_idP);
}
}
static int nack_or_dtx_reported(
COMMON_channels_t *cc,
nfapi_harq_indication_pdu_t *harq_pdu)
{
int i;
if (cc->tdd_Config) {
AssertFatal(0==1, "TDD to be done. FAPI structures (see nfapi_harq_indication_tdd_rel13_t) are not clean. To be cleaned as well?\n");
abort();
} else {
nfapi_harq_indication_fdd_rel13_t *hi = &harq_pdu->harq_indication_fdd_rel13;
for (i = 0; i < hi->number_of_ack_nack; hi++)
if (hi->harq_tb_n[i] != 1)
return 1;
return 0;
}
}
void
harq_indication(module_id_t mod_idP, int CC_idP, frame_t frameP,
sub_frame_t subframeP,
nfapi_harq_indication_pdu_t * harq_pdu)
{
rnti_t rnti = harq_pdu->rx_ue_information.rnti;
uint8_t ul_cqi = harq_pdu->ul_cqi_information.ul_cqi;
uint8_t channel = harq_pdu->ul_cqi_information.channel;
int UE_id = find_UE_id(mod_idP, rnti);
if (UE_id == -1) {
LOG_W(MAC, "harq_indication: UE %x not found\n", rnti);
return;
}
UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list;
UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP];
// extract HARQ Information
LOG_D(MAC,
"Frame %d, subframe %d: Received harq indication (%d) from UE %d/%x, ul_cqi %d\n",
frameP, subframeP, channel, UE_id, rnti, ul_cqi);
if (cc->tdd_Config)
extract_harq(mod_idP, CC_idP, UE_id, frameP, subframeP,
(void *) &harq_pdu->harq_indication_tdd_rel13,
channel);
else
extract_harq(mod_idP, CC_idP, UE_id, frameP, subframeP,
(void *) &harq_pdu->harq_indication_fdd_rel13,
channel);
/* don't care about cqi reporting if NACK/DTX is there */
if (channel == 0 && !nack_or_dtx_reported(cc, harq_pdu)) {
sched_ctl->pucch1_snr[CC_idP] = ul_cqi;
sched_ctl->pucch1_cqi_update[CC_idP] = 1;
}
}
// Flexran Slicing functions
uint16_t flexran_nb_rbs_allowed_slice(float rb_percentage, int total_rbs)
{
return (uint16_t) floor(rb_percentage * total_rbs);
}
int ue_slice_membership(int UE_id, int slice_id)
{
if ((slice_id < 0) || (slice_id > n_active_slices))
LOG_W(MAC, "out of range slice id %d\n", slice_id);
if ((UE_id % n_active_slices) == slice_id) {
return 1; // this ue is a member of this slice
}
return 0;
}