phy_procedures_lte_common.c 25.5 KB
Newer Older
1
/*******************************************************************************
2
    OpenAirInterface
ghaddab's avatar
ghaddab committed
3
    Copyright(c) 1999 - 2014 Eurecom
4

ghaddab's avatar
ghaddab committed
5 6 7 8
    OpenAirInterface is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
9 10


ghaddab's avatar
ghaddab committed
11 12 13 14
    OpenAirInterface is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
15

ghaddab's avatar
ghaddab committed
16
    You should have received a copy of the GNU General Public License
17 18
    along with OpenAirInterface.The full GNU General Public License is
   included in this distribution in the file called "COPYING". If not,
ghaddab's avatar
ghaddab committed
19
   see <http://www.gnu.org/licenses/>.
20 21

  Contact Information
ghaddab's avatar
ghaddab committed
22 23
  OpenAirInterface Admin: openair_admin@eurecom.fr
  OpenAirInterface Tech : openair_tech@eurecom.fr
24
  OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
25

ghaddab's avatar
ghaddab committed
26
  Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
27

ghaddab's avatar
ghaddab committed
28
 *******************************************************************************/
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44

/*! \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"

45
#ifdef LOCALIZATION
46
#include <sys/time.h>
47
#endif
48 49

void get_Msg3_alloc(LTE_DL_FRAME_PARMS *frame_parms,
50 51 52 53 54
                    unsigned char current_subframe,
                    unsigned int current_frame,
                    unsigned int *frame,
                    unsigned char *subframe)
{
55 56 57 58 59

  // Fill in other TDD Configuration!!!!

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

61 62
    if (*subframe>9) {
      *subframe = *subframe-10;
63
      *frame = (current_frame+1) & 1023;
64
    } else {
65 66
      *frame=current_frame;
    }
67
  } else { // TDD
68 69
    if (frame_parms->tdd_config == 1) {
      switch (current_subframe) {
70

71
      case 0:
72 73 74 75
        *subframe = 7;
        *frame = current_frame;
        break;

76
      case 4:
77
        *subframe = 2;
78
        *frame = (current_frame+1) & 1023;
79 80
        break;

81
      case 5:
82
        *subframe = 2;
83
        *frame = (current_frame+1) & 1023;
84 85
        break;

86
      case 9:
87
        *subframe = 7;
88
        *frame = (current_frame+1) & 1023;
89
        break;
90
      }
91
    } else if (frame_parms->tdd_config == 3) {
92
      switch (current_subframe) {
93

94 95 96
      case 0:
      case 5:
      case 6:
97
        *subframe = 2;
98
        *frame = (current_frame+1) & 1023;
99 100
        break;

101
      case 7:
102
        *subframe = 3;
103
        *frame = (current_frame+1) & 1023;
104 105
        break;

106
      case 8:
107
        *subframe = 4;
108
        *frame = (current_frame+1) & 1023;
109 110
        break;

111
      case 9:
112
        *subframe = 2;
113
        *frame = (current_frame+2) & 1023;
114
        break;
115 116 117 118 119 120
      }
    }
  }
}

void get_Msg3_alloc_ret(LTE_DL_FRAME_PARMS *frame_parms,
121 122 123 124 125
                        unsigned char current_subframe,
                        unsigned int current_frame,
                        unsigned int *frame,
                        unsigned char *subframe)
{
126
  if (frame_parms->frame_type == FDD) {
roux's avatar
roux committed
127 128
    /* always retransmit in n+8 */
    *subframe = current_subframe + 8;
129

roux's avatar
roux committed
130 131 132
    if (*subframe > 9) {
      *subframe = *subframe - 10;
      *frame = (current_frame + 1) & 1023;
133
    } else {
roux's avatar
roux committed
134
      *frame = current_frame;
135
    }
136
  } else {
137 138 139 140 141
    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
142
      *frame = (current_frame+1) & 1023;
143
    } else if (frame_parms->tdd_config == 3) {
144 145 146
      // 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
147
      *frame=(current_frame+1) & 1023;
148 149 150 151
    }
  }
}

