Added lte_cell_t struct to PBCH module.

master
ismagom 11 years ago
parent 5eab57670b
commit 231c29ef21

@ -38,10 +38,16 @@
void *uhd; void *uhd;
#endif #endif
lte_cell_t cell = {
6, // nof_prb
1, // nof_ports
1, // cell_id
CPNORM // cyclic prefix
};
char *output_file_name = NULL; char *output_file_name = NULL;
int nof_frames=-1; int nof_frames=-1;
int cell_id = 1;
int nof_prb = 6;
char *uhd_args = ""; char *uhd_args = "";
float uhd_amp=0.25, uhd_gain=10.0, uhd_freq=2400000000; float uhd_amp=0.25, uhd_gain=10.0, uhd_freq=2400000000;
@ -51,7 +57,7 @@ lte_fft_t ifft;
pbch_t pbch; pbch_t pbch;
cf_t *sf_buffer = NULL, *output_buffer = NULL; cf_t *sf_buffer = NULL, *output_buffer = NULL;
int slot_n_re, slot_n_samples; int sf_n_re, sf_n_samples;
#define UHD_SAMP_FREQ 1920000 #define UHD_SAMP_FREQ 1920000
@ -67,8 +73,8 @@ void usage(char *prog) {
#endif #endif
printf("\t-o output_file [Default USRP]\n"); printf("\t-o output_file [Default USRP]\n");
printf("\t-n number of frames [Default %d]\n", nof_frames); printf("\t-n number of frames [Default %d]\n", nof_frames);
printf("\t-c cell id [Default %d]\n", cell_id); printf("\t-c cell id [Default %d]\n", cell.id);
printf("\t-p nof_prb [Default %d]\n", nof_prb); printf("\t-p nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-v [set verbose to debug, default none]\n"); printf("\t-v [set verbose to debug, default none]\n");
} }
@ -95,10 +101,10 @@ void parse_args(int argc, char **argv) {
nof_frames = atoi(argv[optind]); nof_frames = atoi(argv[optind]);
break; break;
case 'p': case 'p':
nof_prb = atoi(argv[optind]); cell.nof_prb = atoi(argv[optind]);
break; break;
case 'c': case 'c':
cell_id = atoi(argv[optind]); cell.id = atoi(argv[optind]);
break; break;
case 'v': case 'v':
verbose++; verbose++;
@ -118,12 +124,12 @@ void parse_args(int argc, char **argv) {
void base_init() { void base_init() {
/* init memory */ /* init memory */
sf_buffer = malloc(sizeof(cf_t) * slot_n_re); sf_buffer = malloc(sizeof(cf_t) * sf_n_re);
if (!sf_buffer) { if (!sf_buffer) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
output_buffer = malloc(sizeof(cf_t) * slot_n_samples); output_buffer = malloc(sizeof(cf_t) * sf_n_samples);
if (!output_buffer) { if (!output_buffer) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
@ -148,11 +154,11 @@ void base_init() {
} }
/* create ifft object */ /* create ifft object */
if (lte_ifft_init(&ifft, CPNORM, nof_prb)) { if (lte_ifft_init(&ifft, CPNORM, cell.nof_prb)) {
fprintf(stderr, "Error creating iFFT object\n"); fprintf(stderr, "Error creating iFFT object\n");
exit(-1); exit(-1);
} }
if (pbch_init(&pbch, 6, cell_id, CPNORM)) { if (pbch_init(&pbch, cell)) {
fprintf(stderr, "Error creating PBCH object\n"); fprintf(stderr, "Error creating PBCH object\n");
exit(-1); exit(-1);
} }
@ -180,14 +186,14 @@ void base_free() {
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
int nf, ns, N_id_2; int nf, sf_idx, N_id_2;
cf_t pss_signal[PSS_LEN]; cf_t pss_signal[PSS_LEN];
float sss_signal0[SSS_LEN]; // for subframe 0 float sss_signal0[SSS_LEN]; // for subframe 0
float sss_signal5[SSS_LEN]; // for subframe 5 float sss_signal5[SSS_LEN]; // for subframe 5
pbch_mib_t mib; pbch_mib_t mib;
refsignal_t refs[NSLOTS_X_FRAME]; refsignal_t refs[NSLOTS_X_FRAME];
int i; int i, n;
cf_t *slot1_symbols[MAX_PORTS]; cf_t *sf_symbols[MAX_PORTS];
#ifdef DISABLE_UHD #ifdef DISABLE_UHD
@ -199,20 +205,20 @@ int main(int argc, char **argv) {
parse_args(argc,argv); parse_args(argc,argv);
N_id_2 = cell_id%3; N_id_2 = cell.id%3;
slot_n_re = CPNORM_NSYMB * nof_prb * RE_X_RB; sf_n_re = 2 * CPNORM_NSYMB * cell.nof_prb * RE_X_RB;
slot_n_samples = SLOT_LEN_CPNORM(lte_symbol_sz(nof_prb)); sf_n_samples = 2 * SLOT_LEN_CPNORM(lte_symbol_sz(cell.nof_prb));
/* this *must* be called after setting slot_len_* */ /* this *must* be called after setting slot_len_* */
base_init(); base_init();
/* Generate PSS/SSS signals */ /* Generate PSS/SSS signals */
pss_generate(pss_signal, N_id_2); pss_generate(pss_signal, N_id_2);
sss_generate(sss_signal0, sss_signal5, cell_id); sss_generate(sss_signal0, sss_signal5, cell.id);
/* Generate CRS signals */ /* Generate CRS signals */
lte_cell_t cell; lte_cell_t cell;
cell.id = cell_id; cell.id = cell.id;
cell.nof_prb = 6; cell.nof_prb = 6;
cell.cp = CPNORM; cell.cp = CPNORM;
cell.nof_ports = 1; cell.nof_ports = 1;
@ -224,14 +230,14 @@ int main(int argc, char **argv) {
} }
} }
mib.nof_ports = 1; mib.nof_ports = cell.nof_ports;
mib.nof_prb = 6; mib.nof_prb = cell.nof_prb;
mib.phich_length = PHICH_NORM; mib.phich_length = PHICH_NORM;
mib.phich_resources = R_1; mib.phich_resources = R_1;
mib.sfn = 0; mib.sfn = 0;
for (i=0;i<MAX_PORTS;i++) { // now there's only 1 port for (i=0;i<MAX_PORTS;i++) { // now there's only 1 port
slot1_symbols[i] = sf_buffer; sf_symbols[i] = sf_buffer;
} }
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
@ -245,35 +251,33 @@ int main(int argc, char **argv) {
nf = 0; nf = 0;
while(nf<nof_frames || nof_frames == -1) { while(nf<nof_frames || nof_frames == -1) {
for (ns=0;ns<NSLOTS_X_FRAME;ns++) { for (sf_idx=0;sf_idx<NSUBFRAMES_X_FRAME;sf_idx++) {
bzero(sf_buffer, sizeof(cf_t) * slot_n_re); bzero(sf_buffer, sizeof(cf_t) * sf_n_re);
switch(ns) {
case 0: // tx pss/sss
case 10: // tx pss/sss
pss_put_slot(pss_signal, sf_buffer, nof_prb, CPNORM);
sss_put_slot(ns?sss_signal5:sss_signal0, sf_buffer, nof_prb, CPNORM);
break;
case 1: // tx pbch
pbch_encode(&pbch, &mib, slot1_symbols, 1);
break;
default: // transmit zeros
break;
}
refsignal_put(&refs[ns], sf_buffer); if (sf_idx == 0 || sf_idx == 5) {
pss_put_slot(pss_signal, sf_buffer, cell.nof_prb, CPNORM);
sss_put_slot(sf_idx?sss_signal5:sss_signal0, sf_buffer, cell.nof_prb, CPNORM);
}
if (sf_idx == 0) {
pbch_encode(&pbch, &mib, sf_symbols);
}
for (n=0;n<2;n++) {
refsignal_put(&refs[2*sf_idx+n], &sf_buffer[n*sf_n_re/2]);
}
/* Transform to OFDM symbols */ /* Transform to OFDM symbols */
lte_ifft_run_slot(&ifft, sf_buffer, output_buffer); lte_ifft_run_sf(&ifft, sf_buffer, output_buffer);
/* send to file or usrp */ /* send to file or usrp */
if (output_file_name) { if (output_file_name) {
filesink_write(&fsink, output_buffer, slot_n_samples); filesink_write(&fsink, output_buffer, sf_n_samples);
usleep(5000); usleep(5000);
} else { } else {
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
vec_sc_prod_cfc(output_buffer, uhd_amp, output_buffer, slot_n_samples); vec_sc_prod_cfc(output_buffer, uhd_amp, output_buffer, sf_n_samples);
cuhd_send(uhd, output_buffer, slot_n_samples, 1); cuhd_send(uhd, output_buffer, sf_n_samples, 1);
#endif #endif
} }
} }

@ -57,7 +57,7 @@ plot_scatter_t pscatrecv, pscatequal;
#define NOF_PORTS 2 #define NOF_PORTS 2
float find_threshold = 20.0; float find_threshold = 9.0;
int max_track_lost = 20, nof_frames = -1; int max_track_lost = 20, nof_frames = -1;
int track_len = 300; int track_len = 300;
char *input_file_name = NULL; char *input_file_name = NULL;
@ -81,7 +81,7 @@ enum sync_state {
}; };
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s [iagfndvp]\n", prog); printf("Usage: %s [iagfndvt]\n", prog);
printf("\t-i input_file [Default use USRP]\n"); printf("\t-i input_file [Default use USRP]\n");
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
printf("\t-a UHD args [Default %s]\n", uhd_args); printf("\t-a UHD args [Default %s]\n", uhd_args);
@ -90,8 +90,9 @@ void usage(char *prog) {
#else #else
printf("\t UHD is disabled. CUHD library not available\n"); printf("\t UHD is disabled. CUHD library not available\n");
#endif #endif
printf("\t-n nof_frames [Default %d]\n", nof_frames); printf("\t-n nof_frames [Default %d]\n", nof_frames);
printf("\t-p PSS threshold [Default %f]\n", find_threshold); printf("\t-t PSS threshold [Default %f]\n", find_threshold);
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
printf("\t-d disable plots [Default enabled]\n"); printf("\t-d disable plots [Default enabled]\n");
#else #else
@ -102,7 +103,7 @@ void usage(char *prog) {
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "iagfndvp")) != -1) { while ((opt = getopt(argc, argv, "iagfndvt")) != -1) {
switch (opt) { switch (opt) {
case 'i': case 'i':
input_file_name = argv[optind]; input_file_name = argv[optind];
@ -116,7 +117,7 @@ void parse_args(int argc, char **argv) {
case 'f': case 'f':
uhd_freq = atof(argv[optind]); uhd_freq = atof(argv[optind]);
break; break;
case 'p': case 't':
find_threshold = atof(argv[optind]); find_threshold = atof(argv[optind]);
break; break;
case 'n': case 'n':
@ -274,11 +275,11 @@ int mib_decoder_init(int cell_id) {
return -1; return -1;
} }
if (pbch_init(&pbch, 6, cell_id, CPNORM)) { if (pbch_init(&pbch, cell)) {
fprintf(stderr, "Error initiating PBCH\n"); fprintf(stderr, "Error initiating PBCH\n");
return -1; return -1;
} }
DEBUG("PBCH initiated cell_id=%d\n", cell_id); DEBUG("PBCH initiated cell_id=%d\n", cell.id);
return 0; return 0;
} }

@ -39,12 +39,18 @@ void *uhd;
#endif #endif
char *output_file_name = NULL; char *output_file_name = NULL;
int nof_frames = -1;
int cell_id = 1; lte_cell_t cell = {
int nof_prb = 6; 6, // nof_prb
char *uhd_args = ""; 1, // nof_ports
1, // cell_id
CPNORM // cyclic prefix
};
uint8_t cfi=1; uint8_t cfi=1;
int nof_frames = -1;
char *uhd_args = "";
float uhd_amp = 0.25, uhd_gain = 10.0, uhd_freq = 2400000000; float uhd_amp = 0.25, uhd_gain = 10.0, uhd_freq = 2400000000;
filesink_t fsink; filesink_t fsink;
@ -70,8 +76,8 @@ void usage(char *prog) {
#endif #endif
printf("\t-o output_file [Default USRP]\n"); printf("\t-o output_file [Default USRP]\n");
printf("\t-n number of frames [Default %d]\n", nof_frames); printf("\t-n number of frames [Default %d]\n", nof_frames);
printf("\t-c cell id [Default %d]\n", cell_id); printf("\t-c cell id [Default %d]\n", cell.id);
printf("\t-p nof_prb [Default %d]\n", nof_prb); printf("\t-p nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-v [set verbose to debug, default none]\n"); printf("\t-v [set verbose to debug, default none]\n");
} }
@ -98,10 +104,10 @@ void parse_args(int argc, char **argv) {
nof_frames = atoi(argv[optind]); nof_frames = atoi(argv[optind]);
break; break;
case 'p': case 'p':
nof_prb = atoi(argv[optind]); cell.nof_prb = atoi(argv[optind]);
break; break;
case 'c': case 'c':
cell_id = atoi(argv[optind]); cell.id = atoi(argv[optind]);
break; break;
case 'v': case 'v':
verbose++; verbose++;
@ -120,12 +126,6 @@ void parse_args(int argc, char **argv) {
} }
void base_init() { void base_init() {
lte_cell_t cell;
cell.id = cell_id;
cell.nof_ports = 1;
cell.nof_prb = nof_prb;
cell.cp = CPNORM;
/* init memory */ /* init memory */
sf_buffer = malloc(sizeof(cf_t) * sf_n_re); sf_buffer = malloc(sizeof(cf_t) * sf_n_re);
@ -158,11 +158,11 @@ void base_init() {
} }
/* create ifft object */ /* create ifft object */
if (lte_ifft_init(&ifft, CPNORM, nof_prb)) { if (lte_ifft_init(&ifft, CPNORM, cell.nof_prb)) {
fprintf(stderr, "Error creating iFFT object\n"); fprintf(stderr, "Error creating iFFT object\n");
exit(-1); exit(-1);
} }
if (pbch_init(&pbch, nof_prb, cell_id, CPNORM)) { if (pbch_init(&pbch, cell)) {
fprintf(stderr, "Error creating PBCH object\n"); fprintf(stderr, "Error creating PBCH object\n");
exit(-1); exit(-1);
} }
@ -229,7 +229,6 @@ int main(int argc, char **argv) {
int i, n; int i, n;
char *data; char *data;
cf_t *sf_symbols[MAX_PORTS]; cf_t *sf_symbols[MAX_PORTS];
cf_t *slot1_symbols[MAX_PORTS];
dci_t dci_tx; dci_t dci_tx;
#ifdef DISABLE_UHD #ifdef DISABLE_UHD
@ -241,24 +240,17 @@ int main(int argc, char **argv) {
parse_args(argc, argv); parse_args(argc, argv);
N_id_2 = cell_id % 3; N_id_2 = cell.id % 3;
sf_n_re = 2 * CPNORM_NSYMB * nof_prb * RE_X_RB; sf_n_re = 2 * CPNORM_NSYMB * cell.nof_prb * RE_X_RB;
sf_n_samples = 2 * SLOT_LEN_CPNORM(lte_symbol_sz(nof_prb)); sf_n_samples = 2 * SLOT_LEN_CPNORM(lte_symbol_sz(cell.nof_prb));
/* this *must* be called after setting slot_len_* */ /* this *must* be called after setting slot_len_* */
base_init(); base_init();
/* Generate PSS/SSS signals */ /* Generate PSS/SSS signals */
pss_generate(pss_signal, N_id_2); pss_generate(pss_signal, N_id_2);
sss_generate(sss_signal0, sss_signal5, cell_id); sss_generate(sss_signal0, sss_signal5, cell.id);
lte_cell_t cell;
cell.id = cell_id;
cell.nof_ports = 1;
cell.nof_prb = nof_prb;
cell.cp = CPNORM;
/* Generate CRS signals */ /* Generate CRS signals */
for (i = 0; i < NSLOTS_X_FRAME; i++) { for (i = 0; i < NSLOTS_X_FRAME; i++) {
if (refsignal_init_LTEDL(&refs[i], 0, i, cell)) { if (refsignal_init_LTEDL(&refs[i], 0, i, cell)) {
@ -267,21 +259,20 @@ int main(int argc, char **argv) {
} }
} }
mib.nof_ports = 1; mib.nof_ports = cell.nof_ports;
mib.nof_prb = nof_prb; mib.nof_prb = cell.nof_prb;
mib.phich_length = PHICH_NORM; mib.phich_length = PHICH_NORM;
mib.phich_resources = R_1; mib.phich_resources = R_1;
mib.sfn = 0; mib.sfn = 0;
for (i = 0; i < MAX_PORTS; i++) { // now there's only 1 port for (i = 0; i < MAX_PORTS; i++) { // now there's only 1 port
sf_symbols[i] = sf_buffer; sf_symbols[i] = sf_buffer;
slot1_symbols[i] = &sf_buffer[sf_n_re/2];
} }
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
if (!output_file_name) { if (!output_file_name) {
printf("Set TX rate: %.2f MHz\n", printf("Set TX rate: %.2f MHz\n",
cuhd_set_tx_srate(uhd, lte_sampling_freq_hz(nof_prb)) / 1000000); cuhd_set_tx_srate(uhd, lte_sampling_freq_hz(cell.nof_prb)) / 1000000);
printf("Set TX gain: %.1f dB\n", cuhd_set_tx_gain(uhd, uhd_gain)); printf("Set TX gain: %.1f dB\n", cuhd_set_tx_gain(uhd, uhd_gain));
printf("Set TX freq: %.2f MHz\n", printf("Set TX freq: %.2f MHz\n",
cuhd_set_tx_freq(uhd, uhd_freq) / 1000000); cuhd_set_tx_freq(uhd, uhd_freq) / 1000000);
@ -297,16 +288,16 @@ int main(int argc, char **argv) {
ra_dl.alloc_type = alloc_type0; ra_dl.alloc_type = alloc_type0;
ra_dl.type0_alloc.rbg_bitmask = 0xffffffff; ra_dl.type0_alloc.rbg_bitmask = 0xffffffff;
dci_msg_pack_pdsch(&ra_dl, &dci_tx.msg[0], Format1, nof_prb, false); dci_msg_pack_pdsch(&ra_dl, &dci_tx.msg[0], Format1, cell.nof_prb, false);
dci_tx.nof_dcis++; dci_tx.nof_dcis++;
pdcch_init_search_ue(&pdcch, 1234, cfi); pdcch_init_search_ue(&pdcch, 1234, cfi);
ra_prb_get_dl(&prb_alloc, &ra_dl, nof_prb); ra_prb_get_dl(&prb_alloc, &ra_dl, cell.nof_prb);
ra_prb_get_re(&prb_alloc, nof_prb, 1, nof_prb<10?(cfi+1):cfi, CPNORM); ra_prb_get_re_dl(&prb_alloc, cell.nof_prb, 1, cell.nof_prb<10?(cfi+1):cfi, CPNORM);
ra_dl.mcs.tbs = ra_tbs_from_idx(ra_dl.mcs.tbs_idx, nof_prb); ra_dl.mcs.tbs = ra_tbs_from_idx(ra_dl.mcs.tbs_idx, cell.nof_prb);
ra_pdsch_fprint(stdout, &ra_dl, nof_prb); ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb);
data = malloc(sizeof(char) * ra_dl.mcs.tbs); data = malloc(sizeof(char) * ra_dl.mcs.tbs);
if (!data) { if (!data) {
@ -321,13 +312,13 @@ int main(int argc, char **argv) {
bzero(sf_buffer, sizeof(cf_t) * sf_n_re); bzero(sf_buffer, sizeof(cf_t) * sf_n_re);
if (sf_idx == 0 || sf_idx == 5) { if (sf_idx == 0 || sf_idx == 5) {
pss_put_slot(pss_signal, sf_buffer, nof_prb, CPNORM); pss_put_slot(pss_signal, sf_buffer, cell.nof_prb, CPNORM);
sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_buffer, nof_prb, sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_buffer, cell.nof_prb,
CPNORM); CPNORM);
} }
if (sf_idx == 0) { if (sf_idx == 0) {
pbch_encode(&pbch, &mib, slot1_symbols, 1); pbch_encode(&pbch, &mib, sf_symbols);
} }
for (n=0;n<2;n++) { for (n=0;n<2;n++) {

@ -55,7 +55,7 @@ plot_scatter_t pscatrecv, pscatequal;
#define NOF_PORTS 2 #define NOF_PORTS 2
float find_threshold = 10.0; float find_threshold = 9.0;
int nof_frames = -1; int nof_frames = -1;
int pdsch_errors = 0, pdsch_total = 0; int pdsch_errors = 0, pdsch_total = 0;
int frame_cnt; int frame_cnt;
@ -362,7 +362,7 @@ int cell_id_init(int nof_prb, int cell_id) {
cell.id = cell_id; cell.id = cell_id;
cell.nof_prb = 6; cell.nof_prb = 6;
cell.nof_ports = MAX_PORTS; cell.nof_ports = 2;
cell.cp = CPNORM; cell.cp = CPNORM;
if (chest_ref_LTEDL(&chest, cell)) { if (chest_ref_LTEDL(&chest, cell)) {
@ -370,7 +370,7 @@ int cell_id_init(int nof_prb, int cell_id) {
return -1; return -1;
} }
if (pbch_init(&pbch, nof_prb, cell_id, CPNORM)) { if (pbch_init(&pbch, cell)) {
fprintf(stderr, "Error initiating PBCH\n"); fprintf(stderr, "Error initiating PBCH\n");
return -1; return -1;
} }
@ -447,7 +447,7 @@ int rx_run(cf_t *input, int sf_idx) {
fprintf(stderr, "Error computing resource allocation\n"); fprintf(stderr, "Error computing resource allocation\n");
break; break;
} }
ra_prb_get_re(&prb_alloc, cell.nof_prb, cell.nof_ports, ra_prb_get_re_dl(&prb_alloc, cell.nof_prb, cell.nof_ports,
cell.nof_prb<10?(cfi+1):cfi, CPNORM); cell.nof_prb<10?(cfi+1):cfi, CPNORM);
if (pdsch_decode(&pdsch, fft_buffer, ce, data, sf_idx, ra_dl.mcs, &prb_alloc)) { if (pdsch_decode(&pdsch, fft_buffer, ce, data, sf_idx, ra_dl.mcs, &prb_alloc)) {
@ -482,19 +482,13 @@ int rx_run(cf_t *input, int sf_idx) {
} }
int mib_decoder_run(cf_t *input, pbch_mib_t *mib) { int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
int i, n; lte_fft_run_sf(&fft, input, fft_buffer);
lte_fft_run_slot(&fft, input, fft_buffer);
/* Get channel estimates for each port */ /* Get channel estimates for each port */
for (i = 0; i < NOF_PORTS; i++) { chest_ce_sf(&chest, fft_buffer, ce, 0);
chest_ce_slot_port(&chest, fft_buffer, ce[i], 1, i);
}
DEBUG("Decoding PBCH\n", 0); DEBUG("Decoding PBCH\n", 0);
n = pbch_decode(&pbch, fft_buffer, ce, mib); return pbch_decode(&pbch, fft_buffer, ce, mib);
return n;
} }
int run_receiver(cf_t *input, int cell_id, int sf_idx) { int run_receiver(cf_t *input, int cell_id, int sf_idx) {
@ -506,7 +500,7 @@ int run_receiver(cf_t *input, int cell_id, int sf_idx) {
if (!cell.nof_prb) { if (!cell.nof_prb) {
if (!sf_idx) { if (!sf_idx) {
if (mib_decoder_run(&input[sf_n_samples/2], &mib)) { if (mib_decoder_run(input, &mib)) {
INFO("MIB decoded!\n", 0); INFO("MIB decoded!\n", 0);
cell.id = cell_id; cell.id = cell_id;
cell.cp = CPNORM; cell.cp = CPNORM;

@ -314,7 +314,7 @@ int mib_decoder_init(int cell_id) {
lte_cell_t cell; lte_cell_t cell;
cell.id = cell_id; cell.id = cell_id;
cell.nof_prb = 6; cell.nof_prb = 6;
cell.nof_ports = MAX_PORTS; cell.nof_ports = 2;
cell.cp = CPNORM; cell.cp = CPNORM;
if (chest_ref_LTEDL(&chest, cell)) { if (chest_ref_LTEDL(&chest, cell)) {
@ -322,7 +322,7 @@ int mib_decoder_init(int cell_id) {
return -1; return -1;
} }
if (pbch_init(&pbch, 6, cell_id, CPNORM)) { if (pbch_init(&pbch, cell)) {
fprintf(stderr, "Error initiating PBCH\n"); fprintf(stderr, "Error initiating PBCH\n");
return -1; return -1;
} }

@ -30,6 +30,7 @@
#define CRC_ #define CRC_
#include "liblte/config.h" #include "liblte/config.h"
#include <stdint.h>
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
unsigned long table[256]; unsigned long table[256];
@ -45,6 +46,6 @@ typedef struct LIBLTE_API {
LIBLTE_API int crc_init(crc_t *h, unsigned int crc_poly, int crc_order); LIBLTE_API int crc_init(crc_t *h, unsigned int crc_poly, int crc_order);
LIBLTE_API int crc_set_init(crc_t *h, unsigned long crc_init_value); LIBLTE_API int crc_set_init(crc_t *h, unsigned long crc_init_value);
LIBLTE_API void crc_attach(crc_t *h, char *data, int len); LIBLTE_API void crc_attach(crc_t *h, char *data, int len);
LIBLTE_API unsigned int crc_checksum(crc_t *h, char *data, int len); LIBLTE_API uint32_t crc_checksum(crc_t *h, char *data, int len);
#endif #endif

@ -47,19 +47,18 @@
typedef _Complex float cf_t; typedef _Complex float cf_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int nof_ports; uint8_t nof_ports;
int nof_prb; uint8_t nof_prb;
int sfn; uint32_t sfn;
phich_length_t phich_length; phich_length_t phich_length;
phich_resources_t phich_resources; phich_resources_t phich_resources;
}pbch_mib_t; }pbch_mib_t;
/* PBCH object */ /* PBCH object */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int cell_id; lte_cell_t cell;
lte_cp_t cp;
int nof_prb; uint8_t nof_symbols;
int nof_symbols;
/* buffers */ /* buffers */
cf_t *ce[MAX_PORTS]; cf_t *ce[MAX_PORTS];
@ -73,7 +72,7 @@ typedef struct LIBLTE_API {
char *data; char *data;
char *data_enc; char *data_enc;
int frame_idx; uint8_t frame_idx;
/* tx & rx objects */ /* tx & rx objects */
modem_table_t mod; modem_table_t mod;
@ -83,23 +82,20 @@ typedef struct LIBLTE_API {
crc_t crc; crc_t crc;
convcoder_t encoder; convcoder_t encoder;
}pbch_t; } pbch_t;
LIBLTE_API int pbch_init(pbch_t *q, LIBLTE_API int pbch_init(pbch_t *q,
int nof_prb, lte_cell_t cell);
int cell_id,
lte_cp_t cp);
LIBLTE_API void pbch_free(pbch_t *q); LIBLTE_API void pbch_free(pbch_t *q);
LIBLTE_API int pbch_decode(pbch_t *q, LIBLTE_API int pbch_decode(pbch_t *q,
cf_t *slot1_symbols, cf_t *sf_symbols,
cf_t *ce[MAX_PORTS], cf_t *ce[MAX_PORTS],
pbch_mib_t *mib); pbch_mib_t *mib);
LIBLTE_API void pbch_encode(pbch_t *q, LIBLTE_API int pbch_encode(pbch_t *q,
pbch_mib_t *mib, pbch_mib_t *mib,
cf_t *slot1_symbols[MAX_PORTS], cf_t *sf_symbols[MAX_PORTS]);
int nof_ports);
LIBLTE_API void pbch_decode_reset(pbch_t *q); LIBLTE_API void pbch_decode_reset(pbch_t *q);

@ -46,7 +46,7 @@ typedef struct LIBLTE_API {
// otherwise mod + tbs values are used to generate the mcs_idx automatically. // otherwise mod + tbs values are used to generate the mcs_idx automatically.
uint8_t tbs_idx; uint8_t tbs_idx;
uint8_t mcs_idx; uint8_t mcs_idx;
int tbs;// If tbs<=0, the tbs_idx value is taken by the packing functions to generate the DCI uint32_t tbs;// If tbs<=0, the tbs_idx value is taken by the packing functions to generate the DCI
// message. Otherwise the tbs_idx corresponding to the lower nearest TBS is taken. // message. Otherwise the tbs_idx corresponding to the lower nearest TBS is taken.
} ra_mcs_t; } ra_mcs_t;
@ -64,9 +64,9 @@ typedef struct LIBLTE_API {
} ra_type1_t; } ra_type1_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
uint32_t riv; // if L_crb==0, DCI message packer will take this value directly uint16_t riv; // if L_crb==0, DCI message packer will take this value directly
uint16_t L_crb; uint8_t L_crb;
uint16_t RB_start; uint8_t RB_start;
enum { enum {
nprb1a_2 = 0, nprb1a_3 = 1 nprb1a_2 = 0, nprb1a_3 = 1
} n_prb1a; } n_prb1a;
@ -79,7 +79,7 @@ typedef struct LIBLTE_API {
} ra_type2_t; } ra_type2_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
unsigned short rnti; uint16_t rnti;
ra_type_t alloc_type; ra_type_t alloc_type;
union { union {
ra_type0_t type0_alloc; ra_type0_t type0_alloc;
@ -88,7 +88,8 @@ typedef struct LIBLTE_API {
}; };
ra_mcs_t mcs; ra_mcs_t mcs;
uint8_t harq_process; uint8_t harq_process;
uint8_t rv_idx;bool ndi; uint8_t rv_idx;
bool ndi;
} ra_pdsch_t; } ra_pdsch_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
@ -107,60 +108,108 @@ typedef struct LIBLTE_API {
ra_mcs_t mcs; ra_mcs_t mcs;
uint8_t rv_idx; // If set to non-zero, a retransmission is requested with the same modulation uint8_t rv_idx; // If set to non-zero, a retransmission is requested with the same modulation
// than before (Format0 message, see also 8.6.1 in 36.2313). // than before (Format0 message, see also 8.6.1 in 36.2313).
bool ndi;bool cqi_request; bool ndi;
bool cqi_request;
} ra_pusch_t; } ra_pusch_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
uint8_t prb_idx[110]; uint8_t prb_idx[MAX_PRB];
int nof_prb; uint8_t nof_prb;
} ra_prb_slot_t; } ra_prb_slot_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
ra_prb_slot_t slot[2]; ra_prb_slot_t slot[2];
int lstart; uint8_t lstart;
int re_sf[NSUBFRAMES_X_FRAME]; uint16_t re_sf[NSUBFRAMES_X_FRAME];
} ra_prb_t; } ra_prb_t;
LIBLTE_API void ra_prb_fprint(FILE *f, ra_prb_slot_t *prb); LIBLTE_API void ra_prb_fprint(FILE *f,
ra_prb_slot_t *prb);
LIBLTE_API int ra_prb_get_dl(ra_prb_t *prb, ra_pdsch_t *ra, int nof_prb); LIBLTE_API int ra_prb_get_dl(ra_prb_t *prb,
LIBLTE_API int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, int nof_prb); ra_pdsch_t *ra,
LIBLTE_API void ra_prb_get_re(ra_prb_t *prb_dist, int nof_prb, int nof_ports, uint8_t nof_prb);
int nof_ctrl_symbols, lte_cp_t cp);
LIBLTE_API int ra_nprb_dl(ra_pdsch_t *ra, int nof_prb); LIBLTE_API int ra_prb_get_ul(ra_prb_slot_t *prb,
LIBLTE_API int ra_nprb_ul(ra_pusch_t *ra, int nof_prb); ra_pusch_t *ra,
LIBLTE_API int ra_re_x_prb(int nsubframe, int nslot, int prb_idx, int nof_prb, uint8_t nof_prb);
int nof_ports, int nof_ctrl_symbols, lte_cp_t cp);
LIBLTE_API void ra_prb_get_re_dl(ra_prb_t *prb_dist,
uint8_t nof_prb,
uint8_t nof_ports,
uint8_t nof_ctrl_symbols,
lte_cp_t cp);
LIBLTE_API uint16_t ra_nprb_dl(ra_pdsch_t *ra,
uint8_t nof_prb);
LIBLTE_API uint16_t ra_nprb_ul(ra_pusch_t *ra,
uint8_t nof_prb);
LIBLTE_API uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs); LIBLTE_API uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs);
LIBLTE_API int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs);
LIBLTE_API int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs); LIBLTE_API int ra_mcs_from_idx_dl(uint8_t idx,
ra_mcs_t *mcs);
LIBLTE_API int ra_mcs_from_idx_ul(uint8_t idx,
ra_mcs_t *mcs);
LIBLTE_API int ra_tbs_from_idx_format1c(uint8_t tbs_idx); LIBLTE_API int ra_tbs_from_idx_format1c(uint8_t tbs_idx);
LIBLTE_API int ra_tbs_to_table_idx_format1c(int tbs);
LIBLTE_API int ra_tbs_from_idx(uint8_t tbs_idx, int n_prb); LIBLTE_API int ra_tbs_to_table_idx_format1c(uint32_t tbs);
LIBLTE_API int ra_tbs_to_table_idx(int tbs, int n_prb);
LIBLTE_API int ra_tbs_from_idx(uint8_t tbs_idx,
uint8_t n_prb);
LIBLTE_API int ra_tbs_to_table_idx(uint32_t tbs,
uint8_t n_prb);
LIBLTE_API uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs); LIBLTE_API uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs);
LIBLTE_API int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs);
LIBLTE_API int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs); LIBLTE_API int ra_mcs_from_idx_dl(uint8_t idx,
ra_mcs_t *mcs);
LIBLTE_API int ra_mcs_from_idx_ul(uint8_t idx,
ra_mcs_t *mcs);
LIBLTE_API char *ra_mod_string(ra_mod_t mod); LIBLTE_API char *ra_mod_string(ra_mod_t mod);
LIBLTE_API int ra_type0_P(int nof_prb); LIBLTE_API uint8_t ra_type0_P(uint8_t nof_prb);
LIBLTE_API uint16_t ra_type2_to_riv(uint8_t L_crb,
uint8_t RB_start,
uint8_t nof_prb);
LIBLTE_API void ra_type2_from_riv(uint16_t riv,
uint8_t *L_crb,
uint8_t *RB_start,
uint8_t nof_prb,
uint8_t nof_vrb);
LIBLTE_API uint8_t ra_type2_n_vrb_dl(uint8_t nof_prb,
bool ngap_is_1);
LIBLTE_API uint8_t ra_type2_n_rb_step(uint8_t nof_prb);
LIBLTE_API uint8_t ra_type2_ngap(uint8_t nof_prb,
bool ngap_is_1);
LIBLTE_API uint8_t ra_type1_N_rb(uint8_t nof_prb);
LIBLTE_API void ra_pdsch_set_mcs_index(ra_pdsch_t *ra,
uint8_t mcs_idx);
LIBLTE_API void ra_pdsch_set_mcs(ra_pdsch_t *ra,
ra_mod_t mod,
uint8_t tbs_idx);
LIBLTE_API uint32_t ra_type2_to_riv(uint16_t L_crb, uint16_t RB_start, int nof_prb); LIBLTE_API void ra_pdsch_fprint(FILE *f,
LIBLTE_API void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start, ra_pdsch_t *ra,
int nof_prb, int nof_vrb); uint8_t nof_prb);
LIBLTE_API int ra_type2_n_vrb_dl(int nof_prb, bool ngap_is_1);
LIBLTE_API int ra_type2_n_rb_step(int nof_prb);
LIBLTE_API int ra_type2_ngap(int nof_prb, bool ngap_is_1);
LIBLTE_API int ra_type1_N_rb(int nof_prb);
LIBLTE_API void ra_pdsch_set_mcs_index(ra_pdsch_t *ra, uint8_t mcs_idx); LIBLTE_API void ra_pusch_fprint(FILE *f,
LIBLTE_API void ra_pdsch_set_mcs(ra_pdsch_t *ra, ra_mod_t mod, uint8_t tbs_idx); ra_pusch_t *ra,
LIBLTE_API void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb); uint8_t nof_prb);
LIBLTE_API void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, int nof_prb);
#endif /* RB_ALLOC_H_ */ #endif /* RB_ALLOC_H_ */

@ -38,7 +38,7 @@ LIBLTE_API uint32_t bit_unpack(char **bits, int nof_bits);
LIBLTE_API void bit_pack(uint32_t value, char **bits, int nof_bits); LIBLTE_API void bit_pack(uint32_t value, char **bits, int nof_bits);
LIBLTE_API void bit_fprint(FILE *stream, char *bits, int nof_bits); LIBLTE_API void bit_fprint(FILE *stream, char *bits, int nof_bits);
LIBLTE_API unsigned int bit_diff(char *x, char *y, int nbits); LIBLTE_API unsigned int bit_diff(char *x, char *y, int nbits);
LIBLTE_API int bit_count(unsigned int n); LIBLTE_API uint8_t bit_count(uint32_t n);
#endif // BIT_ #endif // BIT_

@ -53,11 +53,11 @@ const int tc_cb_sizes[NOF_TC_CB_SIZES] = { 40, 48, 56, 64, 72, 80, 88, 96, 104,
/* Returns true if the structure pointed by cell has valid parameters /* Returns true if the structure pointed by cell has valid parameters
*/ */
bool lte_cell_isvalid(lte_cell_t *cell) { bool lte_cell_isvalid(lte_cell_t *cell) {
if (cell->id < 504 && if (cell->id < 504 &&
cell->nof_ports > 0 && cell->nof_ports > 0 &&
cell->nof_ports < 5 && cell->nof_ports < MAX_PORTS+1 &&
cell->nof_prb > 5 && cell->nof_prb > 5 &&
cell->nof_prb < 111 cell->nof_prb < MAX_PRB+1
) { ) {
return true; return true;
} else { } else {

@ -114,7 +114,7 @@ int crc_init(crc_t *h, unsigned int crc_poly, int crc_order) {
return 0; return 0;
} }
unsigned int crc_checksum(crc_t *h, char *data, int len) { uint32_t crc_checksum(crc_t *h, char *data, int len) {
int i, k, len8, res8, a = 0; int i, k, len8, res8, a = 0;
unsigned int crc = 0; unsigned int crc = 0;
char *pter; char *pter;

@ -83,7 +83,7 @@ uint8_t riv_nbits(uint8_t nof_prb) {
return (uint8_t) ceilf(log2f((float) nof_prb * ((float) nof_prb + 1) / 2)); return (uint8_t) ceilf(log2f((float) nof_prb * ((float) nof_prb + 1) / 2));
} }
const int ambiguous_sizes[10] = { 12, 14, 16, 20, 24, 26, 32, 40, 44, 56 }; const uint8_t ambiguous_sizes[10] = { 12, 14, 16, 20, 24, 26, 32, 40, 44, 56 };
bool is_ambiguous_size(uint8_t size) { bool is_ambiguous_size(uint8_t size) {
int i; int i;
@ -115,7 +115,7 @@ uint8_t dci_format1A_sizeof(uint8_t nof_prb) {
} }
uint8_t dci_format0_sizeof(uint8_t nof_prb) { uint8_t dci_format0_sizeof(uint8_t nof_prb) {
int n = dci_format0_sizeof_(nof_prb); uint8_t n = dci_format0_sizeof_(nof_prb);
while (n < dci_format1A_sizeof(nof_prb)) { while (n < dci_format1A_sizeof(nof_prb)) {
n++; n++;
} }
@ -137,9 +137,9 @@ uint8_t dci_format1_sizeof(uint8_t nof_prb) {
} }
uint8_t dci_format1C_sizeof(uint8_t nof_prb) { uint8_t dci_format1C_sizeof(uint8_t nof_prb) {
int n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true); uint8_t n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true);
int n_step = ra_type2_n_rb_step(nof_prb); uint8_t n_step = ra_type2_n_rb_step(nof_prb);
uint8_t n = +riv_nbits((uint8_t) n_vrb_dl_gap1 / n_step) + 5; uint8_t n = riv_nbits((uint8_t) n_vrb_dl_gap1 / n_step) + 5;
if (nof_prb >= 50) { if (nof_prb >= 50) {
n++; n++;
} }
@ -174,7 +174,7 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint8_t nof_prb) {
/* pack bits */ /* pack bits */
char *y = msg->data; char *y = msg->data;
int n_ul_hop; uint8_t n_ul_hop;
*y++ = 0; // format differentiation *y++ = 0; // format differentiation
if (data->freq_hop_fl == hop_disabled) { // frequency hopping if (data->freq_hop_fl == hop_disabled) { // frequency hopping
@ -193,17 +193,17 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint8_t nof_prb) {
} }
/* pack RIV according to 8.1 of 36.213 */ /* pack RIV according to 8.1 of 36.213 */
uint32_t riv; uint16_t riv;
if (data->type2_alloc.L_crb) { if (data->type2_alloc.L_crb) {
riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start, riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start,
nof_prb); nof_prb);
} else { } else {
riv = data->type2_alloc.riv; riv = data->type2_alloc.riv;
} }
bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop); bit_pack((uint32_t) riv, &y, riv_nbits(nof_prb) - n_ul_hop);
/* pack MCS according to 8.6.1 of 36.213 */ /* pack MCS according to 8.6.1 of 36.213 */
uint32_t mcs; uint8_t mcs;
if (data->cqi_request) { if (data->cqi_request) {
mcs = 29; mcs = 29;
} else { } else {
@ -224,7 +224,7 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint8_t nof_prb) {
} }
} }
bit_pack(mcs, &y, 5); bit_pack((uint32_t) mcs, &y, 5);
*y++ = data->ndi; *y++ = data->ndi;
@ -241,7 +241,7 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint8_t nof_prb) {
*y++ = data->cqi_request; *y++ = data->cqi_request;
// Padding with zeros // Padding with zeros
int n = dci_format0_sizeof(nof_prb); uint8_t n = dci_format0_sizeof(nof_prb);
while (y - msg->data < n) { while (y - msg->data < n) {
*y++ = 0; *y++ = 0;
} }
@ -257,7 +257,7 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, uint8_t nof_prb) {
/* pack bits */ /* pack bits */
char *y = msg->data; char *y = msg->data;
int n_ul_hop; uint8_t n_ul_hop;
/* Make sure it's a Format0 message */ /* Make sure it's a Format0 message */
if (msg->location.nof_bits != dci_format_sizeof(Format0, nof_prb)) { if (msg->location.nof_bits != dci_format_sizeof(Format0, nof_prb)) {
@ -283,14 +283,14 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, uint8_t nof_prb) {
} }
} }
/* unpack RIV according to 8.1 of 36.213 */ /* unpack RIV according to 8.1 of 36.213 */
uint32_t riv = bit_unpack(&y, riv_nbits(nof_prb) - n_ul_hop); uint16_t riv = bit_unpack(&y, riv_nbits(nof_prb) - n_ul_hop);
ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start,
nof_prb, nof_prb); nof_prb, nof_prb);
bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop); bit_pack((uint32_t) riv, &y, riv_nbits(nof_prb) - n_ul_hop);
data->type2_alloc.riv = riv; data->type2_alloc.riv = riv;
/* unpack MCS according to 8.6 of 36.213 */ /* unpack MCS according to 8.6 of 36.213 */
uint32_t mcs = bit_unpack(&y, 5); uint8_t mcs = bit_unpack(&y, 5);
data->ndi = *y++ ? true : false; data->ndi = *y++ ? true : false;
@ -336,16 +336,16 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) {
} }
/* Resource allocation: type0 or type 1 */ /* Resource allocation: type0 or type 1 */
int P = ra_type0_P(nof_prb); uint8_t P = ra_type0_P(nof_prb);
int alloc_size = (int) ceilf((float) nof_prb / P); uint8_t alloc_size = (uint8_t) ceilf((float) nof_prb / P);
switch (data->alloc_type) { switch (data->alloc_type) {
case alloc_type0: case alloc_type0:
bit_pack(data->type0_alloc.rbg_bitmask, &y, alloc_size); bit_pack((uint32_t) data->type0_alloc.rbg_bitmask, &y, alloc_size);
break; break;
case alloc_type1: case alloc_type1:
bit_pack(data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P))); bit_pack((uint32_t) data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P)));
*y++ = data->type1_alloc.shift ? 1 : 0; *y++ = data->type1_alloc.shift ? 1 : 0;
bit_pack(data->type1_alloc.vrb_bitmask, &y, bit_pack((uint32_t) data->type1_alloc.vrb_bitmask, &y,
alloc_size - (int) ceilf(log2f(P)) - 1); alloc_size - (int) ceilf(log2f(P)) - 1);
break; break;
default: default:
@ -355,7 +355,7 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) {
} }
/* pack MCS according to 7.1.7 of 36.213 */ /* pack MCS according to 7.1.7 of 36.213 */
uint32_t mcs; uint8_t mcs;
if (data->mcs.mod == MOD_NULL) { if (data->mcs.mod == MOD_NULL) {
mcs = data->mcs.mcs_idx; mcs = data->mcs.mcs_idx;
} else { } else {
@ -366,22 +366,22 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) {
mcs = ra_mcs_to_table_idx(&data->mcs); mcs = ra_mcs_to_table_idx(&data->mcs);
data->mcs.mcs_idx = mcs; data->mcs.mcs_idx = mcs;
} }
bit_pack(mcs, &y, 5); bit_pack((uint32_t) mcs, &y, 5);
/* harq process number */ /* harq process number */
bit_pack(data->harq_process, &y, 3); bit_pack((uint32_t) data->harq_process, &y, 3);
*y++ = data->ndi; *y++ = data->ndi;
// rv version // rv version
bit_pack(data->rv_idx, &y, 2); bit_pack((uint32_t) data->rv_idx, &y, 2);
// TPC not implemented // TPC not implemented
*y++ = 0; *y++ = 0;
*y++ = 0; *y++ = 0;
// Padding with zeros // Padding with zeros
int n = dci_format1_sizeof(nof_prb); uint8_t n = dci_format1_sizeof(nof_prb);
while (y - msg->data < n) { while (y - msg->data < n) {
*y++ = 0; *y++ = 0;
} }
@ -409,7 +409,7 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) {
/* Resource allocation: type0 or type 1 */ /* Resource allocation: type0 or type 1 */
uint8_t P = ra_type0_P(nof_prb); uint8_t P = ra_type0_P(nof_prb);
int alloc_size = (int) ceilf((float) nof_prb / P); uint8_t alloc_size = (uint8_t) ceilf((float) nof_prb / P);
switch (data->alloc_type) { switch (data->alloc_type) {
case alloc_type0: case alloc_type0:
data->type0_alloc.rbg_bitmask = bit_unpack(&y, alloc_size); data->type0_alloc.rbg_bitmask = bit_unpack(&y, alloc_size);
@ -421,16 +421,24 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) {
alloc_size - (int) ceilf(log2f(P)) - 1); alloc_size - (int) ceilf(log2f(P)) - 1);
break; break;
default: default:
fprintf(stderr, fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n");
"Format 1 accepts type0 or type1 resource allocation only\n");
return LIBLTE_ERROR; return LIBLTE_ERROR;
} }
/* unpack MCS according to 7.1.7 of 36.213 */ /* unpack MCS according to 7.1.7 of 36.213 */
uint32_t mcs = bit_unpack(&y, 5); uint8_t mcs = bit_unpack(&y, 5);
data->mcs.mcs_idx = mcs; data->mcs.mcs_idx = mcs;
ra_mcs_from_idx_dl(mcs, &data->mcs); if (ra_mcs_from_idx_dl(mcs, &data->mcs)) {
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, ra_nprb_dl(data, nof_prb)); fprintf(stderr, "Error getting MCS\n");
return LIBLTE_ERROR;
}
int t = ra_tbs_from_idx(data->mcs.tbs_idx, ra_nprb_dl(data, nof_prb));
if (t < 0) {
fprintf(stderr, "Error getting TBS\n");
return LIBLTE_ERROR;
}
data->mcs.tbs = (uint32_t) t;
/* harq process number */ /* harq process number */
data->harq_process = bit_unpack(&y, 3); data->harq_process = bit_unpack(&y, 3);
@ -471,7 +479,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb,
return LIBLTE_ERROR; return LIBLTE_ERROR;
} }
} else { } else {
int n_vrb_dl; uint8_t n_vrb_dl;
if (crc_is_crnti && nof_prb > 50) { if (crc_is_crnti && nof_prb > 50) {
n_vrb_dl = 16; n_vrb_dl = 16;
} else { } else {
@ -485,28 +493,28 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb,
} }
} }
/* pack RIV according to 7.1.6.3 of 36.213 */ /* pack RIV according to 7.1.6.3 of 36.213 */
uint32_t riv; uint16_t riv;
if (data->type2_alloc.L_crb) { if (data->type2_alloc.L_crb) {
riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start, riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start,
nof_prb); nof_prb);
} else { } else {
riv = data->type2_alloc.riv; riv = data->type2_alloc.riv;
} }
int nb_gap = 0; uint8_t nb_gap = 0;
if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) { if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) {
nb_gap = 1; nb_gap = 1;
*y++ = data->type2_alloc.n_gap; *y++ = data->type2_alloc.n_gap;
} }
bit_pack(riv, &y, riv_nbits(nof_prb) - nb_gap); bit_pack((uint32_t) riv, &y, riv_nbits(nof_prb) - nb_gap);
// in format1A, MCS = TBS according to 7.1.7.2 of 36.213 // in format1A, MCS = TBS according to 7.1.7.2 of 36.213
uint32_t mcs; uint8_t mcs;
if (data->mcs.mod == MOD_NULL) { if (data->mcs.mod == MOD_NULL) {
mcs = data->mcs.mcs_idx; mcs = data->mcs.mcs_idx;
} else { } else {
if (data->mcs.tbs) { if (data->mcs.tbs) {
// In format 1A, n_prb_1a is 2 or 3 if crc is not scrambled with C-RNTI // In format 1A, n_prb_1a is 2 or 3 if crc is not scrambled with C-RNTI
int n_prb; uint8_t n_prb;
if (!crc_is_crnti) { if (!crc_is_crnti) {
n_prb = ra_nprb_dl(data, nof_prb); n_prb = ra_nprb_dl(data, nof_prb);
} else { } else {
@ -516,9 +524,9 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb,
} }
mcs = data->mcs.tbs_idx; mcs = data->mcs.tbs_idx;
} }
bit_pack(mcs, &y, 5); bit_pack((uint32_t) mcs, &y, 5);
bit_pack(data->harq_process, &y, 3); bit_pack((uint32_t) data->harq_process, &y, 3);
if (!crc_is_crnti && nof_prb >= 50 && data->type2_alloc.mode == t2_dist) { if (!crc_is_crnti && nof_prb >= 50 && data->type2_alloc.mode == t2_dist) {
*y++ = data->type2_alloc.n_gap; *y++ = data->type2_alloc.n_gap;
@ -527,7 +535,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb,
} }
// rv version // rv version
bit_pack(data->rv_idx, &y, 2); bit_pack((uint32_t) data->rv_idx, &y, 2);
if (crc_is_crnti) { if (crc_is_crnti) {
// TPC not implemented // TPC not implemented
@ -539,7 +547,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb,
} }
// Padding with zeros // Padding with zeros
int n = dci_format1A_sizeof(nof_prb); uint8_t n = dci_format1A_sizeof(nof_prb);
while (y - msg->data < n) { while (y - msg->data < n) {
*y++ = 0; *y++ = 0;
} }
@ -564,8 +572,7 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb,
} }
if (*y++ != 1) { if (*y++ != 1) {
fprintf(stderr, fprintf(stderr, "Invalid format differentiation field value. This is Format0\n");
"Invalid format differentiation field value. This is Format0\n");
return LIBLTE_ERROR; return LIBLTE_ERROR;
} }
@ -576,18 +583,18 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb,
data->type2_alloc.n_gap = t2_ng1; data->type2_alloc.n_gap = t2_ng1;
/* unpack RIV according to 7.1.6.3 of 36.213 */ /* unpack RIV according to 7.1.6.3 of 36.213 */
int nb_gap = 0; uint8_t nb_gap = 0;
if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) { if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) {
nb_gap = 1; nb_gap = 1;
data->type2_alloc.n_gap = *y++; data->type2_alloc.n_gap = *y++;
} }
int nof_vrb; uint8_t nof_vrb;
if (data->type2_alloc.mode == t2_loc) { if (data->type2_alloc.mode == t2_loc) {
nof_vrb = nof_prb; nof_vrb = nof_prb;
} else { } else {
nof_vrb = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1); nof_vrb = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
} }
uint32_t riv = bit_unpack(&y, riv_nbits(nof_prb) - nb_gap); uint16_t riv = bit_unpack(&y, riv_nbits(nof_prb) - nb_gap);
ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start,
nof_prb, nof_vrb); nof_prb, nof_vrb);
data->type2_alloc.riv = riv; data->type2_alloc.riv = riv;
@ -604,7 +611,7 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb,
} }
// rv version // rv version
bit_pack(data->rv_idx, &y, 2); bit_pack((uint32_t) data->rv_idx, &y, 2);
if (crc_is_crnti) { if (crc_is_crnti) {
// TPC not implemented // TPC not implemented
@ -615,7 +622,8 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb,
data->type2_alloc.n_prb1a = *y++; // LSB indicates N_prb_1a for TBS data->type2_alloc.n_prb1a = *y++; // LSB indicates N_prb_1a for TBS
} }
data->mcs.tbs_idx = data->mcs.mcs_idx; data->mcs.tbs_idx = data->mcs.mcs_idx;
int n_prb;
uint8_t n_prb;
if (crc_is_crnti) { if (crc_is_crnti) {
n_prb = ra_nprb_dl(data, nof_prb); n_prb = ra_nprb_dl(data, nof_prb);
} else { } else {
@ -644,13 +652,12 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) {
if (nof_prb >= 50) { if (nof_prb >= 50) {
*y++ = data->type2_alloc.n_gap; *y++ = data->type2_alloc.n_gap;
} }
int n_step = ra_type2_n_rb_step(nof_prb); uint8_t n_step = ra_type2_n_rb_step(nof_prb);
int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1); uint8_t n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
if (data->type2_alloc.L_crb > ((int) n_vrb_dl / n_step) * n_step) { if (data->type2_alloc.L_crb > ((uint8_t) n_vrb_dl / n_step) * n_step) {
fprintf(stderr, fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n",
"L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", data->type2_alloc.L_crb, ((uint8_t) n_vrb_dl / n_step) * n_step);
data->type2_alloc.L_crb, ((int) n_vrb_dl / n_step) * n_step);
return LIBLTE_ERROR; return LIBLTE_ERROR;
} }
if (data->type2_alloc.L_crb % n_step) { if (data->type2_alloc.L_crb % n_step) {
@ -661,20 +668,20 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) {
fprintf(stderr, "RB_start must be multiple of n_step\n"); fprintf(stderr, "RB_start must be multiple of n_step\n");
return LIBLTE_ERROR; return LIBLTE_ERROR;
} }
int L_p = data->type2_alloc.L_crb / n_step; uint8_t L_p = data->type2_alloc.L_crb / n_step;
int RB_p = data->type2_alloc.RB_start / n_step; uint8_t RB_p = data->type2_alloc.RB_start / n_step;
int n_vrb_p = (int) n_vrb_dl / n_step; uint8_t n_vrb_p = (int) n_vrb_dl / n_step;
uint32_t riv; uint16_t riv;
if (data->type2_alloc.L_crb) { if (data->type2_alloc.L_crb) {
riv = ra_type2_to_riv(L_p, RB_p, n_vrb_p); riv = ra_type2_to_riv(L_p, RB_p, n_vrb_p);
} else { } else {
riv = data->type2_alloc.riv; riv = data->type2_alloc.riv;
} }
bit_pack(riv, &y, riv_nbits((int) n_vrb_dl / n_step)); bit_pack((uint32_t) riv, &y, riv_nbits((int) n_vrb_dl / n_step));
// in format1C, MCS = TBS according to 7.1.7.2 of 36.213 // in format1C, MCS = TBS according to 7.1.7.2 of 36.213
uint32_t mcs; uint8_t mcs;
if (data->mcs.mod == MOD_NULL) { if (data->mcs.mod == MOD_NULL) {
mcs = data->mcs.mcs_idx; mcs = data->mcs.mcs_idx;
} else { } else {
@ -683,7 +690,7 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) {
} }
mcs = data->mcs.tbs_idx; mcs = data->mcs.tbs_idx;
} }
bit_pack(mcs, &y, 5); bit_pack((uint32_t) mcs, &y, 5);
msg->location.nof_bits = (y - msg->data); msg->location.nof_bits = (y - msg->data);
@ -691,7 +698,7 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) {
} }
int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) { int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) {
uint16_t L_p, RB_p; uint8_t L_p, RB_p;
/* pack bits */ /* pack bits */
char *y = msg->data; char *y = msg->data;
@ -705,11 +712,11 @@ int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) {
if (nof_prb >= 50) { if (nof_prb >= 50) {
data->type2_alloc.n_gap = *y++; data->type2_alloc.n_gap = *y++;
} }
int n_step = ra_type2_n_rb_step(nof_prb); uint8_t n_step = ra_type2_n_rb_step(nof_prb);
int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1); uint8_t n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
uint32_t riv = bit_unpack(&y, riv_nbits((int) n_vrb_dl / n_step)); uint16_t riv = bit_unpack(&y, riv_nbits((int) n_vrb_dl / n_step));
int n_vrb_p = (int) n_vrb_dl / n_step; uint8_t n_vrb_p = (uint8_t) n_vrb_dl / n_step;
ra_type2_from_riv(riv, &L_p, &RB_p, n_vrb_p, n_vrb_p); ra_type2_from_riv(riv, &L_p, &RB_p, n_vrb_p, n_vrb_p);
data->type2_alloc.L_crb = L_p * n_step; data->type2_alloc.L_crb = L_p * n_step;
@ -800,7 +807,7 @@ void dci_msg_type_fprint(FILE *f, dci_msg_type_t type) {
} }
int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, uint8_t nof_prb, int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, uint8_t nof_prb,
unsigned short crnti) { uint16_t crnti) {
if (msg->location.nof_bits == dci_format_sizeof(Format0, nof_prb) if (msg->location.nof_bits == dci_format_sizeof(Format0, nof_prb)
&& !msg->data[0]) { && !msg->data[0]) {
type->type = PUSCH_SCHED; type->type = PUSCH_SCHED;

@ -50,47 +50,45 @@ bool pbch_exists(int nframe, int nslot) {
return (!(nframe % 5) && nslot == 1); return (!(nframe % 5) && nslot == 1);
} }
int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id, int pbch_cp(cf_t *input, cf_t *output, lte_cell_t cell, bool put) {
bool put) {
int i; int i;
cf_t *ptr; cf_t *ptr;
assert(cell_id >= 0);
if (put) { if (put) {
ptr = input; ptr = input;
output += nof_prb * RE_X_RB / 2 - 36; output += cell.nof_prb * RE_X_RB / 2 - 36;
} else { } else {
ptr = output; ptr = output;
input += nof_prb * RE_X_RB / 2 - 36; input += cell.nof_prb * RE_X_RB / 2 - 36;
} }
/* symbol 0 & 1 */ /* symbol 0 & 1 */
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
prb_cp_ref(&input, &output, cell_id % 3, 4, 4*6, put); prb_cp_ref(&input, &output, cell.id % 3, 4, 4*6, put);
if (put) { if (put) {
output += nof_prb * RE_X_RB - 2*36; output += cell.nof_prb * RE_X_RB - 2*36;
} else { } else {
input += nof_prb * RE_X_RB - 2*36; input += cell.nof_prb * RE_X_RB - 2*36;
} }
} }
/* symbols 2 & 3 */ /* symbols 2 & 3 */
if (CP_ISNORM(cp)) { if (CP_ISNORM(cell.cp)) {
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
prb_cp(&input, &output, 6); prb_cp(&input, &output, 6);
if (put) { if (put) {
output += nof_prb * RE_X_RB - 2*36; output += cell.nof_prb * RE_X_RB - 2*36;
} else { } else {
input += nof_prb * RE_X_RB - 2*36; input += cell.nof_prb * RE_X_RB - 2*36;
} }
} }
} else { } else {
prb_cp(&input, &output, 6); prb_cp(&input, &output, 6);
if (put) { if (put) {
output += nof_prb * RE_X_RB - 2*36; output += cell.nof_prb * RE_X_RB - 2*36;
} else { } else {
input += nof_prb * RE_X_RB - 2*36; input += cell.nof_prb * RE_X_RB - 2*36;
} }
prb_cp_ref(&input, &output, cell_id % 3, 4, 4*6, put); prb_cp_ref(&input, &output, cell.id % 3, 4, 4*6, put);
} }
if (put) { if (put) {
return input - ptr; return input - ptr;
@ -106,9 +104,8 @@ int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id,
* *
* 36.211 10.3 section 6.6.4 * 36.211 10.3 section 6.6.4
*/ */
int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int pbch_put(cf_t *pbch, cf_t *slot1_data, lte_cell_t cell) {
int cell_id) { return pbch_cp(pbch, slot1_data, cell, true);
return pbch_cp(pbch, slot1_data, nof_prb, cp, cell_id, true);
} }
/** /**
@ -118,92 +115,96 @@ int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp,
* *
* 36.211 10.3 section 6.6.4 * 36.211 10.3 section 6.6.4
*/ */
int pbch_get(cf_t *slot1_data, cf_t *pbch, int nof_prb, lte_cp_t cp, int pbch_get(cf_t *slot1_data, cf_t *pbch, lte_cell_t cell) {
int cell_id) { return pbch_cp(slot1_data, pbch, cell, false);
return pbch_cp(slot1_data, pbch, nof_prb, cp, cell_id, false);
} }
/** Initializes the PBCH transmitter and receiver */ /** Initializes the PBCH transmitter and receiver.
int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp) { * At the receiver, the field nof_ports in the cell structure indicates the
int ret = -1; * maximum number of BS transmitter ports to look for.
if (cell_id < 0) { */
return -1; int pbch_init(pbch_t *q, lte_cell_t cell) {
} int ret = LIBLTE_ERROR_INVALID_INPUTS;
bzero(q, sizeof(pbch_t));
q->cell_id = cell_id;
q->cp = cp;
q->nof_prb = nof_prb;
if (modem_table_std(&q->mod, LTE_QPSK, true)) { if (q != NULL &&
goto clean; lte_cell_isvalid(&cell))
} {
demod_soft_init(&q->demod); ret = LIBLTE_ERROR;
demod_soft_table_set(&q->demod, &q->mod);
demod_soft_alg_set(&q->demod, APPROX);
if (sequence_pbch(&q->seq_pbch, q->cp, q->cell_id)) {
goto clean;
}
int poly[3] = { 0x6D, 0x4F, 0x57 }; bzero(q, sizeof(pbch_t));
if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) { q->cell = cell;
goto clean;
}
if (crc_init(&q->crc, LTE_CRC16, 16)) {
goto clean;
}
q->encoder.K = 7;
q->encoder.R = 3;
q->encoder.tail_biting = true;
memcpy(q->encoder.poly, poly, 3 * sizeof(int));
q->nof_symbols = (CP_ISNORM(q->cp)) ? PBCH_RE_CPNORM : PBCH_RE_CPEXT; if (modem_table_std(&q->mod, LTE_QPSK, true)) {
goto clean;
}
demod_soft_init(&q->demod);
demod_soft_table_set(&q->demod, &q->mod);
demod_soft_alg_set(&q->demod, APPROX);
if (sequence_pbch(&q->seq_pbch, q->cell.cp, q->cell.id)) {
goto clean;
}
q->pbch_d = malloc(sizeof(cf_t) * q->nof_symbols); int poly[3] = { 0x6D, 0x4F, 0x57 };
if (!q->pbch_d) { if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) {
goto clean;
}
int i;
for (i = 0; i < MAX_PORTS; i++) {
q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->ce[i]) {
goto clean; goto clean;
} }
q->pbch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols); if (crc_init(&q->crc, LTE_CRC16, 16)) {
if (!q->pbch_x[i]) {
goto clean; goto clean;
} }
q->pbch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols); q->encoder.K = 7;
if (!q->pbch_symbols[i]) { q->encoder.R = 3;
q->encoder.tail_biting = true;
memcpy(q->encoder.poly, poly, 3 * sizeof(int));
q->nof_symbols = (CP_ISNORM(q->cell.cp)) ? PBCH_RE_CPNORM : PBCH_RE_CPEXT;
q->pbch_d = malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->pbch_d) {
goto clean; goto clean;
} }
int i;
for (i = 0; i < q->cell.nof_ports; i++) {
q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->ce[i]) {
goto clean;
}
q->pbch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->pbch_x[i]) {
goto clean;
}
q->pbch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->pbch_symbols[i]) {
goto clean;
}
}
q->pbch_llr = malloc(sizeof(float) * q->nof_symbols * 4 * 2);
if (!q->pbch_llr) {
goto clean;
}
q->temp = malloc(sizeof(float) * q->nof_symbols * 4 * 2);
if (!q->temp) {
goto clean;
}
q->pbch_rm_f = malloc(sizeof(float) * 120);
if (!q->pbch_rm_f) {
goto clean;
}
q->pbch_rm_b = malloc(sizeof(float) * q->nof_symbols * 4 * 2);
if (!q->pbch_rm_b) {
goto clean;
}
q->data = malloc(sizeof(char) * 40);
if (!q->data) {
goto clean;
}
q->data_enc = malloc(sizeof(char) * 120);
if (!q->data_enc) {
goto clean;
}
ret = LIBLTE_SUCCESS;
} }
q->pbch_llr = malloc(sizeof(float) * q->nof_symbols * 4 * 2); clean:
if (!q->pbch_llr) { if (ret == LIBLTE_ERROR) {
goto clean;
}
q->temp = malloc(sizeof(float) * q->nof_symbols * 4 * 2);
if (!q->temp) {
goto clean;
}
q->pbch_rm_f = malloc(sizeof(float) * 120);
if (!q->pbch_rm_f) {
goto clean;
}
q->pbch_rm_b = malloc(sizeof(float) * q->nof_symbols * 4 * 2);
if (!q->pbch_rm_b) {
goto clean;
}
q->data = malloc(sizeof(char) * 40);
if (!q->data) {
goto clean;
}
q->data_enc = malloc(sizeof(char) * 120);
if (!q->data_enc) {
goto clean;
}
ret = 0;
clean: if (ret == -1) {
pbch_free(q); pbch_free(q);
} }
return ret; return ret;
@ -214,7 +215,7 @@ void pbch_free(pbch_t *q) {
free(q->pbch_d); free(q->pbch_d);
} }
int i; int i;
for (i = 0; i < MAX_PORTS; i++) { for (i = 0; i < q->cell.nof_ports; i++) {
if (q->ce[i]) { if (q->ce[i]) {
free(q->ce[i]); free(q->ce[i]);
} }
@ -371,15 +372,15 @@ void crc_set_mask(char *data, int nof_ports) {
* *
* Returns 0 if the data is correct, -1 otherwise * Returns 0 if the data is correct, -1 otherwise
*/ */
int pbch_crc_check(pbch_t *q, char *bits, int nof_ports) { uint32_t pbch_crc_check(pbch_t *q, char *bits, uint8_t nof_ports) {
char data[40]; char data[40];
memcpy(data, bits, 40 * sizeof(char)); memcpy(data, bits, 40 * sizeof(char));
crc_set_mask(data, nof_ports); crc_set_mask(data, nof_ports);
return crc_checksum(&q->crc, data, 40); return crc_checksum(&q->crc, data, 40);
} }
int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, uint8_t src, uint8_t dst, uint8_t n,
int nof_bits, int nof_ports) { uint16_t nof_bits, uint8_t nof_ports) {
int j; int j;
memcpy(&q->temp[dst * nof_bits], &q->pbch_llr[src * nof_bits], memcpy(&q->temp[dst * nof_bits], &q->pbch_llr[src * nof_bits],
@ -433,149 +434,178 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n,
/* Decodes the PBCH channel /* Decodes the PBCH channel
* *
* The PBCH spans in 40 ms. This function is called every 10 ms. It tries to decode the MIB * The PBCH spans in 40 ms. This function is called every 10 ms. It tries to decode the MIB
* given the symbols of the slot #1 of each radio frame. Successive calls will use more frames * given the symbols of a subframe (1 ms). Successive calls will use more subframes
* to help the decoding process. * to help the decoding process.
* *
* Returns 1 if successfully decoded MIB, 0 if not and -1 on error * Returns 1 if successfully decoded MIB, 0 if not and -1 on error
*/ */
int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mib) { int pbch_decode(pbch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mib) {
int src, dst, res, nb; uint8_t src, dst, nb;
int nant_[3] = { 1, 2, 4 }; uint8_t nant_[3] = { 1, 2, 4 };
int na, nant; uint8_t na, nant;
cf_t *slot1_symbols;
/* Set pointers for layermapping & precoding */
int i; int i;
int nof_bits = 2 * q->nof_symbols; int nof_bits;
cf_t *x[MAX_LAYERS]; cf_t *x[MAX_LAYERS];
cf_t *ce_slot[MAX_PORTS];
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
sf_symbols != NULL &&
mib != NULL)
{
for (i=0;i<q->cell.nof_ports;i++) {
if (ce[i] == NULL) {
return LIBLTE_ERROR_INVALID_INPUTS;
} else {
ce_slot[i] = &ce[i][q->cell.nof_prb * RE_X_RB * CP_NSYMB(q->cell.cp)];
}
}
slot1_symbols = &sf_symbols[q->cell.nof_prb * RE_X_RB * CP_NSYMB(q->cell.cp)];
/* number of layers equals number of ports */ /* Set pointers for layermapping & precoding */
for (i = 0; i < MAX_PORTS; i++) { nof_bits = 2 * q->nof_symbols;
x[i] = q->pbch_x[i];
}
memset(&x[MAX_PORTS], 0, sizeof(cf_t*) * (MAX_LAYERS - MAX_PORTS));
/* extract symbols */
if (q->nof_symbols
!= pbch_get(slot1_symbols, q->pbch_symbols[0], q->nof_prb, q->cp,
q->cell_id)) {
fprintf(stderr, "There was an error getting the PBCH symbols\n");
return -1;
}
/* extract channel estimates */ /* number of layers equals number of ports */
for (i = 0; i < MAX_PORTS; i++) { for (i = 0; i < MAX_PORTS; i++) {
if (q->nof_symbols x[i] = q->pbch_x[i];
!= pbch_get(ce[i], q->ce[i], q->nof_prb, q->cp, q->cell_id)) { }
memset(&x[MAX_PORTS], 0, sizeof(cf_t*) * (MAX_LAYERS - MAX_PORTS));
/* extract symbols */
if (q->nof_symbols != pbch_get(slot1_symbols, q->pbch_symbols[0], q->cell)) {
fprintf(stderr, "There was an error getting the PBCH symbols\n"); fprintf(stderr, "There was an error getting the PBCH symbols\n");
return -1; return LIBLTE_ERROR;
} }
}
q->frame_idx++; /* extract channel estimates */
res = 0; for (i = 0; i < q->cell.nof_ports; i++) {
if (q->nof_symbols != pbch_get(ce_slot[i], q->ce[i], q->cell)) {
fprintf(stderr, "There was an error getting the PBCH symbols\n");
return LIBLTE_ERROR;
}
}
/* Try decoding for 1 to 4 antennas */ q->frame_idx++;
for (na = 0; na < 3 && !res; na++) { ret = 0;
nant = nant_[na];
INFO("Trying %d TX antennas with %d frames\n", nant, q->frame_idx); /* Try decoding for 1 to cell.nof_ports antennas */
for (na = 0; na < q->cell.nof_ports && !ret; na++) {
nant = nant_[na];
/* in conctrol channels, only diversity is supported */ INFO("Trying %d TX antennas with %d frames\n", nant, q->frame_idx);
if (nant == 1) {
/* no need for layer demapping */
predecoding_single_zf(q->pbch_symbols[0], q->ce[0], q->pbch_d,
q->nof_symbols);
} else {
predecoding_diversity_zf(q->pbch_symbols[0], q->ce, x, nant,
q->nof_symbols);
layerdemap_diversity(x, q->pbch_d, nant, q->nof_symbols / nant);
}
/* demodulate symbols */ /* in conctrol channels, only diversity is supported */
demod_soft_sigma_set(&q->demod, 1.0); if (nant == 1) {
demod_soft_demodulate(&q->demod, q->pbch_d, /* no need for layer demapping */
&q->pbch_llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols); predecoding_single_zf(q->pbch_symbols[0], q->ce[0], q->pbch_d,
q->nof_symbols);
/* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received } else {
* 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234. predecoding_diversity_zf(q->pbch_symbols[0], q->ce, x, nant,
* We know they are ordered. q->nof_symbols);
* layerdemap_diversity(x, q->pbch_d, nant, q->nof_symbols / nant);
* FIXME: There are unnecessary checks because 2,3,4 have already been processed in the previous }
* calls.
*/ /* demodulate symbols */
for (nb = 0; nb < q->frame_idx && !res; nb++) { demod_soft_sigma_set(&q->demod, 1.0);
for (dst = 0; (dst < 4 - nb) && !res; dst++) { demod_soft_demodulate(&q->demod, q->pbch_d,
for (src = 0; src < q->frame_idx - nb && !res; src++) { &q->pbch_llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols);
DEBUG("Trying %d blocks at offset %d as subframe mod4 number %d\n",
nb + 1, src, dst); /* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received
res = pbch_decode_frame(q, mib, src, dst, nb + 1, nof_bits, nant); * 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234.
* We know they are ordered.
*
* FIXME: There are unnecessary checks because 2,3,4 have already been processed in the previous
* calls.
*/
for (nb = 0; nb < q->frame_idx && !ret; nb++) {
for (dst = 0; (dst < 4 - nb) && !ret; dst++) {
for (src = 0; src < q->frame_idx - nb && !ret; src++) {
DEBUG("Trying %d blocks at offset %d as subframe mod4 number %d\n",
nb + 1, src, dst);
ret = pbch_decode_frame(q, mib, src, dst, nb + 1, nof_bits, nant);
}
} }
} }
} }
}
/* If not found, make room for the next packet of radio frame symbols */ /* If not found, make room for the next packet of radio frame symbols */
if (q->frame_idx == 4) { if (q->frame_idx == 4) {
memmove(q->pbch_llr, &q->pbch_llr[nof_bits], nof_bits * 3 * sizeof(float)); memmove(q->pbch_llr, &q->pbch_llr[nof_bits], nof_bits * 3 * sizeof(float));
q->frame_idx = 3; q->frame_idx = 3;
}
} }
return res; return ret;
} }
/** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission /** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission
*/ */
void pbch_encode(pbch_t *q, pbch_mib_t *mib, int pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *sf_symbols[MAX_PORTS]) {
cf_t *slot1_symbols[MAX_PORTS], int nof_ports) {
int i; int i;
int nof_bits = 2 * q->nof_symbols; int nof_bits;
cf_t *slot1_symbols[MAX_PORTS];
assert(nof_ports <= MAX_PORTS);
/* Set pointers for layermapping & precoding */
cf_t *x[MAX_LAYERS]; cf_t *x[MAX_LAYERS];
if (q != NULL &&
mib != NULL)
{
for (i=0;i<q->cell.nof_ports;i++) {
if (sf_symbols[i] == NULL) {
return LIBLTE_ERROR_INVALID_INPUTS;
} else {
slot1_symbols[i] = &sf_symbols[i][q->cell.nof_prb * RE_X_RB * CP_NSYMB(q->cell.cp)];
}
}
/* Set pointers for layermapping & precoding */
nof_bits = 2 * q->nof_symbols;
/* number of layers equals number of ports */ /* number of layers equals number of ports */
for (i = 0; i < nof_ports; i++) { for (i = 0; i < q->cell.nof_ports; i++) {
x[i] = q->pbch_x[i]; x[i] = q->pbch_x[i];
} }
memset(&x[nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - nof_ports)); memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports));
if (q->frame_idx == 0) {
/* pack MIB */
pbch_mib_pack(mib, q->data);
if (q->frame_idx == 0) { /* encode & modulate */
/* pack MIB */ crc_attach(&q->crc, q->data, 24);
pbch_mib_pack(mib, q->data); crc_set_mask(q->data, q->cell.nof_ports);
/* encode & modulate */ convcoder_encode(&q->encoder, q->data, q->data_enc, 40);
crc_attach(&q->crc, q->data, 24);
crc_set_mask(q->data, nof_ports);
convcoder_encode(&q->encoder, q->data, q->data_enc, 40); rm_conv_tx(q->data_enc, 120, q->pbch_rm_b, 4 * nof_bits);
rm_conv_tx(q->data_enc, 120, q->pbch_rm_b, 4 * nof_bits); }
} scrambling_b_offset(&q->seq_pbch, &q->pbch_rm_b[q->frame_idx * nof_bits],
q->frame_idx * nof_bits, nof_bits);
mod_modulate(&q->mod, &q->pbch_rm_b[q->frame_idx * nof_bits], q->pbch_d,
nof_bits);
scrambling_b_offset(&q->seq_pbch, &q->pbch_rm_b[q->frame_idx * nof_bits], /* layer mapping & precoding */
q->frame_idx * nof_bits, nof_bits); if (q->cell.nof_ports > 1) {
mod_modulate(&q->mod, &q->pbch_rm_b[q->frame_idx * nof_bits], q->pbch_d, layermap_diversity(q->pbch_d, x, q->cell.nof_ports, q->nof_symbols);
nof_bits); precoding_diversity(x, q->pbch_symbols, q->cell.nof_ports,
q->nof_symbols / q->cell.nof_ports);
} else {
memcpy(q->pbch_symbols[0], q->pbch_d, q->nof_symbols * sizeof(cf_t));
}
/* layer mapping & precoding */ /* mapping to resource elements */
if (nof_ports > 1) { for (i = 0; i < q->cell.nof_ports; i++) {
layermap_diversity(q->pbch_d, x, nof_ports, q->nof_symbols); pbch_put(q->pbch_symbols[i], slot1_symbols[i], q->cell);
precoding_diversity(x, q->pbch_symbols, nof_ports, }
q->nof_symbols / nof_ports); q->frame_idx++;
if (q->frame_idx == 4) {
q->frame_idx = 0;
}
return LIBLTE_SUCCESS;
} else { } else {
memcpy(q->pbch_symbols[0], q->pbch_d, q->nof_symbols * sizeof(cf_t)); return LIBLTE_ERROR_INVALID_INPUTS;
}
/* mapping to resource elements */
for (i = 0; i < nof_ports; i++) {
pbch_put(q->pbch_symbols[i], slot1_symbols[i], q->nof_prb, q->cp,
q->cell_id);
}
q->frame_idx++;
if (q->frame_idx == 4) {
q->frame_idx = 0;
} }
} }

@ -61,10 +61,10 @@ struct cb_segm {
int pdsch_cp(pdsch_t *q, cf_t *input, cf_t *output, ra_prb_t *prb_alloc, int pdsch_cp(pdsch_t *q, cf_t *input, cf_t *output, ra_prb_t *prb_alloc,
uint8_t nsubframe, bool put) { uint8_t nsubframe, bool put) {
int s, n, l, lp, lstart, lend, nof_refs; uint8_t s, n, l, lp, lstart, lend, nof_refs;
bool is_pbch, is_sss; bool is_pbch, is_sss;
cf_t *in_ptr = input, *out_ptr = output; cf_t *in_ptr = input, *out_ptr = output;
int offset; uint8_t offset;
INFO("%s %d RE from %d PRB\n", put ? "Putting" : "Getting", INFO("%s %d RE from %d PRB\n", put ? "Putting" : "Getting",
prb_alloc->re_sf[nsubframe], prb_alloc->slot[0].nof_prb); prb_alloc->re_sf[nsubframe], prb_alloc->slot[0].nof_prb);
@ -76,7 +76,6 @@ int pdsch_cp(pdsch_t *q, cf_t *input, cf_t *output, ra_prb_t *prb_alloc,
} }
for (s = 0; s < 2; s++) { for (s = 0; s < 2; s++) {
for (l = 0; l < CP_NSYMB(q->cell.cp); l++) { for (l = 0; l < CP_NSYMB(q->cell.cp); l++) {
for (n = 0; n < prb_alloc->slot[s].nof_prb; n++) { for (n = 0; n < prb_alloc->slot[s].nof_prb; n++) {
if (s == 0) { if (s == 0) {

@ -41,23 +41,23 @@
#define min(a,b) (a<b?a:b) #define min(a,b) (a<b?a:b)
/* Returns the number of RE in a PRB in a slot and subframe */ /* Returns the number of RE in a PRB in a slot and subframe */
int ra_re_x_prb(int nsubframe, int nslot, int prb_idx, int nof_prb, uint16_t ra_re_x_prb(uint8_t subframe, uint8_t slot, uint8_t prb_idx, uint8_t nof_prb,
int nof_ports, int nof_ctrl_symbols, lte_cp_t cp) { uint8_t nof_ports, uint8_t nof_ctrl_symbols, lte_cp_t cp) {
int re; uint16_t re;
bool skip_refs = false; bool skip_refs = false;
if (nslot == 0) { if (slot == 0) {
re = (CP_NSYMB(cp) - nof_ctrl_symbols) * RE_X_RB; re = (CP_NSYMB(cp) - nof_ctrl_symbols) * RE_X_RB;
} else { } else {
re = CP_NSYMB(cp) * RE_X_RB; re = CP_NSYMB(cp) * RE_X_RB;
} }
/* if it's the prb in the middle, there are less RE due to PBCH and PSS/SSS */ /* if it's the prb in the middle, there are less RE due to PBCH and PSS/SSS */
if ((nsubframe == 0 || nsubframe == 5) if ((subframe == 0 || subframe == 5)
&& (prb_idx >= nof_prb / 2 - 3 && prb_idx <= nof_prb / 2 + 3)) { && (prb_idx >= nof_prb / 2 - 3 && prb_idx <= nof_prb / 2 + 3)) {
if (nsubframe == 0) { if (subframe == 0) {
if (nslot == 0) { if (slot == 0) {
re = (CP_NSYMB(cp) - nof_ctrl_symbols - 2) * RE_X_RB; re = (CP_NSYMB(cp) - nof_ctrl_symbols - 2) * RE_X_RB;
} else { } else {
if (CP_ISEXT(cp)) { if (CP_ISEXT(cp)) {
@ -67,16 +67,16 @@ int ra_re_x_prb(int nsubframe, int nslot, int prb_idx, int nof_prb,
re = (CP_NSYMB(cp) - 4) * RE_X_RB + 2 * nof_ports; re = (CP_NSYMB(cp) - 4) * RE_X_RB + 2 * nof_ports;
} }
} }
} else if (nsubframe == 5) { } else if (subframe == 5) {
if (nslot == 0) { if (slot == 0) {
re = (CP_NSYMB(cp) - nof_ctrl_symbols - 2) * RE_X_RB; re = (CP_NSYMB(cp) - nof_ctrl_symbols - 2) * RE_X_RB;
} }
} }
if ((nof_prb % 2) if ((nof_prb % 2)
&& (prb_idx == nof_prb / 2 - 3 || prb_idx == nof_prb / 2 + 3)) { && (prb_idx == nof_prb / 2 - 3 || prb_idx == nof_prb / 2 + 3)) {
if (nslot == 0) { if (slot == 0) {
re += 2 * RE_X_RB / 2; re += 2 * RE_X_RB / 2;
} else if (nsubframe == 0) { } else if (subframe == 0) {
re += 4 * RE_X_RB / 2 - nof_ports; re += 4 * RE_X_RB / 2 - nof_ports;
if (CP_ISEXT(cp)) { if (CP_ISEXT(cp)) {
re -= nof_ports > 2 ? 2 : nof_ports; re -= nof_ports > 2 ? 2 : nof_ports;
@ -90,10 +90,10 @@ int ra_re_x_prb(int nsubframe, int nslot, int prb_idx, int nof_prb,
switch (nof_ports) { switch (nof_ports) {
case 1: case 1:
case 2: case 2:
re -= 2 * (nslot + 1) * nof_ports; re -= 2 * (slot + 1) * nof_ports;
break; break;
case 4: case 4:
if (nslot == 1) { if (slot == 1) {
re -= 12; re -= 12;
} else { } else {
re -= 4; re -= 4;
@ -109,9 +109,9 @@ int ra_re_x_prb(int nsubframe, int nslot, int prb_idx, int nof_prb,
} }
/* Computes the number of RE for each PRB in the prb_dist structure */ /* Computes the number of RE for each PRB in the prb_dist structure */
void ra_prb_get_re(ra_prb_t *prb_dist, int nof_prb, int nof_ports, void ra_prb_get_re_dl(ra_prb_t *prb_dist, uint8_t nof_prb, uint8_t nof_ports,
int nof_ctrl_symbols, lte_cp_t cp) { uint8_t nof_ctrl_symbols, lte_cp_t cp) {
int i, j, s; uint8_t i, j, s;
/* Set start symbol according to Section 7.1.6.4 in 36.213 */ /* Set start symbol according to Section 7.1.6.4 in 36.213 */
prb_dist->lstart = nof_ctrl_symbols; prb_dist->lstart = nof_ctrl_symbols;
@ -139,25 +139,25 @@ void ra_prb_fprint(FILE *f, ra_prb_slot_t *prb) {
} }
/** Compute PRB allocation for Downlink as defined in 8.1 of 36.213 */ /** Compute PRB allocation for Downlink as defined in 8.1 of 36.213 */
int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, int nof_prb) { int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, uint8_t nof_prb) {
int i; int i;
if (ra->type2_alloc.mode != t2_loc) { if (ra->type2_alloc.mode != t2_loc) {
fprintf(stderr, "Uplink only accepts type2 localized scheduling\n"); fprintf(stderr, "Uplink only accepts type2 localized scheduling\n");
return -1; return LIBLTE_ERROR;
} }
for (i = 0; i < ra->type2_alloc.L_crb; i++) { for (i = 0; i < ra->type2_alloc.L_crb; i++) {
prb->prb_idx[i] = i + ra->type2_alloc.RB_start; prb->prb_idx[i] = i + ra->type2_alloc.RB_start;
prb->nof_prb++; prb->nof_prb++;
} }
return 0; return LIBLTE_SUCCESS;
} }
/** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 */ /** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 */
int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, int nof_prb) { int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, uint8_t nof_prb) {
int i, j; int i, j;
uint32_t bitmask; uint32_t bitmask;
int P = ra_type0_P(nof_prb); uint8_t P = ra_type0_P(nof_prb);
int n_rb_rbg_subset, n_rb_type1; uint8_t n_rb_rbg_subset, n_rb_type1;
bzero(prb_dist, sizeof(ra_prb_t)); bzero(prb_dist, sizeof(ra_prb_t));
switch (ra->alloc_type) { switch (ra->alloc_type) {
@ -260,33 +260,33 @@ int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, int nof_prb) {
} }
break; break;
default: default:
return -1; return LIBLTE_ERROR;
} }
return 0; return LIBLTE_SUCCESS;
} }
/* Returns the number of allocated PRB for Uplink */ /* Returns the number of allocated PRB for Uplink */
int ra_nprb_ul(ra_pusch_t *ra, int nof_prb) { uint16_t ra_nprb_ul(ra_pusch_t *ra, uint8_t nof_prb) {
return ra->type2_alloc.L_crb; return ra->type2_alloc.L_crb;
} }
/* Returns the number of allocated PRB for Downlink */ /* Returns the number of allocated PRB for Downlink */
int ra_nprb_dl(ra_pdsch_t *ra, int nof_prb) { uint16_t ra_nprb_dl(ra_pdsch_t *ra, uint8_t nof_prb) {
int nprb; uint8_t nprb;
int nof_rbg, P; uint8_t nof_rbg, P;
switch (ra->alloc_type) { switch (ra->alloc_type) {
case alloc_type0: case alloc_type0:
// Get the number of allocated RBG except the last RBG // Get the number of allocated RBG except the last RBG
nof_rbg = bit_count(ra->type0_alloc.rbg_bitmask & 0xFFFFFFFE); nof_rbg = bit_count(ra->type0_alloc.rbg_bitmask & 0xFFFFFFFE);
P = ra_type0_P(nof_prb); P = ra_type0_P(nof_prb);
if (nof_rbg > (int) ceilf((float) nof_prb / P)) { if (nof_rbg > (uint8_t) ceilf((float) nof_prb / P)) {
nof_rbg = (int) ceilf((float) nof_prb / P) - 1; nof_rbg = (uint8_t) ceilf((float) nof_prb / P) - 1;
} }
nprb = nof_rbg * P; nprb = nof_rbg * P;
// last RBG may have smaller size. Add if set // last RBG may have smaller size. Add if set
int P_last = (nof_prb % P); uint8_t P_last = (nof_prb % P);
if (!P_last) if (!P_last)
P_last = P; P_last = P;
nprb += P_last * (ra->type0_alloc.rbg_bitmask & 1); nprb += P_last * (ra->type0_alloc.rbg_bitmask & 1);
@ -296,20 +296,20 @@ int ra_nprb_dl(ra_pdsch_t *ra, int nof_prb) {
if (nprb > ra_type1_N_rb(nof_prb)) { if (nprb > ra_type1_N_rb(nof_prb)) {
fprintf(stderr, "Number of RB (%d) can not exceed %d\n", nprb, fprintf(stderr, "Number of RB (%d) can not exceed %d\n", nprb,
ra_type1_N_rb(nof_prb)); ra_type1_N_rb(nof_prb));
return -1; return LIBLTE_ERROR;
} }
break; break;
case alloc_type2: case alloc_type2:
nprb = ra->type2_alloc.L_crb; nprb = ra->type2_alloc.L_crb;
break; break;
default: default:
return -1; return LIBLTE_ERROR;
} }
return nprb; return nprb;
} }
/* RBG size for type0 scheduling as in table 7.1.6.1-1 of 36.213 */ /* RBG size for type0 scheduling as in table 7.1.6.1-1 of 36.213 */
int ra_type0_P(int nof_prb) { uint8_t ra_type0_P(uint8_t nof_prb) {
if (nof_prb <= 10) { if (nof_prb <= 10) {
return 1; return 1;
} else if (nof_prb <= 26) { } else if (nof_prb <= 26) {
@ -322,15 +322,15 @@ int ra_type0_P(int nof_prb) {
} }
/* Returns N_rb_type1 according to section 7.1.6.2 */ /* Returns N_rb_type1 according to section 7.1.6.2 */
int ra_type1_N_rb(int nof_prb) { uint8_t ra_type1_N_rb(uint8_t nof_prb) {
int P = ra_type0_P(nof_prb); uint8_t P = ra_type0_P(nof_prb);
return (int) ceilf((float) nof_prb / P) - (int) ceilf(log2f((float) P)) - 1; return (uint8_t) ceilf((float) nof_prb / P) - (uint8_t) ceilf(log2f((float) P)) - 1;
} }
/* Convert Type2 scheduling L_crb and RB_start to RIV value */ /* Convert Type2 scheduling L_crb and RB_start to RIV value */
uint32_t ra_type2_to_riv(uint16_t L_crb, uint16_t RB_start, int nof_prb) { uint16_t ra_type2_to_riv(uint8_t L_crb, uint8_t RB_start, uint8_t nof_prb) {
uint32_t riv; uint16_t riv;
if (L_crb <= (int) nof_prb / 2) { if (L_crb <= nof_prb / 2) {
riv = nof_prb * (L_crb - 1) + RB_start; riv = nof_prb * (L_crb - 1) + RB_start;
} else { } else {
riv = nof_prb * (nof_prb - L_crb + 1) + nof_prb - 1 - RB_start; riv = nof_prb * (nof_prb - L_crb + 1) + nof_prb - 1 - RB_start;
@ -339,10 +339,10 @@ uint32_t ra_type2_to_riv(uint16_t L_crb, uint16_t RB_start, int nof_prb) {
} }
/* Convert Type2 scheduling RIV value to L_crb and RB_start values */ /* Convert Type2 scheduling RIV value to L_crb and RB_start values */
void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start, void ra_type2_from_riv(uint16_t riv, uint8_t *L_crb, uint8_t *RB_start,
int nof_prb, int nof_vrb) { uint8_t nof_prb, uint8_t nof_vrb) {
*L_crb = (int) (riv / nof_prb) + 1; *L_crb = (uint8_t) (riv / nof_prb) + 1;
*RB_start = riv % nof_prb; *RB_start = (uint8_t) (riv % nof_prb);
if (*L_crb > nof_vrb - *RB_start) { if (*L_crb > nof_vrb - *RB_start) {
*L_crb = nof_prb - (int) (riv / nof_prb) + 1; *L_crb = nof_prb - (int) (riv / nof_prb) + 1;
*RB_start = nof_prb - riv % nof_prb - 1; *RB_start = nof_prb - riv % nof_prb - 1;
@ -350,7 +350,7 @@ void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start,
} }
/* Table 6.2.3.2-1 in 36.211 */ /* Table 6.2.3.2-1 in 36.211 */
int ra_type2_ngap(int nof_prb, bool ngap_is_1) { uint8_t ra_type2_ngap(uint8_t nof_prb, bool ngap_is_1) {
if (nof_prb <= 10) { if (nof_prb <= 10) {
return nof_prb / 2; return nof_prb / 2;
} else if (nof_prb == 11) { } else if (nof_prb == 11) {
@ -373,7 +373,7 @@ int ra_type2_ngap(int nof_prb, bool ngap_is_1) {
} }
/* Table 7.1.6.3-1 in 36.213 */ /* Table 7.1.6.3-1 in 36.213 */
int ra_type2_n_rb_step(int nof_prb) { uint8_t ra_type2_n_rb_step(uint8_t nof_prb) {
if (nof_prb < 50) { if (nof_prb < 50) {
return 2; return 2;
} else { } else {
@ -382,12 +382,12 @@ int ra_type2_n_rb_step(int nof_prb) {
} }
/* as defined in 6.2.3.2 of 36.211 */ /* as defined in 6.2.3.2 of 36.211 */
int ra_type2_n_vrb_dl(int nof_prb, bool ngap_is_1) { uint8_t ra_type2_n_vrb_dl(uint8_t nof_prb, bool ngap_is_1) {
int ngap = ra_type2_ngap(nof_prb, ngap_is_1); uint8_t ngap = ra_type2_ngap(nof_prb, ngap_is_1);
if (ngap_is_1) { if (ngap_is_1) {
return 2 * (ngap < (nof_prb - ngap) ? ngap : nof_prb - ngap); return 2 * (ngap < (nof_prb - ngap) ? ngap : nof_prb - ngap);
} else { } else {
return ((int) nof_prb / ngap) * 2 * ngap; return ((uint8_t) nof_prb / ngap) * 2 * ngap;
} }
} }
@ -401,7 +401,7 @@ uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs) {
case QAM64: case QAM64:
return mcs->tbs_idx + 2; return mcs->tbs_idx + 2;
default: default:
return 0; return LIBLTE_SUCCESS;
} }
} }
@ -428,9 +428,9 @@ int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs) {
} else { } else {
mcs->mod = MOD_NULL; mcs->mod = MOD_NULL;
mcs->tbs_idx = 0; mcs->tbs_idx = 0;
return -1; return LIBLTE_ERROR;
} }
return 0; return LIBLTE_SUCCESS;
} }
/* Converts MCS index to ra_mcs_t structure for Uplink as defined in Table 8.6.1-1 on 36.213 */ /* Converts MCS index to ra_mcs_t structure for Uplink as defined in Table 8.6.1-1 on 36.213 */
@ -447,9 +447,9 @@ int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs) {
} else { } else {
mcs->mod = MOD_NULL; mcs->mod = MOD_NULL;
mcs->tbs_idx = 0; mcs->tbs_idx = 0;
return -1; return LIBLTE_ERROR;
} }
return 0; return LIBLTE_SUCCESS;
} }
/* Downlink Transport Block size for Format 1C as defined in 7.1.7.2.2-1 on 36.213 */ /* Downlink Transport Block size for Format 1C as defined in 7.1.7.2.2-1 on 36.213 */
@ -457,52 +457,52 @@ int ra_tbs_from_idx_format1c(uint8_t tbs_idx) {
if (tbs_idx < 32) { if (tbs_idx < 32) {
return tbs_format1c_table[tbs_idx]; return tbs_format1c_table[tbs_idx];
} else { } else {
return -1; return LIBLTE_ERROR;
} }
} }
/* Returns lowest nearest index of TBS value in table 7.1.7.2.2-1 on 36.213 /* Returns lowest nearest index of TBS value in table 7.1.7.2.2-1 on 36.213
* or -1 if the TBS value is not within the valid TBS values * or -1 if the TBS value is not within the valid TBS values
*/ */
int ra_tbs_to_table_idx_format1c(int tbs) { int ra_tbs_to_table_idx_format1c(uint32_t tbs) {
int idx; int idx;
if (tbs < tbs_format1c_table[0]) { if (tbs < tbs_format1c_table[0]) {
return -1; return LIBLTE_ERROR;
} }
for (idx = 1; idx < 32; idx++) { for (idx = 1; idx < 32; idx++) {
if (tbs_format1c_table[idx - 1] <= tbs && tbs_format1c_table[idx] >= tbs) { if (tbs_format1c_table[idx - 1] <= tbs && tbs_format1c_table[idx] >= tbs) {
return idx; return idx;
} }
} }
return -1; return LIBLTE_ERROR;
} }
/* Downlink Transport Block size determination as defined in 7.1.7.2 on 36.213 */ /* Downlink Transport Block size determination as defined in 7.1.7.2 on 36.213 */
int ra_tbs_from_idx(uint8_t tbs_idx, int n_prb) { int ra_tbs_from_idx(uint8_t tbs_idx, uint8_t n_prb) {
if (tbs_idx < 27 && n_prb > 0 && n_prb <= 110) { if (tbs_idx < 27 && n_prb > 0 && n_prb <= MAX_PRB) {
return tbs_table[tbs_idx][n_prb - 1]; return tbs_table[tbs_idx][n_prb - 1];
} else { } else {
return -1; return LIBLTE_ERROR;
} }
} }
/* Returns lowest nearest index of TBS value in table 7.1.7.2 on 36.213 /* Returns lowest nearest index of TBS value in table 7.1.7.2 on 36.213
* or -1 if the TBS value is not within the valid TBS values * or -1 if the TBS value is not within the valid TBS values
*/ */
int ra_tbs_to_table_idx(int tbs, int n_prb) { int ra_tbs_to_table_idx(uint32_t tbs, uint8_t n_prb) {
int idx; int idx;
if (n_prb > 0 && n_prb <= 110) { if (n_prb > 0 && n_prb <= MAX_PRB) {
return -1; return LIBLTE_ERROR;
} }
if (tbs < tbs_table[0][n_prb]) { if (tbs < tbs_table[0][n_prb]) {
return -1; return LIBLTE_ERROR;
} }
for (idx = 1; idx < 28; idx++) { for (idx = 1; idx < 28; idx++) {
if (tbs_table[idx - 1][n_prb] <= tbs && tbs_table[idx][n_prb] >= tbs) { if (tbs_table[idx - 1][n_prb] <= tbs && tbs_table[idx][n_prb] >= tbs) {
return idx; return idx;
} }
} }
return -1; return LIBLTE_ERROR;
} }
char *ra_mod_string(ra_mod_t mod) { char *ra_mod_string(ra_mod_t mod) {
@ -518,7 +518,7 @@ char *ra_mod_string(ra_mod_t mod) {
} }
} }
void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, int nof_prb) { void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, uint8_t nof_prb) {
fprintf(f, "Frequency Hopping:\t"); fprintf(f, "Frequency Hopping:\t");
if (ra->freq_hop_fl == hop_disabled) { if (ra->freq_hop_fl == hop_disabled) {
fprintf(f, "No"); fprintf(f, "No");
@ -551,7 +551,7 @@ void ra_pdsch_set_mcs(ra_pdsch_t *ra, ra_mod_t mod, uint8_t tbs_idx) {
ra->mcs.tbs = 0; ra->mcs.tbs = 0;
} }
void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb) { void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, uint8_t nof_prb) {
fprintf(f, " - Resource Allocation Type:\t\t%s\n", fprintf(f, " - Resource Allocation Type:\t\t%s\n",
ra_type_string(ra->alloc_type)); ra_type_string(ra->alloc_type));
switch (ra->alloc_type) { switch (ra->alloc_type) {

@ -117,14 +117,14 @@ int base_init() {
exit(-1); exit(-1);
} }
fft_buffer = malloc(CP_NSYMB(cell.cp) * cell.nof_prb * RE_X_RB * sizeof(cf_t)); fft_buffer = malloc(2 * CP_NSYMB(cell.cp) * cell.nof_prb * RE_X_RB * sizeof(cf_t));
if (!fft_buffer) { if (!fft_buffer) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
for (i=0;i<MAX_PORTS;i++) { for (i=0;i<cell.nof_ports;i++) {
ce[i] = malloc(CP_NSYMB(cell.cp) * cell.nof_prb * RE_X_RB * sizeof(cf_t)); ce[i] = malloc(2 * CP_NSYMB(cell.cp) * cell.nof_prb * RE_X_RB * sizeof(cf_t));
if (!ce[i]) { if (!ce[i]) {
perror("malloc"); perror("malloc");
return -1; return -1;
@ -146,7 +146,7 @@ int base_init() {
return -1; return -1;
} }
if (pbch_init(&pbch, cell.nof_prb, cell.id, cell.cp)) { if (pbch_init(&pbch, cell)) {
fprintf(stderr, "Error initiating PBCH\n"); fprintf(stderr, "Error initiating PBCH\n");
return -1; return -1;
} }
@ -167,7 +167,7 @@ void base_free() {
free(fft_buffer); free(fft_buffer);
filesource_free(&fsrc); filesource_free(&fsrc);
for (i=0;i<MAX_PORTS;i++) { for (i=0;i<cell.nof_ports;i++) {
free(ce[i]); free(ce[i]);
} }
chest_free(&chest); chest_free(&chest);
@ -178,7 +178,7 @@ void base_free() {
int main(int argc, char **argv) { int main(int argc, char **argv) {
pbch_mib_t mib; pbch_mib_t mib;
int i, n; int n;
if (argc < 3) { if (argc < 3) {
usage(argv[0]); usage(argv[0]);
@ -194,7 +194,7 @@ int main(int argc, char **argv) {
n = filesource_read(&fsrc, input_buffer, FLEN); n = filesource_read(&fsrc, input_buffer, FLEN);
lte_fft_run_slot(&fft, &input_buffer[960], fft_buffer); lte_fft_run_sf(&fft, input_buffer, fft_buffer);
if (fmatlab) { if (fmatlab) {
fprintf(fmatlab, "outfft="); fprintf(fmatlab, "outfft=");
@ -205,12 +205,7 @@ int main(int argc, char **argv) {
} }
/* Get channel estimates for each port */ /* Get channel estimates for each port */
for (i=0;i<cell.nof_ports;i++) { chest_ce_sf(&chest, fft_buffer, ce, 0);
chest_ce_slot_port(&chest, fft_buffer, ce[i], 1, i);
if (fmatlab) {
chest_fprint(&chest, fmatlab, 1, i);
}
}
INFO("Decoding PBCH\n", 0); INFO("Decoding PBCH\n", 0);

@ -33,16 +33,18 @@
#include "liblte/phy/phy.h" #include "liblte/phy/phy.h"
int cell_id = 1; lte_cell_t cell = {
int nof_prb = 6; 6, // nof_prb
int nof_ports = 1; 1, // nof_ports
1, // cell_id
CPNORM // cyclic prefix
};
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s [cpv]\n", prog); printf("Usage: %s [cpv]\n", prog);
printf("\t-c cell id [Default %d]\n", cell_id); printf("\t-c cell id [Default %d]\n", cell.id);
printf("\t-p nof_ports [Default %d]\n", nof_ports); printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports);
printf("\t-n nof_prb [Default %d]\n", nof_prb); printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-v [set verbose to debug, default none]\n"); printf("\t-v [set verbose to debug, default none]\n");
} }
@ -51,13 +53,13 @@ void parse_args(int argc, char **argv) {
while ((opt = getopt(argc, argv, "cpnv")) != -1) { while ((opt = getopt(argc, argv, "cpnv")) != -1) {
switch(opt) { switch(opt) {
case 'p': case 'p':
nof_ports = atoi(argv[optind]); cell.nof_ports = atoi(argv[optind]);
break; break;
case 'n': case 'n':
nof_prb = atoi(argv[optind]); cell.nof_prb = atoi(argv[optind]);
break; break;
case 'c': case 'c':
cell_id = atoi(argv[optind]); cell.id = atoi(argv[optind]);
break; break;
case 'v': case 'v':
verbose++; verbose++;
@ -76,14 +78,14 @@ int main(int argc, char **argv) {
int i, j; int i, j;
cf_t *ce[MAX_PORTS]; cf_t *ce[MAX_PORTS];
int nof_re; int nof_re;
cf_t *slot1_symbols[MAX_PORTS]; cf_t *sf_symbols[MAX_PORTS];
parse_args(argc,argv); parse_args(argc,argv);
nof_re = CPNORM_NSYMB * nof_prb * RE_X_RB; nof_re = 2 * CPNORM_NSYMB * cell.nof_prb * RE_X_RB;
/* init memory */ /* init memory */
for (i=0;i<MAX_PORTS;i++) { for (i=0;i<cell.nof_ports;i++) {
ce[i] = malloc(sizeof(cf_t) * nof_re); ce[i] = malloc(sizeof(cf_t) * nof_re);
if (!ce[i]) { if (!ce[i]) {
perror("malloc"); perror("malloc");
@ -92,44 +94,44 @@ int main(int argc, char **argv) {
for (j=0;j<nof_re;j++) { for (j=0;j<nof_re;j++) {
ce[i][j] = 1; ce[i][j] = 1;
} }
slot1_symbols[i] = malloc(sizeof(cf_t) * nof_re); sf_symbols[i] = malloc(sizeof(cf_t) * nof_re);
if (!slot1_symbols[i]) { if (!sf_symbols[i]) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
} }
if (pbch_init(&pbch, nof_prb, cell_id, CPNORM)) { if (pbch_init(&pbch, cell)) {
fprintf(stderr, "Error creating PBCH object\n"); fprintf(stderr, "Error creating PBCH object\n");
exit(-1); exit(-1);
} }
mib_tx.nof_ports = nof_ports; mib_tx.nof_ports = cell.nof_ports;
mib_tx.nof_prb = 50; mib_tx.nof_prb = 50;
mib_tx.phich_length = PHICH_EXT; mib_tx.phich_length = PHICH_EXT;
mib_tx.phich_resources = R_1_6; mib_tx.phich_resources = R_1_6;
mib_tx.sfn = 124; mib_tx.sfn = 124;
pbch_encode(&pbch, &mib_tx, slot1_symbols, nof_ports); pbch_encode(&pbch, &mib_tx, sf_symbols);
/* combine outputs */ /* combine outputs */
for (i=1;i<nof_ports;i++) { for (i=1;i<cell.nof_ports;i++) {
for (j=0;j<nof_re;j++) { for (j=0;j<nof_re;j++) {
slot1_symbols[0][j] += slot1_symbols[i][j]; sf_symbols[0][j] += sf_symbols[i][j];
} }
} }
pbch_decode_reset(&pbch); pbch_decode_reset(&pbch);
if (1 != pbch_decode(&pbch, slot1_symbols[0], ce, &mib_rx)) { if (1 != pbch_decode(&pbch, sf_symbols[0], ce, &mib_rx)) {
printf("Error decoding\n"); printf("Error decoding\n");
exit(-1); exit(-1);
} }
pbch_free(&pbch); pbch_free(&pbch);
for (i=0;i<MAX_PORTS;i++) { for (i=0;i<cell.nof_ports;i++) {
free(ce[i]); free(ce[i]);
free(slot1_symbols[i]); free(sf_symbols[i]);
} }
if (!memcmp(&mib_tx, &mib_rx, sizeof(pbch_mib_t))) { if (!memcmp(&mib_tx, &mib_rx, sizeof(pbch_mib_t))) {

@ -314,7 +314,7 @@ int main(int argc, char **argv) {
fprintf(stderr, "Error computing resource allocation\n"); fprintf(stderr, "Error computing resource allocation\n");
goto goout; goto goout;
} }
ra_prb_get_re(&prb_alloc, cell.nof_prb, cell.nof_ports, cell.nof_prb<10?(cfi+1):cfi, cell.cp); ra_prb_get_re_dl(&prb_alloc, cell.nof_prb, cell.nof_ports, cell.nof_prb<10?(cfi+1):cfi, cell.cp);
if (pdsch_decode(&pdsch, fft_buffer, ce, data, nof_frames%10, ra_dl.mcs, &prb_alloc)) { if (pdsch_decode(&pdsch, fft_buffer, ce, data, nof_frames%10, ra_dl.mcs, &prb_alloc)) {
fprintf(stderr, "Error decoding PDSCH\n"); fprintf(stderr, "Error decoding PDSCH\n");

@ -80,10 +80,10 @@ int main(int argc, char **argv) {
pdsch_init(&pdsch, 0, cell); pdsch_init(&pdsch, 0, cell);
memset(prb_alloc.re_sf, 0, sizeof(int) * 10); memset(prb_alloc.re_sf, 0, sizeof(uint16_t) * 10);
prb_alloc.slot[0].nof_prb = test_re_prb[i]; prb_alloc.slot[0].nof_prb = test_re_prb[i];
prb_alloc.slot[1].nof_prb = test_re_prb[i]; prb_alloc.slot[1].nof_prb = test_re_prb[i];
ra_prb_get_re(&prb_alloc, test_re_prb[i], test_re_ports[i], test_re_csymb[i], test_re_cp[i]); ra_prb_get_re_dl(&prb_alloc, test_re_prb[i], test_re_ports[i], test_re_csymb[i], test_re_cp[i]);
for (n=0;n<10;n++) { for (n=0;n<10;n++) {
switch(n) { switch(n) {
case 0: case 0:

@ -134,7 +134,7 @@ int main(int argc, char **argv) {
} }
memcpy(&prb_alloc.slot[1], &prb_alloc.slot[0], sizeof(ra_prb_slot_t)); memcpy(&prb_alloc.slot[1], &prb_alloc.slot[0], sizeof(ra_prb_slot_t));
ra_prb_get_re(&prb_alloc, cell.nof_prb, cell.nof_ports, 2, CPNORM); ra_prb_get_re_dl(&prb_alloc, cell.nof_prb, cell.nof_ports, 2, CPNORM);
/* init memory */ /* init memory */
for (i=0;i<cell.nof_ports;i++) { for (i=0;i<cell.nof_ports;i++) {

@ -75,7 +75,7 @@ unsigned int bit_diff(char *x, char *y, int nbits) {
} }
// Counts the number of ones in a word. K&R book exercise 2.9 // Counts the number of ones in a word. K&R book exercise 2.9
int bit_count(unsigned int n) { uint8_t bit_count(uint32_t n) {
int c; int c;
for (c = 0; n; c++) for (c = 0; n; c++)
n &= n - 1; n &= n - 1;

Loading…
Cancel
Save