@ -31,7 +31,6 @@
# include <strings.h>
# include <strings.h>
# include <stdlib.h>
# include <stdlib.h>
# include <stdbool.h>
# include <stdbool.h>
# include <assert.h>
# include <math.h>
# include <math.h>
# include "liblte/phy/phch/dci.h"
# include "liblte/phy/phch/dci.h"
@ -55,11 +54,13 @@ const dci_format_t ue_formats[NOF_UE_FORMATS] = { Format0, Format1 }; // 1A has
# define MIN(a,b) ((a>b)?b:a)
# define MIN(a,b) ((a>b)?b:a)
void set_cfi ( pdcch_t * q , uint8_t cfi ) ;
/**
/**
* 36.213 9.1
* 36.213 9.1
*/
*/
int gen_common_search ( dci_candidate_t * c , int nof_cce , int nof_bits ,
int gen_common_search ( dci_candidate_t * c , u int16_ t nof_cce , u int16_ t nof_bits ,
u nsigned shor t rnti ) {
u int16_ t rnti ) {
int i , l , L , k ;
int i , l , L , k ;
k = 0 ;
k = 0 ;
for ( l = 3 ; l > 1 ; l - - ) {
for ( l = 3 ; l > 1 ; l - - ) {
@ -80,15 +81,15 @@ int gen_common_search(dci_candidate_t *c, int nof_cce, int nof_bits,
/**
/**
* 36.213 9.1
* 36.213 9.1
*/
*/
int gen_ue_search ( dci_candidate_t * c , int nof_cce , int nof_bits ,
int gen_ue_search ( dci_candidate_t * c , u int16_ t nof_cce , u int8_ t nof_bits ,
u nsigned short rnti , in t subframe ) {
u int16_t rnti , uint8_ t subframe ) {
int i , l , L , k , m ;
int i , l , L , k , m ;
unsigned int Yk ;
unsigned int Yk ;
const int S [ 4 ] = { 6 , 12 , 8 , 16 } ;
const int S [ 4 ] = { 6 , 12 , 8 , 16 } ;
k = 0 ;
k = 0 ;
if ( ! subframe ) {
INFO ( " UE-specific candidates for RNTI: 0x%x, NofBits: %d, NofCCE: %d \n " ,
if ( VERBOSE_ISDEBUG ( ) ) {
rnti , nof_bits , nof_cc e) ;
printf ( " NofBits=%d, RNTI: 0x%x, SF=%d (n, L): " , nof_bits , rnti , subfram e) ;
}
}
for ( l = 3 ; l > = 0 ; l - - ) {
for ( l = 3 ; l > = 0 ; l - - ) {
L = ( 1 < < l ) ;
L = ( 1 < < l ) ;
@ -102,7 +103,12 @@ int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits,
}
}
c [ k ] . ncce = L * ( ( Yk + i ) % ( nof_cce / L ) ) ;
c [ k ] . ncce = L * ( ( Yk + i ) % ( nof_cce / L ) ) ;
if ( VERBOSE_ISDEBUG ( ) ) {
if ( VERBOSE_ISDEBUG ( ) ) {
printf ( " sf %d - (%d, %d), " , subframe , c [ k ] . ncce , c [ k ] . L ) ;
printf ( " (%d, %d), " , c [ k ] . ncce , c [ k ] . L ) ;
}
if ( c [ k ] . ncce + PDCCH_FORMAT_NOF_CCE ( c [ k ] . L ) > nof_cce | |
nof_bits > DCI_MAX_BITS ) {
fprintf ( stderr , " Illegal DCI message \n " ) ;
return LIBLTE_ERROR ;
}
}
k + + ;
k + + ;
}
}
@ -113,35 +119,17 @@ int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits,
return k ;
return k ;
}
}
void pdcch_init_common ( pdcch_t * q , pdcch_search_t * s , unsigned short rnti ) {
int k , i ;
dci_candidate_t * c = s - > candidates [ 0 ] ;
s - > nof_candidates = 0 ;
// Format 1A and 1C L=4 and L=8, 4 and 2 candidates, only if nof_cce > 16
k = 0 ;
for ( i = 0 ; i < NOF_COMMON_FORMATS & & k < MAX_CANDIDATES ; i + + ) {
k + = gen_common_search ( & c [ k ] , q - > nof_cce ,
dci_format_sizeof ( common_formats [ i ] , q - > nof_prb ) , SIRNTI ) ;
}
s - > nof_candidates = k ;
INFO ( " Initiated %d candidate(s) in the Common search space for RNTI: 0x%x \n " ,
s - > nof_candidates , rnti ) ;
}
/** 36.213 v9.3 Table 7.1-1: System Information DCI messages
* Expect DCI formats 1 C and 1 A in the common search space
*/
void pdcch_init_search_si ( pdcch_t * q ) {
pdcch_init_common ( q , & q - > search_mode [ SEARCH_SI ] , SIRNTI ) ;
q - > current_search_mode = SEARCH_SI ;
}
/** 36.213 v9.3 Table 7.1-5
/** 36.213 v9.3 Table 7.1-5
* user - specific search space . Currently supported transmission Mode 1 :
* user - specific search space . Currently supported transmission Mode 1 :
* DCI Format 1 A and 1 + PUSCH scheduling format 0
* DCI Format 1 A and 1 + PUSCH scheduling format 0
*/
*/
void pdcch_init_search_ue ( pdcch_t * q , unsigned short c_rnti ) {
int pdcch_init_search_ue ( pdcch_t * q , uint16_t c_rnti , uint8_t cfi ) {
int n , k , i ;
int k , i , r ;
uint8_t n ;
set_cfi ( q , cfi ) ;
pdcch_search_t * s = & q - > search_mode [ SEARCH_UE ] ;
pdcch_search_t * s = & q - > search_mode [ SEARCH_UE ] ;
for ( n = 0 ; n < NSUBFRAMES_X_FRAME ; n + + ) {
for ( n = 0 ; n < NSUBFRAMES_X_FRAME ; n + + ) {
dci_candidate_t * c = s - > candidates [ n ] ;
dci_candidate_t * c = s - > candidates [ n ] ;
@ -151,23 +139,68 @@ void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) {
// Expect Formats 1, 1A, 0
// Expect Formats 1, 1A, 0
k = 0 ;
k = 0 ;
for ( i = 0 ; i < NOF_UE_FORMATS & & k < MAX_CANDIDATES ; i + + ) {
for ( i = 0 ; i < NOF_UE_FORMATS & & k < MAX_CANDIDATES ; i + + ) {
k + = gen_ue_search ( & c [ k ] , q - > nof_cce ,
r = gen_ue_search ( & c [ k ] , q - > nof_cce ,
dci_format_sizeof ( ue_formats [ i ] , q - > nof_prb ) , c_rnti , n ) ;
dci_format_sizeof ( ue_formats [ i ] , q - > cell . nof_prb ) , c_rnti , n ) ;
if ( r < 0 ) {
fprintf ( stderr , " Error generating UE-specific search space \n " ) ;
return r ;
}
k + = r ;
}
}
s - > nof_candidates = k ;
s - > nof_candidates = k ;
}
}
INFO ( " Initiated %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x \n " ,
INFO ( " Initiated %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x \n " ,
s - > nof_candidates , c_rnti ) ;
s - > nof_candidates , c_rnti ) ;
q - > current_search_mode = SEARCH_UE ;
q - > current_search_mode = SEARCH_UE ;
return LIBLTE_SUCCESS ;
}
int pdcch_init_common ( pdcch_t * q , pdcch_search_t * s , uint16_t rnti ) {
int k , r , i ;
dci_candidate_t * c = s - > candidates [ 0 ] ;
s - > nof_candidates = 0 ;
// Format 1A and 1C L=4 and L=8, 4 and 2 candidates, only if nof_cce > 16
k = 0 ;
for ( i = 0 ; i < NOF_COMMON_FORMATS & & k < MAX_CANDIDATES ; i + + ) {
r = gen_common_search ( & c [ k ] , q - > nof_cce ,
dci_format_sizeof ( common_formats [ i ] , q - > cell . nof_prb ) , SIRNTI ) ;
if ( r < 0 ) {
return r ;
}
k + = r ;
}
s - > nof_candidates = k ;
INFO ( " Initiated %d candidate(s) in the Common search space for RNTI: 0x%x \n " ,
s - > nof_candidates , rnti ) ;
return LIBLTE_SUCCESS ;
}
/** 36.213 v9.3 Table 7.1-1: System Information DCI messages
* Expect DCI formats 1 C and 1 A in the common search space
*/
int pdcch_init_search_si ( pdcch_t * q , uint8_t cfi ) {
set_cfi ( q , cfi ) ;
int r = pdcch_init_common ( q , & q - > search_mode [ SEARCH_SI ] , SIRNTI ) ;
if ( r > = 0 ) {
q - > current_search_mode = SEARCH_SI ;
}
return r ;
}
}
/** 36.213 v9.3 Table 7.1-3
/** 36.213 v9.3 Table 7.1-3
* Expect DCI formats 1 C and 1 A in the common search space
* Expect DCI formats 1 C and 1 A in the common search space
*/
*/
void pdcch_init_search_ra ( pdcch_t * q , unsigned short ra_rnti ) {
int pdcch_init_search_ra ( pdcch_t * q , uint16_t ra_rnti , uint8_t cfi ) {
pdcch_init_common ( q , & q - > search_mode [ SEARCH_RA ] , ra_rnti ) ;
set_cfi ( q , cfi ) ;
int r = pdcch_init_common ( q , & q - > search_mode [ SEARCH_RA ] , ra_rnti ) ;
if ( r > = 0 ) {
q - > current_search_mode = SEARCH_RA ;
q - > current_search_mode = SEARCH_RA ;
}
}
return r ;
}
void pdcch_set_search_si ( pdcch_t * q ) {
void pdcch_set_search_si ( pdcch_t * q ) {
q - > current_search_mode = SEARCH_SI ;
q - > current_search_mode = SEARCH_SI ;
@ -179,52 +212,37 @@ void pdcch_set_search_ra(pdcch_t *q) {
q - > current_search_mode = SEARCH_RA ;
q - > current_search_mode = SEARCH_RA ;
}
}
int pdcch_set_cfi ( pdcch_t * q , int cfi ) {
void set_cfi ( pdcch_t * q , uint8_t cfi ) {
if ( cfi = = - 1 ) {
if ( cfi > 0 & & cfi < 4 ) {
q - > nof_bits = - 1 ;
q - > nof_symbols = - 1 ;
q - > nof_cce = - 1 ;
q - > nof_regs = - 1 ;
return 0 ;
} else if ( cfi < 4 & & cfi > 0 ) {
q - > nof_regs = ( regs_pdcch_nregs ( q - > regs , cfi ) / 9 ) * 9 ;
q - > nof_regs = ( regs_pdcch_nregs ( q - > regs , cfi ) / 9 ) * 9 ;
q - > nof_cce = q - > nof_regs / 9 ;
q - > nof_cce = q - > nof_regs / 9 ;
q - > nof_symbols = 4 * q - > nof_regs ;
q - > nof_symbols = 4 * q - > nof_regs ;
q - > nof_bits = 2 * q - > nof_symbols ;
q - > nof_bits = 2 * q - > nof_symbols ;
return 0 ;
} else {
return - 1 ;
}
}
}
}
/** Initializes the PDCCH transmitter and receiver */
/** Initializes the PDCCH transmitter and receiver */
int pdcch_init ( pdcch_t * q , regs_t * regs , int nof_prb , int nof_ports ,
int pdcch_init ( pdcch_t * q , regs_t * regs , lte_cell_t cell ) {
int cell_id , lte_cp_t cp ) {
int ret = LIBLTE_ERROR_INVALID_INPUTS ;
int ret = - 1 ;
int i ;
int i ;
if ( cell_id < 0 ) {
if ( q ! = NULL & &
return - 1 ;
regs ! = NULL & &
}
lte_cell_isvalid ( & cell ) )
if ( nof_ports > MAX_PORTS ) {
{
fprintf ( stderr , " Invalid number of ports %d \n " , nof_ports ) ;
ret = LIBLTE_ERROR ;
return - 1 ;
}
bzero ( q , sizeof ( pdcch_t ) ) ;
bzero ( q , sizeof ( pdcch_t ) ) ;
q - > cell_id = cell_id ;
q - > cell = cell ;
q - > cp = cp ;
q - > regs = regs ;
q - > regs = regs ;
q - > nof_ports = nof_ports ;
q - > nof_prb = nof_prb ;
q - > current_search_mode = SEARCH_NONE ;
q - > current_search_mode = SEARCH_NONE ;
/* Now allocate memory for the maximum number of REGs (CFI=2), then can
/* Now allocate memory for the maximum number of REGs (CFI=3)
* be changed at runtime
*/
*/
pdcch_set_cfi ( q , 3 ) ;
set_cfi ( q , 3 ) ;
q - > max_bits = q - > nof_bits ;
INFO ( " Init PDCCH: %d CCEs (%d REGs), %d bits, %d symbols, %d ports \n " ,
INFO ( " Init PDCCH: %d CCEs (%d REGs), %d bits, %d symbols, %d ports \n " ,
q - > nof_cce , q - > nof_regs , q - > nof_bits , q - > nof_symbols , q - > nof_ports ) ;
q - > nof_cce , q - > nof_regs , q - > nof_bits , q - > nof_symbols , q - > cell . nof_ports ) ;
if ( modem_table_std ( & q - > mod , LTE_QPSK , true ) ) {
if ( modem_table_std ( & q - > mod , LTE_QPSK , true ) ) {
goto clean ;
goto clean ;
@ -238,7 +256,7 @@ int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports,
demod_soft_alg_set ( & q - > demod , APPROX ) ;
demod_soft_alg_set ( & q - > demod , APPROX ) ;
for ( i = 0 ; i < NSUBFRAMES_X_FRAME ; i + + ) {
for ( i = 0 ; i < NSUBFRAMES_X_FRAME ; i + + ) {
if ( sequence_pdcch ( & q - > seq_pdcch [ i ] , 2 * i , q - > cell _ id, q - > nof_bits ) ) {
if ( sequence_pdcch ( & q - > seq_pdcch [ i ] , 2 * i , q - > cell . id, q - > nof_bits ) ) {
goto clean ;
goto clean ;
}
}
}
}
@ -278,11 +296,10 @@ int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports,
}
}
}
}
/* Reset CFI to make sure we return error if new CFI is not set */
ret = LIBLTE_SUCCESS ;
pdcch_set_cfi ( q , - 1 ) ;
}
clean :
ret = 0 ;
if ( ret = = LIBLTE_ERROR ) {
clean : if ( ret = = - 1 ) {
pdcch_free ( q ) ;
pdcch_free ( q ) ;
}
}
return ret ;
return ret ;
@ -326,13 +343,17 @@ void pdcch_free(pdcch_t *q) {
*
*
* TODO : UE transmit antenna selection CRC mask
* TODO : UE transmit antenna selection CRC mask
*/
*/
uns ig ned shor t dci_decode ( pdcch_t * q , float * e , char * data , int E , int nof_bits ) {
int dci_decode ( pdcch_t * q , float * e , char * data , u int16_ t E , u int16_t nof_bits , uint16_t * crc ) {
float tmp [ 3 * ( DCI_MAX_BITS + 16 ) ] ;
float tmp [ 3 * ( DCI_MAX_BITS + 16 ) ] ;
u nsigned shor t p_bits , crc_res ;
u int16_ t p_bits , crc_res ;
char * x ;
char * x ;
assert ( nof_bits < DCI_MAX_BITS ) ;
if ( q ! = NULL & &
data ! = NULL & &
E < q - > max_bits & &
nof_bits < DCI_MAX_BITS )
{
/* unrate matching */
/* unrate matching */
rm_conv_rx ( e , E , tmp , 3 * ( nof_bits + 16 ) ) ;
rm_conv_rx ( e , E , tmp , 3 * ( nof_bits + 16 ) ) ;
@ -350,20 +371,30 @@ unsigned short dci_decode(pdcch_t *q, float *e, char *data, int E, int nof_bits)
}
}
x = & data [ nof_bits ] ;
x = & data [ nof_bits ] ;
p_bits = ( unsigned shor t) bit_unpack ( & x , 16 ) ;
p_bits = ( uint16_ t) bit_unpack ( & x , 16 ) ;
crc_res = ( ( u nsigned shor t) crc_checksum ( & q - > crc , data , nof_bits ) & 0xffff ) ;
crc_res = ( ( u int16_ t) crc_checksum ( & q - > crc , data , nof_bits ) & 0xffff ) ;
DEBUG ( " p_bits: 0x%x, crc_res: 0x%x, tot: 0x%x \n " , p_bits , crc_res ,
DEBUG ( " p_bits: 0x%x, crc_res: 0x%x, tot: 0x%x \n " , p_bits , crc_res ,
p_bits ^ crc_res ) ;
p_bits ^ crc_res ) ;
return ( p_bits ^ crc_res ) ;
if ( crc ) {
* crc = p_bits ^ crc_res ;
}
return LIBLTE_SUCCESS ;
} else {
return LIBLTE_ERROR_INVALID_INPUTS ;
}
}
}
int pdcch_decode_candidate ( pdcch_t * q , float * llr , dci_candidate_t * c ,
int pdcch_decode_candidate ( pdcch_t * q , float * llr , dci_candidate_t * c ,
dci_msg_t * msg ) {
dci_msg_t * msg ) {
unsigned short crc_res ;
u int16_ t crc_res ;
INFO ( " Trying Candidate: Nbits: %d, E: %3d, nCCE: %d, L: %d, RNTI: 0x%x \n " ,
INFO ( " Trying Candidate: Nbits: %d, E: %3d, nCCE: %d, L: %d, RNTI: 0x%x \n " ,
c - > nof_bits , PDCCH_FORMAT_NOF_BITS ( c - > L ) , c - > ncce , c - > L , c - > rnti ) ;
c - > nof_bits , PDCCH_FORMAT_NOF_BITS ( c - > L ) , c - > ncce , c - > L , c - > rnti ) ;
crc_res = dci_decode ( q , & llr [ 72 * c - > ncce ] , msg - > data ,
PDCCH_FORMAT_NOF_BITS ( c - > L ) , c - > nof_bits ) ;
if ( dci_decode ( q , & llr [ 72 * c - > ncce ] , msg - > data ,
PDCCH_FORMAT_NOF_BITS ( c - > L ) , c - > nof_bits , & crc_res ) ) {
return LIBLTE_ERROR ;
}
if ( c - > rnti = = crc_res ) {
if ( c - > rnti = = crc_res ) {
memcpy ( & msg - > location , c , sizeof ( dci_candidate_t ) ) ;
memcpy ( & msg - > location , c , sizeof ( dci_candidate_t ) ) ;
@ -371,60 +402,59 @@ int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c,
c - > nof_bits , PDCCH_FORMAT_NOF_BITS ( c - > L ) , c - > ncce , c - > L , c - > rnti ) ;
c - > nof_bits , PDCCH_FORMAT_NOF_BITS ( c - > L ) , c - > ncce , c - > L , c - > rnti ) ;
return 1 ;
return 1 ;
}
}
return 0 ;
return LIBLTE_SUCCESS ;
}
}
int pdcch_extract_llr ( pdcch_t * q , cf_t * slot_symbols , cf_t * ce [ MAX_PORTS ] ,
int pdcch_extract_llr ( pdcch_t * q , cf_t * slot_symbols , cf_t * ce [ MAX_PORTS ] ,
float * llr , int nsubframe ) {
float * llr , u int8_ t nsubframe , uint8_t cfi ) {
/* Set pointers for layermapping & precoding */
/* Set pointers for layermapping & precoding */
int i ;
int i ;
cf_t * x [ MAX_LAYERS ] ;
cf_t * x [ MAX_LAYERS ] ;
if ( q - > nof_bits = = - 1 | | q - > nof_cce = = - 1 | | q - > nof_regs = = - 1 ) {
if ( q ! = NULL & &
fprintf ( stderr , " Must call pdcch_set_cfi() first to set the CFI \n " ) ;
llr ! = NULL & &
return - 1 ;
slot_symbols ! = NULL & &
}
nsubframe < 10 & &
cfi > 0 & &
if ( nsubframe < 0 | | nsubframe > NSUBFRAMES_X_FRAME ) {
cfi < 4 )
fprintf ( stderr , " Invalid subframe %d \n " , nsubframe ) ;
{
return - 1 ;
set_cfi ( q , cfi ) ;
}
/* number of layers equals number of ports */
/* number of layers equals number of ports */
for ( i = 0 ; i < q - > nof_ports ; i + + ) {
for ( i = 0 ; i < q - > cell . nof_ports ; i + + ) {
x [ i ] = q - > pdcch_x [ i ] ;
x [ i ] = q - > pdcch_x [ i ] ;
}
}
memset ( & x [ q - > nof_ports ] , 0 , sizeof ( cf_t * ) * ( MAX_LAYERS - q - > nof_ports ) ) ;
memset ( & x [ q - > cell . nof_ports ] , 0 , sizeof ( cf_t * ) * ( MAX_LAYERS - q - > cell . nof_ports ) ) ;
/* extract symbols */
/* extract symbols */
int n = regs_pdcch_get ( q - > regs , slot_symbols , q - > pdcch_symbols [ 0 ] ) ;
int n = regs_pdcch_get ( q - > regs , slot_symbols , q - > pdcch_symbols [ 0 ] ) ;
if ( q - > nof_symbols ! = n ) {
if ( q - > nof_symbols ! = n ) {
fprintf ( stderr , " Expected %d PDCCH symbols but got %d symbols \n " ,
fprintf ( stderr , " Expected %d PDCCH symbols but got %d symbols \n " ,
q - > nof_symbols , n ) ;
q - > nof_symbols , n ) ;
return - 1 ;
return LIBLTE_ERROR ;
}
}
/* extract channel estimates */
/* extract channel estimates */
for ( i = 0 ; i < q - > nof_ports ; i + + ) {
for ( i = 0 ; i < q - > cell . nof_ports ; i + + ) {
n = regs_pdcch_get ( q - > regs , ce [ i ] , q - > ce [ i ] ) ;
n = regs_pdcch_get ( q - > regs , ce [ i ] , q - > ce [ i ] ) ;
if ( q - > nof_symbols ! = n ) {
if ( q - > nof_symbols ! = n ) {
fprintf ( stderr , " Expected %d PDCCH symbols but got %d symbols \n " ,
fprintf ( stderr , " Expected %d PDCCH symbols but got %d symbols \n " ,
q - > nof_symbols , n ) ;
q - > nof_symbols , n ) ;
return - 1 ;
return LIBLTE_ERROR ;
}
}
}
}
/* in control channels, only diversity is supported */
/* in control channels, only diversity is supported */
if ( q - > nof_ports = = 1 ) {
if ( q - > cell . nof_ports = = 1 ) {
/* no need for layer demapping */
/* no need for layer demapping */
predecoding_single_zf ( q - > pdcch_symbols [ 0 ] , q - > ce [ 0 ] , q - > pdcch_d ,
predecoding_single_zf ( q - > pdcch_symbols [ 0 ] , q - > ce [ 0 ] , q - > pdcch_d ,
q - > nof_symbols ) ;
q - > nof_symbols ) ;
} else {
} else {
predecoding_diversity_zf ( q - > pdcch_symbols [ 0 ] , q - > ce , x , q - > nof_ports ,
predecoding_diversity_zf ( q - > pdcch_symbols [ 0 ] , q - > ce , x , q - > cell . nof_ports ,
q - > nof_symbols ) ;
q - > nof_symbols ) ;
layerdemap_diversity ( x , q - > pdcch_d , q - > nof_ports ,
layerdemap_diversity ( x , q - > pdcch_d , q - > cell . nof_ports ,
q - > nof_symbols / q - > nof_ports ) ;
q - > nof_symbols / q - > cell . nof_ports ) ;
}
}
DEBUG ( " pdcch d symbols: " , 0 ) ;
DEBUG ( " pdcch d symbols: " , 0 ) ;
@ -444,11 +474,15 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS],
/* descramble */
/* descramble */
scrambling_f_offset ( & q - > seq_pdcch [ nsubframe ] , llr , 0 , q - > nof_bits ) ;
scrambling_f_offset ( & q - > seq_pdcch [ nsubframe ] , llr , 0 , q - > nof_bits ) ;
return 0 ;
return LIBLTE_SUCCESS ;
} else {
return LIBLTE_ERROR_INVALID_INPUTS ;
}
}
}
int pdcch_decode_current_mode ( pdcch_t * q , float * llr , dci_t * dci , int subframe ) {
int pdcch_decode_current_mode ( pdcch_t * q , float * llr , dci_t * dci , u int8_ t subframe ) {
int k , i ;
int k , i ;
int ret ;
if ( q - > current_search_mode = = SEARCH_UE ) {
if ( q - > current_search_mode = = SEARCH_UE ) {
k = subframe ;
k = subframe ;
@ -459,10 +493,13 @@ int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe)
for ( i = 0 ;
for ( i = 0 ;
i < q - > search_mode [ q - > current_search_mode ] . nof_candidates
i < q - > search_mode [ q - > current_search_mode ] . nof_candidates
& & dci - > nof_dcis < dci - > max_dcis ; i + + ) {
& & dci - > nof_dcis < dci - > max_dcis ; i + + ) {
if ( pdcch_decode_candidate ( q , q - > pdcch_llr ,
ret = pdcch_decode_candidate ( q , q - > pdcch_llr ,
& q - > search_mode [ q - > current_search_mode ] . candidates [ k ] [ i ] ,
& q - > search_mode [ q - > current_search_mode ] . candidates [ k ] [ i ] ,
& dci - > msg [ dci - > nof_dcis ] ) ) {
& dci - > msg [ dci - > nof_dcis ] ) ;
if ( ret = = 1 ) {
dci - > nof_dcis + + ;
dci - > nof_dcis + + ;
} else if ( ret = = - 1 ) {
return LIBLTE_ERROR ;
}
}
}
}
return dci - > nof_dcis ;
return dci - > nof_dcis ;
@ -476,7 +513,7 @@ int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci) {
pdcch_set_search_ra ( q ) ;
pdcch_set_search_ra ( q ) ;
return pdcch_decode_current_mode ( q , llr , dci , 0 ) ;
return pdcch_decode_current_mode ( q , llr , dci , 0 ) ;
}
}
int pdcch_decode_ue ( pdcch_t * q , float * llr , dci_t * dci , int nsubframe ) {
int pdcch_decode_ue ( pdcch_t * q , float * llr , dci_t * dci , u int8_ t nsubframe ) {
pdcch_set_search_ue ( q ) ;
pdcch_set_search_ue ( q ) ;
return pdcch_decode_current_mode ( q , llr , dci , nsubframe ) ;
return pdcch_decode_current_mode ( q , llr , dci , nsubframe ) ;
}
}
@ -488,25 +525,30 @@ int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe) {
* Returns number of messages stored in dci
* Returns number of messages stored in dci
*/
*/
int pdcch_decode ( pdcch_t * q , cf_t * slot_symbols , cf_t * ce [ MAX_PORTS ] ,
int pdcch_decode ( pdcch_t * q , cf_t * slot_symbols , cf_t * ce [ MAX_PORTS ] ,
dci_t * dci , int nsubframe ) {
dci_t * dci , uint8_t subframe , uint8_t cfi ) {
if ( q - > nof_bits = = - 1 | | q - > nof_cce = = - 1 | | q - > nof_regs = = - 1 ) {
fprintf ( stderr , " Must call pdcch_set_cfi() first to set the CFI \n " ) ;
return - 1 ;
}
if ( pdcch_extract_llr ( q , slot_symbols , ce , q - > pdcch_llr , nsubframe ) ) {
if ( q ! = NULL & &
return - 1 ;
dci ! = NULL & &
slot_symbols ! = NULL & &
subframe < 10 & &
cfi > 0 & &
cfi < 4 )
{
if ( pdcch_extract_llr ( q , slot_symbols , ce , q - > pdcch_llr , subframe , cfi ) ) {
return LIBLTE_ERROR ;
}
}
if ( q - > current_search_mode ! = SEARCH_NONE ) {
if ( q - > current_search_mode ! = SEARCH_NONE ) {
return pdcch_decode_current_mode ( q , q - > pdcch_llr , dci , nsubframe ) ;
return pdcch_decode_current_mode ( q , q - > pdcch_llr , dci , subframe) ;
}
}
return 0 ;
return LIBLTE_SUCCESS ;
} else {
return LIBLTE_ERROR_INVALID_INPUTS ;
}
}
}
void crc_set_mask_rnti ( char * crc , unsigned short rnti ) {
void crc_set_mask_rnti ( char * crc , u int16_ t rnti ) {
int i ;
int i ;
char mask [ 16 ] ;
char mask [ 16 ] ;
char * r = mask ;
char * r = mask ;
@ -522,12 +564,17 @@ void crc_set_mask_rnti(char *crc, unsigned short rnti) {
/** 36.212 5.3.3.2 to 5.3.3.4
/** 36.212 5.3.3.2 to 5.3.3.4
* TODO : UE transmit antenna selection CRC mask
* TODO : UE transmit antenna selection CRC mask
*/
*/
void dci_encode ( pdcch_t * q , char * data , char * e , int nof_bits , int E ,
int dci_encode ( pdcch_t * q , char * data , char * e , u int16_ t nof_bits , u int16_ t E ,
u nsigned shor t rnti ) {
u int16_ t rnti ) {
convcoder_t encoder ;
convcoder_t encoder ;
char tmp [ 3 * ( DCI_MAX_BITS + 16 ) ] ;
char tmp [ 3 * ( DCI_MAX_BITS + 16 ) ] ;
assert ( nof_bits < DCI_MAX_BITS ) ;
if ( q ! = NULL & &
data ! = NULL & &
e ! = NULL & &
nof_bits < DCI_MAX_BITS & &
E < q - > max_bits )
{
int poly [ 3 ] = { 0x6D , 0x4F , 0x57 } ;
int poly [ 3 ] = { 0x6D , 0x4F , 0x57 } ;
encoder . K = 7 ;
encoder . K = 7 ;
@ -546,42 +593,48 @@ void dci_encode(pdcch_t *q, char *data, char *e, int nof_bits, int E,
}
}
rm_conv_tx ( tmp , 3 * ( nof_bits + 16 ) , e , E ) ;
rm_conv_tx ( tmp , 3 * ( nof_bits + 16 ) , e , E ) ;
return LIBLTE_SUCCESS ;
} else {
return LIBLTE_ERROR_INVALID_INPUTS ;
}
}
}
/** Converts the set of DCI messages to symbols mapped to the slot ready for transmission
/** Converts the set of DCI messages to symbols mapped to the slot ready for transmission
*/
*/
int pdcch_encode ( pdcch_t * q , dci_t * dci , cf_t * slot_symbols [ MAX_PORTS ] ,
int pdcch_encode ( pdcch_t * q , dci_t * dci , cf_t * slot_symbols [ MAX_PORTS ] ,
int nsubframe ) {
u int8_ t nsubframe , uint8_t cfi ) {
int i ;
int i ;
/* Set pointers for layermapping & precoding */
/* Set pointers for layermapping & precoding */
cf_t * x [ MAX_LAYERS ] ;
cf_t * x [ MAX_LAYERS ] ;
if ( q - > nof_bits = = - 1 | | q - > nof_cce = = - 1 | | q - > nof_regs = = - 1 ) {
if ( q ! = NULL & &
fprintf ( stderr , " Must call pdcch_set_cfi() first to set the CFI \n " ) ;
dci ! = NULL & &
return - 1 ;
slot_symbols ! = NULL & &
}
nsubframe < 10 & &
if ( nsubframe < 0 | | nsubframe > NSUBFRAMES_X_FRAME ) {
cfi > 0 & &
fprintf ( stderr , " Invalid subframe %d \n " , nsubframe ) ;
cfi < 4 )
return - 1 ;
{
}
set_cfi ( q , cfi ) ;
/* number of layers equals number of ports */
/* number of layers equals number of ports */
for ( i = 0 ; i < q - > nof_ports ; i + + ) {
for ( i = 0 ; i < q - > cell . nof_ports ; i + + ) {
x [ i ] = q - > pdcch_x [ i ] ;
x [ i ] = q - > pdcch_x [ i ] ;
}
}
memset ( & x [ q - > nof_ports ] , 0 , sizeof ( cf_t * ) * ( MAX_LAYERS - q - > nof_ports ) ) ;
memset ( & x [ q - > cell . nof_ports ] , 0 , sizeof ( cf_t * ) * ( MAX_LAYERS - q - > cell . nof_ports ) ) ;
/* should add <NIL> elements? Or maybe random bits to facilitate power estimation */
/* should add <NIL> elements? Or maybe random bits to facilitate power estimation */
bzero ( q - > pdcch_e , q - > nof_bits ) ;
bzero ( q - > pdcch_e , q - > nof_bits ) ;
/* Encode DCIs */
/* Encode DCIs */
for ( i = 0 ; i < dci - > nof_dcis ; i + + ) {
for ( i = 0 ; i < dci - > nof_dcis ; i + + ) {
/* do some sanity checks */
/* do some checks */
if ( dci - > msg [ i ] . location . ncce + PDCCH_FORMAT_NOF_CCE ( dci - > msg [ i ] . location . L )
if ( dci - > msg [ i ] . location . ncce + PDCCH_FORMAT_NOF_CCE ( dci - > msg [ i ] . location . L )
> q - > nof_cce | | dci - > msg [ i ] . location . L > 3
> q - > nof_cce | | dci - > msg [ i ] . location . L > 3
| | dci - > msg [ i ] . location . nof_bits > DCI_MAX_BITS ) {
| | dci - > msg [ i ] . location . nof_bits > DCI_MAX_BITS ) {
fprintf ( stderr , " Illegal DCI message %d \n " , i ) ;
fprintf ( stderr , " Illegal DCI message nCCE: %d, L: %d, nof_cce: %d \n " ,
return - 1 ;
dci - > msg [ i ] . location . ncce , dci - > msg [ i ] . location . L , q - > nof_cce ) ;
return LIBLTE_ERROR ;
}
}
INFO ( " Encoding DCI %d: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x \n " , i ,
INFO ( " Encoding DCI %d: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x \n " , i ,
dci - > msg [ i ] . location . nof_bits ,
dci - > msg [ i ] . location . nof_bits ,
@ -600,18 +653,21 @@ int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS],
mod_modulate ( & q - > mod , q - > pdcch_e , q - > pdcch_d , q - > nof_bits ) ;
mod_modulate ( & q - > mod , q - > pdcch_e , q - > pdcch_d , q - > nof_bits ) ;
/* layer mapping & precoding */
/* layer mapping & precoding */
if ( q - > nof_ports > 1 ) {
if ( q - > cell . nof_ports > 1 ) {
layermap_diversity ( q - > pdcch_d , x , q - > nof_ports , q - > nof_symbols ) ;
layermap_diversity ( q - > pdcch_d , x , q - > cell . nof_ports , q - > nof_symbols ) ;
precoding_diversity ( x , q - > pdcch_symbols , q - > nof_ports ,
precoding_diversity ( x , q - > pdcch_symbols , q - > cell . nof_ports ,
q - > nof_symbols / q - > nof_ports ) ;
q - > nof_symbols / q - > cell . nof_ports ) ;
} else {
} else {
memcpy ( q - > pdcch_symbols [ 0 ] , q - > pdcch_d , q - > nof_symbols * sizeof ( cf_t ) ) ;
memcpy ( q - > pdcch_symbols [ 0 ] , q - > pdcch_d , q - > nof_symbols * sizeof ( cf_t ) ) ;
}
}
/* mapping to resource elements */
/* mapping to resource elements */
for ( i = 0 ; i < q - > nof_ports ; i + + ) {
for ( i = 0 ; i < q - > cell . nof_ports ; i + + ) {
regs_pdcch_put ( q - > regs , q - > pdcch_symbols [ i ] , slot_symbols [ i ] ) ;
regs_pdcch_put ( q - > regs , q - > pdcch_symbols [ i ] , slot_symbols [ i ] ) ;
}
}
return 0 ;
return LIBLTE_SUCCESS ;
} else {
return LIBLTE_ERROR_INVALID_INPUTS ;
}
}
}