phich.c 46.3 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 24
  OpenAirInterface Admin: openair_admin@eurecom.fr
  OpenAirInterface Tech : openair_tech@eurecom.fr
  OpenAirInterface Dev  : openair4g-devel@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 45 46 47 48 49 50 51 52 53 54 55

/*! \file PHY/LTE_TRANSPORT/phich.c
* \brief Top-level routines for generating and decoding  the PHICH/HI physical/transport channel V8.6 2009-03
* \author R. Knopp
* \date 2011
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr
* \note
* \warning
*/

#include "PHY/defs.h"
#include "PHY/extern.h"
#include "SCHED/defs.h"
#include "defs.h"
#ifndef USER_MODE
#include "ARCH/CBMIMO1/DEVICE_DRIVER/extern.h"
#endif

//#define DEBUG_PHICH 1

//extern unsigned short pcfich_reg[4];
//extern unsigned char pcfich_first_reg_idx;

//unsigned short phich_reg[MAX_NUM_PHICH_GROUPS][3];

knopp's avatar
 
knopp committed
56 57

uint8_t rv_table[4] = {0, 2, 3, 1};
58

59 60
uint8_t get_mi(LTE_DL_FRAME_PARMS *frame_parms,uint8_t subframe)
{
61 62

  // for FDD
knopp's avatar
 
knopp committed
63
  if (frame_parms->frame_type == FDD)
64 65 66 67 68
    return 1;

  // for TDD
  switch (frame_parms->tdd_config) {

69
  case 0:
70 71 72
    if ((subframe==0) || (subframe==5))
      return(2);
    else return(1);
73

74
    break;
75 76

  case 1:
77 78 79
    if ((subframe==0) || (subframe==5))
      return(0);
    else return(1);
80

81
    break;
82 83

  case 2:
84 85 86
    if ((subframe==3) || (subframe==8))
      return(1);
    else return(0);
87

88
    break;
89 90

  case 3:
91 92 93
    if ((subframe==0) || (subframe==8) || (subframe==9))
      return(1);
    else return(0);
94

95
    break;
96

97 98 99 100
  case 4:
    if ((subframe==8) || (subframe==9))
      return(1);
    else return(0);
101

102
    break;
103

104 105 106 107
  case 5:
    if (subframe==8)
      return(1);
    else return(0);
108

109
    break;
110

111
  case 6:
112 113 114
    return(1);
    break;

115 116 117 118 119
  default:
    return(0);
  }
}

120 121
unsigned char subframe2_ul_harq(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe)
{
122

knopp's avatar
 
knopp committed
123
  if (frame_parms->frame_type == FDD)
124
    return(subframe&7);
125

126 127
  switch (frame_parms->tdd_config) {
  case 3:
128
    if ( (subframe == 8) || (subframe == 9) ) {
129
      return(subframe-8);
130
    } else if (subframe==0)
131 132 133
      return(2);
    else {
      LOG_E(PHY,"phich.c: subframe2_ul_harq, illegal subframe %d for tdd_config %d\n",
134
            subframe,frame_parms->tdd_config);
135 136
      return(0);
    }
137

138
    break;
139

140
  }
141

142 143 144
  return(0);
}

145 146
uint8_t phich_frame2_pusch_frame(LTE_DL_FRAME_PARMS *frame_parms,frame_t frame,uint8_t subframe)
{
knopp's avatar
 
knopp committed
147
  if (frame_parms->frame_type == FDD) {
148
    return((subframe<4) ? (frame - 1) : frame);
149
  } else {
150 151 152 153 154
    // Note this is not true, but it doesn't matter, the frame number is irrelevant for TDD!
    return(frame);
  }
}

155 156
uint8_t phich_subframe2_pusch_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint8_t subframe)
{
157

knopp's avatar
 
knopp committed
158
  if (frame_parms->frame_type == FDD)
159
    return(subframe<4 ? (subframe+6) : (subframe-4));
160

161 162 163 164 165 166
  switch (frame_parms->tdd_config) {
  case 0:
    if (subframe == 0)
      return(3);
    else if (subframe == 5) {
      return (8);
167
    } else if (subframe == 6)
168 169 170 171 172
      return (2);
    else if (subframe == 1)
      return (7);
    else {
      LOG_E(PHY, "phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n",
173
            subframe,frame_parms->tdd_config);
174 175
      return(0);
    }
176

177
    break;
178

179 180 181
  case 1:
    if (subframe == 6)
      return(2);
182
    else if (subframe == 9)
183 184 185 186 187 188 189
      return (3);
    else if (subframe == 1)
      return (7);
    else if (subframe == 4)
      return (8);
    else {
      LOG_E(PHY,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n",
190
            subframe,frame_parms->tdd_config);
191 192
      return(0);
    }
193

194
    break;
195

196 197 198 199 200 201 202
  case 2:
    if (subframe == 8)
      return(2);
    else if (subframe == 3)
      return (7);
    else {
      LOG_E(PHY,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n",
203
            subframe,frame_parms->tdd_config);
204 205
      return(0);
    }
206

207
    break;
208

209
  case 3:
210
    if ( (subframe == 8) || (subframe == 9) ) {
211
      return(subframe-6);
212
    } else if (subframe==0)
213 214 215
      return(4);
    else {
      LOG_E(PHY,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n",
216
            subframe,frame_parms->tdd_config);
217 218
      return(0);
    }
219

220
    break;
221

222
  case 4:
223
    if ( (subframe == 8) || (subframe == 9) ) {
224
      return(subframe-6);
225
    } else {
226
      LOG_E(PHY,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n",
227
            subframe,frame_parms->tdd_config);
228 229
      return(0);
    }
230 231 232

    break;

233
  case 5:
234
    if (subframe == 8) {
235
      return(2);
236
    } else {
237
      LOG_E(PHY,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n",
238
            subframe,frame_parms->tdd_config);
239 240
      return(0);
    }
241

242 243 244
    break;

  case 6:
245
    if (subframe == 6) {
246
      return(2);
247
    } else if (subframe == 9) {
248
      return(3);
249
    } else if (subframe == 0) {
250
      return(4);
251
    } else if (subframe == 1) {
252
      return(7);
253
    } else if (subframe == 5) {
254
      return(8);
255
    } else {
256
      LOG_E(PHY,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n",
257
            subframe,frame_parms->tdd_config);
258 259
      return(0);
    }
260

261
    break;
262

263
  }
264

265 266 267
  return(0);
}