152
uint8_t get_Msg3_harq_pid(LTE_DL_FRAME_PARMS *frame_parms,
153 154 155
                          uint32_t frame,
                          unsigned char current_subframe)
{
156

157
  uint8_t ul_subframe=0;
158
  uint32_t ul_frame=0;
159

160
  if (frame_parms->frame_type ==FDD) {
161
    ul_subframe = (current_subframe>3) ? (current_subframe-4) : (current_subframe+6);
162
    ul_frame    = (current_subframe>3) ? ((frame+1)&1023) : frame;
163
  } else {
164 165 166 167 168 169
    switch (frame_parms->tdd_config) {
    case 1:
      switch (current_subframe) {

      case 9:
      case 0:
170 171 172
        ul_subframe = 7;
        break;

173 174
      case 5:
      case 7:
175 176
        ul_subframe = 2;
        break;
177 178

      }
179

180
      break;
181

182 183 184 185 186 187
    case 3:
      switch (current_subframe) {

      case 0:
      case 5:
      case 6:
188 189 190
        ul_subframe = 2;
        break;

191
      case 7:
192 193 194
        ul_subframe = 3;
        break;

195
      case 8:
196 197 198
        ul_subframe = 4;
        break;

199
      case 9:
200 201
        ul_subframe = 2;
        break;
202
      }
203

204
      break;
205

206 207 208 209 210 211 212 213
    case 4:
      switch (current_subframe) {

      case 0:
      case 5:
      case 6:
      case 8:
      case 9:
214 215 216
        ul_subframe = 2;
        break;

217
      case 7:
218 219
        ul_subframe = 3;
        break;
220
      }
221

222
      break;
223

224 225 226
    case 5:
      ul_subframe =2;
      break;
227

228 229
    default:
      LOG_E(PHY,"get_Msg3_harq_pid: Unsupported TDD configuration %d\n",frame_parms->tdd_config);
gauthier's avatar
gauthier committed
230
      mac_xface->macphy_exit("get_Msg3_harq_pid: Unsupported TDD configuration");
231 232 233
      break;
    }
  }
234

235 236 237 238
  return(subframe2harq_pid(frame_parms,ul_frame,ul_subframe));

}

239 240
unsigned char ul_ACK_subframe2_dl_subframe(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe,unsigned char ACK_index)
{
241

242
  if (frame_parms->frame_type == FDD) {
243
    return((subframe<4) ? subframe+6 : subframe-4);
244
  } else {
245 246 247
    switch (frame_parms->tdd_config) {
    case 3:
      if (subframe == 2) {  // ACK subframes 5 and 6
248 249 250 251 252 253 254 255 256 257 258 259
        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);
260
      }
261

262
      break;
263

264 265
    case 1:
      if (subframe == 2) {  // ACK subframes 5 and 6
266 267 268 269 270 271 272 273 274 275 276
        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);
277
      }
278

279 280 281
      break;
    }
  }
282

283 284 285
  return(0);
}

286 287
unsigned char ul_ACK_subframe2_M(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe)
{
288

289
  if (frame_parms->frame_type == FDD) {
290
    return(1);
291
  } else {
292 293 294
    switch (frame_parms->tdd_config) {
    case 3:
      if (subframe == 2) {  // ACK subframes 5 and 6
295 296 297 298 299 300 301 302 303
        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);
304
      }
305

306
      break;
307

308 309
    case 1:
      if (subframe == 2) {  // ACK subframes 5 and 6
310 311 312 313 314 315 316 317 318 319 320
        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);
321
      }
322

323 324 325
      break;
    }
  }
326

327 328 329 330
  return(0);
}

