gNB_scheduler_primitives.c 131 KB
Newer Older
WEI-TAI CHEN's avatar
WEI-TAI CHEN committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * 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
 */

WEI-TAI CHEN's avatar
WEI-TAI CHEN committed
22 23
/*! \file gNB_scheduler_primitives.c
 * \brief primitives used by gNB for BCH, RACH, ULSCH, DLSCH scheduling
24 25 26
 * \author  Raymond Knopp, Guy De Souza
 * \date 2018, 2019
 * \email: knopp@eurecom.fr, desouza@eurecom.fr
WEI-TAI CHEN's avatar
WEI-TAI CHEN committed
27
 * \version 1.0
28
 * \company Eurecom
WEI-TAI CHEN's avatar
WEI-TAI CHEN committed
29 30 31 32
 * @ingroup _mac

 */

luis_pereira87's avatar
luis_pereira87 committed
33
#include <softmodem-common.h>
WEI-TAI CHEN's avatar
WEI-TAI CHEN committed
34 35
#include "assertions.h"

36 37
#include "NR_MAC_gNB/nr_mac_gNB.h"
#include "NR_MAC_COMMON/nr_mac_extern.h"
WEI-TAI CHEN's avatar
WEI-TAI CHEN committed
38

39
#include "NR_MAC_gNB/mac_proto.h"
Raymond Knopp's avatar
Raymond Knopp committed
40 41
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
42
#include "common/utils/nr/nr_common.h"
WEI-TAI CHEN's avatar
WEI-TAI CHEN committed
43
#include "UTIL/OPT/opt.h"
WEI-TAI CHEN's avatar
WEI-TAI CHEN committed
44

45 46
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"

47
#include "RRC/NR/MESSAGES/asn1_msg.h"
WEI-TAI CHEN's avatar
WEI-TAI CHEN committed
48 49 50 51

#include "intertask_interface.h"

#include "T.h"
52

53 54 55
#include "uper_encoder.h"
#include "uper_decoder.h"

WEI-TAI CHEN's avatar
WEI-TAI CHEN committed
56
#define ENABLE_MAC_PAYLOAD_DEBUG
WEI-TAI CHEN's avatar
WEI-TAI CHEN committed
57
#define DEBUG_gNB_SCHEDULER 1
WEI-TAI CHEN's avatar
WEI-TAI CHEN committed
58 59 60

#include "common/ran_context.h"

61 62
//#define DEBUG_DCI

WEI-TAI CHEN's avatar
WEI-TAI CHEN committed
63 64
extern RAN_CONTEXT_t RC;

65
// CQI TABLES (10 times the value in 214 to adequately compare with R)
francescomani's avatar
francescomani committed
66
// Table 1 (38.214 5.2.2.1-2)
laurent's avatar
laurent committed
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
static const uint16_t cqi_table1[16][2] = {{0, 0},
                                           {2, 780},
                                           {2, 1200},
                                           {2, 1930},
                                           {2, 3080},
                                           {2, 4490},
                                           {2, 6020},
                                           {4, 3780},
                                           {4, 4900},
                                           {4, 6160},
                                           {6, 4660},
                                           {6, 5670},
                                           {6, 6660},
                                           {6, 7720},
                                           {6, 8730},
                                           {6, 9480}};
francescomani's avatar
francescomani committed
83 84

// Table 2 (38.214 5.2.2.1-3)
laurent's avatar
laurent committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
static const uint16_t cqi_table2[16][2] = {{0, 0},
                                           {2, 780},
                                           {2, 1930},
                                           {2, 4490},
                                           {4, 3780},
                                           {4, 4900},
                                           {4, 6160},
                                           {6, 4660},
                                           {6, 5670},
                                           {6, 6660},
                                           {6, 7720},
                                           {6, 8730},
                                           {8, 7110},
                                           {8, 7970},
                                           {8, 8850},
                                           {8, 9480}};
francescomani's avatar
francescomani committed
101 102

// Table 2 (38.214 5.2.2.1-4)
laurent's avatar
laurent committed
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
static const uint16_t cqi_table3[16][2] = {{0, 0},
                                           {2, 300},
                                           {2, 500},
                                           {2, 780},
                                           {2, 1200},
                                           {2, 1930},
                                           {2, 3080},
                                           {2, 4490},
                                           {2, 6020},
                                           {4, 3780},
                                           {4, 4900},
                                           {4, 6160},
                                           {6, 4660},
                                           {6, 5670},
                                           {6, 6660},
                                           {6, 7720}};
francescomani's avatar
francescomani committed
119

francescomani's avatar
francescomani committed
120 121
uint8_t get_dl_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl,
                          const nr_dci_format_t dci_format) {
122

123
  // TODO check this but it should be enough for now
francescomani's avatar
francescomani committed
124 125 126 127 128
  // if there is not csi report activated RI is 0 from initialization
  if(dci_format == NR_DL_DCI_FORMAT_1_0)
    return 1;
  else
    return (sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.ri + 1);
129 130 131

}

francescomani's avatar
francescomani committed
132
uint16_t get_pm_index(const NR_UE_info_t *UE,
133
                      int layers,
134 135 136 137
                      int xp_pdsch_antenna_ports) {

  if (layers == 1) return 0;

francescomani's avatar
francescomani committed
138
  const NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
139 140 141 142 143
  const int report_id = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id;
  const nr_csi_report_t *csi_report = &UE->csi_report_template[report_id];
  const int N1 = csi_report->N1;
  const int N2 = csi_report->N2;
  const int antenna_ports = (N1*N2)<<1;
144

145 146 147
  if (xp_pdsch_antenna_ports == 1 &&
      antenna_ports>1)
    return 0; //identity matrix (basic 5G configuration handled by PMI report is with XP antennas)
148

149 150
  const int x1 = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1;
  const int x2 = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2;
151
  LOG_D(NR_MAC,"PMI report: x1 %d x2 %d\n",x1,x2);
152 153 154 155 156 157 158

  if (antenna_ports == 2)
    return x2;
  else
    AssertFatal(1==0,"More than 2 antenna ports not yet supported\n");
}

159 160 161 162 163 164
uint8_t get_mcs_from_cqi(int mcs_table, int cqi_table, int cqi_idx)
{
  if (cqi_idx <= 0) {
    LOG_E(NR_MAC, "invalid cqi_idx %d, default to MCS 9\n", cqi_idx);
    return 9;
  }
165

166 167 168
  if (mcs_table != cqi_table) {
    LOG_E(NR_MAC, "indices of CQI (%d) and MCS (%d) tables don't correspond yet\n", cqi_table, mcs_table);
    return 9;
francescomani's avatar
francescomani committed
169
  }
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

  uint16_t target_coderate, target_qm;
  switch (cqi_table) {
    case 0:
      target_qm = cqi_table1[cqi_idx][0];
      target_coderate = cqi_table1[cqi_idx][1];
      break;
    case 1:
      target_qm = cqi_table2[cqi_idx][0];
      target_coderate = cqi_table2[cqi_idx][1];
      break;
    case 2:
      target_qm = cqi_table3[cqi_idx][0];
      target_coderate = cqi_table3[cqi_idx][1];
      break;
    default:
      AssertFatal(1==0,"Invalid cqi table index %d\n",cqi_table);
francescomani's avatar
francescomani committed
187
  }
188 189 190 191 192 193
  const int max_mcs = mcs_table == 1 ? 27 : 28;
  for (int i = 0; i <= max_mcs; i++) {
    const int R = nr_get_code_rate_dl(i, mcs_table);
    const int Qm = nr_get_Qm_dl(i, mcs_table);
    if (Qm == target_qm && target_coderate <= R)
      return i;
francescomani's avatar
francescomani committed
194
  }
195 196 197

  LOG_E(NR_MAC, "could not find maximum MCS from cqi_idx %d, default to 9\n", cqi_idx);
  return 9;
francescomani's avatar
francescomani committed
198 199
}

francescomani's avatar
francescomani committed
200 201 202 203
NR_pdsch_dmrs_t get_dl_dmrs_params(const NR_ServingCellConfigCommon_t *scc,
                                   const NR_UE_DL_BWP_t *dl_bwp,
                                   const NR_tda_info_t *tda_info,
                                   const int Layers) {
francescomani's avatar
francescomani committed
204

francescomani's avatar
francescomani committed
205
  NR_pdsch_dmrs_t dmrs = {0};
francescomani's avatar
francescomani committed
206 207 208
  int frontloaded_symb = 1; // default value
  nr_dci_format_t dci_format = dl_bwp ? dl_bwp->dci_format : NR_DL_DCI_FORMAT_1_0;
  if (dci_format == NR_DL_DCI_FORMAT_1_0) {
francescomani's avatar
francescomani committed
209 210
    dmrs.numDmrsCdmGrpsNoData = tda_info->nrOfSymbols == 2 ? 1 : 2;
    dmrs.dmrs_ports_id = 0;
francescomani's avatar
francescomani committed
211 212 213 214 215 216 217 218 219 220 221 222
  }
  else {
    //TODO first basic implementation of dmrs port selection
    //     only vaild for a single codeword
    //     for now it assumes a selection of Nl consecutive dmrs ports
    //     and a single front loaded symbol
    //     dmrs_ports_id is the index of Tables 7.3.1.2.2-1/2/3/4
    //     number of front loaded symbols need to be consistent with maxLength
    //     when a more complete implementation is done

    switch (Layers) {
      case 1:
francescomani's avatar
francescomani committed
223 224
        dmrs.dmrs_ports_id = 0;
        dmrs.numDmrsCdmGrpsNoData = 1;
francescomani's avatar
francescomani committed
225 226 227
        frontloaded_symb = 1;
        break;
      case 2:
francescomani's avatar
francescomani committed
228 229
        dmrs.dmrs_ports_id = 2;
        dmrs.numDmrsCdmGrpsNoData = 1;
francescomani's avatar
francescomani committed
230 231 232
        frontloaded_symb = 1;
        break;
      case 3:
francescomani's avatar
francescomani committed
233 234
        dmrs.dmrs_ports_id = 9;
        dmrs.numDmrsCdmGrpsNoData = 2;
francescomani's avatar
francescomani committed
235 236 237
        frontloaded_symb = 1;
        break;
      case 4:
francescomani's avatar
francescomani committed
238 239
        dmrs.dmrs_ports_id = 10;
        dmrs.numDmrsCdmGrpsNoData = 2;
francescomani's avatar
francescomani committed
240 241 242 243 244 245
        frontloaded_symb = 1;
        break;
      default:
        AssertFatal(1==0,"Number of layers %d\n not supported or not valid\n",Layers);
    }
  }
246

francescomani's avatar
francescomani committed
247 248
  NR_PDSCH_Config_t *pdsch_Config = dl_bwp ? dl_bwp->pdsch_Config : NULL;
  if (pdsch_Config) {
francescomani's avatar
francescomani committed
249 250
    if (tda_info->mapping_type == typeB)
      dmrs.dmrsConfigType = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->dmrs_Type != NULL;
francescomani's avatar
francescomani committed
251
    else
francescomani's avatar
francescomani committed
252
      dmrs.dmrsConfigType = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type != NULL;
253
  }
francescomani's avatar
francescomani committed
254
  else
francescomani's avatar
francescomani committed
255
    dmrs.dmrsConfigType = NFAPI_NR_DMRS_TYPE1;
francescomani's avatar
francescomani committed
256

francescomani's avatar
francescomani committed
257
  dmrs.N_PRB_DMRS = dmrs.numDmrsCdmGrpsNoData * (dmrs.dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6 : 4);
258
  dmrs.dl_dmrs_symb_pos = fill_dmrs_mask(pdsch_Config, dci_format, scc->dmrs_TypeA_Position, tda_info->nrOfSymbols, tda_info->startSymbolIndex, tda_info->mapping_type, frontloaded_symb);
francescomani's avatar
francescomani committed
259 260 261
  dmrs.N_DMRS_SLOT = get_num_dmrs(dmrs.dl_dmrs_symb_pos);
  LOG_D(NR_MAC,"Filling dmrs info, ps->N_PRB_DMRS %d, ps->dl_dmrs_symb_pos %x, ps->N_DMRS_SLOT %d\n",dmrs.N_PRB_DMRS,dmrs.dl_dmrs_symb_pos,dmrs.N_DMRS_SLOT);
  return dmrs;
262 263
}

264
NR_ControlResourceSet_t *get_coreset(gNB_MAC_INST *nrmac,
265
                                     NR_ServingCellConfigCommon_t *scc,
Eurecom's avatar
Eurecom committed
266
                                     void *bwp,
267
                                     NR_SearchSpace_t *ss,
268
                                     NR_SearchSpace__searchSpaceType_PR ss_type) {
269

270
  NR_ControlResourceSetId_t coreset_id = *ss->controlResourceSetId;
271

272
  if (ss_type == NR_SearchSpace__searchSpaceType_PR_common) { // common search space
273
    NR_ControlResourceSet_t *coreset;
274
    if(coreset_id == 0) {
Laurent THOMAS's avatar
Laurent THOMAS committed
275
      coreset =  nrmac->sched_ctrlCommon->coreset; // this is coreset 0
276 277 278
    } else if (bwp) {
      coreset = ((NR_BWP_Downlink_t*)bwp)->bwp_Common->pdcch_ConfigCommon->choice.setup->commonControlResourceSet;
    } else if (scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonControlResourceSet) {
279
      coreset = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonControlResourceSet;
280 281 282
    } else {
      coreset = NULL;
    }
283 284 285 286

    if (coreset) AssertFatal(coreset_id == coreset->controlResourceSetId,
			     "ID of common ss coreset does not correspond to id set in the "
			     "search space\n");
287 288
    return coreset;
  } else {
Eurecom's avatar
Eurecom committed
289
    const int n = ((NR_BWP_DownlinkDedicated_t*)bwp)->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.count;
290 291
    for (int i = 0; i < n; i++) {
      NR_ControlResourceSet_t *coreset =
Eurecom's avatar
Eurecom committed
292
          ((NR_BWP_DownlinkDedicated_t*)bwp)->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.array[i];
293 294 295 296 297 298 299 300
      if (coreset_id == coreset->controlResourceSetId) {
        return coreset;
      }
    }
    AssertFatal(0, "Couldn't find coreset with id %ld\n", coreset_id);
  }
}

301
NR_SearchSpace_t *get_searchspace(NR_ServingCellConfigCommon_t *scc,
302 303 304 305
                                  NR_BWP_DownlinkDedicated_t *bwp_Dedicated,
                                  NR_SearchSpace__searchSpaceType_PR target_ss) {

  int n = 0;
306
  if(bwp_Dedicated)
307
    n = bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count;
308
  else
309
    n = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList->list.count;
310

311
  for (int i=0;i<n;i++) {
312
    NR_SearchSpace_t *ss = NULL;
313
    if(bwp_Dedicated)
314
      ss = bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.array[i];
315
    else
316
      ss = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList->list.array[i];
317 318 319 320 321 322
    AssertFatal(ss->controlResourceSetId != NULL, "ss->controlResourceSetId is null\n");
    AssertFatal(ss->searchSpaceType != NULL, "ss->searchSpaceType is null\n");
    if (ss->searchSpaceType->present == target_ss) {
      return ss;
    }
  }
323
  AssertFatal(0, "Couldn't find an adequate searchspace bwp_Dedicated %p\n",bwp_Dedicated);
324 325
}

326 327 328 329 330 331
NR_sched_pdcch_t set_pdcch_structure(gNB_MAC_INST *gNB_mac,
                                     NR_SearchSpace_t *ss,
                                     NR_ControlResourceSet_t *coreset,
                                     NR_ServingCellConfigCommon_t *scc,
                                     NR_BWP_t *bwp,
                                     NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config) {
332

333
  int sps;
334
  NR_sched_pdcch_t pdcch;
rmagueta's avatar
rmagueta committed
335

336 337 338
  AssertFatal(*ss->controlResourceSetId == coreset->controlResourceSetId,
              "coreset id in SS %ld does not correspond to the one in coreset %ld",
              *ss->controlResourceSetId, coreset->controlResourceSetId);
339

340 341
  if (bwp) { // This is not for SIB1
    if(coreset->controlResourceSetId == 0){
342 343
      pdcch.BWPSize  = gNB_mac->cset0_bwp_size;
      pdcch.BWPStart = gNB_mac->cset0_bwp_start;
344 345
    }
    else {
346 347
      pdcch.BWPSize  = NRRIV2BW(bwp->locationAndBandwidth, MAX_BWP_SIZE);
      pdcch.BWPStart = NRRIV2PRBOFFSET(bwp->locationAndBandwidth, MAX_BWP_SIZE);
348
    }
349 350
    pdcch.SubcarrierSpacing = bwp->subcarrierSpacing;
    pdcch.CyclicPrefix = (bwp->cyclicPrefix==NULL) ? 0 : *bwp->cyclicPrefix;
351

352 353 354 355 356
    //AssertFatal(pdcch_scs==kHz15, "PDCCH SCS above 15kHz not allowed if a symbol above 2 is monitored");
    sps = bwp->cyclicPrefix == NULL ? 14 : 12;
  }
  else {
    AssertFatal(type0_PDCCH_CSS_config!=NULL,"type0_PDCCH_CSS_config is null,bwp %p\n",bwp);
357 358 359 360
    pdcch.BWPSize = type0_PDCCH_CSS_config->num_rbs;
    pdcch.BWPStart = type0_PDCCH_CSS_config->cset_start_rb;
    pdcch.SubcarrierSpacing = type0_PDCCH_CSS_config->scs_pdcch;
    pdcch.CyclicPrefix = 0;
361
    sps = 14;
rmagueta's avatar
rmagueta committed
362
  }
363

364 365
  AssertFatal(ss->monitoringSymbolsWithinSlot!=NULL,"ss->monitoringSymbolsWithinSlot is null\n");
  AssertFatal(ss->monitoringSymbolsWithinSlot->buf!=NULL,"ss->monitoringSymbolsWithinSlot->buf is null\n");
366

367 368 369
  // for SPS=14 8 MSBs in positions 13 downto 6
  uint16_t monitoringSymbolsWithinSlot = (ss->monitoringSymbolsWithinSlot->buf[0]<<(sps-8)) |
                                         (ss->monitoringSymbolsWithinSlot->buf[1]>>(16-sps));
370

371 372
  for (int i=0; i<sps; i++) {
    if ((monitoringSymbolsWithinSlot>>(sps-1-i))&1) {
373
      pdcch.StartSymbolIndex=i;
374
      break;
375
    }
376
  }
377

378
  pdcch.DurationSymbols = coreset->duration;
379

380
  //cce-REG-MappingType
381
  pdcch.CceRegMappingType = coreset->cce_REG_MappingType.present == NR_ControlResourceSet__cce_REG_MappingType_PR_interleaved?
382
    NFAPI_NR_CCE_REG_MAPPING_INTERLEAVED : NFAPI_NR_CCE_REG_MAPPING_NON_INTERLEAVED;
383

384 385
  if (pdcch.CceRegMappingType == NFAPI_NR_CCE_REG_MAPPING_INTERLEAVED) {
    pdcch.RegBundleSize = (coreset->cce_REG_MappingType.choice.interleaved->reg_BundleSize ==
386
                                NR_ControlResourceSet__cce_REG_MappingType__interleaved__reg_BundleSize_n6) ? 6 : (2+coreset->cce_REG_MappingType.choice.interleaved->reg_BundleSize);
387
    pdcch.InterleaverSize = (coreset->cce_REG_MappingType.choice.interleaved->interleaverSize ==
388 389
                                  NR_ControlResourceSet__cce_REG_MappingType__interleaved__interleaverSize_n6) ? 6 : (2+coreset->cce_REG_MappingType.choice.interleaved->interleaverSize);
    AssertFatal(scc->physCellId != NULL,"scc->physCellId is null\n");
390
    pdcch.ShiftIndex = coreset->cce_REG_MappingType.choice.interleaved->shiftIndex != NULL ? *coreset->cce_REG_MappingType.choice.interleaved->shiftIndex : *scc->physCellId;
391 392
  }
  else {
393 394 395
    pdcch.RegBundleSize = 6;
    pdcch.InterleaverSize = 0;
    pdcch.ShiftIndex = 0;
396
  }
397

398 399 400 401 402 403
  int N_rb = 0; // nb of rbs of coreset per symbol
  for (int i=0;i<6;i++) {
    for (int t=0;t<8;t++) {
      N_rb+=((coreset->frequencyDomainResources.buf[i]>>t)&1);
    }
  }
404
  pdcch.n_rb = N_rb*=6; // each bit of frequencyDomainResources represents 6 PRBs
405

406 407
  return pdcch;
}
408

