/******************************************************************************* Eurecom OpenAirInterface Copyright(c) 1999 - 2011 Eurecom This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, version 2, as published by the Free Software Foundation. This program is distributed in the hope 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. The full GNU General Public License is included in this distribution in the file called "COPYING". Contact Information Openair Admin: openair_admin@eurecom.fr Openair Tech : openair_tech@eurecom.fr Forums : http://forums.eurecom.fsr/openairinterface Address : Eurecom, 2229, route des crĂȘtes, 06560 Valbonne Sophia Antipolis, France *******************************************************************************/ /*! \file PHY/LTE_TRANSPORT/ulsch_coding.c * \brief Top-level routines for coding the ULSCH transport channel as described in 36.212 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 "PHY/CODING/defs.h" #include "PHY/CODING/extern.h" #include "PHY/CODING/lte_interleaver_inline.h" #include "PHY/LTE_TRANSPORT/defs.h" #include "defs.h" #include "extern.h" #include "SIMULATION/ETH_TRANSPORT/extern.h" #include "UTIL/LOG/vcd_signal_dumper.h" //#define DEBUG_ULSCH_CODING //#define DEBUG_ULSCH_FREE 1 /* #define is_not_pilot(pilots,first_pilot,re) (pilots==0) || \ ((pilots==1)&&(first_pilot==1)&&(((re>2)&&(re<6))||((re>8)&&(re<12)))) || \ ((pilots==1)&&(first_pilot==0)&&(((re<3))||((re>5)&&(re<9)))) \ */ #define is_not_pilot(pilots,first_pilot,re) (1) void free_ue_ulsch(LTE_UE_ULSCH_t *ulsch) { int i; int r; if (ulsch) { #ifdef DEBUG_ULSCH_FREE msg("Freeing ulsch %p\n",ulsch); #endif for (i=0;iMdlharq;i++) { #ifdef DEBUG_ULSCH_FREE msg("Freeing ulsch process %d\n",i); #endif if (ulsch->harq_processes[i]) { #ifdef DEBUG_ULSCH_FREE msg("Freeing ulsch process %d (%p)\n",i,ulsch->harq_processes[i]); #endif if (ulsch->harq_processes[i]->b) { free16(ulsch->harq_processes[i]->b,MAX_ULSCH_PAYLOAD_BYTES); ulsch->harq_processes[i]->b = NULL; #ifdef DEBUG_ULSCH_FREE msg("Freeing ulsch process %d b (%p)\n",i,ulsch->harq_processes[i]->b); #endif } if (ulsch->harq_processes[i]->c) { #ifdef DEBUG_ULSCH_FREE msg("Freeing ulsch process %d c (%p)\n",i,ulsch->harq_processes[i]->c); #endif for (r=0;rharq_processes[i]->c[r]); #endif if (ulsch->harq_processes[i]->c[r]) { free16(ulsch->harq_processes[i]->c[r],((r==0)?8:0) + 3+768); ulsch->harq_processes[i]->c[r] = NULL; } } } free16(ulsch->harq_processes[i],sizeof(LTE_UL_UE_HARQ_t)); ulsch->harq_processes[i] = NULL; } } free16(ulsch,sizeof(LTE_UE_ULSCH_t)); ulsch = NULL; } } LTE_UE_ULSCH_t *new_ue_ulsch(unsigned char Mdlharq,unsigned char N_RB_UL, u8 abstraction_flag) { LTE_UE_ULSCH_t *ulsch; unsigned char exit_flag = 0,i,j,r; unsigned char bw_scaling =1; switch (N_RB_UL){ case 6: bw_scaling =16; break; case 25: bw_scaling =4; break; case 50: bw_scaling =2; break; default: bw_scaling =1; break; } ulsch = (LTE_UE_ULSCH_t *)malloc16(sizeof(LTE_UE_ULSCH_t)); if (ulsch) { memset(ulsch,0,sizeof(LTE_UE_ULSCH_t)); ulsch->Mdlharq = Mdlharq; for (i=0;iharq_processes[i] = (LTE_UL_UE_HARQ_t *)malloc16(sizeof(LTE_UL_UE_HARQ_t)); // printf("ulsch->harq_processes[%d] %p\n",i,ulsch->harq_processes[i]); if (ulsch->harq_processes[i]) { memset(ulsch->harq_processes[i], 0, sizeof(LTE_UL_UE_HARQ_t)); ulsch->harq_processes[i]->b = (unsigned char*)malloc16(MAX_ULSCH_PAYLOAD_BYTES/bw_scaling); if (ulsch->harq_processes[i]->b) memset(ulsch->harq_processes[i]->b,0,MAX_ULSCH_PAYLOAD_BYTES/bw_scaling); else { LOG_E(PHY,"Can't get b\n"); exit_flag=1; } if (abstraction_flag==0) { for (r=0;rharq_processes[i]->c[r] = (unsigned char*)malloc16(((r==0)?8:0) + 3+768); // account for filler in first segment and CRCs for multiple segment case if (ulsch->harq_processes[i]->c[r]) memset(ulsch->harq_processes[i]->c[r],0,((r==0)?8:0) + 3+768); else { LOG_E(PHY,"Can't get c\n"); exit_flag=2; } } } ulsch->harq_processes[i]->subframe_scheduling_flag = 0; } else { LOG_E(PHY,"Can't get harq_p %d\n",i); exit_flag=3; } } if ((abstraction_flag == 0) && (exit_flag==0)) { for (i=0;iharq_processes[i]->d[r][j] = LTE_NULL; return(ulsch); } else if (abstraction_flag==1) return(ulsch); } LOG_E(PHY,"new_ue_ulsch exit flag, size of %d , %d\n",exit_flag, sizeof(LTE_UE_ULSCH_t)); free_ue_ulsch(ulsch); return(NULL); } u32 ulsch_encoding(u8 *a, PHY_VARS_UE *phy_vars_ue, u8 harq_pid, u8 eNB_id, u8 tmode, u8 control_only_flag, u8 Nbundled) { time_stats_t *seg_stats=&phy_vars_ue->ulsch_segmentation_stats; time_stats_t *rm_stats=&phy_vars_ue->ulsch_rate_matching_stats; time_stats_t *te_stats=&phy_vars_ue->ulsch_turbo_encoding_stats; time_stats_t *i_stats=&phy_vars_ue->ulsch_interleaving_stats; time_stats_t *m_stats=&phy_vars_ue->ulsch_multiplexing_stats; // u16 offset; u32 crc=1; u16 iind; u32 A; u8 Q_m=0; u32 Kr=0,Kr_bytes,r,r_offset=0; u8 y[6*14*1200],*yptr;; u8 *columnset; u32 sumKr=0; u32 Qprime,L,G,Q_CQI=0,Q_RI=0,Q_ACK=0,H=0,Hprime=0,Hpp=0,Cmux=0,Rmux=0,Rmux_prime=0; u32 Qprime_ACK=0,Qprime_CQI=0,Qprime_RI=0,len_ACK=0,len_RI=0; // u32 E; u8 ack_parity; u32 i,q,j,iprime,j2; u16 o_RCC; u8 o_flip[8]; u32 wACK_idx; LTE_DL_FRAME_PARMS *frame_parms=&phy_vars_ue->lte_frame_parms; PHY_MEASUREMENTS *meas = &phy_vars_ue->PHY_measurements; LTE_UE_ULSCH_t *ulsch=phy_vars_ue->ulsch_ue[eNB_id]; LTE_UE_DLSCH_t **dlsch = phy_vars_ue->dlsch_ue[eNB_id]; double sinr_eff; u16 rnti; if (!ulsch) { LOG_E(PHY,"Null ulsch ptr %p\n",ulsch); return(-1); } if (harq_pid > 7) { LOG_E(PHY,"Illegal harq_pid %d\n",harq_pid); return(-1); } if (ulsch->harq_processes[harq_pid]->O_ACK > 2) { LOG_E(PHY,"Illegal O_ACK %d\n",ulsch->harq_processes[harq_pid]->O_ACK); return(-1); } if (ulsch->O_RI > 1) { LOG_E(PHY,"Illegal O_RI %d\n",ulsch->O_RI); return(-1); } vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ULSCH_ENCODING, VCD_FUNCTION_IN); // fill CQI/PMI information if (ulsch->O>0) { if (flag_LA==1) sinr_eff = sinr_eff_cqi_calc(phy_vars_ue, 0); //eNB_id is missing here else sinr_eff = 0; rnti = phy_vars_ue->lte_ue_pdcch_vars[eNB_id]->crnti; fill_CQI(ulsch->o,ulsch->uci_format,meas,0,rnti, tmode,sinr_eff); LOG_D(PHY,"UE CQI\n"); print_CQI(ulsch->o,ulsch->uci_format,0); // save PUSCH pmi for later (transmission modes 4,5,6) if (dlsch[0]) { //LOG_I(PHY,"XXX saving pmi for DL %x\n",pmi2hex_2Ar1(((wideband_cqi_rank1_2A_5MHz *)ulsch->o)->pmi)); dlsch[0]->pmi_alloc = ((wideband_cqi_rank1_2A_5MHz *)ulsch->o)->pmi; } } if (ulsch->O<=32) { o_flip[0] = ulsch->o[3]; o_flip[1] = ulsch->o[2]; o_flip[2] = ulsch->o[1]; o_flip[3] = ulsch->o[0]; } else { o_flip[0] = ulsch->o[7]; o_flip[1] = ulsch->o[6]; o_flip[2] = ulsch->o[5]; o_flip[3] = ulsch->o[4]; o_flip[4] = ulsch->o[3]; o_flip[5] = ulsch->o[2]; o_flip[6] = ulsch->o[1]; o_flip[7] = ulsch->o[0]; } if (control_only_flag == 0) { A=ulsch->harq_processes[harq_pid]->TBS; Q_m = get_Qm_ul(ulsch->harq_processes[harq_pid]->mcs); ulsch->harq_processes[harq_pid]->control_only = 0; #ifdef DEBUG_ULSCH_CODING msg("[PHY][UE] ULSCH coding : A %d, Qm %d, mcs %d, harq_pid %d, round %d, RV %d\n", ulsch->harq_processes[harq_pid]->TBS, Q_m, ulsch->harq_processes[harq_pid]->mcs, harq_pid, ulsch->harq_processes[harq_pid]->round, ulsch->harq_processes[harq_pid]->rvidx); for (i=0;iharq_processes[harq_pid]->O_ACK;i++) msg("ulsch_coding: o_ACK[%d] %d\n",i,ulsch->o_ACK[i]); for (i=0;iO_RI;i++) msg("ulsch_coding: o_RI[%d] %d\n",i,ulsch->o_RI[i]); msg("ulsch_coding: O=%d\n",ulsch->O); for (i=0;i<1+((8+ulsch->O)/8);i++) { // ulsch->o[i] = i; msg("ulsch_coding: O[%d] %d\n",i,ulsch->o[i]); } if ((tmode != 4)) print_CQI(ulsch->o,wideband_cqi_rank1_2A,0); else print_CQI(ulsch->o,HLC_subband_cqi_rank1_2A,0); #endif if (ulsch->harq_processes[harq_pid]->round == 0) { // this is a new packet start_meas(seg_stats); // Add 24-bit crc (polynomial A) to payload crc = crc24a(a, A)>>8; a[A>>3] = ((u8*)&crc)[2]; a[1+(A>>3)] = ((u8*)&crc)[1]; a[2+(A>>3)] = ((u8*)&crc)[0]; ulsch->harq_processes[harq_pid]->B = A+24; ulsch->harq_processes[harq_pid]->b = a; lte_segmentation(ulsch->harq_processes[harq_pid]->b, ulsch->harq_processes[harq_pid]->c, ulsch->harq_processes[harq_pid]->B, &ulsch->harq_processes[harq_pid]->C, &ulsch->harq_processes[harq_pid]->Cplus, &ulsch->harq_processes[harq_pid]->Cminus, &ulsch->harq_processes[harq_pid]->Kplus, &ulsch->harq_processes[harq_pid]->Kminus, &ulsch->harq_processes[harq_pid]->F); stop_meas(seg_stats); for (r=0;rharq_processes[harq_pid]->C;r++) { if (rharq_processes[harq_pid]->Cminus) Kr = ulsch->harq_processes[harq_pid]->Kminus; else Kr = ulsch->harq_processes[harq_pid]->Kplus; Kr_bytes = Kr>>3; // get interleaver index for Turbo code (lookup in Table 5.1.3-3 36-212, V8.6 2009-03, p. 13-14) if (Kr_bytes<=64) iind = (Kr_bytes-5); else if (Kr_bytes <=128) iind = 59 + ((Kr_bytes-64)>>1); else if (Kr_bytes <= 256) iind = 91 + ((Kr_bytes-128)>>2); else if (Kr_bytes <= 768) iind = 123 + ((Kr_bytes-256)>>3); else { LOG_E(PHY,"ulsch_coding: Illegal codeword size %d!!!\n",Kr_bytes); vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ULSCH_ENCODING, VCD_FUNCTION_OUT); return(-1); } #ifdef DEBUG_ULSCH_CODING msg("Generating Code Segment %d (%d bits)\n",r,Kr); // generate codewords msg("bits_per_codeword (Kr)= %d\n",Kr); msg("N_RB = %d\n",ulsch->harq_processes[harq_pid]->nb_rb); msg("Ncp %d\n",frame_parms->Ncp); msg("Qm %d\n",Q_m); #endif // offset=0; #ifdef DEBUG_ULSCH_CODING msg("Encoding ... iind %d f1 %d, f2 %d\n",iind,f1f2mat_old[iind*2],f1f2mat_old[(iind*2)+1]); #endif start_meas(te_stats); threegpplte_turbo_encoder(ulsch->harq_processes[harq_pid]->c[r], Kr>>3, &ulsch->harq_processes[harq_pid]->d[r][96], (r==0) ? ulsch->harq_processes[harq_pid]->F : 0, f1f2mat_old[iind*2], // f1 (see 36212-820, page 14) f1f2mat_old[(iind*2)+1] // f2 (see 36212-820, page 14) ); stop_meas(te_stats); #ifdef DEBUG_ULSCH_CODING if (r==0) write_output("enc_output0.m","enc0",&ulsch->harq_processes[harq_pid]->d[r][96],(3*8*Kr_bytes)+12,1,4); #endif start_meas(i_stats); ulsch->harq_processes[harq_pid]->RTC[r] = sub_block_interleaving_turbo(4+(Kr_bytes*8), &ulsch->harq_processes[harq_pid]->d[r][96], ulsch->harq_processes[harq_pid]->w[r]); stop_meas(i_stats); } } if (ulsch->harq_processes[harq_pid]->C == 0) { LOG_E(PHY,"null segment\n"); vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ULSCH_ENCODING, VCD_FUNCTION_OUT); return(-1); } sumKr = 0; for (r=0;rharq_processes[harq_pid]->C;r++) { if (rharq_processes[harq_pid]->Cminus) Kr = ulsch->harq_processes[harq_pid]->Kminus; else Kr = ulsch->harq_processes[harq_pid]->Kplus; sumKr += Kr; } } else { // This is a control-only PUSCH, set sumKr to O_CQI-MIN ulsch->harq_processes[harq_pid]->control_only = 1; sumKr = ulsch->O_CQI_MIN; } ulsch->harq_processes[harq_pid]->sumKr = sumKr; // Compute Q_ri (p. 23 36-212) Qprime = ulsch->O_RI*ulsch->harq_processes[harq_pid]->Msc_initial*ulsch->harq_processes[harq_pid]->Nsymb_initial * ulsch->beta_offset_ri_times8; if (Qprime > 0) { if ((Qprime % (8*sumKr)) > 0) Qprime = 1+(Qprime/(8*sumKr)); else Qprime = Qprime/(8*sumKr); if (Qprime > 4*ulsch->harq_processes[harq_pid]->nb_rb * 12) Qprime = 4*ulsch->harq_processes[harq_pid]->nb_rb * 12; } Q_RI = Q_m*Qprime; Qprime_RI = Qprime; // Compute Q_ack (p. 23 36-212) Qprime = ulsch->harq_processes[harq_pid]->O_ACK*ulsch->harq_processes[harq_pid]->Msc_initial*ulsch->harq_processes[harq_pid]->Nsymb_initial * ulsch->beta_offset_harqack_times8; if (Qprime > 0) { if ((Qprime % (8*sumKr)) > 0) Qprime = 1+(Qprime/(8*sumKr)); else Qprime = Qprime/(8*sumKr); if (Qprime > 4*ulsch->harq_processes[harq_pid]->nb_rb * 12) Qprime = 4*ulsch->harq_processes[harq_pid]->nb_rb * 12; } Q_ACK = Qprime * Q_m; Qprime_ACK = Qprime; // Compute Q_cqi, assume O>11, p. 26 36-212 if (control_only_flag == 0) { if (ulsch->O < 12) L=0; else L=8; if (ulsch->O > 0) Qprime = (ulsch->O + L) * ulsch->harq_processes[harq_pid]->Msc_initial*ulsch->harq_processes[harq_pid]->Nsymb_initial * ulsch->beta_offset_cqi_times8; else Qprime = 0; if (Qprime > 0) { if ((Qprime % (8*sumKr)) > 0) Qprime = 1+(Qprime/(8*sumKr)); else Qprime = Qprime/(8*sumKr); } G = ulsch->harq_processes[harq_pid]->nb_rb * (12 * Q_m) * (ulsch->Nsymb_pusch); if (Qprime > (G - ulsch->O_RI)) Qprime = G - ulsch->O_RI; Q_CQI = Q_m * Qprime; Qprime_CQI = Qprime; G = G - Q_RI - Q_CQI; if ((int)G < 0) { LOG_E(PHY,"FATAL: ulsch_coding.c G < 0 (%d) : Q_RI %d, Q_CQI %d, O %d, betaCQI_times8 %d)\n",G,Q_RI,Q_CQI,ulsch->O,ulsch->beta_offset_cqi_times8); vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ULSCH_ENCODING, VCD_FUNCTION_OUT); return(-1); } // Data and control multiplexing (5.2.2.7 36-212) H = G + Q_CQI; Hprime = H/Q_m; // Fill in the "e"-sequence from 36-212, V8.6 2009-03, p. 16-17 (for each "e") and concatenate the // outputs for each code segment, see Section 5.1.5 p.20 for (r=0;rharq_processes[harq_pid]->C;r++) { #ifdef DEBUG_ULSCH_CODING msg("Rate Matching, Code segment %d (coded bits (G) %d,unpunctured/repeated bits per code segment %d,mod_order %d, nb_rb %d)...\n", r, G, Kr*3, Q_m,ulsch->harq_processes[harq_pid]->nb_rb); #endif start_meas(rm_stats); r_offset += lte_rate_matching_turbo(ulsch->harq_processes[harq_pid]->RTC[r], G, ulsch->harq_processes[harq_pid]->w[r], &ulsch->e[0], ulsch->harq_processes[harq_pid]->C, // C NSOFT, // Nsoft, ulsch->Mdlharq, 1, ulsch->harq_processes[harq_pid]->rvidx, get_Qm_ul(ulsch->harq_processes[harq_pid]->mcs), 1, r, ulsch->harq_processes[harq_pid]->nb_rb, ulsch->harq_processes[harq_pid]->mcs); // r stop_meas(rm_stats); #ifdef DEBUG_ULSCH_CODING if (r==ulsch->harq_processes[harq_pid]->C-1) write_output("enc_output.m","enc",ulsch->e,r_offset,1,4); #endif } } else { //control-only PUSCH Q_CQI = (ulsch->harq_processes[harq_pid]->nb_rb * (12 * Q_m) * (ulsch->Nsymb_pusch)) - Q_RI; H = Q_CQI; Hprime = H/Q_m; } // Do CQI coding if ((ulsch->O>1) && (ulsch->O < 12)) { LOG_E(PHY,"short CQI sizes not supported yet\n"); vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ULSCH_ENCODING, VCD_FUNCTION_OUT); return(-1); } else { // add 8-bit CRC crc = crc8(o_flip, ulsch->O)>>24; #ifdef DEBUG_ULSCH_CODING printf("crc(cqi) tx : %x\n",crc); #endif memset((void *)&ulsch->o_d[0],LTE_NULL,96); ccodelte_encode(ulsch->O, 1, o_flip, &ulsch->o_d[96], 0); o_RCC = sub_block_interleaving_cc(8+ulsch->O, &ulsch->o_d[96], ulsch->o_w); lte_rate_matching_cc(o_RCC, Q_CQI, ulsch->o_w, ulsch->q); } i=0; // Do RI coding if (ulsch->O_RI == 1) { switch (Q_m) { case 2: ulsch->q_RI[0] = ulsch->o_RI[0]; ulsch->q_RI[1] = PUSCH_y;//ulsch->o_RI[0]; len_RI=2; break; case 4: ulsch->q_RI[0] = ulsch->o_RI[0]; ulsch->q_RI[1] = PUSCH_y;//1; ulsch->q_RI[2] = PUSCH_x;//ulsch->o_RI[0]; ulsch->q_RI[3] = PUSCH_x;//1; len_RI=4; break; case 6: ulsch->q_RI[0] = ulsch->o_RI[0]; ulsch->q_RI[1] = PUSCH_y;//1; ulsch->q_RI[2] = PUSCH_x;//1; ulsch->q_RI[3] = PUSCH_x;//ulsch->o_RI[0]; ulsch->q_RI[4] = PUSCH_x;//1; ulsch->q_RI[5] = PUSCH_x;//1; len_RI=6; break; } } else if (ulsch->O_RI>1){ LOG_E(PHY,"RI cannot be more than 1 bit yet\n"); vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ULSCH_ENCODING, VCD_FUNCTION_OUT); return(-1); } // Do ACK coding, Section 5.2.2.6 36.213 (p.23-24 in v8.6) wACK_idx = (ulsch->bundling==0) ? 4 : ((Nbundled-1)&3); #ifdef DEBUG_ULSCH_CODING msg("ulsch_coding.c: Bundling %d, Nbundled %d, wACK_idx %d\n", ulsch->bundling,Nbundled,wACK_idx); #endif // 1-bit ACK/NAK if (ulsch->harq_processes[harq_pid]->O_ACK == 1) { switch (Q_m) { case 2: ulsch->q_ACK[0] = (ulsch->o_ACK[0]+wACK[wACK_idx][0])&1; ulsch->q_ACK[1] = (ulsch->bundling==0)? PUSCH_y : ((ulsch->o_ACK[0]+wACK[wACK_idx][1])&1);//ulsch->o_ACK[0]; len_ACK = 2; break; case 4: ulsch->q_ACK[0] = (ulsch->o_ACK[0]+wACK[wACK_idx][0])&1; ulsch->q_ACK[1] = (ulsch->bundling==0)? PUSCH_y : ((ulsch->o_ACK[0]+wACK[wACK_idx][1])&1); ulsch->q_ACK[2] = PUSCH_x; ulsch->q_ACK[3] = PUSCH_x; len_ACK = 4; break; case 6: ulsch->q_ACK[0] = (ulsch->o_ACK[0]+wACK[wACK_idx][0])&1; ulsch->q_ACK[1] = (ulsch->bundling==0)? PUSCH_y : ((ulsch->o_ACK[0]+wACK[wACK_idx][1])&1); ulsch->q_ACK[2] = PUSCH_x; ulsch->q_ACK[3] = PUSCH_x; ulsch->q_ACK[4] = PUSCH_x; ulsch->q_ACK[6] = PUSCH_x; len_ACK = 6; break; } } // two-bit ACK/NAK if (ulsch->harq_processes[harq_pid]->O_ACK == 2) { ack_parity = (ulsch->o_ACK[0]+ulsch->o_ACK[1])&1; switch (Q_m) { case 2: ulsch->q_ACK[0] = (ulsch->o_ACK[0]+wACK[wACK_idx][0])&1; ulsch->q_ACK[1] = (ulsch->o_ACK[1]+wACK[wACK_idx][0])&1; ulsch->q_ACK[2] = (ack_parity+wACK[wACK_idx][0])&1; ulsch->q_ACK[3] = (ulsch->o_ACK[0]+wACK[wACK_idx][1])&1; ulsch->q_ACK[4] = (ulsch->o_ACK[1]+wACK[wACK_idx][1])&1; ulsch->q_ACK[5] = (ack_parity+wACK[wACK_idx][1])&1; len_ACK = 6; break; case 4: ulsch->q_ACK[0] = (ulsch->o_ACK[0]+wACK[wACK_idx][0])&1; ulsch->q_ACK[1] = (ulsch->o_ACK[1]+wACK[wACK_idx][0])&1; ulsch->q_ACK[2] = PUSCH_x; ulsch->q_ACK[3] = PUSCH_x;//1; ulsch->q_ACK[4] = (ack_parity+wACK[wACK_idx][0])&1; ulsch->q_ACK[5] = (ulsch->o_ACK[0]+wACK[wACK_idx][1])&1; ulsch->q_ACK[6] = PUSCH_x; ulsch->q_ACK[7] = PUSCH_x;//1; ulsch->q_ACK[8] = (ulsch->o_ACK[1]+wACK[wACK_idx][1])&1; ulsch->q_ACK[9] = (ack_parity+wACK[wACK_idx][1])&1; ulsch->q_ACK[10] = PUSCH_x; ulsch->q_ACK[11] = PUSCH_x;//1; len_ACK = 12; break; case 6: ulsch->q_ACK[0] = (ulsch->o_ACK[0]+wACK[wACK_idx][0])&1; ulsch->q_ACK[1] = (ulsch->o_ACK[1]+wACK[wACK_idx][0])&1; ulsch->q_ACK[2] = PUSCH_x; ulsch->q_ACK[3] = PUSCH_x; ulsch->q_ACK[4] = PUSCH_x; ulsch->q_ACK[5] = PUSCH_x; ulsch->q_ACK[6] = (ack_parity+wACK[wACK_idx][0])&1; ulsch->q_ACK[7] = (ulsch->o_ACK[0]+wACK[wACK_idx][1])&1; ulsch->q_ACK[8] = PUSCH_x; ulsch->q_ACK[9] = PUSCH_x; ulsch->q_ACK[10] = PUSCH_x; ulsch->q_ACK[11] = PUSCH_x; ulsch->q_ACK[12] = (ulsch->o_ACK[1]+wACK[wACK_idx][1])&1; ulsch->q_ACK[13] = (ack_parity+wACK[wACK_idx][1])&1; ulsch->q_ACK[14] = PUSCH_x; ulsch->q_ACK[15] = PUSCH_x; ulsch->q_ACK[16] = PUSCH_x; ulsch->q_ACK[17] = PUSCH_x; len_ACK = 18; break; } } if (ulsch->harq_processes[harq_pid]->O_ACK > 2) { LOG_E(PHY,"ACK cannot be more than 2 bits yet\n"); vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ULSCH_ENCODING, VCD_FUNCTION_OUT); return(-1); } // channel multiplexing/interleaving start_meas(m_stats); Hpp = Hprime + Q_RI; Cmux = ulsch->Nsymb_pusch; Rmux = Hpp*Q_m/Cmux; Rmux_prime = Rmux/Q_m; Qprime_RI = Q_RI / Q_m; Qprime_ACK = Q_ACK / Q_m; Qprime_CQI = Q_CQI / Q_m; // printf("Qprime_CQI = %d\n",Qprime_CQI); // RI BITS memset(y,LTE_NULL,Q_m*Hpp); if (frame_parms->Ncp == 0) columnset = cs_ri_normal; else columnset = cs_ri_extended; j=0; for (i=0;i>2); for (q=0;qq_RI[(q+(Q_m*i))%len_RI]; // printf("ri[%d] %d => y[%d]\n",q+(Q_m*i)%len_RI,ulsch->q_RI[(q+(Q_m*i))%len_RI],q+(Q_m*((r*Cmux) + columnset[j])),y[q+(Q_m*((r*Cmux) + columnset[j]))]); } j=(j+3)&3; } // CQI and Data bits j=0; /* for (i=0,iprime=-Qprime_CQI;iq[q+(Q_m*i)]; //printf("cqi[%d] %d => y[%d]\n",q+(Q_m*i),ulsch->q[q+(Q_m*i)],q+(Q_m*j)); } } else { for (q=0;qe[q+(Q_m*iprime)]; // printf("e[%d] %d => y[%d]\n",q+(Q_m*iprime),ulsch->e[q+(Q_m*iprime)],q+(Q_m*j)); } } j++; } */ for (i=0;iq[q+(Q_m*i)]; // printf("cqi[%d] %d => y[%d] (j %d)\n",q+(Q_m*i),ulsch->q[q+(Q_m*i)],q+(Q_m*j),j); } j++; } j2 = j*Q_m; switch (Q_m) { case 2: for (iprime=0;iprime<(Hprime-Qprime_CQI)<<1;iprime+=2) { while (y[j2] != LTE_NULL) j2+=2; y[j2] = ulsch->e[iprime]; y[1+j2] = ulsch->e[1+iprime]; j2+=2; } break; case 4: for (iprime=0;iprime<(Hprime-Qprime_CQI)<<2;iprime+=4) { while (y[j2] != LTE_NULL) j2+=4; y[j2] = ulsch->e[iprime]; y[1+j2] = ulsch->e[1+iprime]; y[2+j2] = ulsch->e[2+iprime]; y[3+j2] = ulsch->e[3+iprime]; j2+=4; } break; case 6: for (iprime=0;iprime<(Hprime-Qprime_CQI)*6;iprime+=6) { while (y[j2] != LTE_NULL) j2+=6; y[j2] = ulsch->e[iprime]; y[1+j2] = ulsch->e[1+iprime]; y[2+j2] = ulsch->e[2+iprime]; y[3+j2] = ulsch->e[3+iprime]; y[4+j2] = ulsch->e[4+iprime]; y[5+j2] = ulsch->e[5+iprime]; j2+=6; } break; } // HARQ-ACK Bits (Note these overwrite some bits) if (frame_parms->Ncp == 0) columnset = cs_ack_normal; else columnset = cs_ack_extended; j=0; for (i=0;i>2); for (q=0;qq_ACK[(q+(Q_m*i))%len_ACK]; #ifdef DEBUG_ULSCH_CODING msg("ulsch_coding.c: ACK %d => y[%d]=%d (i %d, r*Cmux %d, columnset %d)\n",q+(Q_m*i), q+(Q_m*((r*Cmux) + columnset[j])),ulsch->q_ACK[(q+(Q_m*i))%len_ACK], i,r*Cmux,columnset[j]); #endif } j=(j+3)&3; } // write out buffer j=0; switch (Q_m) { case 2: for (i=0;ih[j++] = *yptr++; ulsch->h[j++] = *yptr++; } break; case 4: for (i=0;ih[j++] = *yptr++; ulsch->h[j++] = *yptr++; ulsch->h[j++] = *yptr++; ulsch->h[j++] = *yptr++; } break; case 6: for (i=0;ih[j++] = *yptr++; ulsch->h[j++] = *yptr++; ulsch->h[j++] = *yptr++; ulsch->h[j++] = *yptr++; ulsch->h[j++] = *yptr++; ulsch->h[j++] = *yptr++; } break; default: break; } stop_meas(m_stats); if (j!=(H+Q_RI)) { LOG_E(PHY,"Error in output buffer length (j %d, H+Q_RI %d)\n",j,H+Q_RI); vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ULSCH_ENCODING, VCD_FUNCTION_OUT); return(-1); } vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ULSCH_ENCODING, VCD_FUNCTION_OUT); return(0); } #ifdef PHY_ABSTRACTION #ifdef OPENAIR2 #include "LAYER2/MAC/extern.h" #include "LAYER2/MAC/defs.h" #endif int ulsch_encoding_emul(u8 *ulsch_buffer, PHY_VARS_UE *phy_vars_ue, u8 eNB_id, u8 harq_pid, u8 control_only_flag) { LTE_UE_ULSCH_t *ulsch = phy_vars_ue->ulsch_ue[eNB_id]; LTE_UE_DLSCH_t **dlsch = phy_vars_ue->dlsch_ue[eNB_id]; PHY_MEASUREMENTS *meas = &phy_vars_ue->PHY_measurements; u8 tmode = phy_vars_ue->transmission_mode[eNB_id]; double sinr_eff; u16 rnti=phy_vars_ue->lte_ue_pdcch_vars[eNB_id]->crnti; LOG_D(PHY,"EMUL UE ulsch_encoding for eNB %d,mod_id %d, harq_pid %d rnti %x, ACK(%d,%d) \n", eNB_id,phy_vars_ue->Mod_id, harq_pid, rnti,ulsch->o_ACK[0],ulsch->o_ACK[1]); if (ulsch->O>0) { // int flag_LA =0; sinr_eff = sinr_eff_cqi_calc(phy_vars_ue, eNB_id); fill_CQI(ulsch->o,ulsch->uci_format,meas,eNB_id,rnti,tmode,sinr_eff); //LOG_D(PHY,"UE CQI\n"); // print_CQI(ulsch->o,ulsch->uci_format,eNB_id); // save PUSCH pmi for later (transmission modes 4,5,6) // msg("ulsch: saving pmi for DL %x\n",pmi2hex_2Ar1(((wideband_cqi_rank1_2A_5MHz *)ulsch->o)->pmi)); // if (ulsch->uci_format != HLC_subband_cqi_mcs_CBA) dlsch[0]->harq_processes[harq_pid]->pmi_alloc = ((wideband_cqi_rank1_2A_5MHz *)ulsch->o)->pmi; } memcpy(phy_vars_ue->ulsch_ue[eNB_id]->harq_processes[harq_pid]->b, ulsch_buffer, phy_vars_ue->ulsch_ue[eNB_id]->harq_processes[harq_pid]->TBS>>3); //memcpy(&UE_transport_info[phy_vars_ue->Mod_id].transport_blocks[UE_transport_info_TB_index[phy_vars_ue->Mod_id]], memcpy(&UE_transport_info[phy_vars_ue->Mod_id].transport_blocks, ulsch_buffer, phy_vars_ue->ulsch_ue[eNB_id]->harq_processes[harq_pid]->TBS>>3); //UE_transport_info_TB_index[phy_vars_ue->Mod_id]+=phy_vars_ue->ulsch_ue[eNB_id]->harq_processes[harq_pid]->TBS>>3; // navid: currently more than one eNB is not supported in the code UE_transport_info[phy_vars_ue->Mod_id].num_eNB = 1; UE_transport_info[phy_vars_ue->Mod_id].rnti[0] = phy_vars_ue->lte_ue_pdcch_vars[0]->crnti; UE_transport_info[phy_vars_ue->Mod_id].eNB_id[0] = eNB_id; UE_transport_info[phy_vars_ue->Mod_id].harq_pid[0] = harq_pid; UE_transport_info[phy_vars_ue->Mod_id].tbs[0] = phy_vars_ue->ulsch_ue[eNB_id]->harq_processes[harq_pid]->TBS>>3 ; // msg("\nphy_vars_ue->Mod_id%d\n",phy_vars_ue->Mod_id); UE_transport_info[phy_vars_ue->Mod_id].cntl.pusch_flag = 1; //UE_transport_info[phy_vars_ue->Mod_id].cntl.pusch_uci = *(u32 *)ulsch->o; memcpy(UE_transport_info[phy_vars_ue->Mod_id].cntl.pusch_uci, ulsch->o, MAX_CQI_BYTES); // msg("[UE]cqi is %d \n", ((HLC_subband_cqi_rank1_2A_5MHz *)ulsch->o)->cqi1); UE_transport_info[phy_vars_ue->Mod_id].cntl.length_uci = ulsch->O; UE_transport_info[phy_vars_ue->Mod_id].cntl.uci_format = ulsch->uci_format; UE_transport_info[phy_vars_ue->Mod_id].cntl.pusch_ri = (ulsch->o_RI[0]&1)+((ulsch->o_RI[1]&1)<<1); UE_transport_info[phy_vars_ue->Mod_id].cntl.pusch_ack = (ulsch->o_ACK[0]&1) + ((ulsch->o_ACK[1]&1)<<1); //msg("ack is %d %d %d\n",UE_transport_info[phy_vars_ue->Mod_id].cntl.pusch_ack, (ulsch->o_ACK[1]&1)<<1, ulsch->o_ACK[0]&1); return(0); } #endif