// This function implements table 10.1-1 of 36-213, p. 69
331
uint8_t get_ack(LTE_DL_FRAME_PARMS *frame_parms,
332 333 334 335
                harq_status_t *harq_ack,
                unsigned char subframe,
                unsigned char *o_ACK)
{
336

337

338 339
  uint8_t status=0;
  uint8_t subframe_dl;
340

341
  //  printf("get_ack: SF %d\n",subframe);
342 343 344 345 346
  if (frame_parms->frame_type == FDD) {
    if (subframe < 4)
      subframe_dl = subframe + 6;
    else
      subframe_dl = subframe - 4;
347

348 349
    o_ACK[0] = harq_ack[subframe_dl].ack;
    status = harq_ack[subframe_dl].send_harq_status;
350
    //printf("get_ack: Getting ACK/NAK for PDSCH (subframe %d) => %d\n",subframe_dl,o_ACK[0]);
351
  } else {
352 353 354
    switch (frame_parms->tdd_config) {
    case 1:
      if (subframe == 2) {  // ACK subframes 5 (forget 6)
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
        o_ACK[0] = harq_ack[5].ack;
        status = harq_ack[5].send_harq_status;
      } else if (subframe == 3) { // ACK subframe 9
        o_ACK[0] = harq_ack[9].ack;
        status = harq_ack[9].send_harq_status;
      } else if (subframe == 4) { // nothing
        status = 0;
      } else if (subframe == 7) { // ACK subframes 0 (forget 1)
        o_ACK[0] = harq_ack[0].ack;
        status = harq_ack[0].send_harq_status;
      } else if (subframe == 8) { // ACK subframes 4
        o_ACK[0] = harq_ack[4].ack;
        status = harq_ack[4].send_harq_status;
      } else {
        LOG_E(PHY,"phy_procedures_lte.c: get_ack, illegal subframe %d for tdd_config %d\n",
              subframe,frame_parms->tdd_config);
        return(0);
372
      }
373

374
      break;
375

376 377
    case 3:
      if (subframe == 2) {  // ACK subframes 5 and 6
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
        if (harq_ack[5].send_harq_status == 1) {
          o_ACK[0] = harq_ack[5].ack;

          if (harq_ack[6].send_harq_status == 1)
            o_ACK[1] = harq_ack[6].ack;
        } else if (harq_ack[6].send_harq_status == 1)
          o_ACK[0] = harq_ack[6].ack;

        status = harq_ack[5].send_harq_status + (harq_ack[6].send_harq_status<<1);
        //printf("Subframe 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 == 3) { // ACK subframes 7 and 8
        if (harq_ack[7].send_harq_status == 1) {
          o_ACK[0] = harq_ack[7].ack;

          if (harq_ack[8].send_harq_status == 1)
            o_ACK[1] = harq_ack[8].ack;
        } else if (harq_ack[8].send_harq_status == 1)
          o_ACK[0] = harq_ack[8].ack;

        status = harq_ack[7].send_harq_status + (harq_ack[8].send_harq_status<<1);
        //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 if (subframe == 4) { // ACK subframes 9 and 0
        if (harq_ack[9].send_harq_status == 1) {
          o_ACK[0] = harq_ack[9].ack;

          if (harq_ack[0].send_harq_status == 1)
            o_ACK[1] = harq_ack[0].ack;
406 407
        } else if (harq_ack[0].send_harq_status == 1)
          o_ACK[0] = harq_ack[0].ack;
408 409 410 411 412 413 414

        status = harq_ack[9].send_harq_status + (harq_ack[0].send_harq_status<<1);
        //printf("Subframe 4, TDD config 3: harq_ack[9] = %d,harq_ack[0] = %d\n",harq_ack[9].ack,harq_ack[0].ack);
      } else {
        LOG_E(PHY,"phy_procedures_lte.c: get_ack, illegal subframe %d for tdd_config %d\n",
              subframe,frame_parms->tdd_config);
        return(0);
415
      }
416

417
      break;
418

419 420
    }
  }
421

422 423 424 425 426
  //printf("status %d\n",status);

  return(status);
}

