Merge branch 'next' of github.com:softwareradiosystems/srsLTE into next

master
Pedro Alvarez 7 years ago
commit 06180a38ef

@ -84,6 +84,8 @@ int mbsfn_area_id = -1;
char *rf_args = "";
float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000;
float output_file_snr = +INFINITY;
bool null_file_sink=false;
srslte_filesink_t fsink;
srslte_ofdm_t ifft[SRSLTE_MAX_PORTS];
@ -145,13 +147,14 @@ void usage(char *prog) {
printf("\t-w Number of codewords/layers (multiplex mode only)* [Default %d]\n", multiplex_nof_layers);
printf("\t-u listen TCP port for input data (-1 is random) [Default %d]\n", net_port);
printf("\t-v [set srslte_verbose to debug, default none]\n");
printf("\t-s output file SNR [Default %f]\n", output_file_snr);
printf("\n");
printf("\t*: See 3GPP 36.212 Table 5.3.3.1.5-4 for more information\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "aglfmoncpvutxbwM")) != -1) {
while ((opt = getopt(argc, argv, "aglfmoncpvutxbwMs")) != -1) {
switch (opt) {
case 'a':
@ -200,6 +203,9 @@ void parse_args(int argc, char **argv) {
case 'v':
srslte_verbose++;
break;
case 's':
output_file_snr = atof(argv[optind]);
break;
default:
usage(argv[0]);
exit(-1);
@ -989,7 +995,14 @@ int main(int argc, char **argv) {
/* send to file or usrp */
if (output_file_name) {
if (!null_file_sink) {
srslte_filesink_write_multi(&fsink, (void**) output_buffer, sf_n_samples, cell.nof_ports);
/* Apply AWGN */
if (output_file_snr != +INFINITY) {
float var = powf(10.0f, -(output_file_snr + 3.0f) / 20.0f);
for (int k = 0; k < cell.nof_ports; k++) {
srslte_ch_awgn_c(output_buffer[k], output_buffer[k], var, sf_n_samples);
}
}
srslte_filesink_write_multi(&fsink, (void**) output_buffer, sf_n_samples, cell.nof_ports);
}
usleep(1000);
} else {

@ -164,6 +164,7 @@ public:
}
b->reset();
pool->deallocate(b);
b = NULL;
}
private:
buffer_pool<byte_buffer_t> *pool;

@ -42,7 +42,10 @@ namespace srslte {
{
public:
void log(std::string *msg) {
fprintf(stdout, "%s", msg->c_str());
if (msg) {
fprintf(stdout, "%s", msg->c_str());
delete msg;
}
}
};

@ -492,6 +492,7 @@ typedef struct {
float estimator_fil_w;
bool rssi_sensor_enabled;
bool sic_pss_enabled;
float rx_gain_offset;
} phy_args_t;

@ -42,8 +42,8 @@
#include "srslte/config.h"
#define SRSLTE_AGC_DEFAULT_TARGET 0.7
#define SRSLTE_AGC_DEFAULT_BW (5e-1)
#define SRSLTE_AGC_DEFAULT_TARGET 0.3
#define SRSLTE_AGC_DEFAULT_BW 0.7
typedef enum SRSLTE_API {
SRSLTE_AGC_MODE_ENERGY = 0,

@ -120,6 +120,8 @@ SRSLTE_API void srslte_vec_abs_square_cf_simd(const cf_t *x, float *z, const int
/* Other Functions */
SRSLTE_API void srslte_vec_lut_sss_simd(const short *x, const unsigned short *lut, short *y, const int len);
SRSLTE_API void srslte_vec_convert_if_simd(const int16_t *x, float *z, const float scale, const int len);
SRSLTE_API void srslte_vec_convert_fi_simd(const float *x, int16_t *z, const float scale, const int len);
SRSLTE_API void srslte_vec_cp_simd(const cf_t *src, cf_t *dst, int len);

@ -71,6 +71,7 @@ class rlc_am
{
public:
rlc_am();
~rlc_am();
void init(log *rlc_entity_log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,

@ -50,6 +50,7 @@ class rlc_um
{
public:
rlc_um();
~rlc_um();
void init(log *rlc_entity_log_,
uint32_t lcid_,

@ -54,7 +54,7 @@ void logger_file::init(std::string file, int max_length_) {
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&not_empty, NULL);
pthread_cond_init(&not_full, NULL);
max_length = max_length_*1024;
max_length = (int64_t)max_length_*1024;
name_idx = 0;
filename = file;
logfile = fopen(filename.c_str(), "w");

@ -177,7 +177,7 @@ void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) {
gg = expf(-0.5*q->bandwidth*logf(q->y_out/q->target));
q->gain *= gg;
}
DEBUG("AGC gain: %.2f (%.2f) y_out=%.3f, y=%.3f target=%.1f gg=%.2f\n", gain_db, gain_uhd_db, q->y_out, y, q->target, gg);
INFO("AGC gain: %.2f (%.2f) y_out=%.3f, y=%.3f target=%.1f gg=%.2f\n", gain_db, gain_uhd_db, q->y_out, y, q->target, gg);
}
}
}

@ -291,7 +291,7 @@ static float estimate_noise_pilots(srslte_chest_dl_t *q, uint32_t port_id, srslt
norm /= norm3;
}
}
float power = norm*q->cell.nof_ports*srslte_vec_avg_power_cf(q->tmp_noise, nref);
float power = norm*srslte_vec_avg_power_cf(q->tmp_noise, nref);
return power;
}
@ -543,7 +543,7 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui
/* Compute RSRP for the channel estimates in this port */
uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
q->rsrp[rxant_id][port_id] = __real__ srslte_vec_dot_prod_conj_ccc(q->pilot_estimates, q->pilot_estimates, npilots) / npilots;
q->rsrp[rxant_id][port_id] = srslte_vec_avg_power_cf(q->pilot_estimates, npilots);
q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id);
}
@ -639,7 +639,10 @@ float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q) {
for (int i=0;i<q->last_nof_antennas;i++) {
n += srslte_vec_acc_ff(q->noise_estimate[i], q->cell.nof_ports)/q->cell.nof_ports;
}
return n/q->last_nof_antennas;
if (q->last_nof_antennas) {
n /= q->last_nof_antennas;
}
return n;
}
float srslte_chest_dl_get_snr(srslte_chest_dl_t *q) {
@ -691,14 +694,25 @@ float srslte_chest_dl_get_rsrp_ant_port(srslte_chest_dl_t *q, uint32_t ant_idx,
}
float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q, uint32_t port) {
float n = 0;
for (int i = 0; i < q->last_nof_antennas; i++) {
n += q->rsrp[i][port];
float sum = 0.0f;
for (int j = 0; j < q->cell.nof_ports; ++j) {
sum +=q->rsrp[port][j];
}
if (q->cell.nof_ports) {
sum /= q->cell.nof_ports;
}
return n / q->last_nof_antennas;
return sum;
}
float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) {
// Note: use only port 0 but average across antennas
return srslte_chest_dl_get_rsrp_port(q, 0);
float max = -0.0f;
for (int i = 0; i < q->last_nof_antennas; ++i) {
float v = srslte_chest_dl_get_rsrp_port(q, i);
if (v > max) {
max = v;
}
}
return max;
}

@ -166,9 +166,15 @@ void free37_avx2_16bit(void *o) {
if (q->symbols_uc) {
free(q->symbols_uc);
}
if (q->symbols_us) {
free(q->symbols_us);
}
if (q->tmp) {
free(q->tmp);
}
if (q->tmp_s) {
free(q->tmp_s);
}
delete_viterbi37_avx2_16bit(q->ptr);
}

@ -57,185 +57,177 @@ float save_corr[4096];
uint32_t prach_Tcp[5] = {3168, 21024, 6240, 21024, 448};
// Table 5.7.1-1 T_seq for preamble formats
uint32_t prach_Tseq[5] = {24576, 24576, 2*24576, 2*24576, 4096};
uint32_t prach_Tseq[5] = {24576, 24576, 2 * 24576, 2 * 24576, 4096};
// Table 5.7.2-2 - N_cs values for unrestricted sets
uint32_t prach_Ncs_unrestricted[16] = {0,13,15,18,22,26,32,38,46,59,76,93,119,167,279,419};
uint32_t prach_Ncs_unrestricted[16] = {0, 13, 15, 18, 22, 26, 32, 38, 46, 59, 76, 93, 119, 167, 279, 419};
#define MAX_N_zc 839
// Table 5.7.2-2 - N_cs values for restricted sets
uint32_t prach_Ncs_restricted[15] = {15,18,22,26,32,38,46,55,68,82,100,128,158,202,237};
uint32_t prach_Ncs_restricted[15] = {15, 18, 22, 26, 32, 38, 46, 55, 68, 82, 100, 128, 158, 202, 237};
// Table 5.7.2-3 - N_cs values for preamble format 4
uint32_t prach_Ncs_format4[7] = {2,4,6,8,10,12,15};
uint32_t prach_Ncs_format4[7] = {2, 4, 6, 8, 10, 12, 15};
// Table 5.7.2-4 - Root ZC sequence order
uint32_t prach_zc_roots[838] = {
129, 710, 140, 699, 120, 719, 210, 629, 168, 671, 84, 755,
105, 734, 93, 746, 70, 769, 60, 779, 2, 837, 1, 838,
56, 783, 112, 727, 148, 691, 80, 759, 42, 797, 40, 799,
35, 804, 73, 766, 146, 693, 31, 808, 28, 811, 30, 809,
27, 812, 29, 810, 24, 815, 48, 791, 68, 771, 74, 765,
178, 661, 136, 703, 86, 753, 78, 761, 43, 796, 39, 800,
20, 819, 21, 818, 95, 744, 202, 637, 190, 649, 181, 658,
137, 702, 125, 714, 151, 688, 217, 622, 128, 711, 142, 697,
122, 717, 203, 636, 118, 721, 110, 729, 89, 750, 103, 736,
61, 778, 55, 784, 15, 824, 14, 825, 12, 827, 23, 816,
34, 805, 37, 802, 46, 793, 207, 632, 179, 660, 145, 694,
130, 709, 223, 616, 228, 611, 227, 612, 132, 707, 133, 706,
143, 696, 135, 704, 161, 678, 201, 638, 173, 666, 106, 733,
83, 756, 91, 748, 66, 773, 53, 786, 10, 829, 9, 830,
7, 832, 8, 831, 16, 823, 47, 792, 64, 775, 57, 782,
104, 735, 101, 738, 108, 731, 208, 631, 184, 655, 197, 642,
191, 648, 121, 718, 141, 698, 149, 690, 216, 623, 218, 621,
152, 687, 144, 695, 134, 705, 138, 701, 199, 640, 162, 677,
176, 663, 119, 720, 158, 681, 164, 675, 174, 665, 171, 668,
170, 669, 87, 752, 169, 670, 88, 751, 107, 732, 81, 758,
82, 757, 100, 739, 98, 741, 71, 768, 59, 780, 65, 774,
50, 789, 49, 790, 26, 813, 17, 822, 13, 826, 6, 833,
5, 834, 33, 806, 51, 788, 75, 764, 99, 740, 96, 743,
97, 742, 166, 673, 172, 667, 175, 664, 187, 652, 163, 676,
185, 654, 200, 639, 114, 725, 189, 650, 115, 724, 194, 645,
195, 644, 192, 647, 182, 657, 157, 682, 156, 683, 211, 628,
154, 685, 123, 716, 139, 700, 212, 627, 153, 686, 213, 626,
215, 624, 150, 689, 225, 614, 224, 615, 221, 618, 220, 619,
127, 712, 147, 692, 124, 715, 193, 646, 205, 634, 206, 633,
116, 723, 160, 679, 186, 653, 167, 672, 79, 760, 85, 754,
77, 762, 92, 747, 58, 781, 62, 777, 69, 770, 54, 785,
36, 803, 32, 807, 25, 814, 18, 821, 11, 828, 4, 835,
3, 836, 19, 820, 22, 817, 41, 798, 38, 801, 44, 795,
52, 787, 45, 794, 63, 776, 67, 772, 72, 767, 76, 763,
94, 745, 102, 737, 90, 749, 109, 730, 165, 674, 111, 728,
209, 630, 204, 635, 117, 722, 188, 651, 159, 680, 198, 641,
113, 726, 183, 656, 180, 659, 177, 662, 196, 643, 155, 684,
214, 625, 126, 713, 131, 708, 219, 620, 222, 617, 226, 613,
230, 609, 232, 607, 262, 577, 252, 587, 418, 421, 416, 423,
413, 426, 411, 428, 376, 463, 395, 444, 283, 556, 285, 554,
379, 460, 390, 449, 363, 476, 384, 455, 388, 451, 386, 453,
361, 478, 387, 452, 360, 479, 310, 529, 354, 485, 328, 511,
315, 524, 337, 502, 349, 490, 335, 504, 324, 515, 323, 516,
320, 519, 334, 505, 359, 480, 295, 544, 385, 454, 292, 547,
291, 548, 381, 458, 399, 440, 380, 459, 397, 442, 369, 470,
377, 462, 410, 429, 407, 432, 281, 558, 414, 425, 247, 592,
277, 562, 271, 568, 272, 567, 264, 575, 259, 580, 237, 602,
239, 600, 244, 595, 243, 596, 275, 564, 278, 561, 250, 589,
246, 593, 417, 422, 248, 591, 394, 445, 393, 446, 370, 469,
365, 474, 300, 539, 299, 540, 364, 475, 362, 477, 298, 541,
312, 527, 313, 526, 314, 525, 353, 486, 352, 487, 343, 496,
327, 512, 350, 489, 326, 513, 319, 520, 332, 507, 333, 506,
348, 491, 347, 492, 322, 517, 330, 509, 338, 501, 341, 498,
340, 499, 342, 497, 301, 538, 366, 473, 401, 438, 371, 468,
408, 431, 375, 464, 249, 590, 269, 570, 238, 601, 234, 605,
257, 582, 273, 566, 255, 584, 254, 585, 245, 594, 251, 588,
412, 427, 372, 467, 282, 557, 403, 436, 396, 443, 392, 447,
391, 448, 382, 457, 389, 450, 294, 545, 297, 542, 311, 528,
344, 495, 345, 494, 318, 521, 331, 508, 325, 514, 321, 518,
346, 493, 339, 500, 351, 488, 306, 533, 289, 550, 400, 439,
378, 461, 374, 465, 415, 424, 270, 569, 241, 598, 231, 608,
260, 579, 268, 571, 276, 563, 409, 430, 398, 441, 290, 549,
304, 535, 308, 531, 358, 481, 316, 523, 293, 546, 288, 551,
284, 555, 368, 471, 253, 586, 256, 583, 263, 576, 242, 597,
274, 565, 402, 437, 383, 456, 357, 482, 329, 510, 317, 522,
307, 532, 286, 553, 287, 552, 266, 573, 261, 578, 236, 603,
303, 536, 356, 483, 355, 484, 405, 434, 404, 435, 406, 433,
235, 604, 267, 572, 302, 537, 309, 530, 265, 574, 233, 606,
367, 472, 296, 543, 336, 503, 305, 534, 373, 466, 280, 559,
279, 560, 419, 420, 240, 599, 258, 581, 229, 610};
129, 710, 140, 699, 120, 719, 210, 629, 168, 671, 84, 755,
105, 734, 93, 746, 70, 769, 60, 779, 2, 837, 1, 838,
56, 783, 112, 727, 148, 691, 80, 759, 42, 797, 40, 799,
35, 804, 73, 766, 146, 693, 31, 808, 28, 811, 30, 809,
27, 812, 29, 810, 24, 815, 48, 791, 68, 771, 74, 765,
178, 661, 136, 703, 86, 753, 78, 761, 43, 796, 39, 800,
20, 819, 21, 818, 95, 744, 202, 637, 190, 649, 181, 658,
137, 702, 125, 714, 151, 688, 217, 622, 128, 711, 142, 697,
122, 717, 203, 636, 118, 721, 110, 729, 89, 750, 103, 736,
61, 778, 55, 784, 15, 824, 14, 825, 12, 827, 23, 816,
34, 805, 37, 802, 46, 793, 207, 632, 179, 660, 145, 694,
130, 709, 223, 616, 228, 611, 227, 612, 132, 707, 133, 706,
143, 696, 135, 704, 161, 678, 201, 638, 173, 666, 106, 733,
83, 756, 91, 748, 66, 773, 53, 786, 10, 829, 9, 830,
7, 832, 8, 831, 16, 823, 47, 792, 64, 775, 57, 782,
104, 735, 101, 738, 108, 731, 208, 631, 184, 655, 197, 642,
191, 648, 121, 718, 141, 698, 149, 690, 216, 623, 218, 621,
152, 687, 144, 695, 134, 705, 138, 701, 199, 640, 162, 677,
176, 663, 119, 720, 158, 681, 164, 675, 174, 665, 171, 668,
170, 669, 87, 752, 169, 670, 88, 751, 107, 732, 81, 758,
82, 757, 100, 739, 98, 741, 71, 768, 59, 780, 65, 774,
50, 789, 49, 790, 26, 813, 17, 822, 13, 826, 6, 833,
5, 834, 33, 806, 51, 788, 75, 764, 99, 740, 96, 743,
97, 742, 166, 673, 172, 667, 175, 664, 187, 652, 163, 676,
185, 654, 200, 639, 114, 725, 189, 650, 115, 724, 194, 645,
195, 644, 192, 647, 182, 657, 157, 682, 156, 683, 211, 628,
154, 685, 123, 716, 139, 700, 212, 627, 153, 686, 213, 626,
215, 624, 150, 689, 225, 614, 224, 615, 221, 618, 220, 619,
127, 712, 147, 692, 124, 715, 193, 646, 205, 634, 206, 633,
116, 723, 160, 679, 186, 653, 167, 672, 79, 760, 85, 754,
77, 762, 92, 747, 58, 781, 62, 777, 69, 770, 54, 785,
36, 803, 32, 807, 25, 814, 18, 821, 11, 828, 4, 835,
3, 836, 19, 820, 22, 817, 41, 798, 38, 801, 44, 795,
52, 787, 45, 794, 63, 776, 67, 772, 72, 767, 76, 763,
94, 745, 102, 737, 90, 749, 109, 730, 165, 674, 111, 728,
209, 630, 204, 635, 117, 722, 188, 651, 159, 680, 198, 641,
113, 726, 183, 656, 180, 659, 177, 662, 196, 643, 155, 684,
214, 625, 126, 713, 131, 708, 219, 620, 222, 617, 226, 613,
230, 609, 232, 607, 262, 577, 252, 587, 418, 421, 416, 423,
413, 426, 411, 428, 376, 463, 395, 444, 283, 556, 285, 554,
379, 460, 390, 449, 363, 476, 384, 455, 388, 451, 386, 453,
361, 478, 387, 452, 360, 479, 310, 529, 354, 485, 328, 511,
315, 524, 337, 502, 349, 490, 335, 504, 324, 515, 323, 516,
320, 519, 334, 505, 359, 480, 295, 544, 385, 454, 292, 547,
291, 548, 381, 458, 399, 440, 380, 459, 397, 442, 369, 470,
377, 462, 410, 429, 407, 432, 281, 558, 414, 425, 247, 592,
277, 562, 271, 568, 272, 567, 264, 575, 259, 580, 237, 602,
239, 600, 244, 595, 243, 596, 275, 564, 278, 561, 250, 589,
246, 593, 417, 422, 248, 591, 394, 445, 393, 446, 370, 469,
365, 474, 300, 539, 299, 540, 364, 475, 362, 477, 298, 541,
312, 527, 313, 526, 314, 525, 353, 486, 352, 487, 343, 496,
327, 512, 350, 489, 326, 513, 319, 520, 332, 507, 333, 506,
348, 491, 347, 492, 322, 517, 330, 509, 338, 501, 341, 498,
340, 499, 342, 497, 301, 538, 366, 473, 401, 438, 371, 468,
408, 431, 375, 464, 249, 590, 269, 570, 238, 601, 234, 605,
257, 582, 273, 566, 255, 584, 254, 585, 245, 594, 251, 588,
412, 427, 372, 467, 282, 557, 403, 436, 396, 443, 392, 447,
391, 448, 382, 457, 389, 450, 294, 545, 297, 542, 311, 528,
344, 495, 345, 494, 318, 521, 331, 508, 325, 514, 321, 518,
346, 493, 339, 500, 351, 488, 306, 533, 289, 550, 400, 439,
378, 461, 374, 465, 415, 424, 270, 569, 241, 598, 231, 608,
260, 579, 268, 571, 276, 563, 409, 430, 398, 441, 290, 549,
304, 535, 308, 531, 358, 481, 316, 523, 293, 546, 288, 551,
284, 555, 368, 471, 253, 586, 256, 583, 263, 576, 242, 597,
274, 565, 402, 437, 383, 456, 357, 482, 329, 510, 317, 522,
307, 532, 286, 553, 287, 552, 266, 573, 261, 578, 236, 603,
303, 536, 356, 483, 355, 484, 405, 434, 404, 435, 406, 433,
235, 604, 267, 572, 302, 537, 309, 530, 265, 574, 233, 606,
367, 472, 296, 543, 336, 503, 305, 534, 373, 466, 280, 559,
279, 560, 419, 420, 240, 599, 258, 581, 229, 610};
// Table 5.7.2-5 - Root ZC sequence order for preamble format 4
uint32_t prach_zc_roots_format4[138] = {
1, 138, 2, 137, 3, 136, 4, 135, 5, 134, 6, 133,
7, 132, 8, 131, 9, 130, 10, 129, 11, 128, 12, 127,
13, 126, 14, 125, 15, 124, 16, 123, 17, 122, 18, 121,
19, 120, 20, 119, 21, 118, 22, 117, 23, 116, 24, 115,
25, 114, 26, 113, 27, 112, 28, 111, 29, 110, 30, 109,
31, 108, 32, 107, 33, 106, 34, 105, 35, 104, 36, 103,
37, 102, 38, 101, 39, 100, 40, 99, 41, 98, 42, 97,
43, 96, 44, 95, 45, 94, 46, 93, 47, 92, 48, 91,
49, 90, 50, 89, 51, 88, 52, 87, 53, 86, 54, 85,
55, 84, 56, 83, 57, 82, 58, 81, 59, 80, 60, 79,
61, 78, 62, 77, 63, 76, 64, 75, 65, 74, 66, 73,
67, 72, 68, 71, 69, 70};
1, 138, 2, 137, 3, 136, 4, 135, 5, 134, 6, 133,
7, 132, 8, 131, 9, 130, 10, 129, 11, 128, 12, 127,
13, 126, 14, 125, 15, 124, 16, 123, 17, 122, 18, 121,
19, 120, 20, 119, 21, 118, 22, 117, 23, 116, 24, 115,
25, 114, 26, 113, 27, 112, 28, 111, 29, 110, 30, 109,
31, 108, 32, 107, 33, 106, 34, 105, 35, 104, 36, 103,
37, 102, 38, 101, 39, 100, 40, 99, 41, 98, 42, 97,
43, 96, 44, 95, 45, 94, 46, 93, 47, 92, 48, 91,
49, 90, 50, 89, 51, 88, 52, 87, 53, 86, 54, 85,
55, 84, 56, 83, 57, 82, 58, 81, 59, 80, 60, 79,
61, 78, 62, 77, 63, 76, 64, 75, 65, 74, 66, 73,
67, 72, 68, 71, 69, 70};
srslte_prach_sf_config_t prach_sf_config[16] = {
{1, {1, 0, 0, 0, 0}},
{1, {4, 0, 0, 0, 0}},
{1, {7, 0, 0, 0, 0}},
{1, {1, 0, 0, 0, 0}},
{1, {4, 0, 0, 0, 0}},
{1, {7, 0, 0, 0, 0}},
{2, {1, 6, 0, 0, 0}},
{2, {2, 7, 0, 0, 0}},
{2, {3, 8, 0, 0, 0}},
{3, {1, 4, 7, 0, 0}},
{3, {2, 5, 8, 0, 0}},
{3, {3, 6, 9, 0, 0}},
{5, {0, 2, 4, 6, 8}},
{5, {1, 3, 5, 7, 9}},
{-1, {0, 0, 0, 0, 0}}, // this means all subframes
{1, {9, 0, 0, 0, 0}}};
{1, {1, 0, 0, 0, 0}},
{1, {4, 0, 0, 0, 0}},
{1, {7, 0, 0, 0, 0}},
{1, {1, 0, 0, 0, 0}},
{1, {4, 0, 0, 0, 0}},
{1, {7, 0, 0, 0, 0}},
{2, {1, 6, 0, 0, 0}},
{2, {2, 7, 0, 0, 0}},
{2, {3, 8, 0, 0, 0}},
{3, {1, 4, 7, 0, 0}},
{3, {2, 5, 8, 0, 0}},
{3, {3, 6, 9, 0, 0}},
{5, {0, 2, 4, 6, 8}},
{5, {1, 3, 5, 7, 9}},
{-1, {0, 0, 0, 0, 0}}, // this means all subframes
{1, {9, 0, 0, 0, 0}}};
uint32_t srslte_prach_get_preamble_format(uint32_t config_idx) {
return config_idx/16;
return config_idx / 16;
}
srslte_prach_sfn_t srslte_prach_get_sfn(uint32_t config_idx) {
if ((config_idx%16)<3 || (config_idx%16)==15) {
if ((config_idx % 16) < 3 || (config_idx % 16) == 15) {
return SRSLTE_PRACH_SFN_EVEN;
} else {
return SRSLTE_PRACH_SFN_ANY;
return SRSLTE_PRACH_SFN_ANY;
}
}
/* Returns true if current_tti is a valid opportunity for PRACH transmission and the is an allowed subframe,
* or allowed_subframe == -1
*/
bool srslte_prach_tti_opportunity(srslte_prach_t *p, uint32_t current_tti, int allowed_subframe)
{
uint32_t config_idx = p->config_idx;
bool srslte_prach_tti_opportunity(srslte_prach_t *p, uint32_t current_tti, int allowed_subframe) {
uint32_t config_idx = p->config_idx;
// Get SFN and sf_idx from the PRACH configuration index
srslte_prach_sfn_t prach_sfn = srslte_prach_get_sfn(config_idx);
srslte_prach_sfn_t prach_sfn = srslte_prach_get_sfn(config_idx);
// This is the only option which provides always an opportunity for PRACH transmission.
if(config_idx == 14) {
if (config_idx == 14) {
return true;
}
if ((prach_sfn == SRSLTE_PRACH_SFN_EVEN && ((current_tti/10)%2)==0) ||
prach_sfn == SRSLTE_PRACH_SFN_ANY)
{
if ((prach_sfn == SRSLTE_PRACH_SFN_EVEN && ((current_tti / 10) % 2) == 0) ||
prach_sfn == SRSLTE_PRACH_SFN_ANY) {
srslte_prach_sf_config_t sf_config;
srslte_prach_sf_config(config_idx, &sf_config);
for (int i=0;i<sf_config.nof_sf;i++) {
if (((current_tti%10) == sf_config.sf[i] && allowed_subframe == -1) ||
((current_tti%10) == sf_config.sf[i] && (current_tti%10) == allowed_subframe))
{
return true;
for (int i = 0; i < sf_config.nof_sf; i++) {
if (((current_tti % 10) == sf_config.sf[i] && allowed_subframe == -1) ||
((current_tti % 10) == sf_config.sf[i] && (current_tti % 10) == allowed_subframe)) {
return true;
}
}
}
return false;
return false;
}
void srslte_prach_sf_config(uint32_t config_idx, srslte_prach_sf_config_t *sf_config) {
memcpy(sf_config, &prach_sf_config[config_idx%16], sizeof(srslte_prach_sf_config_t));
memcpy(sf_config, &prach_sf_config[config_idx % 16], sizeof(srslte_prach_sf_config_t));
}
// For debug use only
void print(void *d, uint32_t size, uint32_t len, char* file_str)
{
void print(void *d, uint32_t size, uint32_t len, char *file_str) {
FILE *f;
f = fopen(file_str, "wb");
fwrite(d , size, len, f);
fwrite(d, size, len, f);
fclose(f);
}
int srslte_prach_gen_seqs(srslte_prach_t *p)
{
int srslte_prach_gen_seqs(srslte_prach_t *p) {
uint32_t u = 0;
uint32_t v = 1;
int v_max = 0;
@ -243,85 +235,91 @@ int srslte_prach_gen_seqs(srslte_prach_t *p)
uint32_t d_u = 0;
uint32_t d_start = 0;
uint32_t N_shift = 0;
int N_neg_shift = 0;
int N_neg_shift = 0;
uint32_t N_group = 0;
uint32_t C_v = 0;
cf_t root[839];
// Generate our 64 preamble sequences
for(int i=0;i<N_SEQS;i++){
for (int i = 0; i < N_SEQS; i++) {
if(v > v_max){
if (v > v_max) {
// Get a new root sequence
if(4 == p->f){
u = prach_zc_roots_format4[(p->rsi + p->N_roots)%138];
}else{
u = prach_zc_roots[(p->rsi + p->N_roots)%838];
if (4 == p->f) {
u = prach_zc_roots_format4[(p->rsi + p->N_roots) % 138];
} else {
u = prach_zc_roots[(p->rsi + p->N_roots) % 838];
}
for(int j=0;j<p->N_zc;j++){
double phase = -M_PI*u*j*(j+1)/p->N_zc;
root[j] = cexp(phase*I);
for (int j = 0; j < p->N_zc; j++) {
double phase = -M_PI * u * j * (j + 1) / p->N_zc;
root[j] = cexp(phase * I);
}
p->root_seqs_idx[p->N_roots++] = i;
// Determine v_max
if(p->hs){
if (p->hs) {
// High-speed cell
for(p_=1; p_<=p->N_zc; p_++){
if(((p_*u) % p->N_zc) == 1)
break;
for (p_ = 1; p_ <= p->N_zc; p_++) {
if (((p_ * u) % p->N_zc) == 1)
break;
}
if(p_ < p->N_zc/2){
d_u = p_;
}else{
d_u = p->N_zc - p_;
if (p_ < p->N_zc / 2) {
d_u = p_;
} else {
d_u = p->N_zc - p_;
}
if(d_u >= p->N_cs && d_u < p->N_zc/3){
N_shift = d_u/p->N_cs;
d_start = 2*d_u + N_shift*p->N_cs;
N_group = p->N_zc/d_start;
N_neg_shift = (p->N_zc - 2*d_u - N_group*d_start)/p->N_cs;
if(N_neg_shift < 0)
N_neg_shift = 0;
}else{
N_shift = (p->N_zc - 2*d_u)/p->N_cs;
d_start = p->N_zc - 2*d_u + N_shift*p->N_cs;
N_group = d_u/d_start;
N_neg_shift = (d_u - N_group*d_start)/p->N_cs;
if(N_neg_shift < 0)
N_neg_shift = 0;
if(N_neg_shift > N_shift)
N_neg_shift = N_shift;
if (d_u >= p->N_cs && d_u < p->N_zc / 3) {
N_shift = d_u / p->N_cs;
d_start = 2 * d_u + N_shift * p->N_cs;
N_group = p->N_zc / d_start;
if (p->N_zc > 2 * d_u + N_group * d_start) {
N_neg_shift = (p->N_zc - 2 * d_u - N_group * d_start) / p->N_cs;
} else {
N_neg_shift = 0;
}
} else if (p->N_zc / 3 <= d_u && d_u <= (p->N_zc - p->N_cs) / 2) {
N_shift = (p->N_zc - 2 * d_u) / p->N_cs;
d_start = p->N_zc - 2 * d_u + N_shift * p->N_cs;
N_group = d_u / d_start;
if (d_u > N_group * d_start) {
N_neg_shift = (d_u - N_group * d_start) / p->N_cs;
} else {
N_neg_shift = 0;
}
if (N_neg_shift > N_shift)
N_neg_shift = N_shift;
} else {
N_shift = 0;
}
v_max = N_shift*N_group + N_neg_shift - 1;
if(v_max < 0){
v_max = N_shift * N_group + N_neg_shift - 1;
if (v_max < 0) {
v_max = 0;
}
}else{
} else {
// Normal cell
if(0 == p->N_cs){
if (0 == p->N_cs) {
v_max = 0;
}else{
v_max = (p->N_zc/p->N_cs)-1;
} else {
v_max = (p->N_zc / p->N_cs) - 1;
}
}
v=0;
v = 0;
}
// Shift root and add to set
if(p->hs){
if(N_shift==0){
if (p->hs) {
if (N_shift == 0) {
C_v = 0;
}else{
C_v = d_start*floor(v/N_shift) + (v % N_shift)*p->N_cs;
} else {
C_v = d_start * floor(v / N_shift) + (v % N_shift) * p->N_cs;
}
}else{
C_v = v*p->N_cs;
} else {
C_v = v * p->N_cs;
}
for(int j=0;j<p->N_zc;j++){
p->seqs[i][j] = root[(j+C_v) % p->N_zc];
for (int j = 0; j < p->N_zc; j++) {
p->seqs[i][j] = root[(j + C_v) % p->N_zc];
}
v++;
@ -329,69 +327,66 @@ int srslte_prach_gen_seqs(srslte_prach_t *p)
return 0;
}
int srslte_prach_init_cfg(srslte_prach_t *p, srslte_prach_cfg_t *cfg, uint32_t nof_prb)
{
int srslte_prach_init_cfg(srslte_prach_t *p, srslte_prach_cfg_t *cfg, uint32_t nof_prb) {
if (srslte_prach_init(p, srslte_symbol_sz(nof_prb))) {
return -1;
}
return srslte_prach_set_cell(p,
srslte_symbol_sz(nof_prb),
cfg->config_idx,
cfg->root_seq_idx,
cfg->hs_flag,
cfg->zero_corr_zone);
srslte_symbol_sz(nof_prb),
cfg->config_idx,
cfg->root_seq_idx,
cfg->hs_flag,
cfg->zero_corr_zone);
}
int srslte_prach_init(srslte_prach_t *p, uint32_t max_N_ifft_ul)
{
int srslte_prach_init(srslte_prach_t *p, uint32_t max_N_ifft_ul) {
int ret = SRSLTE_ERROR;
if(p != NULL &&
max_N_ifft_ul < 2049)
{
if (p != NULL &&
max_N_ifft_ul < 2049) {
bzero(p, sizeof(srslte_prach_t));
p->max_N_ifft_ul = max_N_ifft_ul;
// Set up containers
p->prach_bins = srslte_vec_malloc(sizeof(cf_t)*MAX_N_zc);
p->corr_spec = srslte_vec_malloc(sizeof(cf_t)*MAX_N_zc);
p->corr = srslte_vec_malloc(sizeof(float)*MAX_N_zc);
p->prach_bins = srslte_vec_malloc(sizeof(cf_t) * MAX_N_zc);
p->corr_spec = srslte_vec_malloc(sizeof(cf_t) * MAX_N_zc);
p->corr = srslte_vec_malloc(sizeof(float) * MAX_N_zc);
// Set up ZC FFTS
if(srslte_dft_plan(&p->zc_fft, MAX_N_zc, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)){
if (srslte_dft_plan(&p->zc_fft, MAX_N_zc, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) {
return SRSLTE_ERROR;
}
srslte_dft_plan_set_mirror(&p->zc_fft, false);
srslte_dft_plan_set_norm(&p->zc_fft, true);
if(srslte_dft_plan(&p->zc_ifft, MAX_N_zc, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)){
if (srslte_dft_plan(&p->zc_ifft, MAX_N_zc, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) {
return SRSLTE_ERROR;
}
srslte_dft_plan_set_mirror(&p->zc_ifft, false);
srslte_dft_plan_set_norm(&p->zc_ifft, false);
uint32_t fft_size_alloc = max_N_ifft_ul * DELTA_F/DELTA_F_RA;
uint32_t fft_size_alloc = max_N_ifft_ul * DELTA_F / DELTA_F_RA;
p->ifft_in = (cf_t*)srslte_vec_malloc(fft_size_alloc*sizeof(cf_t));
p->ifft_out = (cf_t*)srslte_vec_malloc(fft_size_alloc*sizeof(cf_t));
if(srslte_dft_plan(&p->ifft, fft_size_alloc, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) {
p->ifft_in = (cf_t *) srslte_vec_malloc(fft_size_alloc * sizeof(cf_t));
p->ifft_out = (cf_t *) srslte_vec_malloc(fft_size_alloc * sizeof(cf_t));
if (srslte_dft_plan(&p->ifft, fft_size_alloc, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) {
fprintf(stderr, "Error creating DFT plan\n");
return -1;
}
srslte_dft_plan_set_mirror(&p->ifft, true);
srslte_dft_plan_set_norm(&p->ifft, true);
if(srslte_dft_plan(&p->fft, fft_size_alloc, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)){
if (srslte_dft_plan(&p->fft, fft_size_alloc, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) {
fprintf(stderr, "Error creating DFT plan\n");
return -1;
}
p->signal_fft = srslte_vec_malloc(sizeof(cf_t)*fft_size_alloc);
p->signal_fft = srslte_vec_malloc(sizeof(cf_t) * fft_size_alloc);
if (!p->signal_fft) {
fprintf(stderr, "Error allocating memory\n");
return -1;
return -1;
}
srslte_dft_plan_set_mirror(&p->fft, true);
srslte_dft_plan_set_norm(&p->fft, false);
@ -403,20 +398,17 @@ int srslte_prach_init(srslte_prach_t *p, uint32_t max_N_ifft_ul)
return ret;
}
int srslte_prach_set_cell(srslte_prach_t *p,
uint32_t N_ifft_ul,
uint32_t config_idx,
uint32_t root_seq_index,
bool high_speed_flag,
uint32_t zero_corr_zone_config)
{
uint32_t N_ifft_ul,
uint32_t config_idx,
uint32_t root_seq_index,
bool high_speed_flag,
uint32_t zero_corr_zone_config) {
int ret = SRSLTE_ERROR;
if(p != NULL &&
N_ifft_ul < 2049 &&
config_idx < 64 &&
root_seq_index < MAX_ROOTS)
{
if (p != NULL &&
N_ifft_ul < 2049 &&
config_idx < 64 &&
root_seq_index < MAX_ROOTS) {
if (N_ifft_ul > p->max_N_ifft_ul) {
fprintf(stderr, "PRACH: Error in set_cell(): N_ifft_ul must be lower or equal max_N_ifft_ul in init()\n");
return -1;
@ -432,7 +424,7 @@ int srslte_prach_set_cell(srslte_prach_t *p,
// Determine N_zc and N_cs
if(4 == preamble_format){
if (4 == preamble_format) {
if (p->zczc < 7) {
p->N_zc = 139;
p->N_cs = prach_Ncs_format4[p->zczc];
@ -440,16 +432,16 @@ int srslte_prach_set_cell(srslte_prach_t *p,
fprintf(stderr, "Invalid zeroCorrelationZoneConfig=%d for format4\n", p->zczc);
return SRSLTE_ERROR;
}
}else{
} else {
p->N_zc = MAX_N_zc;
if(p->hs){
if (p->hs) {
if (p->zczc < 15) {
p->N_cs = prach_Ncs_restricted[p->zczc];
} else {
fprintf(stderr, "Invalid zeroCorrelationZoneConfig=%d for restricted set\n", p->zczc);
return SRSLTE_ERROR;
}
}else{
} else {
if (p->zczc < 16) {
p->N_cs = prach_Ncs_unrestricted[p->zczc];
} else {
@ -461,10 +453,10 @@ int srslte_prach_set_cell(srslte_prach_t *p,
// Set up ZC FFTS
if (p->N_zc != MAX_N_zc) {
if(srslte_dft_replan(&p->zc_fft, p->N_zc)){
if (srslte_dft_replan(&p->zc_fft, p->N_zc)) {
return SRSLTE_ERROR;
}
if(srslte_dft_replan(&p->zc_ifft, p->N_zc)){
if (srslte_dft_replan(&p->zc_ifft, p->N_zc)) {
return SRSLTE_ERROR;
}
}
@ -474,16 +466,16 @@ int srslte_prach_set_cell(srslte_prach_t *p,
srslte_prach_gen_seqs(p);
// Generate sequence FFTs
for(int i=0;i<N_SEQS;i++){
for (int i = 0; i < N_SEQS; i++) {
srslte_dft_run(&p->zc_fft, p->seqs[i], p->dft_seqs[i]);
}
// Create our FFT objects and buffers
p->N_ifft_ul = N_ifft_ul;
if(4 == preamble_format){
p->N_ifft_prach = p->N_ifft_ul * DELTA_F/DELTA_F_RA_4;
}else{
p->N_ifft_prach = p->N_ifft_ul * DELTA_F/DELTA_F_RA;
if (4 == preamble_format) {
p->N_ifft_prach = p->N_ifft_ul * DELTA_F / DELTA_F_RA_4;
} else {
p->N_ifft_prach = p->N_ifft_ul * DELTA_F / DELTA_F_RA;
}
/* The deadzone specifies the number of samples at the end of the correlation window
@ -496,19 +488,19 @@ int srslte_prach_set_cell(srslte_prach_t *p,
p->deadzone = (uint32_t) ceil((float) samp_rate/((float) p->N_zc*subcarrier_spacing));
}*/
if(srslte_dft_replan(&p->ifft, p->N_ifft_prach)) {
if (srslte_dft_replan(&p->ifft, p->N_ifft_prach)) {
fprintf(stderr, "Error creating DFT plan\n");
return -1;
}
if(srslte_dft_replan(&p->fft, p->N_ifft_prach)){
if (srslte_dft_replan(&p->fft, p->N_ifft_prach)) {
fprintf(stderr, "Error creating DFT plan\n");
return -1;
}
p->N_seq = prach_Tseq[p->f]*p->N_ifft_ul/2048;
p->N_cp = prach_Tcp[p->f]*p->N_ifft_ul/2048;
p->T_seq = prach_Tseq[p->f]*SRSLTE_LTE_TS;
p->T_tot = (prach_Tseq[p->f]+prach_Tcp[p->f])*SRSLTE_LTE_TS;
p->N_seq = prach_Tseq[p->f] * p->N_ifft_ul / 2048;
p->N_cp = prach_Tcp[p->f] * p->N_ifft_ul / 2048;
p->T_seq = prach_Tseq[p->f] * SRSLTE_LTE_TS;
p->T_tot = (prach_Tseq[p->f] + prach_Tcp[p->f]) * SRSLTE_LTE_TS;
ret = SRSLTE_SUCCESS;
} else {
@ -519,44 +511,42 @@ int srslte_prach_set_cell(srslte_prach_t *p,
}
int srslte_prach_gen(srslte_prach_t *p,
uint32_t seq_index,
uint32_t freq_offset,
cf_t *signal)
{
uint32_t seq_index,
uint32_t freq_offset,
cf_t *signal) {
int ret = SRSLTE_ERROR;
if(p != NULL &&
seq_index < N_SEQS &&
signal != NULL)
{
if (p != NULL &&
seq_index < N_SEQS &&
signal != NULL) {
// Calculate parameters
uint32_t N_rb_ul = srslte_nof_prb(p->N_ifft_ul);
uint32_t k_0 = freq_offset*N_RB_SC - N_rb_ul*N_RB_SC/2 + p->N_ifft_ul/2;
uint32_t K = DELTA_F/DELTA_F_RA;
uint32_t begin = PHI + (K*k_0) + (K/2);
uint32_t k_0 = freq_offset * N_RB_SC - N_rb_ul * N_RB_SC / 2 + p->N_ifft_ul / 2;
uint32_t K = DELTA_F / DELTA_F_RA;
uint32_t begin = PHI + (K * k_0) + (K / 2);
if (6 + freq_offset > N_rb_ul) {
fprintf(stderr, "Error no space for PRACH: frequency offset=%d, N_rb_ul=%d\n", freq_offset, N_rb_ul);
return ret;
return ret;
}
DEBUG("N_zc: %d, N_cp: %d, N_seq: %d, N_ifft_prach=%d begin: %d\n",
DEBUG("N_zc: %d, N_cp: %d, N_seq: %d, N_ifft_prach=%d begin: %d\n",
p->N_zc, p->N_cp, p->N_seq, p->N_ifft_prach, begin);
// Map dft-precoded sequence to ifft bins
memset(p->ifft_in, 0, begin*sizeof(cf_t));
memset(p->ifft_in, 0, begin * sizeof(cf_t));
memcpy(&p->ifft_in[begin], p->dft_seqs[seq_index], p->N_zc * sizeof(cf_t));
memset(&p->ifft_in[begin+p->N_zc], 0, (p->N_ifft_prach - begin - p->N_zc) * sizeof(cf_t));
memset(&p->ifft_in[begin + p->N_zc], 0, (p->N_ifft_prach - begin - p->N_zc) * sizeof(cf_t));
srslte_dft_run(&p->ifft, p->ifft_in, p->ifft_out);
// Copy CP into buffer
memcpy(signal, &p->ifft_out[p->N_ifft_prach-p->N_cp], p->N_cp*sizeof(cf_t));
memcpy(signal, &p->ifft_out[p->N_ifft_prach - p->N_cp], p->N_cp * sizeof(cf_t));
// Copy preamble sequence into buffer
for(int i=0;i<p->N_seq;i++){
signal[p->N_cp+i] = p->ifft_out[i%p->N_ifft_prach];
for (int i = 0; i < p->N_seq; i++) {
signal[p->N_cp + i] = p->ifft_out[i % p->N_ifft_prach];
}
ret = SRSLTE_SUCCESS;
}
@ -564,7 +554,7 @@ int srslte_prach_gen(srslte_prach_t *p,
}
void srslte_prach_set_detect_factor(srslte_prach_t *p, float ratio) {
p->detect_factor = ratio;
p->detect_factor = ratio;
}
int srslte_prach_detect(srslte_prach_t *p,
@ -572,8 +562,7 @@ int srslte_prach_detect(srslte_prach_t *p,
cf_t *signal,
uint32_t sig_len,
uint32_t *indices,
uint32_t *n_indices)
{
uint32_t *n_indices) {
return srslte_prach_detect_offset(p, freq_offset, signal, sig_len, indices, NULL, NULL, n_indices);
}
@ -583,21 +572,19 @@ int srslte_prach_detect_offset(srslte_prach_t *p,
uint32_t sig_len,
uint32_t *indices,
float *t_offsets,
float *peak_to_avg,
uint32_t *n_indices)
{
float *peak_to_avg,
uint32_t *n_indices) {
int ret = SRSLTE_ERROR;
if(p != NULL &&
signal != NULL &&
sig_len > 0 &&
indices != NULL)
{
if(sig_len < p->N_ifft_prach){
if (p != NULL &&
signal != NULL &&
sig_len > 0 &&
indices != NULL) {
if (sig_len < p->N_ifft_prach) {
fprintf(stderr, "srslte_prach_detect: Signal length is %d and should be %d\n", sig_len, p->N_ifft_prach);
return SRSLTE_ERROR_INVALID_INPUTS;
}
// FFT incoming signal
srslte_dft_run(&p->fft, signal, p->signal_fft);
@ -605,66 +592,65 @@ int srslte_prach_detect_offset(srslte_prach_t *p,
// Extract bins of interest
uint32_t N_rb_ul = srslte_nof_prb(p->N_ifft_ul);
uint32_t k_0 = freq_offset*N_RB_SC - N_rb_ul*N_RB_SC/2 + p->N_ifft_ul/2;
uint32_t K = DELTA_F/DELTA_F_RA;
uint32_t begin = PHI + (K*k_0) + (K/2);
uint32_t k_0 = freq_offset * N_RB_SC - N_rb_ul * N_RB_SC / 2 + p->N_ifft_ul / 2;
uint32_t K = DELTA_F / DELTA_F_RA;
uint32_t begin = PHI + (K * k_0) + (K / 2);
memcpy(p->prach_bins, &p->signal_fft[begin], p->N_zc*sizeof(cf_t));
for(int i=0;i<p->N_roots;i++){
memcpy(p->prach_bins, &p->signal_fft[begin], p->N_zc * sizeof(cf_t));
for (int i = 0; i < p->N_roots; i++) {
cf_t *root_spec = p->dft_seqs[p->root_seqs_idx[i]];
srslte_vec_prod_conj_ccc(p->prach_bins, root_spec, p->corr_spec, p->N_zc);
srslte_dft_run(&p->zc_ifft, p->corr_spec, p->corr_spec);
srslte_vec_abs_square_cf(p->corr_spec, p->corr, p->N_zc);
float corr_ave = srslte_vec_acc_ff(p->corr, p->N_zc)/p->N_zc;
float corr_ave = srslte_vec_acc_ff(p->corr, p->N_zc) / p->N_zc;
uint32_t winsize = 0;
if(p->N_cs != 0){
if (p->N_cs != 0) {
winsize = p->N_cs;
}else{
} else {
winsize = p->N_zc;
}
uint32_t n_wins = p->N_zc/winsize;
float max_peak = 0;
for(int j=0;j<n_wins;j++) {
uint32_t start = (p->N_zc-(j*p->N_cs))%p->N_zc;
uint32_t end = start+winsize;
if (end>p->deadzone) {
end-=p->deadzone;
uint32_t n_wins = p->N_zc / winsize;
float max_peak = 0;
for (int j = 0; j < n_wins; j++) {
uint32_t start = (p->N_zc - (j * p->N_cs)) % p->N_zc;
uint32_t end = start + winsize;
if (end > p->deadzone) {
end -= p->deadzone;
}
start += p->deadzone;
p->peak_values[j] = 0;
for(int k=start;k<end;k++) {
if(p->corr[k] > p->peak_values[j]) {
p->peak_values[j] = p->corr[k];
p->peak_offsets[j] = k-start;
for (int k = start; k < end; k++) {
if (p->corr[k] > p->peak_values[j]) {
p->peak_values[j] = p->corr[k];
p->peak_offsets[j] = k - start;
if (p->peak_values[j] > max_peak) {
max_peak = p->peak_values[j];
}
}
}
}
if (max_peak > p->detect_factor*corr_ave) {
for (int j=0;j<n_wins;j++) {
if(p->peak_values[j] > p->detect_factor*corr_ave)
{
if (max_peak > p->detect_factor * corr_ave) {
for (int j = 0; j < n_wins; j++) {
if (p->peak_values[j] > p->detect_factor * corr_ave) {
//printf("saving prach correlation\n");
//memcpy(save_corr, p->corr, p->N_zc*sizeof(float));
if (indices) {
indices[*n_indices] = (i*n_wins)+j;
indices[*n_indices] = (i * n_wins) + j;
}
if (peak_to_avg) {
peak_to_avg[*n_indices] = p->peak_values[j]/corr_ave;
peak_to_avg[*n_indices] = p->peak_values[j] / corr_ave;
}
if (t_offsets) {
t_offsets[*n_indices] = (float) p->peak_offsets[j]*p->T_seq/p->N_zc;
}
(*n_indices)++;
t_offsets[*n_indices] = (float) p->peak_offsets[j] * p->T_seq / p->N_zc;
}
(*n_indices)++;
}
}
}
@ -687,41 +673,37 @@ int srslte_prach_free(srslte_prach_t *p) {
srslte_dft_plan_free(&p->zc_ifft);
if (p->signal_fft) {
free(p->signal_fft);
free(p->signal_fft);
}
bzero(p, sizeof(srslte_prach_t));
return 0;
}
int srslte_prach_print_seqs(srslte_prach_t *p)
{
for(int i=0; i<N_SEQS;i++)
{
int srslte_prach_print_seqs(srslte_prach_t *p) {
for (int i = 0; i < N_SEQS; i++) {
FILE *f;
char str[32];
sprintf(str, "prach_seq_%d.bin", i);
f = fopen(str, "wb");
fwrite(p->seqs[i] , sizeof(cf_t), p->N_zc, f);
fwrite(p->seqs[i], sizeof(cf_t), p->N_zc, f);
fclose(f);
}
for(int i=0; i<N_SEQS;i++)
{
for (int i = 0; i < N_SEQS; i++) {
FILE *f;
char str[32];
sprintf(str, "prach_dft_seq_%d.bin", i);
f = fopen(str, "wb");
fwrite(p->dft_seqs[i] , sizeof(cf_t), p->N_zc, f);
fwrite(p->dft_seqs[i], sizeof(cf_t), p->N_zc, f);
fclose(f);
}
for(int i=0;i<p->N_roots;i++)
{
for (int i = 0; i < p->N_roots; i++) {
FILE *f;
char str[32];
sprintf(str, "prach_root_seq_%d.bin", i);
f = fopen(str, "wb");
fwrite(p->seqs[p->root_seqs_idx[i]] , sizeof(cf_t), p->N_zc, f);
fwrite(p->seqs[p->root_seqs_idx[i]], sizeof(cf_t), p->N_zc, f);
fclose(f);
}
return 0;

@ -186,9 +186,11 @@ int rf_cell_search(srslte_rf_t *rf, uint32_t nof_rx_antennas,
ret = srslte_ue_cellsearch_scan(&cs, found_cells, &max_peak_cell);
}
if (ret < 0) {
srslte_rf_stop_rx_stream(rf);
fprintf(stderr, "Error searching cell\n");
return SRSLTE_ERROR;
} else if (ret == 0) {
srslte_rf_stop_rx_stream(rf);
fprintf(stderr, "Could not find any cell in this frequency\n");
return SRSLTE_SUCCESS;
}

@ -71,7 +71,7 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o
q->N_id_1 = 1000;
q->cfo_ema_alpha = CFO_EMA_ALPHA;
q->sss_alg = SSS_PARTIAL_3;
q->sss_alg = SSS_FULL;
q->detect_cp = true;
q->sss_en = true;

@ -460,15 +460,15 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3
pmi = grant->pinfo - 1;
} else {
ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo);
return SRSLTE_ERROR;
pmi = grant->pinfo % 4;
}
} else {
if (grant->pinfo < 2) {
pmi = grant->pinfo;
} else {
ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo);
return SRSLTE_ERROR;
if (grant->pinfo == 2) {
ERROR("Not implemented codebook index (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo);
} else if (grant->pinfo > 2) {
ERROR("Reserved codebook index (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo);
}
pmi = grant->pinfo % 2;
}
}
if(SRSLTE_SF_MBSFN == grant->sf_type) {

@ -144,18 +144,11 @@ void srslte_ue_sync_reset(srslte_ue_sync_t *q) {
int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, double (set_gain_callback)(void*, double), float init_gain_value) {
uint32_t nframes;
if (q->nof_recv_sf == 1) {
nframes = 10;
} else {
nframes = 0;
}
int n = srslte_agc_init_uhd(&q->agc, SRSLTE_AGC_MODE_PEAK_AMPLITUDE, nframes, set_gain_callback, q->stream);
int n = srslte_agc_init_uhd(&q->agc, SRSLTE_AGC_MODE_PEAK_AMPLITUDE, 0, set_gain_callback, q->stream);
q->do_agc = n==0?true:false;
if (q->do_agc) {
srslte_agc_set_gain(&q->agc, init_gain_value);
srslte_agc_set_target(&q->agc, 0.3);
srslte_agc_set_bandwidth(&q->agc, 0.8);
srslte_ue_sync_set_agc_period(q, 4);
}
return n;
}
@ -329,7 +322,6 @@ int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell)
memcpy(&q->cell, &cell, sizeof(srslte_cell_t));
q->fft_size = srslte_symbol_sz(q->cell.nof_prb);
q->sf_len = SRSLTE_SF_LEN(q->fft_size);
q->agc_period = 0;
if (cell.id == 1000) {
@ -789,7 +781,7 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE
if (q->do_agc && (q->agc_period == 0 ||
(q->agc_period && (q->frame_total_cnt%q->agc_period) == 0)))
{
srslte_agc_process(&q->agc, input_buffer[0], q->sf_len);
srslte_agc_process(&q->agc, input_buffer[0], q->sf_len);
}
/* Track PSS/SSS around the expected PSS position

@ -355,7 +355,7 @@ int srslte_ue_ul_pucch_encode(srslte_ue_ul_t *q, srslte_uci_data_t uci_data,
}
if (q->normalize_en) {
float norm_factor = (float) 0.8*q->cell.nof_prb/5;
float norm_factor = (float) q->cell.nof_prb/15/10;
srslte_vec_sc_prod_cfc(output_signal, norm_factor, output_signal, SRSLTE_SF_LEN_PRB(q->cell.nof_prb));
}
ret = SRSLTE_SUCCESS;

@ -54,6 +54,7 @@ int srslte_ringbuffer_write(srslte_ringbuffer_t *q, void *p, int nof_bytes)
int w_bytes = nof_bytes;
pthread_mutex_lock(&q->mutex);
if (!q->active) {
pthread_mutex_unlock(&q->mutex);
return 0;
}
if (q->count + w_bytes > q->capacity) {
@ -85,6 +86,7 @@ int srslte_ringbuffer_read(srslte_ringbuffer_t *q, void *p, int nof_bytes)
pthread_cond_wait(&q->cvar, &q->mutex);
}
if (!q->active) {
pthread_mutex_unlock(&q->mutex);
return 0;
}
if (nof_bytes + q->rpm > q->capacity) {

@ -452,6 +452,28 @@ TEST(srslte_vec_convert_fi,
free(z);
)
TEST(srslte_vec_convert_if,
MALLOC(int16_t, x);
MALLOC(float, z);
float scale = 1000.0f;
float gold;
float k = 1.0f/scale;
for (int i = 0; i < block_size; i++) {
x[i] = (int16_t) RANDOM_S();
}
TEST_CALL(srslte_vec_convert_if(x, scale, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = ((float)x[i]) * k;
mse += fabsf(gold - z[i]);
}
free(x);
free(z);
)
TEST(srslte_vec_prod_fff,
MALLOC(float, x);
MALLOC(float, y);
@ -596,7 +618,7 @@ TEST(srslte_vec_div_ccc,
for (int i = 0; i < block_size; i++) {
gold = x[i] / y[i];
mse += cabsf(gold - z[i]);
mse += cabsf(gold - z[i]) / cabsf(gold);
}
mse /= block_size;
@ -614,14 +636,14 @@ TEST(srslte_vec_div_cfc,
cf_t gold;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_CF();
y[i] = RANDOM_F();
y[i] = RANDOM_F() + 0.0001f;
}
TEST_CALL(srslte_vec_div_cfc(x, y, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = x[i] / y[i];
mse += cabsf(gold - z[i])/cabsf(gold);
mse += cabsf(gold - z[i]) / cabsf(gold);
}
mse /= block_size;
@ -638,15 +660,15 @@ TEST(srslte_vec_div_fff,
cf_t gold;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_F() + 0.0001;
y[i] = RANDOM_F()+ 0.0001;
x[i] = RANDOM_F();
y[i] = RANDOM_F() + 0.0001f;
}
TEST_CALL(srslte_vec_div_fff(x, y, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = x[i] / y[i];
mse += cabsf(gold - z[i]);
mse += cabsf(gold - z[i]) / cabsf(gold);
}
mse /= block_size;
@ -753,6 +775,9 @@ int main(int argc, char **argv) {
passed[func_count][size_count] = test_srslte_vec_convert_fi(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_convert_if(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_prod_fff(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;

@ -93,10 +93,7 @@ void srslte_vec_sc_prod_ccc(const cf_t *x, const cf_t h, cf_t *z, const uint32_t
// Used in turbo decoder
void srslte_vec_convert_if(const int16_t *x, const float scale, float *z, const uint32_t len) {
int i;
for (i=0;i<len;i++) {
z[i] = ((float) x[i])/scale;
}
srslte_vec_convert_if_simd(x, z, scale, len);
}
void srslte_vec_convert_fi(const float *x, const float scale, int16_t *z, const uint32_t len) {

@ -228,6 +228,36 @@ void srslte_vec_lut_sss_simd(const short *x, const unsigned short *lut, short *y
}
}
void srslte_vec_convert_if_simd(const int16_t *x, float *z, const float scale, const int len) {
int i = 0;
const float gain = 1.0f / scale;
#ifdef LV_HAVE_SSE
__m128 s = _mm_set1_ps(gain);
if (SRSLTE_IS_ALIGNED(z)) {
for (; i < len - 3; i += 4) {
__m64 *ptr = (__m64 *) &x[i];
__m128 fl = _mm_cvtpi16_ps(*ptr);
__m128 v = _mm_mul_ps(fl, s);
_mm_store_ps(&z[i], v);
}
} else {
for (; i < len - 3; i += 4) {
__m64 *ptr = (__m64 *) &x[i];
__m128 fl = _mm_cvtpi16_ps(*ptr);
__m128 v = _mm_mul_ps(fl, s);
_mm_storeu_ps(&z[i], v);
}
}
#endif /* LV_HAVE_SSE */
for (; i < len; i++) {
z[i] = ((float) x[i]) * gain;
}
}
void srslte_vec_convert_fi_simd(const float *x, int16_t *z, const float scale, const int len) {
int i = 0;
@ -1220,4 +1250,4 @@ void srslte_vec_interleave_add_simd(const cf_t *x, const cf_t *y, cf_t *z, const
z[k++] += x[i];
z[k++] += y[i];
}
}
}

@ -68,6 +68,12 @@ rlc_am::rlc_am() : tx_sdu_queue(16)
do_status = false;
}
rlc_am::~rlc_am()
{
// reset RLC and dealloc SDUs
stop();
}
void rlc_am::init(srslte::log *log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
@ -112,8 +118,10 @@ void rlc_am::reset()
pthread_mutex_lock(&mutex);
reordering_timeout.reset();
if(tx_sdu)
tx_sdu->reset();
if(tx_sdu) {
pool->deallocate(tx_sdu);
tx_sdu = NULL;
}
if(rx_sdu)
rx_sdu->reset();
@ -587,7 +595,8 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r
rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len);
return 0;
}
pdu_space = nof_bytes-head_len-2;
pdu_space = nof_bytes-head_len;
if(pdu_space < (retx.so_end-retx.so_start))
retx.so_end = retx.so_start+pdu_space;
@ -603,10 +612,13 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r
if(lower >= retx.so_end)
break;
if(pdu_space <= 2)
break;
upper += old_header.li[i];
head_len = rlc_am_packed_length(&new_header);
pdu_space = nof_bytes-head_len-2;
pdu_space = nof_bytes-head_len;
if(pdu_space < (retx.so_end-retx.so_start))
retx.so_end = retx.so_start+pdu_space;
@ -1085,11 +1097,11 @@ void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes)
it = tx_window.find(i);
if (it != tx_window.end()) {
if(update_vt_a) {
tx_window.erase(it);
if(it->second.buf) {
pool->deallocate(it->second.buf);
it->second.buf = 0;
}
tx_window.erase(it);
vt_a = (vt_a + 1)%MOD;
vt_ms = (vt_ms + 1)%MOD;
}
@ -1217,15 +1229,33 @@ void rlc_am::print_rx_segments()
bool rlc_am::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment)
{
// Ordered insert
std::list<rlc_amd_rx_pdu_t>::iterator tmpit;
std::list<rlc_amd_rx_pdu_t>::iterator it = pdu->segments.begin();
while(it != pdu->segments.end() && it->header.so < segment->header.so)
it++;
pdu->segments.insert(it, *segment);
// Check for first segment
if(0 == segment->header.so) {
std::list<rlc_amd_rx_pdu_t>::iterator it;
for(it = pdu->segments.begin(); it != pdu->segments.end(); it++) {
pool->deallocate(it->buf);
}
pdu->segments.clear();
pdu->segments.push_back(*segment);
return false;
}
// Check segment offset
uint32_t n = 0;
if(!pdu->segments.empty()) {
rlc_amd_rx_pdu_t &back = pdu->segments.back();
n = back.header.so + back.buf->N_bytes;
}
if(segment->header.so != n) {
pool->deallocate(segment->buf);
return false;
} else {
pdu->segments.push_back(*segment);
}
// Check for complete
uint32_t so = 0;
std::list<rlc_amd_rx_pdu_t>::iterator it, tmpit;
for(it = pdu->segments.begin(); it != pdu->segments.end(); it++) {
if(so != it->header.so)
return false;
@ -1287,6 +1317,7 @@ bool rlc_am::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pd
}
handle_data_pdu(full_pdu->msg, full_pdu->N_bytes, header);
pool->deallocate(full_pdu);
return true;
}

@ -59,6 +59,11 @@ rlc_um::rlc_um() : tx_sdu_queue(16)
pdu_lost = false;
}
rlc_um::~rlc_um()
{
stop();
}
void rlc_um::init(srslte::log *log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
@ -114,12 +119,13 @@ void rlc_um::empty_queue() {
void rlc_um::stop()
{
reset();
mac_timers->timer_release_id(reordering_timer_id);
if (mac_timers) {
mac_timers->timer_release_id(reordering_timer_id);
}
}
void rlc_um::reset()
{
// Empty tx_sdu_queue before locking the mutex
empty_queue();
@ -129,12 +135,17 @@ void rlc_um::reset()
vr_ux = 0;
vr_uh = 0;
pdu_lost = false;
if(rx_sdu)
if(rx_sdu) {
rx_sdu->reset();
if(tx_sdu)
}
if(tx_sdu) {
tx_sdu->reset();
if(mac_timers)
}
if(mac_timers) {
reordering_timer->stop();
}
// Drop all messages in RX window
std::map<uint32_t, rlc_umd_pdu_t>::iterator it;

@ -47,6 +47,7 @@ public:
rlc2 = rlc2_;
fail_rate = fail_rate_;
run_enable = true;
running = false;
}
void stop()
@ -81,9 +82,10 @@ private:
if(((float)rand()/RAND_MAX > fail_rate) && read>0) {
rlc2->write_pdu(1, pdu->msg, opp_size);
}
usleep(1000);
usleep(100);
}
running = false;
byte_buffer_pool::get_instance()->deallocate(pdu);
}
rlc_interface_mac *rlc1;
@ -138,10 +140,12 @@ class rlc_am_tester
,public thread
{
public:
rlc_am_tester(rlc_interface_pdcp *rlc_){
rlc_am_tester(rlc_interface_pdcp *rlc_, std::string name_=""){
rlc = rlc_;
run_enable = true;
running = false;
rx_pdus = 0;
name = name_;
}
void stop()
@ -163,6 +167,7 @@ public:
{
assert(lcid == 1);
byte_buffer_pool::get_instance()->deallocate(sdu);
std::cout << "rlc_am_tester " << name << " received " << rx_pdus++ << " PDUs" << std::endl;
}
void write_pdu_bcch_bch(byte_buffer_t *sdu) {}
void write_pdu_bcch_dlsch(byte_buffer_t *sdu) {}
@ -186,13 +191,16 @@ private:
pdu->N_bytes = 1500;
pdu->msg[0] = sn++;
rlc->write_sdu(1, pdu);
usleep(1000);
usleep(100);
}
running = false;
}
bool run_enable;
bool running;
long rx_pdus;
std::string name;
rlc_interface_pdcp *rlc;
};
@ -211,13 +219,13 @@ void stress_test()
rlc rlc1;
rlc rlc2;
rlc_am_tester tester1(&rlc1);
rlc_am_tester tester2(&rlc2);
rlc_am_tester tester1(&rlc1, "tester1");
rlc_am_tester tester2(&rlc2, "tester2");
mac_dummy mac(&rlc1, &rlc2, fail_rate);
ue_interface ue;
rlc1.init(&tester1, &tester1, &ue, &log1, &mac, 0);
rlc2.init(&tester1, &tester1, &ue, &log2, &mac, 0);
rlc2.init(&tester2, &tester2, &ue, &log2, &mac, 0);
LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg;
cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM;
@ -234,7 +242,7 @@ void stress_test()
rlc2.add_bearer(1, cnfg_);
tester1.start(7);
//tester2.start(7);
tester2.start(7);
mac.start();
usleep(100e6);

@ -59,6 +59,14 @@ public:
n_sdus = 0;
}
~rlc_am_tester(){
for (uint32_t i = 0; i < 10; i++) {
if (sdus[i] != NULL) {
byte_buffer_pool::get_instance()->deallocate(sdus[i]);
}
}
}
// PDCP interface
void write_pdu(uint32_t lcid, byte_buffer_t *sdu)
{
@ -482,17 +490,17 @@ void resegment_test_1()
// Read the retx PDU from RLC1 and force resegmentation
byte_buffer_t retx1;
len = rlc1.read_pdu(retx1.msg, 11); // 4 byte header + 5 data
len = rlc1.read_pdu(retx1.msg, 9); // 4 byte header + 5 data
retx1.N_bytes = len;
// Write the retx PDU to RLC2
rlc2.write_pdu(retx1.msg, retx1.N_bytes);
assert(9 == rlc1.get_buffer_state()); // 4 byte header + 5 data
assert(9 == rlc1.get_buffer_state());
// Read the remaining segment
byte_buffer_t retx2;
len = rlc1.read_pdu(retx2.msg, 11); // 4 byte header + 5 data
len = rlc1.read_pdu(retx2.msg, 9); // 4 byte header + 5 data
retx2.N_bytes = len;
// Write the retx PDU to RLC2
@ -591,16 +599,16 @@ void resegment_test_2()
// Read the retx PDU from RLC1 and force resegmentation
byte_buffer_t retx1;
retx1.N_bytes = rlc1.read_pdu(retx1.msg, 18); // 6 byte header + 10 data
retx1.N_bytes = rlc1.read_pdu(retx1.msg, 16); // 6 byte header + 10 data
// Write the retx PDU to RLC2
rlc2.write_pdu(retx1.msg, retx1.N_bytes);
assert(16 == rlc1.get_buffer_state()); // 6 byte header + 10 data
assert(16 == rlc1.get_buffer_state());
// Read the remaining segment
byte_buffer_t retx2;
retx2.N_bytes = rlc1.read_pdu(retx2.msg, 18); // 6 byte header + 10 data
retx2.N_bytes = rlc1.read_pdu(retx2.msg, 16); // 6 byte header + 10 data
// Write the retx PDU to RLC2
rlc2.write_pdu(retx2.msg, retx2.N_bytes);
@ -696,14 +704,14 @@ void resegment_test_3()
// Read the retx PDU from RLC1 and force resegmentation
byte_buffer_t retx1;
retx1.N_bytes = rlc1.read_pdu(retx1.msg, 16); // 4 byte header + 10 data
retx1.N_bytes = rlc1.read_pdu(retx1.msg, 14); // 4 byte header + 10 data
// Write the retx PDU to RLC2
rlc2.write_pdu(retx1.msg, retx1.N_bytes);
// Read the remaining segment
byte_buffer_t retx2;
retx2.N_bytes = rlc1.read_pdu(retx2.msg, 16); // 4 byte header + 10 data
retx2.N_bytes = rlc1.read_pdu(retx2.msg, 14); // 4 byte header + 10 data
// Write the retx PDU to RLC2
rlc2.write_pdu(retx2.msg, retx2.N_bytes);
@ -799,14 +807,14 @@ void resegment_test_4()
// Read the retx PDU from RLC1 and force resegmentation
byte_buffer_t retx1;
retx1.N_bytes = rlc1.read_pdu(retx1.msg, 23); // 6 byte header + 15 data
retx1.N_bytes = rlc1.read_pdu(retx1.msg, 21); // 6 byte header + 15 data
// Write the retx PDU to RLC2
rlc2.write_pdu(retx1.msg, retx1.N_bytes);
// Read the remaining segment
byte_buffer_t retx2;
retx2.N_bytes = rlc1.read_pdu(retx2.msg, 23); // 6 byte header + 15 data
retx2.N_bytes = rlc1.read_pdu(retx2.msg, 21); // 6 byte header + 15 data
// Write the retx PDU to RLC2
rlc2.write_pdu(retx2.msg, retx2.N_bytes);
@ -902,14 +910,14 @@ void resegment_test_5()
// Read the retx PDU from RLC1 and force resegmentation
byte_buffer_t retx1;
retx1.N_bytes = rlc1.read_pdu(retx1.msg, 29); // 7 byte header + 20 data
retx1.N_bytes = rlc1.read_pdu(retx1.msg, 27); // 7 byte header + 20 data
// Write the retx PDU to RLC2
rlc2.write_pdu(retx1.msg, retx1.N_bytes);
// Read the remaining segment
byte_buffer_t retx2;
retx2.N_bytes = rlc1.read_pdu(retx2.msg, 29); // 7 byte header + 20 data
retx2.N_bytes = rlc1.read_pdu(retx2.msg, 27); // 7 byte header + 20 data
// Write the retx PDU to RLC2
rlc2.write_pdu(retx2.msg, retx2.N_bytes);
@ -1023,11 +1031,11 @@ void resegment_test_6()
// Write the retx PDU to RLC2
rlc2.write_pdu(retx1.msg, retx1.N_bytes);
assert(157 == rlc1.get_buffer_state());
assert(155 == rlc1.get_buffer_state());
// Read the remaining segment
byte_buffer_t retx2;
len = rlc1.read_pdu(retx2.msg, 159);
len = rlc1.read_pdu(retx2.msg, 157);
retx2.N_bytes = len;
// Write the retx PDU to RLC2
@ -1048,24 +1056,91 @@ void resegment_test_6()
}
}
void reset_test()
{
srslte::log_filter log1("RLC_AM_1");
srslte::log_filter log2("RLC_AM_2");
log1.set_level(srslte::LOG_LEVEL_DEBUG);
log2.set_level(srslte::LOG_LEVEL_DEBUG);
log1.set_hex_limit(-1);
log2.set_hex_limit(-1);
rlc_am_tester tester;
mac_dummy_timers timers;
rlc_am rlc1;
int len;
log1.set_level(srslte::LOG_LEVEL_DEBUG);
rlc1.init(&log1, 1, &tester, &tester, &timers);
LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg;
cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM;
cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5;
cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS5;
cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4;
cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25;
cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4;
cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg);
// Push 1 SDU of size 10 into RLC1
byte_buffer_t sdu_buf;
*sdu_buf.msg = 1; // Write the index into the buffer
sdu_buf.N_bytes = 100;
rlc1.write_sdu(&sdu_buf);
// read 1 PDU from RLC1 and force segmentation
byte_buffer_t pdu_bufs;
len = rlc1.read_pdu(pdu_bufs.msg, 4);
pdu_bufs.N_bytes = len;
// reset RLC1
rlc1.reset();
// read another PDU segment from RLC1
len = rlc1.read_pdu(pdu_bufs.msg, 4);
pdu_bufs.N_bytes = len;
// now empty RLC buffer
len = rlc1.read_pdu(pdu_bufs.msg, 100);
pdu_bufs.N_bytes = len;
assert(0 == rlc1.get_buffer_state());
}
int main(int argc, char **argv) {
basic_test();
byte_buffer_pool::get_instance()->cleanup();
concat_test();
byte_buffer_pool::get_instance()->cleanup();
segment_test();
byte_buffer_pool::get_instance()->cleanup();
retx_test();
byte_buffer_pool::get_instance()->cleanup();
resegment_test_1();
byte_buffer_pool::get_instance()->cleanup();
resegment_test_2();
byte_buffer_pool::get_instance()->cleanup();
resegment_test_3();
byte_buffer_pool::get_instance()->cleanup();
resegment_test_4();
byte_buffer_pool::get_instance()->cleanup();
resegment_test_5();
byte_buffer_pool::get_instance()->cleanup();
resegment_test_6();
byte_buffer_pool::get_instance()->cleanup();
reset_test();
byte_buffer_pool::get_instance()->cleanup();
}

@ -62,6 +62,14 @@ public:
n_sdus = 0;
}
~rlc_um_tester(){
for (uint32_t i = 0; i < NBUFS; i++) {
if (sdus[i] != NULL) {
byte_buffer_pool::get_instance()->deallocate(sdus[i]);
}
}
}
// PDCP interface
void write_pdu(uint32_t lcid, byte_buffer_t *sdu)
{

@ -1,3 +1,28 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <string.h>

@ -1,3 +1,28 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <unistd.h>

@ -1,3 +1,29 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

@ -24,6 +24,7 @@
*
*/
#include <iostream>
#include "mme/s1ap.h"
#include "mme/s1ap_nas_transport.h"
#include "srslte/common/security.h"

@ -67,6 +67,9 @@ public:
void msg3_flush();
bool msg3_is_transmitted();
void msg3_prepare();
bool msg3_is_pending();
void append_crnti_ce_next_tx(uint16_t crnti);
@ -105,6 +108,7 @@ private:
/* PDU Buffer */
srslte::sch_pdu pdu_msg;
bool msg3_has_been_transmitted;
bool msg3_pending;
};
} // namespace srsue

@ -237,8 +237,8 @@ private:
// New transmission
reset();
// Uplink grant in a RAR
if (grant->is_from_rar) {
// Uplink grant in a RAR and there is a PDU in the Msg3 buffer
if (grant->is_from_rar && harq_entity->mux_unit->msg3_is_pending()) {
Debug("Getting Msg3 buffer payload, grant size=%d bytes\n", grant->n_bytes[0]);
pdu_ptr = harq_entity->mux_unit->msg3_get(payload_buffer, grant->n_bytes[0]);
if (pdu_ptr) {
@ -246,9 +246,13 @@ private:
} else {
Warning("UL RAR grant available but no Msg3 on buffer\n");
}
printf("Transmitted Msg3\n");
// Normal UL grant
} else {
if (grant->is_from_rar) {
grant->rnti = harq_entity->rntis->crnti;
}
// Request a MAC PDU from the Multiplexing & Assemble Unit
pdu_ptr = harq_entity->mux_unit->pdu_get(payload_buffer, grant->n_bytes[0], tti_tx, pid);
if (pdu_ptr) {
@ -268,7 +272,7 @@ private:
generate_retx(tti_tx, action);
}
if (harq_entity->pcap && grant) {
if (grant->is_from_rar) {
if (grant->is_from_rar && harq_entity->rntis->temp_rnti) {
grant->rnti = harq_entity->rntis->temp_rnti;
}
harq_entity->pcap->write_ul_crnti(pdu_ptr, grant->n_bytes[0], grant->rnti, get_nof_retx(), tti_tx);

@ -87,6 +87,9 @@ public:
uint32_t last_ul_tti[2*HARQ_DELAY_MS];
srslte_mod_t last_ul_mod[2*HARQ_DELAY_MS];
uint8_t last_ri;
uint8_t last_pmi;
phch_common(uint32_t max_mutex = 3);
void init(phy_interface_rrc::phy_cfg_t *config,
phy_args_t *args,

@ -125,6 +125,7 @@ private:
float get_last_gain();
float get_last_cfo();
void set_N_id_2(int N_id_2);
void set_agc_enable(bool enable);
ret_code run(srslte_cell_t *cell);
private:
@ -308,10 +309,11 @@ private:
CELL_SELECT,
CELL_RESELECT,
CELL_MEASURE,
CELL_CAMP
CELL_CAMP,
IDLE_RX
} phy_state;
bool is_in_idle;
bool is_in_idle, is_in_idle_rx;
// Sampling rate mode (find is 1.96 MHz, camp is the full cell BW)
enum {

@ -70,6 +70,9 @@ public:
void start_plot();
float get_ref_cfo();
float get_snr();
float get_rsrp();
float get_noise();
float get_cfo();
float get_ul_cfo();

@ -53,7 +53,7 @@ public:
bool init(srslte::radio_multi *radio_handler,
mac_interface_phy *mac,
rrc_interface_phy *rrc,
std::vector<void*> log_vec,
std::vector<srslte::log*> log_vec,
phy_args_t *args = NULL);
void stop();
@ -159,7 +159,7 @@ private:
const static int WORKERS_THREAD_PRIO = 0;
srslte::radio_multi *radio_handler;
std::vector<void*> log_vec;
std::vector<srslte::log*> log_vec;
srslte::log *log_h;
srslte::log *log_phy_lib_h;
srsue::mac_interface_phy *mac;

@ -101,7 +101,7 @@ private:
srslte::logger *logger;
// rf_log is on ue_base
std::vector<void*> phy_log;
std::vector<srslte::log*> phy_log;
srslte::log_filter mac_log;
srslte::log_filter rlc_log;
srslte::log_filter pdcp_log;

@ -76,17 +76,22 @@ class cell_t
return false;
}
cell_t() {
this->has_valid_sib1 = false;
this->has_valid_sib2 = false;
this->has_valid_sib3 = false;
srslte_cell_t tmp = {};
cell_t(tmp, 0, 0);
}
cell_t(srslte_cell_t phy_cell, uint32_t earfcn, float rsrp) {
this->has_valid_sib1 = false;
this->has_valid_sib2 = false;
this->has_valid_sib3 = false;
this->has_valid_sib13 = false;
this->phy_cell = phy_cell;
this->rsrp = rsrp;
this->earfcn = earfcn;
in_sync = true;
bzero(&sib1, sizeof(sib1));
bzero(&sib2, sizeof(sib2));
bzero(&sib3, sizeof(sib3));
bzero(&sib13, sizeof(sib13));
}
uint32_t earfcn;
@ -114,6 +119,7 @@ class rrc
{
public:
rrc();
~rrc();
void init(phy_interface_rrc *phy_,
mac_interface_rrc *mac_,

@ -65,6 +65,7 @@ void mux::reset()
for (uint32_t i=0;i<lch.size();i++) {
lch[i].Bj = 0;
}
msg3_pending = false;
pending_crnti_ce = 0;
}
@ -343,7 +344,8 @@ void mux::msg3_flush()
if (log_h) {
Debug("Msg3 buffer flushed\n");
}
msg3_has_been_transmitted = false;
msg3_has_been_transmitted = false;
msg3_pending = false;
bzero(msg3_buff, sizeof(MSG3_BUFF_SZ));
}
@ -352,6 +354,14 @@ bool mux::msg3_is_transmitted()
return msg3_has_been_transmitted;
}
void mux::msg3_prepare() {
msg3_pending = true;
}
bool mux::msg3_is_pending() {
return msg3_pending;
}
/* Returns a pointer to the Msg3 buffer */
uint8_t* mux::msg3_get(uint8_t *payload, uint32_t pdu_sz)
{
@ -363,6 +373,7 @@ uint8_t* mux::msg3_get(uint8_t *payload, uint32_t pdu_sz)
}
memcpy(payload, msg3_buff_start_pdu, sizeof(uint8_t)*pdu_sz);
msg3_has_been_transmitted = true;
msg3_pending = false;
return payload;
} else {
Error("Msg3 size (%d) is longer than internal msg3_buff size=%d, (see mux.h)\n", pdu_sz, MSG3_BUFF_SZ-32);

@ -349,7 +349,8 @@ void ra_proc::tb_decoded_ok() {
// Preamble selected by Network
state = COMPLETION;
} else {
// Preamble selected by UE MAC
// Preamble selected by UE MAC
mux_unit->msg3_prepare();
rntis->temp_rnti = rar_pdu_msg.get()->get_temp_crnti();
phy_h->pdcch_dl_search(SRSLTE_RNTI_TEMP, rar_pdu_msg.get()->get_temp_crnti());

@ -162,7 +162,11 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
bpo::value<bool>(&args->expert.phy.rssi_sensor_enabled)->default_value(true),
"Enable or disable RF frontend RSSI sensor. In some USRP devices can cause segmentation fault")
("expert.prach_gain",
("expert.rx_gain_offset",
bpo::value<float>(&args->expert.phy.rx_gain_offset)->default_value(10),
"RX Gain offset to add to rx_gain to correct RSRP value")
("expert.prach_gain",
bpo::value<float>(&args->expert.phy.prach_gain)->default_value(-1.0),
"Disable PRACH power control")

@ -48,6 +48,8 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_)
max_mutex = max_mutex_;
nof_mutex = 0;
rx_gain_offset = 0;
last_ri = 0;
last_pmi = 0;
bzero(&dl_metrics, sizeof(dl_metrics_t));
dl_metrics_read = true;
@ -62,9 +64,10 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_)
bzero(zeros, 50000*sizeof(cf_t));
// FIXME: This is an ugly fix to avoid the TX filters to empty
/*
for (int i=0;i<50000;i++) {
zeros[i] = 0.01*cexpf(((float) i/50000)*0.1*_Complex_I);
}
}*/
reset();

@ -174,16 +174,21 @@ bool phch_recv::wait_radio_reset() {
void phch_recv::set_agc_enable(bool enable)
{
do_agc = enable;
if (do_agc) {
if (running && radio_h) {
srslte_ue_sync_start_agc(&ue_sync, callback_set_rx_gain, radio_h->get_rx_gain());
search_p.set_agc_enable(true);
} else {
fprintf(stderr, "Error setting AGC: PHY not initiatec\n");
}
} else {
fprintf(stderr, "Error stopping AGC: not implemented\n");
}
}
void phch_recv::set_time_adv_sec(float _time_adv_sec)
void phch_recv::set_time_adv_sec(float time_adv_sec)
{
if (TX_MODE_CONTINUOUS && !radio_h->is_first_of_burst()) {
int nsamples = ceil(current_srate*_time_adv_sec);
next_offset = -nsamples;
} else {
time_adv_sec = _time_adv_sec;
}
this->time_adv_sec = time_adv_sec;
}
void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q, float cfo)
@ -375,18 +380,30 @@ bool phch_recv::cell_handover(srslte_cell_t cell)
log_h->info("Cell HO: Waiting pending PHICH\n");
}
bool ret;
bool ret = false;
this->cell = cell;
Info("Cell HO: Stopping sync with current cell\n");
worker_com->reset_ul();
stop_sync();
Info("Cell HO: Reconfiguring cell\n");
if (set_cell()) {
Info("Cell HO: Synchronizing with new cell\n");
resync_sfn(true, true);
ret = true;
phy_state = IDLE_RX;
cnt = 0;
while(!is_in_idle_rx && cnt<20) {
usleep(1000);
cnt++;
}
if (is_in_idle_rx) {
Info("Cell HO: Reconfiguring cell\n");
if (set_cell()) {
//resync_sfn(true, true);
sfn_p.reset();
phy_state = CELL_RESELECT;
Info("Cell HO: Synchronizing with new cell\n");
ret = true;
} else {
log_h->error("Cell HO: Configuring cell PCI=%d\n", cell.id);
ret = false;
}
} else {
log_h->error("Cell HO: Configuring cell PCI=%d\n", cell.id);
log_h->error("Cell HO: Could not stop sync\n");
ret = false;
}
return ret;
@ -567,6 +584,7 @@ void phch_recv::run_thread()
uint32_t sf_idx = 0;
phy_state = IDLE;
is_in_idle = true;
is_in_idle_rx = false;
while (running)
{
@ -575,6 +593,10 @@ void phch_recv::run_thread()
Debug("SYNC: state=%d\n", phy_state);
}
if (phy_state != IDLE_RX) {
is_in_idle_rx = false;
}
log_h->step(tti);
log_phy_lib_h->step(tti);
@ -665,10 +687,11 @@ void phch_recv::run_thread()
case 1:
if (last_worker) {
Debug("SF: cfo_tot=%7.1f Hz, ref=%f Hz, pss=%f Hz\n",
Debug("SF: cfo_tot=%7.1f Hz, ref=%f Hz, pss=%f Hz, snr_sf=%.2f dB, rsrp=%.2f dB, noise=%.2f dB\n",
srslte_ue_sync_get_cfo(&ue_sync),
15000*last_worker->get_ref_cfo(),
15000*ue_sync.strack.cfo_pss_mean);
15000*ue_sync.strack.cfo_pss_mean,
last_worker->get_snr(), last_worker->get_rsrp(), last_worker->get_noise());
}
last_worker = worker;
@ -739,6 +762,23 @@ void phch_recv::run_thread()
is_in_idle = true;
usleep(1000);
break;
case IDLE_RX:
if (!worker) {
worker = (phch_worker *) workers_pool->wait_worker(tti);
}
is_in_idle_rx = true;
if (worker) {
for (uint32_t i = 0; i < SRSLTE_MAX_PORTS; i++) {
buffer[i] = worker->get_buffer(i);
}
if (!radio_h->rx_now(buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb), NULL)) {
Error("SYNC: Receiving from radio while in IDLE_RX\n");
}
} else {
// wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here
running = false;
}
break;
}
// Increase TTI counter and trigger MAC clock (lower priority)
@ -832,6 +872,14 @@ float phch_recv::search::get_last_cfo()
return srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync);
}
void phch_recv::search::set_agc_enable(bool enable) {
if (enable) {
srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, callback_set_rx_gain, p->radio_h->get_rx_gain());
} else {
fprintf(stderr, "Error stop AGC not implemented\n");
}
}
phch_recv::search::ret_code phch_recv::search::run(srslte_cell_t *cell)
{
@ -891,11 +939,6 @@ phch_recv::search::ret_code phch_recv::search::run(srslte_cell_t *cell)
// Set options defined in expert section
p->set_ue_sync_opts(&ue_mib_sync.ue_sync, cfo);
// Start AGC after initial cell search
if (p->do_agc) {
srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, callback_set_rx_gain, p->radio_h->get_rx_gain());
}
srslte_ue_sync_reset(&ue_mib_sync.ue_sync);
/* Find and decode MIB */
@ -1011,7 +1054,6 @@ phch_recv::sfn_sync::ret_code phch_recv::sfn_sync::run_subframe(srslte_cell_t *c
Info("SYNC: DONE, TTI=%d, sfn_offset=%d\n", *tti_cnt, sfn_offset);
}
srslte_ue_sync_set_agc_period(ue_sync, 20);
srslte_ue_sync_decode_sss_on_track(ue_sync, true);
reset();
return SFN_FOUND;
@ -1169,6 +1211,9 @@ phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *in
return ret;
}
}
if (ret != ERROR) {
return MEASURE_OK;
}
} else {
Info("INTRA: not running because offset=%d, sf_len*max_sf=%d*%d\n", offset, sf_len, max_sf);
}
@ -1216,9 +1261,6 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx)
}
mean_rsrp -= temporal_offset;
}
}
if (cnt > 2) {
return MEASURE_OK;
} else {
return IDLE;
@ -1264,13 +1306,11 @@ void phch_recv::scell_recv::init(srslte::log *log_h, bool sic_pss_enabled, uint3
srslte_sync_set_cfo_i_enable(&sync_find, false);
srslte_sync_set_cfo_pss_enable(&sync_find, true);
srslte_sync_set_pss_filt_enable(&sync_find, true);
srslte_sync_set_sss_eq_enable(&sync_find, false);
srslte_sync_set_sss_eq_enable(&sync_find, true);
sync_find.pss.chest_on_filter = true;
if (!sic_pss_enabled) {
sync_find.sss_channel_equalize = false;
}
sync_find.sss_channel_equalize = true;
reset();
}
@ -1311,13 +1351,12 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset,
if (n_id_2 != (cell.id%3) || sic_pss_enabled) {
srslte_sync_set_N_id_2(&sync_find, n_id_2);
srslte_sync_find_ret_t sync_res, best_sync_res;
srslte_sync_find_ret_t sync_res;
do {
srslte_sync_reset(&sync_find);
srslte_sync_cfo_reset(&sync_find);
best_sync_res = SRSLTE_SYNC_NOFOUND;
sync_res = SRSLTE_SYNC_NOFOUND;
cell_id = 0;
float max_peak = -1;
@ -1330,14 +1369,13 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset,
n_id_2, sf5_cnt, nof_sf/5, sync_res, srslte_sync_get_sf_idx(&sync_find), peak_idx, sync_find.peak_value);
if (sync_find.peak_value > max_peak && sync_res == SRSLTE_SYNC_FOUND) {
best_sync_res = sync_res;
max_sf5 = sf5_cnt;
max_sf_idx = srslte_sync_get_sf_idx(&sync_find);
cell_id = srslte_sync_get_cell_id(&sync_find);
}
}
switch(best_sync_res) {
switch(sync_res) {
case SRSLTE_SYNC_ERROR:
return SRSLTE_ERROR;
fprintf(stderr, "Error finding correlation peak\n");

@ -203,6 +203,22 @@ float phch_worker::get_ref_cfo()
return srslte_chest_dl_get_cfo(&ue_dl.chest);
}
float phch_worker::get_snr()
{
return 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest));
}
float phch_worker::get_rsrp()
{
return 10*log10(srslte_chest_dl_get_rsrp(&ue_dl.chest));
}
float phch_worker::get_noise()
{
return 10*log10(srslte_chest_dl_get_noise_estimate(&ue_dl.chest));
}
float phch_worker::get_cfo()
{
return cfo;
@ -874,19 +890,20 @@ void phch_worker::set_uci_periodic_cqi()
int cqi_fixed = phy->args->cqi_fixed;
int cqi_max = phy->args->cqi_max;
uint8_t ri = (uint8_t) ue_dl.ri;
uint8_t pmi = (uint8_t) ue_dl.pmi[ri];
float sinr = ue_dl.sinr[ri][pmi];
float sinr = ue_dl.sinr[phy->last_ri & SRSLTE_MAX_LAYERS][phy->last_pmi % SRSLTE_MAX_CODEBOOKS];
if (period_cqi.configured && rnti_is_set) {
if (period_cqi.ri_idx_present && srslte_ri_send(period_cqi.pmi_idx, period_cqi.ri_idx, TTI_TX(tti))) {
/* Compute RI, PMI and SINR */
compute_ri(&ri, &pmi, &sinr);
uci_data.uci_ri = ri;
compute_ri(&phy->last_ri, &phy->last_pmi, &sinr);
uci_data.uci_ri = phy->last_ri;
uci_data.uci_ri_len = 1;
uci_data.ri_periodic_report = true;
Debug("PUCCH: Periodic ri=%d\n", ri);
Debug("PUCCH: Periodic ri=%d, SINR=%.1f\n", phy->last_ri, sinr);
} else if (srslte_cqi_send(period_cqi.pmi_idx, TTI_TX(tti))) {
compute_ri(NULL, NULL, NULL);
phy->last_pmi = (uint8_t) ue_dl.pmi[phy->last_ri % SRSLTE_MAX_LAYERS];
srslte_cqi_value_t cqi_report = {0};
if (period_cqi.format_is_subband) {
// TODO: Implement subband periodic reports
@ -907,8 +924,8 @@ void phch_worker::set_uci_periodic_cqi()
}
if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) {
cqi_report.wideband.pmi_present = true;
cqi_report.wideband.pmi = pmi;
cqi_report.wideband.rank_is_not_one = (ri != 0);
cqi_report.wideband.pmi = phy->last_pmi;
cqi_report.wideband.rank_is_not_one = (phy->last_ri != 0);
}
Debug("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db);
}
@ -920,13 +937,11 @@ void phch_worker::set_uci_periodic_cqi()
void phch_worker::set_uci_aperiodic_cqi()
{
uint8_t ri = (uint8_t) ue_dl.ri;
uint8_t pmi = (uint8_t) ue_dl.pmi[ri];
float sinr_db = ue_dl.sinr[ri][pmi];
float sinr_db = ue_dl.sinr[phy->last_ri % SRSLTE_MAX_LAYERS][phy->last_pmi%SRSLTE_MAX_CODEBOOKS];
if (phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic_present) {
/* Compute RI, PMI and SINR */
compute_ri(&ri, &pmi, &sinr_db);
compute_ri(&phy->last_ri, &phy->last_pmi, &sinr_db);
switch(phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic) {
case LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30:
@ -961,7 +976,7 @@ void phch_worker::set_uci_aperiodic_cqi()
/* Set RI = 1 */
if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3 ||
phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) {
uci_data.uci_ri = ri;
uci_data.uci_ri = phy->last_ri;
uci_data.uci_ri_len = 1;
} else {
uci_data.uci_ri_len = 0;
@ -991,13 +1006,13 @@ void phch_worker::set_uci_aperiodic_cqi()
cqi_report.subband_hl.wideband_cqi_cw0 = srslte_cqi_from_snr(sinr_db);
cqi_report.subband_hl.subband_diff_cqi_cw0 = 0; // Always report zero offset on all subbands
if (ri > 0) {
if (phy->last_ri > 0) {
cqi_report.subband_hl.rank_is_not_one = true;
cqi_report.subband_hl.wideband_cqi_cw1 = srslte_cqi_from_snr(sinr_db);
cqi_report.subband_hl.subband_diff_cqi_cw1 = 0; // Always report zero offset on all subbands
}
cqi_report.subband_hl.pmi = pmi;
cqi_report.subband_hl.pmi = phy->last_pmi;
cqi_report.subband_hl.pmi_present = true;
cqi_report.subband_hl.four_antenna_ports = (cell.nof_ports == 4);
@ -1011,7 +1026,7 @@ void phch_worker::set_uci_aperiodic_cqi()
}
uci_data.uci_cqi_len = (uint32_t) cqi_len;
uci_data.uci_ri_len = 1;
uci_data.uci_ri = ri;
uci_data.uci_ri = phy->last_ri;
char cqi_str[SRSLTE_CQI_STR_MAX_CHAR] = {0};
srslte_cqi_to_str(uci_data.uci_cqi, uci_data.uci_cqi_len, cqi_str, SRSLTE_CQI_STR_MAX_CHAR);
@ -1019,11 +1034,11 @@ void phch_worker::set_uci_aperiodic_cqi()
if (cqi_report.subband_hl.rank_is_not_one) {
Info("PUSCH: Aperiodic RM31 ri~1, CQI=%02d/%02d, SINR=%2.1f/%2.1fdB, pmi=%d for %d subbands\n",
cqi_report.subband_hl.wideband_cqi_cw0, cqi_report.subband_hl.wideband_cqi_cw1,
sinr_db, sinr_db, pmi, cqi_report.subband_hl.N);
sinr_db, sinr_db, phy->last_pmi, cqi_report.subband_hl.N);
} else {
Info("PUSCH: Aperiodic RM31 ri=1, CQI=%02d, SINR=%2.1f, pmi=%d for %d subbands\n",
cqi_report.subband_hl.wideband_cqi_cw0,
sinr_db, pmi, cqi_report.subband_hl.N);
sinr_db, phy->last_pmi, cqi_report.subband_hl.N);
}
}
break;
@ -1370,7 +1385,7 @@ void phch_worker::update_measurements()
phy->last_radio_rssi = phy->get_radio()->get_rssi();
phy->rx_gain_offset = phy->avg_rssi_dbm - phy->last_radio_rssi + 30;
} else {
phy->rx_gain_offset = phy->get_radio()->get_rx_gain();
phy->rx_gain_offset = phy->get_radio()->get_rx_gain() + phy->args->rx_gain_offset;
}
}
rssi_read_cnt++;

@ -120,7 +120,7 @@ bool phy::check_args(phy_args_t *args)
}
bool phy::init(srslte::radio_multi* radio_handler, mac_interface_phy *mac, rrc_interface_phy *rrc,
std::vector<void*> log_vec, phy_args_t *phy_args) {
std::vector<srslte::log*> log_vec, phy_args_t *phy_args) {
mlockall(MCL_CURRENT | MCL_FUTURE);
@ -226,7 +226,7 @@ void phy::set_timeadv_rar(uint32_t ta_cmd) {
void phy::set_timeadv(uint32_t ta_cmd) {
uint32_t new_nta = srslte_N_ta_new(n_ta, ta_cmd);
sf_recv.set_time_adv_sec(((float) (new_nta - n_ta))*SRSLTE_LTE_TS);
//sf_recv.set_time_adv_sec(((float) new_nta)*SRSLTE_LTE_TS);
Info("PHY: Set TA: ta_cmd: %d, n_ta: %d, old_n_ta: %d, ta_usec: %.1f\n", ta_cmd, new_nta, n_ta, ((float) new_nta)*SRSLTE_LTE_TS*1e6);
n_ta = new_nta;
}

@ -68,7 +68,7 @@ bool ue::init(all_args_t *args_)
char tmp[16];
sprintf(tmp, "PHY%d",i);
mylog->init(tmp, logger, true);
phy_log.push_back((void*) mylog);
phy_log.push_back(mylog);
}
mac_log.init("MAC ", logger, true);
@ -91,7 +91,7 @@ bool ue::init(all_args_t *args_)
char tmp[16];
sprintf(tmp, "PHY_LIB");
lib_log->init(tmp, logger, true);
phy_log.push_back((void*) lib_log);
phy_log.push_back(lib_log);
((srslte::log_filter*) phy_log[args->expert.phy.nof_phy_threads])->set_level(level(args->log.phy_lib_level));
@ -130,11 +130,7 @@ bool ue::init(all_args_t *args_)
// Init layers
if (args->rf.rx_gain < 0) {
phy.set_agc_enable(true);
}
// PHY initis in background, start before radio
// PHY inits in background, start before radio
args->expert.phy.nof_rx_ant = args->rf.nof_rx_ant;
phy.init(&radio, &mac, &rrc, phy_log, &args->expert.phy);
@ -222,6 +218,11 @@ bool ue::init(all_args_t *args_)
phy.wait_initialize();
phy.configure_ul_params();
// Enable AGC once PHY is initialized
if (args->rf.rx_gain < 0) {
phy.set_agc_enable(true);
}
printf("...\n");
nas.attach_request();

@ -49,12 +49,20 @@ rrc::rrc()
:state(RRC_STATE_IDLE)
,drb_up(false)
,sysinfo_index(0)
,serving_cell(NULL)
{
n310_cnt = 0;
n311_cnt = 0;
serving_cell = new cell_t();
}
rrc::~rrc()
{
if (serving_cell) {
delete(serving_cell);
}
}
static void liblte_rrc_handler(void *ctx, char *str) {
rrc *r = (rrc *) ctx;
r->liblte_rrc_log(str);
@ -333,11 +341,14 @@ void rrc::run_si_acquisition_procedure()
// Instruct MAC to look for SIB1
tti = mac->get_current_tti();
si_win_start = sib_start_tti(tti, 2, 0, 5);
if (tti > last_win_start + 10) {
if (last_win_start == 0 ||
(srslte_tti_interval(last_win_start, tti) > 20 && srslte_tti_interval(last_win_start, tti) < 1000))
{
last_win_start = si_win_start;
mac->bcch_start_rx(si_win_start, 1);
rrc_log->debug("Instructed MAC to search for SIB1, win_start=%d, win_len=%d\n",
si_win_start, 1);
rrc_log->info("Instructed MAC to search for SIB1, win_start=%d, win_len=%d, interval=%d\n",
si_win_start, 1, srslte_tti_interval(last_win_start, tti));
nof_sib1_trials++;
if (nof_sib1_trials >= SIB1_SEARCH_TIMEOUT) {
if (state == RRC_STATE_CELL_SELECTING) {
@ -361,13 +372,15 @@ void rrc::run_si_acquisition_procedure()
tti = mac->get_current_tti();
period = liblte_rrc_si_periodicity_num[serving_cell->sib1.sched_info[sysinfo_index].si_periodicity];
si_win_start = sib_start_tti(tti, period, offset, sf);
si_win_len = liblte_rrc_si_window_length_num[serving_cell->sib1.si_window_length];
if (tti > last_win_start + 10) {
if (last_win_start == 0 ||
(srslte_tti_interval(last_win_start, tti) > period*10 && srslte_tti_interval(last_win_start, tti) < 1000))
{
last_win_start = si_win_start;
si_win_len = liblte_rrc_si_window_length_num[serving_cell->sib1.si_window_length];
mac->bcch_start_rx(si_win_start, si_win_len);
rrc_log->debug("Instructed MAC to search for system info, win_start=%d, win_len=%d\n",
rrc_log->info("Instructed MAC to search for system info, win_start=%d, win_len=%d\n",
si_win_start, si_win_len);
}
@ -1054,6 +1067,7 @@ bool rrc::ho_prepare() {
int target_cell_idx = find_neighbour_cell(serving_cell->earfcn, mob_reconf.mob_ctrl_info.target_pci);
if (target_cell_idx < 0) {
rrc_log->console("Received HO command to unknown PCI=%d\n", mob_reconf.mob_ctrl_info.target_pci);
rrc_log->error("Could not find target cell earfcn=%d, pci=%d\n", serving_cell->earfcn, mob_reconf.mob_ctrl_info.target_pci);
return false;
}
@ -1075,6 +1089,7 @@ bool rrc::ho_prepare() {
ho_src_rnti = uernti.crnti;
// Reset/Reestablish stack
mac->bcch_stop_rx(); // FIXME: change function name
phy->meas_reset();
mac->wait_uplink();
pdcp->reestablish();
@ -1304,6 +1319,9 @@ void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu) {
handle_sib13();
}
}
last_win_start = 0;
if(serving_cell->has_valid_sib2) {
sysinfo_index++;
}
@ -1762,9 +1780,9 @@ void rrc::apply_rr_config_common_dl(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config)
mac->get_config(&mac_cfg);
if (config->rach_cnfg_present) {
memcpy(&mac_cfg.rach, &config->rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT));
mac_cfg.ul_harq_params.max_harq_msg3_tx = config->rach_cnfg.max_harq_msg3_tx;
}
mac_cfg.prach_config_index = config->prach_cnfg.root_sequence_index;
mac_cfg.ul_harq_params.max_harq_msg3_tx = config->rach_cnfg.max_harq_msg3_tx;
mac->set_config(&mac_cfg);
@ -2530,6 +2548,8 @@ void rrc::rrc_meas::calculate_triggers(uint32_t tti)
}
}
for (std::map<uint32_t, meas_t>::iterator m = active.begin(); m != active.end(); ++m) {
report_cfg_t *cfg = &reports_cfg[m->second.report_id];
float hyst = 0.5*cfg->event.hysteresis;
@ -2554,45 +2574,53 @@ void rrc::rrc_meas::calculate_triggers(uint32_t tti)
enter_condition = Mp + hyst < range_to_value(cfg->trigger_quantity, cfg->event.event_a1.eutra.range);
exit_condition = Mp - hyst > range_to_value(cfg->trigger_quantity, cfg->event.event_a1.eutra.range);
}
// check only if
gen_report |= process_event(&cfg->event, tti, enter_condition, exit_condition,
&m->second, &m->second.cell_values[serving_cell_idx]);
&m->second, &pcell_measurement);
if (gen_report) {
log_h->info("Triggered by A1/A2 event\n");
}
// Rest are evaluated for every cell in frequency
} else {
meas_obj_t *obj = &objects[m->second.object_id];
for (std::map<uint32_t, meas_cell_t>::iterator cell = obj->cells.begin(); cell != obj->cells.end(); ++cell) {
float Ofn = obj->q_offset;
float Ocn = cell->second.q_offset;
float Mn = m->second.cell_values[cell->second.pci].ms[cfg->trigger_quantity];
float Off=0, th=0, th1=0, th2=0;
bool enter_condition = false;
bool exit_condition = false;
switch (event_id) {
case LIBLTE_RRC_EVENT_ID_EUTRA_A3:
Off = 0.5*cfg->event.event_a3.offset;
enter_condition = Mn + Ofn + Ocn - hyst > Mp + Ofp + Ocp + Off;
exit_condition = Mn + Ofn + Ocn + hyst < Mp + Ofp + Ocp + Off;
break;
case LIBLTE_RRC_EVENT_ID_EUTRA_A4:
th = range_to_value(cfg->trigger_quantity, cfg->event.event_a4.eutra.range);
enter_condition = Mn + Ofn + Ocn - hyst > th;
exit_condition = Mn + Ofn + Ocn + hyst < th;
break;
case LIBLTE_RRC_EVENT_ID_EUTRA_A5:
th1 = range_to_value(cfg->trigger_quantity, cfg->event.event_a5.eutra1.range);
th2 = range_to_value(cfg->trigger_quantity, cfg->event.event_a5.eutra2.range);
enter_condition = (Mp + hyst < th1) && (Mn + Ofn + Ocn - hyst > th2);
exit_condition = (Mp - hyst > th1) && (Mn + Ofn + Ocn + hyst < th2);
break;
default:
log_h->error("Error event %s not implemented\n", event_str);
if (m->second.cell_values.count(cell->second.pci)) {
float Ofn = obj->q_offset;
float Ocn = cell->second.q_offset;
float Mn = m->second.cell_values[cell->second.pci].ms[cfg->trigger_quantity];
float Off=0, th=0, th1=0, th2=0;
bool enter_condition = false;
bool exit_condition = false;
switch (event_id) {
case LIBLTE_RRC_EVENT_ID_EUTRA_A3:
Off = 0.5*cfg->event.event_a3.offset;
enter_condition = Mn + Ofn + Ocn - hyst > Mp + Ofp + Ocp + Off;
exit_condition = Mn + Ofn + Ocn + hyst < Mp + Ofp + Ocp + Off;
break;
case LIBLTE_RRC_EVENT_ID_EUTRA_A4:
th = range_to_value(cfg->trigger_quantity, cfg->event.event_a4.eutra.range);
enter_condition = Mn + Ofn + Ocn - hyst > th;
exit_condition = Mn + Ofn + Ocn + hyst < th;
break;
case LIBLTE_RRC_EVENT_ID_EUTRA_A5:
th1 = range_to_value(cfg->trigger_quantity, cfg->event.event_a5.eutra1.range);
th2 = range_to_value(cfg->trigger_quantity, cfg->event.event_a5.eutra2.range);
enter_condition = (Mp + hyst < th1) && (Mn + Ofn + Ocn - hyst > th2);
exit_condition = (Mp - hyst > th1) && (Mn + Ofn + Ocn + hyst < th2);
break;
default:
log_h->error("Error event %s not implemented\n", event_str);
}
gen_report |= process_event(&cfg->event, tti, enter_condition, exit_condition,
&m->second, &m->second.cell_values[cell->second.pci]);
}
gen_report |= process_event(&cfg->event, tti, enter_condition, exit_condition,
&m->second, &m->second.cell_values[cell->second.pci]);
}
}
}
if (gen_report) {
log_h->info("Generate report MeasId=%d, from event\n", m->first);
generate_report(m->first);
}
}
@ -2622,6 +2650,7 @@ void rrc::rrc_meas::ho_finish() {
bool rrc::rrc_meas::timer_expired(uint32_t timer_id) {
for (std::map<uint32_t, meas_t>::iterator iter = active.begin(); iter != active.end(); ++iter) {
if (iter->second.periodic_timer == timer_id) {
log_h->info("Generate report MeasId=%d, from timerId=%d\n", iter->first, timer_id);
generate_report(iter->first);
return true;
}
@ -2805,6 +2834,8 @@ void rrc::rrc_meas::parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *cfg)
remove_meas_id(cfg->meas_id_to_remove_list[i]);
}
log_h->info("nof active measId=%d\n", active.size());
// Measurement identity addition/modification 5.5.2.3
if (cfg->meas_id_to_add_mod_list_present) {
for (uint32_t i=0;i<cfg->meas_id_to_add_mod_list.N_meas_id;i++) {
@ -2819,8 +2850,9 @@ void rrc::rrc_meas::parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *cfg)
}
active[measId->meas_id].object_id = measId->meas_obj_id;
active[measId->meas_id].report_id = measId->rep_cnfg_id;
log_h->info("MEAS: %s measId=%d, measObjectId=%d, reportConfigId=%d\n",
is_new?"Added":"Updated", measId->meas_id, measId->meas_obj_id, measId->rep_cnfg_id);
log_h->info("MEAS: %s measId=%d, measObjectId=%d, reportConfigId=%d, nof_values=%d\n",
is_new?"Added":"Updated", measId->meas_id, measId->meas_obj_id, measId->rep_cnfg_id,
active[measId->meas_id].cell_values.size());
}
}

@ -451,12 +451,12 @@ int main(int argc, char *argv[])
exit(1);
}
std::vector<void*> phy_log;
std::vector<srslte::log*> phy_log;
srslte::log_filter *mylog = new srslte::log_filter("PHY");
char tmp[16];
sprintf(tmp, "PHY%d",0);
phy_log.push_back((void*) mylog);
phy_log.push_back((srslte::log*) mylog);
switch (prog_args.verbose) {
case 1:

@ -101,19 +101,11 @@ imei = 353490069873319
#####################################################################
# RRC configuration
#
# stimsi_attach: If enabled, always tries first an S-TMSI attach using the
# S-TMSI value stored in .stimsi file generated in previous run
# mmec_value: If defined (non-zero), overwrites the value stored in .stimsi file
# m_tmsi_value: If defined (non-zero), overwrites the value stored in .stimsi file
#
# ue_category: Sets UE category (range 1-5). Default: 4
# feature_group: Hex value of the featureGroupIndicators field in the
# UECapabilityInformation message. Default 0xe6041c00
#####################################################################
[rrc]
#stmsi_attach = false
#mmec_value = 0
#mtmsi_value = 0
#ue_category = 4
#feature_group = 0xe6041c00

Loading…
Cancel
Save