phy_procedures_lte_common.c 40.5 KB
Newer Older
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.0  (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
 */

22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
/*! \file phy_procedures_lte_eNB.c
* \brief Implementation of common utilities for eNB/UE procedures from 36.213 LTE specifications
* \author R. Knopp, F. Kaltenberger
* \date 2011
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr
* \note
* \warning
*/
#include "PHY/defs.h"
#include "PHY/extern.h"
#include "SCHED/defs.h"
#include "SCHED/extern.h"

37
#ifdef LOCALIZATION
38
#include <sys/time.h>
39
#endif
40 41

void get_Msg3_alloc(LTE_DL_FRAME_PARMS *frame_parms,
42 43 44 45 46
                    unsigned char current_subframe,
                    unsigned int current_frame,
                    unsigned int *frame,
                    unsigned char *subframe)
{
47 48 49 50 51

  // Fill in other TDD Configuration!!!!

  if (frame_parms->frame_type == FDD) {
    *subframe = current_subframe+6;
52

53 54
    if (*subframe>9) {
      *subframe = *subframe-10;
55
      *frame = (current_frame+1) & 1023;
56
    } else {
57 58
      *frame=current_frame;
    }
59
  } else { // TDD
60 61
    if (frame_parms->tdd_config == 1) {
      switch (current_subframe) {
62

63
      case 0:
64 65 66 67
        *subframe = 7;
        *frame = current_frame;
        break;

68
      case 4:
69
        *subframe = 2;
70
        *frame = (current_frame+1) & 1023;
71 72
        break;

73
      case 5:
74
        *subframe = 2;
75
        *frame = (current_frame+1) & 1023;
76 77
        break;

78
      case 9:
79
        *subframe = 7;
80
        *frame = (current_frame+1) & 1023;
81
        break;
82
      }
83
    } else if (frame_parms->tdd_config == 3) {
84
      switch (current_subframe) {
85

86 87 88
      case 0:
      case 5:
      case 6:
89
        *subframe = 2;
90
        *frame = (current_frame+1) & 1023;
91 92
        break;

93
      case 7:
94
        *subframe = 3;
95
        *frame = (current_frame+1) & 1023;
96 97
        break;

98
      case 8:
99
        *subframe = 4;
100
        *frame = (current_frame+1) & 1023;
101 102
        break;

103
      case 9:
104
        *subframe = 2;
105
        *frame = (current_frame+2) & 1023;
106
        break;
107
      }
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
    } else if (frame_parms->tdd_config == 4) {
        switch (current_subframe) {

        case 0:
        case 4:
        case 5:
        case 6:
          *subframe = 2;
          *frame = (current_frame+1) & 1023;
          break;

        case 7:
          *subframe = 3;
          *frame = (current_frame+1) & 1023;
          break;

        case 8:
        case 9:
          *subframe = 2;
          *frame = (current_frame+2) & 1023;
          break;
        }
      } else if (frame_parms->tdd_config == 5) {
          switch (current_subframe) {

          case 0:
          case 4:
          case 5:
          case 6:
            *subframe = 2;
            *frame = (current_frame+1) & 1023;
            break;

          case 7:
          case 8:
          case 9:
            *subframe = 2;
            *frame = (current_frame+2) & 1023;
            break;
          }
        }
149 150 151 152
  }
}

void get_Msg3_alloc_ret(LTE_DL_FRAME_PARMS *frame_parms,
153 154 155 156 157
                        unsigned char current_subframe,
                        unsigned int current_frame,
                        unsigned int *frame,
                        unsigned char *subframe)
{
knopp's avatar
 
knopp committed
158
  if (frame_parms->frame_type == FDD) {
roux's avatar
roux committed
159 160
    /* always retransmit in n+8 */
    *subframe = current_subframe + 8;
161

roux's avatar
roux committed
162 163 164
    if (*subframe > 9) {
      *subframe = *subframe - 10;
      *frame = (current_frame + 1) & 1023;
165
    } else {
roux's avatar
roux committed
166
      *frame = current_frame;
167
    }
168
  } else {
169 170 171 172 173
    if (frame_parms->tdd_config == 1) {
      // original PUSCH in 2, PHICH in 6 (S), ret in 2
      // original PUSCH in 3, PHICH in 9, ret in 3
      // original PUSCH in 7, PHICH in 1 (S), ret in 7
      // original PUSCH in 8, PHICH in 4, ret in 8
174
      *frame = (current_frame+1) & 1023;
175
    } else if (frame_parms->tdd_config == 3) {
176 177 178
      // original PUSCH in 2, PHICH in 8, ret in 2 next frame
      // original PUSCH in 3, PHICH in 9, ret in 3 next frame
      // original PUSCH in 4, PHICH in 0, ret in 4 next frame
179
      *frame=(current_frame+1) & 1023;
180 181 182 183 184 185 186
    } else if (frame_parms->tdd_config == 4) {
        // original PUSCH in 2, PHICH in 8, ret in 2 next frame
        // original PUSCH in 3, PHICH in 9, ret in 3 next frame
        *frame=(current_frame+1) & 1023;
    } else if (frame_parms->tdd_config == 5) {
        // original PUSCH in 2, PHICH in 8, ret in 2 next frame
        *frame=(current_frame+1) & 1023;
187 188 189 190
    }
  }
}

gauthier's avatar
gauthier committed
191
uint8_t get_Msg3_harq_pid(LTE_DL_FRAME_PARMS *frame_parms,
192 193 194
                          uint32_t frame,
                          unsigned char current_subframe)
{
195

gauthier's avatar
gauthier committed
196
  uint8_t ul_subframe=0;
197
  uint32_t ul_frame=0;
198

knopp's avatar
 
knopp committed
199
  if (frame_parms->frame_type ==FDD) {
200
    ul_subframe = (current_subframe>3) ? (current_subframe-4) : (current_subframe+6);
201
    ul_frame    = (current_subframe>3) ? ((frame+1)&1023) : frame;
202
  } else {
203 204 205 206 207 208
    switch (frame_parms->tdd_config) {
    case 1:
      switch (current_subframe) {

      case 9:
      case 0:
209 210 211
        ul_subframe = 7;
        break;

212 213
      case 5:
      case 7:
214 215
        ul_subframe = 2;
        break;
216 217

      }
218

219
      break;
220

221 222 223 224 225 226
    case 3:
      switch (current_subframe) {

      case 0:
      case 5:
      case 6:
227 228 229
        ul_subframe = 2;
        break;

230
      case 7:
231 232 233
        ul_subframe = 3;
        break;

234
      case 8:
235 236 237
        ul_subframe = 4;
        break;

238
      case 9:
239 240
        ul_subframe = 2;
        break;
241
      }
242

243
      break;
244

245 246 247 248 249 250 251 252
    case 4:
      switch (current_subframe) {

      case 0:
      case 5:
      case 6:
      case 8:
      case 9:
253 254 255
        ul_subframe = 2;
        break;

256
      case 7:
257 258
        ul_subframe = 3;
        break;
259
      }
260

261
      break;
262

263 264 265
    case 5:
      ul_subframe =2;
      break;
266

267 268
    default:
      LOG_E(PHY,"get_Msg3_harq_pid: Unsupported TDD configuration %d\n",frame_parms->tdd_config);
gauthier's avatar
gauthier committed
269
      mac_xface->macphy_exit("get_Msg3_harq_pid: Unsupported TDD configuration");
270 271 272
      break;
    }
  }
273

274 275 276 277
  return(subframe2harq_pid(frame_parms,ul_frame,ul_subframe));

}

278 279
unsigned char ul_ACK_subframe2_dl_subframe(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe,unsigned char ACK_index)
{
280

knopp's avatar
 
knopp committed
281
  if (frame_parms->frame_type == FDD) {
282
    return((subframe<4) ? subframe+6 : subframe-4);
283
  } else {
284 285 286
    switch (frame_parms->tdd_config) {
    case 3:
      if (subframe == 2) {  // ACK subframes 5 and 6
287 288 289 290 291 292 293 294 295 296 297 298
        if (ACK_index==2)
          return(1);

        return(5+ACK_index);
      } else if (subframe == 3) { // ACK subframes 7 and 8
        return(7+ACK_index);  // To be updated
      } else if (subframe == 4) { // ACK subframes 9 and 0
        return((9+ACK_index)%10);
      } else {
        LOG_E(PHY,"phy_procedures_lte_common.c/subframe2_dl_harq_pid: illegal subframe %d for tdd_config %d\n",
              subframe,frame_parms->tdd_config);
        return(0);
299
      }
300

301
      break;
302

303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
    case 4:
          if (subframe == 2) {  // ACK subframes 0, 4 and 5
            //if (ACK_index==2)
            //  return(1); TBC
            if (ACK_index==2)
            return(0);

            return(4+ACK_index);
          } else if (subframe == 3) { // ACK subframes 6, 7 8 and 9
            return(6+ACK_index);  // To be updated
          } else {
            LOG_E(PHY,"phy_procedures_lte_common.c/subframe2_dl_harq_pid: illegal subframe %d for tdd_config %d\n",
                  subframe,frame_parms->tdd_config);
            return(0);
          }

          break;

321 322
    case 1:
      if (subframe == 2) {  // ACK subframes 5 and 6
323 324 325 326 327 328 329 330 331 332 333
        return(5+ACK_index);
      } else if (subframe == 3) { // ACK subframe 9
        return(9);  // To be updated
      } else if (subframe == 7) { // ACK subframes 0 and 1
        return(ACK_index);  // To be updated
      } else if (subframe == 8) { // ACK subframe 4
        return(4);  // To be updated
      } else {
        LOG_E(PHY,"phy_procedures_lte_common.c/ul_ACK_subframe2_dl_subframe: illegal subframe %d for tdd_config %d\n",
              subframe,frame_parms->tdd_config);
        return(0);
334
      }
335

336 337 338
      break;
    }
  }
339

340 341 342
  return(0);
}

343 344
unsigned char ul_ACK_subframe2_M(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe)
{
345

knopp's avatar
 
knopp committed
346
  if (frame_parms->frame_type == FDD) {
347
    return(1);
348
  } else {
349 350 351
    switch (frame_parms->tdd_config) {
    case 3:
      if (subframe == 2) {  // ACK subframes 5 and 6
352 353 354 355 356 357 358 359 360
        return(2); // should be 3
      } else if (subframe == 3) { // ACK subframes 7 and 8
        return(2);  // To be updated
      } else if (subframe == 4) { // ACK subframes 9 and 0
        return(2);
      } else {
        LOG_E(PHY,"phy_procedures_lte_common.c/subframe2_dl_harq_pid: illegal subframe %d for tdd_config %d\n",
              subframe,frame_parms->tdd_config);
        return(0);
361
      }
362

363
      break;
364

365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
    case 4:
          if (subframe == 2) {  // ACK subframes 0,4 and 5
            return(3); // should be 4
          } else if (subframe == 3) { // ACK subframes 6,7,8 and 9
            return(4);
          } else {
            LOG_E(PHY,"phy_procedures_lte_common.c/subframe2_dl_harq_pid: illegal subframe %d for tdd_config %d\n",
                  subframe,frame_parms->tdd_config);
            return(0);
          }

          break;

    case 5:
              if (subframe == 2) {  // ACK subframes 0,3,4,5,6,7,8 and 9
                return(8); // should be 3
              } else {
                LOG_E(PHY,"phy_procedures_lte_common.c/subframe2_dl_harq_pid: illegal subframe %d for tdd_config %d\n",
                      subframe,frame_parms->tdd_config);
                return(0);
              }

              break;

389 390
    case 1:
      if (subframe == 2) {  // ACK subframes 5 and 6
391 392 393 394 395 396 397 398 399 400 401
        return(2);
      } else if (subframe == 3) { // ACK subframe 9
        return(1);  // To be updated
      } else if (subframe == 7) { // ACK subframes 0 and 1
        return(2);  // To be updated
      } else if (subframe == 8) { // ACK subframe 4
        return(1);  // To be updated
      } else {
        LOG_E(PHY,"phy_procedures_lte_common.c/subframe2_dl_harq_pid: illegal subframe %d for tdd_config %d\n",
              subframe,frame_parms->tdd_config);
        return(0);
402
      }
403

404 405 406
      break;
    }
  }
407

408 409 410 411
  return(0);
}

// This function implements table 10.1-1 of 36-213, p. 69
412 413
// return the number 'Nbundled'
uint8_t get_reset_ack(LTE_DL_FRAME_PARMS *frame_parms,
414
                harq_status_t *harq_ack,
Bilel's avatar
Bilel committed
415 416
                unsigned char subframe_tx,
                unsigned char subframe_rx,
417
                unsigned char *o_ACK,
Bilel's avatar
Bilel committed
418
                uint8_t *pN_bundled,
419
                uint8_t cw_idx,
420
                uint8_t do_reset) // 1 to reset ACK/NACK status : 0 otherwise
421
{
gauthier's avatar
gauthier committed
422
  uint8_t status=0;
423
  uint8_t subframe_ul=0xff, subframe_dl0=0xff, subframe_dl1=0xff,subframe_dl2=0xff, subframe_dl3=0xff;
424

knopp's avatar
 
knopp committed
425
  //  printf("get_ack: SF %d\n",subframe);
426
  if (frame_parms->frame_type == FDD) {
Bilel's avatar
Bilel committed
427 428
    if (subframe_tx < 4)
      subframe_dl0 = subframe_tx + 6;
429
    else
Bilel's avatar
Bilel committed
430
      subframe_dl0 = subframe_tx - 4;
431

432
    o_ACK[cw_idx] = harq_ack[subframe_dl0].ack;
433
    status = harq_ack[subframe_dl0].send_harq_status;
434

435
    //LOG_I(PHY,"dl subframe %d send_harq_status %d cw_idx %d, reset %d\n",subframe_dl0, status, cw_idx, do_reset);
436 437
    if(do_reset)
    	harq_ack[subframe_dl0].send_harq_status = 0;
438
    //printf("get_ack: Getting ACK/NAK for PDSCH (subframe %d) => %d\n",subframe_dl,o_ACK[0]);
439
  } else {
440 441
    switch (frame_parms->tdd_config) {
    case 1:
Bilel's avatar
Bilel committed
442
      if (subframe_tx == 2) {  // ACK subframes 5,6
443 444 445
        subframe_ul  = 6;
        subframe_dl0 = 5;
        subframe_dl1 = 6;
Bilel's avatar
Bilel committed
446
      } else if (subframe_tx == 3) { // ACK subframe 9
447 448 449
        subframe_ul  = 9;
        subframe_dl0 = 9;
        subframe_dl1 = 0xff;
Bilel's avatar
Bilel committed
450
      } else if (subframe_tx == 4) { // nothing
451 452 453
        subframe_ul  = 0xff;
        subframe_dl0 = 0xff; // invalid subframe number indicates ACK/NACK is not needed
        subframe_dl1 = 0xff;
Bilel's avatar
Bilel committed
454
      } else if (subframe_tx == 7) { // ACK subframes 0,1
455 456 457
        subframe_ul  = 1;
        subframe_dl0 = 0;
        subframe_dl1 = 1;
Bilel's avatar
Bilel committed
458
      } else if (subframe_tx == 8) { // ACK subframes 4
459 460 461
        subframe_ul  = 4;
        subframe_dl0 = 4;
        subframe_dl1 = 0xff;
462
      } else {
Bilel's avatar
Bilel committed
463 464
        LOG_E(PHY,"phy_procedures_lte.c: get_ack, illegal subframe_tx %d for tdd_config %d\n",
              subframe_tx,frame_parms->tdd_config);
465
        return(0);
466
      }
467

468
      // report ACK/NACK status
Gabriel's avatar
Gabriel committed
469
      o_ACK[cw_idx] = 1;
470 471
      status = 0;
      if ((subframe_dl0 < 10) && (harq_ack[subframe_dl0].send_harq_status)) {
Gabriel's avatar
Gabriel committed
472
        o_ACK[cw_idx] &= harq_ack[subframe_dl0].ack;
473 474 475
        status = harq_ack[subframe_dl0].send_harq_status;
      }
      if ((subframe_dl1 < 10) && (harq_ack[subframe_dl1].send_harq_status)) {
Gabriel's avatar
Gabriel committed
476
        o_ACK[cw_idx] &= harq_ack[subframe_dl1].ack;
477 478 479 480
        status = harq_ack[subframe_dl1].send_harq_status;
      }
      // report status = Nbundled
      if (!status) {
Gabriel's avatar
Gabriel committed
481
        o_ACK[cw_idx] = 0;
482 483 484 485 486 487 488 489 490
      } else {
        if (harq_ack[subframe_ul].vDAI_UL < 0xff) {
          status = harq_ack[subframe_ul].vDAI_UL;
        }
      }

      if (!do_reset && (subframe_ul < 10)) {
        if ((subframe_dl0 < 10) && (subframe_dl1 < 10)) {
          LOG_D(PHY,"ul-sf#%d vDAI_UL[sf#%d]=%d Nbundled=%d: dlsf#%d ACK=%d harq_status=%d vDAI_DL=%d, dlsf#%d ACK=%d harq_status=%d vDAI_DL=%d, o_ACK[0]=%d status=%d\n",
Bilel's avatar
Bilel committed
491
              subframe_tx, subframe_ul, harq_ack[subframe_ul].vDAI_UL, status,
492 493
              subframe_dl0, harq_ack[subframe_dl0].ack, harq_ack[subframe_dl0].send_harq_status, harq_ack[subframe_dl0].vDAI_DL,
              subframe_dl1, harq_ack[subframe_dl1].ack, harq_ack[subframe_dl1].send_harq_status, harq_ack[subframe_dl1].vDAI_DL,
Gabriel's avatar
Gabriel committed
494
              o_ACK[cw_idx], status);
495 496
        } else if (subframe_dl0 < 10) {
          LOG_D(PHY,"ul-sf#%d vDAI_UL[sf#%d]=%d Nbundled=%d: dlsf#%d ACK=%d status=%d vDAI_DL=%d, o_ACK[0]=%d status=%d\n",
Bilel's avatar
Bilel committed
497
              subframe_tx, subframe_ul, harq_ack[subframe_ul].vDAI_UL, status,
498
              subframe_dl0, harq_ack[subframe_dl0].ack, harq_ack[subframe_dl0].send_harq_status, harq_ack[subframe_dl0].vDAI_DL,
Gabriel's avatar
Gabriel committed
499
              o_ACK[cw_idx], status);
500 501
        }else if (subframe_dl1 < 10) {
          LOG_D(PHY,"ul-sf#%d vDAI_UL[sf#%d]=%d Nbundled=%d: dlsf#%d ACK=%d status=%d vDAI_DL=%d, o_ACK[0]=%d status=%d\n",
Bilel's avatar
Bilel committed
502
              subframe_tx, subframe_ul, harq_ack[subframe_ul].vDAI_UL, status,
503
              subframe_dl1, harq_ack[subframe_dl1].ack, harq_ack[subframe_dl1].send_harq_status, harq_ack[subframe_dl1].vDAI_DL,
Gabriel's avatar
Gabriel committed
504
              o_ACK[cw_idx], status);
505 506 507 508 509
        }
      }

      // reset ACK/NACK status
      if (do_reset) {
Bilel's avatar
Bilel committed
510
        LOG_D(PHY,"ul-sf#%d ACK/NACK status resetting @ dci0-sf#%d, dci1x/2x-sf#%d, dci1x/2x-sf#%d\n", subframe_tx, subframe_ul, subframe_dl0, subframe_dl1);
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
        if (subframe_ul < 10) {
          harq_ack[subframe_ul].vDAI_UL = 0xff;
        }
        if (subframe_dl0 < 10) {
          harq_ack[subframe_dl0].vDAI_DL = 0xff;
          harq_ack[subframe_dl0].ack = 2;
          harq_ack[subframe_dl0].send_harq_status = 0;
        }
        if (subframe_dl1 < 10) {
          harq_ack[subframe_dl1].vDAI_DL = 0xff;
          harq_ack[subframe_dl1].ack = 2;
          harq_ack[subframe_dl1].send_harq_status = 0;
        }
      }

526
      break;
527

528
    case 3:
Bilel's avatar
Bilel committed
529
      if (subframe_tx == 2) {  // ACK subframes 5 and 6
530 531
        subframe_dl0 = 5;
        subframe_dl1 = 6;
Bilel's avatar
Bilel committed
532 533 534
        subframe_ul  = 2;
        //printf("subframe_tx 2, TDD config 3: harq_ack[5] = %d (%d),harq_ack[6] = %d (%d)\n",harq_ack[5].ack,harq_ack[5].send_harq_status,harq_ack[6].ack,harq_ack[6].send_harq_status);
      } else if (subframe_tx == 3) { // ACK subframes 7 and 8
535 536
        subframe_dl0 = 7;
        subframe_dl1 = 8;
Bilel's avatar
Bilel committed
537
        subframe_ul  = 3;
538 539
        //printf("Subframe 3, TDD config 3: harq_ack[7] = %d,harq_ack[8] = %d\n",harq_ack[7].ack,harq_ack[8].ack);
        //printf("status %d : o_ACK (%d,%d)\n", status,o_ACK[0],o_ACK[1]);
Bilel's avatar
Bilel committed
540
      } else if (subframe_tx == 4) { // ACK subframes 9 and 0
541 542
        subframe_dl0 = 9;
        subframe_dl1 = 0;
Bilel's avatar
Bilel committed
543
        subframe_ul  = 4;
544 545
        //printf("Subframe 4, TDD config 3: harq_ack[9] = %d,harq_ack[0] = %d\n",harq_ack[9].ack,harq_ack[0].ack);
      } else {
Bilel's avatar
Bilel committed
546 547
        LOG_E(PHY,"phy_procedures_lte.c: get_ack, illegal subframe_tx %d for tdd_config %d\n",
              subframe_tx,frame_parms->tdd_config);
548
        return(0);
549
      }
550

551
      // report ACK/NACK status
Bilel's avatar
Bilel committed
552
      o_ACK[cw_idx] = 0;
553
      if (harq_ack[subframe_dl0].send_harq_status == 1) {
Gabriel's avatar
Gabriel committed
554
        o_ACK[cw_idx] = harq_ack[subframe_dl0].ack;
555 556

        if (harq_ack[subframe_dl1].send_harq_status == 1)
Gabriel's avatar
Gabriel committed
557
          o_ACK[cw_idx] &= harq_ack[subframe_dl1].ack;
558
      } else if (harq_ack[subframe_dl1].send_harq_status == 1)
Gabriel's avatar
Gabriel committed
559
        o_ACK[cw_idx] = harq_ack[subframe_dl1].ack;
560

Bilel's avatar
Bilel committed
561
      pN_bundled[0] = harq_ack[subframe_rx].vDAI_UL;
Bilel's avatar
Bilel committed
562
      status = harq_ack[subframe_dl0].send_harq_status + harq_ack[subframe_dl1].send_harq_status;
563

564 565 566
      //LOG_D(PHY,"TDD Config3 UL Sfn %d, dl Sfn0 %d status %d o_Ack %d, dl Sfn1 %d status %d o_Ack %d subframe_rx %d N_bundled %d \n",
      //	  subframe_tx, subframe_dl0, harq_ack[subframe_dl0].send_harq_status,harq_ack[subframe_dl0].ack,
      //    subframe_dl1, harq_ack[subframe_dl1].send_harq_status,harq_ack[subframe_dl1].ack, subframe_rx, pN_bundled[0]);
567 568 569 570 571 572 573 574
      if (do_reset) {
        // reset ACK/NACK status
        harq_ack[subframe_dl0].ack = 2;
        harq_ack[subframe_dl1].ack = 2;
        harq_ack[subframe_dl0].send_harq_status = 0;
        harq_ack[subframe_dl1].send_harq_status = 0;
      }

575
      break;
576

577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633
    case 4:
          if (subframe_tx == 2) {  // ACK subframes 4, 5 and 0
            subframe_dl0 = 4;
            subframe_dl1 = 5;
            subframe_dl2 = 0;
            subframe_ul  = 2;
            //printf("subframe_tx 2, TDD config 3: harq_ack[5] = %d (%d),harq_ack[6] = %d (%d)\n",harq_ack[5].ack,harq_ack[5].send_harq_status,harq_ack[6].ack,harq_ack[6].send_harq_status);
          } else if (subframe_tx == 3) { // ACK subframes 6, 7 8 and 9
            subframe_dl0 = 6;
            subframe_dl1 = 7;
            subframe_dl2 = 8;
            subframe_dl3 = 9;
            subframe_ul  = 3;
            //printf("Subframe 3, TDD config 3: harq_ack[7] = %d,harq_ack[8] = %d\n",harq_ack[7].ack,harq_ack[8].ack);
            //printf("status %d : o_ACK (%d,%d)\n", status,o_ACK[0],o_ACK[1]);
          } else {
            LOG_E(PHY,"phy_procedures_lte.c: get_ack, illegal subframe_tx %d for tdd_config %d\n",
                  subframe_tx,frame_parms->tdd_config);
            return(0);
          }

          // report ACK/NACK status
          o_ACK[cw_idx] = 0;
          if (harq_ack[subframe_dl0].send_harq_status == 1)
            o_ACK[cw_idx] = harq_ack[subframe_dl0].ack;

          if (harq_ack[subframe_dl1].send_harq_status == 1)
            o_ACK[cw_idx] &= harq_ack[subframe_dl1].ack;

          if (harq_ack[subframe_dl2].send_harq_status == 1)
            o_ACK[cw_idx] &= harq_ack[subframe_dl2].ack;

          if (harq_ack[subframe_dl3].send_harq_status == 1)
            o_ACK[cw_idx] &= harq_ack[subframe_dl3].ack;

          pN_bundled[0] = harq_ack[subframe_rx].vDAI_UL;
          status = harq_ack[subframe_dl0].send_harq_status + harq_ack[subframe_dl1].send_harq_status + harq_ack[subframe_dl2].send_harq_status + harq_ack[subframe_dl3].send_harq_status;

          LOG_I(PHY,"TDD Config3 UL Sfn %d, dl Sfn0 %d status %d o_Ack %d, dl Sfn1 %d status %d o_Ack %d dl Sfn2 %d status %d o_Ack %d dl Sfn3 %d status %d o_Ack %d subframe_rx %d N_bundled %d status %d\n",
                subframe_tx, subframe_dl0, harq_ack[subframe_dl0].send_harq_status,harq_ack[subframe_dl0].ack,
              subframe_dl1, harq_ack[subframe_dl1].send_harq_status,harq_ack[subframe_dl1].ack,
              subframe_dl2, harq_ack[subframe_dl2].send_harq_status,harq_ack[subframe_dl2].ack,
              subframe_dl3, harq_ack[subframe_dl3].send_harq_status,harq_ack[subframe_dl3].ack,subframe_rx, pN_bundled[0], status);
          if (do_reset) {
            // reset ACK/NACK status
            harq_ack[subframe_dl0].ack = 2;
            harq_ack[subframe_dl1].ack = 2;
            harq_ack[subframe_dl2].ack = 2;
            harq_ack[subframe_dl3].ack = 2;
            harq_ack[subframe_dl0].send_harq_status = 0;
            harq_ack[subframe_dl1].send_harq_status = 0;
            harq_ack[subframe_dl2].send_harq_status = 0;
            harq_ack[subframe_dl3].send_harq_status = 0;
          }

          break;

634 635
    }
  }
636

637 638 639 640 641
  //printf("status %d\n",status);

  return(status);
}

642 643
uint8_t get_ack(LTE_DL_FRAME_PARMS *frame_parms,
                harq_status_t *harq_ack,
Bilel's avatar
Bilel committed
644 645
                unsigned char subframe_tx,
                unsigned char subframe_rx,
646 647
                unsigned char *o_ACK,
                uint8_t cw_idx)
648
{
Bilel's avatar
Bilel committed
649 650
    uint8_t N_bundled = 0;
  return get_reset_ack(frame_parms, harq_ack, subframe_tx, subframe_rx, o_ACK, &N_bundled, cw_idx, 0);
651 652 653 654
}

uint8_t reset_ack(LTE_DL_FRAME_PARMS *frame_parms,
                harq_status_t *harq_ack,
Bilel's avatar
Bilel committed
655 656
                unsigned char subframe_tx,
                unsigned char subframe_rx,
657
                unsigned char *o_ACK,
Bilel's avatar
Bilel committed
658
                uint8_t *pN_bundled,
659
                uint8_t cw_idx)
660
{
Bilel's avatar
Bilel committed
661
  return get_reset_ack(frame_parms, harq_ack, subframe_tx, subframe_rx, o_ACK, pN_bundled, cw_idx, 1);
662 663 664 665
}



666 667 668 669 670 671
uint8_t Np6[4]= {0,1,3,5};
uint8_t Np15[4]= {0,3,8,13};
uint8_t Np25[4]= {0,5,13,22};
uint8_t Np50[4]= {0,11,27,44};
uint8_t Np75[4]= {0,16,41,66};
uint8_t Np100[4]= {0,22,55,88};
672
// This is part of the PUCCH allocation procedure (see Section 10.1 36.213)
673 674
uint16_t get_Np(uint8_t N_RB_DL,uint8_t nCCE,uint8_t plus1)
{
gauthier's avatar
gauthier committed
675
  uint8_t *Np;
676

677
  switch (N_RB_DL) {
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
  case 6:
    Np=Np6;
    break;

  case 15:
    Np=Np15;
    break;

  case 25:
    Np=Np25;
    break;

  case 50:
    Np=Np50;
    break;

  case 75:
    Np=Np75;
    break;

  case 100:
    Np=Np100;
    break;

  default:
    LOG_E(PHY,"get_Np() FATAL: unsupported N_RB_DL %d\n",N_RB_DL);
    return(0);
    break;
  }
707 708 709 710 711 712 713 714 715

  if (nCCE>=Np[2])
    return(Np[2+plus1]);
  else if (nCCE>=Np[1])
    return(Np[1+plus1]);
  else
    return(Np[0+plus1]);
}

716 717
lte_subframe_t subframe_select(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe)
{
718 719

  // if FDD return dummy value
knopp's avatar
 
knopp committed
720
  if (frame_parms->frame_type == FDD)
721 722 723 724 725 726 727 728 729 730 731 732
    return(SF_DL);

  switch (frame_parms->tdd_config) {

  case 1:
    switch (subframe) {
    case 0:
    case 4:
    case 5:
    case 9:
      return(SF_DL);
      break;
733

734 735 736 737 738 739
    case 2:
    case 3:
    case 7:
    case 8:
      return(SF_UL);
      break;
740

741 742 743 744
    default:
      return(SF_S);
      break;
    }
745

746
  case 3:
747
    if  ((subframe<1) || (subframe>=5))
748
      return(SF_DL);
749
    else if ((subframe>1) && (subframe < 5))
750 751 752 753 754 755 756
      return(SF_UL);
    else if (subframe==1)
      return (SF_S);
    else  {
      LOG_E(PHY,"[PHY_PROCEDURES_LTE] Unknown subframe number\n");
      return(255);
    }
757

758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
  case 4:
      if  ((subframe<1) || (subframe>=4))
        return(SF_DL);
      else if ((subframe>1) && (subframe < 4))
        return(SF_UL);
      else if (subframe==1)
        return (SF_S);
      else  {
        LOG_E(PHY,"[PHY_PROCEDURES_LTE] Unknown subframe number\n");
        return(255);
      }

  case 5:
        if  ((subframe<1) || (subframe>=3))
          return(SF_DL);
        else if ((subframe>1) && (subframe < 3))
          return(SF_UL);
        else if (subframe==1)
          return (SF_S);
        else  {
          LOG_E(PHY,"[PHY_PROCEDURES_LTE] Unknown subframe number\n");
          return(255);
        }
781
    break;
782

783 784
  default:
    LOG_E(PHY,"subframe %d Unsupported TDD configuration %d\n",subframe,frame_parms->tdd_config);
gauthier's avatar
gauthier committed
785
    mac_xface->macphy_exit("subframe x Unsupported TDD configuration");
786
    return(255);
787

788 789 790
  }
}

791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818
dci_detect_mode_t dci_detect_mode_select(LTE_DL_FRAME_PARMS *frame_parms,uint8_t subframe)
{
  dci_detect_mode_t ret = 0;

  static dci_detect_mode_t Table_8_2_3gpp_36_213[][10] = {
     //subf0    , subf1     , subf2 , subf3         , subf4     , subf5     , subf6     , subf7 , subf8     , subf9
      {UL_DL_DCI, UL_DL_DCI , NO_DCI    , NO_DCI    , NO_DCI    , UL_DL_DCI , UL_DL_DCI , NO_DCI, NO_DCI    , NO_DCI    },  // tdd0
      {DL_DCI   , UL_DL_DCI , NO_DCI    , NO_DCI    , UL_DL_DCI , DL_DCI    , UL_DL_DCI , NO_DCI, NO_DCI    , UL_DL_DCI },  // tdd1
      {DL_DCI   , DL_DCI    , NO_DCI    , UL_DL_DCI , DL_DCI    , DL_DCI    , DL_DCI    , NO_DCI, UL_DL_DCI , DL_DCI    },  // tdd2
      {UL_DL_DCI, DL_DCI    , NO_DCI    , NO_DCI    , NO_DCI    , DL_DCI    , DL_DCI    , DL_DCI, UL_DL_DCI , UL_DL_DCI },  // tdd3
      {DL_DCI   , DL_DCI    , NO_DCI    , NO_DCI    , DL_DCI    , DL_DCI    , DL_DCI    , DL_DCI, UL_DL_DCI , UL_DL_DCI },  // tdd4
      {DL_DCI   , DL_DCI    , NO_DCI    , DL_DCI    , DL_DCI    , DL_DCI    , DL_DCI    , DL_DCI, UL_DL_DCI , DL_DCI    },  // tdd5
      {UL_DL_DCI, UL_DL_DCI , NO_DCI    , NO_DCI    , NO_DCI    , UL_DL_DCI , UL_DL_DCI , NO_DCI, NO_DCI    , UL_DL_DCI }}; // tdd6


  DevAssert(subframe>=0 && subframe<=9);
  DevAssert((frame_parms->tdd_config)>=0 && (frame_parms->tdd_config)<=6);

  if (frame_parms->frame_type == FDD) {
    ret = UL_DL_DCI;
  } else {
    ret = Table_8_2_3gpp_36_213[frame_parms->tdd_config][subframe];
  }

  LOG_D(PHY, "subframe %d: detect UL_DCI=%d, detect DL_DCI=%d\n", subframe, (ret & UL_DCI)>0, (ret & DL_DCI)>0);
  return ret;
}

819 820
lte_subframe_t get_subframe_direction(uint8_t Mod_id,uint8_t CC_id,uint8_t subframe)
{
821

822
  return(subframe_select(&PHY_vars_eNB_g[Mod_id][CC_id]->frame_parms,subframe));
823 824 825

}

826 827
uint8_t phich_subframe_to_harq_pid(LTE_DL_FRAME_PARMS *frame_parms,uint32_t frame,uint8_t subframe)
{
828 829 830

  //LOG_D(PHY,"phich_subframe_to_harq_pid.c: frame %d, subframe %d\n",frame,subframe);
  return(subframe2harq_pid(frame_parms,
831 832
                           phich_frame2_pusch_frame(frame_parms,frame,subframe),
                           phich_subframe2_pusch_subframe(frame_parms,subframe)));
833 834
}

835 836
unsigned int is_phich_subframe(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe)
{
837

knopp's avatar
 
knopp committed
838
  if (frame_parms->frame_type == FDD) {
839
    return(1);
840
  } else {
841 842 843
    switch (frame_parms->tdd_config) {
    case 1:
      if ((subframe == 1) || (subframe == 4) || (subframe == 6) || (subframe == 9))
844 845
        return(1);

846
      break;
847

848 849
    case 3:
      if ((subframe == 0) || (subframe == 8) || (subframe == 9))
850 851
        return(1);

852
      break;
853

854
    case 4:
855
      if ((subframe == 8) || (subframe == 9) )
856 857
        return(1);

858
      break;
859

860
    case 5:
861
      if (subframe == 8)
862 863
        return(1);

864
      break;
865

866 867 868 869 870
    default:
      return(0);
      break;
    }
  }
871

872 873 874 875
  return(0);
}


876
#ifdef LOCALIZATION
877 878 879 880 881 882 883 884 885 886 887
double aggregate_eNB_UE_localization_stats(PHY_VARS_eNB *phy_vars_eNB, int8_t UE_id, frame_t frame, sub_frame_t subframe, int32_t UE_tx_power_dB)
{
  // parameters declaration
  int8_t Mod_id, CC_id;
  //    int32_t harq_pid;
  int32_t avg_power, avg_rssi, median_power, median_rssi, median_subcarrier_rss, median_TA, median_TA_update, ref_timestamp_ms, current_timestamp_ms;
  char cqis[100], sub_powers[2048];
  int len = 0, i;
  struct timeval ts;
  double sys_bw = 0;
  uint8_t N_RB_DL;
888
  LTE_DL_FRAME_PARMS *frame_parms = &eNB->frame_parms;
889

890 891 892
  Mod_id = eNB->Mod_id;
  CC_id = eNB->CC_id;
  ref_timestamp_ms = eNB->ulsch[UE_id+1]->reference_timestamp_ms;
893 894

  for (i=0; i<13; i++) {
895
    len += sprintf(&cqis[len]," %d ", eNB->UE_stats[(uint32_t)UE_id].DL_subband_cqi[0][i]);
896 897 898 899
  }

  len = 0;

900 901
  for (i=0; i<eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->active_subcarrier; i++) {
    len += sprintf(&sub_powers[len]," %d ", eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->subcarrier_power[i]);
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
  }

  gettimeofday(&ts, NULL);
  current_timestamp_ms = ts.tv_sec * 1000 + ts.tv_usec / 1000;


  LOG_D(LOCALIZE, " PHY: [UE %x/%d -> eNB %d], timestamp %d, "
        "frame %d, subframe %d"
        "UE Tx power %d dBm, "
        "RSSI ant1 %d dBm, "
        "RSSI ant2 %d dBm, "
        "pwr ant1 %d dBm, "
        "pwr ant2 %d dBm, "
        "Rx gain %d dB, "
        "TA %d, "
        "TA update %d, "
        "DL_CQI (%d,%d), "
        "Wideband CQI (%d,%d), "
        "DL Subband CQI[13] %s \n",
        //          "timestamp %d, (%d active subcarrier) %s \n"
922
        eNB->dlsch[(uint32_t)UE_id][0]->rnti, UE_id, Mod_id, current_timestamp_ms,
923 924
        frame,subframe,
        UE_tx_power_dB,
925 926 927 928 929 930 931 932 933 934
        eNB->UE_stats[(uint32_t)UE_id].UL_rssi[0],
        eNB->UE_stats[(uint32_t)UE_id].UL_rssi[1],
        dB_fixed(eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->ulsch_power[0]),
        dB_fixed(eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->ulsch_power[1]),
        eNB->rx_total_gain_eNB_dB,
        eNB->UE_stats[(uint32_t)UE_id].UE_timing_offset, // raw timing advance 1/sampling rate
        eNB->UE_stats[(uint32_t)UE_id].timing_advance_update,
        eNB->UE_stats[(uint32_t)UE_id].DL_cqi[0],eNB->UE_stats[(uint32_t)UE_id].DL_cqi[1],
        eNB->measurements[Mod_id].wideband_cqi_dB[(uint32_t)UE_id][0],
        eNB->measurements[Mod_id].wideband_cqi_dB[(uint32_t)UE_id][1],
935 936 937
        cqis);
  LOG_D(LOCALIZE, " PHY: timestamp %d, (%d active subcarrier) %s \n",
        current_timestamp_ms,
938
        eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->active_subcarrier,
939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960
        sub_powers);

  N_RB_DL = frame_parms->N_RB_DL;

  switch (N_RB_DL) {
  case 6:
    sys_bw = 1.92;
    break;

  case 25:
    sys_bw = 7.68;
    break;

  case 50:
    sys_bw = 15.36;
    break;

  case 100:
    sys_bw = 30.72;
    break;
  }

961
  if ((current_timestamp_ms - ref_timestamp_ms > eNB->ulsch[UE_id+1]->aggregation_period_ms)) {
962 963 964
    // check the size of one list to be sure there was a message transmitted during the defined aggregation period

    // make the reference timestamp == current timestamp
965
    eNB->ulsch[UE_id+1]->reference_timestamp_ms = current_timestamp_ms;
966 967 968
    int i;

    for (i=0; i<10; i++) {
969 970 971 972 973 974 975 976 977 978
      median_power = calculate_median(&eNB->ulsch[UE_id+1]->loc_rss_list[i]);
      del(&eNB->ulsch[UE_id+1]->loc_rss_list[i]);
      median_rssi = calculate_median(&eNB->ulsch[UE_id+1]->loc_rssi_list[i]);
      del(&eNB->ulsch[UE_id+1]->loc_rssi_list[i]);
      median_subcarrier_rss = calculate_median(&eNB->ulsch[UE_id+1]->loc_subcarrier_rss_list[i]);
      del(&eNB->ulsch[UE_id+1]->loc_subcarrier_rss_list[i]);
      median_TA = calculate_median(&eNB->ulsch[UE_id+1]->loc_timing_advance_list[i]);
      del(&eNB->ulsch[UE_id+1]->loc_timing_advance_list[i]);
      median_TA_update = calculate_median(&eNB->ulsch[UE_id+1]->loc_timing_update_list[i]);
      del(&eNB->ulsch[UE_id+1]->loc_timing_update_list[i]);
979 980

      if (median_power != 0)
981
        push_front(&eNB->ulsch[UE_id+1]->tot_loc_rss_list,median_power);
982 983

      if (median_rssi != 0)
984
        push_front(&eNB->ulsch[UE_id+1]->tot_loc_rssi_list,median_rssi);
985 986

      if (median_subcarrier_rss != 0)
987
        push_front(&eNB->ulsch[UE_id+1]->tot_loc_subcarrier_rss_list,median_subcarrier_rss);
988 989

      if (median_TA != 0)
990
        push_front(&eNB->ulsch[UE_id+1]->tot_loc_timing_advance_list,median_TA);
991 992

      if (median_TA_update != 0)
993
        push_front(&eNB->ulsch[UE_id+1]->tot_loc_timing_update_list,median_TA_update);
994

995 996 997 998 999
      initialize(&eNB->ulsch[UE_id+1]->loc_rss_list[i]);
      initialize(&eNB->ulsch[UE_id+1]->loc_subcarrier_rss_list[i]);
      initialize(&eNB->ulsch[UE_id+1]->loc_rssi_list[i]);
      initialize(&eNB->ulsch[UE_id+1]->loc_timing_advance_list[i]);
      initialize(&eNB->ulsch[UE_id+1]->loc_timing_update_list[i]);
1000
    }
1001

1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
    median_power = calculate_median(&eNB->ulsch[UE_id+1]->tot_loc_rss_list);
    del(&eNB->ulsch[UE_id+1]->tot_loc_rss_list);
    median_rssi = calculate_median(&eNB->ulsch[UE_id+1]->tot_loc_rssi_list);
    del(&eNB->ulsch[UE_id+1]->tot_loc_rssi_list);
    median_subcarrier_rss = calculate_median(&eNB->ulsch[UE_id+1]->tot_loc_subcarrier_rss_list);
    del(&eNB->ulsch[UE_id+1]->tot_loc_subcarrier_rss_list);
    median_TA = calculate_median(&eNB->ulsch[UE_id+1]->tot_loc_timing_advance_list);
    del(&eNB->ulsch[UE_id+1]->tot_loc_timing_advance_list);
    median_TA_update = calculate_median(&eNB->ulsch[UE_id+1]->tot_loc_timing_update_list);
    del(&eNB->ulsch[UE_id+1]->tot_loc_timing_update_list);

    initialize(&eNB->ulsch[UE_id+1]->tot_loc_rss_list);
    initialize(&eNB->ulsch[UE_id+1]->tot_loc_subcarrier_rss_list);
    initialize(&eNB->ulsch[UE_id+1]->tot_loc_rssi_list);
    initialize(&eNB->ulsch[UE_id+1]->tot_loc_timing_advance_list);
    initialize(&eNB->ulsch[UE_id+1]->tot_loc_timing_update_list);
1018 1019 1020

    double alpha = 2, power_distance, time_distance;
    // distance = 10^((Ptx - Prx - A)/10alpha), A is a constance experimentally evaluated
1021 1022
    // A includes the rx gain (eNB->rx_total_gain_eNB_dB) and hardware calibration
    power_distance = pow(10, ((UE_tx_power_dB - median_power - eNB->rx_total_gain_eNB_dB + 133)/(10.0*alpha)));
1023 1024
    /* current measurements shows constant UE_timing_offset = 18
       and timing_advance_update = 11 at 1m. at 5m, timing_advance_update = 12*/
1025 1026
    //time_distance = (double) 299792458*(eNB->UE_stats[(uint32_t)UE_id].timing_advance_update)/(sys_bw*1000000);
    time_distance = (double) abs(eNB->UE_stats[(uint32_t)UE_id].timing_advance_update - 11) * 4.89;//  (3 x 108 x 1 / (15000 x 2048)) / 2 = 4.89 m
1027

1028 1029
    eNB->UE_stats[(uint32_t)UE_id].distance.time_based = time_distance;
    eNB->UE_stats[(uint32_t)UE_id].distance.power_based = power_distance;
1030 1031 1032

    LOG_D(LOCALIZE, " PHY agg [UE %x/%d -> eNB %d], timestamp %d, "
          "frame %d, subframe %d "
1033
          "UE Tx power %d dBm, "