427 428 429 430 431 432
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};
433
// This is part of the PUCCH allocation procedure (see Section 10.1 36.213)
434 435
uint16_t get_Np(uint8_t N_RB_DL,uint8_t nCCE,uint8_t plus1)
{
436
  uint8_t *Np;
437

438
  switch (N_RB_DL) {
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
  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;
  }
468 469 470 471 472 473 474 475 476

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

477 478
lte_subframe_t subframe_select(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe)
{
479 480

  // if FDD return dummy value
481
  if (frame_parms->frame_type == FDD)
482 483 484 485 486 487 488 489 490 491 492 493
    return(SF_DL);

  switch (frame_parms->tdd_config) {

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

495 496 497 498 499 500
    case 2:
    case 3:
    case 7:
    case 8:
      return(SF_UL);
      break;
501

502 503 504 505
    default:
      return(SF_S);
      break;
    }
506

507
  case 3:
508
    if  ((subframe<1) || (subframe>=5))
509
      return(SF_DL);
510
    else if ((subframe>1) && (subframe < 5))
511 512 513 514 515 516 517
      return(SF_UL);
    else if (subframe==1)
      return (SF_S);
    else  {
      LOG_E(PHY,"[PHY_PROCEDURES_LTE] Unknown subframe number\n");
      return(255);
    }
518

519
    break;
520

521 522
  default:
    LOG_E(PHY,"subframe %d Unsupported TDD configuration %d\n",subframe,frame_parms->tdd_config);
gauthier's avatar
gauthier committed
523
    mac_xface->macphy_exit("subframe x Unsupported TDD configuration");
524
    return(255);
525

526 527 528
  }
}

529 530
lte_subframe_t get_subframe_direction(uint8_t Mod_id,uint8_t CC_id,uint8_t subframe)
{
531

532
  return(subframe_select(&PHY_vars_eNB_g[Mod_id][CC_id]->lte_frame_parms,subframe));
533 534 535

}

536 537
uint8_t phich_subframe_to_harq_pid(LTE_DL_FRAME_PARMS *frame_parms,uint32_t frame,uint8_t subframe)
{
538 539 540

  //LOG_D(PHY,"phich_subframe_to_harq_pid.c: frame %d, subframe %d\n",frame,subframe);
  return(subframe2harq_pid(frame_parms,
541 542
                           phich_frame2_pusch_frame(frame_parms,frame,subframe),
                           phich_subframe2_pusch_subframe(frame_parms,subframe)));
543 544
}

545 546
unsigned int is_phich_subframe(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe)
{
547

548
  if (frame_parms->frame_type == FDD) {
549
    return(1);
550
  } else {
551 552 553
    switch (frame_parms->tdd_config) {
    case 1:
      if ((subframe == 1) || (subframe == 4) || (subframe == 6) || (subframe == 9))
554 555
        return(1);

556
      break;
557

558 559
    case 3:
      if ((subframe == 0) || (subframe == 8) || (subframe == 9))
560 561
        return(1);

562
      break;
563

564 565
    case 4:
      if ((subframe == 0) || (subframe == 8) )
566 567
        return(1);

568
      break;
569

570 571
    case 5:
      if (subframe == 0)
572 573
        return(1);

574
      break;
575

576 577 578 579 580
    default:
      return(0);
      break;
    }
  }
581

582 583 584 585
  return(0);
}