268 269
int check_pcfich(LTE_DL_FRAME_PARMS *frame_parms,uint16_t reg)
{
270 271 272 273 274 275

  if ((reg == frame_parms->pcfich_reg[0]) ||
      (reg == frame_parms->pcfich_reg[1]) ||
      (reg == frame_parms->pcfich_reg[2]) ||
      (reg == frame_parms->pcfich_reg[3]))
    return(1);
276

277 278 279
  return(0);
}

280 281
void generate_phich_reg_mapping(LTE_DL_FRAME_PARMS *frame_parms)
{
282 283 284 285 286 287

  unsigned short n0 = (frame_parms->N_RB_DL * 2) - 4;  // 2 REG per RB less the 4 used by PCFICH in first symbol
  unsigned short n1 = (frame_parms->N_RB_DL * 3);      // 3 REG per RB in second and third symbol
  unsigned short n2 = n1;
  unsigned short mprime = 0;
  unsigned short Ngroup_PHICH;
gauthier's avatar
gauthier committed
288 289
  //  uint16_t *phich_reg = frame_parms->phich_reg;
  uint16_t *pcfich_reg = frame_parms->pcfich_reg;
290 291 292

  // compute Ngroup_PHICH (see formula at beginning of Section 6.9 in 36-211
  Ngroup_PHICH = (frame_parms->phich_config_common.phich_resource*frame_parms->N_RB_DL)/48;
293

294

295 296
  if (((frame_parms->phich_config_common.phich_resource*frame_parms->N_RB_DL)%48) > 0)
    Ngroup_PHICH++;
297

298 299 300 301
  // check if Extended prefix
  if (frame_parms->Ncp == 1) {
    Ngroup_PHICH<<=1;
  }
302

303 304 305 306 307 308 309 310 311 312 313
  //#ifdef DEBUG_PHICH
  printf("Ngroup_PHICH %d (phich_config_common.phich_resource %d,phich_config_common.phich_duration %s, NidCell %d,Ncp %d, frame_type %d), smallest pcfich REG %d, n0 %d, n1 %d (first PHICH REG %d)\n",
	 ((frame_parms->Ncp == NORMAL)?Ngroup_PHICH:(Ngroup_PHICH>>1)),
	 frame_parms->phich_config_common.phich_resource,
	 frame_parms->phich_config_common.phich_duration==normal?"normal":"extended",
	 frame_parms->Nid_cell,frame_parms->Ncp,frame_parms->frame_type,
	 pcfich_reg[frame_parms->pcfich_first_reg_idx],
	 n0,
	 n1,
	 ((frame_parms->Nid_cell*n0)/n1)%n0);
  //#endif
314

315
  // This is the algorithm from Section 6.9.3 in 36-211, it works only for normal PHICH duration for now ...
316

317 318 319 320 321
  for (mprime=0; 
       mprime<((frame_parms->Ncp == NORMAL)?Ngroup_PHICH:(Ngroup_PHICH>>1)); 
       mprime++) {

    if (frame_parms->phich_config_common.phich_duration==normal) { // normal PHICH duration
322 323 324 325

      frame_parms->phich_reg[mprime][0] = (frame_parms->Nid_cell + mprime)%n0;

      if (frame_parms->phich_reg[mprime][0]>=pcfich_reg[frame_parms->pcfich_first_reg_idx])
326 327
        frame_parms->phich_reg[mprime][0]++;

328
      if (frame_parms->phich_reg[mprime][0]>=pcfich_reg[(frame_parms->pcfich_first_reg_idx+1)&3])
329 330
        frame_parms->phich_reg[mprime][0]++;

331
      if (frame_parms->phich_reg[mprime][0]>=pcfich_reg[(frame_parms->pcfich_first_reg_idx+2)&3])
332 333
        frame_parms->phich_reg[mprime][0]++;

334
      if (frame_parms->phich_reg[mprime][0]>=pcfich_reg[(frame_parms->pcfich_first_reg_idx+3)&3])
335
        frame_parms->phich_reg[mprime][0]++;
336 337 338

      frame_parms->phich_reg[mprime][1] = (frame_parms->Nid_cell + mprime + (n0/3))%n0;

339
      
340
      if (frame_parms->phich_reg[mprime][1]>=pcfich_reg[frame_parms->pcfich_first_reg_idx])
341
        frame_parms->phich_reg[mprime][1]++;
342
      
343
      if (frame_parms->phich_reg[mprime][1]>=pcfich_reg[(frame_parms->pcfich_first_reg_idx+1)&3])
344 345
        frame_parms->phich_reg[mprime][1]++;

346
      if (frame_parms->phich_reg[mprime][1]>=pcfich_reg[(frame_parms->pcfich_first_reg_idx+2)&3])
347 348
        frame_parms->phich_reg[mprime][1]++;

349
      if (frame_parms->phich_reg[mprime][1]>=pcfich_reg[(frame_parms->pcfich_first_reg_idx+3)&3])
350
        frame_parms->phich_reg[mprime][1]++;
351
      
352 353

      frame_parms->phich_reg[mprime][2] = (frame_parms->Nid_cell + mprime + (2*n0/3))%n0;
354
      
355
      if (frame_parms->phich_reg[mprime][2]>=pcfich_reg[frame_parms->pcfich_first_reg_idx])
356 357
        frame_parms->phich_reg[mprime][2]++;

358
      if (frame_parms->phich_reg[mprime][2]>=pcfich_reg[(frame_parms->pcfich_first_reg_idx+1)&3])
359 360
        frame_parms->phich_reg[mprime][2]++;

361
      if (frame_parms->phich_reg[mprime][2]>=pcfich_reg[(frame_parms->pcfich_first_reg_idx+2)&3])
362 363
        frame_parms->phich_reg[mprime][2]++;

364
      if (frame_parms->phich_reg[mprime][2]>=pcfich_reg[(frame_parms->pcfich_first_reg_idx+3)&3])
365
        frame_parms->phich_reg[mprime][2]++;
366 367 368 369 370
      
      //#ifdef DEBUG_PHICH
      printf("phich_reg :%d => %d,%d,%d\n",mprime,frame_parms->phich_reg[mprime][0],frame_parms->phich_reg[mprime][1],frame_parms->phich_reg[mprime][2]);
      //#endif
    } else { // extended PHICH duration
371 372 373 374 375 376 377 378
      frame_parms->phich_reg[mprime<<1][0] = (frame_parms->Nid_cell + mprime)%n0;
      frame_parms->phich_reg[1+(mprime<<1)][0] = (frame_parms->Nid_cell + mprime)%n0;

      frame_parms->phich_reg[mprime<<1][1] = ((frame_parms->Nid_cell*n1/n0) + mprime + (n1/3))%n1;
      frame_parms->phich_reg[mprime<<1][2] = ((frame_parms->Nid_cell*n2/n0) + mprime + (2*n2/3))%n2;

      frame_parms->phich_reg[1+(mprime<<1)][1] = ((frame_parms->Nid_cell*n1/n0) + mprime + (n1/3))%n1;
      frame_parms->phich_reg[1+(mprime<<1)][2] = ((frame_parms->Nid_cell*n2/n0) + mprime + (2*n2/3))%n2;
379 380 381 382
      //#ifdef DEBUG_PHICH
      printf("phich_reg :%d => %d,%d,%d\n",mprime<<1,frame_parms->phich_reg[mprime<<1][0],frame_parms->phich_reg[mprime][1],frame_parms->phich_reg[mprime][2]);
      printf("phich_reg :%d => %d,%d,%d\n",1+(mprime<<1),frame_parms->phich_reg[1+(mprime<<1)][0],frame_parms->phich_reg[1+(mprime<<1)][1],frame_parms->phich_reg[1+(mprime<<1)][2]);
      //#endif
383 384 385 386 387 388
    }
  } // mprime loop
}  // num_pdcch_symbols loop