409
int find_pdcch_candidate(const gNB_MAC_INST *mac,
410 411 412
                         int cc_id,
                         int aggregation,
                         int nr_of_candidates,
413 414
                         const NR_sched_pdcch_t *pdcch,
                         const NR_ControlResourceSet_t *coreset,
415 416
                         uint32_t Y)
{
417
  const uint16_t *vrb_map = mac->common_channels[cc_id].vrb_map;
418
  const int N_ci = 0;
419

420 421
  const int N_rb = pdcch->n_rb;  // nb of rbs of coreset per symbol
  const int N_symb = coreset->duration; // nb of coreset symbols
422
  const int N_regs = N_rb * N_symb; // nb of REGs per coreset
423 424 425
  const int N_cces = N_regs / NR_NB_REG_PER_CCE; // nb of cces in coreset
  const int R = pdcch->InterleaverSize;
  const int L = pdcch->RegBundleSize;
426 427
  const int C = R > 0 ? N_regs / (L * R) : 0;
  const int B_rb = L / N_symb; // nb of RBs occupied by each REG bundle
428 429

  // loop over all the available candidates
430
  // this implements TS 38.211 Sec. 7.3.2.2
431
  for(int m = 0; m < nr_of_candidates; m++) { // loop over candidates
432
    bool taken = false; // flag if the resource for a given candidate are taken
433
    int first_cce = aggregation * ((Y + ((m * N_cces) / (aggregation * nr_of_candidates)) + N_ci) % (N_cces / aggregation));
434
    LOG_D(NR_MAC,"Candidate %d of %d first_cce %d (L %d N_cces %d Y %d)\n", m, nr_of_candidates, first_cce, aggregation, N_cces, Y);
435 436
    for (int j = first_cce; (j < first_cce + aggregation) && !taken; j++) { // loop over CCEs
      for (int k = 6 * j / L; (k < (6 * j / L + 6 / L)) && !taken; k++) { // loop over REG bundles
437
        int f = cce_to_reg_interleaving(R, k, pdcch->ShiftIndex, C, L, N_regs);
438 439
        for(int rb = 0; rb < B_rb; rb++) { // loop over the RBs of the bundle
          if(vrb_map[pdcch->BWPStart + f * B_rb + rb] & SL_to_bitmap(pdcch->StartSymbolIndex,N_symb)) {
440 441 442 443 444 445
            taken = true;
            break;
          }
        }
      }
    }
446
    if(!taken)
447 448 449 450
      return first_cce;
  }
  return -1;
}
451

452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484

int get_cce_index(const gNB_MAC_INST *nrmac,
                  const int CC_id,
                  const int slot,
                  const rnti_t rnti,
                  uint8_t *aggregation_level,
                  const NR_SearchSpace_t *ss,
                  const NR_ControlResourceSet_t *coreset,
                  NR_sched_pdcch_t *sched_pdcch,
                  bool is_common)
{

  const uint32_t Y = is_common ? 0 : get_Y(ss, slot, rnti);
  uint8_t nr_of_candidates;
  for (int i=0; i<5; i++) {
    // for now taking the lowest value among the available aggregation levels
    find_aggregation_candidates(aggregation_level,
                                &nr_of_candidates,
                                ss,
                                1<<i);
    if(nr_of_candidates>0)
      break;
  }
  int CCEIndex = find_pdcch_candidate(nrmac,
                                      CC_id,
                                      *aggregation_level,
                                      nr_of_candidates,
                                      sched_pdcch,
                                      coreset,
                                      Y);
  return CCEIndex;
}

485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
void fill_pdcch_vrb_map(gNB_MAC_INST *mac,
                        int CC_id,
                        NR_sched_pdcch_t *pdcch,
                        int first_cce,
                        int aggregation){

  uint16_t *vrb_map = mac->common_channels[CC_id].vrb_map;

  int N_rb = pdcch->n_rb; // nb of rbs of coreset per symbol
  int L = pdcch->RegBundleSize;
  int R = pdcch->InterleaverSize;
  int n_shift = pdcch->ShiftIndex;
  int N_symb = pdcch->DurationSymbols;
  int N_regs = N_rb*N_symb; // nb of REGs per coreset
  int B_rb = L/N_symb; // nb of RBs occupied by each REG bundle
  int C = R>0 ? N_regs/(L*R) : 0;

  for (int j=first_cce; j<first_cce+aggregation; j++) { // loop over CCEs
    for (int k=6*j/L; k<(6*j/L+6/L); k++) { // loop over REG bundles
francescomani's avatar
francescomani committed
504
      int f = cce_to_reg_interleaving(R, k, n_shift, C, L, N_regs);
505
      for(int rb=0; rb<B_rb; rb++) // loop over the RBs of the bundle
506
        vrb_map[pdcch->BWPStart + f*B_rb + rb] |= SL_to_bitmap(pdcch->StartSymbolIndex, N_symb);
507 508
    }
  }
509 510
}

511
static bool multiple_2_3_5(int rb)
512 513 514 515 516 517 518 519 520 521 522
{
  while (rb % 2 == 0)
    rb /= 2;
  while (rb % 3 == 0)
    rb /= 3;
  while (rb % 5 == 0)
    rb /= 5;

  return (rb == 1);
}

523 524
bool nr_find_nb_rb(uint16_t Qm,
                   uint16_t R,
525
                   long transform_precoding,
526
                   uint8_t nrOfLayers,
527 528 529
                   uint16_t nb_symb_sch,
                   uint16_t nb_dmrs_prb,
                   uint32_t bytes,
530
                   uint16_t nb_rb_min,
531 532 533 534
                   uint16_t nb_rb_max,
                   uint32_t *tbs,
                   uint16_t *nb_rb)
{
535 536 537 538 539
  // for transform precoding only RB = 2^a_2 * 3^a_3 * 5^a_5 is allowed with a non-negative
  while(transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled &&
        !multiple_2_3_5(nb_rb_max))
    nb_rb_max--;

540 541
  /* is the maximum (not even) enough? */
  *nb_rb = nb_rb_max;
542
  *tbs = nr_compute_tbs(Qm, R, *nb_rb, nb_symb_sch, nb_dmrs_prb, 0, 0, nrOfLayers) >> 3;
543 544 545 546 547 548 549 550
  /* check whether it does not fit, or whether it exactly fits. Some algorithms
   * might depend on the return value! */
  if (bytes > *tbs)
    return false;
  if (bytes == *tbs)
    return true;

  /* is the minimum enough? */
551
  *nb_rb = nb_rb_min;
552
  *tbs = nr_compute_tbs(Qm, R, *nb_rb, nb_symb_sch, nb_dmrs_prb, 0, 0, nrOfLayers) >> 3;
553 554 555 556 557 558
  if (bytes <= *tbs)
    return true;

  /* perform binary search to allocate all bytes within a TBS up to nb_rb_max
   * RBs */
  int hi = nb_rb_max;
559
  int lo = nb_rb_min;
560
  for (int p = (hi + lo) / 2; lo + 1 < hi; p = (hi + lo) / 2) {
561 562 563 564
    // for transform precoding only RB = 2^a_2 * 3^a_3 * 5^a_5 is allowed with a non-negative
    while(transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled &&
          !multiple_2_3_5(p))
      p++;
francescomani's avatar
francescomani committed
565 566 567 568 569

    // If by increasing p for transform precoding we already hit the high, break to avoid infinite loop
    if (p == hi)
      break;

570
    const uint32_t TBS = nr_compute_tbs(Qm, R, p, nb_symb_sch, nb_dmrs_prb, 0, 0, nrOfLayers) >> 3;
571 572 573 574 575 576 577 578 579 580
    if (bytes == TBS) {
      hi = p;
      break;
    } else if (bytes < TBS) {
      hi = p;
    } else {
      lo = p;
    }
  }
  *nb_rb = hi;
581
  *tbs = nr_compute_tbs(Qm, R, *nb_rb, nb_symb_sch, nb_dmrs_prb, 0, 0, nrOfLayers) >> 3;
582 583 584 585
  /* return whether we could allocate all bytes and stay below nb_rb_max */
  return *tbs >= bytes && *nb_rb <= nb_rb_max;
}

francescomani's avatar
francescomani committed
586 587 588 589
NR_pusch_dmrs_t get_ul_dmrs_params(const NR_ServingCellConfigCommon_t *scc,
                                   const NR_UE_UL_BWP_t *ul_bwp,
                                   const NR_tda_info_t *tda_info,
                                   const int Layers) {
590

francescomani's avatar
francescomani committed
591
  NR_pusch_dmrs_t dmrs = {0};
francescomani's avatar
francescomani committed
592
  // TODO setting of cdm groups with no data to be redone for MIMO
593
  if (ul_bwp->transform_precoding && Layers < 3)
francescomani's avatar
francescomani committed
594
    dmrs.num_dmrs_cdm_grps_no_data = ul_bwp->dci_format == NR_UL_DCI_FORMAT_0_1 || tda_info->nrOfSymbols == 2 ? 1 : 2;
francescomani's avatar
francescomani committed
595
  else
francescomani's avatar
francescomani committed
596
    dmrs.num_dmrs_cdm_grps_no_data = 2;
597

francescomani's avatar
francescomani committed
598
  NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = ul_bwp->pusch_Config ?
francescomani's avatar
francescomani committed
599 600 601
                                                 (tda_info->mapping_type == typeA ?
                                                 ul_bwp->pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup :
                                                 ul_bwp->pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup) : NULL;
francescomani's avatar
francescomani committed
602

francescomani's avatar
francescomani committed
603
  dmrs.dmrs_config_type = NR_DMRS_UplinkConfig && NR_DMRS_UplinkConfig->dmrs_Type ? 1 : 0;
francescomani's avatar
francescomani committed
604

francescomani's avatar
francescomani committed
605 606
  const pusch_dmrs_AdditionalPosition_t additional_pos = (NR_DMRS_UplinkConfig && NR_DMRS_UplinkConfig->dmrs_AdditionalPosition) ?
                                                         (*NR_DMRS_UplinkConfig->dmrs_AdditionalPosition ==
francescomani's avatar
francescomani committed
607
                                                         NR_DMRS_UplinkConfig__dmrs_AdditionalPosition_pos3 ?
francescomani's avatar
francescomani committed
608
                                                         3 : *NR_DMRS_UplinkConfig->dmrs_AdditionalPosition) : 2;
francescomani's avatar
francescomani committed
609 610

  const pusch_maxLength_t pusch_maxLength = NR_DMRS_UplinkConfig ? (NR_DMRS_UplinkConfig->maxLength == NULL ? 1 : 2) : 1;
francescomani's avatar
francescomani committed
611
  dmrs.ul_dmrs_symb_pos = get_l_prime(tda_info->nrOfSymbols,
francescomani's avatar
francescomani committed
612 613 614 615 616 617
                                       tda_info->mapping_type,
                                       additional_pos,
                                       pusch_maxLength,
                                       tda_info->startSymbolIndex,
                                       scc->dmrs_TypeA_Position);

618
  uint8_t num_dmrs_symb = 0;
francescomani's avatar
francescomani committed
619
  for(int i = tda_info->startSymbolIndex; i < tda_info->startSymbolIndex + tda_info->nrOfSymbols; i++)
francescomani's avatar
francescomani committed
620 621 622
    num_dmrs_symb += (dmrs.ul_dmrs_symb_pos >> i) & 1;
  dmrs.num_dmrs_symb = num_dmrs_symb;
  dmrs.N_PRB_DMRS = dmrs.num_dmrs_cdm_grps_no_data * (dmrs.dmrs_config_type == 0 ? 6 : 4);
francescomani's avatar
francescomani committed
623

francescomani's avatar
francescomani committed
624 625
  dmrs.NR_DMRS_UplinkConfig = NR_DMRS_UplinkConfig;
  return dmrs;
626 627
}

628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
#define BLER_UPDATE_FRAME 10
#define BLER_FILTER 0.9f
int get_mcs_from_bler(const NR_bler_options_t *bler_options,
                      const NR_mac_dir_stats_t *stats,
                      NR_bler_stats_t *bler_stats,
                      int max_mcs,
                      frame_t frame)
{
  /* first call: everything is zero. Initialize to sensible default */
  if (bler_stats->last_frame == 0 && bler_stats->mcs == 0) {
    bler_stats->last_frame = frame;
    bler_stats->mcs = 9;
    bler_stats->bler = (bler_options->lower + bler_options->upper) / 2.0f;
  }
  int diff = frame - bler_stats->last_frame;
  if (diff < 0) // wrap around
    diff += 1024;

  max_mcs = min(max_mcs, bler_options->max_mcs);
  const uint8_t old_mcs = min(bler_stats->mcs, max_mcs);
  if (diff < BLER_UPDATE_FRAME)
    return old_mcs; // no update

  // last update is longer than x frames ago
  const int dtx = (int)(stats->rounds[0] - bler_stats->rounds[0]);
  const int dretx = (int)(stats->rounds[1] - bler_stats->rounds[1]);
  const float bler_window = dtx > 0 ? (float) dretx / dtx : bler_stats->bler;
  bler_stats->bler = BLER_FILTER * bler_stats->bler + (1 - BLER_FILTER) * bler_window;

  int new_mcs = old_mcs;
  if (bler_stats->bler < bler_options->lower && old_mcs < max_mcs && dtx > 9)
    new_mcs += 1;
  else if ((bler_stats->bler > bler_options->upper && old_mcs > 6) // above threshold
      || (dtx <= 3 && old_mcs > 9))                                // no activity
    new_mcs -= 1;
  // else we are within threshold boundaries

  bler_stats->last_frame = frame;
  bler_stats->mcs = new_mcs;
  memcpy(bler_stats->rounds, stats->rounds, sizeof(stats->rounds));
  LOG_D(MAC, "frame %4d MCS %d -> %d (dtx %d, dretx %d, BLER wnd %.3f avg %.6f)\n",
        frame, old_mcs, new_mcs, dtx, dretx, bler_window, bler_stats->bler);
  return new_mcs;
}

673
void config_uldci(const NR_SIB1_t *sib1,
674
                  const NR_ServingCellConfigCommon_t *scc,
675
                  const nfapi_nr_pusch_pdu_t *pusch_pdu,
676
                  dci_pdu_rel15_t *dci_pdu_rel15,
677
                  nr_srs_feedback_t *srs_feedback,
678 679
                  int time_domain_assignment,
                  uint8_t tpc,
680
                  uint8_t ndi,
francescomani's avatar
francescomani committed
681
                  NR_UE_UL_BWP_t *ul_bwp) {
682

francescomani's avatar
francescomani committed
683 684
  int bwp_id = ul_bwp->bwp_id;
  nr_dci_format_t dci_format = ul_bwp->dci_format;
685

Robert Schmidt's avatar
Robert Schmidt committed
686
  dci_pdu_rel15->frequency_domain_assignment.val =
francescomani's avatar
francescomani committed
687
      PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size, pusch_pdu->rb_start, ul_bwp->BWPSize);
Robert Schmidt's avatar
Robert Schmidt committed
688 689 690
  dci_pdu_rel15->time_domain_assignment.val = time_domain_assignment;
  dci_pdu_rel15->frequency_hopping_flag.val = pusch_pdu->frequency_hopping;
  dci_pdu_rel15->mcs = pusch_pdu->mcs_index;
691
  dci_pdu_rel15->ndi = ndi;
Robert Schmidt's avatar
Robert Schmidt committed
692 693 694
  dci_pdu_rel15->rv = pusch_pdu->pusch_data.rv_index;
  dci_pdu_rel15->harq_pid = pusch_pdu->pusch_data.harq_process_id;
  dci_pdu_rel15->tpc = tpc;
francescomani's avatar
francescomani committed
695
  NR_PUSCH_Config_t *pusch_Config = ul_bwp->pusch_Config;
Eurecom's avatar
Eurecom committed
696

697
  if (pusch_Config) AssertFatal(pusch_Config->resourceAllocation == NR_PUSCH_Config__resourceAllocation_resourceAllocationType1,
698
			"Only frequency resource allocation type 1 is currently supported\n");
699
  switch (dci_format) {
700 701 702 703
    case NR_UL_DCI_FORMAT_0_0:
      dci_pdu_rel15->format_indicator = 0;
      break;
    case NR_UL_DCI_FORMAT_0_1:
704
      LOG_D(NR_MAC,"Configuring DCI Format 0_1\n");
705
      dci_pdu_rel15->dai[0].val = 0; //TODO
Robert Schmidt's avatar
Robert Schmidt committed
706
      // bwp indicator as per table 7.3.1.1.2-1 in 38.212
francescomani's avatar
francescomani committed
707
      dci_pdu_rel15->bwp_indicator.val = ul_bwp->n_ul_bwp < 4 ? bwp_id : bwp_id - 1;
708
      // SRS resource indicator
709 710 711
      if (pusch_Config &&
          pusch_Config->txConfig != NULL) {
        AssertFatal(*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook,
712
                    "Non Codebook configuration non supported\n");
713
        compute_srs_resource_indicator(ul_bwp->pusch_servingcellconfig, pusch_Config, ul_bwp->srs_Config, srs_feedback, &dci_pdu_rel15->srs_resource_indicator.val);
714
      }
715 716
      compute_precoding_information(pusch_Config,
                                    ul_bwp->srs_Config,
717 718 719 720
                                    dci_pdu_rel15->srs_resource_indicator,
                                    srs_feedback,
                                    &pusch_pdu->nrOfLayers,
                                    &dci_pdu_rel15->precoding_information.val);
721

722
      // antenna_ports.val = 0 for transform precoder is disabled, dmrs-Type=1, maxLength=1, Rank=1/2/3/4
723
      // Antenna Ports
724 725
      dci_pdu_rel15->antenna_ports.val = 0;

726 727 728 729 730 731 732
      // DMRS sequence initialization
      dci_pdu_rel15->dmrs_sequence_initialization.val = pusch_pdu->scid;
      break;
    default :
      AssertFatal(0, "Valid UL formats are 0_0 and 0_1\n");
  }

733
  LOG_D(NR_MAC,
734
        "%s() ULDCI type 0 payload: dci_format %d, freq_alloc %d, time_alloc %d, freq_hop_flag %d, precoding_information.val %d antenna_ports.val %d mcs %d tpc %d ndi %d rv %d\n",
735
        __func__,
736
        dci_format,
737 738 739
        dci_pdu_rel15->frequency_domain_assignment.val,
        dci_pdu_rel15->time_domain_assignment.val,
        dci_pdu_rel15->frequency_hopping_flag.val,
740 741
        dci_pdu_rel15->precoding_information.val,
        dci_pdu_rel15->antenna_ports.val,
742 743 744 745 746 747
        dci_pdu_rel15->mcs,
        dci_pdu_rel15->tpc,
        dci_pdu_rel15->ndi,
        dci_pdu_rel15->rv);
}

748 749 750 751 752 753 754 755 756 757 758 759
const int default_pucch_fmt[]       = {0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1};
const int default_pucch_firstsymb[] = {12,12,12,10,10,10,10,4,4,4,4,0,0,0,0,0};
const int default_pucch_numbsymb[]  = {2,2,2,2,4,4,4,4,10,10,10,10,14,14,14,14,14};
const int default_pucch_prboffset[] = {0,0,3,0,0,2,4,0,0,2,4,0,0,2,4,-1};
const int default_pucch_csset[]     = {2,3,3,2,4,4,4,2,4,4,4,2,4,4,4,4};

int nr_get_default_pucch_res(int pucch_ResourceCommon) {

  AssertFatal(pucch_ResourceCommon>=0 && pucch_ResourceCommon < 16, "illegal pucch_ResourceCommon %d\n",pucch_ResourceCommon);

  return(default_pucch_csset[pucch_ResourceCommon]);
}
760

761 762
void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu,
                        NR_ControlResourceSet_t *coreset,
763
                        bool is_sib1,
764
                        NR_sched_pdcch_t *pdcch) {
765

766

767 768 769 770 771
  pdcch_pdu->BWPSize = pdcch->BWPSize;
  pdcch_pdu->BWPStart = pdcch->BWPStart;
  pdcch_pdu->SubcarrierSpacing = pdcch->SubcarrierSpacing;
  pdcch_pdu->CyclicPrefix = pdcch->CyclicPrefix;
  pdcch_pdu->StartSymbolIndex = pdcch->StartSymbolIndex;
772

773
  pdcch_pdu->DurationSymbols  = coreset->duration;
774

775 776
  for (int i=0;i<6;i++)
    pdcch_pdu->FreqDomainResource[i] = coreset->frequencyDomainResources.buf[i];
777

778
  LOG_D(MAC,"Coreset : BWPstart %d, BWPsize %d, SCS %d, freq %x, , duration %d\n",
779
        pdcch_pdu->BWPStart,pdcch_pdu->BWPSize,(int)pdcch_pdu->SubcarrierSpacing,(int)coreset->frequencyDomainResources.buf[0],(int)coreset->duration);
780

781 782 783 784
  pdcch_pdu->CceRegMappingType = pdcch->CceRegMappingType;
  pdcch_pdu->RegBundleSize = pdcch->RegBundleSize;
  pdcch_pdu->InterleaverSize = pdcch->InterleaverSize;
  pdcch_pdu->ShiftIndex = pdcch->ShiftIndex;
785

786
  if(coreset->controlResourceSetId == 0) {
787
    if(is_sib1)
788 789 790
      pdcch_pdu->CoreSetType = NFAPI_NR_CSET_CONFIG_MIB_SIB1;
    else
      pdcch_pdu->CoreSetType = NFAPI_NR_CSET_CONFIG_PDCCH_CONFIG_CSET_0;
791 792
  } else{
    pdcch_pdu->CoreSetType = NFAPI_NR_CSET_CONFIG_PDCCH_CONFIG;
793
  }
794 795 796

  //precoderGranularity
  pdcch_pdu->precoderGranularity = coreset->precoderGranularity;
797
}
798