586
#ifdef LOCALIZATION
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 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 673 674 675 676 677 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 707 708 709
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;
  LTE_DL_FRAME_PARMS *frame_parms = &phy_vars_eNB->lte_frame_parms;

  Mod_id = phy_vars_eNB->Mod_id;
  CC_id = phy_vars_eNB->CC_id;
  ref_timestamp_ms = phy_vars_eNB->ulsch_eNB[UE_id+1]->reference_timestamp_ms;

  for (i=0; i<13; i++) {
    len += sprintf(&cqis[len]," %d ", phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].DL_subband_cqi[0][i]);
  }

  len = 0;

  for (i=0; i<phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->active_subcarrier; i++) {
    len += sprintf(&sub_powers[len]," %d ", phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->subcarrier_power[i]);
  }

  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"
        phy_vars_eNB->dlsch_eNB[(uint32_t)UE_id][0]->rnti, UE_id, Mod_id, current_timestamp_ms,
        frame,subframe,
        UE_tx_power_dB,
        phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].UL_rssi[0],
        phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].UL_rssi[1],
        dB_fixed(phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->ulsch_power[0]),
        dB_fixed(phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->ulsch_power[1]),
        phy_vars_eNB->rx_total_gain_eNB_dB,
        phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].UE_timing_offset, // raw timing advance 1/sampling rate
        phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].timing_advance_update,
        phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].DL_cqi[0],phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].DL_cqi[1],
        phy_vars_eNB->PHY_measurements_eNB[Mod_id].wideband_cqi_dB[(uint32_t)UE_id][0],
        phy_vars_eNB->PHY_measurements_eNB[Mod_id].wideband_cqi_dB[(uint32_t)UE_id][1],
        cqis);
  LOG_D(LOCALIZE, " PHY: timestamp %d, (%d active subcarrier) %s \n",
        current_timestamp_ms,
        phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->active_subcarrier,
        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;
  }

  if ((current_timestamp_ms - ref_timestamp_ms > phy_vars_eNB->ulsch_eNB[UE_id+1]->aggregation_period_ms)) {
    // 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
    phy_vars_eNB->ulsch_eNB[UE_id+1]->reference_timestamp_ms = current_timestamp_ms;
    int i;

    for (i=0; i<10; i++) {
      median_power = calculate_median(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_rss_list[i]);
      del(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_rss_list[i]);
      median_rssi = calculate_median(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_rssi_list[i]);
      del(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_rssi_list[i]);
      median_subcarrier_rss = calculate_median(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_subcarrier_rss_list[i]);
      del(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_subcarrier_rss_list[i]);
      median_TA = calculate_median(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_timing_advance_list[i]);
      del(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_timing_advance_list[i]);
      median_TA_update = calculate_median(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_timing_update_list[i]);
      del(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_timing_update_list[i]);

      if (median_power != 0)
        push_front(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_rss_list,median_power);

      if (median_rssi != 0)
        push_front(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_rssi_list,median_rssi);

      if (median_subcarrier_rss != 0)
        push_front(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_subcarrier_rss_list,median_subcarrier_rss);

      if (median_TA != 0)
        push_front(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_timing_advance_list,median_TA);

      if (median_TA_update != 0)
        push_front(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_timing_update_list,median_TA_update);

      initialize(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_rss_list[i]);
      initialize(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_subcarrier_rss_list[i]);
      initialize(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_rssi_list[i]);
      initialize(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_timing_advance_list[i]);
      initialize(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_timing_update_list[i]);
710
    }
711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742

    median_power = calculate_median(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_rss_list);
    del(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_rss_list);
    median_rssi = calculate_median(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_rssi_list);
    del(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_rssi_list);
    median_subcarrier_rss = calculate_median(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_subcarrier_rss_list);
    del(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_subcarrier_rss_list);
    median_TA = calculate_median(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_timing_advance_list);
    del(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_timing_advance_list);
    median_TA_update = calculate_median(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_timing_update_list);
    del(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_timing_update_list);

    initialize(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_rss_list);
    initialize(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_subcarrier_rss_list);
    initialize(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_rssi_list);
    initialize(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_timing_advance_list);
    initialize(&phy_vars_eNB->ulsch_eNB[UE_id+1]->tot_loc_timing_update_list);

    double alpha = 2, power_distance, time_distance;
    // distance = 10^((Ptx - Prx - A)/10alpha), A is a constance experimentally evaluated
    // A includes the rx gain (phy_vars_eNB->rx_total_gain_eNB_dB) and hardware calibration
    power_distance = pow(10, ((UE_tx_power_dB - median_power - phy_vars_eNB->rx_total_gain_eNB_dB + 133)/(10.0*alpha)));
    /* current measurements shows constant UE_timing_offset = 18
       and timing_advance_update = 11 at 1m. at 5m, timing_advance_update = 12*/
    //time_distance = (double) 299792458*(phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].timing_advance_update)/(sys_bw*1000000);
    time_distance = (double) abs(phy_vars_eNB->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

    phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].distance.time_based = time_distance;
    phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].distance.power_based = power_distance;

    LOG_D(LOCALIZE, " PHY agg [UE %x/%d -> eNB %d], timestamp %d, "
          "frame %d, subframe %d "
743
          "UE Tx power %d dBm, "
744 745
          "median RSSI %d dBm, "
          "median Power %d dBm, "
746
          "Rx gain %d dB, "
747 748 749 750 751
          "power estimated r = %0.3f, "
          " TA %d, update %d "
          "TA estimated r = %0.3f\n"
          ,phy_vars_eNB->dlsch_eNB[(uint32_t)UE_id][0]->rnti, UE_id, Mod_id, current_timestamp_ms,
          frame, subframe,
752
          UE_tx_power_dB,
753 754
          median_rssi,
          median_power,
755
          phy_vars_eNB->rx_total_gain_eNB_dB,
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
          power_distance,
          phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].UE_timing_offset, median_TA_update,
          time_distance);

    return 0;
  } else {
    avg_power = (dB_fixed(phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->ulsch_power[0]) + dB_fixed(phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->ulsch_power[1]))/2;
    avg_rssi = (phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].UL_rssi[0] + phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].UL_rssi[1])/2;

    push_front(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_rss_list[subframe],avg_power);
    push_front(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_rssi_list[subframe],avg_rssi);

    for (i=0; i<phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->active_subcarrier; i++) {
      push_front(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_subcarrier_rss_list[subframe], phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->subcarrier_power[i]);
    }

    push_front(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_timing_advance_list[subframe], phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].UE_timing_offset);
    push_front(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_timing_update_list[subframe], phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].timing_advance_update);
    return -1;
  }