void generate_phich_emul(LTE_DL_FRAME_PARMS *frame_parms,
389 390 391
                         uint8_t HI,
                         uint8_t subframe)
{
392 393 394 395 396


}

mod_sym_t alam_bpsk_perm1[4] = {2,1,4,3}; // -conj(x) 1 (-1-j) -> 2 (1-j), 2->1, 3 (-1+j) -> (4) 1+j, 4->3
397
mod_sym_t alam_bpsk_perm2[4] = {3,4,2,1}; // conj(x) 1 (-1-j) -> 3 (-1+j), 3->1, 2 (1-j) -> 4 (1+j), 4->2
398

399
// This routine generates the PHICH
400 401

void generate_phich(LTE_DL_FRAME_PARMS *frame_parms,
402 403 404 405 406 407 408 409
                    int16_t amp,
                    uint8_t nseq_PHICH,
                    uint8_t ngroup_PHICH,
                    uint8_t HI,
                    uint8_t subframe,
                    mod_sym_t **y)
{

410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
  int16_t d[24],*dp;
  //  unsigned int i,aa;
  unsigned int re_offset;
  int16_t y0_16[8],y1_16[8];
  int16_t *y0,*y1;
  // scrambling
  uint32_t x1, x2, s=0;
  uint8_t reset = 1;
  int16_t cs[12];
  uint32_t i,i2,i3,m,j;
  int16_t gain_lin_QPSK;
  uint32_t subframe_offset=((frame_parms->Ncp==0)?14:12)*frame_parms->ofdm_symbol_size*subframe;

  memset(d,0,24*sizeof(int16_t));

425 426
  if (frame_parms->mode1_flag==1)
    gain_lin_QPSK = (int16_t)(((int32_t)amp*ONE_OVER_SQRT2_Q15)>>15);
427
  else
428
    gain_lin_QPSK = amp/2;
429 430 431 432 433 434

  //printf("PHICH : gain_lin_QPSK %d\n",gain_lin_QPSK);

  // BPSK modulation of HI input (to be repeated 3 times, 36-212 Section 5.3.5, p. 56 in v8.6)
  if (HI>0)
    HI=1;
435

436 437
  //  c = (1-(2*HI))*SSS_AMP;
  // x1 is set in lte_gold_generic
438 439
  x2 = (((subframe+1)*(frame_parms->Nid_cell+1))<<9) + frame_parms->Nid_cell;

440
  s = lte_gold_generic(&x1, &x2, reset);
441

442
  // compute scrambling sequence
443
  for (i=0; i<12; i++) {
444 445 446 447 448 449 450 451
    cs[i] = (uint8_t)((s>>(i&0x1f))&1);
    cs[i] = (cs[i] == 0) ? (1-(HI<<1)) : ((HI<<1)-1);
  }

  if (frame_parms->Ncp == 0) { // Normal Cyclic Prefix

    //    printf("Doing PHICH : Normal CP, subframe %d\n",subframe);
    // 12 output symbols (Msymb)
452
    for (i=0,i2=0,i3=0; i<3; i++,i2+=4,i3+=8) {
453 454
      switch (nseq_PHICH) {
      case 0: // +1 +1 +1 +1
455 456 457 458 459 460 461 462 463 464
        d[i3]   = cs[i2];
        d[1+i3] = cs[i2];
        d[2+i3] = cs[1+i2];
        d[3+i3] = cs[1+i2];
        d[4+i3] = cs[2+i2];
        d[5+i3] = cs[2+i2];
        d[6+i3] = cs[3+i2];
        d[7+i3] = cs[3+i2];
        break;

465
      case 1: // +1 -1 +1 -1
466 467 468 469 470 471 472 473 474 475
        d[i3] = cs[i2];
        d[1+i3] = cs[i2];
        d[2+i3] = -cs[1+i2];
        d[3+i3] = -cs[1+i2];
        d[4+i3] = cs[2+i2];
        d[5+i3] = cs[2+i2];
        d[6+i3] = -cs[3+i2];
        d[7+i3] = -cs[3+i2];
        break;

476
      case 2: // +1 +1 -1 -1
477 478 479 480 481 482 483 484 485 486
        d[i3]   = cs[i2];
        d[1+i3]   = cs[i2];
        d[2+i3] = cs[1+i2];
        d[3+i3] = cs[1+i2];
        d[4+i3] = -cs[2+i2];
        d[5+i3] = -cs[2+i2];
        d[6+i3] = -cs[3+i2];
        d[7+i3] = -cs[3+i2];
        break;

487
      case 3: // +1 -1 -1 +1
488 489 490 491 492 493 494 495 496 497
        d[i3]   = cs[i2];
        d[1+i3]   = cs[i2];
        d[2+i3] = -cs[1+i2];
        d[3+i3] = -cs[1+i2];
        d[4+i3] = -cs[2+i2];
        d[5+i3] = -cs[2+i2];
        d[6+i3] = cs[3+i2];
        d[7+i3] = cs[3+i2];
        break;

498
      case 4: // +j +j +j +j
499 500 501 502 503 504 505 506 507 508
        d[i3]   = -cs[i2];
        d[1+i3] = cs[i2];
        d[2+i3] = -cs[1+i2];
        d[3+i3] = cs[1+i2];
        d[4+i3] = -cs[2+i2];
        d[5+i3] = cs[2+i2];
        d[6+i3] = -cs[3+i2];
        d[7+i3] = cs[3+i2];
        break;

509
      case 5: // +j -j +j -j
510 511 512 513 514 515 516 517 518 519
        d[1+i3] = cs[i2];
        d[3+i3] = -cs[1+i2];
        d[5+i3] = cs[2+i2];
        d[7+i3] = -cs[3+i2];
        d[i3]   = -cs[i2];
        d[2+i3] = cs[1+i2];
        d[4+i3] = -cs[2+i2];
        d[6+i3] = cs[3+i2];
        break;

520
      case 6: // +j +j -j -j
521 522 523 524 525 526 527 528 529 530
        d[1+i3] = cs[i2];
        d[3+i3] = cs[1+i2];
        d[5+i3] = -cs[2+i2];
        d[7+i3] = -cs[3+i2];
        d[i3]   = -cs[i2];
        d[2+i3] = -cs[1+i2];
        d[4+i3] = cs[2+i2];
        d[6+i3] = cs[3+i2];
        break;

531
      case 7: // +j -j -j +j
532 533 534 535 536 537 538 539 540 541
        d[1+i3] = cs[i2];
        d[3+i3] = -cs[1+i2];
        d[5+i3] = -cs[2+i2];
        d[7+i3] = cs[3+i2];
        d[i3]   = -cs[i2];
        d[2+i3] = cs[1+i2];
        d[4+i3] = cs[2+i2];
        d[6+i3] = -cs[3+i2];
        break;

542
      default:
543
        LOG_E(PHY,"phich_coding.c: Illegal PHICH Number\n");
544 545
      } // nseq_PHICH
    }
546

547 548
#ifdef DEBUG_PHICH
    LOG_D(PHY,"[PUSCH 0]PHICH d = ");
549 550

    for (i=0; i<24; i+=2)
551
      LOG_D(PHY,"(%d,%d)",d[i],d[i+1]);
552

553 554
    LOG_D(PHY,"\n");
#endif
555 556

    // modulation here
557 558
    if (frame_parms->mode1_flag == 0) {
      // do Alamouti precoding here
559

560 561 562 563
      // Symbol 0
      re_offset = frame_parms->first_carrier_offset + (frame_parms->phich_reg[ngroup_PHICH][0]*6);

      if (re_offset > frame_parms->ofdm_symbol_size)
564
        re_offset -= (frame_parms->ofdm_symbol_size-1);
565 566 567

      y0 = (int16_t*)&y[0][re_offset+subframe_offset];
      y1 = (int16_t*)&y[1][re_offset+subframe_offset];
568

569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
      // first antenna position n -> x0
      y0_16[0]   = d[0]*gain_lin_QPSK;
      y0_16[1]   = d[1]*gain_lin_QPSK;
      // second antenna position n -> -x1*
      y1_16[0]   = -d[2]*gain_lin_QPSK;
      y1_16[1]   = d[3]*gain_lin_QPSK;
      // fill in the rest of the ALAMOUTI precoding
      y0_16[2] = -y1_16[0];
      y0_16[3] = y1_16[1];
      y1_16[2] = y0_16[0];
      y1_16[3] = -y0_16[1];

      // first antenna position n -> x0
      y0_16[4]   = d[4]*gain_lin_QPSK;
      y0_16[5]   = d[5]*gain_lin_QPSK;
      // second antenna position n -> -x1*
      y1_16[4]   = -d[6]*gain_lin_QPSK;
      y1_16[5]   = d[7]*gain_lin_QPSK;
      // fill in the rest of the ALAMOUTI precoding
      y0_16[6] = -y1_16[4];
      y0_16[7] = y1_16[5];
      y1_16[6] = y0_16[4];
      y1_16[7] = -y0_16[5];

593 594 595 596 597 598 599
      for (i=0,j=0,m=0; i<6; i++,j+=2) {
        if ((i!=(frame_parms->nushift))&&(i!=(frame_parms->nushift+3))) {
          y0[j]   += y0_16[m];
          y1[j]   += y1_16[m++];
          y0[j+1] += y0_16[m];
          y1[j+1] += y1_16[m++];
        }
600
      }
601

602 603 604 605
      // Symbol 1
      re_offset = frame_parms->first_carrier_offset + (frame_parms->phich_reg[ngroup_PHICH][1]*6);

      if (re_offset > frame_parms->ofdm_symbol_size)
606
        re_offset -= (frame_parms->ofdm_symbol_size-1);
607 608 609

      y0 = (int16_t*)&y[0][re_offset+subframe_offset];
      y1 = (int16_t*)&y[1][re_offset+subframe_offset];
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
      // first antenna position n -> x0
      y0_16[0]   = d[8]*gain_lin_QPSK;
      y0_16[1]   = d[9]*gain_lin_QPSK;
      // second antenna position n -> -x1*
      y1_16[0]   = -d[10]*gain_lin_QPSK;
      y1_16[1]   = d[11]*gain_lin_QPSK;
      // fill in the rest of the ALAMOUTI precoding
      y0_16[2] = -y1_16[0];
      y0_16[3] = y1_16[1];
      y1_16[2] = y0_16[0];
      y1_16[3] = -y0_16[1];

      // first antenna position n -> x0
      y0_16[4]   = d[12]*gain_lin_QPSK;
      y0_16[5]   = d[13]*gain_lin_QPSK;
      // second antenna position n -> -x1*
      y1_16[4]   = -d[14]*gain_lin_QPSK;
      y1_16[5]   = d[15]*gain_lin_QPSK;
      // fill in the rest of the ALAMOUTI precoding
      y0_16[6] = -y1_16[4];
      y0_16[7] = y1_16[5];
      y1_16[6] = y0_16[4];
      y1_16[7] = -y0_16[5];

635 636 637 638 639 640 641
      for (i=0,j=0,m=0; i<6; i++,j+=2) {
        if ((i!=(frame_parms->nushift))&&(i!=(frame_parms->nushift+3))) {
          y0[j]   += y0_16[m];
          y1[j]   += y1_16[m++];
          y0[j+1] += y0_16[m];
          y1[j+1] += y1_16[m++];
        }
642 643 644 645 646 647
      }

      // Symbol 2
      re_offset = frame_parms->first_carrier_offset + (frame_parms->phich_reg[ngroup_PHICH][2]*6);

      if (re_offset > frame_parms->ofdm_symbol_size)
648
        re_offset -= (frame_parms->ofdm_symbol_size-1);
649 650 651

      y0 = (int16_t*)&y[0][re_offset+subframe_offset];
      y1 = (int16_t*)&y[1][re_offset+subframe_offset];
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
      // first antenna position n -> x0
      y0_16[0]   = d[16]*gain_lin_QPSK;
      y0_16[1]   = d[17]*gain_lin_QPSK;
      // second antenna position n -> -x1*
      y1_16[0]   = -d[18]*gain_lin_QPSK;
      y1_16[1]   = d[19]*gain_lin_QPSK;
      // fill in the rest of the ALAMOUTI precoding
      y0_16[2] = -y1_16[0];
      y0_16[3] = y1_16[1];
      y1_16[2] = y0_16[0];
      y1_16[3] = -y0_16[1];

      // first antenna position n -> x0
      y0_16[4]   = d[20]*gain_lin_QPSK;
      y0_16[5]   = d[21]*gain_lin_QPSK;
      // second antenna position n -> -x1*
      y1_16[4]   = -d[22]*gain_lin_QPSK;
      y1_16[5]   = d[23]*gain_lin_QPSK;
      // fill in the rest of the ALAMOUTI precoding
      y0_16[6] = -y1_16[4];
      y0_16[7] = y1_16[5];
      y1_16[6] = y0_16[4];
      y1_16[7] = -y0_16[5];

677 678 679 680 681 682 683
      for (i=0,j=0,m=0; i<6; i++,j+=2) {
        if ((i!=(frame_parms->nushift))&&(i!=(frame_parms->nushift+3))) {
          y0[j]   += y0_16[m];
          y1[j]   += y1_16[m++];
          y0[j+1] += y0_16[m];
          y1[j+1] += y1_16[m++];
        }
684 685 686 687 688 689 690 691 692 693
      }

    } // mode1_flag

    else {
      // Symbol 0
      //      printf("[PUSCH 0]PHICH REG %d\n",frame_parms->phich_reg[ngroup_PHICH][0]);
      re_offset = frame_parms->first_carrier_offset + (frame_parms->phich_reg[ngroup_PHICH][0]*6);

      if (re_offset > frame_parms->ofdm_symbol_size)
694
        re_offset -= (frame_parms->ofdm_symbol_size-1);
695 696 697 698 699 700 701 702 703 704 705 706 707

      y0 = (int16_t*)&y[0][re_offset+subframe_offset];
      //      printf("y0 %p\n",y0);

      y0_16[0]   = d[0]*gain_lin_QPSK;
      y0_16[1]   = d[1]*gain_lin_QPSK;
      y0_16[2]   = d[2]*gain_lin_QPSK;
      y0_16[3]   = d[3]*gain_lin_QPSK;
      y0_16[4]   = d[4]*gain_lin_QPSK;
      y0_16[5]   = d[5]*gain_lin_QPSK;
      y0_16[6]   = d[6]*gain_lin_QPSK;
      y0_16[7]   = d[7]*gain_lin_QPSK;

708 709 710 711 712
      for (i=0,j=0,m=0; i<6; i++,j+=2) {
        if ((i!=(frame_parms->nushift))&&(i!=(frame_parms->nushift+3))) {
          y0[j]   += y0_16[m++];
          y0[j+1] += y0_16[m++];
        }
713
      }
714

715 716 717 718 719
      // Symbol 1
      //      printf("[PUSCH 0]PHICH REG %d\n",frame_parms->phich_reg[ngroup_PHICH][1]);
      re_offset = frame_parms->first_carrier_offset + (frame_parms->phich_reg[ngroup_PHICH][1]*6);

      if (re_offset > frame_parms->ofdm_symbol_size)
720
        re_offset -= (frame_parms->ofdm_symbol_size-1);
721 722

      y0 = (int16_t*)&y[0][re_offset+subframe_offset];
723

724 725 726 727 728 729 730 731 732
      y0_16[0]   = d[8]*gain_lin_QPSK;
      y0_16[1]   = d[9]*gain_lin_QPSK;
      y0_16[2]   = d[10]*gain_lin_QPSK;
      y0_16[3]   = d[11]*gain_lin_QPSK;
      y0_16[4]   = d[12]*gain_lin_QPSK;
      y0_16[5]   = d[13]*gain_lin_QPSK;
      y0_16[6]   = d[14]*gain_lin_QPSK;
      y0_16[7]   = d[15]*gain_lin_QPSK;

733 734 735 736 737
      for (i=0,j=0,m=0; i<6; i++,j+=2) {
        if ((i!=(frame_parms->nushift))&&(i!=(frame_parms->nushift+3))) {
          y0[j]   += y0_16[m++];
          y0[j+1] += y0_16[m++];
        }
738 739 740 741 742 743 744
      }

      // Symbol 2
      re_offset = frame_parms->first_carrier_offset + (frame_parms->phich_reg[ngroup_PHICH][2]*6);

      //      printf("[PUSCH 0]PHICH REG %d\n",frame_parms->phich_reg[ngroup_PHICH][2]);
      if (re_offset > frame_parms->ofdm_symbol_size)
745 746
        re_offset -= (frame_parms->ofdm_symbol_size-1);

747
      y0 = (int16_t*)&y[0][re_offset+subframe_offset];
748

749 750 751 752 753 754 755 756 757
      y0_16[0]   = d[16]*gain_lin_QPSK;
      y0_16[1]   = d[17]*gain_lin_QPSK;
      y0_16[2]   = d[18]*gain_lin_QPSK;
      y0_16[3]   = d[19]*gain_lin_QPSK;
      y0_16[4]   = d[20]*gain_lin_QPSK;
      y0_16[5]   = d[21]*gain_lin_QPSK;
      y0_16[6]   = d[22]*gain_lin_QPSK;
      y0_16[7]   = d[23]*gain_lin_QPSK;

758 759 760 761 762
      for (i=0,j=0,m=0; i<6; i++,j+=2) {
        if ((i!=(frame_parms->nushift))&&(i!=(frame_parms->nushift+3))) {
          y0[j]   += y0_16[m++];
          y0[j+1] += y0_16[m++];
        }
763
      }
764

765 766
      /*
      for (i=0;i<512;i++)
767
      printf("re %d (%d): %d,%d\n",i,subframe_offset+i,((int16_t*)&y[0][subframe_offset+i])[0],((int16_t*)&y[0][subframe_offset+i])[1]);
768 769
      */
    } // mode1_flag
770 771
  } else { // extended prefix

772 773 774
    // 6 output symbols
    if ((ngroup_PHICH & 1) == 1)
      dp = &d[4];
775
    else
776 777 778
      dp = d;

    switch (nseq_PHICH) {
779
    case 0: // +1 +1
780 781 782 783 784 785 786 787 788 789 790 791 792
      dp[0]  = cs[0];
      dp[2]  = cs[1];
      dp[8]  = cs[2];
      dp[10] = cs[3];
      dp[16] = cs[4];
      dp[18] = cs[5];
      dp[1]  = cs[0];
      dp[3]  = cs[1];
      dp[9]  = cs[2];
      dp[11] = cs[3];
      dp[17] = cs[4];
      dp[19] = cs[5];
      break;
793

794 795 796 797 798 799 800 801 802 803 804 805 806 807
    case 1: // +1 -1
      dp[0]  = cs[0];
      dp[2]  = -cs[1];
      dp[8]  = cs[2];
      dp[10] = -cs[3];
      dp[16] = cs[4];
      dp[18] = -cs[5];
      dp[1]  = cs[0];
      dp[3]  = -cs[1];
      dp[9]  = cs[2];
      dp[11] = -cs[3];
      dp[17] = cs[4];
      dp[19] = -cs[5];
      break;
808 809

    case 2: // +j +j
810 811 812 813 814 815 816 817 818 819 820 821
      dp[1]  = cs[0];
      dp[3]  = cs[1];
      dp[9]  = cs[2];
      dp[11] = cs[3];
      dp[17] = cs[4];
      dp[19] = cs[5];
      dp[0]  = -cs[0];
      dp[2]  = -cs[1];
      dp[8]  = -cs[2];
      dp[10] = -cs[3];
      dp[16] = -cs[4];
      dp[18] = -cs[5];
822

823
      break;
824 825

    case 3: // +j -j
826 827 828 829 830 831 832 833 834 835 836 837 838
      dp[1]  = cs[0];
      dp[3]  = -cs[1];
      dp[9]  = cs[2];
      dp[11] = -cs[3];
      dp[17] = cs[4];
      dp[19] = -cs[5];
      dp[0]  = -cs[0];
      dp[2]  = cs[1];
      dp[8]  = -cs[2];
      dp[10] = cs[3];
      dp[16] = -cs[4];
      dp[18] = cs[5];
      break;
839

840 841 842
    default:
      LOG_E(PHY,"phich_coding.c: Illegal PHICH Number\n");
    }
843 844 845



846 847 848 849
    if (frame_parms->mode1_flag == 0) {
      // do Alamouti precoding here
      // Symbol 0
      re_offset = frame_parms->first_carrier_offset + (frame_parms->phich_reg[ngroup_PHICH][0]*6);
850

851
      if (re_offset > frame_parms->ofdm_symbol_size)
852
        re_offset -= (frame_parms->ofdm_symbol_size-1);
853 854 855

      y0 = (int16_t*)&y[0][re_offset+subframe_offset];
      y1 = (int16_t*)&y[1][re_offset+subframe_offset];
856

857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880
      // first antenna position n -> x0
      y0_16[0]   = d[0]*gain_lin_QPSK;
      y0_16[1]   = d[1]*gain_lin_QPSK;
      // second antenna position n -> -x1*
      y1_16[0]   = -d[2]*gain_lin_QPSK;
      y1_16[1]   = d[3]*gain_lin_QPSK;
      // fill in the rest of the ALAMOUTI precoding
      y0_16[2] = -y1_16[0];
      y0_16[3] = y1_16[1];
      y1_16[2] = y0_16[0];
      y1_16[3] = -y0_16[1];

      // first antenna position n -> x0
      y0_16[4]   = d[4]*gain_lin_QPSK;
      y0_16[5]   = d[5]*gain_lin_QPSK;
      // second antenna position n -> -x1*
      y1_16[4]   = -d[6]*gain_lin_QPSK;
      y1_16[5]   = d[7]*gain_lin_QPSK;
      // fill in the rest of the ALAMOUTI precoding
      y0_16[6] = -y1_16[4];
      y0_16[7] = y1_16[5];
      y1_16[6] = y0_16[4];
      y1_16[7] = -y0_16[5];

881 882 883 884 885 886 887
      for (i=0,j=0,m=0; i<6; i++,j+=2) {
        if ((i!=(frame_parms->nushift))&&(i!=(frame_parms->nushift+3))) {
          y0[j] += y0_16[m];
          y1[j] += y1_16[m++];
          y0[j+1] += y0_16[m];
          y1[j+1] += y1_16[m++];
        }
888 889 890 891
      }

      // Symbol 1
      re_offset = frame_parms->first_carrier_offset + (frame_parms->phich_reg[ngroup_PHICH][1]<<2);
892

893
      if (re_offset > frame_parms->ofdm_symbol_size)
894 895
        re_offset -= (frame_parms->ofdm_symbol_size-1);

896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924
      re_offset += (frame_parms->ofdm_symbol_size);

      y0 = (int16_t*)&y[0][re_offset+subframe_offset];
      y1 = (int16_t*)&y[1][re_offset+subframe_offset];

      // first antenna position n -> x0
      y0_16[0]   = d[8]*gain_lin_QPSK;
      y0_16[1]   = d[9]*gain_lin_QPSK;
      // second antenna position n -> -x1*
      y1_16[0]   = -d[10]*gain_lin_QPSK;
      y1_16[1]   = d[11]*gain_lin_QPSK;
      // fill in the rest of the ALAMOUTI precoding
      y0_16[2] = -y1_16[0];
      y0_16[3] = y1_16[1];
      y1_16[2] = y0_16[0];
      y1_16[3] = -y0_16[1];

      // first antenna position n -> x0
      y0_16[4]   = d[12]*gain_lin_QPSK;
      y0_16[5]   = d[13]*gain_lin_QPSK;
      // second antenna position n -> -x1*
      y1_16[4]   = -d[14]*gain_lin_QPSK;
      y1_16[5]   = d[15]*gain_lin_QPSK;
      // fill in the rest of the ALAMOUTI precoding
      y0_16[6] = -y1_16[4];
      y0_16[7] = y1_16[5];
      y1_16[6] = y0_16[4];
      y1_16[7] = -y0_16[5];

925 926 927 928 929
      for (i=0,j=0,m=0; i<4; i++,j+=2) {
        y0[j] += y0_16[m];
        y1[j] += y1_16[m++];
        y0[j+1] += y0_16[m];
        y1[j+1] += y1_16[m++];
930 931 932 933
      }

      // Symbol 2
      re_offset = frame_parms->first_carrier_offset +  (frame_parms->phich_reg[ngroup_PHICH][2]<<2);
934

935
      if (re_offset > frame_parms->ofdm_symbol_size)
936 937
        re_offset -= (frame_parms->ofdm_symbol_size-1);

938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966
      re_offset += (frame_parms->ofdm_symbol_size<<1);

      y0 = (int16_t*)&y[0][re_offset+subframe_offset];
      y1 = (int16_t*)&y[1][re_offset+subframe_offset];

      // first antenna position n -> x0
      y0_16[0]   = d[16]*gain_lin_QPSK;
      y0_16[1]   = d[17]*gain_lin_QPSK;
      // second antenna position n -> -x1*
      y1_16[0]   = -d[18]*gain_lin_QPSK;
      y1_16[1]   = d[19]*gain_lin_QPSK;
      // fill in the rest of the ALAMOUTI precoding
      y0_16[2] = -y1_16[0];
      y0_16[3] = y1_16[1];
      y1_16[2] = y0_16[0];
      y1_16[3] = -y0_16[1];

      // first antenna position n -> x0
      y0_16[4]   = d[20]*gain_lin_QPSK;
      y0_16[5]   = d[21]*gain_lin_QPSK;
      // second antenna position n -> -x1*
      y1_16[4]   = -d[22]*gain_lin_QPSK;
      y1_16[5]   = d[23]*gain_lin_QPSK;
      // fill in the rest of the ALAMOUTI precoding
      y0_16[6] = -y1_16[4];
      y0_16[7] = y1_16[5];
      y1_16[6] = y0_16[4];
      y1_16[7] = -y0_16[5];

967 968 969 970 971
      for (i=0,j=0,m=0; i<4; i++,j+=2) {
        y0[j]   += y0_16[m];
        y1[j]   += y1_16[m++];
        y0[j+1] += y0_16[m];
        y1[j+1] += y1_16[m++];
972
      }
973
    } else {
974 975 976

      // Symbol 0
      re_offset = frame_parms->first_carrier_offset + (frame_parms->phich_reg[ngroup_PHICH][0]*6);
977

978
      if (re_offset > frame_parms->ofdm_symbol_size)
979
        re_offset -= (frame_parms->ofdm_symbol_size-1);
980 981

      y0 = (int16_t*)&y[0][re_offset+subframe_offset];
982

983 984 985 986 987 988 989 990 991
      y0_16[0]   = d[0]*gain_lin_QPSK;
      y0_16[1]   = d[1]*gain_lin_QPSK;
      y0_16[2]   = d[2]*gain_lin_QPSK;
      y0_16[3]   = d[3]*gain_lin_QPSK;
      y0_16[4]   = d[4]*gain_lin_QPSK;
      y0_16[5]   = d[5]*gain_lin_QPSK;
      y0_16[6]   = d[6]*gain_lin_QPSK;
      y0_16[7]   = d[7]*gain_lin_QPSK;

992 993 994 995 996
      for (i=0,j=0,m=0; i<6; i++,j+=2) {
        if ((i!=(frame_parms->nushift))&&(i!=(frame_parms->nushift+3))) {
          y0[j] += y0_16[m++];
          y0[j+1] += y0_16[m++];
        }
997 998 999 1000
      }

      // Symbol 1
      re_offset = frame_parms->first_carrier_offset + (frame_parms->phich_reg[ngroup_PHICH][1]<<2);
1001

1002
      if (re_offset > frame_parms->ofdm_symbol_size)
1003 1004
        re_offset -= (frame_parms->ofdm_symbol_size-1);

1005 1006 1007
      re_offset += (frame_parms->ofdm_symbol_size);

      y0 = (int16_t*)&y[0][re_offset+subframe_offset];
1008

1009 1010 1011 1012 1013 1014 1015 1016 1017
      y0_16[0]   = d[8]*gain_lin_QPSK;
      y0_16[1]   = d[9]*gain_lin_QPSK;
      y0_16[2]   = d[10]*gain_lin_QPSK;
      y0_16[3]   = d[11]*gain_lin_QPSK;
      y0_16[4]   = d[12]*gain_lin_QPSK;
      y0_16[5]   = d[13]*gain_lin_QPSK;
      y0_16[6]   = d[14]*gain_lin_QPSK;
      y0_16[7]   = d[15]*gain_lin_QPSK;

1018 1019 1020
      for (i=0,j=0,m=0; i<4; i++,j+=2) {
        y0[j] += y0_16[m++];
        y0[j+1] += y0_16[m++];
1021 1022