799
int nr_get_pucch_resource(NR_ControlResourceSet_t *coreset,
francescomani's avatar
francescomani committed
800
                          NR_PUCCH_Config_t *pucch_Config,
801 802
                          int CCEIndex) {
  int r_pucch = -1;
francescomani's avatar
francescomani committed
803
  if(pucch_Config == NULL) {
804 805 806 807 808 809 810 811
    int n_rb,rb_offset;
    get_coreset_rballoc(coreset->frequencyDomainResources.buf,&n_rb,&rb_offset);
    const uint16_t N_cce = n_rb * coreset->duration / NR_NB_REG_PER_CCE;
    const int delta_PRI=0;
    r_pucch = ((CCEIndex<<1)/N_cce)+(delta_PRI<<1);
  }
  return r_pucch;
}
812

813
// This function configures pucch pdu fapi structure
francescomani's avatar
francescomani committed
814
void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu,
815
                        NR_ServingCellConfigCommon_t *scc,
816
                        NR_UE_info_t *UE,
817
                        uint8_t pucch_resource,
818
                        uint16_t O_csi,
819
                        uint16_t O_ack,
820
                        uint8_t O_sr,
821
                        int r_pucch) {
822 823

  NR_PUCCH_Resource_t *pucchres;
824
  NR_PUCCH_ResourceSet_t *pucchresset;
825
  NR_PUCCH_FormatConfig_t *pucchfmt;
826
  NR_PUCCH_ResourceId_t *resource_id = NULL;
francescomani's avatar
francescomani committed
827
  NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP;
828

829 830 831 832 833
  int n_list, n_set;
  uint16_t N2,N3;
  int res_found = 0;

  pucch_pdu->bit_len_harq = O_ack;
r.karey's avatar
r.karey committed
834
  pucch_pdu->bit_len_csi_part1 = O_csi;
835

836 837
  uint16_t O_uci = O_csi + O_ack;

francescomani's avatar
francescomani committed
838
  NR_PUSCH_Config_t *pusch_Config = current_BWP->pusch_Config;
839

Eurecom's avatar
Eurecom committed
840
  long *pusch_id = pusch_Config ? pusch_Config->dataScramblingIdentityPUSCH : NULL;
841

842 843 844 845
  long *id0 = NULL;
  if (pusch_Config &&
      pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA != NULL &&
      pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->transformPrecodingDisabled != NULL)
846
    id0 = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->transformPrecodingDisabled->scramblingID0;
847 848
  else if (pusch_Config && pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB != NULL &&
           pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->transformPrecodingDisabled != NULL)
849
    id0 = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->transformPrecodingDisabled->scramblingID0;
850
  else id0 = scc->physCellId;
851

francescomani's avatar
francescomani committed
852
  NR_PUCCH_ConfigCommon_t *pucch_ConfigCommon = current_BWP->pucch_ConfigCommon;
853

854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871
  // hop flags and hopping id are valid for any BWP
  switch (pucch_ConfigCommon->pucch_GroupHopping){
  case 0 :
    // if neither, both disabled
    pucch_pdu->group_hop_flag = 0;
    pucch_pdu->sequence_hop_flag = 0;
    break;
  case 1 :
    // if enable, group enabled
    pucch_pdu->group_hop_flag = 1;
    pucch_pdu->sequence_hop_flag = 0;
    break;
  case 2 :
    // if disable, sequence disabled
    pucch_pdu->group_hop_flag = 0;
    pucch_pdu->sequence_hop_flag = 1;
    break;
  default:
Eurecom's avatar
Eurecom committed
872
    AssertFatal(1==0,"Group hopping flag %ld undefined (0,1,2) \n", pucch_ConfigCommon->pucch_GroupHopping);
873
  }
874

875 876 877 878
  if (pucch_ConfigCommon->hoppingId != NULL)
    pucch_pdu->hopping_id = *pucch_ConfigCommon->hoppingId;
  else
    pucch_pdu->hopping_id = *scc->physCellId;
879

francescomani's avatar
francescomani committed
880 881 882 883
  pucch_pdu->bwp_size  = current_BWP->BWPSize;
  pucch_pdu->bwp_start = current_BWP->BWPStart;
  pucch_pdu->subcarrier_spacing = current_BWP->scs;
  pucch_pdu->cyclic_prefix = (current_BWP->cyclicprefix==NULL) ? 0 : *current_BWP->cyclicprefix;
884

francescomani's avatar
francescomani committed
885
  NR_PUCCH_Config_t *pucch_Config = current_BWP->pucch_Config;
886
  if (r_pucch<0 || pucch_Config) {
887
      LOG_D(NR_MAC,"pucch_acknak: Filling dedicated configuration for PUCCH\n");
888

889
      AssertFatal(pucch_Config->resourceSetToAddModList!=NULL,
890
		    "PUCCH resourceSetToAddModList is null\n");
891

892 893
      n_set = pucch_Config->resourceSetToAddModList->list.count;
      AssertFatal(n_set>0,"PUCCH resourceSetToAddModList is empty\n");
894

895
      LOG_D(NR_MAC, "UCI n_set= %d\n", n_set);
896

897
      N2 = 2;
898
	// procedure to select pucch resource id from resource sets according to
899 900
	// number of uci bits and pucch resource indicator pucch_resource
	// ( see table 9.2.3.2 in 38.213)
901 902 903 904 905 906 907 908 909 910
      for (int i=0; i<n_set; i++) {
	pucchresset = pucch_Config->resourceSetToAddModList->list.array[i];
	n_list = pucchresset->resourceList.list.count;
	if (pucchresset->pucch_ResourceSetId == 0 && O_uci<3) {
	  if (pucch_resource < n_list)
            resource_id = pucchresset->resourceList.list.array[pucch_resource];
          else
            AssertFatal(1==0,"Couldn't fine pucch resource indicator %d in PUCCH resource set %d for %d UCI bits",pucch_resource,i,O_uci);
        }
        if (pucchresset->pucch_ResourceSetId == 1 && O_uci>2) {
911 912 913 914 915 916 917 918
        N3 = pucchresset->maxPayloadSize!= NULL ?  *pucchresset->maxPayloadSize : 1706;
        if (N2<O_uci && N3>O_uci) {
          if (pucch_resource < n_list)
            resource_id = pucchresset->resourceList.list.array[pucch_resource];
          else
            AssertFatal(1==0,"Couldn't fine pucch resource indicator %d in PUCCH resource set %d for %d UCI bits",pucch_resource,i,O_uci);
        }
        else N2 = N3;
919
      }
920
    }
921

922 923 924 925 926 927 928 929 930 931 932 933 934 935
    AssertFatal(resource_id!=NULL,"Couldn-t find any matching PUCCH resource in the PUCCH resource sets");

    AssertFatal(pucch_Config->resourceToAddModList!=NULL,
                "PUCCH resourceToAddModList is null\n");

    n_list = pucch_Config->resourceToAddModList->list.count;
    AssertFatal(n_list>0,"PUCCH resourceToAddModList is empty\n");

    // going through the list of PUCCH resources to find the one indexed by resource_id
    for (int i=0; i<n_list; i++) {
      pucchres = pucch_Config->resourceToAddModList->list.array[i];
      if (pucchres->pucch_ResourceId == *resource_id) {
        res_found = 1;
        pucch_pdu->prb_start = pucchres->startingPRB;
936
        pucch_pdu->rnti = UE->rnti;
937 938 939 940 941 942 943 944 945 946 947
        // FIXME why there is only one frequency hopping flag
        // what about inter slot frequency hopping?
        pucch_pdu->freq_hop_flag = pucchres->intraSlotFrequencyHopping!= NULL ?  1 : 0;
        pucch_pdu->second_hop_prb = pucchres->secondHopPRB!= NULL ?  *pucchres->secondHopPRB : 0;
        switch(pucchres->format.present) {
          case NR_PUCCH_Resource__format_PR_format0 :
            pucch_pdu->format_type = 0;
            pucch_pdu->initial_cyclic_shift = pucchres->format.choice.format0->initialCyclicShift;
            pucch_pdu->nr_of_symbols = pucchres->format.choice.format0->nrofSymbols;
            pucch_pdu->start_symbol_index = pucchres->format.choice.format0->startingSymbolIndex;
            pucch_pdu->sr_flag = O_sr;
948
            pucch_pdu->prb_size = 1;
949 950 951 952 953 954 955 956
            break;
          case NR_PUCCH_Resource__format_PR_format1 :
            pucch_pdu->format_type = 1;
            pucch_pdu->initial_cyclic_shift = pucchres->format.choice.format1->initialCyclicShift;
            pucch_pdu->nr_of_symbols = pucchres->format.choice.format1->nrofSymbols;
            pucch_pdu->start_symbol_index = pucchres->format.choice.format1->startingSymbolIndex;
            pucch_pdu->time_domain_occ_idx = pucchres->format.choice.format1->timeDomainOCC;
            pucch_pdu->sr_flag = O_sr;
957
            pucch_pdu->prb_size = 1;
958 959 960
            break;
          case NR_PUCCH_Resource__format_PR_format2 :
            pucch_pdu->format_type = 2;
francescomani's avatar
francescomani committed
961
            pucch_pdu->sr_flag = O_sr;
962 963 964 965
            pucch_pdu->nr_of_symbols = pucchres->format.choice.format2->nrofSymbols;
            pucch_pdu->start_symbol_index = pucchres->format.choice.format2->startingSymbolIndex;
            pucch_pdu->data_scrambling_id = pusch_id!= NULL ? *pusch_id : *scc->physCellId;
            pucch_pdu->dmrs_scrambling_id = id0!= NULL ? *id0 : *scc->physCellId;
966 967 968 969 970 971 972
            pucch_pdu->prb_size = compute_pucch_prb_size(2,
                                                         pucchres->format.choice.format2->nrofPRBs,
                                                         O_uci + O_sr,
                                                         pucch_Config->format2->choice.setup->maxCodeRate,
                                                         2,
                                                         pucchres->format.choice.format2->nrofSymbols,
                                                         8);
973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997
            pucch_pdu->bit_len_csi_part1 = O_csi;
            break;
          case NR_PUCCH_Resource__format_PR_format3 :
            pucch_pdu->format_type = 3;
            pucch_pdu->nr_of_symbols = pucchres->format.choice.format3->nrofSymbols;
            pucch_pdu->start_symbol_index = pucchres->format.choice.format3->startingSymbolIndex;
            pucch_pdu->data_scrambling_id = pusch_id!= NULL ? *pusch_id : *scc->physCellId;
            if (pucch_Config->format3 == NULL) {
              pucch_pdu->pi_2bpsk = 0;
              pucch_pdu->add_dmrs_flag = 0;
            }
            else {
              pucchfmt = pucch_Config->format3->choice.setup;
              pucch_pdu->pi_2bpsk = pucchfmt->pi2BPSK!= NULL ?  1 : 0;
              pucch_pdu->add_dmrs_flag = pucchfmt->additionalDMRS!= NULL ?  1 : 0;
            }
            int f3_dmrs_symbols;
            if (pucchres->format.choice.format3->nrofSymbols==4)
              f3_dmrs_symbols = 1<<pucch_pdu->freq_hop_flag;
            else {
              if(pucchres->format.choice.format3->nrofSymbols<10)
                f3_dmrs_symbols = 2;
              else
                f3_dmrs_symbols = 2<<pucch_pdu->add_dmrs_flag;
            }
998 999 1000 1001 1002 1003 1004
            pucch_pdu->prb_size = compute_pucch_prb_size(3,
                                                         pucchres->format.choice.format3->nrofPRBs,
                                                         O_uci + O_sr,
                                                         pucch_Config->format3->choice.setup->maxCodeRate,
                                                         2 - pucch_pdu->pi_2bpsk,
                                                         pucchres->format.choice.format3->nrofSymbols - f3_dmrs_symbols,
                                                         12);
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
            pucch_pdu->bit_len_csi_part1 = O_csi;
            break;
          case NR_PUCCH_Resource__format_PR_format4 :
            pucch_pdu->format_type = 4;
            pucch_pdu->nr_of_symbols = pucchres->format.choice.format4->nrofSymbols;
            pucch_pdu->start_symbol_index = pucchres->format.choice.format4->startingSymbolIndex;
            pucch_pdu->pre_dft_occ_len = pucchres->format.choice.format4->occ_Length;
            pucch_pdu->pre_dft_occ_idx = pucchres->format.choice.format4->occ_Index;
            pucch_pdu->data_scrambling_id = pusch_id!= NULL ? *pusch_id : *scc->physCellId;
            if (pucch_Config->format3 == NULL) {
              pucch_pdu->pi_2bpsk = 0;
              pucch_pdu->add_dmrs_flag = 0;
            }
            else {
              pucchfmt = pucch_Config->format3->choice.setup;
              pucch_pdu->pi_2bpsk = pucchfmt->pi2BPSK!= NULL ?  1 : 0;
              pucch_pdu->add_dmrs_flag = pucchfmt->additionalDMRS!= NULL ?  1 : 0;
            }
            pucch_pdu->bit_len_csi_part1 = O_csi;
            break;
          default :
            AssertFatal(1==0,"Undefined PUCCH format \n");
        }
      }
    }
    AssertFatal(res_found==1,"No PUCCH resource found corresponding to id %ld\n",*resource_id);
1031
    LOG_D(NR_MAC,"Configure pucch: pucch_pdu->format_type %d pucch_pdu->bit_len_harq %d, pucch->pdu->bit_len_csi %d\n",pucch_pdu->format_type,pucch_pdu->bit_len_harq,pucch_pdu->bit_len_csi_part1);
1032 1033
  }
  else { // this is the default PUCCH configuration, PUCCH format 0 or 1
francescomani's avatar
francescomani committed
1034 1035
    LOG_D(NR_MAC,"pucch_acknak: Filling default PUCCH configuration from Tables (r_pucch %d, pucch_Config %p)\n",r_pucch,pucch_Config);
    int rsetindex = *pucch_ConfigCommon->pucch_ResourceCommon;
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
    int prb_start, second_hop_prb, nr_of_symb, start_symb;
    set_r_pucch_parms(rsetindex,
                      r_pucch,
                      pucch_pdu->bwp_size,
                      &prb_start,
                      &second_hop_prb,
                      &nr_of_symb,
                      &start_symb);

    pucch_pdu->prb_start = prb_start;
1046
    pucch_pdu->rnti = UE->rnti;
1047
    pucch_pdu->freq_hop_flag = 1;
1048
    pucch_pdu->second_hop_prb = second_hop_prb;
1049 1050 1051
    pucch_pdu->format_type = default_pucch_fmt[rsetindex];
    pucch_pdu->initial_cyclic_shift = r_pucch%default_pucch_csset[rsetindex];
    if (rsetindex==3||rsetindex==7||rsetindex==11) pucch_pdu->initial_cyclic_shift*=6;
1052 1053
    else if (rsetindex==1||rsetindex==2) pucch_pdu->initial_cyclic_shift*=4;
    else pucch_pdu->initial_cyclic_shift*=3;
1054 1055
    pucch_pdu->nr_of_symbols = nr_of_symb;
    pucch_pdu->start_symbol_index = start_symb;
1056 1057
    if (pucch_pdu->format_type == 1) pucch_pdu->time_domain_occ_idx = 0; // check this!!
    pucch_pdu->sr_flag = O_sr;
1058
    pucch_pdu->prb_size=1;
1059
  }
1060 1061
}

Francesco Mani's avatar
Francesco Mani committed
1062

1063 1064 1065 1066 1067 1068 1069 1070
void set_r_pucch_parms(int rsetindex,
                       int r_pucch,
                       int bwp_size,
                       int *prb_start,
                       int *second_hop_prb,
                       int *nr_of_symbols,
                       int *start_symbol_index) {

francescomani's avatar
francescomani committed
1071 1072
  // procedure described in 38.213 section 9.2.1

1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087
  int prboffset = r_pucch/default_pucch_csset[rsetindex];
  int prboffsetm8 = (r_pucch-8)/default_pucch_csset[rsetindex];

  *prb_start = (r_pucch>>3)==0 ?
              default_pucch_prboffset[rsetindex] + prboffset:
              bwp_size-1-default_pucch_prboffset[rsetindex]-prboffsetm8;

  *second_hop_prb = (r_pucch>>3)==0?
                   bwp_size-1-default_pucch_prboffset[rsetindex]-prboffset:
                   default_pucch_prboffset[rsetindex] + prboffsetm8;

  *nr_of_symbols = default_pucch_numbsymb[rsetindex];
  *start_symbol_index = default_pucch_firstsymb[rsetindex];
}

1088
void prepare_dci(const NR_CellGroupConfig_t *CellGroup, const NR_UE_DL_BWP_t *current_BWP, const NR_ControlResourceSet_t *coreset, dci_pdu_rel15_t *dci_pdu_rel15, nr_dci_format_t format)
1089
{
Eurecom's avatar
Eurecom committed
1090 1091
  AssertFatal(CellGroup!=NULL,"CellGroup shouldn't be null here\n");

francescomani's avatar
francescomani committed
1092
  const NR_PDSCH_Config_t *pdsch_Config = current_BWP ? current_BWP->pdsch_Config : NULL;
Francesco Mani's avatar
Francesco Mani committed
1093 1094

  switch(format) {
1095 1096 1097 1098
    case NR_UL_DCI_FORMAT_0_1:
      // format indicator
      dci_pdu_rel15->format_indicator = 0;
      // carrier indicator
1099
      if (CellGroup->spCellConfig->spCellConfigDedicated->crossCarrierSchedulingConfig != NULL)
1100 1101
        AssertFatal(1==0,"Cross Carrier Scheduling Config currently not supported\n");
      // supplementary uplink
1102
      if (CellGroup->spCellConfig->spCellConfigDedicated->supplementaryUplink != NULL)
1103 1104 1105 1106 1107
        AssertFatal(1==0,"Supplementary Uplink currently not supported\n");
      // SRS request
      dci_pdu_rel15->srs_request.val = 0;
      dci_pdu_rel15->ulsch_indicator = 1;
      break;
Francesco Mani's avatar
Francesco Mani committed
1108 1109 1110 1111
    case NR_DL_DCI_FORMAT_1_1:
      // format indicator
      dci_pdu_rel15->format_indicator = 1;
      // carrier indicator
1112
      if (CellGroup->spCellConfig->spCellConfigDedicated->crossCarrierSchedulingConfig != NULL)
Francesco Mani's avatar
Francesco Mani committed
1113 1114
        AssertFatal(1==0,"Cross Carrier Scheduling Config currently not supported\n");
      //vrb to prb mapping
Eurecom's avatar
Eurecom committed
1115
      if (pdsch_Config->vrb_ToPRB_Interleaver==NULL)
Francesco Mani's avatar
Francesco Mani committed
1116 1117 1118 1119
        dci_pdu_rel15->vrb_to_prb_mapping.val = 0;
      else
        dci_pdu_rel15->vrb_to_prb_mapping.val = 1;
      //bundling size indicator
Eurecom's avatar
Eurecom committed
1120
      if (pdsch_Config->prb_BundlingType.present == NR_PDSCH_Config__prb_BundlingType_PR_dynamicBundling)
Francesco Mani's avatar
Francesco Mani committed
1121 1122
        AssertFatal(1==0,"Dynamic PRB bundling type currently not supported\n");
      //rate matching indicator
Eurecom's avatar
Eurecom committed
1123 1124
      uint16_t msb = (pdsch_Config->rateMatchPatternGroup1==NULL)?0:1;
      uint16_t lsb = (pdsch_Config->rateMatchPatternGroup2==NULL)?0:1;
Francesco Mani's avatar
Francesco Mani committed
1125 1126
      dci_pdu_rel15->rate_matching_indicator.val = lsb | (msb<<1);
      // aperiodic ZP CSI-RS trigger
Eurecom's avatar
Eurecom committed
1127
      if (pdsch_Config->aperiodic_ZP_CSI_RS_ResourceSetsToAddModList != NULL)
Francesco Mani's avatar
Francesco Mani committed
1128 1129
        AssertFatal(1==0,"Aperiodic ZP CSI-RS currently not supported\n");
      // transmission configuration indication
1130
      if (coreset->tci_PresentInDCI != NULL)
Francesco Mani's avatar
Francesco Mani committed
1131 1132
        AssertFatal(1==0,"TCI in DCI currently not supported\n");
      //srs resource set
1133 1134
      if (CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->carrierSwitching!=NULL) {
        NR_SRS_CarrierSwitching_t *cs = CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->carrierSwitching->choice.setup;
Francesco Mani's avatar
Francesco Mani committed
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
        if (cs->srs_TPC_PDCCH_Group!=NULL){
          switch(cs->srs_TPC_PDCCH_Group->present) {
            case NR_SRS_CarrierSwitching__srs_TPC_PDCCH_Group_PR_NOTHING:
              dci_pdu_rel15->srs_request.val = 0;
              break;
            case NR_SRS_CarrierSwitching__srs_TPC_PDCCH_Group_PR_typeA:
              AssertFatal(1==0,"SRS TPC PRCCH group type A currently not supported\n");
              break;
            case NR_SRS_CarrierSwitching__srs_TPC_PDCCH_Group_PR_typeB:
              AssertFatal(1==0,"SRS TPC PRCCH group type B currently not supported\n");
              break;
          }
        }
        else
          dci_pdu_rel15->srs_request.val = 0;
      }
      else
        dci_pdu_rel15->srs_request.val = 0;
    // CBGTI and CBGFI
francescomani's avatar
francescomani committed
1154 1155
    if (current_BWP->pdsch_servingcellconfig &&
        current_BWP->pdsch_servingcellconfig->codeBlockGroupTransmission != NULL)
Francesco Mani's avatar
Francesco Mani committed
1156 1157
      AssertFatal(1==0,"CBG transmission currently not supported\n");
    break;
Francesco Mani's avatar
Francesco Mani committed
1158
  default :
1159
    AssertFatal(1==0,"Prepare dci currently only implemented for 1_1 and 0_1 \n");
Francesco Mani's avatar
Francesco Mani committed
1160 1161 1162
  }
}