776 777
}
#endif
778 779
LTE_eNB_UE_stats* get_eNB_UE_stats(uint8_t Mod_id, uint8_t  CC_id,uint16_t rnti)
{
780
  int8_t UE_id;
781

782 783
  if ((PHY_vars_eNB_g == NULL) || (PHY_vars_eNB_g[Mod_id] == NULL) || (PHY_vars_eNB_g[Mod_id][CC_id]==NULL)) {
    LOG_E(PHY,"get_eNB_UE_stats: No phy_vars_eNB found (or not allocated) for Mod_id %d,CC_id %d\n",Mod_id,CC_id);
784 785
    return NULL;
  }
786

787
  UE_id = find_ue(rnti, PHY_vars_eNB_g[Mod_id][CC_id]);
788

789
  if (UE_id == -1) {
790
    //    LOG_E(PHY,"get_eNB_UE_stats: UE with rnti %x not found\n",rnti);
791 792
    return NULL;
  }
793

794
  return(&PHY_vars_eNB_g[Mod_id][CC_id]->eNB_UE_stats[(uint32_t)UE_id]);
795 796
}

797 798
int8_t find_ue(uint16_t rnti, PHY_VARS_eNB *phy_vars_eNB)
{
799
  uint8_t i;
800

801 802 803 804
  for (i=0; i<NUMBER_OF_UE_MAX; i++) {
    if ((phy_vars_eNB->dlsch_eNB[i]) &&
        (phy_vars_eNB->dlsch_eNB[i][0]) &&
        (phy_vars_eNB->dlsch_eNB[i][0]->rnti==rnti)) {
805 806 807
      return(i);
    }
  }
808 809 810 811

#ifdef CBA

  for (i=0; i<NUM_MAX_CBA_GROUP; i++) {
812
    if ((phy_vars_eNB->ulsch_eNB[i]) && // ue J is the representative of group j
813 814
        (phy_vars_eNB->ulsch_eNB[i]->num_active_cba_groups) &&
        (phy_vars_eNB->ulsch_eNB[i]->cba_rnti[i]== rnti))
815 816
      return(i);
  }
817 818 819

#endif

820 821 822
  return(-1);
}

823 824
LTE_DL_FRAME_PARMS* get_lte_frame_parms(module_id_t Mod_id, uint8_t  CC_id)
{
825 826 827 828 829

  return(&PHY_vars_eNB_g[Mod_id][CC_id]->lte_frame_parms);

}

830 831 832
MU_MIMO_mode *get_mu_mimo_mode (module_id_t Mod_id, uint8_t  CC_id, rnti_t rnti)
{
  int8_t UE_id = find_ue( rnti, PHY_vars_eNB_g[Mod_id][CC_id] );
833

834
  if (UE_id == -1)
835 836
    return 0;

837
  return &PHY_vars_eNB_g[Mod_id][CC_id]->mu_mimo_mode[UE_id];
838
}