464 lines
15 KiB
C
464 lines
15 KiB
C
/*******************************************************************************
|
|
OpenAirInterface
|
|
Copyright(c) 1999 - 2014 Eurecom
|
|
|
|
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.
|
|
|
|
|
|
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.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with OpenAirInterface.The full GNU General Public License is
|
|
included in this distribution in the file called "COPYING". If not,
|
|
see <http://www.gnu.org/licenses/>.
|
|
|
|
Contact Information
|
|
OpenAirInterface Admin: openair_admin@eurecom.fr
|
|
OpenAirInterface Tech : openair_tech@eurecom.fr
|
|
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
|
|
|
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
|
|
|
*******************************************************************************/
|
|
|
|
/*! \file PHY/LTE_TRANSPORT/dlsch_coding.c
|
|
* \brief Top-level routines for implementing Turbo-coded (DLSCH) transport channels from 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 "SCHED/defs.h"
|
|
#include "defs.h"
|
|
#include "UTIL/LOG/vcd_signal_dumper.h"
|
|
|
|
//#define DEBUG_DLSCH_CODING
|
|
//#define DEBUG_DLSCH_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_eNB_dlsch(LTE_eNB_DLSCH_t *dlsch)
|
|
{
|
|
int i;
|
|
int r;
|
|
|
|
if (dlsch) {
|
|
#ifdef DEBUG_DLSCH_FREE
|
|
msg("Freeing dlsch %p\n",dlsch);
|
|
#endif
|
|
|
|
for (i=0; i<dlsch->Mdlharq; i++) {
|
|
#ifdef DEBUG_DLSCH_FREE
|
|
msg("Freeing dlsch process %d\n",i);
|
|
#endif
|
|
|
|
if (dlsch->harq_processes[i]) {
|
|
#ifdef DEBUG_DLSCH_FREE
|
|
msg("Freeing dlsch process %d (%p)\n",i,dlsch->harq_processes[i]);
|
|
#endif
|
|
|
|
if (dlsch->harq_processes[i]->b) {
|
|
free16(dlsch->harq_processes[i]->b,MAX_DLSCH_PAYLOAD_BYTES);
|
|
dlsch->harq_processes[i]->b = NULL;
|
|
#ifdef DEBUG_DLSCH_FREE
|
|
msg("Freeing dlsch process %d b (%p)\n",i,dlsch->harq_processes[i]->b);
|
|
#endif
|
|
}
|
|
|
|
#ifdef DEBUG_DLSCH_FREE
|
|
msg("Freeing dlsch process %d c (%p)\n",i,dlsch->harq_processes[i]->c);
|
|
#endif
|
|
|
|
for (r=0; r<MAX_NUM_DLSCH_SEGMENTS; r++) {
|
|
|
|
#ifdef DEBUG_DLSCH_FREE
|
|
msg("Freeing dlsch process %d c[%d] (%p)\n",i,r,dlsch->harq_processes[i]->c[r]);
|
|
#endif
|
|
|
|
if (dlsch->harq_processes[i]->c[r]) {
|
|
free16(dlsch->harq_processes[i]->c[r],((r==0)?8:0) + 3+768);
|
|
dlsch->harq_processes[i]->c[r] = NULL;
|
|
}
|
|
if (dlsch->harq_processes[i]->d[r]) {
|
|
free16(dlsch->harq_processes[i]->d[r],(96+12+3+(3*6144)));
|
|
dlsch->harq_processes[i]->d[r] = NULL;
|
|
}
|
|
}
|
|
|
|
free16(dlsch->harq_processes[i],sizeof(LTE_DL_eNB_HARQ_t));
|
|
dlsch->harq_processes[i] = NULL;
|
|
}
|
|
}
|
|
|
|
free16(dlsch,sizeof(LTE_eNB_DLSCH_t));
|
|
dlsch = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,uint32_t Nsoft,unsigned char N_RB_DL, uint8_t abstraction_flag)
|
|
{
|
|
|
|
LTE_eNB_DLSCH_t *dlsch;
|
|
unsigned char exit_flag = 0,i,j,r;
|
|
unsigned char bw_scaling =1;
|
|
|
|
switch (N_RB_DL) {
|
|
case 6:
|
|
bw_scaling =16;
|
|
break;
|
|
|
|
case 25:
|
|
bw_scaling =4;
|
|
break;
|
|
|
|
case 50:
|
|
bw_scaling =2;
|
|
break;
|
|
|
|
default:
|
|
bw_scaling =1;
|
|
break;
|
|
}
|
|
|
|
dlsch = (LTE_eNB_DLSCH_t *)malloc16(sizeof(LTE_eNB_DLSCH_t));
|
|
|
|
if (dlsch) {
|
|
bzero(dlsch,sizeof(LTE_eNB_DLSCH_t));
|
|
dlsch->Kmimo = Kmimo;
|
|
dlsch->Mdlharq = Mdlharq;
|
|
dlsch->Nsoft = Nsoft;
|
|
|
|
for (i=0; i<10; i++)
|
|
dlsch->harq_ids[i] = Mdlharq;
|
|
|
|
dlsch->head_freelist = 0;
|
|
dlsch->tail_freelist = 0;
|
|
|
|
for (i=0; i<Mdlharq; i++) {
|
|
dlsch->harq_processes[i] = (LTE_DL_eNB_HARQ_t *)malloc16(sizeof(LTE_DL_eNB_HARQ_t));
|
|
LOG_T(PHY, "Required mem size %d (bw scaling %d), dlsch->harq_processes[%d] %p\n",
|
|
MAX_DLSCH_PAYLOAD_BYTES/bw_scaling,bw_scaling, i,dlsch->harq_processes[i]);
|
|
|
|
if (dlsch->harq_processes[i]) {
|
|
bzero(dlsch->harq_processes[i],sizeof(LTE_DL_eNB_HARQ_t));
|
|
// dlsch->harq_processes[i]->first_tx=1;
|
|
dlsch->harq_processes[i]->b = (unsigned char*)malloc16(MAX_DLSCH_PAYLOAD_BYTES/bw_scaling);
|
|
|
|
if (dlsch->harq_processes[i]->b) {
|
|
bzero(dlsch->harq_processes[i]->b,MAX_DLSCH_PAYLOAD_BYTES/bw_scaling);
|
|
} else {
|
|
msg("Can't get b\n");
|
|
exit_flag=1;
|
|
}
|
|
|
|
if (abstraction_flag==0) {
|
|
for (r=0; r<MAX_NUM_DLSCH_SEGMENTS/bw_scaling; r++) {
|
|
// account for filler in first segment and CRCs for multiple segment case
|
|
dlsch->harq_processes[i]->c[r] = (uint8_t*)malloc16(((r==0)?8:0) + 3+ 768);
|
|
dlsch->harq_processes[i]->d[r] = (uint8_t*)malloc16((96+12+3+(3*6144)));
|
|
if (dlsch->harq_processes[i]->c[r]) {
|
|
bzero(dlsch->harq_processes[i]->c[r],((r==0)?8:0) + 3+ 768);
|
|
} else {
|
|
msg("Can't get c\n");
|
|
exit_flag=2;
|
|
}
|
|
if (dlsch->harq_processes[i]->d[r]) {
|
|
bzero(dlsch->harq_processes[i]->d[r],(96+12+3+(3*6144)));
|
|
} else {
|
|
msg("Can't get d\n");
|
|
exit_flag=2;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
msg("Can't get harq_p %d\n",i);
|
|
exit_flag=3;
|
|
}
|
|
|
|
put_harq_pid_in_freelist(dlsch, i);
|
|
}
|
|
|
|
if (exit_flag==0) {
|
|
for (i=0; i<Mdlharq; i++) {
|
|
dlsch->harq_processes[i]->round=0;
|
|
|
|
if (abstraction_flag==0) {
|
|
for (j=0; j<96; j++)
|
|
for (r=0; r<MAX_NUM_DLSCH_SEGMENTS/bw_scaling; r++) {
|
|
// printf("dlsch->harq_processes[%d]->d[%d] %p\n",i,r,dlsch->harq_processes[i]->d[r]);
|
|
dlsch->harq_processes[i]->d[r][j] = LTE_NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(dlsch);
|
|
}
|
|
}
|
|
|
|
LOG_D(PHY, "new_eNB_dlsch exit flag %d, size of %ld\n",
|
|
exit_flag, sizeof(LTE_eNB_DLSCH_t));
|
|
free_eNB_dlsch(dlsch);
|
|
return(NULL);
|
|
|
|
|
|
}
|
|
|
|
void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch, uint8_t abstraction_flag)
|
|
{
|
|
|
|
unsigned char Mdlharq;
|
|
unsigned char i,j,r;
|
|
|
|
if (dlsch) {
|
|
Mdlharq = dlsch->Mdlharq;
|
|
dlsch->rnti = 0;
|
|
dlsch->active = 0;
|
|
|
|
for (i=0; i<10; i++)
|
|
dlsch->harq_ids[i] = Mdlharq;
|
|
|
|
for (i=0; i<Mdlharq; i++) {
|
|
if (dlsch->harq_processes[i]) {
|
|
// dlsch->harq_processes[i]->Ndi = 0;
|
|
dlsch->harq_processes[i]->status = 0;
|
|
dlsch->harq_processes[i]->round = 0;
|
|
|
|
if (abstraction_flag==0) {
|
|
for (j=0; j<96; j++)
|
|
for (r=0; r<MAX_NUM_DLSCH_SEGMENTS; r++)
|
|
if (dlsch->harq_processes[i]->d[r])
|
|
dlsch->harq_processes[i]->d[r][j] = LTE_NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int dlsch_encoding(unsigned char *a,
|
|
LTE_DL_FRAME_PARMS *frame_parms,
|
|
uint8_t num_pdcch_symbols,
|
|
LTE_eNB_DLSCH_t *dlsch,
|
|
int frame,
|
|
uint8_t subframe,
|
|
time_stats_t *rm_stats,
|
|
time_stats_t *te_stats,
|
|
time_stats_t *i_stats)
|
|
{
|
|
|
|
unsigned int G;
|
|
unsigned int crc=1;
|
|
unsigned short iind;
|
|
|
|
unsigned char harq_pid = dlsch->current_harq_pid;
|
|
unsigned short nb_rb = dlsch->harq_processes[harq_pid]->nb_rb;
|
|
unsigned int A;
|
|
unsigned char mod_order;
|
|
unsigned int Kr=0,Kr_bytes,r,r_offset=0;
|
|
unsigned short m=dlsch->harq_processes[harq_pid]->mcs;
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING, VCD_FUNCTION_IN);
|
|
|
|
A = dlsch->harq_processes[harq_pid]->TBS; //6228
|
|
// printf("Encoder: A: %d\n",A);
|
|
mod_order = get_Qm(dlsch->harq_processes[harq_pid]->mcs);
|
|
|
|
G = get_G(frame_parms,nb_rb,dlsch->harq_processes[harq_pid]->rb_alloc,mod_order,dlsch->harq_processes[harq_pid]->Nl,num_pdcch_symbols,frame,subframe);
|
|
|
|
|
|
// if (dlsch->harq_processes[harq_pid]->Ndi == 1) { // this is a new packet
|
|
if (dlsch->harq_processes[harq_pid]->round == 0) { // this is a new packet
|
|
|
|
/*
|
|
int i;
|
|
printf("dlsch (tx): \n");
|
|
for (i=0;i<(A>>3);i++)
|
|
printf("%02x.",a[i]);
|
|
printf("\n");
|
|
*/
|
|
// Add 24-bit crc (polynomial A) to payload
|
|
crc = crc24a(a, //input bits for computation, A is a size of a
|
|
A)>>8;
|
|
a[A>>3] = ((uint8_t*)&crc)[2];
|
|
a[1+(A>>3)] = ((uint8_t*)&crc)[1];
|
|
a[2+(A>>3)] = ((uint8_t*)&crc)[0];
|
|
// printf("CRC %x (A %d)\n",crc,A);
|
|
|
|
dlsch->harq_processes[harq_pid]->B = A+24;
|
|
// dlsch->harq_processes[harq_pid]->b = a;
|
|
memcpy(dlsch->harq_processes[harq_pid]->b,a,(A/8)+4);
|
|
|
|
if (lte_segmentation(dlsch->harq_processes[harq_pid]->b, // bits after CRC attachement
|
|
dlsch->harq_processes[harq_pid]->c, // output from segmentation
|
|
dlsch->harq_processes[harq_pid]->B, //size of B=L+A
|
|
&dlsch->harq_processes[harq_pid]->C, //number of codeblocks
|
|
&dlsch->harq_processes[harq_pid]->Cplus, //Number of segments of size K+
|
|
&dlsch->harq_processes[harq_pid]->Cminus,//Number of segments of size K_
|
|
&dlsch->harq_processes[harq_pid]->Kplus, //First segmentation size
|
|
&dlsch->harq_processes[harq_pid]->Kminus, //Second segmentation size
|
|
&dlsch->harq_processes[harq_pid]->F)<0) //Number of filler bits
|
|
return(-1);
|
|
|
|
for (r=0; r<dlsch->harq_processes[harq_pid]->C; r++) {
|
|
if (r<dlsch->harq_processes[harq_pid]->Cminus)
|
|
Kr = dlsch->harq_processes[harq_pid]->Kminus;
|
|
else
|
|
Kr = dlsch->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 {
|
|
msg("dlsch_coding: Illegal codeword size %d!!!\n",Kr_bytes);
|
|
return(-1);
|
|
}
|
|
|
|
|
|
#ifdef DEBUG_DLSCH_CODING
|
|
printf("Generating Code Segment %d (%d bits)\n",r,Kr);
|
|
// generate codewords
|
|
|
|
msg("bits_per_codeword (Kr)= %d, A %d\n",Kr,A);
|
|
msg("N_RB = %d\n",nb_rb);
|
|
msg("Ncp %d\n",frame_parms->Ncp);
|
|
msg("mod_order %d\n",mod_order);
|
|
#endif
|
|
|
|
|
|
#ifdef DEBUG_DLSCH_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(dlsch->harq_processes[harq_pid]->c[r],
|
|
Kr>>3,
|
|
&dlsch->harq_processes[harq_pid]->d[r][96],
|
|
(r==0) ? dlsch->harq_processes[harq_pid]->F : 0,
|
|
f1f2mat_old[iind*2], // f1 (see 36121-820, page 14)
|
|
f1f2mat_old[(iind*2)+1] // f2 (see 36121-820, page 14)
|
|
);
|
|
stop_meas(te_stats);
|
|
#ifdef DEBUG_DLSCH_CODING
|
|
|
|
if (r==0)
|
|
write_output("enc_output0.m","enc0",&dlsch->harq_processes[harq_pid]->d[r][96],(3*8*Kr_bytes)+12,1,4);
|
|
|
|
#endif
|
|
start_meas(i_stats);
|
|
dlsch->harq_processes[harq_pid]->RTC[r] =
|
|
sub_block_interleaving_turbo(4+(Kr_bytes*8),
|
|
&dlsch->harq_processes[harq_pid]->d[r][96],
|
|
dlsch->harq_processes[harq_pid]->w[r]);
|
|
stop_meas(i_stats);
|
|
}
|
|
|
|
}
|
|
|
|
// 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; r<dlsch->harq_processes[harq_pid]->C; r++) {
|
|
#ifdef DEBUG_DLSCH_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,
|
|
mod_order,nb_rb);
|
|
#endif
|
|
|
|
start_meas(rm_stats);
|
|
r_offset += lte_rate_matching_turbo(dlsch->harq_processes[harq_pid]->RTC[r],
|
|
G, //G
|
|
dlsch->harq_processes[harq_pid]->w[r],
|
|
dlsch->harq_processes[harq_pid]->e+r_offset, // sequence of bits for transmission
|
|
dlsch->harq_processes[harq_pid]->C, // C
|
|
dlsch->Nsoft, // Nsoft,
|
|
dlsch->Mdlharq,
|
|
dlsch->Kmimo,
|
|
dlsch->harq_processes[harq_pid]->rvidx,
|
|
get_Qm(dlsch->harq_processes[harq_pid]->mcs),
|
|
dlsch->harq_processes[harq_pid]->Nl,
|
|
r,
|
|
nb_rb,
|
|
m); // r
|
|
stop_meas(rm_stats);
|
|
#ifdef DEBUG_DLSCH_CODING
|
|
|
|
if (r==dlsch->harq_processes[harq_pid]->C-1)
|
|
write_output("enc_output.m","enc",dlsch->harq_processes[harq_pid]->e,r_offset,1,4);
|
|
|
|
#endif
|
|
}
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING, VCD_FUNCTION_OUT);
|
|
|
|
return(0);
|
|
}
|
|
|
|
#ifdef PHY_ABSTRACTION
|
|
void dlsch_encoding_emul(PHY_VARS_eNB *phy_vars_eNB,
|
|
uint8_t *DLSCH_pdu,
|
|
LTE_eNB_DLSCH_t *dlsch)
|
|
{
|
|
|
|
//int payload_offset = 0;
|
|
unsigned char harq_pid = dlsch->current_harq_pid;
|
|
unsigned short i;
|
|
|
|
// if (dlsch->harq_processes[harq_pid]->Ndi == 1) {
|
|
if (dlsch->harq_processes[harq_pid]->round == 0) {
|
|
memcpy(dlsch->harq_processes[harq_pid]->b,
|
|
DLSCH_pdu,
|
|
dlsch->harq_processes[harq_pid]->TBS>>3);
|
|
LOG_D(PHY, "eNB %d dlsch_encoding_emul, tbs is %d harq pid %d \n",
|
|
phy_vars_eNB->Mod_id,
|
|
dlsch->harq_processes[harq_pid]->TBS>>3,
|
|
harq_pid);
|
|
|
|
for (i=0; i<dlsch->harq_processes[harq_pid]->TBS>>3; i++)
|
|
LOG_T(PHY,"%x.",DLSCH_pdu[i]);
|
|
|
|
LOG_T(PHY,"\n");
|
|
|
|
memcpy(&eNB_transport_info[phy_vars_eNB->Mod_id][phy_vars_eNB->CC_id].transport_blocks[eNB_transport_info_TB_index[phy_vars_eNB->Mod_id][phy_vars_eNB->CC_id]],
|
|
// memcpy(&eNB_transport_info[phy_vars_eNB->Mod_id].transport_blocks[payload_offset],
|
|
DLSCH_pdu,
|
|
dlsch->harq_processes[harq_pid]->TBS>>3);
|
|
}
|
|
|
|
eNB_transport_info_TB_index[phy_vars_eNB->Mod_id][phy_vars_eNB->CC_id]+=dlsch->harq_processes[harq_pid]->TBS>>3;
|
|
//payload_offset +=dlsch->harq_processes[harq_pid]->TBS>>3;
|
|
|
|
}
|
|
#endif
|