1163
void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc,
1164
                        const NR_CellGroupConfig_t *CellGroup,
1165 1166
                        const NR_UE_DL_BWP_t *current_DL_BWP,
                        const NR_UE_UL_BWP_t *current_UL_BWP,
1167
                        nfapi_nr_dl_dci_pdu_t *pdcch_dci_pdu,
1168
                        dci_pdu_rel15_t *dci_pdu_rel15,
1169 1170
                        int dci_format,
                        int rnti_type,
1171
                        int bwp_id,
1172
                        NR_SearchSpace_t *ss,
1173
                        NR_ControlResourceSet_t *coreset,
1174 1175
                        uint16_t cset0_bwp_size)
{
1176

1177
  uint8_t fsize = 0, pos = 0;
1178
  uint64_t *dci_pdu = (uint64_t *)pdcch_dci_pdu->Payload;
1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
  *dci_pdu = 0;
  uint16_t alt_size = 0;
  uint16_t N_RB;
  if(current_DL_BWP) {
    N_RB = get_rb_bwp_dci(dci_format,
                          ss->searchSpaceType->present,
                          cset0_bwp_size,
                          current_UL_BWP->BWPSize,
                          current_DL_BWP->BWPSize,
                          current_UL_BWP->initial_BWPSize,
                          current_DL_BWP->initial_BWPSize);

    // computing alternative size for padding
    dci_pdu_rel15_t temp_pdu;
1193
    if(dci_format == NR_DL_DCI_FORMAT_1_0)
1194
      alt_size = nr_dci_size(current_DL_BWP, current_UL_BWP, CellGroup, &temp_pdu, NR_UL_DCI_FORMAT_0_0, rnti_type, coreset, bwp_id, ss->searchSpaceType->present, cset0_bwp_size, 0);
1195

1196
    if(dci_format == NR_UL_DCI_FORMAT_0_0)
1197
      alt_size = nr_dci_size(current_DL_BWP, current_UL_BWP, CellGroup, &temp_pdu, NR_DL_DCI_FORMAT_1_0, rnti_type, coreset, bwp_id, ss->searchSpaceType->present, cset0_bwp_size, 0);
1198

1199 1200 1201
  }
  else
    N_RB = cset0_bwp_size;
1202

1203
  int dci_size = nr_dci_size(current_DL_BWP, current_UL_BWP, CellGroup, dci_pdu_rel15, dci_format, rnti_type, coreset, bwp_id, ss->searchSpaceType->present, cset0_bwp_size, alt_size);
1204 1205 1206
  pdcch_dci_pdu->PayloadSizeBits = dci_size;
  AssertFatal(dci_size <= 64, "DCI sizes above 64 bits not yet supported");
  if (dci_format == NR_DL_DCI_FORMAT_1_1 || dci_format == NR_UL_DCI_FORMAT_0_1)
1207
    prepare_dci(CellGroup, current_DL_BWP, coreset, dci_pdu_rel15, dci_format);
1208 1209 1210 1211 1212 1213 1214 1215 1216 1217

  /// Payload generation
  switch (dci_format) {
  case NR_DL_DCI_FORMAT_1_0:
    switch (rnti_type) {
    case NR_RNTI_RA:
      // Freq domain assignment
      fsize = (int)ceil(log2((N_RB * (N_RB + 1)) >> 1));
      pos = fsize;
      *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val & ((1 << fsize) - 1)) << (dci_size - pos));
1218
      LOG_D(NR_MAC,
1219 1220
            "RA_RNTI, size %d frequency-domain assignment %d (%d bits) N_RB_BWP %d=> %d (0x%lx)\n",
            dci_size,dci_pdu_rel15->frequency_domain_assignment.val,
1221 1222 1223 1224 1225 1226 1227
            fsize,
            N_RB,
            dci_size - pos,
            *dci_pdu);
      // Time domain assignment
      pos += 4;
      *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val & 0xf) << (dci_size - pos));
1228
      LOG_D(NR_MAC,
Raymond Knopp's avatar
Raymond Knopp committed
1229
            "time-domain assignment %d  (4 bits)=> %d (0x%lx)\n",
1230 1231 1232 1233 1234 1235
            dci_pdu_rel15->time_domain_assignment.val,
            dci_size - pos,
            *dci_pdu);
      // VRB to PRB mapping
      pos++;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val & 0x1) << (dci_size - pos);
1236
      LOG_D(NR_MAC,
1237 1238 1239 1240 1241 1242 1243
            "vrb to prb mapping %d  (1 bits)=> %d (0x%lx)\n",
            dci_pdu_rel15->vrb_to_prb_mapping.val,
            dci_size - pos,
            *dci_pdu);
      // MCS
      pos += 5;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->mcs & 0x1f) << (dci_size - pos);
rmagueta's avatar
rmagueta committed
1244
      LOG_D(NR_MAC, "mcs %d  (5 bits)=> %d (0x%lx)\n", dci_pdu_rel15->mcs, dci_size - pos, *dci_pdu);
1245 1246 1247
      // TB scaling
      pos += 2;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->tb_scaling & 0x3) << (dci_size - pos);
rmagueta's avatar
rmagueta committed
1248
      LOG_D(NR_MAC, "tb_scaling %d  (2 bits)=> %d (0x%lx)\n", dci_pdu_rel15->tb_scaling, dci_size - pos, *dci_pdu);
1249
      break;
1250

1251 1252 1253
    case NR_RNTI_C:
      // indicating a DL DCI format 1bit
      pos++;
1254
      *dci_pdu |= ((uint64_t)1) << (dci_size - pos);
1255
      LOG_D(NR_MAC,
Eurecom's avatar
Eurecom committed
1256 1257
            "DCI1_0 (size %d): Format indicator %d (%d bits) N_RB_BWP %d => %d (0x%lx)\n",
            dci_size,
1258 1259 1260 1261 1262 1263 1264 1265 1266
            dci_pdu_rel15->format_indicator,
            1,
            N_RB,
            dci_size - pos,
            *dci_pdu);
      // Freq domain assignment (275rb >> fsize = 16)
      fsize = (int)ceil(log2((N_RB * (N_RB + 1)) >> 1));
      pos += fsize;
      *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val & ((1 << fsize) - 1)) << (dci_size - pos));
1267
      LOG_D(NR_MAC,
1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296
            "Freq domain assignment %d (%d bits)=> %d (0x%lx)\n",
            dci_pdu_rel15->frequency_domain_assignment.val,
            fsize,
            dci_size - pos,
            *dci_pdu);
      uint16_t is_ra = 1;
      for (int i = 0; i < fsize; i++) {
        if (!((dci_pdu_rel15->frequency_domain_assignment.val >> i) & 1)) {
          is_ra = 0;
          break;
        }
      }
      if (is_ra) { // fsize are all 1  38.212 p86
        // ra_preamble_index 6 bits
        pos += 6;
        *dci_pdu |= ((dci_pdu_rel15->ra_preamble_index & 0x3f) << (dci_size - pos));
        // UL/SUL indicator  1 bit
        pos++;
        *dci_pdu |= (dci_pdu_rel15->ul_sul_indicator.val & 1) << (dci_size - pos);
        // SS/PBCH index  6 bits
        pos += 6;
        *dci_pdu |= ((dci_pdu_rel15->ss_pbch_index & 0x3f) << (dci_size - pos));
        //  prach_mask_index  4 bits
        pos += 4;
        *dci_pdu |= ((dci_pdu_rel15->prach_mask_index & 0xf) << (dci_size - pos));
      } else {
        // Time domain assignment 4bit
        pos += 4;
        *dci_pdu |= ((dci_pdu_rel15->time_domain_assignment.val & 0xf) << (dci_size - pos));
1297
        LOG_D(NR_MAC,
1298 1299 1300 1301 1302 1303 1304 1305
              "Time domain assignment %d (%d bits)=> %d (0x%lx)\n",
              dci_pdu_rel15->time_domain_assignment.val,
              4,
              dci_size - pos,
              *dci_pdu);
        // VRB to PRB mapping  1bit
        pos++;
        *dci_pdu |= (dci_pdu_rel15->vrb_to_prb_mapping.val & 1) << (dci_size - pos);
1306
        LOG_D(NR_MAC,
1307 1308 1309 1310 1311
              "VRB to PRB %d (%d bits)=> %d (0x%lx)\n",
              dci_pdu_rel15->vrb_to_prb_mapping.val,
              1,
              dci_size - pos,
              *dci_pdu);
1312
        // MCS 5bit  //bit over 32, so dci_pdu ++
1313 1314
        pos += 5;
        *dci_pdu |= (dci_pdu_rel15->mcs & 0x1f) << (dci_size - pos);
1315
        LOG_D(NR_MAC, "MCS %d (%d bits)=> %d (0x%lx)\n", dci_pdu_rel15->mcs, 5, dci_size - pos, *dci_pdu);
1316 1317 1318
        // New data indicator 1bit
        pos++;
        *dci_pdu |= (dci_pdu_rel15->ndi & 1) << (dci_size - pos);
1319
        LOG_D(NR_MAC, "NDI %d (%d bits)=> %d (0x%lx)\n", dci_pdu_rel15->ndi, 1, dci_size - pos, *dci_pdu);
1320 1321 1322
        // Redundancy version  2bit
        pos += 2;
        *dci_pdu |= (dci_pdu_rel15->rv & 0x3) << (dci_size - pos);
1323
        LOG_D(NR_MAC, "RV %d (%d bits)=> %d (0x%lx)\n", dci_pdu_rel15->rv, 2, dci_size - pos, *dci_pdu);
1324 1325 1326
        // HARQ process number  4bit
        pos += 4;
        *dci_pdu |= ((dci_pdu_rel15->harq_pid & 0xf) << (dci_size - pos));
1327
        LOG_D(NR_MAC, "HARQ_PID %d (%d bits)=> %d (0x%lx)\n", dci_pdu_rel15->harq_pid, 4, dci_size - pos, *dci_pdu);
1328 1329 1330
        // Downlink assignment index  2bit
        pos += 2;
        *dci_pdu |= ((dci_pdu_rel15->dai[0].val & 3) << (dci_size - pos));
1331
        LOG_D(NR_MAC, "DAI %d (%d bits)=> %d (0x%lx)\n", dci_pdu_rel15->dai[0].val, 2, dci_size - pos, *dci_pdu);
1332 1333 1334
        // TPC command for scheduled PUCCH  2bit
        pos += 2;
        *dci_pdu |= ((dci_pdu_rel15->tpc & 3) << (dci_size - pos));
1335
        LOG_D(NR_MAC, "TPC %d (%d bits)=> %d (0x%lx)\n", dci_pdu_rel15->tpc, 2, dci_size - pos, *dci_pdu);
1336 1337 1338
        // PUCCH resource indicator  3bit
        pos += 3;
        *dci_pdu |= ((dci_pdu_rel15->pucch_resource_indicator & 0x7) << (dci_size - pos));
1339
        LOG_D(NR_MAC,
1340 1341 1342 1343 1344 1345 1346 1347
              "PUCCH RI %d (%d bits)=> %d (0x%lx)\n",
              dci_pdu_rel15->pucch_resource_indicator,
              3,
              dci_size - pos,
              *dci_pdu);
        // PDSCH-to-HARQ_feedback timing indicator 3bit
        pos += 3;
        *dci_pdu |= ((dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val & 0x7) << (dci_size - pos));
1348
        LOG_D(NR_MAC,
1349 1350 1351 1352 1353 1354 1355
              "PDSCH to HARQ TI %d (%d bits)=> %d (0x%lx)\n",
              dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val,
              3,
              dci_size - pos,
              *dci_pdu);
      } // end else
      break;
1356

1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379
    case NR_RNTI_P:
      // Short Messages Indicator – 2 bits
      for (int i = 0; i < 2; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->short_messages_indicator >> (1 - i)) & 1) << (dci_size - pos++);
      // Short Messages – 8 bits
      for (int i = 0; i < 8; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->short_messages >> (7 - i)) & 1) << (dci_size - pos++);
      // Freq domain assignment 0-16 bit
      fsize = (int)ceil(log2((N_RB * (N_RB + 1)) >> 1));
      for (int i = 0; i < fsize; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val >> (fsize - i - 1)) & 1) << (dci_size - pos++);
      // Time domain assignment 4 bit
      for (int i = 0; i < 4; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val >> (3 - i)) & 1) << (dci_size - pos++);
      // VRB to PRB mapping 1 bit
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val & 1) << (dci_size - pos++);
      // MCS 5 bit
      for (int i = 0; i < 5; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->mcs >> (4 - i)) & 1) << (dci_size - pos++);
      // TB scaling 2 bit
      for (int i = 0; i < 2; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->tb_scaling >> (1 - i)) & 1) << (dci_size - pos++);
      break;
1380

1381 1382 1383 1384
    case NR_RNTI_SI:
      pos = 1;
      // Freq domain assignment 0-16 bit
      fsize = (int)ceil(log2((N_RB * (N_RB + 1)) >> 1));
francescomani's avatar
francescomani committed
1385
      LOG_D(NR_MAC, "fsize = %i\n", fsize);
1386 1387
      for (int i = 0; i < fsize; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val >> (fsize - i - 1)) & 1) << (dci_size - pos++);
francescomani's avatar
francescomani committed
1388
      LOG_D(NR_MAC, "dci_pdu_rel15->frequency_domain_assignment.val = %i\n", dci_pdu_rel15->frequency_domain_assignment.val);
1389 1390 1391
      // Time domain assignment 4 bit
      for (int i = 0; i < 4; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val >> (3 - i)) & 1) << (dci_size - pos++);
francescomani's avatar
francescomani committed
1392
      LOG_D(NR_MAC, "dci_pdu_rel15->time_domain_assignment.val = %i\n", dci_pdu_rel15->time_domain_assignment.val);
1393 1394
      // VRB to PRB mapping 1 bit
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val & 1) << (dci_size - pos++);
francescomani's avatar
francescomani committed
1395
      LOG_D(NR_MAC, "dci_pdu_rel15->vrb_to_prb_mapping.val = %i\n", dci_pdu_rel15->vrb_to_prb_mapping.val);
1396 1397 1398
      // MCS 5bit  //bit over 32, so dci_pdu ++
      for (int i = 0; i < 5; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->mcs >> (4 - i)) & 1) << (dci_size - pos++);
francescomani's avatar
francescomani committed
1399
      LOG_D(NR_MAC, "dci_pdu_rel15->mcs = %i\n", dci_pdu_rel15->mcs);
1400 1401 1402
      // Redundancy version  2bit
      for (int i = 0; i < 2; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->rv >> (1 - i)) & 1) << (dci_size - pos++);
francescomani's avatar
francescomani committed
1403
      LOG_D(NR_MAC, "dci_pdu_rel15->rv = %i\n", dci_pdu_rel15->rv);
1404 1405
      // System information indicator 1bit
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->system_info_indicator&1)<<(dci_size-pos++);
francescomani's avatar
francescomani committed
1406
      LOG_D(NR_MAC, "dci_pdu_rel15->system_info_indicator = %i\n", dci_pdu_rel15->system_info_indicator);
1407
      break;
1408

1409
    case NR_RNTI_TC:
1410
      pos = 1;
1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438
      // indicating a DL DCI format 1bit
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator & 1) << (dci_size - pos++);
      // Freq domain assignment 0-16 bit
      fsize = (int)ceil(log2((N_RB * (N_RB + 1)) >> 1));
      for (int i = 0; i < fsize; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val >> (fsize - i - 1)) & 1) << (dci_size - pos++);
      // Time domain assignment 4 bit
      for (int i = 0; i < 4; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val >> (3 - i)) & 1) << (dci_size - pos++);
      // VRB to PRB mapping 1 bit
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val & 1) << (dci_size - pos++);
      // MCS 5bit  //bit over 32, so dci_pdu ++
      for (int i = 0; i < 5; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->mcs >> (4 - i)) & 1) << (dci_size - pos++);
      // New data indicator 1bit
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi & 1) << (dci_size - pos++);
      // Redundancy version  2bit
      for (int i = 0; i < 2; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->rv >> (1 - i)) & 1) << (dci_size - pos++);
      // HARQ process number  4bit
      for (int i = 0; i < 4; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->harq_pid >> (3 - i)) & 1) << (dci_size - pos++);
      // Downlink assignment index – 2 bits
      for (int i = 0; i < 2; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->dai[0].val >> (1 - i)) & 1) << (dci_size - pos++);
      // TPC command for scheduled PUCCH – 2 bits
      for (int i = 0; i < 2; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->tpc >> (1 - i)) & 1) << (dci_size - pos++);
1439 1440 1441
      // PUCCH resource indicator – 3 bits
      for (int i = 0; i < 3; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->pucch_resource_indicator >> (2 - i)) & 1) << (dci_size - pos++);
1442 1443 1444
      // PDSCH-to-HARQ_feedback timing indicator – 3 bits
      for (int i = 0; i < 3; i++)
        *dci_pdu |= (((uint64_t)dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val >> (2 - i)) & 1) << (dci_size - pos++);
1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459

      LOG_D(NR_MAC,"N_RB = %i\n", N_RB);
      LOG_D(NR_MAC,"dci_size = %i\n", dci_size);
      LOG_D(NR_MAC,"fsize = %i\n", fsize);
      LOG_D(NR_MAC,"dci_pdu_rel15->format_indicator = %i\n", dci_pdu_rel15->format_indicator);
      LOG_D(NR_MAC,"dci_pdu_rel15->frequency_domain_assignment.val = %i\n", dci_pdu_rel15->frequency_domain_assignment.val);
      LOG_D(NR_MAC,"dci_pdu_rel15->time_domain_assignment.val = %i\n", dci_pdu_rel15->time_domain_assignment.val);
      LOG_D(NR_MAC,"dci_pdu_rel15->vrb_to_prb_mapping.val = %i\n", dci_pdu_rel15->vrb_to_prb_mapping.val);
      LOG_D(NR_MAC,"dci_pdu_rel15->mcs = %i\n", dci_pdu_rel15->mcs);
      LOG_D(NR_MAC,"dci_pdu_rel15->rv = %i\n", dci_pdu_rel15->rv);
      LOG_D(NR_MAC,"dci_pdu_rel15->harq_pid = %i\n", dci_pdu_rel15->harq_pid);
      LOG_D(NR_MAC,"dci_pdu_rel15->dai[0].val = %i\n", dci_pdu_rel15->dai[0].val);
      LOG_D(NR_MAC,"dci_pdu_rel15->tpc = %i\n", dci_pdu_rel15->tpc);
      LOG_D(NR_MAC,"dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val = %i\n", dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val);

1460
      break;
1461 1462 1463 1464 1465 1466
    }
    break;

  case NR_UL_DCI_FORMAT_0_0:
    switch (rnti_type) {
    case NR_RNTI_C:
1467
      LOG_D(NR_MAC,"Filling format 0_0 DCI for CRNTI (size %d bits, format ind %d)\n",dci_size,dci_pdu_rel15->format_indicator);
1468
      // indicating a UL DCI format 1bit
1469
      pos=1;
1470
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator & 1) << (dci_size - pos);
1471
      // Freq domain assignment  max 16 bit
1472
      fsize = dci_pdu_rel15->frequency_domain_assignment.nbits;
1473 1474
      pos+=fsize;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val & ((1 << fsize) - 1)) << (dci_size - pos);
1475
      // Time domain assignment 4bit
1476 1477
      pos += 4;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->time_domain_assignment.val & ((1 << 4) - 1)) << (dci_size - pos);
1478
      // Frequency hopping flag – 1 bit
1479 1480
      pos++;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_hopping_flag.val & 1) << (dci_size - pos);
1481
      // MCS  5 bit
1482 1483
      pos+=5;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->mcs & 0x1f) << (dci_size - pos);
1484
      // New data indicator 1bit
1485 1486
      pos++;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi & 1) << (dci_size - pos);
1487
      // Redundancy version  2bit
1488 1489
      pos+=2;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->rv & 0x3) << (dci_size - pos);
1490
      // HARQ process number  4bit
1491 1492
      pos+=4;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->harq_pid & 0xf) << (dci_size - pos);
1493
      // TPC command for scheduled PUSCH – 2 bits
1494 1495
      pos+=2;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->tpc & 0x3) << (dci_size - pos);
1496
      // Padding bits
1497
      for (int a = pos; a < dci_size; a++)
1498 1499 1500 1501 1502 1503 1504
        *dci_pdu |= ((uint64_t)dci_pdu_rel15->padding & 1) << (dci_size - pos++);
      // UL/SUL indicator – 1 bit
      /* commented for now (RK): need to get this from BWP descriptor
      if (cfg->pucch_config.pucch_GroupHopping.value)
        *dci_pdu |=
      ((uint64_t)dci_pdu_rel15->ul_sul_indicator.val&1)<<(dci_size-pos++);
        */
1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517

        LOG_D(NR_MAC,"N_RB = %i\n", N_RB);
        LOG_D(NR_MAC,"dci_size = %i\n", dci_size);
        LOG_D(NR_MAC,"fsize = %i\n", fsize);
        LOG_D(NR_MAC,"dci_pdu_rel15->frequency_domain_assignment.val = %i\n", dci_pdu_rel15->frequency_domain_assignment.val);
        LOG_D(NR_MAC,"dci_pdu_rel15->time_domain_assignment.val = %i\n", dci_pdu_rel15->time_domain_assignment.val);
        LOG_D(NR_MAC,"dci_pdu_rel15->frequency_hopping_flag.val = %i\n", dci_pdu_rel15->frequency_hopping_flag.val);
        LOG_D(NR_MAC,"dci_pdu_rel15->mcs = %i\n", dci_pdu_rel15->mcs);
        LOG_D(NR_MAC,"dci_pdu_rel15->ndi = %i\n", dci_pdu_rel15->ndi);
        LOG_D(NR_MAC,"dci_pdu_rel15->rv = %i\n", dci_pdu_rel15->rv);
        LOG_D(NR_MAC,"dci_pdu_rel15->harq_pid = %i\n", dci_pdu_rel15->harq_pid);
        LOG_D(NR_MAC,"dci_pdu_rel15->tpc = %i\n", dci_pdu_rel15->tpc);
        LOG_D(NR_MAC,"dci_pdu_rel15->padding = %i\n", dci_pdu_rel15->padding);
1518
      break;
1519

1520
    case NFAPI_NR_RNTI_TC:
francescomani's avatar
francescomani committed
1521 1522 1523
      // indicating a UL DCI format 1bit
      pos=1;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator & 1) << (dci_size - pos);
1524
      // Freq domain assignment  max 16 bit
1525
      fsize = dci_pdu_rel15->frequency_domain_assignment.nbits;
francescomani's avatar
francescomani committed
1526 1527
      pos+=fsize;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val & ((1 << fsize) - 1)) << (dci_size - pos);
1528
      // Time domain assignment 4bit
francescomani's avatar
francescomani committed
1529 1530
      pos += 4;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->time_domain_assignment.val & ((1 << 4) - 1)) << (dci_size - pos);
1531
      // Frequency hopping flag – 1 bit
francescomani's avatar
francescomani committed
1532 1533
      pos++;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_hopping_flag.val & 1) << (dci_size - pos);
1534
      // MCS  5 bit
francescomani's avatar
francescomani committed
1535 1536
      pos+=5;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->mcs & 0x1f) << (dci_size - pos);
1537
      // New data indicator 1bit
francescomani's avatar
francescomani committed
1538 1539
      pos++;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi & 1) << (dci_size - pos);
1540
      // Redundancy version  2bit
francescomani's avatar
francescomani committed
1541 1542
      pos+=2;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->rv & 0x3) << (dci_size - pos);
1543
      // HARQ process number  4bit
francescomani's avatar
francescomani committed
1544 1545
      pos+=4;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->harq_pid & 0xf) << (dci_size - pos);
1546
      // Padding bits
1547
      for (int a = pos; a < dci_size; a++)
1548 1549
        *dci_pdu |= ((uint64_t)dci_pdu_rel15->padding & 1) << (dci_size - pos++);
      // UL/SUL indicator – 1 bit
francescomani's avatar
francescomani committed
1550 1551
      /* commented for now (RK): need to get this from BWP descriptor
      if (cfg->pucch_config.pucch_GroupHopping.value)
1552
        *dci_pdu |=
francescomani's avatar
francescomani committed
1553
      ((uint64_t)dci_pdu_rel15->ul_sul_indicator.val&1)<<(dci_size-pos++);
1554
        */
francescomani's avatar
francescomani committed
1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567
      LOG_D(NR_MAC,"N_RB = %i\n", N_RB);
      LOG_D(NR_MAC,"dci_size = %i\n", dci_size);
      LOG_D(NR_MAC,"fsize = %i\n", fsize);
      LOG_D(NR_MAC,"dci_pdu_rel15->frequency_domain_assignment.val = %i\n", dci_pdu_rel15->frequency_domain_assignment.val);
      LOG_D(NR_MAC,"dci_pdu_rel15->time_domain_assignment.val = %i\n", dci_pdu_rel15->time_domain_assignment.val);
      LOG_D(NR_MAC,"dci_pdu_rel15->frequency_hopping_flag.val = %i\n", dci_pdu_rel15->frequency_hopping_flag.val);
      LOG_D(NR_MAC,"dci_pdu_rel15->mcs = %i\n", dci_pdu_rel15->mcs);
      LOG_D(NR_MAC,"dci_pdu_rel15->ndi = %i\n", dci_pdu_rel15->ndi);
      LOG_D(NR_MAC,"dci_pdu_rel15->rv = %i\n", dci_pdu_rel15->rv);
      LOG_D(NR_MAC,"dci_pdu_rel15->harq_pid = %i\n", dci_pdu_rel15->harq_pid);
      LOG_D(NR_MAC,"dci_pdu_rel15->tpc = %i\n", dci_pdu_rel15->tpc);
      LOG_D(NR_MAC,"dci_pdu_rel15->padding = %i\n", dci_pdu_rel15->padding);

1568
      break;
1569 1570
    }
    break;
1571

1572 1573 1574
  case NR_UL_DCI_FORMAT_0_1:
    switch (rnti_type) {
    case NR_RNTI_C:
1575
      LOG_D(NR_MAC,"Filling NR_UL_DCI_FORMAT_0_1 size %d format indicator %d\n",dci_size,dci_pdu_rel15->format_indicator);
1576
      // Indicating a DL DCI format 1bit
1577 1578
      pos = 1;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator & 0x1) << (dci_size - pos);
1579
      // Carrier indicator
1580 1581 1582 1583 1584
      pos += dci_pdu_rel15->carrier_indicator.nbits;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->carrier_indicator.val & ((1 << dci_pdu_rel15->carrier_indicator.nbits) - 1)) << (dci_size - pos);
      // UL/SUL Indicator
      pos += dci_pdu_rel15->ul_sul_indicator.nbits;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->ul_sul_indicator.val & ((1 << dci_pdu_rel15->ul_sul_indicator.nbits) - 1)) << (dci_size - pos);
1585
      // BWP indicator
1586 1587
      pos += dci_pdu_rel15->bwp_indicator.nbits;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->bwp_indicator.val & ((1 << dci_pdu_rel15->bwp_indicator.nbits) - 1)) << (dci_size - pos);
1588
      // Frequency domain resource assignment
1589 1590
      pos += dci_pdu_rel15->frequency_domain_assignment.nbits;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val & ((1 << dci_pdu_rel15->frequency_domain_assignment.nbits) - 1)) << (dci_size - pos);
1591
      // Time domain resource assignment
1592 1593 1594 1595 1596
      pos += dci_pdu_rel15->time_domain_assignment.nbits;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->time_domain_assignment.val & ((1 << dci_pdu_rel15->time_domain_assignment.nbits) - 1)) << (dci_size - pos);
      // Frequency hopping
      pos += dci_pdu_rel15->frequency_hopping_flag.nbits;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_hopping_flag.val & ((1 << dci_pdu_rel15->frequency_hopping_flag.nbits) - 1)) << (dci_size - pos);
1597
      // MCS 5bit
1598 1599
      pos += 5;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->mcs & 0x1f) << (dci_size - pos);
1600
      // New data indicator 1bit
1601 1602
      pos += 1;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi & 0x1) << (dci_size - pos);
1603
      // Redundancy version  2bit
1604 1605
      pos += 2;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->rv & 0x3) << (dci_size - pos);
1606
      // HARQ process number  4bit
1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623
      pos += 4;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->harq_pid & 0xf) << (dci_size - pos);
      // 1st Downlink assignment index
      pos += dci_pdu_rel15->dai[0].nbits;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->dai[0].val & ((1 << dci_pdu_rel15->dai[0].nbits) - 1)) << (dci_size - pos);
      // 2nd Downlink assignment index
      pos += dci_pdu_rel15->dai[1].nbits;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->dai[1].val & ((1 << dci_pdu_rel15->dai[1].nbits) - 1)) << (dci_size - pos);
      // TPC command for scheduled PUSCH  2bit
      pos += 2;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->tpc & 0x3) << (dci_size - pos);
      // SRS resource indicator
      pos += dci_pdu_rel15->srs_resource_indicator.nbits;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->srs_resource_indicator.val & ((1 << dci_pdu_rel15->srs_resource_indicator.nbits) - 1)) << (dci_size - pos);
      // Precoding info and n. of layers
      pos += dci_pdu_rel15->precoding_information.nbits;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->precoding_information.val & ((1 << dci_pdu_rel15->precoding_information.nbits) - 1)) << (dci_size - pos);
1624
      // Antenna ports
1625 1626
      pos += dci_pdu_rel15->antenna_ports.nbits;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->antenna_ports.val & ((1 << dci_pdu_rel15->antenna_ports.nbits) - 1)) << (dci_size - pos);
1627
      // SRS request
1628 1629 1630 1631 1632
      pos += dci_pdu_rel15->srs_request.nbits;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->srs_request.val & ((1 << dci_pdu_rel15->srs_request.nbits) - 1)) << (dci_size - pos);
      // CSI request
      pos += dci_pdu_rel15->csi_request.nbits;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->csi_request.val & ((1 << dci_pdu_rel15->csi_request.nbits) - 1)) << (dci_size - pos);
1633
      // CBG transmission information
1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647
      pos += dci_pdu_rel15->cbgti.nbits;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->cbgti.val & ((1 << dci_pdu_rel15->cbgti.nbits) - 1)) << (dci_size - pos);
      // PTRS DMRS association
      pos += dci_pdu_rel15->ptrs_dmrs_association.nbits;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->ptrs_dmrs_association.val & ((1 << dci_pdu_rel15->ptrs_dmrs_association.nbits) - 1)) << (dci_size - pos);
      // Beta offset indicator
      pos += dci_pdu_rel15->beta_offset_indicator.nbits;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->beta_offset_indicator.val & ((1 << dci_pdu_rel15->beta_offset_indicator.nbits) - 1)) << (dci_size - pos);
      // DMRS sequence initialization
      pos += dci_pdu_rel15->dmrs_sequence_initialization.nbits;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->dmrs_sequence_initialization.val & ((1 << dci_pdu_rel15->dmrs_sequence_initialization.nbits) - 1)) << (dci_size - pos);
      // UL-SCH indicator
      pos += 1;
      *dci_pdu |= ((uint64_t)dci_pdu_rel15->ulsch_indicator & 0x1) << (dci_size - pos);
1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678

#ifdef DEBUG_DCI
        LOG_I(NR_MAC,"============= NR_UL_DCI_FORMAT_0_1 =============\n");
        LOG_I(NR_MAC,"dci_size = %i\n", dci_size);
        LOG_I(NR_MAC,"dci_pdu_rel15->format_indicator = %i\n", dci_pdu_rel15->format_indicator);
        LOG_I(NR_MAC,"dci_pdu_rel15->carrier_indicator.val = %i\n", dci_pdu_rel15->carrier_indicator.val);
        LOG_I(NR_MAC,"dci_pdu_rel15->ul_sul_indicator.val = %i\n", dci_pdu_rel15->ul_sul_indicator.val);
        LOG_I(NR_MAC,"dci_pdu_rel15->bwp_indicator.val = %i\n", dci_pdu_rel15->bwp_indicator.val);
        LOG_I(NR_MAC,"dci_pdu_rel15->frequency_domain_assignment.val = %i\n", dci_pdu_rel15->frequency_domain_assignment.val);
        LOG_I(NR_MAC,"dci_pdu_rel15->time_domain_assignment.val = %i\n", dci_pdu_rel15->time_domain_assignment.val);
        LOG_I(NR_MAC,"dci_pdu_rel15->frequency_hopping_flag.val = %i\n", dci_pdu_rel15->frequency_hopping_flag.val);
        LOG_I(NR_MAC,"dci_pdu_rel15->mcs = %i\n", dci_pdu_rel15->mcs);
        LOG_I(NR_MAC,"dci_pdu_rel15->ndi = %i\n", dci_pdu_rel15->ndi);
        LOG_I(NR_MAC,"dci_pdu_rel15->rv= %i\n", dci_pdu_rel15->rv);
        LOG_I(NR_MAC,"dci_pdu_rel15->harq_pid = %i\n", dci_pdu_rel15->harq_pid);
        LOG_I(NR_MAC,"dci_pdu_rel15->dai[0].val = %i\n", dci_pdu_rel15->dai[0].val);
        LOG_I(NR_MAC,"dci_pdu_rel15->dai[1].val = %i\n", dci_pdu_rel15->dai[1].val);
        LOG_I(NR_MAC,"dci_pdu_rel15->tpc = %i\n", dci_pdu_rel15->tpc);
        LOG_I(NR_MAC,"dci_pdu_rel15->srs_resource_indicator.val = %i\n", dci_pdu_rel15->srs_resource_indicator.val);
        LOG_I(NR_MAC,"dci_pdu_rel15->precoding_information.val = %i\n", dci_pdu_rel15->precoding_information.val);
        LOG_I(NR_MAC,"dci_pdu_rel15->antenna_ports.val = %i\n", dci_pdu_rel15->antenna_ports.val);
        LOG_I(NR_MAC,"dci_pdu_rel15->srs_request.val = %i\n", dci_pdu_rel15->srs_request.val);
        LOG_I(NR_MAC,"dci_pdu_rel15->csi_request.val = %i\n", dci_pdu_rel15->csi_request.val);
        LOG_I(NR_MAC,"dci_pdu_rel15->cbgti.val = %i\n", dci_pdu_rel15->cbgti.val);
        LOG_I(NR_MAC,"dci_pdu_rel15->ptrs_dmrs_association.val = %i\n", dci_pdu_rel15->ptrs_dmrs_association.val);
        LOG_I(NR_MAC,"dci_pdu_rel15->beta_offset_indicator.val = %i\n", dci_pdu_rel15->beta_offset_indicator.val);
        LOG_I(NR_MAC,"dci_pdu_rel15->dmrs_sequence_initialization.val = %i\n", dci_pdu_rel15->dmrs_sequence_initialization.val);
        LOG_I(NR_MAC,"dci_pdu_rel15->ulsch_indicator = %i\n", dci_pdu_rel15->ulsch_indicator);
#endif

        break;
1679
    }
1680 1681 1682 1683
    break;

  case NR_DL_DCI_FORMAT_1_1:
    // Indicating a DL DCI format 1bit
1684
    LOG_D(NR_MAC,"Filling Format 1_1 DCI of size %d\n",dci_size);
1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764
    pos = 1;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator & 0x1) << (dci_size - pos);
    // Carrier indicator
    pos += dci_pdu_rel15->carrier_indicator.nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->carrier_indicator.val & ((1 << dci_pdu_rel15->carrier_indicator.nbits) - 1)) << (dci_size - pos);
    // BWP indicator
    pos += dci_pdu_rel15->bwp_indicator.nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->bwp_indicator.val & ((1 << dci_pdu_rel15->bwp_indicator.nbits) - 1)) << (dci_size - pos);
    // Frequency domain resource assignment
    pos += dci_pdu_rel15->frequency_domain_assignment.nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val & ((1 << dci_pdu_rel15->frequency_domain_assignment.nbits) - 1)) << (dci_size - pos);
    // Time domain resource assignment
    pos += dci_pdu_rel15->time_domain_assignment.nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->time_domain_assignment.val & ((1 << dci_pdu_rel15->time_domain_assignment.nbits) - 1)) << (dci_size - pos);
    // VRB-to-PRB mapping
    pos += dci_pdu_rel15->vrb_to_prb_mapping.nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val & ((1 << dci_pdu_rel15->vrb_to_prb_mapping.nbits) - 1)) << (dci_size - pos);
    // PRB bundling size indicator
    pos += dci_pdu_rel15->prb_bundling_size_indicator.nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->prb_bundling_size_indicator.val & ((1 << dci_pdu_rel15->prb_bundling_size_indicator.nbits) - 1)) << (dci_size - pos);
    // Rate matching indicator
    pos += dci_pdu_rel15->rate_matching_indicator.nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->rate_matching_indicator.val & ((1 << dci_pdu_rel15->rate_matching_indicator.nbits) - 1)) << (dci_size - pos);
    // ZP CSI-RS trigger
    pos += dci_pdu_rel15->zp_csi_rs_trigger.nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->zp_csi_rs_trigger.val & ((1 << dci_pdu_rel15->zp_csi_rs_trigger.nbits) - 1)) << (dci_size - pos);
    // TB1
    // MCS 5bit
    pos += 5;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->mcs & 0x1f) << (dci_size - pos);
    // New data indicator 1bit
    pos += 1;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi & 0x1) << (dci_size - pos);
    // Redundancy version  2bit
    pos += 2;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->rv & 0x3) << (dci_size - pos);
    // TB2
    // MCS 5bit
    pos += dci_pdu_rel15->mcs2.nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->mcs2.val & ((1 << dci_pdu_rel15->mcs2.nbits) - 1)) << (dci_size - pos);
    // New data indicator 1bit
    pos += dci_pdu_rel15->ndi2.nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi2.val & ((1 << dci_pdu_rel15->ndi2.nbits) - 1)) << (dci_size - pos);
    // Redundancy version  2bit
    pos += dci_pdu_rel15->rv2.nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->rv2.val & ((1 << dci_pdu_rel15->rv2.nbits) - 1)) << (dci_size - pos);
    // HARQ process number  4bit
    pos += 4;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->harq_pid & 0xf) << (dci_size - pos);
    // Downlink assignment index
    pos += dci_pdu_rel15->dai[0].nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->dai[0].val & ((1 << dci_pdu_rel15->dai[0].nbits) - 1)) << (dci_size - pos);
    // TPC command for scheduled PUCCH  2bit
    pos += 2;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->tpc & 0x3) << (dci_size - pos);
    // PUCCH resource indicator  3bit
    pos += 3;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->pucch_resource_indicator & 0x7) << (dci_size - pos);
    // PDSCH-to-HARQ_feedback timing indicator
    pos += dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val & ((1 << dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.nbits) - 1)) << (dci_size - pos);
    // Antenna ports
    pos += dci_pdu_rel15->antenna_ports.nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->antenna_ports.val & ((1 << dci_pdu_rel15->antenna_ports.nbits) - 1)) << (dci_size - pos);
    // TCI
    pos += dci_pdu_rel15->transmission_configuration_indication.nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->transmission_configuration_indication.val & ((1 << dci_pdu_rel15->transmission_configuration_indication.nbits) - 1)) << (dci_size - pos);
    // SRS request
    pos += dci_pdu_rel15->srs_request.nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->srs_request.val & ((1 << dci_pdu_rel15->srs_request.nbits) - 1)) << (dci_size - pos);
    // CBG transmission information
    pos += dci_pdu_rel15->cbgti.nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->cbgti.val & ((1 << dci_pdu_rel15->cbgti.nbits) - 1)) << (dci_size - pos);
    // CBG flushing out information
    pos += dci_pdu_rel15->cbgfi.nbits;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->cbgfi.val & ((1 << dci_pdu_rel15->cbgfi.nbits) - 1)) << (dci_size - pos);
    // DMRS sequence init
    pos += 1;
    *dci_pdu |= ((uint64_t)dci_pdu_rel15->dmrs_sequence_initialization.val & 0x1) << (dci_size - pos);
  }
1765
  LOG_D(NR_MAC, "DCI has %d bits and the payload is %lx\n", dci_size, *dci_pdu);
1766 1767
}

1768
int get_spf(nfapi_nr_config_request_scf_t *cfg) {
1769

1770
  int mu = cfg->ssb_config.scs_common.value;
1771 1772 1773 1774 1775
  AssertFatal(mu>=0&&mu<4,"Illegal scs %d\n",mu);

  return(10 * (1<<mu));
} 

1776
int to_absslot(nfapi_nr_config_request_scf_t *cfg,int frame,int slot) {
1777 1778 1779 1780

  return(get_spf(cfg)*frame) + slot; 

}
1781

1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796
int extract_startSymbol(int startSymbolAndLength) {
  int tmp = startSymbolAndLength/14;
  int tmp2 = startSymbolAndLength%14;

  if (tmp > 0 && tmp < (14-tmp2)) return(tmp2);
  else                            return(13-tmp2);
}

int extract_length(int startSymbolAndLength) {
  int tmp = startSymbolAndLength/14;
  int tmp2 = startSymbolAndLength%14;

  if (tmp > 0 && tmp < (14-tmp2)) return(tmp);
  else                            return(15-tmp2);
}
1797 1798

/*
1799
 * Dump the UL or DL UE_info into LOG_T(MAC)
1800
 */
Laurent THOMAS's avatar
Laurent THOMAS committed
1801
void dump_nr_list(NR_UE_info_t **list)
1802
{
Laurent THOMAS's avatar
Laurent THOMAS committed
1803 1804 1805
  UE_iterator(list, UE) {
    LOG_T(NR_MAC, "NR list UEs rntis %04x\n", (*list)->rnti);
  }
1806 1807 1808 1809 1810 1811 1812 1813
}

/*
 * Create a new NR_list
 */
void create_nr_list(NR_list_t *list, int len)
{
  list->head = -1;
1814
  list->next = malloc(len * sizeof(*list->next));
Robert Schmidt's avatar
Robert Schmidt committed
1815
  AssertFatal(list->next, "cannot malloc() memory for NR_list_t->next\n");
1816 1817 1818 1819
  for (int i = 0; i < len; ++i)
    list->next[i] = -1;
  list->tail = -1;
  list->len = len;
1820 1821
}

1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852
/*
 * Resize an NR_list
 */
void resize_nr_list(NR_list_t *list, int new_len)
{
  if (new_len == list->len)
    return;
  if (new_len > list->len) {
    /* list->head remains */
    const int old_len = list->len;
    int* n = realloc(list->next, new_len * sizeof(*list->next));
    AssertFatal(n, "cannot realloc() memory for NR_list_t->next\n");
    list->next = n;
    for (int i = old_len; i < new_len; ++i)
      list->next[i] = -1;
    /* list->tail remains */
    list->len = new_len;
  } else { /* new_len < len */
    AssertFatal(list->head < new_len, "shortened list head out of index %d (new len %d)\n", list->head, new_len);
    AssertFatal(list->tail < new_len, "shortened list tail out of index %d (new len %d)\n", list->head, new_len);
    for (int i = 0; i < list->len; ++i)
      AssertFatal(list->next[i] < new_len, "shortened list entry out of index %d (new len %d)\n", list->next[i], new_len);
    /* list->head remains */
    int *n = realloc(list->next, new_len * sizeof(*list->next));
    AssertFatal(n, "cannot realloc() memory for NR_list_t->next\n");
    list->next = n;
    /* list->tail remains */
    list->len = new_len;
  }
}

Robert Schmidt's avatar
Robert Schmidt committed
1853
/*
1854
 * Destroy an NR_list
Robert Schmidt's avatar
Robert Schmidt committed
1855
 */
1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867
void destroy_nr_list(NR_list_t *list)
{
  free(list->next);
}

/*
 * Add an ID to an NR_list at the end, traversing the whole list. Note:
 * add_tail_nr_list() is a faster alternative, but this implementation ensures
 * we do not add an existing ID.
 */
void add_nr_list(NR_list_t *listP, int id)
{
Robert Schmidt's avatar
Robert Schmidt committed
1868 1869
  int *cur = &listP->head;
  while (*cur >= 0) {
1870
    AssertFatal(*cur != id, "id %d already in NR_UE_list!\n", id);
Robert Schmidt's avatar
Robert Schmidt committed
1871 1872
    cur = &listP->next[*cur];
  }
1873 1874 1875
  *cur = id;
  if (listP->next[id] < 0)
    listP->tail = id;
1876 1877
}

1878
/*
1879
 * Remove an ID from an NR_list
1880
 */
1881 1882
void remove_nr_list(NR_list_t *listP, int id)
{
1883
  int *cur = &listP->head;
1884 1885 1886
  int *prev = &listP->head;
  while (*cur != -1 && *cur != id) {
    prev = cur;
1887
    cur = &listP->next[*cur];
1888
  }
Laurent THOMAS's avatar
Laurent THOMAS committed
1889
  AssertFatal(*cur != -1, "ID %d not found in UE_list\n", id);
1890 1891 1892
  int *next = &listP->next[*cur];
  *cur = listP->next[*cur];
  *next = -1;
1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931
  listP->tail = *prev >= 0 && listP->next[*prev] >= 0 ? listP->tail : *prev;
}

/*
 * Add an ID to the tail of the NR_list in O(1). Note that there is
 * corresponding remove_tail_nr_list(), as we cannot set the tail backwards and
 * therefore need to go through the whole list (use remove_nr_list())
 */
void add_tail_nr_list(NR_list_t *listP, int id)
{
  int *last = listP->tail < 0 ? &listP->head : &listP->next[listP->tail];
  *last = id;
  listP->next[id] = -1;
  listP->tail = id;
}

/*
 * Add an ID to the front of the NR_list in O(1)
 */
void add_front_nr_list(NR_list_t *listP, int id)
{
  const int ohead = listP->head;
  listP->head = id;
  listP->next[id] = ohead;
  if (listP->tail < 0)
    listP->tail = id;
}

/*
 * Remove an ID from the front of the NR_list in O(1)
 */
void remove_front_nr_list(NR_list_t *listP)
{
  AssertFatal(listP->head >= 0, "Nothing to remove\n");
  const int ohead = listP->head;
  listP->head = listP->next[ohead];
  listP->next[ohead] = -1;
  if (listP->head < 0)
    listP->tail = -1;
1932 1933
}

1934
NR_UE_info_t *find_nr_UE(NR_UEs_t *UEs, rnti_t rntiP)
1935
{
1936

Laurent THOMAS's avatar
Laurent THOMAS committed
1937 1938 1939 1940
  UE_iterator(UEs->list, UE) {
    if (UE->rnti == rntiP) {
      LOG_D(NR_MAC,"Search and found rnti: %04x\n", rntiP);
      return UE;
1941 1942
    }
  }
Laurent THOMAS's avatar
Laurent THOMAS committed
1943
  return NULL;
1944
}
cig's avatar
cig committed
1945

1946
int find_nr_RA_id(module_id_t mod_idP, int CC_idP, rnti_t rntiP) {
kn.raju's avatar
kn.raju committed
1947 1948 1949 1950 1951
//------------------------------------------------------------------------------
  int RA_id;
  RA_t *ra = (RA_t *) &RC.nrmac[mod_idP]->common_channels[CC_idP].ra[0];

  for (RA_id = 0; RA_id < NB_RA_PROC_MAX; RA_id++) {
1952
    LOG_D(NR_MAC, "Checking RA_id %d for %x : state %d\n",
kn.raju's avatar
kn.raju committed
1953 1954 1955 1956 1957 1958 1959 1960 1961 1962
          RA_id,
          rntiP,
          ra[RA_id].state);

    if (ra[RA_id].state != IDLE && ra[RA_id].rnti == rntiP)
      return RA_id;
  }

  return -1;
}
1963

1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983
int get_nrofHARQ_ProcessesForPDSCH(e_NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH n)
{
  switch (n) {
  case NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH_n2:
    return 2;
  case NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH_n4:
    return 4;
  case NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH_n6:
    return 6;
  case NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH_n10:
    return 10;
  case NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH_n12:
    return 12;
  case NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH_n16:
    return 16;
  default:
    return 8;
  }
}

1984
void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr, uid_allocator_t *uia)
Laurent THOMAS's avatar
Laurent THOMAS committed
1985 1986 1987 1988 1989 1990 1991 1992
{
  NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
  destroy_nr_list(&sched_ctrl->available_dl_harq);
  destroy_nr_list(&sched_ctrl->feedback_dl_harq);
  destroy_nr_list(&sched_ctrl->retrans_dl_harq);
  destroy_nr_list(&sched_ctrl->available_ul_harq);
  destroy_nr_list(&sched_ctrl->feedback_ul_harq);
  destroy_nr_list(&sched_ctrl->retrans_ul_harq);
1993
  uid_linear_allocator_free(uia, UE->uid);
Laurent THOMAS's avatar
Laurent THOMAS committed
1994 1995 1996 1997
  LOG_I(NR_MAC, "Remove NR rnti 0x%04x\n", UE->rnti);
  free(UE);
}

francescomani's avatar
francescomani committed
1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011

void set_max_fb_time(NR_UE_UL_BWP_t *UL_BWP, const NR_UE_DL_BWP_t *DL_BWP)
{
  UL_BWP->max_fb_time = 8; // default value
  // take the maximum in dl_DataToUL_ACK list
  if (DL_BWP->dci_format != NR_DL_DCI_FORMAT_1_0 && UL_BWP->pucch_Config) {
    const struct NR_PUCCH_Config__dl_DataToUL_ACK *fb_times = UL_BWP->pucch_Config->dl_DataToUL_ACK;
    for (int i = 0; i < fb_times->list.count; i++) {
      if(*fb_times->list.array[i] > UL_BWP->max_fb_time)
        UL_BWP->max_fb_time = *fb_times->list.array[i];
    }
  }
}

2012 2013 2014 2015 2016 2017 2018
void reset_sched_ctrl(NR_UE_sched_ctrl_t *sched_ctrl)
{
  sched_ctrl->srs_feedback.ul_ri = 0;
  sched_ctrl->srs_feedback.tpmi = 0;
  sched_ctrl->srs_feedback.sri = 0;
}

2019
// main function to configure parameters of current BWP
2020
void configure_UE_BWP(gNB_MAC_INST *nr_mac,
2021
                      NR_ServingCellConfigCommon_t *scc,
2022
                      NR_UE_sched_ctrl_t *sched_ctrl,
2023
                      NR_RA_t *ra,
2024 2025 2026 2027
                      NR_UE_info_t *UE,
                      int dl_bwp_switch,
                      int ul_bwp_switch)
{
2028 2029
  AssertFatal((ra != NULL && UE == NULL) || (ra == NULL && UE != NULL), "RA and UE structures are mutually exlusive in BWP configuration\n");

2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041
  NR_CellGroupConfig_t *CellGroup;
  NR_UE_DL_BWP_t *DL_BWP;
  NR_UE_UL_BWP_t *UL_BWP;

  if (ra) {
    DL_BWP = &ra->DL_BWP;
    UL_BWP = &ra->UL_BWP;
    CellGroup = ra->CellGroup;
  }
  else {
    DL_BWP = &UE->current_DL_BWP;
    UL_BWP = &UE->current_UL_BWP;
2042 2043
    sched_ctrl->next_dl_bwp_id = -1;
    sched_ctrl->next_ul_bwp_id = -1;
2044 2045
    CellGroup = UE->CellGroup;
  }
2046 2047
  NR_BWP_Downlink_t *dl_bwp = NULL;
  NR_BWP_Uplink_t *ul_bwp = NULL;
2048 2049
  NR_BWP_DownlinkDedicated_t *bwpd = NULL;
  NR_BWP_UplinkDedicated_t *ubwpd = NULL;
francescomani's avatar
fixes  
francescomani committed
2050 2051 2052
  // number of additional BWPs (excluding initial BWP)
  DL_BWP->n_dl_bwp = 0;
  UL_BWP->n_ul_bwp = 0;
2053
  int old_dl_bwp_id = DL_BWP->bwp_id;
francescomani's avatar
francescomani committed
2054
  int old_ul_bwp_id = UL_BWP->bwp_id;
2055 2056

  int target_ss;
2057

2058
  if (CellGroup && CellGroup->physicalCellGroupConfig)
2059 2060
    DL_BWP->pdsch_HARQ_ACK_Codebook = &CellGroup->physicalCellGroupConfig->pdsch_HARQ_ACK_Codebook;

2061 2062 2063
  if (CellGroup &&
      CellGroup->spCellConfig &&
      CellGroup->spCellConfig->spCellConfigDedicated) {
2064

2065
    const NR_ServingCellConfig_t *servingCellConfig = CellGroup->spCellConfig->spCellConfigDedicated;
2066
    DL_BWP->pdsch_servingcellconfig = servingCellConfig->pdsch_ServingCellConfig ? servingCellConfig->pdsch_ServingCellConfig->choice.setup : NULL;
francescomani's avatar
francescomani committed
2067 2068
    UL_BWP->pusch_servingcellconfig = servingCellConfig->uplinkConfig && servingCellConfig->uplinkConfig->pusch_ServingCellConfig ?
                                      servingCellConfig->uplinkConfig->pusch_ServingCellConfig->choice.setup : NULL;
2069

2070
    target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
2071

2072 2073 2074 2075
    if(dl_bwp_switch >= 0 && ul_bwp_switch >= 0) {
      AssertFatal(dl_bwp_switch == ul_bwp_switch, "Different UL and DL BWP not supported\n");
      DL_BWP->bwp_id = dl_bwp_switch;
      UL_BWP->bwp_id = ul_bwp_switch;
2076 2077 2078 2079 2080 2081 2082 2083 2084 2085
    }
    else {
      // (re)configuring BWP
      // TODO BWP switching not via RRC reconfiguration
      // via RRC if firstActiveXlinkBWP_Id is NULL, MAC stays on the same BWP as before
      if (servingCellConfig->firstActiveDownlinkBWP_Id)
        DL_BWP->bwp_id = *servingCellConfig->firstActiveDownlinkBWP_Id;
      if (servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id)
        UL_BWP->bwp_id = *servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id;
    }
2086 2087

    const struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList = servingCellConfig->downlinkBWP_ToAddModList;
francescomani's avatar
francescomani committed
2088
    if(bwpList)
2089 2090
      DL_BWP->n_dl_bwp = bwpList->list.count;
    if (DL_BWP->bwp_id>0) {
2091
      for (int i=0; i<bwpList->list.count; i++) {
2092
        dl_bwp = bwpList->list.array[i];
2093
        if(dl_bwp->bwp_Id == DL_BWP->bwp_id)
2094 2095
          break;
      }
2096
      AssertFatal(dl_bwp!=NULL,"Couldn't find DLBWP corresponding to BWP ID %ld\n",DL_BWP->bwp_id);
2097 2098 2099
    }

    const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList;
francescomani's avatar
francescomani committed
2100 2101
    if(ubwpList)
      UL_BWP->n_ul_bwp = ubwpList->list.count;
2102
    if (UL_BWP->bwp_id>0) {
2103
      for (int i=0; i<ubwpList->list.count; i++) {
2104
        ul_bwp = ubwpList->list.array[i];
2105
        if(ul_bwp->bwp_Id == UL_BWP->bwp_id)
2106 2107
          break;
      }
francescomani's avatar
francescomani committed
2108
      AssertFatal(ul_bwp!=NULL,"Couldn't find ULBWP corresponding to BWP ID %ld\n",UL_BWP->bwp_id);
2109
    }
2110 2111 2112 2113 2114 2115 2116 2117 2118 2119

    // selection of dedicated BWPs
    if(dl_bwp)
      bwpd = dl_bwp->bwp_Dedicated;
    else
      bwpd = servingCellConfig->initialDownlinkBWP;
    if(ul_bwp)
      ubwpd = ul_bwp->bwp_Dedicated;
    else
      ubwpd = servingCellConfig->uplinkConfig->initialUplinkBWP;
francescomani's avatar
francescomani committed
2120

2121
    DL_BWP->pdsch_Config = bwpd->pdsch_Config->choice.setup;
2122
    UL_BWP->configuredGrantConfig = ubwpd->configuredGrantConfig ? ubwpd->configuredGrantConfig->choice.setup : NULL;
2123
    UL_BWP->pusch_Config = ubwpd->pusch_Config->choice.setup;
francescomani's avatar
francescomani committed
2124
    UL_BWP->pucch_Config = ubwpd->pucch_Config->choice.setup;
2125 2126
    UL_BWP->srs_Config = ubwpd->srs_Config->choice.setup;
    UL_BWP->csi_MeasConfig = servingCellConfig->csi_MeasConfig ? servingCellConfig->csi_MeasConfig->choice.setup : NULL;
2127 2128
  }
  else {
2129
    DL_BWP->bwp_id = 0;
2130
    UL_BWP->bwp_id = 0;
2131
    target_ss = NR_SearchSpace__searchSpaceType_PR_common;
2132
    DL_BWP->pdsch_Config = NULL;
2133
    UL_BWP->pusch_Config = NULL;
francescomani's avatar
francescomani committed
2134
    UL_BWP->pucch_Config = NULL;
2135
    UL_BWP->csi_MeasConfig = NULL;
2136
    UL_BWP->configuredGrantConfig = NULL;
2137
  }
2138

2139 2140
  if (old_dl_bwp_id != DL_BWP->bwp_id)
    LOG_I(NR_MAC, "Switching to DL-BWP %li\n", DL_BWP->bwp_id);
francescomani's avatar
francescomani committed
2141 2142
  if (old_ul_bwp_id != UL_BWP->bwp_id)
    LOG_I(NR_MAC, "Switching to UL-BWP %li\n", UL_BWP->bwp_id);
francescomani's avatar
francescomani committed
2143

2144
  // TDA lists
2145
  if (DL_BWP->bwp_id>0)
2146
    DL_BWP->tdaList_Common = dl_bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList;
francescomani's avatar
francescomani committed
2147
  else
2148
    DL_BWP->tdaList_Common = scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList;
francescomani's avatar
francescomani committed
2149

2150
  if(UL_BWP->bwp_id>0)
2151
    UL_BWP->tdaList_Common = ul_bwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList;
2152
  else
2153
    UL_BWP->tdaList_Common = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList;
2154

2155
  // setting generic parameters
2156
  NR_BWP_t dl_genericParameters = (DL_BWP->bwp_id > 0 && dl_bwp) ?
2157 2158 2159
    dl_bwp->bwp_Common->genericParameters:
    scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters;

2160 2161 2162 2163
  DL_BWP->scs = dl_genericParameters.subcarrierSpacing;
  DL_BWP->cyclicprefix = dl_genericParameters.cyclicPrefix;
  DL_BWP->BWPSize = NRRIV2BW(dl_genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
  DL_BWP->BWPStart = NRRIV2PRBOFFSET(dl_genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
2164 2165
  DL_BWP->initial_BWPSize = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
  DL_BWP->initial_BWPStart = NRRIV2PRBOFFSET(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
2166

2167
  NR_BWP_t ul_genericParameters = (UL_BWP->bwp_id > 0 && ul_bwp) ?
2168 2169 2170
    ul_bwp->bwp_Common->genericParameters:
    scc->uplinkConfigCommon->initialUplinkBWP->genericParameters;

2171 2172 2173 2174
  UL_BWP->scs = ul_genericParameters.subcarrierSpacing;
  UL_BWP->cyclicprefix = ul_genericParameters.cyclicPrefix;
  UL_BWP->BWPSize = NRRIV2BW(ul_genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
  UL_BWP->BWPStart = NRRIV2PRBOFFSET(ul_genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
2175 2176
  UL_BWP->initial_BWPSize = NRRIV2BW(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
  UL_BWP->initial_BWPStart = NRRIV2PRBOFFSET(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
2177

2178
  if (UL_BWP->bwp_id > 0) {
2179 2180
    UL_BWP->pucch_ConfigCommon = ul_bwp->bwp_Common->pucch_ConfigCommon ? ul_bwp->bwp_Common->pucch_ConfigCommon->choice.setup : NULL;
    UL_BWP->rach_ConfigCommon = ul_bwp->bwp_Common->rach_ConfigCommon ? ul_bwp->bwp_Common->rach_ConfigCommon->choice.setup : NULL;
2181
  } else {
francescomani's avatar
francescomani committed
2182
    UL_BWP->pucch_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup;
2183 2184
    UL_BWP->rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
  }
francescomani's avatar
francescomani committed
2185

2186
  if(UE) {
2187 2188 2189 2190

    // Reset required fields in sched_ctrl (e.g. ul_ri and tpmi)
    reset_sched_ctrl(sched_ctrl);

2191
    // setting PDCCH related structures for sched_ctrl
2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204
    sched_ctrl->search_space = get_searchspace(scc,
                                               bwpd,
                                               target_ss);
    sched_ctrl->coreset = get_coreset(nr_mac,
                                      scc,
                                      bwpd,
                                      sched_ctrl->search_space,
                                      target_ss);

    sched_ctrl->sched_pdcch = set_pdcch_structure(nr_mac,
                                                  sched_ctrl->search_space,
                                                  sched_ctrl->coreset,
                                                  scc,
2205
                                                  &dl_genericParameters,
2206
                                                  nr_mac->type0_PDCCH_CSS_config);
2207

2208 2209 2210 2211 2212 2213
    // set DL DCI format
    DL_BWP->dci_format = (sched_ctrl->search_space->searchSpaceType &&
                         sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) ?
                         (sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats == NR_SearchSpace__searchSpaceType__ue_Specific__dci_Formats_formats0_1_And_1_1 ?
                         NR_DL_DCI_FORMAT_1_1 : NR_DL_DCI_FORMAT_1_0) :
                         NR_DL_DCI_FORMAT_1_0;
2214 2215 2216 2217 2218 2219 2220
    // set UL DCI format
    UL_BWP->dci_format = (sched_ctrl->search_space->searchSpaceType &&
                         sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) ?
                         (sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats == NR_SearchSpace__searchSpaceType__ue_Specific__dci_Formats_formats0_1_And_1_1 ?
                         NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0) :
                         NR_UL_DCI_FORMAT_0_0;

2221
    if (UL_BWP->csi_MeasConfig)
2222
      compute_csi_bitlen (UL_BWP->csi_MeasConfig, UE->csi_report_template);
francescomani's avatar
francescomani committed
2223

francescomani's avatar
francescomani committed
2224
    set_max_fb_time(UL_BWP, DL_BWP);
2225
    set_sched_pucch_list(sched_ctrl, UL_BWP, scc);
2226
  }
2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253

  if(ra) {
    // setting PDCCH related structures for RA
    struct NR_PDCCH_ConfigCommon__commonSearchSpaceList *commonSearchSpaceList = NULL;
    NR_SearchSpaceId_t ra_SearchSpace = 0;
    if(dl_bwp) {
      commonSearchSpaceList = dl_bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList;
      ra_SearchSpace = *dl_bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->ra_SearchSpace;
    } else {
      commonSearchSpaceList = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList;
      ra_SearchSpace = *scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->ra_SearchSpace;
    }
    AssertFatal(commonSearchSpaceList->list.count > 0, "common SearchSpace list has 0 elements\n");
    for (int i = 0; i < commonSearchSpaceList->list.count; i++) {
      NR_SearchSpace_t * ss = commonSearchSpaceList->list.array[i];
      if (ss->searchSpaceId == ra_SearchSpace)
        ra->ra_ss = ss;
    }
    AssertFatal(ra->ra_ss!=NULL,"SearchSpace cannot be null for RA\n");

    ra->coreset = get_coreset(nr_mac, scc, dl_bwp, ra->ra_ss, NR_SearchSpace__searchSpaceType_PR_common);
    ra->sched_pdcch = set_pdcch_structure(nr_mac,
                                          ra->ra_ss,
                                          ra->coreset,
                                          scc,
                                          &dl_genericParameters,
                                          &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]);
2254 2255

    UL_BWP->dci_format = NR_UL_DCI_FORMAT_0_0;
2256
    DL_BWP->dci_format = NR_DL_DCI_FORMAT_1_0;
2257
  }
2258

2259 2260 2261 2262
  // Set MCS tables
  long *dl_mcs_Table = DL_BWP->pdsch_Config ? DL_BWP->pdsch_Config->mcs_Table : NULL;
  DL_BWP->mcsTableIdx = get_pdsch_mcs_table(dl_mcs_Table, DL_BWP->dci_format, NR_RNTI_C, target_ss);

2263
  // 0 precoding enabled 1 precoding disabled
2264
  UL_BWP->transform_precoding = get_transformPrecoding(UL_BWP, UL_BWP->dci_format, 0);
2265 2266
  // Set uplink MCS table
  long *mcs_Table = NULL;
2267
  if (UL_BWP->pusch_Config)
2268
    mcs_Table = UL_BWP->transform_precoding ?
2269 2270
                UL_BWP->pusch_Config->mcs_Table :
                UL_BWP->pusch_Config->mcs_TableTransformPrecoder;
2271

2272
  UL_BWP->mcs_table = get_pusch_mcs_table(mcs_Table,
2273
                                          !UL_BWP->transform_precoding,
2274 2275 2276 2277
                                          UL_BWP->dci_format,
                                          NR_RNTI_C,
                                          target_ss,
                                          false);
2278

2279 2280
}

2281 2282 2283 2284 2285 2286
void reset_srs_stats(NR_UE_info_t *UE) {
  if (UE) {
    UE->mac_stats.srs_stats[0] = '\0';
  }
}

kn.raju's avatar
kn.raju committed
2287
//------------------------------------------------------------------------------
Laurent THOMAS's avatar
Laurent THOMAS committed
2288
NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConfig_t *CellGroup)
2289
{
2290
  NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels[0].ServingCellConfigCommon;
Laurent THOMAS's avatar
Laurent THOMAS committed
2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304
  NR_UEs_t *UE_info = &nr_mac->UE_info;
  LOG_I(NR_MAC, "Adding UE with rnti 0x%04x\n",
        rntiP);
  dump_nr_list(UE_info->list);

  // We will attach at the end, to mitigate race conditions
  // This is not good, but we will fix it progressively
  NR_UE_info_t *UE=calloc(1,sizeof(NR_UE_info_t));
  if(!UE) {
    LOG_E(NR_MAC,"want to add UE %04x but the fixed allocated size is full\n",rntiP);
    return NULL;
  }

  UE->rnti = rntiP;
2305
  UE->uid = uid_linear_allocator_new(&UE_info->uid_allocator);
Laurent THOMAS's avatar
Laurent THOMAS committed
2306 2307 2308 2309 2310 2311
  UE->CellGroup = CellGroup;

  if (CellGroup)
    UE->Msg4_ACKed = true;
  else
    UE->Msg4_ACKed = false;
2312

Laurent THOMAS's avatar
Laurent THOMAS committed
2313
  NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
2314 2315 2316 2317 2318 2319 2320
  memset(sched_ctrl, 0, sizeof(*sched_ctrl));
  sched_ctrl->dl_max_mcs = 28; /* do not limit MCS for individual UEs */
  sched_ctrl->ta_update = 31;
  sched_ctrl->sched_srs.frame = -1;
  sched_ctrl->sched_srs.slot = -1;

  // initialize UE BWP information
francescomani's avatar
francescomani committed
2321 2322 2323 2324
  NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP;
  memset(dl_bwp, 0, sizeof(*dl_bwp));
  NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
  memset(ul_bwp, 0, sizeof(*ul_bwp));
2325
  configure_UE_BWP(nr_mac, scc, sched_ctrl, NULL, UE, -1, -1);
2326 2327

  /* set illegal time domain allocation to force recomputation of all fields */
francescomani's avatar
francescomani committed
2328
  sched_ctrl->sched_pdsch.time_domain_allocation = -1;
francescomani's avatar
francescomani committed
2329
  sched_ctrl->sched_pusch.time_domain_allocation = -1;
2330

Laurent THOMAS's avatar
Laurent THOMAS committed
2331
  /* Set default BWPs */
2332 2333
  sched_ctrl->next_dl_bwp_id = -1;
  sched_ctrl->next_ul_bwp_id = -1;
francescomani's avatar
francescomani committed
2334
  AssertFatal(ul_bwp->n_ul_bwp <= NR_MAX_NUM_BWP,
2335
              "uplinkBWP_ToAddModList has %d BWP!\n",
francescomani's avatar
francescomani committed
2336
              ul_bwp->n_ul_bwp);
2337

2338 2339 2340
  if (get_softmodem_params()->phy_test == 0) {
    UE->ra_timer = 12000 << UE->current_DL_BWP.scs; // 12000 ms is arbitrary and found to be a good timeout from experiments
  }
2341

2342
  /* get Number of HARQ processes for this UE */
2343
  // pdsch_servingcellconfig == NULL in SA -> will create default (8) number of HARQ processes
francescomani's avatar
francescomani committed
2344
  create_dl_harq_list(sched_ctrl, dl_bwp->pdsch_servingcellconfig);
2345 2346 2347 2348 2349 2350 2351
  // add all available UL HARQ processes for this UE
  // nb of ul harq processes not configurable
  create_nr_list(&sched_ctrl->available_ul_harq, 16);
  for (int harq = 0; harq < 16; harq++)
    add_tail_nr_list(&sched_ctrl->available_ul_harq, harq);
  create_nr_list(&sched_ctrl->feedback_ul_harq, 16);
  create_nr_list(&sched_ctrl->retrans_ul_harq, 16);
Laurent THOMAS's avatar
Laurent THOMAS committed
2352

2353 2354
  reset_srs_stats(UE);

2355
  NR_SCHED_LOCK(&UE_info->mutex);
Laurent THOMAS's avatar
Laurent THOMAS committed
2356
  int i;
2357
  for(i=0; i<MAX_MOBILES_PER_GNB; i++) {
Laurent THOMAS's avatar
Laurent THOMAS committed
2358 2359 2360 2361
    if (UE_info->list[i] == NULL) {
      UE_info->list[i] = UE;
      break;
    }
2362
  }
Laurent THOMAS's avatar
Laurent THOMAS committed
2363 2364
  if (i == MAX_MOBILES_PER_GNB) {
    LOG_E(NR_MAC,"Try to add UE %04x but the list is full\n", rntiP);
2365
    delete_nr_ue_data(UE, nr_mac->common_channels, &UE_info->uid_allocator);
2366
    NR_SCHED_UNLOCK(&UE_info->mutex);
Laurent THOMAS's avatar
Laurent THOMAS committed
2367
    return NULL;
2368
  }
2369
  NR_SCHED_UNLOCK(&UE_info->mutex);
2370

Laurent THOMAS's avatar
Laurent THOMAS committed
2371 2372 2373
  LOG_D(NR_MAC, "Add NR rnti %x\n", rntiP);
  dump_nr_list(UE_info->list);
  return (UE);
2374
}
2375

2376
void set_sched_pucch_list(NR_UE_sched_ctrl_t *sched_ctrl,
francescomani's avatar
francescomani committed
2377 2378
                          const NR_UE_UL_BWP_t *ul_bwp,
                          const NR_ServingCellConfigCommon_t *scc) {
2379 2380 2381 2382 2383

  const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL;
  const int n_slots_frame = nr_slots_per_frame[ul_bwp->scs];
  const int nr_slots_period = tdd ? n_slots_frame / get_nb_periods_per_frame(tdd->dl_UL_TransmissionPeriodicity) : n_slots_frame;
  const int n_ul_slots_period = tdd ? tdd->nrofUplinkSlots + (tdd->nrofUplinkSymbols > 0 ? 1 : 0) : n_slots_frame;
francescomani's avatar
francescomani committed
2384 2385
  // PUCCH list size is given by the number of UL slots in the PUCCH period
  // the length PUCCH period is determined by max_fb_time since we may need to prepare PUCCH for ACK/NACK max_fb_time slots ahead
2386 2387
  const int list_size = n_ul_slots_period << (ul_bwp->max_fb_time/nr_slots_period);
  if(!sched_ctrl->sched_pucch) {
francescomani's avatar
francescomani committed
2388
    sched_ctrl->sched_pucch = calloc(list_size, sizeof(*sched_ctrl->sched_pucch));
2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400
    sched_ctrl->sched_pucch_size = list_size;
  }
  else if (list_size > sched_ctrl->sched_pucch_size) {
    sched_ctrl->sched_pucch = realloc(sched_ctrl->sched_pucch, list_size * sizeof(*sched_ctrl->sched_pucch));
    for(int i=sched_ctrl->sched_pucch_size; i<list_size; i++){
      NR_sched_pucch_t *curr_pucch = &sched_ctrl->sched_pucch[i];
      memset(curr_pucch, 0, sizeof(*curr_pucch));
    }
    sched_ctrl->sched_pucch_size = list_size;
  }
}

2401 2402 2403 2404 2405
void create_dl_harq_list(NR_UE_sched_ctrl_t *sched_ctrl,
                         const NR_PDSCH_ServingCellConfig_t *pdsch) {
  const int nrofHARQ = pdsch && pdsch->nrofHARQ_ProcessesForPDSCH ?
                       get_nrofHARQ_ProcessesForPDSCH(*pdsch->nrofHARQ_ProcessesForPDSCH) : 8;
  // add all available DL HARQ processes for this UE
2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417
  AssertFatal(sched_ctrl->available_dl_harq.len == sched_ctrl->feedback_dl_harq.len
              && sched_ctrl->available_dl_harq.len == sched_ctrl->retrans_dl_harq.len,
              "HARQ lists have different lengths (%d/%d/%d)\n",
              sched_ctrl->available_dl_harq.len,
              sched_ctrl->feedback_dl_harq.len,
              sched_ctrl->retrans_dl_harq.len);
  if (sched_ctrl->available_dl_harq.len == 0) {
    create_nr_list(&sched_ctrl->available_dl_harq, nrofHARQ);
    for (int harq = 0; harq < nrofHARQ; harq++)
      add_tail_nr_list(&sched_ctrl->available_dl_harq, harq);
    create_nr_list(&sched_ctrl->feedback_dl_harq, nrofHARQ);
    create_nr_list(&sched_ctrl->retrans_dl_harq, nrofHARQ);
2418 2419
  } else if (sched_ctrl->available_dl_harq.len == nrofHARQ) {
    LOG_D(NR_MAC, "nrofHARQ %d already configured\n", nrofHARQ);
2420
  } else {
2421 2422 2423 2424
    const int old_nrofHARQ = sched_ctrl->available_dl_harq.len;
    AssertFatal(nrofHARQ > old_nrofHARQ,
                "cannot resize HARQ list to be smaller (nrofHARQ %d, old_nrofHARQ %d)\n",
                nrofHARQ, old_nrofHARQ);
2425
    resize_nr_list(&sched_ctrl->available_dl_harq, nrofHARQ);
2426 2427
    for (int harq = old_nrofHARQ; harq < nrofHARQ; harq++)
      add_tail_nr_list(&sched_ctrl->available_dl_harq, harq);
2428 2429 2430
    resize_nr_list(&sched_ctrl->feedback_dl_harq, nrofHARQ);
    resize_nr_list(&sched_ctrl->retrans_dl_harq, nrofHARQ);
  }
2431 2432
}

2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444
void reset_dl_harq_list(NR_UE_sched_ctrl_t *sched_ctrl) {
  int harq;
  while ((harq = sched_ctrl->feedback_dl_harq.head) >= 0) {
    remove_front_nr_list(&sched_ctrl->feedback_dl_harq);
    add_tail_nr_list(&sched_ctrl->available_dl_harq, harq);
  }

  while ((harq = sched_ctrl->retrans_dl_harq.head) >= 0) {
    remove_front_nr_list(&sched_ctrl->retrans_dl_harq);
    add_tail_nr_list(&sched_ctrl->available_dl_harq, harq);
  }

francescomani's avatar
francescomani committed
2445
  for (int i = 0; i < NR_MAX_HARQ_PROCESSES; i++) {
2446 2447
    sched_ctrl->harq_processes[i].feedback_slot = -1;
    sched_ctrl->harq_processes[i].round = 0;
2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463
    sched_ctrl->harq_processes[i].is_waiting = false;
  }
}

void reset_ul_harq_list(NR_UE_sched_ctrl_t *sched_ctrl) {
  int harq;
  while ((harq = sched_ctrl->feedback_ul_harq.head) >= 0) {
    remove_front_nr_list(&sched_ctrl->feedback_ul_harq);
    add_tail_nr_list(&sched_ctrl->available_ul_harq, harq);
  }

  while ((harq = sched_ctrl->retrans_ul_harq.head) >= 0) {
    remove_front_nr_list(&sched_ctrl->retrans_ul_harq);
    add_tail_nr_list(&sched_ctrl->available_ul_harq, harq);
  }

francescomani's avatar
francescomani committed
2464
  for (int i = 0; i < NR_MAX_HARQ_PROCESSES; i++) {
2465 2466
    sched_ctrl->ul_harq_processes[i].feedback_slot = -1;
    sched_ctrl->ul_harq_processes[i].round = 0;
2467 2468 2469 2470
    sched_ctrl->ul_harq_processes[i].is_waiting = false;
  }
}

Laurent THOMAS's avatar
Laurent THOMAS committed
2471
void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti)
Cedric Roux's avatar
Cedric Roux committed
2472
{
2473 2474 2475
  /* already mutex protected */
  NR_SCHED_ENSURE_LOCKED(&nr_mac->sched_lock);

2476
  NR_UEs_t *UE_info = &nr_mac->UE_info;
2477
  NR_SCHED_LOCK(&UE_info->mutex);
2478 2479 2480 2481 2482 2483 2484
  UE_iterator(UE_info->list, UE) {
    if (UE->rnti==rnti)
      break;
  }

  if (!UE) {
    LOG_W(NR_MAC,"Call to del rnti %04x, but not existing\n", rnti);
2485
    NR_SCHED_UNLOCK(&UE_info->mutex);
2486 2487 2488 2489 2490 2491 2492 2493 2494
    return;
  }

  NR_UE_info_t * newUEs[MAX_MOBILES_PER_GNB+1]={0};
  int newListIdx=0;
  for (int i=0; i<MAX_MOBILES_PER_GNB; i++)
    if(UE_info->list[i] && UE_info->list[i]->rnti != rnti)
      newUEs[newListIdx++]=UE_info->list[i];
  memcpy(UE_info->list, newUEs, sizeof(UE_info->list));
2495
  NR_SCHED_UNLOCK(&UE_info->mutex);
2496 2497

  delete_nr_ue_data(UE, nr_mac->common_channels, &UE_info->uid_allocator);
Cedric Roux's avatar
Cedric Roux committed
2498
}
2499 2500 2501 2502 2503 2504

uint8_t nr_get_tpc(int target, uint8_t cqi, int incr) {
  // al values passed to this function are x10
  int snrx10 = (cqi*5) - 640;
  if (snrx10 > target + incr) return 0; // decrease 1dB
  if (snrx10 < target - (3*incr)) return 3; // increase 3dB
2505
  if (snrx10 < target - incr) return 2; // increase 1dB
2506
  LOG_D(NR_MAC,"tpc : target %d, snrx10 %d\n",target,snrx10);
2507 2508 2509 2510
  return 1; // no change
}


2511
int get_pdsch_to_harq_feedback(NR_PUCCH_Config_t *pucch_Config,
2512
                                nr_dci_format_t dci_format,
Francesco Mani's avatar
Francesco Mani committed
2513
                                uint8_t *pdsch_to_harq_feedback) {
2514
  /* already mutex protected: held in nr_acknack_scheduling() */
Francesco Mani's avatar
Francesco Mani committed
2515

2516
  if (dci_format == NR_DL_DCI_FORMAT_1_0) {
2517 2518 2519
    for (int i = 0; i < 8; i++)
      pdsch_to_harq_feedback[i] = i + 1;
    return 8;
Francesco Mani's avatar
Francesco Mani committed
2520 2521
  }
  else {
2522 2523 2524
    AssertFatal(pucch_Config != NULL && pucch_Config->dl_DataToUL_ACK != NULL,"dl_DataToUL_ACK shouldn't be null here\n");
    for (int i = 0; i < pucch_Config->dl_DataToUL_ACK->list.count; i++) {
      pdsch_to_harq_feedback[i] = *pucch_Config->dl_DataToUL_ACK->list.array[i];
Francesco Mani's avatar
Francesco Mani committed
2525
    }
2526
    return pucch_Config->dl_DataToUL_ACK->list.count;
Francesco Mani's avatar
Francesco Mani committed
2527 2528 2529
  }
}

2530 2531
void nr_csirs_scheduling(int Mod_idP, frame_t frame, sub_frame_t slot, int n_slots_frame, nfapi_nr_dl_tti_request_t *DL_req)
{
2532
  int CC_id = 0;
Laurent THOMAS's avatar
Laurent THOMAS committed
2533
  NR_UEs_t *UE_info = &RC.nrmac[Mod_idP]->UE_info;
2534
  gNB_MAC_INST *gNB_mac = RC.nrmac[Mod_idP];
2535 2536 2537

  NR_SCHED_ENSURE_LOCKED(&gNB_mac->sched_lock);

2538
  uint16_t *vrb_map = gNB_mac->common_channels[CC_id].vrb_map;
2539

2540
  UE_info->sched_csirs = 0;
francescomani's avatar
francescomani committed
2541

Laurent THOMAS's avatar
Laurent THOMAS committed
2542
  UE_iterator(UE_info->list, UE) {
2543 2544
    NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP;
    NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
2545

2546 2547 2548 2549 2550 2551
    // CSI-RS is common to all UEs in a given BWP
    // therefore we need to schedule only once per BWP
    // the following condition verifies if CSI-RS
    // has been already scheduled in this BWP
    if (UE_info->sched_csirs & (1 << dl_bwp->bwp_id))
      continue;
Laurent THOMAS's avatar
Laurent THOMAS committed
2552
    NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
2553 2554 2555
    if (sched_ctrl->rrc_processing_timer > 0) {
      continue;
    }
2556

francescomani's avatar
francescomani committed
2557
    if (!ul_bwp->csi_MeasConfig) continue;
2558

francescomani's avatar
francescomani committed
2559
    NR_CSI_MeasConfig_t *csi_measconfig = ul_bwp->csi_MeasConfig;
2560

2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573
    // looking for the correct CSI-RS resource in current BWP
    NR_NZP_CSI_RS_ResourceSetId_t *nzp = NULL;
    for (int csi_list=0; csi_list<csi_measconfig->csi_ResourceConfigToAddModList->list.count; csi_list++) {
      NR_CSI_ResourceConfig_t *csires = csi_measconfig->csi_ResourceConfigToAddModList->list.array[csi_list];
      if(csires->bwp_Id == dl_bwp->bwp_id &&
         csires->csi_RS_ResourceSetList.present == NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB &&
         csires->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList) {
        nzp = csires->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.array[0];
      }
    }

    if (csi_measconfig->nzp_CSI_RS_ResourceToAddModList != NULL &&
        nzp != NULL) {
2574

2575 2576
      NR_NZP_CSI_RS_Resource_t *nzpcsi;
      int period, offset;
2577

2578
      nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body;
Laurent THOMAS's avatar
Laurent THOMAS committed
2579

2580 2581
      for (int id = 0; id < csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.count; id++){
        nzpcsi = csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.array[id];
2582 2583 2584 2585
        // transmitting CSI-RS only for current BWP
        if (nzpcsi->nzp_CSI_RS_ResourceId != *nzp)
          continue;

2586
        NR_CSI_RS_ResourceMapping_t  resourceMapping = nzpcsi->resourceMapping;
francescomani's avatar
francescomani committed
2587
        csi_period_offset(NULL,nzpcsi->periodicityAndOffset,&period,&offset);
2588

2589
        if((frame*n_slots_frame+slot-offset)%period == 0) {
2590

2591 2592 2593
          LOG_D(NR_MAC,"Scheduling CSI-RS in frame %d slot %d Resource ID %ld\n",
                frame, slot, nzpcsi->nzp_CSI_RS_ResourceId);
          UE_info->sched_csirs |= (1 << dl_bwp->bwp_id);
2594

2595 2596 2597 2598
          nfapi_nr_dl_tti_request_pdu_t *dl_tti_csirs_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs];
          memset((void*)dl_tti_csirs_pdu,0,sizeof(nfapi_nr_dl_tti_request_pdu_t));
          dl_tti_csirs_pdu->PDUType = NFAPI_NR_DL_TTI_CSI_RS_PDU_TYPE;
          dl_tti_csirs_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_csi_rs_pdu));
2599

2600 2601
          nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *csirs_pdu_rel15 = &dl_tti_csirs_pdu->csi_rs_pdu.csi_rs_pdu_rel15;

francescomani's avatar
francescomani committed
2602 2603 2604
          csirs_pdu_rel15->subcarrier_spacing = dl_bwp->scs;
          if (dl_bwp->cyclicprefix)
            csirs_pdu_rel15->cyclic_prefix = *dl_bwp->cyclicprefix;
2605 2606 2607
          else
            csirs_pdu_rel15->cyclic_prefix = 0;

2608
          // According to last paragraph of TS 38.214 5.2.2.3.1
francescomani's avatar
francescomani committed
2609 2610
          if (resourceMapping.freqBand.startingRB < dl_bwp->BWPStart) {
            csirs_pdu_rel15->start_rb = dl_bwp->BWPStart;
2611 2612 2613
          } else {
            csirs_pdu_rel15->start_rb = resourceMapping.freqBand.startingRB;
          }
francescomani's avatar
francescomani committed
2614 2615
          if (resourceMapping.freqBand.nrofRBs > (dl_bwp->BWPStart + dl_bwp->BWPSize - csirs_pdu_rel15->start_rb)) {
            csirs_pdu_rel15->nr_of_rbs = dl_bwp->BWPStart + dl_bwp->BWPSize - csirs_pdu_rel15->start_rb;
2616 2617 2618 2619 2620
          } else {
            csirs_pdu_rel15->nr_of_rbs = resourceMapping.freqBand.nrofRBs;
          }
          AssertFatal(csirs_pdu_rel15->nr_of_rbs >= 24, "CSI-RS has %d RBs, but the minimum is 24\n", csirs_pdu_rel15->nr_of_rbs);

2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640
          csirs_pdu_rel15->csi_type = 1; // NZP-CSI-RS
          csirs_pdu_rel15->symb_l0 = resourceMapping.firstOFDMSymbolInTimeDomain;
          if (resourceMapping.firstOFDMSymbolInTimeDomain2)
            csirs_pdu_rel15->symb_l1 = *resourceMapping.firstOFDMSymbolInTimeDomain2;
          csirs_pdu_rel15->cdm_type = resourceMapping.cdm_Type;
          csirs_pdu_rel15->freq_density = resourceMapping.density.present;
          if ((resourceMapping.density.present == NR_CSI_RS_ResourceMapping__density_PR_dot5)
              && (resourceMapping.density.choice.dot5 == NR_CSI_RS_ResourceMapping__density__dot5_evenPRBs))
            csirs_pdu_rel15->freq_density--;
          csirs_pdu_rel15->scramb_id = nzpcsi->scramblingID;
          csirs_pdu_rel15->power_control_offset = nzpcsi->powerControlOffset + 8;
          if (nzpcsi->powerControlOffsetSS)
            csirs_pdu_rel15->power_control_offset_ss = *nzpcsi->powerControlOffsetSS;
          else
            csirs_pdu_rel15->power_control_offset_ss = 1; // 0 dB
          switch(resourceMapping.frequencyDomainAllocation.present){
            case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row1:
              csirs_pdu_rel15->row = 1;
              csirs_pdu_rel15->freq_domain = ((resourceMapping.frequencyDomainAllocation.choice.row1.buf[0])>>4)&0x0f;
              for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++)
2641
                vrb_map[rb] |= SL_to_bitmap(csirs_pdu_rel15->symb_l0, 1);
2642 2643 2644 2645
              break;
            case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row2:
              csirs_pdu_rel15->row = 2;
              csirs_pdu_rel15->freq_domain = (((resourceMapping.frequencyDomainAllocation.choice.row2.buf[1]>>4)&0x0f) |
2646
                                             ((resourceMapping.frequencyDomainAllocation.choice.row2.buf[0]<<4)&0xff0));
2647
              for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++)
2648
                vrb_map[rb] |= SL_to_bitmap(csirs_pdu_rel15->symb_l0, 1);
2649 2650 2651 2652 2653
              break;
            case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row4:
              csirs_pdu_rel15->row = 4;
              csirs_pdu_rel15->freq_domain = ((resourceMapping.frequencyDomainAllocation.choice.row4.buf[0])>>5)&0x07;
              for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++)
2654
                vrb_map[rb] |= SL_to_bitmap(csirs_pdu_rel15->symb_l0, 1);
2655 2656 2657 2658 2659 2660
              break;
            case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_other:
              csirs_pdu_rel15->freq_domain = ((resourceMapping.frequencyDomainAllocation.choice.other.buf[0])>>2)&0x3f;
              // determining the row of table 7.4.1.5.3-1 in 38.211
              switch(resourceMapping.nrofPorts){
                case NR_CSI_RS_ResourceMapping__nrofPorts_p1:
2661
                  AssertFatal(1==0,"Resource with 1 CSI port shouldn't be within other rows\n");
2662 2663 2664 2665
                  break;
                case NR_CSI_RS_ResourceMapping__nrofPorts_p2:
                  csirs_pdu_rel15->row = 3;
                  for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++)
2666
                    vrb_map[rb] |= SL_to_bitmap(csirs_pdu_rel15->symb_l0, 1);
2667 2668 2669
                  break;
                case NR_CSI_RS_ResourceMapping__nrofPorts_p4:
                  csirs_pdu_rel15->row = 5;
2670
                  for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++)
2671
                    vrb_map[rb] |= SL_to_bitmap(csirs_pdu_rel15->symb_l0, 2);
2672 2673 2674 2675
                  break;
                case NR_CSI_RS_ResourceMapping__nrofPorts_p8:
                  if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) {
                    csirs_pdu_rel15->row = 8;
2676
                    for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++)
2677
                      vrb_map[rb] |= SL_to_bitmap(csirs_pdu_rel15->symb_l0, 2);
2678
                  }
2679 2680 2681 2682 2683 2684 2685
                  else{
                    int num_k = 0;
                    for (int k=0; k<6; k++)
                      num_k+=(((csirs_pdu_rel15->freq_domain)>>k)&0x01);
                    if(num_k==4) {
                      csirs_pdu_rel15->row = 6;
                      for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++)
2686
                        vrb_map[rb] |= SL_to_bitmap(csirs_pdu_rel15->symb_l0, 1);
2687 2688 2689 2690
                    }
                    else {
                      csirs_pdu_rel15->row = 7;
                      for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++)
2691
                        vrb_map[rb] |= SL_to_bitmap(csirs_pdu_rel15->symb_l0, 2);
2692 2693 2694 2695 2696 2697
                    }
                  }
                  break;
                case NR_CSI_RS_ResourceMapping__nrofPorts_p12:
                  if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) {
                    csirs_pdu_rel15->row = 10;
2698
                    for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++)
2699
                      vrb_map[rb] |= SL_to_bitmap(csirs_pdu_rel15->symb_l0, 2);
2700 2701
                  }
                  else {
2702
                    csirs_pdu_rel15->row = 9;
2703
                    for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++)
2704
                      vrb_map[rb] |= SL_to_bitmap(csirs_pdu_rel15->symb_l0, 1);
2705
                  }
2706 2707 2708 2709 2710 2711
                  break;
                case NR_CSI_RS_ResourceMapping__nrofPorts_p16:
                  if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
                    csirs_pdu_rel15->row = 12;
                  else
                    csirs_pdu_rel15->row = 11;
2712
                  for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++)
2713
                    vrb_map[rb] |= SL_to_bitmap(csirs_pdu_rel15->symb_l0, 2);
2714 2715 2716 2717
                  break;
                case NR_CSI_RS_ResourceMapping__nrofPorts_p24:
                  if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) {
                    csirs_pdu_rel15->row = 14;
2718
                    for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++)
2719
                      vrb_map[rb] |= (SL_to_bitmap(csirs_pdu_rel15->symb_l0, 2) | SL_to_bitmap(csirs_pdu_rel15->symb_l1, 2));
2720
                  }
2721 2722 2723 2724
                  else{
                    if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm8_FD2_TD4) {
                      csirs_pdu_rel15->row = 15;
                      for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++)
2725
                        vrb_map[rb] |= SL_to_bitmap(csirs_pdu_rel15->symb_l0, 3);
2726 2727 2728 2729
                    }
                    else {
                      csirs_pdu_rel15->row = 13;
                      for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++)
2730
                        vrb_map[rb] |= (SL_to_bitmap(csirs_pdu_rel15->symb_l0, 2) | SL_to_bitmap(csirs_pdu_rel15->symb_l1, 2));
2731 2732 2733 2734 2735 2736
                    }
                  }
                  break;
                case NR_CSI_RS_ResourceMapping__nrofPorts_p32:
                  if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) {
                    csirs_pdu_rel15->row = 17;
2737
                    for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++)
2738
                      vrb_map[rb] |= (SL_to_bitmap(csirs_pdu_rel15->symb_l0, 2) | SL_to_bitmap(csirs_pdu_rel15->symb_l1, 2));
2739
                  }
2740 2741 2742 2743
                  else{
                    if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm8_FD2_TD4) {
                      csirs_pdu_rel15->row = 18;
                      for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++)
2744
                        vrb_map[rb] |= SL_to_bitmap(csirs_pdu_rel15->symb_l0, 3);
2745 2746 2747 2748
                    }
                    else {
                      csirs_pdu_rel15->row = 16;
                      for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++)
2749
                        vrb_map[rb] |= (SL_to_bitmap(csirs_pdu_rel15->symb_l0, 2) | SL_to_bitmap(csirs_pdu_rel15->symb_l1, 2));
2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760
                    }
                  }
                  break;
              default:
                AssertFatal(1==0,"Invalid number of ports in CSI-RS resource\n");
              }
              break;
          default:
            AssertFatal(1==0,"Invalid freqency domain allocation in CSI-RS resource\n");
          }
          dl_req->nPDUs++;
2761
        }
2762 2763 2764 2765 2766
      }
    }
  }
}

2767 2768
void nr_mac_update_timers(module_id_t module_id,
                          frame_t frame,
2769 2770 2771 2772
                          sub_frame_t slot)
{
  /* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */
  NR_SCHED_ENSURE_LOCKED(&RC.nrmac[module_id]->sched_lock);
2773

2774
  NR_UEs_t *UE_info = &RC.nrmac[module_id]->UE_info;
Laurent THOMAS's avatar
Laurent THOMAS committed
2775 2776
  UE_iterator(UE_info->list, UE) {
    NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
2777 2778 2779 2780 2781 2782 2783 2784 2785 2786

    if (nr_mac_check_release(sched_ctrl, UE->rnti)) {
      nr_rlc_remove_ue(UE->rnti);
      mac_remove_nr_ue(RC.nrmac[module_id], UE->rnti);
      // go back to examine the next UE, which is at the position the
      // current UE was
      UE--;
      continue;
    }

2787 2788 2789
    /* check if UL failure and trigger release request if necessary */
    nr_mac_check_ul_failure(RC.nrmac[module_id], UE->rnti, sched_ctrl);

2790 2791 2792
    if (sched_ctrl->rrc_processing_timer > 0) {
      sched_ctrl->rrc_processing_timer--;
      if (sched_ctrl->rrc_processing_timer == 0) {
Laurent THOMAS's avatar
Laurent THOMAS committed
2793
        LOG_I(NR_MAC, "(%d.%d) De-activating RRC processing timer for UE %04x\n", frame, slot, UE->rnti);
2794

2795 2796
        reset_srs_stats(UE);

2797 2798
        NR_CellGroupConfig_t *cg = NULL;
        uper_decode(NULL,
laurent's avatar
laurent committed
2799
                    &asn_DEF_NR_CellGroupConfig, // might be added prefix later
2800 2801
                    (void **)&cg,
                    (uint8_t *)UE->cg_buf,
laurent's avatar
laurent committed
2802 2803 2804
                    (UE->enc_rval.encoded + 7) / 8,
                    0,
                    0);
2805 2806
        UE->CellGroup = cg;

2807 2808 2809 2810
        if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
          xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) UE->CellGroup);
        }

2811
        NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon;
2812

2813
        LOG_I(NR_MAC,"Modified rnti %04x with CellGroup\n", UE->rnti);
2814
        process_CellGroup(cg, UE);
2815
        NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
2816
        configure_UE_BWP(RC.nrmac[module_id], scc, sched_ctrl, NULL, UE, -1, -1);
2817

2818 2819
        if (get_softmodem_params()->sa) {
          // add all available DL HARQ processes for this UE in SA
2820
          create_dl_harq_list(sched_ctrl, UE->current_DL_BWP.pdsch_servingcellconfig);
2821
        }
2822 2823
      }
    }
2824 2825 2826 2827 2828 2829 2830 2831 2832

    // RA timer
    if (UE->ra_timer > 0) {
      UE->ra_timer--;
      if (UE->ra_timer == 0) {
        LOG_W(NR_MAC, "Removing UE %04x because RA timer expired\n", UE->rnti);
        mac_remove_nr_ue(RC.nrmac[module_id], UE->rnti);
      }
    }
2833 2834
  }
}
2835

2836 2837
void schedule_nr_bwp_switch(module_id_t module_id,
                            frame_t frame,
2838 2839 2840 2841
                            sub_frame_t slot)
{
  /* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */
  NR_SCHED_ENSURE_LOCKED(&RC.nrmac[module_id]->sched_lock);
2842

Laurent THOMAS's avatar
Laurent THOMAS committed
2843
  NR_UEs_t *UE_info = &RC.nrmac[module_id]->UE_info;
2844 2845

  // TODO: Implementation of a algorithm to perform:
2846 2847
  //  - DL BWP selection:     sched_ctrl->next_dl_bwp_id = dl_bwp_id
  //  - UL BWP selection:     sched_ctrl->next_ul_bwp_id = ul_bwp_id
2848

Laurent THOMAS's avatar
Laurent THOMAS committed
2849 2850
  UE_iterator(UE_info->list, UE) {
    NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
francescomani's avatar
francescomani committed
2851 2852
    NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP;
    NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
2853
    if (sched_ctrl->rrc_processing_timer == 0 && UE->Msg4_ACKed && sched_ctrl->next_dl_bwp_id >= 0) {
2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864
      LOG_W(NR_MAC,
            "%4d.%2d UE %04x Scheduling BWP switch from DL_BWP %ld to %ld and from UL_BWP %ld to %ld\n",
            frame,
            slot,
            UE->rnti,
            dl_bwp->bwp_id,
            sched_ctrl->next_dl_bwp_id,
            ul_bwp->bwp_id,
            sched_ctrl->next_ul_bwp_id);

      nr_mac_rrc_bwp_switch_req(module_id, frame, slot, UE->rnti, sched_ctrl->next_dl_bwp_id, sched_ctrl->next_ul_bwp_id);
2865
    }
2866 2867
  }
}
2868

2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879
int ul_buffer_index(int frame, int slot, int scs, int size)
{
  const int abs_slot = frame * nr_slots_per_frame[scs] + slot;
  return abs_slot % size;
}

void UL_tti_req_ahead_initialization(gNB_MAC_INST * gNB, NR_ServingCellConfigCommon_t *scc, int n, int CCid, frame_t frameP, int slotP, int scs)
{

  if(gNB->UL_tti_req_ahead[CCid])
    return;
2880

2881 2882 2883
  int size = n;
  if (scs == 0)
    size <<= 1; // to have enough room for feedback possibly beyond the frame we need a larger array at 15kHz SCS
2884

2885 2886 2887
  gNB->UL_tti_req_ahead_size = size;
  gNB->UL_tti_req_ahead[CCid] = calloc(size, sizeof(nfapi_nr_ul_tti_request_t));
  AssertFatal(gNB->UL_tti_req_ahead[CCid], "could not allocate memory for RC.nrmac[]->UL_tti_req_ahead[]\n");
2888 2889 2890
  /* fill in slot/frame numbers: slot is fixed, frame will be updated by scheduler
   * consider that scheduler runs sl_ahead: the first sl_ahead slots are
   * already "in the past" and thus we put frame 1 instead of 0! */
2891 2892 2893 2894 2895
  for (int i = 0; i < size; ++i) {
    int abs_slot = frameP * n + slotP + i;
    nfapi_nr_ul_tti_request_t *req = &gNB->UL_tti_req_ahead[CCid][abs_slot % size];
    req->SFN = abs_slot / n;
    req->Slot = abs_slot % n;
2896 2897
  }
}
2898

2899
void send_initial_ul_rrc_message(gNB_MAC_INST *mac, int rnti, const uint8_t *sdu, sdu_size_t sdu_len, void *rawUE)
2900
{
2901

2902
  NR_UE_info_t *UE = (NR_UE_info_t *)rawUE;
2903
  NR_SCHED_ENSURE_LOCKED(&mac->sched_lock);
2904

2905 2906
  uint8_t du2cu[1024];
  int encoded = encode_cellGroupConfig(UE->CellGroup, du2cu, sizeof(du2cu));
2907 2908 2909

  const f1ap_initial_ul_rrc_message_t ul_rrc_msg = {
    /* TODO: add mcc, mnc, cell_id, ..., is not available at MAC yet */
2910
    .gNB_DU_ue_id = rnti,
2911 2912 2913
    .crnti = rnti,
    .rrc_container = (uint8_t *) sdu,
    .rrc_container_length = sdu_len,
2914 2915
    .du2cu_rrc_container = (uint8_t *) du2cu,
    .du2cu_rrc_container_length = encoded
2916
  };
2917 2918 2919
  mac->mac_rrc.initial_ul_rrc_message_transfer(0, &ul_rrc_msg);
}

2920
void prepare_initial_ul_rrc_message(gNB_MAC_INST *mac, NR_UE_info_t *UE)
2921
{
2922
  NR_SCHED_ENSURE_LOCKED(&mac->sched_lock);
2923 2924 2925 2926 2927 2928 2929
  /* create this UE's initial CellGroup */
  /* Note: relying on the RRC is a hack, as we are in the DU; there should be
   * no RRC, remove in the future */
  module_id_t mod_id = 0;
  gNB_RRC_INST *rrc = RC.nrrrc[mod_id];
  const NR_ServingCellConfigCommon_t *scc = rrc->carrier.servingcellconfigcommon;
  const NR_ServingCellConfig_t *sccd = rrc->configuration.scd;
2930
  NR_CellGroupConfig_t *cellGroupConfig = get_initial_cellGroupConfig(UE->uid, scc, sccd, &rrc->configuration);
2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942

  UE->CellGroup = cellGroupConfig;
  nr_mac_update_cellgroup(mac, UE->rnti, cellGroupConfig);

  /* activate SRB0 */
  nr_rlc_activate_srb0(UE->rnti, mac, UE, send_initial_ul_rrc_message);

  /* the cellGroup sent to CU specifies there is SRB1, so create it */
  DevAssert(cellGroupConfig->rlc_BearerToAddModList->list.count == 1);
  const NR_RLC_BearerConfig_t *bearer = cellGroupConfig->rlc_BearerToAddModList->list.array[0];
  DevAssert(bearer->servedRadioBearer->choice.srb_Identity == 1);
  nr_rlc_add_srb(UE->rnti, DCCH, bearer);
2943
}
2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957

void nr_mac_trigger_release_timer(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierSpacing_t subcarrier_spacing)
{
  // trigger 60ms
  sched_ctrl->release_timer = 60 << subcarrier_spacing;
}

bool nr_mac_check_release(NR_UE_sched_ctrl_t *sched_ctrl, int rnti)
{
  if (sched_ctrl->release_timer == 0)
    return false;
  sched_ctrl->release_timer--;
  return sched_ctrl->release_timer == 0;
}
2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993

void nr_mac_trigger_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierSpacing_t subcarrier_spacing)
{
  if (sched_ctrl->ul_failure) {
    /* already running */
    return;
  }
  sched_ctrl->ul_failure = true;
  // 30 seconds till triggering release request
  sched_ctrl->ul_failure_timer = 30000 << subcarrier_spacing;
}

void nr_mac_reset_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl)
{
  sched_ctrl->ul_failure = false;
  sched_ctrl->ul_failure_timer = 0;
  sched_ctrl->pusch_consecutive_dtx_cnt = 0;
}

void nr_mac_check_ul_failure(const gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t *sched_ctrl)
{
  if (!sched_ctrl->ul_failure)
    return;
  if (sched_ctrl->ul_failure_timer > 0)
    sched_ctrl->ul_failure_timer--;
  /* to trigger only once: trigger when ul_failure_timer == 1, but timer will
   * stop at 0 and we wait for a UE release command from upper layers */
  if (sched_ctrl->ul_failure_timer == 1) {
    f1ap_ue_context_release_complete_t complete = {
      .rnti = rnti,
      .cause = F1AP_CAUSE_RADIO_NETWORK,
      .cause_value = 12, // F1AP_CauseRadioNetwork_rl_failure_others
    };
    nrmac->mac_rrc.ue_context_release_request(&complete);
  }
}