Merge branch 'mob_crypto_mimo' into next

master
Ismael Gomez 7 years ago
commit fba900f63c

@ -67,7 +67,6 @@ configure_file(
option(ENABLE_SRSUE "Build srsUE application" ON) option(ENABLE_SRSUE "Build srsUE application" ON)
option(ENABLE_SRSENB "Build srsENB application" ON) option(ENABLE_SRSENB "Build srsENB application" ON)
option(ENABLE_VOLK "Enable use of VOLK SIMD library" OFF)
option(ENABLE_GUI "Enable GUI (using srsGUI)" ON) option(ENABLE_GUI "Enable GUI (using srsGUI)" ON)
option(ENABLE_BLADERF "Enable BladeRF" ON) option(ENABLE_BLADERF "Enable BladeRF" ON)

@ -295,7 +295,7 @@ int main(int argc, char **argv) {
return -1; return -1;
} }
srslte_rf_start_rx_stream(&rf); srslte_rf_start_rx_stream(&rf, false);
float rx_gain_offset = 0; float rx_gain_offset = 0;
@ -329,7 +329,7 @@ int main(int argc, char **argv) {
case DECODE_SIB: case DECODE_SIB:
/* We are looking for SI Blocks, search only in appropiate places */ /* We are looking for SI Blocks, search only in appropiate places */
if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) { if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) {
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); n = srslte_ue_dl_decode(&ue_dl, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks);
if (n < 0) { if (n < 0) {
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
return -1; return -1;
@ -366,7 +366,7 @@ int main(int argc, char **argv) {
if ((nframes%100) == 0 || rx_gain_offset == 0) { if ((nframes%100) == 0 || rx_gain_offset == 0) {
if (srslte_rf_has_rssi(&rf)) { if (srslte_rf_has_rssi(&rf)) {
rx_gain_offset = 10*log10(rssi*1000)-srslte_rf_get_rssi(&rf); rx_gain_offset = 30+10*log10(rssi*1000)-srslte_rf_get_rssi(&rf);
} else { } else {
rx_gain_offset = srslte_rf_get_rx_gain(&rf); rx_gain_offset = srslte_rf_get_rx_gain(&rf);
} }

@ -221,7 +221,7 @@ int main(int argc, char **argv) {
INFO("Setting sampling frequency %.2f MHz for PSS search\n", SRSLTE_CS_SAMP_FREQ/1000000); INFO("Setting sampling frequency %.2f MHz for PSS search\n", SRSLTE_CS_SAMP_FREQ/1000000);
srslte_rf_set_rx_srate(&rf, SRSLTE_CS_SAMP_FREQ); srslte_rf_set_rx_srate(&rf, SRSLTE_CS_SAMP_FREQ);
INFO("Starting receiver...\n", 0); INFO("Starting receiver...\n", 0);
srslte_rf_start_rx_stream(&rf); srslte_rf_start_rx_stream(&rf, false);
n = srslte_ue_cellsearch_scan(&cs, found_cells, NULL); n = srslte_ue_cellsearch_scan(&cs, found_cells, NULL);
if (n < 0) { if (n < 0) {

@ -570,7 +570,7 @@ int main(int argc, char **argv) {
#ifndef DISABLE_RF #ifndef DISABLE_RF
if (!prog_args.input_file_name) { if (!prog_args.input_file_name) {
srslte_rf_start_rx_stream(&rf); srslte_rf_start_rx_stream(&rf, false);
} }
#endif #endif
@ -676,19 +676,19 @@ int main(int argc, char **argv) {
if(sfidx != 1 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe if(sfidx != 1 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe
if (cell.nof_ports == 1) { if (cell.nof_ports == 1) {
/* Transmission mode 1 */ /* Transmission mode 1 */
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); n = srslte_ue_dl_decode(&ue_dl, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks);
} else { } else {
if (prog_args.rf_nof_rx_ant == 1) { if (prog_args.rf_nof_rx_ant == 1) {
/* Transmission mode 2 */ /* Transmission mode 2 */
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 1, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), n = srslte_ue_dl_decode(&ue_dl, data, 1, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync),
acks); acks);
} else { } else {
/* Transmission mode 3 */ /* Transmission mode 3 */
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), n = srslte_ue_dl_decode(&ue_dl, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync),
acks); acks);
if (n < 1) { if (n < 1) {
/* Transmission mode 4 */ /* Transmission mode 4 */
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 3, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), n = srslte_ue_dl_decode(&ue_dl, data, 3, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync),
acks); acks);
} }
} }
@ -701,7 +701,6 @@ int main(int argc, char **argv) {
}else{ // MBSFN subframe }else{ // MBSFN subframe
n = srslte_ue_dl_decode_mbsfn(&ue_dl, n = srslte_ue_dl_decode_mbsfn(&ue_dl,
sf_buffer,
data[0], data[0],
sfn*10+srslte_ue_sync_get_sfidx(&ue_sync)); sfn*10+srslte_ue_sync_get_sfidx(&ue_sync));
if(n>0){ if(n>0){
@ -959,7 +958,7 @@ void *plot_thread_run(void *arg) {
plot_real_init(&pce); plot_real_init(&pce);
plot_real_setTitle(&pce, "Channel Response - Magnitude"); plot_real_setTitle(&pce, "Channel Response - Magnitude");
plot_real_setLabels(&pce, "Index", "dB"); plot_real_setLabels(&pce, "Index", "dB");
plot_real_setYAxisScale(&pce, -M_PI, M_PI); plot_real_setYAxisScale(&pce, -40, 40);
plot_real_init(&p_sync); plot_real_init(&p_sync);
plot_real_setTitle(&p_sync, "PSS Cross-Corr abs value"); plot_real_setTitle(&p_sync, "PSS Cross-Corr abs value");
@ -995,15 +994,11 @@ void *plot_thread_run(void *arg) {
tmp_plot2[g+i] = -80; tmp_plot2[g+i] = -80;
} }
} }
uint32_t nrefs = 2*ue_dl.cell.nof_prb; plot_real_setNewData(&pce, tmp_plot2, sz);
for (i=0;i<nrefs;i++) {
tmp_plot2[i] = cargf(ue_dl.chest.tmp_cfo_estimate[i]);
}
plot_real_setNewData(&pce, tmp_plot2, nrefs);
if (!prog_args.input_file_name) { if (!prog_args.input_file_name) {
if (plot_track) { if (plot_track) {
srslte_pss_synch_t *pss_obj = srslte_sync_get_cur_pss_obj(&ue_sync.strack); srslte_pss_t *pss_obj = srslte_sync_get_cur_pss_obj(&ue_sync.strack);
int max = srslte_vec_max_fi(pss_obj->conv_output_avg, pss_obj->frame_size+pss_obj->fft_size-1); int max = srslte_vec_max_fi(pss_obj->conv_output_avg, pss_obj->frame_size+pss_obj->fft_size-1);
srslte_vec_sc_prod_fff(pss_obj->conv_output_avg, srslte_vec_sc_prod_fff(pss_obj->conv_output_avg,
1/pss_obj->conv_output_avg[max], 1/pss_obj->conv_output_avg[max],

@ -102,8 +102,8 @@ void parse_args(int argc, char **argv) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
srslte_filesource_t fsrc; srslte_filesource_t fsrc;
srslte_filesink_t fsink; srslte_filesink_t fsink;
srslte_pss_synch_t pss[3]; // One for each N_id_2 srslte_pss_t pss[3]; // One for each N_id_2
srslte_sss_synch_t sss[3]; // One for each N_id_2 srslte_sss_t sss[3]; // One for each N_id_2
srslte_cfo_t cfocorr; srslte_cfo_t cfocorr;
int peak_pos[3]; int peak_pos[3];
float *cfo; float *cfo;
@ -163,19 +163,19 @@ int main(int argc, char **argv) {
* a) requries more memory but has less latency and is paralellizable. * a) requries more memory but has less latency and is paralellizable.
*/ */
for (N_id_2=0;N_id_2<3;N_id_2++) { for (N_id_2=0;N_id_2<3;N_id_2++) {
if (srslte_pss_synch_init(&pss[N_id_2], frame_length)) { if (srslte_pss_init(&pss[N_id_2], frame_length)) {
fprintf(stderr, "Error initializing PSS object\n"); fprintf(stderr, "Error initializing PSS object\n");
exit(-1); exit(-1);
} }
if (srslte_pss_synch_set_N_id_2(&pss[N_id_2], N_id_2)) { if (srslte_pss_set_N_id_2(&pss[N_id_2], N_id_2)) {
fprintf(stderr, "Error initializing N_id_2\n"); fprintf(stderr, "Error initializing N_id_2\n");
exit(-1); exit(-1);
} }
if (srslte_sss_synch_init(&sss[N_id_2], 128)) { if (srslte_sss_init(&sss[N_id_2], 128)) {
fprintf(stderr, "Error initializing SSS object\n"); fprintf(stderr, "Error initializing SSS object\n");
exit(-1); exit(-1);
} }
if (srslte_sss_synch_set_N_id_2(&sss[N_id_2], N_id_2)) { if (srslte_sss_set_N_id_2(&sss[N_id_2], N_id_2)) {
fprintf(stderr, "Error initializing N_id_2\n"); fprintf(stderr, "Error initializing N_id_2\n");
exit(-1); exit(-1);
} }
@ -199,10 +199,10 @@ int main(int argc, char **argv) {
if (force_N_id_2 != -1) { if (force_N_id_2 != -1) {
N_id_2 = force_N_id_2; N_id_2 = force_N_id_2;
peak_pos[N_id_2] = srslte_pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); peak_pos[N_id_2] = srslte_pss_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]);
} else { } else {
for (N_id_2=0;N_id_2<3;N_id_2++) { for (N_id_2=0;N_id_2<3;N_id_2++) {
peak_pos[N_id_2] = srslte_pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); peak_pos[N_id_2] = srslte_pss_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]);
} }
float max_value=-99999; float max_value=-99999;
N_id_2=-1; N_id_2=-1;
@ -220,13 +220,13 @@ int main(int argc, char **argv) {
sss_idx = peak_pos[N_id_2]-2*(symbol_sz+SRSLTE_CP_LEN(symbol_sz,SRSLTE_CP_NORM_LEN)); sss_idx = peak_pos[N_id_2]-2*(symbol_sz+SRSLTE_CP_LEN(symbol_sz,SRSLTE_CP_NORM_LEN));
if (sss_idx >= 0) { if (sss_idx >= 0) {
srslte_sss_synch_m0m1_diff(&sss[N_id_2], &input[sss_idx], srslte_sss_m0m1_diff(&sss[N_id_2], &input[sss_idx],
&m0, &m0_value, &m1, &m1_value); &m0, &m0_value, &m1, &m1_value);
cfo[frame_cnt] = srslte_pss_synch_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2]-128]); cfo[frame_cnt] = srslte_pss_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2]-128]);
printf("\t%d\t%d\t%d\t%d\t%.3f\t\t%3d\t%d\t%d\t%.3f\n", printf("\t%d\t%d\t%d\t%d\t%.3f\t\t%3d\t%d\t%d\t%.3f\n",
frame_cnt,N_id_2, srslte_sss_synch_N_id_1(&sss[N_id_2], m0, m1), frame_cnt,N_id_2, srslte_sss_N_id_1(&sss[N_id_2], m0, m1),
srslte_sss_synch_subframe(m0, m1), peak_value[N_id_2], srslte_sss_subframe(m0, m1), peak_value[N_id_2],
peak_pos[N_id_2], m0, m1, peak_pos[N_id_2], m0, m1,
cfo[frame_cnt]); cfo[frame_cnt]);
} }
@ -254,8 +254,8 @@ int main(int argc, char **argv) {
printf("Average CFO: %.3f\n", cfo_mean); printf("Average CFO: %.3f\n", cfo_mean);
for (N_id_2=0;N_id_2<3;N_id_2++) { for (N_id_2=0;N_id_2<3;N_id_2++) {
srslte_pss_synch_free(&pss[N_id_2]); srslte_pss_free(&pss[N_id_2]);
srslte_sss_synch_free(&sss[N_id_2]); srslte_sss_free(&sss[N_id_2]);
} }
srslte_filesource_free(&fsrc); srslte_filesource_free(&fsrc);

@ -153,7 +153,7 @@ int main(int argc, char **argv) {
printf("Correctly RX rate: %.2f MHz\n", srate*1e-6); printf("Correctly RX rate: %.2f MHz\n", srate*1e-6);
srslte_rf_rx_wait_lo_locked(&rf); srslte_rf_rx_wait_lo_locked(&rf);
srslte_rf_start_rx_stream(&rf); srslte_rf_start_rx_stream(&rf, false);
while((sample_count < nof_samples || nof_samples == -1) while((sample_count < nof_samples || nof_samples == -1)

@ -158,7 +158,7 @@ int main(int argc, char **argv) {
exit(-1); exit(-1);
} }
srslte_rf_rx_wait_lo_locked(&rf); srslte_rf_rx_wait_lo_locked(&rf);
srslte_rf_start_rx_stream(&rf); srslte_rf_start_rx_stream(&rf, false);
cell.cp = SRSLTE_CP_NORM; cell.cp = SRSLTE_CP_NORM;
cell.id = N_id_2; cell.id = N_id_2;

@ -175,7 +175,7 @@ int main(int argc, char **argv) {
srslte_timestamp_t tstamp; srslte_timestamp_t tstamp;
srslte_rf_start_rx_stream(&rf); srslte_rf_start_rx_stream(&rf, false);
uint32_t nframe=0; uint32_t nframe=0;

@ -2545,6 +2545,9 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_transaction_identifier_ie(uint8
// Enums // Enums
// Structs // Structs
// Functions // Functions
LIBLTE_ERROR_ENUM liblte_mme_parse_msg_sec_header(LIBLTE_BYTE_MSG_STRUCT *msg,
uint8 *pd,
uint8 *sec_hdr_type);
LIBLTE_ERROR_ENUM liblte_mme_parse_msg_header(LIBLTE_BYTE_MSG_STRUCT *msg, LIBLTE_ERROR_ENUM liblte_mme_parse_msg_header(LIBLTE_BYTE_MSG_STRUCT *msg,
uint8 *pd, uint8 *pd,
uint8 *msg_type); uint8 *msg_type);

@ -1218,6 +1218,9 @@ typedef enum{
}LIBLTE_RRC_REPORT_AMOUNT_ENUM; }LIBLTE_RRC_REPORT_AMOUNT_ENUM;
static const char liblte_rrc_report_amount_text[LIBLTE_RRC_REPORT_AMOUNT_N_ITEMS][20] = { "r1", "r2", "r4", "r8", static const char liblte_rrc_report_amount_text[LIBLTE_RRC_REPORT_AMOUNT_N_ITEMS][20] = { "r1", "r2", "r4", "r8",
"r16", "r32", "r64", "INFINITY"}; "r16", "r32", "r64", "INFINITY"};
static const int8 liblte_rrc_report_amount_num[LIBLTE_RRC_REPORT_AMOUNT_N_ITEMS] = {1, 2, 4, 8, 16, 32, 64, -1};
typedef enum{ typedef enum{
LIBLTE_RRC_THRESHOLD_UTRA_TYPE_RSCP = 0, LIBLTE_RRC_THRESHOLD_UTRA_TYPE_RSCP = 0,
LIBLTE_RRC_THRESHOLD_UTRA_TYPE_ECNO, LIBLTE_RRC_THRESHOLD_UTRA_TYPE_ECNO,
@ -2681,6 +2684,7 @@ typedef enum{
}LIBLTE_RRC_T304_ENUM; }LIBLTE_RRC_T304_ENUM;
static const char liblte_rrc_t304_text[LIBLTE_RRC_T304_N_ITEMS][20] = { "50", "100", "150", "200", static const char liblte_rrc_t304_text[LIBLTE_RRC_T304_N_ITEMS][20] = { "50", "100", "150", "200",
"500", "1000", "2000", "SPARE"}; "500", "1000", "2000", "SPARE"};
static const int32 liblte_rrc_t304_num[LIBLTE_RRC_T304_N_ITEMS] = {50, 100, 150, 200, 500, 1000, 2000, -1};
// Structs // Structs
typedef struct{ typedef struct{
uint8 p_b; uint8 p_b;

@ -96,6 +96,35 @@ static const char error_text[ERROR_N_ITEMS][20] = { "None",
"Can't start", "Can't start",
"Already started"}; "Already started"};
// Radio bearers
typedef enum{
RB_ID_SRB0 = 0,
RB_ID_SRB1,
RB_ID_SRB2,
RB_ID_DRB1,
RB_ID_DRB2,
RB_ID_DRB3,
RB_ID_DRB4,
RB_ID_DRB5,
RB_ID_DRB6,
RB_ID_DRB7,
RB_ID_DRB8,
RB_ID_MAX
} rb_id_t;
static const char rb_id_str[RB_ID_MAX][8] = {"SRB0", "SRB1", "SRB2",
"DRB1", "DRB2", "DRB3",
"DRB4", "DRB5", "DRB6",
"DRB7", "DRB8"};
inline const char* get_rb_name(uint32_t lcid) {
if (lcid < RB_ID_MAX) {
return rb_id_str[lcid];
} else {
return "INVALID_RB";
}
}
/****************************************************************************** /******************************************************************************
* Byte and Bit buffers * Byte and Bit buffers
* *

@ -52,13 +52,11 @@ public:
:direction(direction_) :direction(direction_)
,is_control(is_control_) ,is_control(is_control_)
,is_data(is_data_) ,is_data(is_data_)
,do_security(false)
,sn_len(12) {} ,sn_len(12) {}
uint8_t direction; uint8_t direction;
bool is_control; bool is_control;
bool is_data; bool is_data;
bool do_security;
uint8_t sn_len; uint8_t sn_len;
// TODO: Support the following configurations // TODO: Support the following configurations

@ -86,6 +86,15 @@ LIBLTE_ERROR_ENUM liblte_security_generate_k_enb(uint8 *k_asme,
uint32 nas_count, uint32 nas_count,
uint8 *k_enb); uint8 *k_enb);
LIBLTE_ERROR_ENUM liblte_security_generate_k_enb_star(uint8 *k_enb,
uint32 pci,
uint32_t earfcn,
uint8 *k_enb_star);
LIBLTE_ERROR_ENUM liblte_security_generate_nh( uint8_t *k_asme,
uint8_t *sync,
uint8_t *nh);
/********************************************************************* /*********************************************************************
Name: liblte_security_generate_k_nas Name: liblte_security_generate_k_nas
@ -121,6 +130,8 @@ LIBLTE_ERROR_ENUM liblte_security_generate_k_nas(uint8
uint8 *k_nas_enc, uint8 *k_nas_enc,
uint8 *k_nas_int); uint8 *k_nas_int);
/********************************************************************* /*********************************************************************
Name: liblte_security_generate_k_rrc Name: liblte_security_generate_k_rrc
@ -185,6 +196,73 @@ LIBLTE_ERROR_ENUM liblte_security_128_eia2(uint8 *key,
LIBLTE_BIT_MSG_STRUCT *msg, LIBLTE_BIT_MSG_STRUCT *msg,
uint8 *mac); uint8 *mac);
/*********************************************************************
Name: liblte_security_encryption_eea1
Description: 128-bit encryption algorithm EEA1.
Document Reference: 33.401 v13.1.0 Annex B.1.2
35.215 v13.0.0 References
Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D1 v2.1
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_encryption_eea1(uint8 *key,
uint32 count,
uint8 bearer,
uint8 direction,
uint8 *msg,
uint32 msg_len,
uint8 *out);
/*********************************************************************
Name: liblte_security_decryption_eea1
Description: 128-bit decryption algorithm EEA1.
Document Reference: 33.401 v13.1.0 Annex B.1.2
35.215 v13.0.0 References
Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D1 v2.1
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_decryption_eea1(uint8 *key,
uint32 count,
uint8 bearer,
uint8 direction,
uint8 *ct,
uint32 ct_len,
uint8 *out);
/*********************************************************************
Name: liblte_security_encryption_eea2
Description: 128-bit encryption algorithm EEA2.
Document Reference: 33.401 v13.1.0 Annex B.1.3
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_encryption_eea2(uint8 *key,
uint32 count,
uint8 bearer,
uint8 direction,
uint8 *msg,
uint32 msg_len,
uint8 *out);
/*********************************************************************
Name: liblte_security_decryption_eea2
Description: 128-bit decryption algorithm EEA2.
Document Reference: 33.401 v13.1.0 Annex B.1.3
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_decryption_eea2(uint8 *key,
uint32 count,
uint8 bearer,
uint8 direction,
uint8 *ct,
uint32 ct_len,
uint8 *out);
/********************************************************************* /*********************************************************************
Name: liblte_security_milenage_f1 Name: liblte_security_milenage_f1

@ -38,6 +38,18 @@ int aes_crypt_ecb( aes_context *ctx,
return mbedtls_aes_crypt_ecb(ctx, mode, input, output); return mbedtls_aes_crypt_ecb(ctx, mode, input, output);
} }
int aes_crypt_ctr(aes_context *ctx,
size_t length,
size_t *nc_off,
unsigned char nonce_counter[16],
unsigned char stream_block[16],
const unsigned char *input,
unsigned char *output )
{
return mbedtls_aes_crypt_ctr(ctx, length, nc_off, nonce_counter,
stream_block, input, output);
}
void sha256(const unsigned char *key, size_t keylen, void sha256(const unsigned char *key, size_t keylen,
const unsigned char *input, size_t ilen, const unsigned char *input, size_t ilen,
unsigned char output[32], int is224 ) unsigned char output[32], int is224 )

@ -39,6 +39,9 @@ public:
void enable(bool en); void enable(bool en);
void open(const char *filename, uint32_t ue_id = 0); void open(const char *filename, uint32_t ue_id = 0);
void close(); void close();
void set_ue_id(uint16_t ue_id);
void write_ul_crnti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint32_t reTX, uint32_t tti); void write_ul_crnti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint32_t reTX, uint32_t tti);
void write_dl_crnti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t crnti, bool crc_ok, uint32_t tti); void write_dl_crnti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t crnti, bool crc_ok, uint32_t tti);
void write_dl_ranti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t ranti, bool crc_ok, uint32_t tti); void write_dl_ranti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t ranti, bool crc_ok, uint32_t tti);

@ -0,0 +1,25 @@
#ifndef NAS_PCAP_H
#define NAS_PCAP_H
#include "srslte/common/pcap.h"
namespace srslte {
class nas_pcap
{
public:
nas_pcap() {enable_write=false; ue_id=0; pcap_file = NULL; }
void enable();
void open(const char *filename, uint32_t ue_id=0);
void close();
void write_nas(uint8_t *pdu, uint32_t pdu_len_bytes);
private:
bool enable_write;
FILE *pcap_file;
uint32_t ue_id;
void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes);
};
} //namespace srsue
#endif // NAS_PCAP_H

@ -33,6 +33,7 @@
#include <sys/time.h> #include <sys/time.h>
#define MAC_LTE_DLT 147 #define MAC_LTE_DLT 147
#define NAS_LTE_DLT 148
/* This structure gets written to the start of the file */ /* This structure gets written to the start of the file */
@ -73,29 +74,14 @@ typedef struct pcaprec_hdr_s {
#define M_RNTI 6 #define M_RNTI 6
#define MAC_LTE_START_STRING "mac-lte" #define MAC_LTE_START_STRING "mac-lte"
#define MAC_LTE_PAYLOAD_TAG 0x01
#define MAC_LTE_RNTI_TAG 0x02 #define MAC_LTE_RNTI_TAG 0x02
/* 2 bytes, network order */
#define MAC_LTE_UEID_TAG 0x03 #define MAC_LTE_UEID_TAG 0x03
/* 2 bytes, network order */
#define MAC_LTE_FRAME_SUBFRAME_TAG 0x04 #define MAC_LTE_FRAME_SUBFRAME_TAG 0x04
/* 2 bytes, network order */
/* SFN is stored in 12 MSB and SF in 4 LSB */
#define MAC_LTE_PREDFINED_DATA_TAG 0x05 #define MAC_LTE_PREDFINED_DATA_TAG 0x05
/* 1 byte */
#define MAC_LTE_RETX_TAG 0x06 #define MAC_LTE_RETX_TAG 0x06
/* 1 byte */
#define MAC_LTE_CRC_STATUS_TAG 0x07 #define MAC_LTE_CRC_STATUS_TAG 0x07
/* 1 byte */
/* MAC PDU. Following this tag comes the actual MAC PDU (there is no length, the PDU
continues until the end of the frame) */
#define MAC_LTE_PAYLOAD_TAG 0x01
/* Context information for every MAC PDU that will be logged */ /* Context information for every MAC PDU that will be logged */
@ -110,17 +96,20 @@ typedef struct MAC_Context_Info_t {
unsigned short sysFrameNumber; unsigned short sysFrameNumber;
unsigned short subFrameNumber; unsigned short subFrameNumber;
} MAC_Context_Info_t; } MAC_Context_Info_t;
/* Context information for every NAS PDU that will be logged */
typedef struct NAS_Context_Info_s {
// No Context yet
} NAS_Context_Info_t;
/**************************************************************************
/**************************************************************************/ * API functions for opening/closing LTE PCAP files *
/* API functions for opening/writing/closing MAC-LTE PCAP files */ **************************************************************************/
/* Open the file and write file header */ /* Open the file and write file header */
inline FILE *MAC_LTE_PCAP_Open(const char *fileName) inline FILE *LTE_PCAP_Open(uint32_t DLT, const char *fileName)
{ {
pcap_hdr_t file_header = pcap_hdr_t file_header =
{ {
@ -129,7 +118,7 @@ inline FILE *MAC_LTE_PCAP_Open(const char *fileName)
0, /* timezone */ 0, /* timezone */
0, /* sigfigs - apparently all tools do this */ 0, /* sigfigs - apparently all tools do this */
65535, /* snaplen - this should be long enough */ 65535, /* snaplen - this should be long enough */
MAC_LTE_DLT /* Data Link Type (DLT). Set as unused value 147 for now */ DLT /* Data Link Type (DLT). Set as unused value 147 for now */
}; };
FILE *fd = fopen(fileName, "w"); FILE *fd = fopen(fileName, "w");
@ -144,8 +133,20 @@ inline FILE *MAC_LTE_PCAP_Open(const char *fileName)
return fd; return fd;
} }
/* Close the PCAP file */
inline void LTE_PCAP_Close(FILE *fd)
{
if(fd)
fclose(fd);
}
/**************************************************************************
* API functions for writing MAC-LTE PCAP files *
**************************************************************************/
/* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */ /* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */
inline int MAC_LTE_PCAP_WritePDU(FILE *fd, MAC_Context_Info_t *context, inline int LTE_PCAP_MAC_WritePDU(FILE *fd, MAC_Context_Info_t *context,
const unsigned char *PDU, unsigned int length) const unsigned char *PDU, unsigned int length)
{ {
pcaprec_hdr_t packet_header; pcaprec_hdr_t packet_header;
@ -211,11 +212,39 @@ inline int MAC_LTE_PCAP_WritePDU(FILE *fd, MAC_Context_Info_t *context,
return 1; return 1;
} }
/* Close the PCAP file */
inline void MAC_LTE_PCAP_Close(FILE *fd)
/**************************************************************************
* API functions for writing NAS-EPS PCAP files *
**************************************************************************/
/* Write an individual PDU (PCAP packet header + nas-context + nas-pdu) */
inline int LTE_PCAP_NAS_WritePDU(FILE *fd, NAS_Context_Info_t *context,
const unsigned char *PDU, unsigned int length)
{ {
if(fd) pcaprec_hdr_t packet_header;
fclose(fd);
/* Can't write if file wasn't successfully opened */
if (fd == NULL) {
printf("Error: Can't write to empty file handle\n");
return 0;
}
/****************************************************************/
/* PCAP Header */
struct timeval t;
gettimeofday(&t, NULL);
packet_header.ts_sec = t.tv_sec;
packet_header.ts_usec = t.tv_usec;
packet_header.incl_len = length;
packet_header.orig_len = length;
/***************************************************************/
/* Now write everything to the file */
fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, fd);
fwrite(PDU, 1, length, fd);
return 1;
} }
#endif /* UEPCAP_H */ #endif /* UEPCAP_H */

@ -76,6 +76,15 @@ uint8_t security_generate_k_enb( uint8_t *k_asme,
uint32_t nas_count, uint32_t nas_count,
uint8_t *k_enb); uint8_t *k_enb);
uint8_t security_generate_k_enb_star( uint8_t *k_enb,
uint32_t pci,
uint32_t earfcn,
uint8_t *k_enb_star);
uint8_t security_generate_nh( uint8_t *k_asme,
uint8_t *sync,
uint8_t *nh);
uint8_t security_generate_k_nas( uint8_t *k_asme, uint8_t security_generate_k_nas( uint8_t *k_asme,
CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, CIPHERING_ALGORITHM_ID_ENUM enc_alg_id,
INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, INTEGRITY_ALGORITHM_ID_ENUM int_alg_id,
@ -114,6 +123,26 @@ uint8_t security_128_eia2( uint8_t *key,
uint32_t msg_len, uint32_t msg_len,
uint8_t *mac); uint8_t *mac);
/******************************************************************************
* Encryption / Decryption
*****************************************************************************/
uint8_t security_128_eea1( uint8_t *key,
uint32_t count,
uint8_t bearer,
uint8_t direction,
uint8_t *msg,
uint32_t msg_len,
uint8_t *msg_out);
uint8_t security_128_eea2(uint8_t *key,
uint32_t count,
uint8_t bearer,
uint8_t direction,
uint8_t *msg,
uint32_t msg_len,
uint8_t *msg_out);
/****************************************************************************** /******************************************************************************
* Authentication * Authentication
*****************************************************************************/ *****************************************************************************/

@ -78,24 +78,32 @@ class periodic_thread : public thread
{ {
public: public:
void start_periodic(int period_us_, int priority = -1) { void start_periodic(int period_us_, int priority = -1) {
run_enable = true;
period_us = period_us_; period_us = period_us_;
start(priority); start(priority);
} }
void stop() {
run_enable = false;
wait_thread_finish();
}
protected: protected:
virtual void run_period() = 0; virtual void run_period() = 0;
private: private:
int wakeups_missed; int wakeups_missed;
int timer_fd; int timer_fd;
int period_us; int period_us;
bool run_enable;
void run_thread() { void run_thread() {
if (make_periodic()) { if (make_periodic()) {
return; return;
} }
while(1) { while(run_enable) {
run_period(); run_period();
if (run_enable) {
wait_period(); wait_period();
} }
} }
}
int make_periodic() { int make_periodic() {
int ret = -1; int ret = -1;
unsigned int ns; unsigned int ns;

@ -64,7 +64,7 @@ public:
return (counter < timeout) && running; return (counter < timeout) && running;
} }
bool is_expired() { bool is_expired() {
return callback && (counter >= timeout || !running); return (timeout > 0) && (counter >= timeout || !running);
} }
uint32_t get_timeout() { uint32_t get_timeout() {
return timeout; return timeout;
@ -72,6 +72,9 @@ public:
void reset() { void reset() {
counter = 0; counter = 0;
} }
uint32_t value() {
return counter;
}
void step() { void step() {
if (running) { if (running) {
counter++; counter++;

@ -50,6 +50,7 @@ class tti_sync
init_counters(0); init_counters(0);
} }
virtual void increase() = 0; virtual void increase() = 0;
virtual void increase(uint32_t cnt) = 0;
virtual void resync() = 0; virtual void resync() = 0;
virtual uint32_t wait() = 0; virtual uint32_t wait() = 0;
virtual void set_producer_cntr(uint32_t) = 0; virtual void set_producer_cntr(uint32_t) = 0;
@ -60,6 +61,7 @@ class tti_sync
} }
protected: protected:
void increase_producer() { producer_cntr = (producer_cntr + increment)%modulus; } void increase_producer() { producer_cntr = (producer_cntr + increment)%modulus; }
void increase_producer(uint32_t cnt) { producer_cntr = cnt%modulus; }
void increase_consumer() { consumer_cntr = (consumer_cntr + increment)%modulus; } void increase_consumer() { consumer_cntr = (consumer_cntr + increment)%modulus; }
bool wait_condition() { return producer_cntr == consumer_cntr; } bool wait_condition() { return producer_cntr == consumer_cntr; }
void init_counters(uint32_t val) void init_counters(uint32_t val)

@ -44,6 +44,7 @@ class tti_sync_cv : public tti_sync
tti_sync_cv(uint32_t modulus = 10240); tti_sync_cv(uint32_t modulus = 10240);
~tti_sync_cv(); ~tti_sync_cv();
void increase(); void increase();
void increase(uint32_t cnt);
uint32_t wait(); uint32_t wait();
void resync(); void resync();
void set_producer_cntr(uint32_t producer_cntr); void set_producer_cntr(uint32_t producer_cntr);

@ -64,9 +64,11 @@ public:
virtual int sr_detected(uint32_t tti, uint16_t rnti) = 0; virtual int sr_detected(uint32_t tti, uint16_t rnti) = 0;
virtual int rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv) = 0; virtual int rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv) = 0;
virtual int ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value) = 0;
virtual int pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value) = 0;
virtual int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) = 0; virtual int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) = 0;
virtual int snr_info(uint32_t tti, uint16_t rnti, float snr_db) = 0; virtual int snr_info(uint32_t tti, uint16_t rnti, float snr_db) = 0;
virtual int ack_info(uint32_t tti, uint16_t rnti, bool ack) = 0; virtual int ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack) = 0;
virtual int crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc_res) = 0; virtual int crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc_res) = 0;
virtual int get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) = 0; virtual int get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) = 0;
@ -93,6 +95,7 @@ public:
class phy_interface_rrc class phy_interface_rrc
{ {
public: public:
virtual void set_conf_dedicated_ack(uint16_t rnti, bool rrc_completed) = 0;
virtual void set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated) = 0; virtual void set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated) = 0;
}; };
@ -111,6 +114,7 @@ public:
/* Manages UE bearers and associated configuration */ /* Manages UE bearers and associated configuration */
virtual int bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, sched_interface::ue_bearer_cfg_t *cfg) = 0; virtual int bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, sched_interface::ue_bearer_cfg_t *cfg) = 0;
virtual int bearer_ue_rem(uint16_t rnti, uint32_t lc_id) = 0; virtual int bearer_ue_rem(uint16_t rnti, uint32_t lc_id) = 0;
virtual int set_dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dl_ant_info) = 0;
virtual void phy_config_enabled(uint16_t rnti, bool enabled) = 0; virtual void phy_config_enabled(uint16_t rnti, bool enabled) = 0;
}; };
@ -147,6 +151,7 @@ public:
/* PDCP calls RLC to push an RLC SDU. SDU gets placed into the RLC buffer and MAC pulls /* PDCP calls RLC to push an RLC SDU. SDU gets placed into the RLC buffer and MAC pulls
* RLC PDUs according to TB size. */ * RLC PDUs according to TB size. */
virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu) = 0;
virtual bool rb_is_um(uint16_t rnti, uint32_t lcid) = 0;
}; };
// RLC interface for RRC // RLC interface for RRC

@ -131,13 +131,14 @@ public:
typedef struct { typedef struct {
uint32_t rnti; uint32_t rnti;
srslte_dci_format_t dci_format;
srslte_ra_dl_dci_t dci; srslte_ra_dl_dci_t dci;
srslte_dci_location_t dci_location; srslte_dci_location_t dci_location;
uint32_t tbs; uint32_t tbs[SRSLTE_MAX_TB];
bool mac_ce_ta; bool mac_ce_ta;
bool mac_ce_rnti; bool mac_ce_rnti;
uint32_t nof_pdu_elems; uint32_t nof_pdu_elems[SRSLTE_MAX_TB];
dl_sched_pdu_t pdu[MAX_RLC_PDU_LIST]; dl_sched_pdu_t pdu[SRSLTE_MAX_TB][MAX_RLC_PDU_LIST];
} dl_sched_data_t; } dl_sched_data_t;
typedef struct { typedef struct {
@ -225,8 +226,10 @@ public:
virtual int dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code) = 0; virtual int dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code) = 0;
/* DL information */ /* DL information */
virtual int dl_ack_info(uint32_t tti, uint16_t rnti, bool ack) = 0; virtual int dl_ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack) = 0;
virtual int dl_rach_info(uint32_t tti, uint32_t ra_id, uint16_t rnti, uint32_t estimated_size) = 0; virtual int dl_rach_info(uint32_t tti, uint32_t ra_id, uint16_t rnti, uint32_t estimated_size) = 0;
virtual int dl_ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value) = 0;
virtual int dl_pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value) = 0;
virtual int dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) = 0; virtual int dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) = 0;
/* UL information */ /* UL information */

@ -83,6 +83,15 @@ public:
uint8_t *k_up_int, uint8_t *k_up_int,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0;
virtual void generate_as_keys_ho(uint32_t pci,
uint32_t earfcn,
int ncc,
uint8_t *k_rrc_enc,
uint8_t *k_rrc_int,
uint8_t *k_up_enc,
uint8_t *k_up_int,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0;
}; };
// GW interface for NAS // GW interface for NAS
@ -139,7 +148,9 @@ public:
class rrc_interface_mac : public rrc_interface_mac_common class rrc_interface_mac : public rrc_interface_mac_common
{ {
public: public:
virtual void ho_ra_completed(bool ra_successful) = 0;
virtual void release_pucch_srs() = 0; virtual void release_pucch_srs() = 0;
virtual void run_tti(uint32_t tti) = 0;
}; };
// RRC interface for PHY // RRC interface for PHY
@ -150,6 +161,7 @@ public:
virtual void out_of_sync() = 0; virtual void out_of_sync() = 0;
virtual void earfcn_end() = 0; virtual void earfcn_end() = 0;
virtual void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) = 0; virtual void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) = 0;
virtual void new_phy_meas(float rsrp, float rsrq, uint32_t tti, uint32_t earfcn = 0, uint32_t pci = 0) = 0;
}; };
// RRC interface for NAS // RRC interface for NAS
@ -162,7 +174,6 @@ public:
virtual void enable_capabilities() = 0; virtual void enable_capabilities() = 0;
virtual void plmn_search() = 0; virtual void plmn_search() = 0;
virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) = 0; virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
}; };
// RRC interface for PDCP // RRC interface for PDCP
@ -173,7 +184,6 @@ public:
virtual void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu) = 0;
virtual void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu) = 0;
virtual void write_pdu_pcch(srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu_pcch(srslte::byte_buffer_t *pdu) = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
}; };
// RRC interface for RLC // RRC interface for RLC
@ -181,7 +191,6 @@ class rrc_interface_rlc
{ {
public: public:
virtual void max_retx_attempted() = 0; virtual void max_retx_attempted() = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
}; };
// PDCP interface for GW // PDCP interface for GW
@ -196,14 +205,21 @@ public:
class pdcp_interface_rrc class pdcp_interface_rrc
{ {
public: public:
virtual void reestablish() = 0;
virtual void reset() = 0; virtual void reset() = 0;
virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0;
virtual void add_bearer(uint32_t lcid, srslte::srslte_pdcp_config_t cnfg = srslte::srslte_pdcp_config_t()) = 0; virtual void add_bearer(uint32_t lcid, srslte::srslte_pdcp_config_t cnfg = srslte::srslte_pdcp_config_t()) = 0;
virtual void config_security(uint32_t lcid, virtual void config_security(uint32_t lcid,
uint8_t *k_rrc_enc_, uint8_t *k_enc_,
uint8_t *k_rrc_int_, uint8_t *k_int_,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0;
virtual void config_security_all(uint8_t *k_enc_,
uint8_t *k_int_,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0; srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0;
virtual void enable_integrity(uint32_t lcid) = 0;
virtual void enable_encryption(uint32_t lcid) = 0;
}; };
// PDCP interface for RLC // PDCP interface for RLC
@ -222,6 +238,7 @@ class rlc_interface_rrc
{ {
public: public:
virtual void reset() = 0; virtual void reset() = 0;
virtual void reestablish() = 0;
virtual void add_bearer(uint32_t lcid) = 0; virtual void add_bearer(uint32_t lcid) = 0;
virtual void add_bearer(uint32_t lcid, srslte::srslte_rlc_config_t cnfg) = 0; virtual void add_bearer(uint32_t lcid, srslte::srslte_rlc_config_t cnfg) = 0;
}; };
@ -233,6 +250,7 @@ public:
/* PDCP calls RLC to push an RLC SDU. SDU gets placed into the RLC buffer and MAC pulls /* PDCP calls RLC to push an RLC SDU. SDU gets placed into the RLC buffer and MAC pulls
* RLC PDUs according to TB size. */ * RLC PDUs according to TB size. */
virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0;
virtual bool rb_is_um(uint32_t lcid) = 0;
}; };
//RLC interface for MAC //RLC interface for MAC
@ -421,10 +439,14 @@ public:
virtual void get_rntis(ue_rnti_t *rntis) = 0; virtual void get_rntis(ue_rnti_t *rntis) = 0;
virtual void set_contention_id(uint64_t uecri) = 0; virtual void set_contention_id(uint64_t uecri) = 0;
virtual void set_ho_rnti(uint16_t crnti, uint16_t target_pci) = 0;
virtual void start_noncont_ho(uint32_t preamble_index, uint32_t prach_mask) = 0;
virtual void start_cont_ho() = 0;
virtual void reconfiguration() = 0; virtual void reconfiguration() = 0;
virtual void reset() = 0; virtual void reset() = 0;
virtual void wait_uplink() = 0;
}; };
@ -466,6 +488,7 @@ typedef struct {
std::string sss_algorithm; std::string sss_algorithm;
float estimator_fil_w; float estimator_fil_w;
bool rssi_sensor_enabled; bool rssi_sensor_enabled;
bool sic_pss_enabled;
} phy_args_t; } phy_args_t;
@ -535,7 +558,10 @@ public:
bool enable_64qam; bool enable_64qam;
} phy_cfg_t; } phy_cfg_t;
virtual void get_current_cell(srslte_cell_t *cell) = 0; virtual void get_current_cell(srslte_cell_t *cell, uint32_t *current_earfcn = NULL) = 0;
virtual uint32_t get_current_earfcn() = 0;
virtual uint32_t get_current_pci() = 0;
virtual void get_config(phy_cfg_t *phy_cfg) = 0; virtual void get_config(phy_cfg_t *phy_cfg) = 0;
virtual void set_config(phy_cfg_t *phy_cfg) = 0; virtual void set_config(phy_cfg_t *phy_cfg) = 0;
virtual void set_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated) = 0; virtual void set_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated) = 0;
@ -543,11 +569,17 @@ public:
virtual void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd) = 0; virtual void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd) = 0;
virtual void set_config_64qam_en(bool enable) = 0; virtual void set_config_64qam_en(bool enable) = 0;
/* Measurements interface */
virtual void meas_reset() = 0;
virtual int meas_start(uint32_t earfcn, int pci = -1) = 0;
virtual int meas_stop(uint32_t earfcn, int pci = -1) = 0;
/* Cell search and selection procedures */ /* Cell search and selection procedures */
virtual void cell_search_start() = 0; virtual void cell_search_start() = 0;
virtual void cell_search_stop() = 0; virtual void cell_search_stop() = 0;
virtual void cell_search_next() = 0; virtual void cell_search_next() = 0;
virtual bool cell_select(uint32_t earfcn, srslte_cell_t cell) = 0; virtual bool cell_select(uint32_t earfcn, srslte_cell_t cell) = 0;
virtual bool cell_handover(srslte_cell_t cell) = 0;
/* Is the PHY downlink synchronized? */ /* Is the PHY downlink synchronized? */
virtual bool sync_status() = 0; virtual bool sync_status() = 0;

@ -301,6 +301,7 @@ SRSLTE_API int srslte_str2mimotype(char *mimo_type_str,
SRSLTE_API char *srslte_mimotype2str(srslte_mimo_type_t mimo_type); SRSLTE_API char *srslte_mimotype2str(srslte_mimo_type_t mimo_type);
/* Returns the interval tti1-tti2 mod 10240 */
SRSLTE_API uint32_t srslte_tti_interval(uint32_t tti1, SRSLTE_API uint32_t srslte_tti_interval(uint32_t tti1,
uint32_t tti2); uint32_t tti2);

@ -113,8 +113,16 @@ SRSLTE_API void srslte_ofdm_rx_free(srslte_ofdm_t *q);
SRSLTE_API void srslte_ofdm_rx_slot(srslte_ofdm_t *q, SRSLTE_API void srslte_ofdm_rx_slot(srslte_ofdm_t *q,
int slot_in_sf); int slot_in_sf);
SRSLTE_API void srslte_ofdm_rx_slot_ng(srslte_ofdm_t *q,
cf_t *input,
cf_t *output);
SRSLTE_API void srslte_ofdm_rx_sf(srslte_ofdm_t *q); SRSLTE_API void srslte_ofdm_rx_sf(srslte_ofdm_t *q);
SRSLTE_API void srslte_ofdm_rx_sf_ng(srslte_ofdm_t *q,
cf_t *input,
cf_t *output);
SRSLTE_API int srslte_ofdm_tx_init(srslte_ofdm_t *q, SRSLTE_API int srslte_ofdm_tx_init(srslte_ofdm_t *q,
srslte_cp_t cp_type, srslte_cp_t cp_type,
cf_t *in_buffer, cf_t *in_buffer,

@ -95,10 +95,11 @@ typedef struct SRSLTE_API {
typedef struct { typedef struct {
uint16_t rnti; uint16_t rnti;
srslte_dci_format_t dci_format;
srslte_ra_dl_dci_t grant; srslte_ra_dl_dci_t grant;
srslte_dci_location_t location; srslte_dci_location_t location;
srslte_softbuffer_tx_t *softbuffer; srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_TB];
uint8_t *data; uint8_t *data[SRSLTE_MAX_TB];
} srslte_enb_dl_pdsch_t; } srslte_enb_dl_pdsch_t;
typedef struct { typedef struct {
@ -162,8 +163,7 @@ SRSLTE_API int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q,
int rv_idx[SRSLTE_MAX_CODEWORDS], int rv_idx[SRSLTE_MAX_CODEWORDS],
uint32_t sf_idx, uint32_t sf_idx,
uint8_t *data[SRSLTE_MAX_CODEWORDS], uint8_t *data[SRSLTE_MAX_CODEWORDS],
srslte_mimo_type_t mimo_type, srslte_mimo_type_t mimo_type);
uint32_t pmi);
SRSLTE_API int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q, SRSLTE_API int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q,
srslte_ra_dl_dci_t *grant, srslte_ra_dl_dci_t *grant,

@ -125,8 +125,7 @@ SRSLTE_API int srslte_enb_ul_cfg_ue(srslte_enb_ul_t *q, uint16_t rnti,
srslte_refsignal_srs_cfg_t *srs_cfg); srslte_refsignal_srs_cfg_t *srs_cfg);
SRSLTE_API void srslte_enb_ul_fft(srslte_enb_ul_t *q, SRSLTE_API void srslte_enb_ul_fft(srslte_enb_ul_t *q);
cf_t *signal_buffer);
SRSLTE_API int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, SRSLTE_API int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q,
uint16_t rnti, uint16_t rnti,
@ -141,6 +140,7 @@ SRSLTE_API int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q,
uint32_t rv_idx, uint32_t rv_idx,
uint32_t current_tx_nb, uint32_t current_tx_nb,
uint8_t *data, uint8_t *data,
srslte_cqi_value_t *cqi_value,
srslte_uci_data_t *uci_data, srslte_uci_data_t *uci_data,
uint32_t tti); uint32_t tti);

@ -55,13 +55,22 @@ typedef struct {
} srslte_cqi_periodic_cfg_t; } srslte_cqi_periodic_cfg_t;
/* Table 5.2.2.6.2-1: Fields for channel quality information feedback for higher layer configured subband /* Table 5.2.2.6.2-1: Fields for channel quality information feedback for higher layer configured subband
CQI reports CQI reports (transmission mode 1, transmission mode 2, transmission mode 3, transmission mode 7 and
(transmission mode 1, transmission mode 2, transmission mode 3, transmission mode 7 and
transmission mode 8 configured without PMI/RI reporting). */ transmission mode 8 configured without PMI/RI reporting). */
/* Table 5.2.2.6.2-2: Fields for channel quality information (CQI) feedback for higher layer configured subband CQI
reports (transmission mode 4, transmission mode 5 and transmission mode 6). */
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
uint8_t wideband_cqi; // 4-bit width uint8_t wideband_cqi_cw0; // 4-bit width
uint32_t subband_diff_cqi; // 2N-bit width uint32_t subband_diff_cqi_cw0; // 2N-bit width
uint8_t wideband_cqi_cw1; // if RI > 1 then 4-bit width otherwise 0-bit width
uint32_t subband_diff_cqi_cw1; // if RI > 1 then 2N-bit width otherwise 0-bit width
uint32_t pmi; // if RI > 1 then 2-bit width otherwise 1-bit width
uint32_t N; uint32_t N;
bool pmi_present;
bool four_antenna_ports; // If cell has 4 antenna ports then true otherwise false
bool rank_is_not_one; // If rank > 1 then true otherwise false
} srslte_cqi_hl_subband_t; } srslte_cqi_hl_subband_t;
/* Table 5.2.2.6.3-1: Fields for channel quality information feedback for UE selected subband CQI /* Table 5.2.2.6.3-1: Fields for channel quality information feedback for UE selected subband CQI

@ -157,7 +157,8 @@ SRSLTE_API int srslte_pucch_decode(srslte_pucch_t *q,
cf_t *sf_symbols, cf_t *sf_symbols,
cf_t *ce, cf_t *ce,
float noise_estimate, float noise_estimate,
uint8_t bits[SRSLTE_PUCCH_MAX_BITS]); uint8_t bits[SRSLTE_PUCCH_MAX_BITS],
uint32_t nof_bits);
SRSLTE_API float srslte_pucch_alpha_format1(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB], SRSLTE_API float srslte_pucch_alpha_format1(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB],
srslte_pucch_cfg_t *cfg, srslte_pucch_cfg_t *cfg,

@ -142,6 +142,7 @@ SRSLTE_API int srslte_pusch_decode(srslte_pusch_t *q,
float noise_estimate, float noise_estimate,
uint16_t rnti, uint16_t rnti,
uint8_t *data, uint8_t *data,
srslte_cqi_value_t *cqi_value,
srslte_uci_data_t *uci_data); srslte_uci_data_t *uci_data);
SRSLTE_API float srslte_pusch_average_noi(srslte_pusch_t *q); SRSLTE_API float srslte_pusch_average_noi(srslte_pusch_t *q);

@ -57,8 +57,8 @@ typedef struct SRSLTE_API {
} srslte_uci_cqi_pusch_t; } srslte_uci_cqi_pusch_t;
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
uint8_t *cqi_table[16]; uint8_t **cqi_table;
int16_t *cqi_table_s[16]; int16_t **cqi_table_s;
} srslte_uci_cqi_pucch_t; } srslte_uci_cqi_pucch_t;
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
@ -73,6 +73,7 @@ typedef struct SRSLTE_API {
uint8_t uci_ack; // 1st codeword bit for HARQ-ACK uint8_t uci_ack; // 1st codeword bit for HARQ-ACK
uint8_t uci_ack_2; // 2st codeword bit for HARQ-ACK uint8_t uci_ack_2; // 2st codeword bit for HARQ-ACK
uint32_t uci_ack_len; uint32_t uci_ack_len;
bool ri_periodic_report;
bool scheduling_request; bool scheduling_request;
bool channel_selection; bool channel_selection;
bool cqi_ack; bool cqi_ack;
@ -95,6 +96,11 @@ SRSLTE_API int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data,
uint32_t cqi_len, uint32_t cqi_len,
uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]); uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]);
SRSLTE_API int srslte_uci_encode_cqi_pucch_from_table(srslte_uci_cqi_pucch_t *q,
uint8_t *cqi_data,
uint32_t cqi_len,
uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]);
SRSLTE_API int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, SRSLTE_API int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q,
int16_t b_bits[32], // aligned for simd int16_t b_bits[32], // aligned for simd
uint8_t *cqi_data, uint8_t *cqi_data,
@ -130,31 +136,25 @@ SRSLTE_API int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg,
uint32_t H_prime_total, uint32_t H_prime_total,
srslte_uci_bit_t *ri_bits); srslte_uci_bit_t *ri_bits);
SRSLTE_API int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, SRSLTE_API int srslte_uci_encode_ack_ri(srslte_pusch_cfg_t *cfg,
int16_t *q_bits, uint8_t *data,
uint8_t *c_seq, uint32_t data_len,
float beta,
uint32_t H_prime_total,
uint32_t O_cqi,
srslte_uci_bit_t *ack_bits,
uint8_t acks[2],
uint32_t nof_acks);
SRSLTE_API int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg,
uint8_t data,
uint32_t O_cqi, uint32_t O_cqi,
float beta, float beta,
uint32_t H_prime_total, uint32_t H_prime_total,
srslte_uci_bit_t *ri_bits); srslte_uci_bit_t *ri_bits,
bool is_ri);
SRSLTE_API int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, SRSLTE_API int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t *cfg,
int16_t *q_bits, int16_t *q_bits,
uint8_t *c_seq, uint8_t *c_seq,
float beta, float beta,
uint32_t H_prime_total, uint32_t H_prime_total,
uint32_t O_cqi, uint32_t O_cqi,
srslte_uci_bit_t *ri_bits, srslte_uci_bit_t *ack_ri_bits,
uint8_t *data); uint8_t data[2],
uint32_t nof_bits,
bool is_ri);
#endif #endif

@ -73,16 +73,12 @@ SRSLTE_API int srslte_rf_open(srslte_rf_t *h,
SRSLTE_API int srslte_rf_open_multi(srslte_rf_t *h, SRSLTE_API int srslte_rf_open_multi(srslte_rf_t *h,
char *args, char *args,
uint32_t nof_rx_antennas); uint32_t nof_channels);
SRSLTE_API int srslte_rf_open_devname(srslte_rf_t *h, SRSLTE_API int srslte_rf_open_devname(srslte_rf_t *h,
char *devname,
char *args);
SRSLTE_API int srslte_rf_open_devname_multi(srslte_rf_t *h,
char *devname, char *devname,
char *args, char *args,
uint32_t nof_rx_antennas); uint32_t nof_channels);
SRSLTE_API const char *srslte_rf_name(srslte_rf_t *h); SRSLTE_API const char *srslte_rf_name(srslte_rf_t *h);
@ -95,7 +91,7 @@ SRSLTE_API void srslte_rf_set_tx_cal(srslte_rf_t *h, srslte_rf_cal_t *cal);
SRSLTE_API void srslte_rf_set_rx_cal(srslte_rf_t *h, srslte_rf_cal_t *cal); SRSLTE_API void srslte_rf_set_rx_cal(srslte_rf_t *h, srslte_rf_cal_t *cal);
SRSLTE_API int srslte_rf_start_rx_stream(srslte_rf_t *h); SRSLTE_API int srslte_rf_start_rx_stream(srslte_rf_t *h, bool now);
SRSLTE_API int srslte_rf_stop_rx_stream(srslte_rf_t *h); SRSLTE_API int srslte_rf_stop_rx_stream(srslte_rf_t *h);

@ -29,9 +29,9 @@
* *
* Description: Primary synchronization signal (PSS) generation and detection. * Description: Primary synchronization signal (PSS) generation and detection.
* *
* The srslte_pss_synch_t object provides functions for fast * The srslte_pss_t object provides functions for fast
* computation of the crosscorrelation between the PSS and received * computation of the crosscorrelation between the PSS and received
* signal and CFO estimation. Also, the function srslte_pss_synch_tperiodic() * signal and CFO estimation. Also, the function srslte_pss_tperiodic()
* is designed to be called periodically every subframe, taking * is designed to be called periodically every subframe, taking
* care of the correct data alignment with respect to the PSS sequence. * care of the correct data alignment with respect to the PSS sequence.
* *
@ -61,7 +61,7 @@
/* PSS processing options */ /* PSS processing options */
#define SRSLTE_PSS_ACCUMULATE_ABS // If enabled, accumulates the correlation absolute value on consecutive calls to srslte_pss_synch_find_pss #define SRSLTE_PSS_ACCUMULATE_ABS // If enabled, accumulates the correlation absolute value on consecutive calls to srslte_pss_find_pss
#define SRSLTE_PSS_RETURN_PSR // If enabled returns peak to side-lobe ratio, otherwise returns absolute peak value #define SRSLTE_PSS_RETURN_PSR // If enabled returns peak to side-lobe ratio, otherwise returns absolute peak value
@ -85,6 +85,7 @@ typedef struct SRSLTE_API {
cf_t *pss_signal_freq_full[3]; cf_t *pss_signal_freq_full[3];
cf_t *pss_signal_time[3]; cf_t *pss_signal_time[3];
cf_t *pss_signal_time_scale[3];
cf_t pss_signal_freq[3][SRSLTE_PSS_LEN]; // One sequence for each N_id_2 cf_t pss_signal_freq[3][SRSLTE_PSS_LEN]; // One sequence for each N_id_2
cf_t *tmp_input; cf_t *tmp_input;
@ -100,41 +101,48 @@ typedef struct SRSLTE_API {
cf_t tmp_fft[SRSLTE_SYMBOL_SZ_MAX]; cf_t tmp_fft[SRSLTE_SYMBOL_SZ_MAX];
cf_t tmp_fft2[SRSLTE_SYMBOL_SZ_MAX]; cf_t tmp_fft2[SRSLTE_SYMBOL_SZ_MAX];
}srslte_pss_synch_t; cf_t tmp_ce[SRSLTE_PSS_LEN];
bool chest_on_filter;
}srslte_pss_t;
typedef enum { PSS_TX, PSS_RX } pss_direction_t; typedef enum { PSS_TX, PSS_RX } pss_direction_t;
/* Basic functionality */ /* Basic functionality */
SRSLTE_API int srslte_pss_synch_init_fft(srslte_pss_synch_t *q, SRSLTE_API int srslte_pss_init_fft(srslte_pss_t *q,
uint32_t frame_size, uint32_t frame_size,
uint32_t fft_size); uint32_t fft_size);
SRSLTE_API int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, SRSLTE_API int srslte_pss_init_fft_offset(srslte_pss_t *q,
uint32_t frame_size, uint32_t frame_size,
uint32_t fft_size, uint32_t fft_size,
int cfo_i); int cfo_i);
SRSLTE_API int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, SRSLTE_API int srslte_pss_init_fft_offset_decim(srslte_pss_t *q,
uint32_t frame_size, uint32_t frame_size,
uint32_t fft_size, uint32_t fft_size,
int cfo_i, int cfo_i,
int decimate); int decimate);
SRSLTE_API int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, SRSLTE_API int srslte_pss_resize(srslte_pss_t *q, uint32_t frame_size,
uint32_t fft_size, uint32_t fft_size,
int offset); int offset);
SRSLTE_API int srslte_pss_synch_init(srslte_pss_synch_t *q, SRSLTE_API int srslte_pss_init(srslte_pss_t *q,
uint32_t frame_size); uint32_t frame_size);
SRSLTE_API void srslte_pss_synch_free(srslte_pss_synch_t *q); SRSLTE_API void srslte_pss_free(srslte_pss_t *q);
SRSLTE_API void srslte_pss_synch_reset(srslte_pss_synch_t *q); SRSLTE_API void srslte_pss_reset(srslte_pss_t *q);
SRSLTE_API void srslte_pss_synch_filter_enable(srslte_pss_synch_t *q, SRSLTE_API void srslte_pss_filter_enable(srslte_pss_t *q,
bool enable); bool enable);
SRSLTE_API void srslte_pss_synch_filter(srslte_pss_synch_t *q, SRSLTE_API void srslte_pss_sic(srslte_pss_t *q,
cf_t *input);
SRSLTE_API void srslte_pss_filter(srslte_pss_t *q,
const cf_t *input, const cf_t *input,
cf_t *output); cf_t *output);
@ -151,21 +159,21 @@ SRSLTE_API void srslte_pss_put_slot(cf_t *pss_signal,
uint32_t nof_prb, uint32_t nof_prb,
srslte_cp_t cp); srslte_cp_t cp);
SRSLTE_API void srslte_pss_synch_set_ema_alpha(srslte_pss_synch_t *q, SRSLTE_API void srslte_pss_set_ema_alpha(srslte_pss_t *q,
float alpha); float alpha);
SRSLTE_API int srslte_pss_synch_set_N_id_2(srslte_pss_synch_t *q, SRSLTE_API int srslte_pss_set_N_id_2(srslte_pss_t *q,
uint32_t N_id_2); uint32_t N_id_2);
SRSLTE_API int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, SRSLTE_API int srslte_pss_find_pss(srslte_pss_t *q,
const cf_t *input, const cf_t *input,
float *corr_peak_value); float *corr_peak_value);
SRSLTE_API int srslte_pss_synch_chest(srslte_pss_synch_t *q, SRSLTE_API int srslte_pss_chest(srslte_pss_t *q,
const cf_t *input, const cf_t *input,
cf_t ce[SRSLTE_PSS_LEN]); cf_t ce[SRSLTE_PSS_LEN]);
SRSLTE_API float srslte_pss_synch_cfo_compute(srslte_pss_synch_t* q, SRSLTE_API float srslte_pss_cfo_compute(srslte_pss_t* q,
const cf_t *pss_recv); const cf_t *pss_recv);
#endif // PSS_ #endif // PSS_

@ -83,17 +83,17 @@ typedef struct SRSLTE_API {
float corr_output_m0[SRSLTE_SSS_N]; float corr_output_m0[SRSLTE_SSS_N];
float corr_output_m1[SRSLTE_SSS_N]; float corr_output_m1[SRSLTE_SSS_N];
}srslte_sss_synch_t; }srslte_sss_t;
/* Basic functionality */ /* Basic functionality */
SRSLTE_API int srslte_sss_synch_init(srslte_sss_synch_t *q, SRSLTE_API int srslte_sss_init(srslte_sss_t *q,
uint32_t fft_size); uint32_t fft_size);
SRSLTE_API int srslte_sss_synch_resize(srslte_sss_synch_t *q, SRSLTE_API int srslte_sss_resize(srslte_sss_t *q,
uint32_t fft_size); uint32_t fft_size);
SRSLTE_API void srslte_sss_synch_free(srslte_sss_synch_t *q); SRSLTE_API void srslte_sss_free(srslte_sss_t *q);
SRSLTE_API void srslte_sss_generate(float *signal0, SRSLTE_API void srslte_sss_generate(float *signal0,
float *signal5, float *signal5,
@ -104,10 +104,10 @@ SRSLTE_API void srslte_sss_put_slot(float *sss,
uint32_t nof_prb, uint32_t nof_prb,
srslte_cp_t cp); srslte_cp_t cp);
SRSLTE_API int srslte_sss_synch_set_N_id_2(srslte_sss_synch_t *q, SRSLTE_API int srslte_sss_set_N_id_2(srslte_sss_t *q,
uint32_t N_id_2); uint32_t N_id_2);
SRSLTE_API int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q, SRSLTE_API int srslte_sss_m0m1_partial(srslte_sss_t *q,
const cf_t *input, const cf_t *input,
uint32_t M, uint32_t M,
cf_t ce[2*SRSLTE_SSS_N], cf_t ce[2*SRSLTE_SSS_N],
@ -116,7 +116,7 @@ SRSLTE_API int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q,
uint32_t *m1, uint32_t *m1,
float *m1_value); float *m1_value);
SRSLTE_API int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, SRSLTE_API int srslte_sss_m0m1_diff_coh(srslte_sss_t *q,
const cf_t *input, const cf_t *input,
cf_t ce[2*SRSLTE_SSS_N], cf_t ce[2*SRSLTE_SSS_N],
uint32_t *m0, uint32_t *m0,
@ -124,7 +124,7 @@ SRSLTE_API int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q,
uint32_t *m1, uint32_t *m1,
float *m1_value); float *m1_value);
SRSLTE_API int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, SRSLTE_API int srslte_sss_m0m1_diff(srslte_sss_t *q,
const cf_t *input, const cf_t *input,
uint32_t *m0, uint32_t *m0,
float *m0_value, float *m0_value,
@ -132,25 +132,25 @@ SRSLTE_API int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q,
float *m1_value); float *m1_value);
SRSLTE_API uint32_t srslte_sss_synch_subframe(uint32_t m0, SRSLTE_API uint32_t srslte_sss_subframe(uint32_t m0,
uint32_t m1); uint32_t m1);
SRSLTE_API int srslte_sss_synch_N_id_1(srslte_sss_synch_t *q, SRSLTE_API int srslte_sss_N_id_1(srslte_sss_t *q,
uint32_t m0, uint32_t m0,
uint32_t m1); uint32_t m1);
SRSLTE_API int srslte_sss_synch_frame(srslte_sss_synch_t *q, SRSLTE_API int srslte_sss_frame(srslte_sss_t *q,
cf_t *input, cf_t *input,
uint32_t *subframe_idx, uint32_t *subframe_idx,
uint32_t *N_id_1); uint32_t *N_id_1);
SRSLTE_API void srslte_sss_synch_set_threshold(srslte_sss_synch_t *q, SRSLTE_API void srslte_sss_set_threshold(srslte_sss_t *q,
float threshold); float threshold);
SRSLTE_API void srslte_sss_synch_set_symbol_sz(srslte_sss_synch_t *q, SRSLTE_API void srslte_sss_set_symbol_sz(srslte_sss_t *q,
uint32_t symbol_sz); uint32_t symbol_sz);
SRSLTE_API void srslte_sss_synch_set_subframe_sz(srslte_sss_synch_t *q, SRSLTE_API void srslte_sss_set_subframe_sz(srslte_sss_t *q,
uint32_t subframe_sz); uint32_t subframe_sz);
#endif // SSS_ #endif // SSS_

@ -60,9 +60,9 @@
typedef enum {SSS_DIFF=0, SSS_PARTIAL_3=2, SSS_FULL=1} sss_alg_t; typedef enum {SSS_DIFF=0, SSS_PARTIAL_3=2, SSS_FULL=1} sss_alg_t;
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
srslte_pss_synch_t pss; srslte_pss_t pss;
srslte_pss_synch_t pss_i[2]; srslte_pss_t pss_i[2];
srslte_sss_synch_t sss; srslte_sss_t sss;
srslte_cp_synch_t cp_synch; srslte_cp_synch_t cp_synch;
cf_t *cfo_i_corr[2]; cf_t *cfo_i_corr[2];
int decimate; int decimate;
@ -110,7 +110,7 @@ typedef struct SRSLTE_API {
srslte_cfo_t cfo_corr_frame; srslte_cfo_t cfo_corr_frame;
srslte_cfo_t cfo_corr_symbol; srslte_cfo_t cfo_corr_symbol;
bool sss_filtering_enabled; bool sss_channel_equalize;
bool pss_filtering_enabled; bool pss_filtering_enabled;
cf_t sss_filt[SRSLTE_SYMBOL_SZ_MAX]; cf_t sss_filt[SRSLTE_SYMBOL_SZ_MAX];
cf_t pss_filt[SRSLTE_SYMBOL_SZ_MAX]; cf_t pss_filt[SRSLTE_SYMBOL_SZ_MAX];
@ -186,7 +186,7 @@ SRSLTE_API int srslte_sync_get_cell_id(srslte_sync_t *q);
SRSLTE_API void srslte_sync_set_pss_filt_enable(srslte_sync_t *q, SRSLTE_API void srslte_sync_set_pss_filt_enable(srslte_sync_t *q,
bool enable); bool enable);
SRSLTE_API void srslte_sync_set_sss_filt_enable(srslte_sync_t *q, SRSLTE_API void srslte_sync_set_sss_eq_enable(srslte_sync_t *q,
bool enable); bool enable);
/* Gets the CFO estimation from the last call to synch_run() */ /* Gets the CFO estimation from the last call to synch_run() */
@ -227,7 +227,7 @@ SRSLTE_API void srslte_sync_set_cp(srslte_sync_t *q,
SRSLTE_API void srslte_sync_sss_en(srslte_sync_t *q, SRSLTE_API void srslte_sync_sss_en(srslte_sync_t *q,
bool enabled); bool enabled);
SRSLTE_API srslte_pss_synch_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q); SRSLTE_API srslte_pss_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q);
SRSLTE_API bool srslte_sync_sss_detected(srslte_sync_t *q); SRSLTE_API bool srslte_sync_sss_detected(srslte_sync_t *q);

@ -131,7 +131,7 @@ typedef struct SRSLTE_API {
/* This function shall be called just after the initial synchronization */ /* This function shall be called just after the initial synchronization */
SRSLTE_API int srslte_ue_dl_init(srslte_ue_dl_t *q, SRSLTE_API int srslte_ue_dl_init(srslte_ue_dl_t *q,
cf_t *in_buffer[SRSLTE_MAX_PORTS], cf_t *input[SRSLTE_MAX_PORTS],
uint32_t max_prb, uint32_t max_prb,
uint32_t nof_rx_antennas); uint32_t nof_rx_antennas);
@ -141,18 +141,20 @@ SRSLTE_API int srslte_ue_dl_set_cell(srslte_ue_dl_t *q,
srslte_cell_t cell); srslte_cell_t cell);
int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS],
uint32_t sf_idx, uint32_t sf_idx,
uint32_t *cfi); uint32_t *cfi);
SRSLTE_API int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, SRSLTE_API int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS],
uint32_t sf_idx, uint32_t sf_idx,
uint32_t *cfi, uint32_t *cfi,
srslte_sf_t sf_type); srslte_sf_t sf_type);
SRSLTE_API int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS],
uint32_t sf_idx,
uint32_t *cfi);
int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, SRSLTE_API int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q,
uint32_t sf_idx, uint32_t sf_idx,
uint32_t *cfi); uint32_t *cfi);
@ -195,14 +197,12 @@ SRSLTE_API void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q,
float sample_offset); float sample_offset);
SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t *q, SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS],
uint8_t *data[SRSLTE_MAX_CODEWORDS], uint8_t *data[SRSLTE_MAX_CODEWORDS],
uint32_t tm, uint32_t tm,
uint32_t tti, uint32_t tti,
bool acks[SRSLTE_MAX_CODEWORDS]); bool acks[SRSLTE_MAX_CODEWORDS]);
SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS],
uint8_t *data[SRSLTE_MAX_CODEWORDS], uint8_t *data[SRSLTE_MAX_CODEWORDS],
uint32_t tm, uint32_t tm,
uint32_t tti, uint32_t tti,
@ -216,7 +216,6 @@ SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q,
* srslte_pmch_decode_multi * srslte_pmch_decode_multi
*/ */
SRSLTE_API int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q, SRSLTE_API int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q,
cf_t *input[SRSLTE_MAX_PORTS],
uint8_t *data, uint8_t *data,
uint32_t tti); uint32_t tti);

@ -65,7 +65,7 @@ SRSLTE_API extern int srslte_verbose;
#if CMAKE_BUILD_TYPE==Debug #if CMAKE_BUILD_TYPE==Debug
/* In debug mode, it prints out the */ /* In debug mode, it prints out the */
#define ERROR(_fmt, ...) fprintf(stderr, "%s.%d: " _fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__) #define ERROR(_fmt, ...) fprintf(stderr, "\e[31m%s.%d: " _fmt "\e[0m\n", __FILE__, __LINE__, ##__VA_ARGS__)
#else #else
#define ERROR(_fmt, ...) fprintf(stderr, "[ERROR in %s]:" _fmt "\n", __FUNCTION__, ##__VA_ARGS__) #define ERROR(_fmt, ...) fprintf(stderr, "[ERROR in %s]:" _fmt "\n", __FUNCTION__, ##__VA_ARGS__)
#endif /* CMAKE_BUILD_TYPE==Debug */ #endif /* CMAKE_BUILD_TYPE==Debug */

@ -20,15 +20,18 @@ typedef struct {
SRSLTE_API int srslte_ringbuffer_init(srslte_ringbuffer_t *q, SRSLTE_API int srslte_ringbuffer_init(srslte_ringbuffer_t *q,
int capacity); int capacity);
SRSLTE_API void srslte_ringbuffer_free(srslte_ringbuffer_t *q, SRSLTE_API void srslte_ringbuffer_free(srslte_ringbuffer_t *q);
int capacity);
SRSLTE_API void srslte_ringbuffer_reset(srslte_ringbuffer_t *q);
SRSLTE_API int srslte_ringbuffer_status(srslte_ringbuffer_t *q);
SRSLTE_API int srslte_ringbuffer_write(srslte_ringbuffer_t *q, SRSLTE_API int srslte_ringbuffer_write(srslte_ringbuffer_t *q,
uint8_t *ptr, void *ptr,
int nof_bytes); int nof_bytes);
SRSLTE_API int srslte_ringbuffer_read(srslte_ringbuffer_t *q, SRSLTE_API int srslte_ringbuffer_read(srslte_ringbuffer_t *q,
uint8_t *ptr, void *ptr,
int nof_bytes); int nof_bytes);

@ -74,7 +74,7 @@ namespace srslte {
agc_enabled = false; agc_enabled = false;
}; };
bool init(char *args = NULL, char *devname = NULL); bool init(char *args = NULL, char *devname = NULL, uint32_t nof_channels = 1);
void stop(); void stop();
void reset(); void reset();
bool start_agc(bool tx_gain_same_rx); bool start_agc(bool tx_gain_same_rx);
@ -86,9 +86,10 @@ namespace srslte {
void set_manual_calibration(rf_cal_t *calibration); void set_manual_calibration(rf_cal_t *calibration);
void get_time(srslte_timestamp_t *now); void get_time(srslte_timestamp_t *now);
bool tx(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); bool tx_single(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
bool tx(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time);
void tx_end(); void tx_end();
bool rx_now(void *buffer, uint32_t nof_samples, srslte_timestamp_t *rxd_time); bool rx_now(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t *rxd_time);
bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time); bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time);
void set_tx_gain(float gain); void set_tx_gain(float gain);
@ -117,7 +118,7 @@ namespace srslte {
void start_trace(); void start_trace();
void write_trace(std::string filename); void write_trace(std::string filename);
void start_rx(); void start_rx(bool now = false);
void stop_rx(); void stop_rx();
void set_tti(uint32_t tti); void set_tti(uint32_t tti);
@ -166,6 +167,7 @@ namespace srslte {
uint32_t tti; uint32_t tti;
bool agc_enabled; bool agc_enabled;
uint32_t saved_nof_channels;
char saved_args[128]; char saved_args[128];
char saved_devname[128]; char saved_devname[128];

@ -39,6 +39,7 @@
#include "srslte/version.h" #include "srslte/version.h"
#include "srslte/phy/utils/bit.h" #include "srslte/phy/utils/bit.h"
#include "srslte/phy/utils/ringbuffer.h"
#include "srslte/phy/utils/convolution.h" #include "srslte/phy/utils/convolution.h"
#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/cexptab.h" #include "srslte/phy/utils/cexptab.h"

@ -54,14 +54,21 @@ public:
bool is_drb_enabled(uint32_t lcid); bool is_drb_enabled(uint32_t lcid);
// RRC interface // RRC interface
void reestablish();
void reset(); void reset();
void write_sdu(uint32_t lcid, byte_buffer_t *sdu); void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
void add_bearer(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t()); void add_bearer(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t());
void config_security(uint32_t lcid, void config_security(uint32_t lcid,
uint8_t *k_rrc_enc, uint8_t *k_enc,
uint8_t *k_rrc_int, uint8_t *k_int,
CIPHERING_ALGORITHM_ID_ENUM cipher_algo, CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo); INTEGRITY_ALGORITHM_ID_ENUM integ_algo);
void config_security_all(uint8_t *k_enc,
uint8_t *k_int,
CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo);
void enable_integrity(uint32_t lcid);
void enable_encryption(uint32_t lcid);
// RLC interface // RLC interface
void write_pdu(uint32_t lcid, byte_buffer_t *sdu); void write_pdu(uint32_t lcid, byte_buffer_t *sdu);

@ -32,6 +32,8 @@
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/security.h" #include "srslte/common/security.h"
#include "srslte/common/msg_queue.h"
#include "srslte/common/threads.h"
namespace srslte { namespace srslte {
@ -59,6 +61,7 @@ static const char pdcp_d_c_text[PDCP_D_C_N_ITEMS][20] = {"Control PDU",
* Common interface for all PDCP entities * Common interface for all PDCP entities
***************************************************************************/ ***************************************************************************/
class pdcp_entity class pdcp_entity
:public thread
{ {
public: public:
pdcp_entity(); pdcp_entity();
@ -68,16 +71,20 @@ public:
srslte::log *log_, srslte::log *log_,
uint32_t lcid_, uint32_t lcid_,
srslte_pdcp_config_t cfg_); srslte_pdcp_config_t cfg_);
void stop();
void reset(); void reset();
void reestablish();
bool is_active(); bool is_active();
// RRC interface // RRC interface
void write_sdu(byte_buffer_t *sdu); void write_sdu(byte_buffer_t *sdu);
void config_security(uint8_t *k_rrc_enc_, void config_security(uint8_t *k_enc_,
uint8_t *k_rrc_int_, uint8_t *k_int_,
CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo_); INTEGRITY_ALGORITHM_ID_ENUM integ_algo_);
void enable_integrity();
void enable_encryption();
// RLC interface // RLC interface
void write_pdu(byte_buffer_t *pdu); void write_pdu(byte_buffer_t *pdu);
@ -90,26 +97,46 @@ private:
srsue::rrc_interface_pdcp *rrc; srsue::rrc_interface_pdcp *rrc;
srsue::gw_interface_pdcp *gw; srsue::gw_interface_pdcp *gw;
static const int PDCP_THREAD_PRIO = 7;
srslte::msg_queue rx_pdu_queue;
bool running;
bool active; bool active;
uint32_t lcid; uint32_t lcid;
srslte_pdcp_config_t cfg; srslte_pdcp_config_t cfg;
uint8_t sn_len_bytes;
bool do_integrity;
bool do_encryption;
uint32_t rx_count; uint32_t rx_count;
uint32_t tx_count; uint32_t tx_count;
uint8_t k_rrc_enc[32]; uint8_t k_enc[32];
uint8_t k_rrc_int[32]; uint8_t k_int[32];
CIPHERING_ALGORITHM_ID_ENUM cipher_algo; CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
INTEGRITY_ALGORITHM_ID_ENUM integ_algo; INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
void integrity_generate(uint8_t *key_128, void integrity_generate(uint8_t *msg,
uint32_t msg_len,
uint8_t *mac);
bool integrity_verify(uint8_t *msg,
uint32_t count, uint32_t count,
uint8_t rb_id,
uint8_t direction,
uint8_t *msg,
uint32_t msg_len, uint32_t msg_len,
uint8_t *mac); uint8_t *mac);
void cipher_encrypt(uint8_t *msg,
uint32_t msg_len,
uint8_t *ct);
void cipher_decrypt(uint8_t *ct,
uint32_t count,
uint32_t ct_len,
uint8_t *msg);
void run_thread();
uint8_t get_bearer_id(uint8_t lcid);
}; };
/**************************************************************************** /****************************************************************************

@ -64,7 +64,8 @@ public:
// PDCP interface // PDCP interface
void write_sdu(uint32_t lcid, byte_buffer_t *sdu); void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
std::string get_rb_name(uint32_t lcid);
bool rb_is_um(uint32_t lcid);
// MAC interface // MAC interface
uint32_t get_buffer_state(uint32_t lcid); uint32_t get_buffer_state(uint32_t lcid);
@ -76,6 +77,7 @@ public:
void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes); void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes);
// RRC interface // RRC interface
void reestablish();
void reset(); void reset();
void empty_queue(); void empty_queue();
void add_bearer(uint32_t lcid); void add_bearer(uint32_t lcid);

@ -78,6 +78,7 @@ public:
mac_interface_timers *mac_timers); mac_interface_timers *mac_timers);
void configure(srslte_rlc_config_t cnfg); void configure(srslte_rlc_config_t cnfg);
void reset(); void reset();
void reestablish();
void stop(); void stop();
void empty_queue(); void empty_queue();

@ -56,6 +56,7 @@ public:
void configure(srslte_rlc_config_t cnfg); void configure(srslte_rlc_config_t cnfg);
void reset(); void reset();
void reestablish();
void stop(); void stop();
void empty_queue(); void empty_queue();
bool active(); bool active();

@ -4922,6 +4922,32 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_transaction_identifier_ie(uint8
MESSAGE FUNCTIONS MESSAGE FUNCTIONS
*******************************************************************************/ *******************************************************************************/
/*********************************************************************
Message Name: Security Message Header (Plain NAS Message)
Description: Security header for NAS messages.
Document Reference: 24.301 v10.2.0 Section 9.1
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_mme_parse_msg_sec_header(LIBLTE_BYTE_MSG_STRUCT *msg,
uint8 *pd,
uint8 *sec_hdr_type)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if (msg != NULL &&
pd != NULL &&
sec_hdr_type != NULL)
{
*sec_hdr_type = (uint8) ((msg->msg[0] & 0xF0) >> 4);
err = LIBLTE_SUCCESS;
}
return(err);
}
/********************************************************************* /*********************************************************************
Message Name: Message Header (Plain NAS Message) Message Name: Message Header (Plain NAS Message)

@ -55,6 +55,11 @@ typedef struct{
uint8 state[4][4]; uint8 state[4][4];
}STATE_STRUCT; }STATE_STRUCT;
typedef struct{
uint32 * lfsr;
uint32 * fsm;
}S3G_STATE;
/******************************************************************************* /*******************************************************************************
GLOBAL VARIABLES GLOBAL VARIABLES
*******************************************************************************/ *******************************************************************************/
@ -76,6 +81,35 @@ static const uint8 S[256] = { 99,124,119,123,242,107,111,197, 48, 1,103, 43,254
225,248,152, 17,105,217,142,148,155, 30,135,233,206, 85, 40,223, 225,248,152, 17,105,217,142,148,155, 30,135,233,206, 85, 40,223,
140,161,137, 13,191,230, 66,104, 65,153, 45, 15,176, 84,187, 22}; 140,161,137, 13,191,230, 66,104, 65,153, 45, 15,176, 84,187, 22};
/* S-box SQ */
static const uint8 SQ[256] = { 0x25, 0x24, 0x73, 0x67, 0xD7, 0xAE,
0x5C, 0x30, 0xA4, 0xEE, 0x6E, 0xCB, 0x7D, 0xB5, 0x82, 0xDB,
0xE4, 0x8E, 0x48, 0x49, 0x4F, 0x5D, 0x6A, 0x78, 0x70, 0x88,
0xE8, 0x5F, 0x5E, 0x84, 0x65, 0xE2, 0xD8, 0xE9, 0xCC, 0xED,
0x40, 0x2F, 0x11, 0x28, 0x57, 0xD2, 0xAC, 0xE3, 0x4A, 0x15,
0x1B, 0xB9, 0xB2, 0x80, 0x85, 0xA6, 0x2E, 0x02, 0x47, 0x29,
0x07, 0x4B, 0x0E, 0xC1, 0x51, 0xAA, 0x89, 0xD4, 0xCA, 0x01,
0x46, 0xB3, 0xEF, 0xDD, 0x44, 0x7B, 0xC2, 0x7F, 0xBE, 0xC3,
0x9F, 0x20, 0x4C, 0x64, 0x83, 0xA2, 0x68, 0x42, 0x13, 0xB4,
0x41, 0xCD, 0xBA, 0xC6, 0xBB, 0x6D, 0x4D, 0x71, 0x21, 0xF4,
0x8D, 0xB0, 0xE5, 0x93, 0xFE, 0x8F, 0xE6, 0xCF, 0x43, 0x45,
0x31, 0x22, 0x37, 0x36, 0x96, 0xFA, 0xBC, 0x0F, 0x08, 0x52,
0x1D, 0x55, 0x1A, 0xC5, 0x4E, 0x23, 0x69, 0x7A, 0x92, 0xFF,
0x5B, 0x5A, 0xEB, 0x9A, 0x1C, 0xA9, 0xD1, 0x7E, 0x0D, 0xFC,
0x50, 0x8A, 0xB6, 0x62, 0xF5, 0x0A, 0xF8, 0xDC, 0x03, 0x3C,
0x0C, 0x39, 0xF1, 0xB8, 0xF3, 0x3D, 0xF2, 0xD5, 0x97, 0x66,
0x81, 0x32, 0xA0, 0x00, 0x06, 0xCE, 0xF6, 0xEA, 0xB7, 0x17,
0xF7, 0x8C, 0x79, 0xD6, 0xA7, 0xBF, 0x8B, 0x3F, 0x1F, 0x53,
0x63, 0x75, 0x35, 0x2C, 0x60, 0xFD, 0x27, 0xD3, 0x94, 0xA5,
0x7C, 0xA1, 0x05, 0x58, 0x2D, 0xBD, 0xD9, 0xC7, 0xAF, 0x6B,
0x54, 0x0B, 0xE0, 0x38, 0x04, 0xC8, 0x9D, 0xE7, 0x14, 0xB1,
0x87, 0x9C, 0xDF, 0x6F, 0xF9, 0xDA, 0x2A, 0xC4, 0x59, 0x16,
0x74, 0x91, 0xAB, 0x26, 0x61, 0x76, 0x34, 0x2B, 0xAD, 0x99,
0xFB, 0x72, 0xEC, 0x33, 0x12, 0xDE, 0x98, 0x3B, 0xC0, 0x9B,
0x3E, 0x18, 0x10, 0x3A, 0x56, 0xE1, 0x77, 0xC9, 0x1E, 0x9E,
0x95, 0xA3, 0x90, 0x19, 0xA8, 0x6C, 0x09, 0xD0, 0xF0, 0x86 };
static const uint8 X_TIME[256] = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, static const uint8 X_TIME[256] = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94,
@ -195,6 +229,136 @@ void shift_row(STATE_STRUCT *state);
// Functions // Functions
void mix_column(STATE_STRUCT *state); void mix_column(STATE_STRUCT *state);
/*********************************************************************
Name: zero_tailing_bits
Description: Fill tailing bits with zeros.
Document Reference: -
*********************************************************************/
void zero_tailing_bits(uint8 * data, uint32 length_bits);
/*********************************************************************
Name: s3g_mul_x
Description: Multiplication with reduction.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 3.1.1
*********************************************************************/
uint8 s3g_mul_x(uint8 v, uint8 c);
/*********************************************************************
Name: s3g_mul_x_pow
Description: Recursive multiplication with reduction.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 3.1.2
*********************************************************************/
uint8 s3g_mul_x_pow(uint8 v, uint8 i, uint8 c);
/*********************************************************************
Name: s3g_mul_alpha
Description: Multiplication with alpha.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 3.4.2
*********************************************************************/
uint32 s3g_mul_alpha(uint8 c);
/*********************************************************************
Name: s3g_div_alpha
Description: Division by alpha.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 3.4.3
*********************************************************************/
uint32 s3g_div_alpha(uint8 c);
/*********************************************************************
Name: s3g_s1
Description: S-Box S1.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 3.3.1
*********************************************************************/
uint32 s3g_s1(uint32 w);
/*********************************************************************
Name: s3g_s2
Description: S-Box S2.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 3.3.2
*********************************************************************/
uint32 s3g_s2(uint32 w);
/*********************************************************************
Name: s3g_clock_lfsr
Description: Clocking LFSR.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 3.4.4 and Section 3.4.5
*********************************************************************/
void s3g_clock_lfsr(S3G_STATE * state, uint32 f);
/*********************************************************************
Name: s3g_clock_fsm
Description: Clocking FSM.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 3.4.6
*********************************************************************/
uint32 s3g_clock_fsm(S3G_STATE * state);
/*********************************************************************
Name: s3g_initialize
Description: Initialization.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 4.1
*********************************************************************/
void s3g_initialize(S3G_STATE * state, uint32 k[4], uint32 iv[4]);
/*********************************************************************
Name: s3g_deinitialize
Description: Deinitialization.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
*********************************************************************/
void s3g_deinitialize(S3G_STATE * state);
/*********************************************************************
Name: s3g_generate_keystream
Description: Generation of Keystream.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 4.2
*********************************************************************/
void s3g_generate_keystream(S3G_STATE * state, uint32 n, uint32 *ks);
/******************************************************************************* /*******************************************************************************
FUNCTIONS FUNCTIONS
*******************************************************************************/ *******************************************************************************/
@ -298,6 +462,71 @@ LIBLTE_ERROR_ENUM liblte_security_generate_k_enb(uint8 *k_asme,
return(err); return(err);
} }
/*********************************************************************
Name: liblte_security_generate_k_enb_star
Description: Generate the security key Kenb*.
Document Reference: 33.401 v10.0.0 Annex A.5
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_generate_k_enb_star(uint8 *k_enb,
uint32 pci,
uint32_t earfcn,
uint8 *k_enb_star)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 s[9];
if (k_enb_star != NULL &&
k_enb != NULL) {
// Construct S
s[0] = 0x13; // FC
s[1] = (pci >> 8) & 0xFF; // First byte of P0
s[2] = pci & 0xFF; // Second byte of P0
s[3] = 0x00; // First byte of L0
s[4] = 0x02; // Second byte of L0
s[5] = (earfcn >> 8) & 0xFF; // First byte of P0
s[6] = earfcn & 0xFF; // Second byte of P0
s[7] = 0x00; // First byte of L0
s[8] = 0x02; // Second byte of L0
// Derive Kenb
sha256(k_enb, 32, s, 9, k_enb_star, 0);
err = LIBLTE_SUCCESS;
}
return (err);
}
LIBLTE_ERROR_ENUM liblte_security_generate_nh( uint8_t *k_asme,
uint8_t *sync,
uint8_t *nh)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 s[35];
if (k_asme != NULL &&
sync != NULL &&
nh != NULL)
{
// Construct S
s[0] = 0x12; // FC
for (int i=0;i<32;i++) {
s[1+i] = sync[i];
}
s[33] = 0x00; // First byte of L0
s[34] = 0x20, // Second byte of L0
// Derive NH
sha256(k_asme, 32, s, 35, nh, 0);
err = LIBLTE_SUCCESS;
}
return (err);
}
/********************************************************************* /*********************************************************************
Name: liblte_security_generate_k_nas Name: liblte_security_generate_k_nas
@ -682,6 +911,183 @@ LIBLTE_ERROR_ENUM liblte_security_128_eia2(uint8 *key,
return(err); return(err);
} }
/*********************************************************************
Name: liblte_security_encryption_eea1
Description: 128-bit encryption algorithm EEA1.
Document Reference: 33.401 v13.1.0 Annex B.1.2
35.215 v13.0.0 References
Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D1 v2.1
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_encryption_eea1(uint8 *key,
uint32 count,
uint8 bearer,
uint8 direction,
uint8 *msg,
uint32 msg_len,
uint8 *out)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
S3G_STATE state, *state_ptr;
uint32 k[] = {0,0,0,0};
uint32 iv[] = {0,0,0,0};
uint32 *ks;
int32 i;
uint32 msg_len_block_8, msg_len_block_32, m;
if (key != NULL &&
msg != NULL &&
out != NULL)
{
state_ptr = &state;
msg_len_block_8 = (msg_len + 7) / 8;
msg_len_block_32 = (msg_len + 31) / 32;
// Transform key
for (i = 3; i >= 0; i--) {
k[i] = (key[4 * (3 - i) + 0] << 24) |
(key[4 * (3 - i) + 1] << 16) |
(key[4 * (3 - i) + 2] << 8) |
(key[4 * (3 - i) + 3]);
}
// Construct iv
iv[3] = count;
iv[2] = ((bearer & 0x1F) << 27) | ((direction & 0x01) << 26);
iv[1] = iv[3];
iv[0] = iv[2];
// Initialize keystream
s3g_initialize(state_ptr, k, iv);
// Generate keystream
ks = (uint32 *) calloc(msg_len_block_32, sizeof(uint32));
s3g_generate_keystream(state_ptr, msg_len_block_32, ks);
// Generate output except last block
for (i = 0; i < (int32_t)msg_len_block_32 - 1; i++) {
out[4 * i + 0] = msg[4 * i + 0] ^ ((ks[i] >> 24) & 0xFF);
out[4 * i + 1] = msg[4 * i + 1] ^ ((ks[i] >> 16) & 0xFF);
out[4 * i + 2] = msg[4 * i + 2] ^ ((ks[i] >> 8) & 0xFF);
out[4 * i + 3] = msg[4 * i + 3] ^ ((ks[i] & 0xFF));
}
// Process last bytes
for (i = (msg_len_block_32 - 1) * 4; i < (int32_t)msg_len_block_8; i++) {
out[i] = msg[i] ^ ((ks[i / 4] >> ((3 - (i % 4)) * 8)) & 0xFF);
}
// Zero tailing bits
zero_tailing_bits(out, msg_len);
// Clean up
free(ks);
s3g_deinitialize(state_ptr);
err = LIBLTE_SUCCESS;
}
return(err);
}
/*********************************************************************
Name: liblte_security_decryption_eea1
Description: 128-bit decryption algorithm EEA1.
Document Reference: 33.401 v13.1.0 Annex B.1.2
35.215 v13.0.0 References
Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D1 v2.1
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_decryption_eea1(uint8 *key,
uint32 count,
uint8 bearer,
uint8 direction,
uint8 *ct,
uint32 ct_len,
uint8 *out) {
return liblte_security_encryption_eea1(key, count, bearer,
direction, ct, ct_len, out);
}
/*********************************************************************
Name: liblte_security_encryption_eea2
Description: 128-bit encryption algorithm EEA2.
Document Reference: 33.401 v13.1.0 Annex B.1.3
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_encryption_eea2(uint8 *key,
uint32 count,
uint8 bearer,
uint8 direction,
uint8 *msg,
uint32 msg_len,
uint8 *out)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
aes_context ctx;
unsigned char stream_blk[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
unsigned char nonce_cnt[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int32 i;
int ret;
size_t nc_off = 0;
if(key != NULL &&
msg != NULL &&
out != NULL)
{
ret = aes_setkey_enc(&ctx, key, 128);
if (ret == 0) {
// Construct nonce
nonce_cnt[0] = (count >> 24) & 0xFF;
nonce_cnt[1] = (count >> 16) & 0xFF;
nonce_cnt[2] = (count >> 8) & 0xFF;
nonce_cnt[3] = (count) & 0xFF;
nonce_cnt[4] = ((bearer & 0x1F) << 3) |
((direction & 0x01) << 2);
// Encryption
ret = aes_crypt_ctr(&ctx, (msg_len + 7) / 8, &nc_off, nonce_cnt,
stream_blk, msg, out);
}
if (ret == 0) {
// Zero tailing bits
zero_tailing_bits(out, msg_len);
err = LIBLTE_SUCCESS;
}
}
return(err);
}
/*********************************************************************
Name: liblte_security_decryption_eea2
Description: 128-bit decryption algorithm EEA2.
Document Reference: 33.401 v13.1.0 Annex B.1.3
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_decryption_eea2(uint8 *key,
uint32 count,
uint8 bearer,
uint8 direction,
uint8 *ct,
uint32 ct_len,
uint8 *out)
{
return liblte_security_encryption_eea2(key, count, bearer,
direction, ct, ct_len, out);
}
/********************************************************************* /*********************************************************************
Name: liblte_security_milenage_f1 Name: liblte_security_milenage_f1
@ -1243,3 +1649,293 @@ void mix_column(STATE_STRUCT *state)
state->state[3][i] ^= temp ^ tmp; state->state[3][i] ^= temp ^ tmp;
} }
} }
/*********************************************************************
Name: zero_tailing_bits
Description: Fill tailing bits with zeros.
Document Reference: -
*********************************************************************/
void zero_tailing_bits(uint8 * data, uint32 length_bits) {
uint8 bits = (8 - (length_bits & 0x07)) & 0x07;
data[(length_bits + 7) / 8 - 1] &= (uint8) (0xFF << bits);
}
/*********************************************************************
Name: s3g_mul_x
Description: Multiplication with reduction.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 3.1.1
*********************************************************************/
uint8 s3g_mul_x(uint8 v, uint8 c) {
if (v & 0x80)
return ((v << 1) ^ c);
else
return (v << 1);
}
/*********************************************************************
Name: s3g_mul_x_pow
Description: Recursive multiplication with reduction.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 3.1.2
*********************************************************************/
uint8 s3g_mul_x_pow(uint8 v, uint8 i, uint8 c) {
if (i == 0)
return v;
else
return s3g_mul_x(s3g_mul_x_pow(v, i - 1, c), c);
}
/*********************************************************************
Name: s3g_mul_alpha
Description: Multiplication with alpha.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 3.4.2
*********************************************************************/
uint32 s3g_mul_alpha(uint8 c) {
return ((((uint32) s3g_mul_x_pow(c, 23, 0xa9)) << 24) |
(((uint32) s3g_mul_x_pow(c, 245, 0xa9)) << 16) |
(((uint32) s3g_mul_x_pow(c, 48, 0xa9)) << 8) |
(((uint32) s3g_mul_x_pow(c, 239, 0xa9))));
}
/*********************************************************************
Name: s3g_div_alpha
Description: Division by alpha.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 3.4.3
*********************************************************************/
uint32 s3g_div_alpha(uint8 c) {
return ((((uint32) s3g_mul_x_pow(c, 16, 0xa9)) << 24) |
(((uint32) s3g_mul_x_pow(c, 39, 0xa9)) << 16) |
(((uint32) s3g_mul_x_pow(c, 6, 0xa9)) << 8) |
(((uint32) s3g_mul_x_pow(c, 64, 0xa9))));
}
/*********************************************************************
Name: s3g_s1
Description: S-Box S1.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 3.3.1
*********************************************************************/
uint32 s3g_s1(uint32 w) {
uint8 r0 = 0, r1 = 0, r2 = 0, r3 = 0;
uint8 srw0 = S[(uint8) ((w >> 24) & 0xff)];
uint8 srw1 = S[(uint8) ((w >> 16) & 0xff)];
uint8 srw2 = S[(uint8) ((w >> 8) & 0xff)];
uint8 srw3 = S[(uint8) ((w) & 0xff)];
r0 = ((s3g_mul_x(srw0, 0x1b)) ^
(srw1) ^
(srw2) ^
((s3g_mul_x(srw3, 0x1b)) ^ srw3));
r1 = (((s3g_mul_x(srw0, 0x1b)) ^ srw0) ^
(s3g_mul_x(srw1, 0x1b)) ^
(srw2) ^
(srw3));
r2 = ((srw0) ^
((s3g_mul_x(srw1, 0x1b)) ^ srw1) ^
(s3g_mul_x(srw2, 0x1b)) ^
(srw3));
r3 = ((srw0) ^
(srw1) ^
((s3g_mul_x(srw2, 0x1b)) ^ srw2) ^
(s3g_mul_x(srw3, 0x1b)));
return ((((uint32) r0) << 24) |
(((uint32) r1) << 16) |
(((uint32) r2) << 8) |
(((uint32) r3)));
}
/*********************************************************************
Name: s3g_s2
Description: S-Box S2.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 3.3.2
*********************************************************************/
uint32 s3g_s2(uint32 w) {
uint8 r0 = 0, r1 = 0, r2 = 0, r3 = 0;
uint8 sqw0 = SQ[(uint8) ((w >> 24) & 0xff)];
uint8 sqw1 = SQ[(uint8) ((w >> 16) & 0xff)];
uint8 sqw2 = SQ[(uint8) ((w >> 8) & 0xff)];
uint8 sqw3 = SQ[(uint8) ((w) & 0xff)];
r0 = ((s3g_mul_x(sqw0, 0x69)) ^
(sqw1) ^
(sqw2) ^
((s3g_mul_x(sqw3, 0x69)) ^ sqw3));
r1 = (((s3g_mul_x(sqw0, 0x69)) ^ sqw0) ^
(s3g_mul_x(sqw1, 0x69)) ^
(sqw2) ^
(sqw3));
r2 = ((sqw0) ^
((s3g_mul_x(sqw1, 0x69)) ^ sqw1) ^
(s3g_mul_x(sqw2, 0x69)) ^
(sqw3));
r3 = ((sqw0) ^
(sqw1) ^
((s3g_mul_x(sqw2, 0x69)) ^ sqw2) ^
(s3g_mul_x(sqw3, 0x69)));
return ((((uint32) r0) << 24) |
(((uint32) r1) << 16) |
(((uint32) r2) << 8) |
(((uint32) r3)));
}
/*********************************************************************
Name: s3g_clock_lfsr
Description: Clocking LFSR.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 3.4.4 and Section 3.4.5
*********************************************************************/
void s3g_clock_lfsr(S3G_STATE * state, uint32 f) {
uint32 v = (
((state->lfsr[0] << 8) & 0xffffff00) ^
(s3g_mul_alpha((uint8) ((state->lfsr[0] >> 24) & 0xff))) ^
(state->lfsr[2]) ^
((state->lfsr[11] >> 8) & 0x00ffffff) ^
(s3g_div_alpha((uint8) ((state->lfsr[11]) & 0xff))) ^
(f)
);
uint8 i;
for (i = 0; i < 15; i++) {
state->lfsr[i] = state->lfsr[i + 1];
}
state->lfsr[15] = v;
}
/*********************************************************************
Name: s3g_clock_fsm
Description: Clocking FSM.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 3.4.6
*********************************************************************/
uint32 s3g_clock_fsm(S3G_STATE * state) {
uint32 f = ((state->lfsr[15] + state->fsm[0]) & 0xffffffff) ^
state->fsm[1];
uint32 r = (state->fsm[1] + (state->fsm[2] ^ state->lfsr[5])) &
0xffffffff;
state->fsm[2] = s3g_s2(state->fsm[1]);
state->fsm[1] = s3g_s1(state->fsm[0]);
state->fsm[0] = r;
return f;
}
/*********************************************************************
Name: s3g_initialize
Description: Initialization.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 4.1
*********************************************************************/
void s3g_initialize(S3G_STATE * state, uint32 k[4], uint32 iv[4]) {
uint8 i = 0;
uint32 f = 0x0;
state->lfsr = (uint32 *) calloc(16, sizeof(uint32));
state->fsm = (uint32 *) calloc( 3, sizeof(uint32));
state->lfsr[15] = k[3] ^ iv[0];
state->lfsr[14] = k[2];
state->lfsr[13] = k[1];
state->lfsr[12] = k[0] ^ iv[1];
state->lfsr[11] = k[3] ^ 0xffffffff;
state->lfsr[10] = k[2] ^ 0xffffffff ^ iv[2];
state->lfsr[ 9] = k[1] ^ 0xffffffff ^ iv[3];
state->lfsr[ 8] = k[0] ^ 0xffffffff;
state->lfsr[ 7] = k[3];
state->lfsr[ 6] = k[2];
state->lfsr[ 5] = k[1];
state->lfsr[ 4] = k[0];
state->lfsr[ 3] = k[3] ^ 0xffffffff;
state->lfsr[ 2] = k[2] ^ 0xffffffff;
state->lfsr[ 1] = k[1] ^ 0xffffffff;
state->lfsr[ 0] = k[0] ^ 0xffffffff;
state->fsm[0] = 0x0;
state->fsm[1] = 0x0;
state->fsm[2] = 0x0;
for (i = 0; i < 32; i++) {
f = s3g_clock_fsm(state);
s3g_clock_lfsr(state, f);
}
}
/*********************************************************************
Name: s3g_deinitialize
Description: Deinitialization.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
*********************************************************************/
void s3g_deinitialize(S3G_STATE * state) {
free(state->lfsr);
free(state->fsm);
}
/*********************************************************************
Name: s3g_generate_keystream
Description: Generation of Keystream.
Document Reference: Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D2 v1.1
Section 4.2
*********************************************************************/
void s3g_generate_keystream(S3G_STATE * state, uint32 n, uint32 *ks) {
uint32 t = 0;
uint32 f = 0x0;
// Clock FSM once. Discard the output.
s3g_clock_fsm(state);
// Clock LFSR in keystream mode once.
s3g_clock_lfsr(state, 0x0);
for (t = 0; t < n; t++) {
f = s3g_clock_fsm(state);
// Note that ks[t] corresponds to z_{t+1} in section 4.2
ks[t] = f ^ state->lfsr[0];
s3g_clock_lfsr(state, 0x0);
}
}

@ -40,14 +40,18 @@ void mac_pcap::enable(bool en)
} }
void mac_pcap::open(const char* filename, uint32_t ue_id) void mac_pcap::open(const char* filename, uint32_t ue_id)
{ {
pcap_file = MAC_LTE_PCAP_Open(filename); pcap_file = LTE_PCAP_Open(MAC_LTE_DLT, filename);
ue_id = ue_id; this->ue_id = ue_id;
enable_write = true; enable_write = true;
} }
void mac_pcap::close() void mac_pcap::close()
{ {
fprintf(stdout, "Saving PCAP file\n"); fprintf(stdout, "Saving MAC PCAP file\n");
MAC_LTE_PCAP_Close(pcap_file); LTE_PCAP_Close(pcap_file);
}
void mac_pcap::set_ue_id(uint16_t ue_id) {
this->ue_id = ue_id;
} }
void mac_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti, void mac_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti,
@ -65,7 +69,7 @@ void mac_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reT
(uint16_t)(tti%10) /* Subframe number */ (uint16_t)(tti%10) /* Subframe number */
}; };
if (pdu) { if (pdu) {
MAC_LTE_PCAP_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); LTE_PCAP_MAC_WritePDU(pcap_file, &context, pdu, pdu_len_bytes);
} }
} }
} }

@ -0,0 +1,35 @@
#include <stdint.h>
#include "srslte/srslte.h"
#include "srslte/common/pcap.h"
#include "srslte/common/nas_pcap.h"
namespace srslte {
void nas_pcap::enable()
{
enable_write = true;
}
void nas_pcap::open(const char* filename, uint32_t ue_id)
{
pcap_file = LTE_PCAP_Open(NAS_LTE_DLT, filename);
ue_id = ue_id;
enable_write = true;
}
void nas_pcap::close()
{
fprintf(stdout, "Saving NAS PCAP file\n");
LTE_PCAP_Close(pcap_file);
}
void nas_pcap::write_nas(uint8_t *pdu, uint32_t pdu_len_bytes)
{
if (enable_write) {
NAS_Context_Info_t context;
if (pdu) {
LTE_PCAP_NAS_WritePDU(pcap_file, &context, pdu, pdu_len_bytes);
}
}
}
}

@ -61,6 +61,26 @@ uint8_t security_generate_k_enb( uint8_t *k_asme,
k_enb); k_enb);
} }
uint8_t security_generate_k_enb_star( uint8_t *k_enb,
uint32_t pci,
uint32_t earfcn,
uint8_t *k_enb_star)
{
return liblte_security_generate_k_enb_star(k_enb,
pci,
earfcn,
k_enb_star);
}
uint8_t security_generate_nh( uint8_t *k_asme,
uint8_t *sync,
uint8_t *nh)
{
return liblte_security_generate_nh( k_asme,
sync,
nh);
}
uint8_t security_generate_k_nas( uint8_t *k_asme, uint8_t security_generate_k_nas( uint8_t *k_asme,
CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, CIPHERING_ALGORITHM_ID_ENUM enc_alg_id,
INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, INTEGRITY_ALGORITHM_ID_ENUM int_alg_id,
@ -146,6 +166,46 @@ uint8_t security_128_eia2( uint8_t *key,
mac); mac);
} }
/******************************************************************************
* Encryption / Decryption
*****************************************************************************/
uint8_t security_128_eea1(uint8_t *key,
uint32_t count,
uint8_t bearer,
uint8_t direction,
uint8_t *msg,
uint32_t msg_len,
uint8_t *msg_out){
return liblte_security_encryption_eea1(key,
count,
bearer,
direction,
msg,
msg_len * 8,
msg_out);
}
uint8_t security_128_eea2(uint8_t *key,
uint32_t count,
uint8_t bearer,
uint8_t direction,
uint8_t *msg,
uint32_t msg_len,
uint8_t *msg_out){
return liblte_security_encryption_eea2(key,
count,
bearer,
direction,
msg,
msg_len * 8,
msg_out);
}
/****************************************************************************** /******************************************************************************
* Authentication * Authentication
*****************************************************************************/ *****************************************************************************/

@ -75,4 +75,11 @@ namespace srslte {
pthread_cond_signal(&cond); pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
} }
void tti_sync_cv::increase(uint32_t tti)
{
pthread_mutex_lock(&mutex);
increase_producer(tti);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
} }

@ -495,7 +495,9 @@ 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 */ /* Compute RSRP for the channel estimates in this port */
q->rsrp[rxant_id][port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
float energy = cabsf(srslte_vec_acc_cc(q->pilot_estimates, npilots)/npilots);
q->rsrp[rxant_id][port_id] = energy*energy;
if (port_id == 0) { if (port_id == 0) {
/* compute rssi only for port 0 */ /* compute rssi only for port 0 */
q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id); q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id);

@ -380,15 +380,8 @@ void srslte_ofdm_tx_free(srslte_ofdm_t *q) {
srslte_ofdm_free_(q); srslte_ofdm_free_(q);
} }
/* Transforms input samples into output OFDM symbols. void srslte_ofdm_rx_slot_ng(srslte_ofdm_t *q, cf_t *input, cf_t *output) {
* Performs FFT on a each symbol and removes CP.
*/
void srslte_ofdm_rx_slot(srslte_ofdm_t *q, int slot_in_sf) {
cf_t *output = q->out_buffer + slot_in_sf * q->nof_re * q->nof_symbols;
#ifdef AVOID_GURU
uint32_t i; uint32_t i;
cf_t *input = q->in_buffer + slot_in_sf * q->slot_sz;
for (i=0;i<q->nof_symbols;i++) { for (i=0;i<q->nof_symbols;i++) {
input += SRSLTE_CP_ISNORM(q->cp)?SRSLTE_CP_LEN_NORM(i, q->symbol_sz):SRSLTE_CP_LEN_EXT(q->symbol_sz); input += SRSLTE_CP_ISNORM(q->cp)?SRSLTE_CP_LEN_NORM(i, q->symbol_sz):SRSLTE_CP_LEN_EXT(q->symbol_sz);
srslte_dft_run_c(&q->fft_plan, input, q->tmp); srslte_dft_run_c(&q->fft_plan, input, q->tmp);
@ -396,6 +389,16 @@ void srslte_ofdm_rx_slot(srslte_ofdm_t *q, int slot_in_sf) {
input += q->symbol_sz; input += q->symbol_sz;
output += q->nof_re; output += q->nof_re;
} }
}
/* Transforms input samples into output OFDM symbols.
* Performs FFT on a each symbol and removes CP.
*/
void srslte_ofdm_rx_slot(srslte_ofdm_t *q, int slot_in_sf) {
cf_t *output = q->out_buffer + slot_in_sf * q->nof_re * q->nof_symbols;
#ifdef AVOID_GURU
srslte_ofdm_rx_slot_ng(q, q->in_buffer + slot_in_sf * q->slot_sz, q->out_buffer + slot_in_sf * q->nof_re * q->nof_symbols);
#else #else
float norm = 1.0f/sqrtf(q->fft_plan.size); float norm = 1.0f/sqrtf(q->fft_plan.size);
cf_t *tmp = q->tmp + slot_in_sf * q->symbol_sz * q->nof_symbols; cf_t *tmp = q->tmp + slot_in_sf * q->symbol_sz * q->nof_symbols;
@ -462,6 +465,22 @@ void srslte_ofdm_rx_sf(srslte_ofdm_t *q) {
} }
} }
void srslte_ofdm_rx_sf_ng(srslte_ofdm_t *q, cf_t *input, cf_t *output) {
uint32_t n;
if (q->freq_shift) {
srslte_vec_prod_ccc(q->in_buffer, q->shift_buffer, q->in_buffer, 2*q->slot_sz);
}
if(!q->mbsfn_subframe){
for (n=0;n<2;n++) {
srslte_ofdm_rx_slot_ng(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]);
}
}
else{
srslte_ofdm_rx_slot_mbsfn(q, &q->in_buffer[0*q->slot_sz], &q->out_buffer[0*q->nof_re*q->nof_symbols]);
srslte_ofdm_rx_slot(q, 1);
}
}
/* Transforms input OFDM symbols into output samples. /* Transforms input OFDM symbols into output samples.
* Performs FFT on a each symbol and adds CP. * Performs FFT on a each symbol and adds CP.
*/ */

@ -31,7 +31,6 @@
#include <string.h> #include <string.h>
#include <srslte/phy/common/phy_common.h> #include <srslte/phy/common/phy_common.h>
#include <srslte/srslte.h> #include <srslte/srslte.h>
#include <srslte/phy/dft/ofdm.h>
#define CURRENT_FFTSIZE srslte_symbol_sz(q->cell.nof_prb) #define CURRENT_FFTSIZE srslte_symbol_sz(q->cell.nof_prb)
@ -224,15 +223,19 @@ void srslte_enb_dl_clear_sf(srslte_enb_dl_t *q)
void srslte_enb_dl_put_sync(srslte_enb_dl_t *q, uint32_t sf_idx) void srslte_enb_dl_put_sync(srslte_enb_dl_t *q, uint32_t sf_idx)
{ {
if (sf_idx == 0 || sf_idx == 5) { if (sf_idx == 0 || sf_idx == 5) {
srslte_pss_put_slot(q->pss_signal, q->sf_symbols[0], q->cell.nof_prb, q->cell.cp); for (int p = 0; p < q->cell.nof_ports; p++) {
srslte_sss_put_slot(sf_idx ? q->sss_signal5 : q->sss_signal0, q->sf_symbols[0], srslte_pss_put_slot(q->pss_signal, q->sf_symbols[p], q->cell.nof_prb, q->cell.cp);
srslte_sss_put_slot(sf_idx ? q->sss_signal5 : q->sss_signal0, q->sf_symbols[p],
q->cell.nof_prb, SRSLTE_CP_NORM); q->cell.nof_prb, SRSLTE_CP_NORM);
} }
} }
}
void srslte_enb_dl_put_refs(srslte_enb_dl_t *q, uint32_t sf_idx) void srslte_enb_dl_put_refs(srslte_enb_dl_t *q, uint32_t sf_idx)
{ {
srslte_refsignal_cs_put_sf(q->cell, 0, q->csr_signal.pilots[0][sf_idx], q->sf_symbols[0]); for (int p = 0; p < q->cell.nof_ports; p++) {
srslte_refsignal_cs_put_sf(q->cell, (uint32_t) p, q->csr_signal.pilots[p / 2][sf_idx], q->sf_symbols[p]);
}
} }
void srslte_enb_dl_put_mib(srslte_enb_dl_t *q, uint32_t tti) void srslte_enb_dl_put_mib(srslte_enb_dl_t *q, uint32_t tti)
@ -327,11 +330,41 @@ int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q, srslte_ra_ul_dci_t *grant,
int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srslte_softbuffer_tx_t *softbuffer[SRSLTE_MAX_CODEWORDS], int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srslte_softbuffer_tx_t *softbuffer[SRSLTE_MAX_CODEWORDS],
uint16_t rnti, int rv_idx[SRSLTE_MAX_CODEWORDS], uint32_t sf_idx, uint16_t rnti, int rv_idx[SRSLTE_MAX_CODEWORDS], uint32_t sf_idx,
uint8_t *data[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type, uint32_t pmi) uint8_t *data[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type)
{ {
uint32_t pmi = 0;
uint32_t nof_tb = SRSLTE_RA_DL_GRANT_NOF_TB(grant);
/* Translates Precoding Information (pinfo) to Precoding matrix Index (pmi) as 3GPP 36.212 Table 5.3.3.1.5-4 */
if (mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) {
switch(nof_tb) {
case 1:
if (grant->pinfo == 0) {
mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
} else if (grant->pinfo > 0 && grant->pinfo < 5) {
pmi = grant->pinfo - 1;
} else {
ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo);
return SRSLTE_ERROR;
}
break;
case 2:
if (grant->pinfo < 2) {
pmi = grant->pinfo;
} else {
ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo);
return SRSLTE_ERROR;
}
break;
default:
ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo);
return SRSLTE_ERROR;
}
}
/* Configure pdsch_cfg parameters */ /* Configure pdsch_cfg parameters */
if (srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, q->cfi, sf_idx, rv_idx, mimo_type, pmi)) { if (srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, q->cfi, sf_idx, rv_idx, mimo_type, pmi)) {
fprintf(stderr, "Error configuring PDSCH\n"); ERROR("Error configuring PDSCH (rnti=0x%04x)", rnti);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }

@ -253,18 +253,22 @@ int srslte_enb_ul_cfg_ue(srslte_enb_ul_t *q, uint16_t rnti,
} }
} }
void srslte_enb_ul_fft(srslte_enb_ul_t *q, cf_t *signal_buffer) void srslte_enb_ul_fft(srslte_enb_ul_t *q)
{ {
srslte_ofdm_rx_sf(&q->fft); srslte_ofdm_rx_sf(&q->fft);
} }
int get_pucch(srslte_enb_ul_t *q, uint16_t rnti, int get_pucch(srslte_enb_ul_t *q, uint16_t rnti,
uint32_t pdcch_n_cce, uint32_t sf_rx, uint32_t pdcch_n_cce, uint32_t sf_rx,
srslte_uci_data_t *uci_data, uint8_t bits[SRSLTE_PUCCH_MAX_BITS]) srslte_uci_data_t *uci_data, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], uint32_t nof_bits)
{ {
float noise_power = srslte_chest_ul_get_noise_estimate(&q->chest); float noise_power = srslte_chest_ul_get_noise_estimate(&q->chest);
srslte_pucch_format_t format = srslte_pucch_get_format(uci_data, q->cell.cp); srslte_pucch_format_t format = srslte_pucch_get_format(uci_data, q->cell.cp);
if (format == SRSLTE_PUCCH_FORMAT_ERROR) {
fprintf(stderr,"Error getting format\n");
return SRSLTE_ERROR;
}
uint32_t n_pucch = srslte_pucch_get_npucch(pdcch_n_cce, format, uci_data->scheduling_request, &q->users[rnti]->pucch_sched); uint32_t n_pucch = srslte_pucch_get_npucch(pdcch_n_cce, format, uci_data->scheduling_request, &q->users[rnti]->pucch_sched);
@ -273,7 +277,7 @@ int get_pucch(srslte_enb_ul_t *q, uint16_t rnti,
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
int ret_val = srslte_pucch_decode(&q->pucch, format, n_pucch, sf_rx, rnti, q->sf_symbols, q->ce, noise_power, bits); int ret_val = srslte_pucch_decode(&q->pucch, format, n_pucch, sf_rx, rnti, q->sf_symbols, q->ce, noise_power, bits, nof_bits);
if (ret_val < 0) { if (ret_val < 0) {
fprintf(stderr,"Error decoding PUCCH\n"); fprintf(stderr,"Error decoding PUCCH\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -288,14 +292,16 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti,
uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS]; uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS];
if (q->users[rnti]) { if (q->users[rnti]) {
uint32_t nof_uci_bits = uci_data->ri_periodic_report ? uci_data->uci_ri_len : (uci_data->uci_cqi_len +
int ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits); uci_data->uci_dif_cqi_len +
uci_data->uci_pmi_len);
int ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits, nof_uci_bits);
// If we are looking for SR and ACK at the same time and ret=0, means there is no SR. // If we are looking for SR and ACK at the same time and ret=0, means there is no SR.
// try again to decode ACK only // try again to decode ACK only
if (uci_data->scheduling_request && uci_data->uci_ack_len && ret_val != 1) { if (uci_data->scheduling_request && uci_data->uci_ack_len && ret_val != 1) {
uci_data->scheduling_request = false; uci_data->scheduling_request = false;
ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits); ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits, nof_uci_bits);
} }
// update schedulign request // update schedulign request
@ -308,9 +314,29 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti,
uci_data->uci_ack = pucch_bits[0]; uci_data->uci_ack = pucch_bits[0];
} }
if (uci_data->uci_ack_len > 1) {
uci_data->uci_ack_2 = pucch_bits[1];
}
// PUCCH2 CQI bits are decoded inside srslte_pucch_decode() // PUCCH2 CQI bits are decoded inside srslte_pucch_decode()
if (uci_data->uci_cqi_len) { if (uci_data->uci_cqi_len) {
memcpy(uci_data->uci_cqi, pucch_bits, uci_data->uci_cqi_len*sizeof(uint8_t)); memcpy(uci_data->uci_cqi, pucch_bits, uci_data->uci_cqi_len*sizeof(uint8_t));
}
if (uci_data->uci_dif_cqi_len) {
memcpy(uci_data->uci_dif_cqi, pucch_bits + uci_data->uci_cqi_len, uci_data->uci_dif_cqi_len*sizeof(uint8_t));
}
if (uci_data->uci_pmi_len) {
memcpy(uci_data->uci_pmi, pucch_bits + uci_data->uci_cqi_len + uci_data->uci_dif_cqi_len,
uci_data->uci_pmi_len*sizeof(uint8_t));
}
if (uci_data->uci_ri_len) {
uci_data->uci_ri = pucch_bits[0]; /* Assume only one bit of RI */
}
if (uci_data->uci_cqi_len || uci_data->uci_ri_len) {
if (uci_data->uci_ack_len >= 1) { if (uci_data->uci_ack_len >= 1) {
uci_data->uci_ack = pucch_bits[20]; uci_data->uci_ack = pucch_bits[20];
} }
@ -328,7 +354,7 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti,
int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srslte_softbuffer_rx_t *softbuffer, int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srslte_softbuffer_rx_t *softbuffer,
uint16_t rnti, uint32_t rv_idx, uint32_t current_tx_nb, uint16_t rnti, uint32_t rv_idx, uint32_t current_tx_nb,
uint8_t *data, srslte_uci_data_t *uci_data, uint32_t tti) uint8_t *data, srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data, uint32_t tti)
{ {
if (q->users[rnti]) { if (q->users[rnti]) {
if (srslte_pusch_cfg(&q->pusch, if (srslte_pusch_cfg(&q->pusch,
@ -364,6 +390,7 @@ int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srs
softbuffer, q->sf_symbols, softbuffer, q->sf_symbols,
q->ce, noise_power, q->ce, noise_power,
rnti, data, rnti, data,
cqi_value,
uci_data); uci_data);
} }

@ -45,10 +45,37 @@
int srslte_cqi_hl_subband_pack(srslte_cqi_hl_subband_t *msg, uint8_t buff[SRSLTE_CQI_MAX_BITS]) int srslte_cqi_hl_subband_pack(srslte_cqi_hl_subband_t *msg, uint8_t buff[SRSLTE_CQI_MAX_BITS])
{ {
uint8_t *body_ptr = buff; uint8_t *body_ptr = buff;
srslte_bit_unpack(msg->wideband_cqi, &body_ptr, 4); uint32_t bit_count = 0;
srslte_bit_unpack(msg->subband_diff_cqi, &body_ptr, 2*msg->N);
/* Unpack codeword 0, common for 3GPP 36.212 Tables 5.2.2.6.2-1 and 5.2.2.6.2-2 */
srslte_bit_unpack(msg->wideband_cqi_cw0, &body_ptr, 4);
srslte_bit_unpack(msg->subband_diff_cqi_cw0, &body_ptr, 2*msg->N);
bit_count += 4+2*msg->N;
/* Unpack codeword 1, 3GPP 36.212 Table 5.2.2.6.2-2 */
if (msg->rank_is_not_one) {
srslte_bit_unpack(msg->wideband_cqi_cw1, &body_ptr, 4);
srslte_bit_unpack(msg->subband_diff_cqi_cw1, &body_ptr, 2*msg->N);
bit_count += 4+2*msg->N;
}
/* If PMI is present, unpack it */
if (msg->pmi_present) {
if (msg->four_antenna_ports) {
srslte_bit_unpack(msg->pmi, &body_ptr, 4);
bit_count += 4;
} else {
if (msg->rank_is_not_one) {
srslte_bit_unpack(msg->pmi, &body_ptr, 1);
bit_count += 1;
} else {
srslte_bit_unpack(msg->pmi, &body_ptr, 2);
bit_count += 2;
}
}
}
return 4+2*msg->N; return bit_count;
} }
int srslte_cqi_ue_subband_pack(srslte_cqi_ue_subband_t *msg, uint8_t buff[SRSLTE_CQI_MAX_BITS]) int srslte_cqi_ue_subband_pack(srslte_cqi_ue_subband_t *msg, uint8_t buff[SRSLTE_CQI_MAX_BITS])
@ -99,10 +126,36 @@ int srslte_cqi_value_pack(srslte_cqi_value_t *value, uint8_t buff[SRSLTE_CQI_MAX
int srslte_cqi_hl_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_hl_subband_t *msg) int srslte_cqi_hl_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_hl_subband_t *msg)
{ {
uint8_t *body_ptr = buff; uint8_t *body_ptr = buff;
msg->wideband_cqi = srslte_bit_pack(&body_ptr, 4); uint32_t bit_count = 0;
msg->subband_diff_cqi = srslte_bit_pack(&body_ptr, 2*msg->N);
msg->wideband_cqi_cw0 = (uint8_t) srslte_bit_pack(&body_ptr, 4);
msg->subband_diff_cqi_cw0 = srslte_bit_pack(&body_ptr, 2*msg->N);
bit_count += 4+2*msg->N;
return 4+2*msg->N; /* Unpack codeword 1, 3GPP 36.212 Table 5.2.2.6.2-2 */
if (msg->rank_is_not_one) {
msg->wideband_cqi_cw1 = (uint8_t) srslte_bit_pack(&body_ptr, 4);
msg->subband_diff_cqi_cw1 = srslte_bit_pack(&body_ptr, 2*msg->N);
bit_count += 4+2*msg->N;
}
/* If PMI is present, unpack it */
if (msg->pmi_present) {
if (msg->four_antenna_ports) {
msg->pmi = (uint8_t) srslte_bit_pack(&body_ptr, 4);
bit_count += 4;
} else {
if (msg->rank_is_not_one) {
msg->pmi = (uint8_t) srslte_bit_pack(&body_ptr, 1);
bit_count += 1;
} else {
msg->pmi = (uint8_t) srslte_bit_pack(&body_ptr, 2);
bit_count += 2;
}
}
}
return bit_count;
} }
int srslte_cqi_ue_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_ue_subband_t *msg) int srslte_cqi_ue_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_ue_subband_t *msg)
@ -146,17 +199,44 @@ int srslte_cqi_value_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_value_
} }
int srslte_cqi_size(srslte_cqi_value_t *value) { int srslte_cqi_size(srslte_cqi_value_t *value) {
int size = 0;
switch(value->type) { switch(value->type) {
case SRSLTE_CQI_TYPE_WIDEBAND: case SRSLTE_CQI_TYPE_WIDEBAND:
return 4; size = 4;
break;
case SRSLTE_CQI_TYPE_SUBBAND: case SRSLTE_CQI_TYPE_SUBBAND:
return 4+(value->subband.subband_label_2_bits)?2:1; size = 4 + (value->subband.subband_label_2_bits) ? 2 : 1;
break;
case SRSLTE_CQI_TYPE_SUBBAND_UE: case SRSLTE_CQI_TYPE_SUBBAND_UE:
return 4+2+value->subband_ue.L; size = 4 + 2 + value->subband_ue.L;
break;
case SRSLTE_CQI_TYPE_SUBBAND_HL: case SRSLTE_CQI_TYPE_SUBBAND_HL:
return 4+2*value->subband_hl.N; /* First codeword */
size += 4 + 2 * value->subband_hl.N;
/* Add Second codeword if required */
if (value->subband_hl.rank_is_not_one && value->subband_hl.pmi_present) {
size += 4 + 2 * value->subband_hl.N;
} }
return -1;
/* Add PMI if required*/
if (value->subband_hl.pmi_present) {
if (value->subband_hl.four_antenna_ports) {
size += 4;
} else {
if (value->subband_hl.rank_is_not_one) {
size += 1;
} else {
size += 2;
}
}
}
break;
default:
size = SRSLTE_ERROR;
}
return size;
} }
static bool srslte_cqi_get_N(uint32_t I_cqi_pmi, uint32_t *N_p, uint32_t *N_offset) { static bool srslte_cqi_get_N(uint32_t I_cqi_pmi, uint32_t *N_p, uint32_t *N_offset) {

@ -473,7 +473,7 @@ int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra
for (int cw = 0; cw < SRSLTE_MAX_CODEWORDS; cw++) { for (int cw = 0; cw < SRSLTE_MAX_CODEWORDS; cw++) {
if (grant->tb_en[cw]) { if (grant->tb_en[cw]) {
if (srslte_cbsegm(&cfg->cb_segm[cw], (uint32_t) cfg->grant.mcs[cw].tbs)) { if (srslte_cbsegm(&cfg->cb_segm[cw], (uint32_t) cfg->grant.mcs[cw].tbs)) {
fprintf(stderr, "Error computing Codeblock (1) segmentation for TBS=%d\n", cfg->grant.mcs[cw].tbs); fprintf(stderr, "Error computing Codeword (%d) segmentation for TBS=%d\n", cw, cfg->grant.mcs[cw].tbs);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
} }
@ -554,8 +554,14 @@ static int srslte_pdsch_codeword_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c
srslte_ra_nbits_t *nbits = &cfg->nbits[tb_idx]; srslte_ra_nbits_t *nbits = &cfg->nbits[tb_idx];
srslte_ra_mcs_t *mcs = &cfg->grant.mcs[tb_idx]; srslte_ra_mcs_t *mcs = &cfg->grant.mcs[tb_idx];
uint32_t rv = cfg->rv[tb_idx]; uint32_t rv = cfg->rv[tb_idx];
bool valid_inputs = true;
if (nbits->nof_bits) { if (!softbuffer) {
ERROR("Error encoding (TB%d -> CW%d), softbuffer=NULL", tb_idx, codeword_idx);
valid_inputs = false;
}
if (nbits->nof_bits && valid_inputs) {
INFO("Encoding PDSCH SF: %d (TB%d -> CW%d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", INFO("Encoding PDSCH SF: %d (TB%d -> CW%d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
cfg->sf_idx, tb_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs, cfg->sf_idx, tb_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs,
nbits->nof_re, nbits->nof_bits, rv); nbits->nof_re, nbits->nof_bits, rv);
@ -577,6 +583,8 @@ static int srslte_pdsch_codeword_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c
(uint8_t *) q->e[codeword_idx], (uint8_t *) q->e[codeword_idx],
q->d[codeword_idx], nbits->nof_bits); q->d[codeword_idx], nbits->nof_bits);
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;

@ -173,7 +173,7 @@ srslte_pucch_format_t srslte_pucch_get_format(srslte_uci_data_t *uci_data, srslt
{ {
srslte_pucch_format_t format = SRSLTE_PUCCH_FORMAT_ERROR; srslte_pucch_format_t format = SRSLTE_PUCCH_FORMAT_ERROR;
// No CQI data // No CQI data
if (uci_data->uci_cqi_len == 0) { if (uci_data->uci_cqi_len == 0 && uci_data->uci_ri_len == 0) {
// 1-bit ACK + optional SR // 1-bit ACK + optional SR
if (uci_data->uci_ack_len == 1) { if (uci_data->uci_ack_len == 1) {
format = SRSLTE_PUCCH_FORMAT_1A; format = SRSLTE_PUCCH_FORMAT_1A;
@ -750,7 +750,7 @@ float srslte_pucch_get_last_corr(srslte_pucch_t* q)
/* Equalize, demodulate and decode PUCCH bits according to Section 5.4.1 of 36.211 */ /* Equalize, demodulate and decode PUCCH bits according to Section 5.4.1 of 36.211 */
int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format, int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format,
uint32_t n_pucch, uint32_t sf_idx, uint16_t rnti, cf_t *sf_symbols, cf_t *ce, float noise_estimate, uint32_t n_pucch, uint32_t sf_idx, uint16_t rnti, cf_t *sf_symbols, cf_t *ce, float noise_estimate,
uint8_t bits[SRSLTE_PUCCH_MAX_BITS]) uint8_t bits[SRSLTE_PUCCH_MAX_BITS], uint32_t nof_bits)
{ {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && if (q != NULL &&
@ -791,7 +791,7 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format,
// Perform ML-decoding // Perform ML-decoding
float corr=0, corr_max=-1e9; float corr=0, corr_max=-1e9;
int b_max = 0; // default bit value, eg. HI is NACK uint8_t b_max = 0, b2_max = 0; // default bit value, eg. HI is NACK
switch(format) { switch(format) {
case SRSLTE_PUCCH_FORMAT_1: case SRSLTE_PUCCH_FORMAT_1:
bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t)); bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t));
@ -808,7 +808,7 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format,
case SRSLTE_PUCCH_FORMAT_1A: case SRSLTE_PUCCH_FORMAT_1A:
bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t)); bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t));
ret = 0; ret = 0;
for (int b=0;b<2;b++) { for (uint8_t b=0;b<2;b++) {
bits[0] = b; bits[0] = b;
pucch_encode(q, format, n_pucch, sf_idx, rnti, bits, q->z_tmp); pucch_encode(q, format, n_pucch, sf_idx, rnti, bits, q->z_tmp);
corr = srslte_vec_corr_ccc(q->z, q->z_tmp, nof_re); corr = srslte_vec_corr_ccc(q->z, q->z_tmp, nof_re);
@ -824,6 +824,30 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format,
q->last_corr = corr_max; q->last_corr = corr_max;
bits[0] = b_max; bits[0] = b_max;
break; break;
case SRSLTE_PUCCH_FORMAT_1B:
bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t));
ret = 0;
for (uint8_t b=0;b<2;b++) {
for (uint8_t b2 = 0; b2 < 2; b2++) {
bits[0] = b;
bits[1] = b2;
pucch_encode(q, format, n_pucch, sf_idx, rnti, bits, q->z_tmp);
corr = srslte_vec_corr_ccc(q->z, q->z_tmp, nof_re);
if (corr > corr_max) {
corr_max = corr;
b_max = b;
b2_max = b2;
}
if (corr_max > q->threshold_format1) { // check with format1 in case ack+sr because ack only is binary
ret = 1;
}
DEBUG("format1b b=%d, corr=%f, nof_re=%d\n", b, corr, nof_re);
}
}
q->last_corr = corr_max;
bits[0] = b_max;
bits[1] = b2_max;
break;
case SRSLTE_PUCCH_FORMAT_2: case SRSLTE_PUCCH_FORMAT_2:
case SRSLTE_PUCCH_FORMAT_2A: case SRSLTE_PUCCH_FORMAT_2A:
case SRSLTE_PUCCH_FORMAT_2B: case SRSLTE_PUCCH_FORMAT_2B:
@ -838,7 +862,7 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format,
} }
srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->z, llr_pucch2, SRSLTE_PUCCH2_NOF_BITS/2); srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->z, llr_pucch2, SRSLTE_PUCCH2_NOF_BITS/2);
srslte_scrambling_s(&q->users[rnti]->seq_f2[sf_idx], llr_pucch2); srslte_scrambling_s(&q->users[rnti]->seq_f2[sf_idx], llr_pucch2);
q->last_corr = (float) srslte_uci_decode_cqi_pucch(&q->cqi, llr_pucch2, bits, 4)/2000; q->last_corr = (float) srslte_uci_decode_cqi_pucch(&q->cqi, llr_pucch2, bits, nof_bits)/2000;
ret = 1; ret = 1;
} else { } else {
fprintf(stderr, "Decoding PUCCH2: rnti not set\n"); fprintf(stderr, "Decoding PUCCH2: rnti not set\n");

@ -566,9 +566,9 @@ int srslte_pusch_decode(srslte_pusch_t *q,
srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
cf_t *sf_symbols, cf_t *sf_symbols,
cf_t *ce, float noise_estimate, uint16_t rnti, cf_t *ce, float noise_estimate, uint16_t rnti,
uint8_t *data, srslte_uci_data_t *uci_data) uint8_t *data, srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data)
{ {
int ret = SRSLTE_ERROR_INVALID_INPUTS;
uint32_t n; uint32_t n;
if (q != NULL && if (q != NULL &&
@ -607,21 +607,44 @@ int srslte_pusch_decode(srslte_pusch_t *q,
// Generate scrambling sequence if not pre-generated // Generate scrambling sequence if not pre-generated
srslte_sequence_t *seq = get_user_sequence(q, rnti, cfg->sf_idx, cfg->nbits.nof_bits); srslte_sequence_t *seq = get_user_sequence(q, rnti, cfg->sf_idx, cfg->nbits.nof_bits);
// Set CQI len assuming RI = 1 (3GPP 36.212 Clause 5.2.4.1. Uplink control information on PUSCH without UL-SCH data)
if (cqi_value) {
if (cqi_value->type == SRSLTE_CQI_TYPE_SUBBAND_HL) {
cqi_value->subband_hl.rank_is_not_one = false;
}
uci_data->uci_cqi_len = (uint32_t) srslte_cqi_size(cqi_value);
uci_data->uci_ri_len = (q->cell.nof_ports == 4) ? 2 : 1;
}
// Decode RI/HARQ bits before descrambling // Decode RI/HARQ bits before descrambling
if (srslte_ulsch_uci_decode_ri_ack(&q->ul_sch, cfg, softbuffer, q->q, seq->c, uci_data)) { if (srslte_ulsch_uci_decode_ri_ack(&q->ul_sch, cfg, softbuffer, q->q, seq->c, uci_data)) {
fprintf(stderr, "Error decoding RI/HARQ bits\n"); fprintf(stderr, "Error decoding RI/HARQ bits\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Set CQI len with corresponding RI
if (cqi_value) {
if (cqi_value->type == SRSLTE_CQI_TYPE_SUBBAND_HL) {
cqi_value->subband_hl.rank_is_not_one = (uci_data->uci_ri != 0);
}
uci_data->uci_cqi_len = (uint32_t) srslte_cqi_size(cqi_value);
}
// Descrambling // Descrambling
srslte_scrambling_s_offset(seq, q->q, 0, cfg->nbits.nof_bits); srslte_scrambling_s_offset(seq, q->q, 0, cfg->nbits.nof_bits);
return srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data); // Decode
} else { ret = srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data);
return SRSLTE_ERROR_INVALID_INPUTS;
// Unpack CQI value if available
if (cqi_value) {
srslte_cqi_value_unpack(uci_data->uci_cqi, cqi_value);
} }
} }
return ret;
}
uint32_t srslte_pusch_last_noi(srslte_pusch_t *q) { uint32_t srslte_pusch_last_noi(srslte_pusch_t *q) {
return q->ul_sch.nof_iterations; return q->ul_sch.nof_iterations;
} }

@ -559,16 +559,16 @@ void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srsl
srslte_ra_nbits_t nbits [SRSLTE_MAX_CODEWORDS]) srslte_ra_nbits_t nbits [SRSLTE_MAX_CODEWORDS])
{ {
// Compute number of RE // Compute number of RE
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { for (int i = 0; i < SRSLTE_MAX_TB; i++) {
/* Compute number of RE for first transport block */
nbits[i].nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb < 10 ? (cfi + 1) : cfi); nbits[i].nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb < 10 ? (cfi + 1) : cfi);
nbits[i].lstart = cell.nof_prb < 10 ? (cfi + 1) : cfi; nbits[i].lstart = cell.nof_prb < 10 ? (cfi + 1) : cfi;
if (grant->tb_en[i]) {
/* Compute number of RE for first transport block */
if (SRSLTE_SF_NORM == grant->sf_type) { if (SRSLTE_SF_NORM == grant->sf_type) {
nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart; nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart;
} else if (SRSLTE_SF_MBSFN == grant->sf_type) { } else if (SRSLTE_SF_MBSFN == grant->sf_type) {
nbits[i].nof_symb = 2 * SRSLTE_CP_EXT_NSYMB - nbits[0].lstart; nbits[i].nof_symb = 2 * SRSLTE_CP_EXT_NSYMB - nbits[0].lstart;
} }
if (grant->tb_en[i]) {
nbits[i].nof_bits = nbits[i].nof_re * grant->Qm[i]; nbits[i].nof_bits = nbits[i].nof_re * grant->Qm[i];
} }
} }

@ -658,7 +658,7 @@ int srslte_ulsch_uci_decode_ri_ack(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srs
if (cfg->cb_segm.tbs == 0) { if (cfg->cb_segm.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi];
} }
ret = srslte_uci_decode_ack(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, acks, uci_data->uci_ack_len); ret = srslte_uci_decode_ack_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, acks, uci_data->uci_ack_len, false);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -678,7 +678,7 @@ int srslte_ulsch_uci_decode_ri_ack(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srs
if (cfg->cb_segm.tbs == 0) { if (cfg->cb_segm.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi];
} }
ret = srslte_uci_decode_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, &uci_data->uci_ri); ret = srslte_uci_decode_ack_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, &uci_data->uci_ri, uci_data->uci_ri_len, true);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -756,13 +756,18 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q,
uint32_t nb_q = cfg->nbits.nof_bits; uint32_t nb_q = cfg->nbits.nof_bits;
uint32_t Qm = cfg->grant.Qm; uint32_t Qm = cfg->grant.Qm;
// Encode RI // Encode RI if CQI enabled
if (uci_data.uci_ri_len > 0) { if (uci_data.uci_ri_len > 0 || uci_data.uci_cqi_len > 0) {
/* If no RI is reported set it to zero as specified in 3GPP 36.213 clause 7.2.1 */
if (uci_data.uci_ri_len == 0) {
uci_data.uci_ri = 0;
}
float beta = beta_ri_offset[cfg->uci_cfg.I_offset_ri]; float beta = beta_ri_offset[cfg->uci_cfg.I_offset_ri];
if (cfg->cb_segm.tbs == 0) { if (cfg->cb_segm.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi];
} }
ret = srslte_uci_encode_ri(cfg, uci_data.uci_ri, uci_data.uci_cqi_len, beta, nb_q/Qm, q->ack_ri_bits); uint8_t ri[2] = {uci_data.uci_ri, 0};
ret = srslte_uci_encode_ack_ri(cfg, ri, uci_data.uci_ri_len, uci_data.uci_cqi_len, beta, nb_q/Qm, q->ack_ri_bits, true);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -809,8 +814,8 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q,
if (cfg->cb_segm.tbs == 0) { if (cfg->cb_segm.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi];
} }
ret = srslte_uci_encode_ack(cfg, acks, uci_data.uci_ack_len, uci_data.uci_cqi_len, ret = srslte_uci_encode_ack_ri(cfg, acks, uci_data.uci_ack_len, uci_data.uci_cqi_len,
beta, nb_q / Qm, &q->ack_ri_bits[Q_prime_ri * Qm]); beta, nb_q / Qm, &q->ack_ri_bits[Q_prime_ri * Qm], false);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }

@ -234,6 +234,7 @@ add_executable(pucch_test pucch_test.c)
target_link_libraries(pucch_test srslte_phy) target_link_libraries(pucch_test srslte_phy)
add_test(pucch_test pucch_test) add_test(pucch_test pucch_test)
add_test(pucch_test_uci_cqi_decoder pucch_test -q)
######################################################################## ########################################################################
# PRACH TEST # PRACH TEST

@ -182,7 +182,7 @@ int main(int argc, char **argv) {
srslte_filesource_read(&fsrc, input_buffer[0], flen); srslte_filesource_read(&fsrc, input_buffer[0], flen);
INFO("Reading %d samples sub-frame %d\n", flen, sf_idx); INFO("Reading %d samples sub-frame %d\n", flen, sf_idx);
ret = srslte_ue_dl_decode(&ue_dl, input_buffer, data, 0, sf_idx, acks); ret = srslte_ue_dl_decode(&ue_dl, data, 0, sf_idx, acks);
if(ret > 0) { if(ret > 0) {
printf("PDSCH Decoded OK!\n"); printf("PDSCH Decoded OK!\n");
} else if (ret == 0) { } else if (ret == 0) {

@ -187,7 +187,7 @@ int main(int argc, char **argv) {
srslte_filesource_read(&fsrc, input_buffer[0], flen); srslte_filesource_read(&fsrc, input_buffer[0], flen);
INFO("Reading %d samples sub-frame %d\n", flen, sf_idx); INFO("Reading %d samples sub-frame %d\n", flen, sf_idx);
ret = srslte_ue_dl_decode_mbsfn(&ue_dl, input_buffer, data[0], sf_idx); ret = srslte_ue_dl_decode_mbsfn(&ue_dl, data[0], sf_idx);
if(ret > 0) { if(ret > 0) {
printf("PMCH Decoded OK!\n"); printf("PMCH Decoded OK!\n");
} else if (ret < 0) { } else if (ret < 0) {

@ -199,7 +199,7 @@ int main(int argc, char **argv) {
srslte_timestamp_t tstamp; srslte_timestamp_t tstamp;
srslte_rf_start_rx_stream(&rf); srslte_rf_start_rx_stream(&rf, false);
uint32_t nframe=0; uint32_t nframe=0;
while(nframe<nof_frames) { while(nframe<nof_frames) {

@ -43,18 +43,20 @@ srslte_cell_t cell = {
}; };
uint32_t subframe = 0; uint32_t subframe = 0;
bool test_cqi_only = false;
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s [csNnv]\n", prog); printf("Usage: %s [csNnv]\n", prog);
printf("\t-c cell id [Default %d]\n", cell.id); printf("\t-c cell id [Default %d]\n", cell.id);
printf("\t-s subframe [Default %d]\n", subframe); printf("\t-s subframe [Default %d]\n", subframe);
printf("\t-n nof_prb [Default %d]\n", cell.nof_prb); printf("\t-n nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-q Test CQI encoding/decoding only [Default %s].\n", test_cqi_only?"yes":"no");
printf("\t-v [set verbose to debug, default none]\n"); printf("\t-v [set verbose to debug, default none]\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "csNnv")) != -1) { while ((opt = getopt(argc, argv, "csNnqv")) != -1) {
switch(opt) { switch(opt) {
case 's': case 's':
subframe = atoi(argv[optind]); subframe = atoi(argv[optind]);
@ -65,6 +67,9 @@ void parse_args(int argc, char **argv) {
case 'c': case 'c':
cell.id = atoi(argv[optind]); cell.id = atoi(argv[optind]);
break; break;
case 'q':
test_cqi_only = true;
break;
case 'v': case 'v':
srslte_verbose++; srslte_verbose++;
break; break;
@ -75,6 +80,59 @@ void parse_args(int argc, char **argv) {
} }
} }
int test_uci_cqi_pucch(void) {
int ret = SRSLTE_SUCCESS;
__attribute__((aligned(256))) uint8_t o_bits[SRSLTE_UCI_MAX_CQI_LEN_PUCCH] = {0};
__attribute__((aligned(256))) uint8_t e_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B] = {0};
__attribute__((aligned(256))) int16_t e_symb[SRSLTE_UCI_CQI_CODED_PUCCH_B] = {0};
__attribute__((aligned(256))) uint8_t d_bits[SRSLTE_UCI_MAX_CQI_LEN_PUCCH] = {0};
srslte_uci_cqi_pucch_t uci_cqi_pucch = {0};
srslte_uci_cqi_pucch_init(&uci_cqi_pucch);
for (uint32_t nof_bits = 1; nof_bits <= SRSLTE_UCI_MAX_CQI_LEN_PUCCH-1; nof_bits++) {
for (uint32_t cqi = 0; cqi < (1 <<nof_bits); cqi++) {
uint32_t recv;
uint8_t *ptr = o_bits;
srslte_bit_unpack(cqi, &ptr, nof_bits);
srslte_uci_encode_cqi_pucch(o_bits, nof_bits, e_bits);
//srslte_uci_encode_cqi_pucch_from_table(&uci_cqi_pucch, o_bits, nof_bits, e_bits);
for (int i = 0; i < SRSLTE_UCI_CQI_CODED_PUCCH_B; i++) {
e_symb[i] = 2*e_bits[i] - 1;
}
srslte_uci_decode_cqi_pucch(&uci_cqi_pucch, e_symb, d_bits, nof_bits);
ptr = d_bits;
recv = srslte_bit_pack(&ptr, nof_bits);
if (recv != cqi) {
printf("Error! cqi = %d (len: %d), %X!=%X \n", cqi, nof_bits, cqi, recv);
if (srslte_verbose) {
printf("original: ");
srslte_vec_fprint_b(stdout, o_bits, nof_bits);
printf(" decoded: ");
srslte_vec_fprint_b(stdout, d_bits, nof_bits);
}
ret = SRSLTE_ERROR;
}
}
}
srslte_uci_cqi_pucch_free(&uci_cqi_pucch);
if (ret) {
printf("Error\n");
} else {
printf("Ok\n");
}
return ret;
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
srslte_pucch_t pucch; srslte_pucch_t pucch;
srslte_pucch_cfg_t pucch_cfg; srslte_pucch_cfg_t pucch_cfg;
@ -87,6 +145,10 @@ int main(int argc, char **argv) {
parse_args(argc,argv); parse_args(argc,argv);
if (test_cqi_only) {
return test_uci_cqi_pucch();
}
if (srslte_pucch_init(&pucch)) { if (srslte_pucch_init(&pucch)) {
fprintf(stderr, "Error creating PDSCH object\n"); fprintf(stderr, "Error creating PDSCH object\n");
exit(-1); exit(-1);

@ -252,7 +252,7 @@ int main(int argc, char **argv) {
} }
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
int r = srslte_pusch_decode(&pusch_rx, &cfg, &softbuffer_rx, sf_symbols, ce, 0, rnti, data, &uci_data_rx); int r = srslte_pusch_decode(&pusch_rx, &cfg, &softbuffer_rx, sf_symbols, ce, 0, rnti, data, NULL, &uci_data_rx);
gettimeofday(&t[2], NULL); gettimeofday(&t[2], NULL);
get_time_interval(t); get_time_interval(t);
if (r) { if (r) {

@ -108,21 +108,24 @@ static uint8_t M_basis_seq_pucch[20][13]={
void srslte_uci_cqi_pucch_init(srslte_uci_cqi_pucch_t *q) { void srslte_uci_cqi_pucch_init(srslte_uci_cqi_pucch_t *q) {
uint8_t word[16]; uint8_t word[16];
uint32_t nwords = 16; uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH;
q->cqi_table = srslte_vec_malloc(nwords * sizeof(int8_t *));
q->cqi_table_s = srslte_vec_malloc(nwords * sizeof(int16_t *));
for (uint32_t w = 0; w < nwords; w++) { for (uint32_t w = 0; w < nwords; w++) {
q->cqi_table[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B * sizeof(int8_t)); q->cqi_table[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B * sizeof(int8_t));
q->cqi_table_s[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B * sizeof(int16_t)); q->cqi_table_s[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B * sizeof(int16_t));
uint8_t *ptr = word; uint8_t *ptr = word;
srslte_bit_unpack(w, &ptr, 4); srslte_bit_unpack(w, &ptr, SRSLTE_UCI_MAX_CQI_LEN_PUCCH);
srslte_uci_encode_cqi_pucch(word, 4, q->cqi_table[w]); srslte_uci_encode_cqi_pucch(word, SRSLTE_UCI_MAX_CQI_LEN_PUCCH, q->cqi_table[w]);
for (int j = 0; j < SRSLTE_UCI_CQI_CODED_PUCCH_B; j++) { for (int j = 0; j < SRSLTE_UCI_CQI_CODED_PUCCH_B; j++) {
q->cqi_table_s[w][j] = 2*q->cqi_table[w][j]-1; q->cqi_table_s[w][j] = (int16_t)(2 * q->cqi_table[w][j] - 1);
} }
} }
} }
void srslte_uci_cqi_pucch_free(srslte_uci_cqi_pucch_t *q) { void srslte_uci_cqi_pucch_free(srslte_uci_cqi_pucch_t *q) {
uint32_t nwords = 16; uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH;
for (uint32_t w=0;w<nwords;w++) { for (uint32_t w=0;w<nwords;w++) {
if (q->cqi_table[w]) { if (q->cqi_table[w]) {
free(q->cqi_table[w]); free(q->cqi_table[w]);
@ -131,6 +134,8 @@ void srslte_uci_cqi_pucch_free(srslte_uci_cqi_pucch_t *q) {
free(q->cqi_table_s[w]); free(q->cqi_table_s[w]);
} }
} }
free(q->cqi_table);
free(q->cqi_table_s);
} }
/* Encode UCI CQI/PMI as described in 5.2.3.3 of 36.212 /* Encode UCI CQI/PMI as described in 5.2.3.3 of 36.212
@ -151,17 +156,32 @@ int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_b
} }
} }
int srslte_uci_encode_cqi_pucch_from_table(srslte_uci_cqi_pucch_t *q, uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B])
{
if (cqi_len <= SRSLTE_UCI_MAX_CQI_LEN_PUCCH) {
bzero(&cqi_data[cqi_len], SRSLTE_UCI_MAX_CQI_LEN_PUCCH - cqi_len);
uint8_t *ptr = cqi_data;
uint32_t packed = srslte_bit_pack(&ptr, SRSLTE_UCI_MAX_CQI_LEN_PUCCH);
memcpy(b_bits, q->cqi_table[packed], SRSLTE_UCI_CQI_CODED_PUCCH_B);
return SRSLTE_SUCCESS;
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
/* Decode UCI CQI/PMI over PUCCH /* Decode UCI CQI/PMI over PUCCH
*/ */
int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, int16_t b_bits[32], uint8_t *cqi_data, uint32_t cqi_len) int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, int16_t b_bits[32], uint8_t *cqi_data, uint32_t cqi_len)
{ {
if (cqi_len == 4 && if (cqi_len < SRSLTE_UCI_MAX_CQI_LEN_PUCCH &&
b_bits != NULL && b_bits != NULL &&
cqi_data != NULL) cqi_data != NULL)
{ {
uint32_t max_w = 0; uint32_t max_w = 0;
int32_t max_corr = INT32_MIN; int32_t max_corr = INT32_MIN;
for (uint32_t w=0;w<16;w++) { uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH;
for (uint32_t w=0;w<nwords;w += 1<<(SRSLTE_UCI_MAX_CQI_LEN_PUCCH - cqi_len)) {
// Calculate correlation with pregenerated word and select maximum // Calculate correlation with pregenerated word and select maximum
int32_t corr = srslte_vec_dot_prod_sss(q->cqi_table_s[w], b_bits, SRSLTE_UCI_CQI_CODED_PUCCH_B); int32_t corr = srslte_vec_dot_prod_sss(q->cqi_table_s[w], b_bits, SRSLTE_UCI_CQI_CODED_PUCCH_B);
@ -172,7 +192,7 @@ int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, int16_t b_bits[32
} }
// Convert word to bits again // Convert word to bits again
uint8_t *ptr = cqi_data; uint8_t *ptr = cqi_data;
srslte_bit_unpack(max_w, &ptr, cqi_len); srslte_bit_unpack(max_w, &ptr, SRSLTE_UCI_MAX_CQI_LEN_PUCCH);
INFO("Decoded CQI: w=%d, corr=%d\n", max_w, max_corr); INFO("Decoded CQI: w=%d, corr=%d\n", max_w, max_corr);
return max_corr; return max_corr;
@ -586,9 +606,7 @@ static uint32_t encode_ri_ack(uint8_t data[2], uint32_t data_len, srslte_uci_bit
/* Decode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212 /* Decode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212
* Currently only supporting 1-bit HARQ * Currently only supporting 1-bit HARQ
*/ */
#ifndef MIMO_ENB static int32_t decode_ri_ack_1bit(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos)
static int32_t decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos)
{ {
uint32_t p0 = pos[0].position; uint32_t p0 = pos[0].position;
uint32_t p1 = pos[1].position; uint32_t p1 = pos[1].position;
@ -598,33 +616,8 @@ static int32_t decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *
return -(q0+q1); return -(q0+q1);
} }
int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq,
float beta, uint32_t H_prime_total,
uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t acks[2], uint32_t nof_acks)
{
int32_t rx_ack = 0;
if (beta < 0) { static void decode_ri_ack_2bits(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos, uint32_t Qm, int32_t data[3])
fprintf(stderr, "Error beta is reserved\n");
return -1;
}
uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta);
// Use the same interleaver function to get the HARQ bit position
for (uint32_t i=0;i<Qprime;i++) {
uci_ulsch_interleave_ack_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]);
rx_ack += (int32_t) decode_ri_ack(q_bits, c_seq, &ack_bits[cfg->grant.Qm*i]);
}
if (acks) {
acks[0] = rx_ack>0;
}
return (int) Qprime;
}
#else
static void decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos, uint32_t Qm, int32_t data[3])
{ {
uint32_t p0 = pos[Qm * 0 + 0].position; uint32_t p0 = pos[Qm * 0 + 0].position;
uint32_t p1 = pos[Qm * 0 + 1].position; uint32_t p1 = pos[Qm * 0 + 1].position;
@ -645,118 +638,91 @@ static void decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos
data[2] -= q2 + q5; data[2] -= q2 + q5;
} }
int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, /* Encode UCI ACK/RI bits as described in 5.2.2.6 of 36.212
float beta, uint32_t H_prime_total, * Currently only supporting 1-bit RI
uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t acks[2], uint32_t nof_acks)
{
int32_t acks_sum[3] = {0, 0, 0};
if (beta < 0) {
fprintf(stderr, "Error beta is reserved\n");
return -1;
}
uint32_t Qprime = Q_prime_ri_ack(cfg, nof_acks, O_cqi, beta);
// Use the same interleaver function to get the HARQ bit position
for (uint32_t i = 0; i < Qprime; i++) {
uci_ulsch_interleave_ack_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]);
if ((i % 3 == 0) && i > 0) {
decode_ri_ack(q_bits, &c_seq[0], &ack_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, acks_sum);
}
}
if (acks) {
acks[0] = (uint8_t)(acks_sum[0] > 0);
acks[1] = (uint8_t)(acks_sum[1] > 0);
// TODO: Do something with acks_sum[2]
}
return (int) Qprime;
}
#endif
/* Encode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212
* Currently only supporting 1-bit HARQ
*/ */
int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, uint8_t acks[2], uint32_t nof_acks, int srslte_uci_encode_ack_ri(srslte_pusch_cfg_t *cfg,
uint8_t *data, uint32_t data_len,
uint32_t O_cqi, float beta, uint32_t H_prime_total, uint32_t O_cqi, float beta, uint32_t H_prime_total,
srslte_uci_bit_t *ack_bits) srslte_uci_bit_t *bits, bool ack_ri) {
{
if (beta < 0) { if (beta < 0) {
fprintf(stderr, "Error beta is reserved\n"); fprintf(stderr, "Error beta is reserved\n");
return -1; return -1;
} }
uint32_t Qprime = Q_prime_ri_ack(cfg, data_len, O_cqi, beta);
uint32_t Qprime = Q_prime_ri_ack(cfg, nof_acks, O_cqi, beta);
srslte_uci_bit_type_t q_encoded_bits[18]; srslte_uci_bit_type_t q_encoded_bits[18];
uint32_t nof_encoded_bits = encode_ri_ack(acks, nof_acks, q_encoded_bits, cfg->grant.Qm); uint32_t nof_encoded_bits = encode_ri_ack(data, data_len, q_encoded_bits, cfg->grant.Qm);
for (uint32_t i = 0; i < Qprime; i++) { for (uint32_t i = 0; i < Qprime; i++) {
uci_ulsch_interleave_ack_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]); if (ack_ri) {
uci_ulsch_interleave_put(&q_encoded_bits[(i*cfg->grant.Qm)%nof_encoded_bits], cfg->grant.Qm, &ack_bits[cfg->grant.Qm*i]); uci_ulsch_interleave_ri_gen(i,
cfg->grant.Qm,
H_prime_total,
cfg->nbits.nof_symb,
cfg->cp,
&bits[cfg->grant.Qm * i]);
} else {
uci_ulsch_interleave_ack_gen(i,
cfg->grant.Qm,
H_prime_total,
cfg->nbits.nof_symb,
cfg->cp,
&bits[cfg->grant.Qm * i]);
}
uci_ulsch_interleave_put(&q_encoded_bits[(i * cfg->grant.Qm) % nof_encoded_bits],
cfg->grant.Qm,
&bits[cfg->grant.Qm * i]);
} }
return (int) Qprime; return (int) Qprime;
} }
/* Encode UCI RI bits as described in 5.2.2.6 of 36.212 /* Decode UCI ACK/RI bits as described in 5.2.2.6 of 36.212
* Currently only supporting 1-bit RI * Currently only supporting 1-bit RI
*/ */
int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq,
float beta, uint32_t H_prime_total, float beta, uint32_t H_prime_total,
uint32_t O_cqi, srslte_uci_bit_t *ri_bits, uint8_t *data) uint32_t O_cqi, srslte_uci_bit_t *ack_ri_bits, uint8_t data[2], uint32_t nof_bits, bool is_ri)
{ {
int32_t ri_sum[3] = {0, 0, 0}; int32_t sum[3] = {0, 0, 0};
if (beta < 0) { if (beta < 0) {
fprintf(stderr, "Error beta is reserved\n"); fprintf(stderr, "Error beta is reserved\n");
return -1; return -1;
} }
uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta); uint32_t Qprime = Q_prime_ri_ack(cfg, nof_bits, O_cqi, beta);
// Use the same interleaver function to get the HARQ bit position
for (uint32_t i = 0; i < Qprime; i++) { for (uint32_t i = 0; i < Qprime; i++) {
uci_ulsch_interleave_ri_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]); if (is_ri) {
if ((i % 3 == 0) && i > 0) { uci_ulsch_interleave_ri_gen(i,
//decode_ri_ack(q_bits, &c_seq[0], &ri_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, ri_sum); cfg->grant.Qm,
} H_prime_total,
} cfg->nbits.nof_symb,
cfg->cp,
&ack_ri_bits[cfg->grant.Qm * i]);
} else {
uci_ulsch_interleave_ack_gen(i,
cfg->grant.Qm,
H_prime_total,
cfg->nbits.nof_symb,
cfg->cp,
&ack_ri_bits[cfg->grant.Qm * i]);
if (data) {
*data = (uint8_t) ((ri_sum[0] + ri_sum[1] + ri_sum[2]) > 0);
} }
if (nof_bits == 2 && (i % 3 == 0) && i > 0) {
return (int) Qprime; decode_ri_ack_2bits(q_bits, &c_seq[0], &ack_ri_bits[cfg->grant.Qm * (i - 3)], cfg->grant.Qm, sum);
} else if (nof_bits == 1) {
sum[0] += (int32_t) decode_ri_ack_1bit(q_bits, c_seq, &ack_ri_bits[cfg->grant.Qm * i]);
} }
/* Encode UCI RI bits as described in 5.2.2.6 of 36.212
* Currently only supporting 1-bit RI
*/
int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg,
uint8_t ri,
uint32_t O_cqi, float beta, uint32_t H_prime_total,
srslte_uci_bit_t *ri_bits)
{
// FIXME: It supports RI of 1 bit only
uint8_t data[2] = {ri, 0};
if (beta < 0) {
fprintf(stderr, "Error beta is reserved\n");
return -1;
} }
uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta);
srslte_uci_bit_type_t q_encoded_bits[18];
uint32_t nof_encoded_bits = encode_ri_ack(data, 1, q_encoded_bits, cfg->grant.Qm);
for (uint32_t i=0;i<Qprime;i++) { data[0] = (uint8_t) (sum[0] > 0);
uci_ulsch_interleave_ri_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]); if (nof_bits == 2) {
uci_ulsch_interleave_put(&q_encoded_bits[(i*cfg->grant.Qm)%nof_encoded_bits], cfg->grant.Qm, &ri_bits[cfg->grant.Qm*i]); data[1] = (uint8_t) (sum[1] > 0);
} }
return (int) Qprime; return (int) Qprime;
} }

@ -101,7 +101,7 @@ int rf_blade_start_tx_stream(void *h)
return 0; return 0;
} }
int rf_blade_start_rx_stream(void *h) int rf_blade_start_rx_stream(void *h, bool now)
{ {
int status; int status;
rf_blade_handler_t *handler = (rf_blade_handler_t*) h; rf_blade_handler_t *handler = (rf_blade_handler_t*) h;

@ -44,7 +44,7 @@ SRSLTE_API void rf_blade_set_tx_cal(void *h, srslte_rf_cal_t *cal);
SRSLTE_API void rf_blade_set_rx_cal(void *h, srslte_rf_cal_t *cal); SRSLTE_API void rf_blade_set_rx_cal(void *h, srslte_rf_cal_t *cal);
SRSLTE_API int rf_blade_start_rx_stream(void *h); SRSLTE_API int rf_blade_start_rx_stream(void *h, bool now);
SRSLTE_API int rf_blade_start_rx_stream_nsamples(void *h, SRSLTE_API int rf_blade_start_rx_stream_nsamples(void *h,
uint32_t nsamples); uint32_t nsamples);

@ -30,7 +30,7 @@ typedef struct {
const char *name; const char *name;
char* (*srslte_rf_devname) (void *h); char* (*srslte_rf_devname) (void *h);
bool (*srslte_rf_rx_wait_lo_locked) (void *h); bool (*srslte_rf_rx_wait_lo_locked) (void *h);
int (*srslte_rf_start_rx_stream)(void *h); int (*srslte_rf_start_rx_stream)(void *h, bool now);
int (*srslte_rf_stop_rx_stream)(void *h); int (*srslte_rf_stop_rx_stream)(void *h);
void (*srslte_rf_flush_buffer)(void *h); void (*srslte_rf_flush_buffer)(void *h);
bool (*srslte_rf_has_rssi)(void *h); bool (*srslte_rf_has_rssi)(void *h);

@ -99,11 +99,7 @@ const char* srslte_rf_get_devname(srslte_rf_t *rf) {
return ((rf_dev_t*) rf->dev)->name; return ((rf_dev_t*) rf->dev)->name;
} }
int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args) { int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args, uint32_t nof_channels) {
return srslte_rf_open_devname_multi(rf, devname, args, 1);
}
int srslte_rf_open_devname_multi(srslte_rf_t *rf, char *devname, char *args, uint32_t nof_channels) {
/* Try to open the device if name is provided */ /* Try to open the device if name is provided */
if (devname) { if (devname) {
if (devname[0] != '\0') { if (devname[0] != '\0') {
@ -150,9 +146,9 @@ bool srslte_rf_rx_wait_lo_locked(srslte_rf_t *rf)
return ((rf_dev_t*) rf->dev)->srslte_rf_rx_wait_lo_locked(rf->handler); return ((rf_dev_t*) rf->dev)->srslte_rf_rx_wait_lo_locked(rf->handler);
} }
int srslte_rf_start_rx_stream(srslte_rf_t *rf) int srslte_rf_start_rx_stream(srslte_rf_t *rf, bool now)
{ {
return ((rf_dev_t*) rf->dev)->srslte_rf_start_rx_stream(rf->handler); return ((rf_dev_t*) rf->dev)->srslte_rf_start_rx_stream(rf->handler, now);
} }
int srslte_rf_stop_rx_stream(srslte_rf_t *rf) int srslte_rf_stop_rx_stream(srslte_rf_t *rf)
@ -187,12 +183,12 @@ void srslte_rf_register_error_handler(srslte_rf_t *rf, srslte_rf_error_handler_t
int srslte_rf_open(srslte_rf_t *h, char *args) int srslte_rf_open(srslte_rf_t *h, char *args)
{ {
return srslte_rf_open_devname_multi(h, NULL, args, 1); return srslte_rf_open_devname(h, NULL, args, 1);
} }
int srslte_rf_open_multi(srslte_rf_t *h, char *args, uint32_t nof_rx_antennas) int srslte_rf_open_multi(srslte_rf_t *h, char *args, uint32_t nof_channels)
{ {
return srslte_rf_open_devname_multi(h, NULL, args, nof_rx_antennas); return srslte_rf_open_devname(h, NULL, args, nof_channels);
} }
int srslte_rf_close(srslte_rf_t *rf) int srslte_rf_close(srslte_rf_t *rf)

@ -115,7 +115,7 @@ void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal)
} }
int rf_soapy_start_rx_stream(void *h) int rf_soapy_start_rx_stream(void *h, bool now)
{ {
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if(handler->rx_stream_active == false){ if(handler->rx_stream_active == false){

@ -45,7 +45,7 @@ SRSLTE_API void rf_soapy_set_tx_cal(void *h, srslte_rf_cal_t *cal);
SRSLTE_API void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal); SRSLTE_API void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal);
SRSLTE_API int rf_soapy_start_rx_stream(void *h); SRSLTE_API int rf_soapy_start_rx_stream(void *h, bool now);
SRSLTE_API int rf_soapy_stop_rx_stream(void *h); SRSLTE_API int rf_soapy_stop_rx_stream(void *h);

@ -219,20 +219,22 @@ void rf_uhd_set_rx_cal(void *h, srslte_rf_cal_t *cal)
} }
int rf_uhd_start_rx_stream(void *h) int rf_uhd_start_rx_stream(void *h, bool now)
{ {
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
uhd_stream_cmd_t stream_cmd = { uhd_stream_cmd_t stream_cmd = {
.stream_mode = UHD_STREAM_MODE_START_CONTINUOUS, .stream_mode = UHD_STREAM_MODE_START_CONTINUOUS,
.stream_now = false .stream_now = now
}; };
if (!now) {
uhd_usrp_get_time_now(handler->usrp, 0, &stream_cmd.time_spec_full_secs, &stream_cmd.time_spec_frac_secs); uhd_usrp_get_time_now(handler->usrp, 0, &stream_cmd.time_spec_full_secs, &stream_cmd.time_spec_frac_secs);
stream_cmd.time_spec_frac_secs += 0.1; stream_cmd.time_spec_frac_secs += 0.1;
if (stream_cmd.time_spec_frac_secs > 1) { if (stream_cmd.time_spec_frac_secs > 1) {
stream_cmd.time_spec_frac_secs -= 1; stream_cmd.time_spec_frac_secs -= 1;
stream_cmd.time_spec_full_secs += 1; stream_cmd.time_spec_full_secs += 1;
} }
}
uhd_rx_streamer_issue_stream_cmd(handler->rx_stream, &stream_cmd); uhd_rx_streamer_issue_stream_cmd(handler->rx_stream, &stream_cmd);
return 0; return 0;
} }

@ -49,7 +49,8 @@ SRSLTE_API void rf_uhd_set_tx_cal(void *h, srslte_rf_cal_t *cal);
SRSLTE_API void rf_uhd_set_rx_cal(void *h, srslte_rf_cal_t *cal); SRSLTE_API void rf_uhd_set_rx_cal(void *h, srslte_rf_cal_t *cal);
SRSLTE_API int rf_uhd_start_rx_stream(void *h); SRSLTE_API int rf_uhd_start_rx_stream(void *h,
bool now);
SRSLTE_API int rf_uhd_start_rx_stream_nsamples(void *h, SRSLTE_API int rf_uhd_start_rx_stream_nsamples(void *h,
uint32_t nsamples); uint32_t nsamples);

@ -60,7 +60,7 @@ int rf_rssi_scan(srslte_rf_t *rf, float *freqs, float *rssi, int nof_bands, doub
srslte_rf_set_rx_freq(rf, f); srslte_rf_set_rx_freq(rf, f);
srslte_rf_rx_wait_lo_locked(rf); srslte_rf_rx_wait_lo_locked(rf);
usleep(10000); usleep(10000);
srslte_rf_start_rx_stream(rf); srslte_rf_start_rx_stream(rf, false);
/* discard first samples */ /* discard first samples */
for (j=0;j<2;j++) { for (j=0;j<2;j++) {
@ -122,7 +122,7 @@ int rf_mib_decoder(srslte_rf_t *rf, uint32_t nof_rx_antennas,cell_search_cfg_t *
srslte_rf_set_rx_srate(rf, (float) srate); srslte_rf_set_rx_srate(rf, (float) srate);
INFO("Starting receiver...\n", 0); INFO("Starting receiver...\n", 0);
srslte_rf_start_rx_stream(rf); srslte_rf_start_rx_stream(rf, true);
/* Find and decody MIB */ /* Find and decody MIB */
ret = srslte_ue_mib_sync_decode(&ue_mib, config->max_frames_pbch, bch_payload, &cell->nof_ports, NULL); ret = srslte_ue_mib_sync_decode(&ue_mib, config->max_frames_pbch, bch_payload, &cell->nof_ports, NULL);
@ -179,7 +179,7 @@ int rf_cell_search(srslte_rf_t *rf, uint32_t nof_rx_antennas,
srslte_rf_set_rx_srate(rf, SRSLTE_CS_SAMP_FREQ); srslte_rf_set_rx_srate(rf, SRSLTE_CS_SAMP_FREQ);
INFO("Starting receiver...\n", 0); INFO("Starting receiver...\n", 0);
srslte_rf_start_rx_stream(rf); srslte_rf_start_rx_stream(rf, false);
/* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */ /* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */
uint32_t max_peak_cell = 0; uint32_t max_peak_cell = 0;

@ -68,7 +68,7 @@ static void corr_all_sz_partial(cf_t z[SRSLTE_SSS_N], float s[SRSLTE_SSS_N][SRSL
} }
} }
static void extract_pair_sss(srslte_sss_synch_t *q, const cf_t *input, cf_t *ce, cf_t y[2][SRSLTE_SSS_N]) { static void extract_pair_sss(srslte_sss_t *q, const cf_t *input, cf_t *ce, cf_t y[2][SRSLTE_SSS_N]) {
cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX]; cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX];
srslte_dft_run_c(&q->dftp_input, input, input_fft); srslte_dft_run_c(&q->dftp_input, input, input_fft);
@ -88,10 +88,10 @@ static void extract_pair_sss(srslte_sss_synch_t *q, const cf_t *input, cf_t *ce,
} }
int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, const cf_t *input, uint32_t *m0, float *m0_value, int srslte_sss_m0m1_diff(srslte_sss_t *q, const cf_t *input, uint32_t *m0, float *m0_value,
uint32_t *m1, float *m1_value) uint32_t *m1, float *m1_value)
{ {
return srslte_sss_synch_m0m1_diff_coh(q, input, NULL, m0, m0_value, m1, m1_value); return srslte_sss_m0m1_diff_coh(q, input, NULL, m0, m0_value, m1, m1_value);
} }
/* Differential SSS estimation. /* Differential SSS estimation.
@ -102,7 +102,7 @@ int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, const cf_t *input, uint32_
* *
*/ */
int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, const cf_t *input, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, int srslte_sss_m0m1_diff_coh(srslte_sss_t *q, const cf_t *input, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value,
uint32_t *m1, float *m1_value) uint32_t *m1, float *m1_value)
{ {
@ -145,7 +145,7 @@ int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, const cf_t *input, cf_
* Jung-In Kim, Jung-Su Han, Hee-Jin Roh and Hyung-Jin Choi * Jung-In Kim, Jung-Su Han, Hee-Jin Roh and Hyung-Jin Choi
*/ */
int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q, const cf_t *input, uint32_t M, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, int srslte_sss_m0m1_partial(srslte_sss_t *q, const cf_t *input, uint32_t M, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value,
uint32_t *m1, float *m1_value) uint32_t *m1, float *m1_value)
{ {

@ -35,7 +35,7 @@
#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/debug.h"
int srslte_pss_synch_init_N_id_2(cf_t *pss_signal_freq, cf_t *pss_signal_time, int srslte_pss_init_N_id_2(cf_t *pss_signal_freq, cf_t *pss_signal_time,
uint32_t N_id_2, uint32_t fft_size, int cfo_i) { uint32_t N_id_2, uint32_t fft_size, int cfo_i) {
srslte_dft_plan_t plan; srslte_dft_plan_t plan;
cf_t pss_signal_pad[2048]; cf_t pss_signal_pad[2048];
@ -73,16 +73,16 @@ int srslte_pss_synch_init_N_id_2(cf_t *pss_signal_freq, cf_t *pss_signal_time,
/* Initializes the PSS synchronization object with fft_size=128 /* Initializes the PSS synchronization object with fft_size=128
*/ */
int srslte_pss_synch_init(srslte_pss_synch_t *q, uint32_t frame_size) { int srslte_pss_init(srslte_pss_t *q, uint32_t frame_size) {
return srslte_pss_synch_init_fft(q, frame_size, 128); return srslte_pss_init_fft(q, frame_size, 128);
} }
int srslte_pss_synch_init_fft(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size) { int srslte_pss_init_fft(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size) {
return srslte_pss_synch_init_fft_offset(q, frame_size, fft_size, 0); return srslte_pss_init_fft_offset(q, frame_size, fft_size, 0);
} }
int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { int srslte_pss_init_fft_offset(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, int offset) {
return srslte_pss_synch_init_fft_offset_decim(q, frame_size, fft_size, offset, 1); return srslte_pss_init_fft_offset_decim(q, frame_size, fft_size, offset, 1);
} }
/* Initializes the PSS synchronization object. /* Initializes the PSS synchronization object.
@ -90,7 +90,7 @@ int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size,
* It correlates a signal of frame_size samples with the PSS sequence in the frequency * It correlates a signal of frame_size samples with the PSS sequence in the frequency
* domain. The PSS sequence is transformed using fft_size samples. * domain. The PSS sequence is transformed using fft_size samples.
*/ */
int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, int srslte_pss_init_fft_offset_decim(srslte_pss_t *q,
uint32_t max_frame_size, uint32_t max_fft_size, uint32_t max_frame_size, uint32_t max_fft_size,
int offset, int decimate) int offset, int decimate)
{ {
@ -102,7 +102,7 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q,
uint32_t N_id_2; uint32_t N_id_2;
uint32_t buffer_size; uint32_t buffer_size;
bzero(q, sizeof(srslte_pss_synch_t)); bzero(q, sizeof(srslte_pss_t));
q->N_id_2 = 10; q->N_id_2 = 10;
q->ema_alpha = 0.2; q->ema_alpha = 0.2;
@ -143,7 +143,7 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q,
} }
srslte_dft_plan_set_mirror(&q->idftp_input, true); srslte_dft_plan_set_mirror(&q->idftp_input, true);
srslte_dft_plan_set_dc(&q->idftp_input, true); srslte_dft_plan_set_dc(&q->idftp_input, true);
srslte_dft_plan_set_norm(&q->idftp_input, true); srslte_dft_plan_set_norm(&q->idftp_input, false);
bzero(q->tmp_fft2, sizeof(cf_t)*SRSLTE_SYMBOL_SZ_MAX); bzero(q->tmp_fft2, sizeof(cf_t)*SRSLTE_SYMBOL_SZ_MAX);
@ -183,7 +183,7 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q,
goto clean_and_exit; goto clean_and_exit;
} }
/* The PSS is translated into the time domain for each N_id_2 */ /* The PSS is translated into the time domain for each N_id_2 */
if (srslte_pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { if (srslte_pss_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) {
fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size);
goto clean_and_exit; goto clean_and_exit;
} }
@ -192,27 +192,25 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q,
#ifdef CONVOLUTION_FFT #ifdef CONVOLUTION_FFT
for(N_id_2=0; N_id_2<3; N_id_2++)
q->pss_signal_freq_full[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t));
if (srslte_conv_fft_cc_init(&q->conv_fft, frame_size, fft_size)) { if (srslte_conv_fft_cc_init(&q->conv_fft, frame_size, fft_size)) {
fprintf(stderr, "Error initiating convolution FFT\n"); fprintf(stderr, "Error initiating convolution FFT\n");
goto clean_and_exit; goto clean_and_exit;
} }
for(int i=0; i<3; i++) { for(N_id_2=0; N_id_2<3; N_id_2++) {
srslte_dft_run_c(&q->conv_fft.filter_plan, q->pss_signal_time[i], q->pss_signal_freq_full[i]); q->pss_signal_freq_full[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t));
srslte_dft_run_c(&q->conv_fft.filter_plan, q->pss_signal_time[N_id_2], q->pss_signal_freq_full[N_id_2]);
} }
#endif #endif
srslte_pss_synch_reset(q); srslte_pss_reset(q);
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
clean_and_exit: clean_and_exit:
if (ret == SRSLTE_ERROR) { if (ret == SRSLTE_ERROR) {
srslte_pss_synch_free(q); srslte_pss_free(q);
} }
return ret; return ret;
@ -224,7 +222,7 @@ clean_and_exit:
* It correlates a signal of frame_size samples with the PSS sequence in the frequency * It correlates a signal of frame_size samples with the PSS sequence in the frequency
* domain. The PSS sequence is transformed using fft_size samples. * domain. The PSS sequence is transformed using fft_size samples.
*/ */
int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { int srslte_pss_resize(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, int offset) {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
@ -233,7 +231,7 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
if (fft_size > q->max_fft_size || frame_size > q->max_frame_size) { if (fft_size > q->max_fft_size || frame_size > q->max_frame_size) {
fprintf(stderr, "Error in pss_synch_config(): fft_size and frame_size must be lower than initialized\n"); fprintf(stderr, "Error in pss_config(): fft_size and frame_size must be lower than initialized\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -273,7 +271,7 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t
// Generate PSS sequences for this FFT size // Generate PSS sequences for this FFT size
for (N_id_2=0;N_id_2<3;N_id_2++) { for (N_id_2=0;N_id_2<3;N_id_2++) {
if (srslte_pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { if (srslte_pss_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) {
fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -291,7 +289,7 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t
#endif #endif
srslte_pss_synch_reset(q); srslte_pss_reset(q);
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
@ -299,7 +297,7 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t
} }
void srslte_pss_synch_free(srslte_pss_synch_t *q) { void srslte_pss_free(srslte_pss_t *q) {
uint32_t i; uint32_t i;
if (q) { if (q) {
@ -339,11 +337,11 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) {
} }
bzero(q, sizeof(srslte_pss_synch_t)); bzero(q, sizeof(srslte_pss_t));
} }
} }
void srslte_pss_synch_reset(srslte_pss_synch_t *q) { void srslte_pss_reset(srslte_pss_t *q) {
uint32_t buffer_size = q->fft_size + q->frame_size + 1; uint32_t buffer_size = q->fft_size + q->frame_size + 1;
bzero(q->conv_output_avg, sizeof(float) * buffer_size); bzero(q->conv_output_avg, sizeof(float) * buffer_size);
} }
@ -401,7 +399,7 @@ void srslte_pss_get_slot(cf_t *slot, cf_t *pss_signal, uint32_t nof_prb, srslte_
/** Sets the current N_id_2 value. Returns -1 on error, 0 otherwise /** Sets the current N_id_2 value. Returns -1 on error, 0 otherwise
*/ */
int srslte_pss_synch_set_N_id_2(srslte_pss_synch_t *q, uint32_t N_id_2) { int srslte_pss_set_N_id_2(srslte_pss_t *q, uint32_t N_id_2) {
if (!srslte_N_id_2_isvalid((N_id_2))) { if (!srslte_N_id_2_isvalid((N_id_2))) {
fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2);
return -1; return -1;
@ -413,11 +411,11 @@ int srslte_pss_synch_set_N_id_2(srslte_pss_synch_t *q, uint32_t N_id_2) {
/* Sets the weight factor alpha for the exponential moving average of the PSS correlation output /* Sets the weight factor alpha for the exponential moving average of the PSS correlation output
*/ */
void srslte_pss_synch_set_ema_alpha(srslte_pss_synch_t *q, float alpha) { void srslte_pss_set_ema_alpha(srslte_pss_t *q, float alpha) {
q->ema_alpha = alpha; q->ema_alpha = alpha;
} }
float compute_peak_sidelobe(srslte_pss_synch_t *q, uint32_t corr_peak_pos, uint32_t conv_output_len) float compute_peak_sidelobe(srslte_pss_t *q, uint32_t corr_peak_pos, uint32_t conv_output_len)
{ {
// Find end of peak lobe to the right // Find end of peak lobe to the right
int pl_ub = corr_peak_pos+1; int pl_ub = corr_peak_pos+1;
@ -455,7 +453,7 @@ float compute_peak_sidelobe(srslte_pss_synch_t *q, uint32_t corr_peak_pos, uint3
* *
* Input buffer must be subframe_size long. * Input buffer must be subframe_size long.
*/ */
int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, const cf_t *input, float *corr_peak_value) int srslte_pss_find_pss(srslte_pss_t *q, const cf_t *input, float *corr_peak_value)
{ {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
@ -474,7 +472,7 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, const cf_t *input, float *c
/* Correlate input with PSS sequence /* Correlate input with PSS sequence
* *
* We do not reverse time-domain PSS signal because it's conjugate is symmetric. * We do not reverse time-domain PSS signal because it's conjugate is symmetric.
* The conjugate operation on pss_signal_time has been done in srslte_pss_synch_init_N_id_2 * The conjugate operation on pss_signal_time has been done in srslte_pss_init_N_id_2
* This is why we can use FFT-based convolution * This is why we can use FFT-based convolution
*/ */
if (q->frame_size >= q->fft_size) { if (q->frame_size >= q->fft_size) {
@ -545,9 +543,8 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, const cf_t *input, float *c
* input signal is in the time-domain. * input signal is in the time-domain.
* ce is the returned frequency-domain channel estimates. * ce is the returned frequency-domain channel estimates.
*/ */
int srslte_pss_synch_chest(srslte_pss_synch_t *q, const cf_t *input, cf_t ce[SRSLTE_PSS_LEN]) { int srslte_pss_chest(srslte_pss_t *q, const cf_t *input, cf_t ce[SRSLTE_PSS_LEN]) {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX];
if (q != NULL && if (q != NULL &&
input != NULL) input != NULL)
@ -559,18 +556,41 @@ int srslte_pss_synch_chest(srslte_pss_synch_t *q, const cf_t *input, cf_t ce[SRS
} }
/* Transform to frequency-domain */ /* Transform to frequency-domain */
srslte_dft_run_c(&q->dftp_input, input, input_fft); srslte_dft_run_c(&q->dftp_input, input, q->tmp_fft);
/* Compute channel estimate taking the PSS sequence as reference */ /* Compute channel estimate taking the PSS sequence as reference */
srslte_vec_prod_conj_ccc(&input_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], q->pss_signal_freq[q->N_id_2], ce, SRSLTE_PSS_LEN); srslte_vec_prod_conj_ccc(&q->tmp_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], q->pss_signal_freq[q->N_id_2], ce, SRSLTE_PSS_LEN);
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
return ret; return ret;
} }
/* input points to beginning of last OFDM symbol of slot 0 of subframe 0 or 5
* It must be called after calling srslte_pss_cfo_compute() with filter enabled
*/
void srslte_pss_sic(srslte_pss_t *q, cf_t *input) {
if (q->chest_on_filter) {
bzero(q->tmp_fft, sizeof(cf_t)*q->fft_size);
// Pass transmitted PSS sequence through the channel
srslte_vec_prod_ccc(q->pss_signal_freq[q->N_id_2], q->tmp_ce, &q->tmp_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], SRSLTE_PSS_LEN);
// Get time-domain version of the received PSS
srslte_dft_run_c(&q->idftp_input, q->tmp_fft, q->tmp_fft2);
// Substract received PSS from this N_id_2 from the input signal
srslte_vec_sc_prod_cfc(q->tmp_fft2, 1.0/q->fft_size, q->tmp_fft2, q->fft_size);
srslte_vec_sub_ccc(input, q->tmp_fft2, input, q->fft_size);
} else {
fprintf(stderr, "Error calling srslte_pss_sic(): need to enable channel estimation on filtering\n");
}
}
// Frequency-domain filtering of the central 64 sub-carriers // Frequency-domain filtering of the central 64 sub-carriers
void srslte_pss_synch_filter(srslte_pss_synch_t *q, const cf_t *input, cf_t *output) void srslte_pss_filter(srslte_pss_t *q, const cf_t *input, cf_t *output)
{ {
srslte_dft_run_c(&q->dftp_input, input, q->tmp_fft); srslte_dft_run_c(&q->dftp_input, input, q->tmp_fft);
@ -578,6 +598,10 @@ void srslte_pss_synch_filter(srslte_pss_synch_t *q, const cf_t *input, cf_t *out
&q->tmp_fft[q->fft_size/2-SRSLTE_PSS_LEN/2], &q->tmp_fft[q->fft_size/2-SRSLTE_PSS_LEN/2],
sizeof(cf_t)*SRSLTE_PSS_LEN); sizeof(cf_t)*SRSLTE_PSS_LEN);
if (q->chest_on_filter) {
srslte_vec_prod_conj_ccc(&q->tmp_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], q->pss_signal_freq[q->N_id_2], q->tmp_ce, SRSLTE_PSS_LEN);
}
srslte_dft_run_c(&q->idftp_input, q->tmp_fft2, output); srslte_dft_run_c(&q->idftp_input, q->tmp_fft2, output);
} }
@ -586,13 +610,13 @@ void srslte_pss_synch_filter(srslte_pss_synch_t *q, const cf_t *input, cf_t *out
* Source: An Efcient CFO Estimation Algorithm for the Downlink of 3GPP-LTE * Source: An Efcient CFO Estimation Algorithm for the Downlink of 3GPP-LTE
* Feng Wang and Yu Zhu * Feng Wang and Yu Zhu
*/ */
float srslte_pss_synch_cfo_compute(srslte_pss_synch_t* q, const cf_t *pss_recv) { float srslte_pss_cfo_compute(srslte_pss_t* q, const cf_t *pss_recv) {
cf_t y0, y1; cf_t y0, y1;
const cf_t *pss_ptr = pss_recv; const cf_t *pss_ptr = pss_recv;
if (q->filter_pss_enable) { if (q->filter_pss_enable) {
srslte_pss_synch_filter(q, pss_recv, q->tmp_fft); srslte_pss_filter(q, pss_recv, q->tmp_fft);
pss_ptr = (const cf_t*) q->tmp_fft; pss_ptr = (const cf_t*) q->tmp_fft;
} }

@ -40,7 +40,7 @@ void generate_sss_all_tables(srslte_sss_tables_t *tables, uint32_t N_id_2);
void convert_tables(srslte_sss_fc_tables_t *fc_tables, srslte_sss_tables_t *in); void convert_tables(srslte_sss_fc_tables_t *fc_tables, srslte_sss_tables_t *in);
void generate_N_id_1_table(uint32_t table[30][30]); void generate_N_id_1_table(uint32_t table[30][30]);
int srslte_sss_synch_init(srslte_sss_synch_t *q, uint32_t fft_size) { int srslte_sss_init(srslte_sss_t *q, uint32_t fft_size) {
if (q != NULL && if (q != NULL &&
fft_size <= 2048) fft_size <= 2048)
@ -48,10 +48,10 @@ int srslte_sss_synch_init(srslte_sss_synch_t *q, uint32_t fft_size) {
uint32_t N_id_2; uint32_t N_id_2;
srslte_sss_tables_t sss_tables; srslte_sss_tables_t sss_tables;
bzero(q, sizeof(srslte_sss_synch_t)); bzero(q, sizeof(srslte_sss_t));
if (srslte_dft_plan(&q->dftp_input, fft_size, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) { if (srslte_dft_plan(&q->dftp_input, fft_size, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) {
srslte_sss_synch_free(q); srslte_sss_free(q);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
srslte_dft_plan_set_mirror(&q->dftp_input, true); srslte_dft_plan_set_mirror(&q->dftp_input, true);
@ -72,7 +72,7 @@ int srslte_sss_synch_init(srslte_sss_synch_t *q, uint32_t fft_size) {
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
int srslte_sss_synch_resize(srslte_sss_synch_t *q, uint32_t fft_size) { int srslte_sss_resize(srslte_sss_t *q, uint32_t fft_size) {
if (q != NULL && if (q != NULL &&
fft_size <= 2048) fft_size <= 2048)
{ {
@ -81,7 +81,7 @@ int srslte_sss_synch_resize(srslte_sss_synch_t *q, uint32_t fft_size) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (srslte_dft_replan(&q->dftp_input, fft_size)) { if (srslte_dft_replan(&q->dftp_input, fft_size)) {
srslte_sss_synch_free(q); srslte_sss_free(q);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
q->fft_size = fft_size; q->fft_size = fft_size;
@ -90,13 +90,13 @@ int srslte_sss_synch_resize(srslte_sss_synch_t *q, uint32_t fft_size) {
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
void srslte_sss_synch_free(srslte_sss_synch_t *q) { void srslte_sss_free(srslte_sss_t *q) {
srslte_dft_plan_free(&q->dftp_input); srslte_dft_plan_free(&q->dftp_input);
bzero(q, sizeof(srslte_sss_synch_t)); bzero(q, sizeof(srslte_sss_t));
} }
/** Sets the N_id_2 to search for */ /** Sets the N_id_2 to search for */
int srslte_sss_synch_set_N_id_2(srslte_sss_synch_t *q, uint32_t N_id_2) { int srslte_sss_set_N_id_2(srslte_sss_t *q, uint32_t N_id_2) {
if (!srslte_N_id_2_isvalid(N_id_2)) { if (!srslte_N_id_2_isvalid(N_id_2)) {
fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2);
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -124,12 +124,12 @@ void srslte_sss_put_slot(float *sss, cf_t *slot, uint32_t nof_prb, srslte_cp_t c
} }
/** Sets the SSS correlation peak detection threshold */ /** Sets the SSS correlation peak detection threshold */
void srslte_sss_synch_set_threshold(srslte_sss_synch_t *q, float threshold) { void srslte_sss_set_threshold(srslte_sss_t *q, float threshold) {
q->corr_peak_threshold = threshold; q->corr_peak_threshold = threshold;
} }
/** Returns the subframe index based on the m0 and m1 values */ /** Returns the subframe index based on the m0 and m1 values */
uint32_t srslte_sss_synch_subframe(uint32_t m0, uint32_t m1) { uint32_t srslte_sss_subframe(uint32_t m0, uint32_t m1) {
if (m1 > m0) { if (m1 > m0) {
return 0; return 0;
} else { } else {
@ -138,7 +138,7 @@ uint32_t srslte_sss_synch_subframe(uint32_t m0, uint32_t m1) {
} }
/** Returns the N_id_1 value based on the m0 and m1 values */ /** Returns the N_id_1 value based on the m0 and m1 values */
int srslte_sss_synch_N_id_1(srslte_sss_synch_t *q, uint32_t m0, uint32_t m1) { int srslte_sss_N_id_1(srslte_sss_t *q, uint32_t m0, uint32_t m1) {
int N_id_1 = -1; int N_id_1 = -1;
if (m1 > m0) { if (m1 > m0) {
if (m0 < 30 && m1 - 1 < 30) { if (m0 < 30 && m1 - 1 < 30) {

@ -42,6 +42,8 @@
#define DEFAULT_CFO_TOL 0.0 // Hz #define DEFAULT_CFO_TOL 0.0 // Hz
#define MAX_CFO_PSS_OFFSET 7000
static bool fft_size_isvalid(uint32_t fft_size) { static bool fft_size_isvalid(uint32_t fft_size) {
if (fft_size >= SRSLTE_SYNC_FFT_SZ_MIN && fft_size <= SRSLTE_SYNC_FFT_SZ_MAX && (fft_size%64) == 0) { if (fft_size >= SRSLTE_SYNC_FFT_SZ_MIN && fft_size <= SRSLTE_SYNC_FFT_SZ_MAX && (fft_size%64) == 0) {
return true; return true;
@ -60,7 +62,6 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && if (q != NULL &&
frame_size <= 307200 &&
fft_size_isvalid(fft_size)) fft_size_isvalid(fft_size))
{ {
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
@ -78,7 +79,6 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o
q->cfo_cp_enable = false; q->cfo_cp_enable = false;
q->cfo_i_initiated = false; q->cfo_i_initiated = false;
q->pss_filtering_enabled = false; q->pss_filtering_enabled = false;
q->sss_filtering_enabled = false;
q->fft_size = fft_size; q->fft_size = fft_size;
q->frame_size = frame_size; q->frame_size = frame_size;
@ -120,11 +120,11 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o
decimate = 1; decimate = 1;
} }
if (srslte_pss_synch_init_fft_offset_decim(&q->pss, max_offset, fft_size, 0, decimate)) { if (srslte_pss_init_fft_offset_decim(&q->pss, max_offset, fft_size, 0, decimate)) {
fprintf(stderr, "Error initializing PSS object\n"); fprintf(stderr, "Error initializing PSS object\n");
goto clean_exit; goto clean_exit;
} }
if (srslte_sss_synch_init(&q->sss, fft_size)) { if (srslte_sss_init(&q->sss, fft_size)) {
fprintf(stderr, "Error initializing SSS object\n"); fprintf(stderr, "Error initializing SSS object\n");
goto clean_exit; goto clean_exit;
} }
@ -152,8 +152,8 @@ void srslte_sync_free(srslte_sync_t *q)
{ {
if (q) { if (q) {
srslte_pss_synch_free(&q->pss); srslte_pss_free(&q->pss);
srslte_sss_synch_free(&q->sss); srslte_sss_free(&q->sss);
srslte_cfo_free(&q->cfo_corr_frame); srslte_cfo_free(&q->cfo_corr_frame);
srslte_cfo_free(&q->cfo_corr_symbol); srslte_cfo_free(&q->cfo_corr_symbol);
srslte_cp_synch_free(&q->cp_synch); srslte_cp_synch_free(&q->cp_synch);
@ -163,7 +163,7 @@ void srslte_sync_free(srslte_sync_t *q)
if (q->cfo_i_corr[i]) { if (q->cfo_i_corr[i]) {
free(q->cfo_i_corr[i]); free(q->cfo_i_corr[i]);
} }
srslte_pss_synch_free(&q->pss_i[i]); srslte_pss_free(&q->pss_i[i]);
} }
} }
if (q->temp) { if (q->temp) {
@ -189,11 +189,11 @@ int srslte_sync_resize(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offse
q->frame_size = frame_size; q->frame_size = frame_size;
q->max_offset = max_offset; q->max_offset = max_offset;
if (srslte_pss_synch_resize(&q->pss, q->max_offset, q->fft_size, 0)) { if (srslte_pss_resize(&q->pss, q->max_offset, q->fft_size, 0)) {
fprintf(stderr, "Error resizing PSS object\n"); fprintf(stderr, "Error resizing PSS object\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (srslte_sss_synch_resize(&q->sss, q->fft_size)) { if (srslte_sss_resize(&q->sss, q->fft_size)) {
fprintf(stderr, "Error resizing SSS object\n"); fprintf(stderr, "Error resizing SSS object\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -216,7 +216,7 @@ int srslte_sync_resize(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offse
if (q->cfo_i_initiated) { if (q->cfo_i_initiated) {
for (int i=0;i<2;i++) { for (int i=0;i<2;i++) {
int offset=(i==0)?-1:1; int offset=(i==0)?-1:1;
if (srslte_pss_synch_resize(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { if (srslte_pss_resize(&q->pss_i[i], q->max_offset, q->fft_size, offset)) {
fprintf(stderr, "Error initializing PSS object\n"); fprintf(stderr, "Error initializing PSS object\n");
} }
for (int t=0;t<q->frame_size;t++) { for (int t=0;t<q->frame_size;t++) {
@ -303,7 +303,7 @@ void srslte_sync_set_cfo_i_enable(srslte_sync_t *q, bool enable) {
if (q->cfo_i_enable && !q->cfo_i_initiated) { if (q->cfo_i_enable && !q->cfo_i_initiated) {
for (int i=0;i<2;i++) { for (int i=0;i<2;i++) {
int offset=(i==0)?-1:1; int offset=(i==0)?-1:1;
if (srslte_pss_synch_init_fft_offset(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { if (srslte_pss_init_fft_offset(&q->pss_i[i], q->max_offset, q->fft_size, offset)) {
fprintf(stderr, "Error initializing PSS object\n"); fprintf(stderr, "Error initializing PSS object\n");
} }
for (int t=0;t<q->frame_size;t++) { for (int t=0;t<q->frame_size;t++) {
@ -314,8 +314,12 @@ void srslte_sync_set_cfo_i_enable(srslte_sync_t *q, bool enable) {
} }
} }
void srslte_sync_set_sss_filt_enable(srslte_sync_t *q, bool enable) { void srslte_sync_set_sss_eq_enable(srslte_sync_t *q, bool enable) {
q->sss_filtering_enabled = enable; q->sss_channel_equalize = enable;
if (enable) {
q->pss_filtering_enabled = true;
q->pss.chest_on_filter = true;
}
} }
void srslte_sync_set_pss_filt_enable(srslte_sync_t *q, bool enable) { void srslte_sync_set_pss_filt_enable(srslte_sync_t *q, bool enable) {
@ -344,7 +348,7 @@ void srslte_sync_cp_en(srslte_sync_t *q, bool enabled) {
void srslte_sync_set_em_alpha(srslte_sync_t *q, float alpha) void srslte_sync_set_em_alpha(srslte_sync_t *q, float alpha)
{ {
srslte_pss_synch_set_ema_alpha(&q->pss, alpha); srslte_pss_set_ema_alpha(&q->pss, alpha);
} }
srslte_cp_t srslte_sync_get_cp(srslte_sync_t *q) srslte_cp_t srslte_sync_get_cp(srslte_sync_t *q)
@ -435,22 +439,22 @@ int sync_sss_symbol(srslte_sync_t *q, const cf_t *input)
{ {
int ret; int ret;
srslte_sss_synch_set_N_id_2(&q->sss, q->N_id_2); srslte_sss_set_N_id_2(&q->sss, q->N_id_2);
switch(q->sss_alg) { switch(q->sss_alg) {
case SSS_DIFF: case SSS_DIFF:
srslte_sss_synch_m0m1_diff(&q->sss, input, &q->m0, &q->m0_value, &q->m1, &q->m1_value); srslte_sss_m0m1_diff(&q->sss, input, &q->m0, &q->m0_value, &q->m1, &q->m1_value);
break; break;
case SSS_PARTIAL_3: case SSS_PARTIAL_3:
srslte_sss_synch_m0m1_partial(&q->sss, input, 3, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); srslte_sss_m0m1_partial(&q->sss, input, 3, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value);
break; break;
case SSS_FULL: case SSS_FULL:
srslte_sss_synch_m0m1_partial(&q->sss, input, 1, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); srslte_sss_m0m1_partial(&q->sss, input, 1, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value);
break; break;
} }
q->sf_idx = srslte_sss_synch_subframe(q->m0, q->m1); q->sf_idx = srslte_sss_subframe(q->m0, q->m1);
ret = srslte_sss_synch_N_id_1(&q->sss, q->m0, q->m1); ret = srslte_sss_N_id_1(&q->sss, q->m0, q->m1);
if (ret >= 0) { if (ret >= 0) {
q->N_id_1 = (uint32_t) ret; q->N_id_1 = (uint32_t) ret;
DEBUG("SSS detected N_id_1=%d, sf_idx=%d, %s CP\n", DEBUG("SSS detected N_id_1=%d, sf_idx=%d, %s CP\n",
@ -462,9 +466,9 @@ int sync_sss_symbol(srslte_sync_t *q, const cf_t *input)
} }
} }
srslte_pss_synch_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q) srslte_pss_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q)
{ {
srslte_pss_synch_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]}; srslte_pss_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]};
return pss_obj[q->cfo_i_value+1]; return pss_obj[q->cfo_i_value+1];
} }
@ -482,10 +486,10 @@ static int cfo_i_estimate(srslte_sync_t *q, const cf_t *input, int find_offset,
float peak_value; float peak_value;
float max_peak_value = -99; float max_peak_value = -99;
int max_cfo_i = 0; int max_cfo_i = 0;
srslte_pss_synch_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]}; srslte_pss_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]};
for (int cfo_i=0;cfo_i<3;cfo_i++) { for (int cfo_i=0;cfo_i<3;cfo_i++) {
srslte_pss_synch_set_N_id_2(pss_obj[cfo_i], q->N_id_2); srslte_pss_set_N_id_2(pss_obj[cfo_i], q->N_id_2);
int p = srslte_pss_synch_find_pss(pss_obj[cfo_i], &input[find_offset], &peak_value); int p = srslte_pss_find_pss(pss_obj[cfo_i], &input[find_offset], &peak_value);
if (p < 0) { if (p < 0) {
return -1; return -1;
} }
@ -575,8 +579,8 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin
/* Find maximum of PSS correlation. If Integer CFO is enabled, correlation is already done /* Find maximum of PSS correlation. If Integer CFO is enabled, correlation is already done
*/ */
if (!q->cfo_i_enable) { if (!q->cfo_i_enable) {
srslte_pss_synch_set_N_id_2(&q->pss, q->N_id_2); srslte_pss_set_N_id_2(&q->pss, q->N_id_2);
peak_pos = srslte_pss_synch_find_pss(&q->pss, &input_ptr[find_offset], q->threshold>0?&q->peak_value:NULL); peak_pos = srslte_pss_find_pss(&q->pss, &input_ptr[find_offset], q->threshold>0?&q->peak_value:NULL);
if (peak_pos < 0) { if (peak_pos < 0) {
fprintf(stderr, "Error calling finding PSS sequence at : %d \n", peak_pos); fprintf(stderr, "Error calling finding PSS sequence at : %d \n", peak_pos);
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -603,16 +607,16 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin
// Filter central bands before PSS-based CFO estimation // Filter central bands before PSS-based CFO estimation
const cf_t *pss_ptr = &input_ptr[find_offset + peak_pos - q->fft_size]; const cf_t *pss_ptr = &input_ptr[find_offset + peak_pos - q->fft_size];
if (q->pss_filtering_enabled) { if (q->pss_filtering_enabled) {
srslte_pss_synch_filter(&q->pss, pss_ptr, q->pss_filt); srslte_pss_filter(&q->pss, pss_ptr, q->pss_filt);
pss_ptr = q->pss_filt; pss_ptr = q->pss_filt;
} }
// PSS-based CFO estimation // PSS-based CFO estimation
float cfo_pss = srslte_pss_synch_cfo_compute(&q->pss, pss_ptr); float cfo_pss = srslte_pss_cfo_compute(&q->pss, pss_ptr);
if (!q->cfo_pss_is_set) { if (!q->cfo_pss_is_set) {
q->cfo_pss_mean = cfo_pss; q->cfo_pss_mean = cfo_pss;
q->cfo_pss_is_set = true; q->cfo_pss_is_set = true;
} else { } else if (15000*fabsf(cfo_pss) < MAX_CFO_PSS_OFFSET) {
q->cfo_pss_mean = SRSLTE_VEC_EMA(cfo_pss, q->cfo_pss_mean, q->cfo_ema_alpha); q->cfo_pss_mean = SRSLTE_VEC_EMA(cfo_pss, q->cfo_pss_mean, q->cfo_ema_alpha);
} }
@ -621,7 +625,7 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin
} }
// If there is enough space for CP and PSS-based CFO estimation // If there is enough space for CP and SSS estimation
if (peak_pos + find_offset >= 2 * (q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { if (peak_pos + find_offset >= 2 * (q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) {
// If SSS search is enabled, correlate SSS sequence // If SSS search is enabled, correlate SSS sequence
@ -638,12 +642,11 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin
// Correct CFO if detected in PSS // Correct CFO if detected in PSS
if (q->cfo_pss_enable) { if (q->cfo_pss_enable) {
srslte_cfo_correct(&q->cfo_corr_symbol, sss_ptr, q->sss_filt, -q->cfo_pss_mean / q->fft_size); srslte_cfo_correct(&q->cfo_corr_symbol, sss_ptr, q->sss_filt, -q->cfo_pss_mean / q->fft_size);
sss_ptr = q->sss_filt; // Equalize channel if estimated in PSS
if (q->sss_channel_equalize && q->pss.chest_on_filter && q->pss_filtering_enabled) {
srslte_vec_prod_ccc(&q->sss_filt[q->fft_size/2-SRSLTE_PSS_LEN/2], q->pss.tmp_ce,
&q->sss_filt[q->fft_size/2-SRSLTE_PSS_LEN/2], SRSLTE_PSS_LEN);
} }
// Filter central bands before SSS estimation
if (q->sss_filtering_enabled) {
srslte_pss_synch_filter(&q->pss, sss_ptr, q->sss_filt);
sss_ptr = q->sss_filt; sss_ptr = q->sss_filt;
} }
@ -682,5 +685,5 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin
void srslte_sync_reset(srslte_sync_t *q) { void srslte_sync_reset(srslte_sync_t *q) {
q->M_ext_avg = 0; q->M_ext_avg = 0;
q->M_norm_avg = 0; q->M_norm_avg = 0;
srslte_pss_synch_reset(&q->pss); srslte_pss_reset(&q->pss);
} }

@ -121,9 +121,9 @@ int main(int argc, char **argv) {
srslte_filesource_t fsrc; srslte_filesource_t fsrc;
cf_t *buffer; cf_t *buffer;
int frame_cnt, n; int frame_cnt, n;
srslte_pss_synch_t pss; srslte_pss_t pss;
srslte_cfo_t cfocorr, cfocorr64; srslte_cfo_t cfocorr, cfocorr64;
srslte_sss_synch_t sss; srslte_sss_t sss;
int32_t flen; int32_t flen;
int peak_idx, last_peak; int peak_idx, last_peak;
float peak_value; float peak_value;
@ -152,12 +152,12 @@ int main(int argc, char **argv) {
exit(-1); exit(-1);
} }
if (srslte_pss_synch_init_fft(&pss, flen, fft_size)) { if (srslte_pss_init_fft(&pss, flen, fft_size)) {
fprintf(stderr, "Error initiating PSS\n"); fprintf(stderr, "Error initiating PSS\n");
exit(-1); exit(-1);
} }
if (srslte_pss_synch_set_N_id_2(&pss, N_id_2_sync)) { if (srslte_pss_set_N_id_2(&pss, N_id_2_sync)) {
fprintf(stderr, "Error setting N_id_2=%d\n",N_id_2_sync); fprintf(stderr, "Error setting N_id_2=%d\n",N_id_2_sync);
exit(-1); exit(-1);
} }
@ -165,12 +165,12 @@ int main(int argc, char **argv) {
srslte_cfo_init(&cfocorr, flen); srslte_cfo_init(&cfocorr, flen);
srslte_cfo_init(&cfocorr64, flen); srslte_cfo_init(&cfocorr64, flen);
if (srslte_sss_synch_init(&sss, fft_size)) { if (srslte_sss_init(&sss, fft_size)) {
fprintf(stderr, "Error initializing SSS object\n"); fprintf(stderr, "Error initializing SSS object\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
srslte_sss_synch_set_N_id_2(&sss, N_id_2); srslte_sss_set_N_id_2(&sss, N_id_2);
printf("Opening file...\n"); printf("Opening file...\n");
if (srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) { if (srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) {
@ -210,7 +210,7 @@ int main(int argc, char **argv) {
break; break;
} }
peak_idx = srslte_pss_synch_find_pss(&pss, buffer, &peak_value); peak_idx = srslte_pss_find_pss(&pss, buffer, &peak_value);
if (peak_idx < 0) { if (peak_idx < 0) {
fprintf(stderr, "Error finding PSS peak\n"); fprintf(stderr, "Error finding PSS peak\n");
exit(-1); exit(-1);
@ -224,14 +224,14 @@ int main(int argc, char **argv) {
if (peak_idx >= fft_size) { if (peak_idx >= fft_size) {
// Estimate CFO // Estimate CFO
cfo = srslte_pss_synch_cfo_compute(&pss, &buffer[peak_idx-fft_size]); cfo = srslte_pss_cfo_compute(&pss, &buffer[peak_idx-fft_size]);
mean_cfo = SRSLTE_VEC_CMA(cfo, mean_cfo, frame_cnt); mean_cfo = SRSLTE_VEC_CMA(cfo, mean_cfo, frame_cnt);
// Correct CFO // Correct CFO
srslte_cfo_correct(&cfocorr, buffer, buffer, -mean_cfo / fft_size); srslte_cfo_correct(&cfocorr, buffer, buffer, -mean_cfo / fft_size);
// Estimate channel // Estimate channel
if (srslte_pss_synch_chest(&pss, &buffer[peak_idx-fft_size], ce)) { if (srslte_pss_chest(&pss, &buffer[peak_idx-fft_size], ce)) {
fprintf(stderr, "Error computing channel estimation\n"); fprintf(stderr, "Error computing channel estimation\n");
exit(-1); exit(-1);
} }
@ -239,22 +239,22 @@ int main(int argc, char **argv) {
// Find SSS // Find SSS
int sss_idx = peak_idx-2*fft_size-(SRSLTE_CP_ISNORM(cp)?SRSLTE_CP_LEN(fft_size, SRSLTE_CP_NORM_LEN):SRSLTE_CP_LEN(fft_size, SRSLTE_CP_EXT_LEN)); int sss_idx = peak_idx-2*fft_size-(SRSLTE_CP_ISNORM(cp)?SRSLTE_CP_LEN(fft_size, SRSLTE_CP_NORM_LEN):SRSLTE_CP_LEN(fft_size, SRSLTE_CP_EXT_LEN));
if (sss_idx >= 0 && sss_idx < flen-fft_size) { if (sss_idx >= 0 && sss_idx < flen-fft_size) {
srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value); srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value);
if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) {
sss_error2++; sss_error2++;
} }
INFO("sf_idx = %d\n", srslte_sss_synch_subframe(m0, m1)); INFO("sf_idx = %d\n", srslte_sss_subframe(m0, m1));
INFO("Partial N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); INFO("Partial N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1));
srslte_sss_synch_m0m1_diff(&sss, &buffer[sss_idx], &m0, &m0_value, &m1, &m1_value); srslte_sss_m0m1_diff(&sss, &buffer[sss_idx], &m0, &m0_value, &m1, &m1_value);
if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) {
sss_error3++; sss_error3++;
} }
INFO("Diff N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); INFO("Diff N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1));
srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value);
if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) {
sss_error1++; sss_error1++;
} }
INFO("Full N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); INFO("Full N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1));
} }
// Estimate CP // Estimate CP
@ -269,7 +269,7 @@ int main(int argc, char **argv) {
INFO("No space for CFO computation. Frame starts at \n",peak_idx); INFO("No space for CFO computation. Frame starts at \n",peak_idx);
} }
if(srslte_sss_synch_subframe(m0,m1) == 0) if(srslte_sss_subframe(m0,m1) == 0)
{ {
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
if (!disable_plots) if (!disable_plots)
@ -317,7 +317,7 @@ int main(int argc, char **argv) {
} }
srslte_pss_synch_free(&pss); srslte_pss_free(&pss);
free(buffer); free(buffer);
srslte_filesource_free(&fsrc); srslte_filesource_free(&fsrc);
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS

@ -47,7 +47,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{ {
srslte_cell_t cell; srslte_cell_t cell;
srslte_pss_synch_t pss; srslte_pss_t pss;
cf_t *input_symbols; cf_t *input_symbols;
int frame_len; int frame_len;
@ -74,17 +74,17 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
frame_len = (int) mxGetScalar(prhs[NOF_INPUTS]); frame_len = (int) mxGetScalar(prhs[NOF_INPUTS]);
} }
if (srslte_pss_synch_init_fft(&pss, frame_len, srslte_symbol_sz(cell.nof_prb))) { if (srslte_pss_init_fft(&pss, frame_len, srslte_symbol_sz(cell.nof_prb))) {
fprintf(stderr, "Error initiating PSS\n"); fprintf(stderr, "Error initiating PSS\n");
exit(-1); exit(-1);
} }
if (srslte_pss_synch_set_N_id_2(&pss, cell.id%3)) { if (srslte_pss_set_N_id_2(&pss, cell.id%3)) {
fprintf(stderr, "Error setting N_id_2=%d\n",cell.id%3); fprintf(stderr, "Error setting N_id_2=%d\n",cell.id%3);
exit(-1); exit(-1);
} }
srslte_pss_synch_set_ema_alpha(&pss, 1.0); srslte_pss_set_ema_alpha(&pss, 1.0);
int peak_idx = srslte_pss_synch_find_pss(&pss, input_symbols, NULL); int peak_idx = srslte_pss_find_pss(&pss, input_symbols, NULL);
if (nlhs >= 1) { if (nlhs >= 1) {
plhs[0] = mxCreateDoubleScalar(peak_idx); plhs[0] = mxCreateDoubleScalar(peak_idx);
@ -93,7 +93,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
mexutils_write_cf(pss.conv_output, &plhs[1], frame_len, 1); mexutils_write_cf(pss.conv_output, &plhs[1], frame_len, 1);
} }
srslte_pss_synch_free(&pss); srslte_pss_free(&pss);
free(input_symbols); free(input_symbols);
return; return;

@ -125,9 +125,9 @@ int main(int argc, char **argv) {
cf_t *buffer; cf_t *buffer;
int frame_cnt, n; int frame_cnt, n;
srslte_rf_t rf; srslte_rf_t rf;
srslte_pss_synch_t pss; srslte_pss_t pss;
srslte_cfo_t cfocorr, cfocorr64; srslte_cfo_t cfocorr, cfocorr64;
srslte_sss_synch_t sss; srslte_sss_t sss;
int32_t flen; int32_t flen;
int peak_idx, last_peak; int peak_idx, last_peak;
float peak_value; float peak_value;
@ -176,12 +176,12 @@ int main(int argc, char **argv) {
exit(-1); exit(-1);
} }
if (srslte_pss_synch_init_fft(&pss, flen, fft_size)) { if (srslte_pss_init_fft(&pss, flen, fft_size)) {
fprintf(stderr, "Error initiating PSS\n"); fprintf(stderr, "Error initiating PSS\n");
exit(-1); exit(-1);
} }
if (srslte_pss_synch_set_N_id_2(&pss, N_id_2_sync)) { if (srslte_pss_set_N_id_2(&pss, N_id_2_sync)) {
fprintf(stderr, "Error setting N_id_2=%d\n",N_id_2_sync); fprintf(stderr, "Error setting N_id_2=%d\n",N_id_2_sync);
exit(-1); exit(-1);
} }
@ -189,16 +189,16 @@ int main(int argc, char **argv) {
srslte_cfo_init(&cfocorr, flen); srslte_cfo_init(&cfocorr, flen);
srslte_cfo_init(&cfocorr64, flen); srslte_cfo_init(&cfocorr64, flen);
if (srslte_sss_synch_init(&sss, fft_size)) { if (srslte_sss_init(&sss, fft_size)) {
fprintf(stderr, "Error initializing SSS object\n"); fprintf(stderr, "Error initializing SSS object\n");
exit(-1); exit(-1);
} }
srslte_sss_synch_set_N_id_2(&sss, N_id_2); srslte_sss_set_N_id_2(&sss, N_id_2);
printf("N_id_2: %d\n", N_id_2); printf("N_id_2: %d\n", N_id_2);
srslte_rf_start_rx_stream(&rf); srslte_rf_start_rx_stream(&rf, false);
printf("Frame length %d samples\n", flen); printf("Frame length %d samples\n", flen);
printf("PSS detection threshold: %.2f\n", threshold); printf("PSS detection threshold: %.2f\n", threshold);
@ -232,7 +232,7 @@ int main(int argc, char **argv) {
exit(-1); exit(-1);
} }
peak_idx = srslte_pss_synch_find_pss(&pss, buffer, &peak_value); peak_idx = srslte_pss_find_pss(&pss, buffer, &peak_value);
if (peak_idx < 0) { if (peak_idx < 0) {
fprintf(stderr, "Error finding PSS peak\n"); fprintf(stderr, "Error finding PSS peak\n");
exit(-1); exit(-1);
@ -246,14 +246,14 @@ int main(int argc, char **argv) {
if (peak_idx >= fft_size) { if (peak_idx >= fft_size) {
// Estimate CFO // Estimate CFO
cfo = srslte_pss_synch_cfo_compute(&pss, &buffer[peak_idx-fft_size]); cfo = srslte_pss_cfo_compute(&pss, &buffer[peak_idx-fft_size]);
mean_cfo = SRSLTE_VEC_CMA(cfo, mean_cfo, frame_cnt); mean_cfo = SRSLTE_VEC_CMA(cfo, mean_cfo, frame_cnt);
// Correct CFO // Correct CFO
srslte_cfo_correct(&cfocorr, buffer, buffer, -mean_cfo / fft_size); srslte_cfo_correct(&cfocorr, buffer, buffer, -mean_cfo / fft_size);
// Estimate channel // Estimate channel
if (srslte_pss_synch_chest(&pss, &buffer[peak_idx-fft_size], ce)) { if (srslte_pss_chest(&pss, &buffer[peak_idx-fft_size], ce)) {
fprintf(stderr, "Error computing channel estimation\n"); fprintf(stderr, "Error computing channel estimation\n");
exit(-1); exit(-1);
} }
@ -263,22 +263,22 @@ int main(int argc, char **argv) {
if (sss_idx >= 0 && sss_idx < flen-fft_size) { if (sss_idx >= 0 && sss_idx < flen-fft_size) {
// Filter SSS // Filter SSS
srslte_pss_synch_filter(&pss, &buffer[sss_idx], &buffer[sss_idx]); srslte_pss_filter(&pss, &buffer[sss_idx], &buffer[sss_idx]);
INFO("Full N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); INFO("Full N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1));
srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, ce, &m0, &m0_value, &m1, &m1_value); srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 1, ce, &m0, &m0_value, &m1, &m1_value);
if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) {
sss_error2++; sss_error2++;
} }
INFO("Partial N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); INFO("Partial N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1));
srslte_sss_synch_m0m1_diff_coh(&sss, &buffer[sss_idx], ce, &m0, &m0_value, &m1, &m1_value); srslte_sss_m0m1_diff_coh(&sss, &buffer[sss_idx], ce, &m0, &m0_value, &m1, &m1_value);
if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) {
sss_error3++; sss_error3++;
} }
INFO("Diff N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); INFO("Diff N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1));
} }
srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value);
if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) {
sss_error1++; sss_error1++;
} }
@ -294,7 +294,7 @@ int main(int argc, char **argv) {
INFO("No space for CFO computation. Frame starts at \n",peak_idx); INFO("No space for CFO computation. Frame starts at \n",peak_idx);
} }
if(srslte_sss_synch_subframe(m0,m1) == 0) if(srslte_sss_subframe(m0,m1) == 0)
{ {
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
if (!disable_plots) if (!disable_plots)
@ -358,8 +358,8 @@ int main(int argc, char **argv) {
} }
srslte_sss_synch_free(&sss); srslte_sss_free(&sss);
srslte_pss_synch_free(&pss); srslte_pss_free(&pss);
free(buffer); free(buffer);
srslte_rf_close(&rf); srslte_rf_close(&rf);

@ -50,7 +50,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{ {
srslte_cell_t cell; srslte_cell_t cell;
srslte_sss_synch_t sss; srslte_sss_t sss;
cf_t *input_symbols; cf_t *input_symbols;
int frame_len; int frame_len;
uint32_t m0, m1; uint32_t m0, m1;
@ -80,12 +80,12 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
return; return;
} }
if (srslte_sss_synch_init(&sss, srslte_symbol_sz(cell.nof_prb))) { if (srslte_sss_init(&sss, srslte_symbol_sz(cell.nof_prb))) {
mexErrMsgTxt("Error initializing SSS object\n"); mexErrMsgTxt("Error initializing SSS object\n");
return; return;
} }
srslte_sss_synch_set_N_id_2(&sss, cell.id%3); srslte_sss_set_N_id_2(&sss, cell.id%3);
// Find SSS // Find SSS
uint32_t sss_idx = SRSLTE_SLOT_IDX_CPNORM(5,srslte_symbol_sz(cell.nof_prb)); uint32_t sss_idx = SRSLTE_SLOT_IDX_CPNORM(5,srslte_symbol_sz(cell.nof_prb));
@ -95,23 +95,23 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
} }
//mexPrintf("SSS begins at %d/%d. Running algorithm %s\n", sss_idx, frame_len, alg); //mexPrintf("SSS begins at %d/%d. Running algorithm %s\n", sss_idx, frame_len, alg);
if (!strcmp(alg, "partial")) { if (!strcmp(alg, "partial")) {
srslte_sss_synch_m0m1_partial(&sss, &input_symbols[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value); srslte_sss_m0m1_partial(&sss, &input_symbols[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value);
} else if (!strcmp(alg, "diff")) { } else if (!strcmp(alg, "diff")) {
srslte_sss_synch_m0m1_diff(&sss, &input_symbols[sss_idx], &m0, &m0_value, &m1, &m1_value); srslte_sss_m0m1_diff(&sss, &input_symbols[sss_idx], &m0, &m0_value, &m1, &m1_value);
} else if (!strcmp(alg, "full")) { } else if (!strcmp(alg, "full")) {
srslte_sss_synch_m0m1_partial(&sss, &input_symbols[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); srslte_sss_m0m1_partial(&sss, &input_symbols[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value);
} else { } else {
mexErrMsgTxt("Unsupported algorithm type\n"); mexErrMsgTxt("Unsupported algorithm type\n");
return; return;
} }
//mexPrintf("m0: %d, m1: %d, N_id_1: %d\n", m0, m1, srslte_sss_synch_N_id_1(&sss, m0, m1)); //mexPrintf("m0: %d, m1: %d, N_id_1: %d\n", m0, m1, srslte_sss_N_id_1(&sss, m0, m1));
if (nlhs >= 1) { if (nlhs >= 1) {
plhs[0] = mxCreateDoubleScalar(srslte_sss_synch_N_id_1(&sss, m0, m1)); plhs[0] = mxCreateDoubleScalar(srslte_sss_N_id_1(&sss, m0, m1));
} }
if (nlhs >= 2) { if (nlhs >= 2) {
plhs[1] = mxCreateDoubleScalar(srslte_sss_synch_subframe(m0, m1)); plhs[1] = mxCreateDoubleScalar(srslte_sss_subframe(m0, m1));
} }
if (nlhs >= 3) { if (nlhs >= 3) {
mexutils_write_f(sss.corr_output_m0, &plhs[2], SRSLTE_SSS_N, 1); mexutils_write_f(sss.corr_output_m0, &plhs[2], SRSLTE_SSS_N, 1);
@ -119,7 +119,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
if (nlhs >= 4) { if (nlhs >= 4) {
mexutils_write_f(sss.corr_output_m1, &plhs[3], SRSLTE_SSS_N, 1); mexutils_write_f(sss.corr_output_m1, &plhs[3], SRSLTE_SSS_N, 1);
} }
srslte_sss_synch_free(&sss); srslte_sss_free(&sss);
free(input_symbols); free(input_symbols);
return; return;

@ -257,7 +257,7 @@ int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, srslte_cell_t cell)
} }
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} else { } else {
fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", fprintf(stderr, "Invalid cell properties ue_dl: Id=%d, Ports=%d, PRBs=%d\n",
cell.id, cell.nof_ports, cell.nof_prb); cell.id, cell.nof_ports, cell.nof_prb);
} }
return ret; return ret;
@ -359,20 +359,20 @@ void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) {
* - PDCCH decoding: Find DCI for RNTI given by previous call to srslte_ue_dl_set_rnti() * - PDCCH decoding: Find DCI for RNTI given by previous call to srslte_ue_dl_set_rnti()
* - PDSCH decoding: Decode TB scrambling with RNTI given by srslte_ue_dl_set_rnti() * - PDSCH decoding: Decode TB scrambling with RNTI given by srslte_ue_dl_set_rnti()
*/ */
int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], int srslte_ue_dl_decode(srslte_ue_dl_t *q, uint8_t *data[SRSLTE_MAX_CODEWORDS],
uint32_t tm, uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]) { uint32_t tm, uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]) {
return srslte_ue_dl_decode_rnti(q, input, data, tm, tti, q->current_rnti, acks); return srslte_ue_dl_decode_rnti(q, data, tm, tti, q->current_rnti, acks);
} }
int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi){ int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi){
return srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, cfi, SRSLTE_SF_NORM); return srslte_ue_dl_decode_fft_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM);
} }
int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type) int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type)
{ {
if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { if (q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) {
/* Run FFT for all subframe data */ /* Run FFT for all subframe data */
for (int j=0;j<q->nof_rx_antennas;j++) { for (int j=0;j<q->nof_rx_antennas;j++) {
@ -398,6 +398,32 @@ int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, cf_t *input[SRSLTE
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
} }
int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi)
{
if (input && q && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) {
/* Run FFT for all subframe data */
for (int j=0;j<q->nof_rx_antennas;j++) {
srslte_ofdm_rx_sf_ng(&q->fft[j], input[j], q->sf_symbols_m[j]);
/* Correct SFO multiplying by complex exponential in the time domain */
if (q->sample_offset) {
int nsym = SRSLTE_CP_NSYMB(q->cell.cp);
for (int i=0;i<2*nsym;i++) {
srslte_cfo_correct(&q->sfo_correct,
&q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE],
&q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE],
q->sample_offset / q->fft[j].symbol_sz);
}
}
}
return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM);
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi) { int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi) {
return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM); return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM);
@ -468,7 +494,7 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3
} }
} }
int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q,
uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, uint16_t rnti, uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, uint16_t rnti,
bool acks[SRSLTE_MAX_CODEWORDS]) { bool acks[SRSLTE_MAX_CODEWORDS]) {
srslte_mimo_type_t mimo_type; srslte_mimo_type_t mimo_type;
@ -479,7 +505,7 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS],
uint32_t cfi; uint32_t cfi;
uint32_t sf_idx = tti%10; uint32_t sf_idx = tti%10;
if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, &cfi, SRSLTE_SF_NORM)) < 0) { if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, sf_idx, &cfi, SRSLTE_SF_NORM)) < 0) {
return ret; return ret;
} }
@ -621,7 +647,6 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS],
int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q, int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q,
cf_t *input[SRSLTE_MAX_PORTS],
uint8_t *data, uint8_t *data,
uint32_t tti) uint32_t tti)
{ {
@ -630,7 +655,7 @@ int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q,
uint32_t cfi; uint32_t cfi;
uint32_t sf_idx = tti%10; uint32_t sf_idx = tti%10;
if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, &cfi, SRSLTE_SF_MBSFN)) < 0) { if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, sf_idx, &cfi, SRSLTE_SF_MBSFN)) < 0) {
return ret; return ret;
} }
@ -700,7 +725,8 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo
/* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */ /* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */
for (uint32_t nof_layers = 1; nof_layers <= SRSLTE_MAX_LAYERS; nof_layers++) { for (uint32_t nof_layers = 1; nof_layers <= SRSLTE_MAX_LAYERS; nof_layers++) {
float _sinr = q->sinr[nof_layers - 1][q->pmi[nof_layers - 1]] * nof_layers * nof_layers; float _sinr = q->sinr[nof_layers - 1][q->pmi[nof_layers - 1]] * nof_layers * nof_layers;
if (_sinr > best_sinr + 0.1) { /* Find best SINR, force maximum number of layers if SNR is higher than 30 dB */
if (_sinr > best_sinr + 0.1 || _sinr > 1.0e+3) {
best_sinr = _sinr; best_sinr = _sinr;
best_pmi = (uint8_t) q->pmi[nof_layers - 1]; best_pmi = (uint8_t) q->pmi[nof_layers - 1];
best_ri = (uint8_t) (nof_layers - 1); best_ri = (uint8_t) (nof_layers - 1);
@ -715,6 +741,7 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo
} }
/* Set RI */ /* Set RI */
q->ri = best_ri;
if (ri != NULL) { if (ri != NULL) {
*ri = best_ri; *ri = best_ri;
} }
@ -750,9 +777,10 @@ int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, uint8_t *ri, float *cn) {
*cn = _cn; *cn = _cn;
} }
q->ri = (uint8_t)((_cn < 17.0f)? 1:0);
/* Set rank indicator */ /* Set rank indicator */
if (!ret && ri) { if (!ret && ri) {
*ri = (uint8_t)((_cn < 17.0f)? 1:0); *ri = (uint8_t) q->ri;
} }
return ret; return ret;

@ -272,14 +272,14 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q,
srslte_sync_set_cfo_cp_enable(&q->sfind, true); srslte_sync_set_cfo_cp_enable(&q->sfind, true);
srslte_sync_set_cfo_pss_enable(&q->sfind, true); srslte_sync_set_cfo_pss_enable(&q->sfind, true);
srslte_sync_set_pss_filt_enable(&q->sfind, true); srslte_sync_set_pss_filt_enable(&q->sfind, true);
srslte_sync_set_sss_filt_enable(&q->sfind, true); srslte_sync_set_sss_eq_enable(&q->sfind, true);
// During track, we do CFO correction outside the sync object // During track, we do CFO correction outside the sync object
srslte_sync_set_cfo_i_enable(&q->strack, false); srslte_sync_set_cfo_i_enable(&q->strack, false);
srslte_sync_set_cfo_cp_enable(&q->strack, false); srslte_sync_set_cfo_cp_enable(&q->strack, false);
srslte_sync_set_cfo_pss_enable(&q->strack, true); srslte_sync_set_cfo_pss_enable(&q->strack, true);
srslte_sync_set_pss_filt_enable(&q->strack, true); srslte_sync_set_pss_filt_enable(&q->strack, true);
srslte_sync_set_sss_filt_enable(&q->strack, false); srslte_sync_set_sss_eq_enable(&q->strack, false);
// FIXME: CP detection not working very well. Not supporting Extended CP right now // FIXME: CP detection not working very well. Not supporting Extended CP right now
srslte_sync_cp_en(&q->strack, false); srslte_sync_cp_en(&q->strack, false);

@ -178,7 +178,7 @@ int srslte_ue_ul_set_cell(srslte_ue_ul_t *q,
} }
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} else { } else {
fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", fprintf(stderr, "Invalid cell properties ue_ul: Id=%d, Ports=%d, PRBs=%d\n",
cell.id, cell.nof_ports, cell.nof_prb); cell.id, cell.nof_ports, cell.nof_prb);
} }
return ret; return ret;
@ -274,20 +274,32 @@ void pucch_encode_bits(srslte_uci_data_t *uci_data, srslte_pucch_format_t format
uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS], uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS],
uint8_t pucch2_bits[SRSLTE_PUCCH_MAX_BITS]) uint8_t pucch2_bits[SRSLTE_PUCCH_MAX_BITS])
{ {
uint8_t uci_buffer[SRSLTE_CQI_MAX_BITS];
uint8_t uci_buffer_len = 0;
if (format == SRSLTE_PUCCH_FORMAT_1A || format == SRSLTE_PUCCH_FORMAT_1B) { if (format == SRSLTE_PUCCH_FORMAT_1A || format == SRSLTE_PUCCH_FORMAT_1B) {
pucch_bits[0] = uci_data->uci_ack; pucch_bits[0] = uci_data->uci_ack;
pucch_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 1a pucch_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 1a
} }
if (format >= SRSLTE_PUCCH_FORMAT_2) { if (format >= SRSLTE_PUCCH_FORMAT_2) {
/* Put RI (goes alone) */
if (uci_data->ri_periodic_report) {
uci_buffer[0] = uci_data->uci_ri; // It assumes only 1 bit of RI
uci_buffer_len += uci_data->uci_ri_len;
} else {
/* Append CQI */
memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_cqi, uci_data->uci_cqi_len);
uci_buffer_len += uci_data->uci_cqi_len;
/* Append Differential CQI */ /* Append Differential CQI */
memcpy(&uci_data->uci_cqi[uci_data->uci_cqi_len], uci_data->uci_dif_cqi, uci_data->uci_dif_cqi_len); memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_dif_cqi, uci_data->uci_dif_cqi_len);
uci_data->uci_cqi_len += uci_data->uci_dif_cqi_len; uci_buffer_len += uci_data->uci_dif_cqi_len;
/* Append PMI */ /* Append PMI */
memcpy(&uci_data->uci_cqi[uci_data->uci_cqi_len], uci_data->uci_pmi, uci_data->uci_pmi_len); memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_pmi, uci_data->uci_pmi_len);
uci_data->uci_cqi_len += uci_data->uci_pmi_len; uci_buffer_len += uci_data->uci_pmi_len;
}
srslte_uci_encode_cqi_pucch(uci_data->uci_cqi, uci_data->uci_cqi_len, pucch_bits); srslte_uci_encode_cqi_pucch(uci_buffer, uci_buffer_len, pucch_bits);
if (format > SRSLTE_PUCCH_FORMAT_2) { if (format > SRSLTE_PUCCH_FORMAT_2) {
pucch2_bits[0] = uci_data->uci_ack; pucch2_bits[0] = uci_data->uci_ack;
pucch2_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 2a pucch2_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 2a

@ -11,10 +11,9 @@ int srslte_ringbuffer_init(srslte_ringbuffer_t *q, int capacity)
if (!q->buffer) { if (!q->buffer) {
return -1; return -1;
} }
q->capacity = capacity; q->capacity = capacity;
q->count = 0; srslte_ringbuffer_reset(q);
q->wpm = 0;
q->rpm = 0;
pthread_mutex_init(&q->mutex, NULL); pthread_mutex_init(&q->mutex, NULL);
pthread_cond_init(&q->cvar, NULL); pthread_cond_init(&q->cvar, NULL);
@ -22,7 +21,7 @@ int srslte_ringbuffer_init(srslte_ringbuffer_t *q, int capacity)
return 0; return 0;
} }
void srslte_ringbuffer_free(srslte_ringbuffer_t *q, int capacity) void srslte_ringbuffer_free(srslte_ringbuffer_t *q)
{ {
if (q) { if (q) {
if (q->buffer) { if (q->buffer) {
@ -34,11 +33,26 @@ void srslte_ringbuffer_free(srslte_ringbuffer_t *q, int capacity)
} }
} }
int srslte_ringbuffer_write(srslte_ringbuffer_t *q, uint8_t *ptr, int nof_bytes) void srslte_ringbuffer_reset(srslte_ringbuffer_t *q)
{
pthread_mutex_lock(&q->mutex);
q->count = 0;
q->wpm = 0;
q->rpm = 0;
pthread_mutex_unlock(&q->mutex);
}
int srslte_ringbuffer_status(srslte_ringbuffer_t *q)
{
return q->count;
}
int srslte_ringbuffer_write(srslte_ringbuffer_t *q, void *p, int nof_bytes)
{ {
uint8_t *ptr = (uint8_t*) p;
int w_bytes = nof_bytes; int w_bytes = nof_bytes;
pthread_mutex_lock(&q->mutex); pthread_mutex_lock(&q->mutex);
if (q->count + w_bytes >= q->capacity) { if (q->count + w_bytes > q->capacity) {
w_bytes = q->capacity - q->count; w_bytes = q->capacity - q->count;
fprintf(stderr, "Buffer overrun: lost %d bytes\n", nof_bytes - w_bytes); fprintf(stderr, "Buffer overrun: lost %d bytes\n", nof_bytes - w_bytes);
} }
@ -59,8 +73,9 @@ int srslte_ringbuffer_write(srslte_ringbuffer_t *q, uint8_t *ptr, int nof_bytes)
return w_bytes; return w_bytes;
} }
int srslte_ringbuffer_read(srslte_ringbuffer_t *q, uint8_t *ptr, int nof_bytes) int srslte_ringbuffer_read(srslte_ringbuffer_t *q, void *p, int nof_bytes)
{ {
uint8_t *ptr = (uint8_t*) p;
pthread_mutex_lock(&q->mutex); pthread_mutex_lock(&q->mutex);
while(q->count < nof_bytes) { while(q->count < nof_bytes) {
pthread_cond_wait(&q->cvar, &q->mutex); pthread_cond_wait(&q->cvar, &q->mutex);

@ -34,9 +34,9 @@ extern "C" {
namespace srslte { namespace srslte {
bool radio::init(char *args, char *devname) bool radio::init(char *args, char *devname, uint32_t nof_channels)
{ {
if (srslte_rf_open_devname(&rf_device, devname, args)) { if (srslte_rf_open_devname(&rf_device, devname, args, nof_channels)) {
fprintf(stderr, "Error opening RF device\n"); fprintf(stderr, "Error opening RF device\n");
return false; return false;
} }
@ -69,6 +69,7 @@ bool radio::init(char *args, char *devname)
if (devname) { if (devname) {
strncpy(saved_devname, devname, 127); strncpy(saved_devname, devname, 127);
} }
saved_nof_channels = nof_channels;
return true; return true;
} }
@ -83,7 +84,7 @@ void radio::reset()
printf("Resetting Radio...\n"); printf("Resetting Radio...\n");
srslte_rf_close(&rf_device); srslte_rf_close(&rf_device);
sleep(3); sleep(3);
if (srslte_rf_open_devname(&rf_device, saved_devname, saved_args)) { if (srslte_rf_open_devname(&rf_device, saved_devname, saved_args, saved_nof_channels)) {
fprintf(stderr, "Error opening RF device\n"); fprintf(stderr, "Error opening RF device\n");
} }
} }
@ -138,9 +139,9 @@ bool radio::rx_at(void* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time
return false; return false;
} }
bool radio::rx_now(void* buffer, uint32_t nof_samples, srslte_timestamp_t* rxd_time) bool radio::rx_now(void* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time)
{ {
if (srslte_rf_recv_with_time(&rf_device, buffer, nof_samples, true, if (srslte_rf_recv_with_time_multi(&rf_device, buffer, nof_samples, true,
rxd_time?&rxd_time->full_secs:NULL, rxd_time?&rxd_time->frac_secs:NULL) > 0) { rxd_time?&rxd_time->full_secs:NULL, rxd_time?&rxd_time->frac_secs:NULL) > 0) {
return true; return true;
} else { } else {
@ -187,10 +188,18 @@ bool radio::is_first_of_burst() {
#define BLOCKING_TX true #define BLOCKING_TX true
bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) bool radio::tx_single(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) {
{ void *_buffer[SRSLTE_MAX_PORTS];
void *iq_samples[4] = {(void *) zeros, (void *) zeros, (void *) zeros, (void *) zeros};
_buffer[0] = buffer;
for (int p = 1; p < SRSLTE_MAX_PORTS; p++) {
_buffer[p] = zeros;
}
return this->tx(_buffer, nof_samples, tx_time);
}
bool radio::tx(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time) {
if (!tx_adv_negative) { if (!tx_adv_negative) {
srslte_timestamp_sub(&tx_time, 0, tx_adv_sec); srslte_timestamp_sub(&tx_time, 0, tx_adv_sec);
} else { } else {
@ -203,7 +212,7 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time)
srslte_timestamp_copy(&tx_time_pad, &tx_time); srslte_timestamp_copy(&tx_time_pad, &tx_time);
srslte_timestamp_sub(&tx_time_pad, 0, burst_preamble_time_rounded); srslte_timestamp_sub(&tx_time_pad, 0, burst_preamble_time_rounded);
save_trace(1, &tx_time_pad); save_trace(1, &tx_time_pad);
srslte_rf_send_timed_multi(&rf_device, iq_samples, burst_preamble_samples, tx_time_pad.full_secs, tx_time_pad.frac_secs, true, true, false); srslte_rf_send_timed_multi(&rf_device, buffer, burst_preamble_samples, tx_time_pad.full_secs, tx_time_pad.frac_secs, true, true, false);
is_start_of_burst = false; is_start_of_burst = false;
} }
} }
@ -213,8 +222,7 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time)
srslte_timestamp_add(&end_of_burst_time, 0, (double) nof_samples/cur_tx_srate); srslte_timestamp_add(&end_of_burst_time, 0, (double) nof_samples/cur_tx_srate);
save_trace(0, &tx_time); save_trace(0, &tx_time);
iq_samples[0] = buffer; int ret = srslte_rf_send_timed_multi(&rf_device, buffer, nof_samples,
int ret = srslte_rf_send_timed_multi(&rf_device, (void**) iq_samples, nof_samples,
tx_time.full_secs, tx_time.frac_secs, tx_time.full_secs, tx_time.frac_secs,
BLOCKING_TX, is_start_of_burst, false); BLOCKING_TX, is_start_of_burst, false);
is_start_of_burst = false; is_start_of_burst = false;
@ -433,9 +441,9 @@ void radio::set_tx_srate(double srate)
tx_adv_sec = nsamples/cur_tx_srate; tx_adv_sec = nsamples/cur_tx_srate;
} }
void radio::start_rx() void radio::start_rx(bool now)
{ {
srslte_rf_start_rx_stream(&rf_device); srslte_rf_start_rx_stream(&rf_device, now);
} }
void radio::stop_rx() void radio::stop_rx()

@ -4,7 +4,7 @@ namespace srslte {
bool radio_multi::init_multi(uint32_t nof_rx_antennas, char* args, char* devname) bool radio_multi::init_multi(uint32_t nof_rx_antennas, char* args, char* devname)
{ {
if (srslte_rf_open_devname_multi(&rf_device, devname, args, nof_rx_antennas)) { if (srslte_rf_open_devname(&rf_device, devname, args, nof_rx_antennas)) {
fprintf(stderr, "Error opening RF device\n"); fprintf(stderr, "Error opening RF device\n");
return false; return false;
} }

@ -51,7 +51,19 @@ void pdcp::init(srsue::rlc_interface_pdcp *rlc_, srsue::rrc_interface_pdcp *rrc_
} }
void pdcp::stop() void pdcp::stop()
{} {
for(uint32_t i=0;i<SRSLTE_N_RADIO_BEARERS;i++) {
pdcp_array[i].stop();
}
}
void pdcp::reestablish() {
for(uint32_t i=0;i<SRSLTE_N_RADIO_BEARERS;i++) {
if (pdcp_array[i].is_active()) {
pdcp_array[i].reestablish();
}
}
}
void pdcp::reset() void pdcp::reset()
{ {
@ -88,20 +100,44 @@ void pdcp::add_bearer(uint32_t lcid, srslte_pdcp_config_t cfg)
} }
if (!pdcp_array[lcid].is_active()) { if (!pdcp_array[lcid].is_active()) {
pdcp_array[lcid].init(rlc, rrc, gw, pdcp_log, lcid, cfg); pdcp_array[lcid].init(rlc, rrc, gw, pdcp_log, lcid, cfg);
pdcp_log->info("Added bearer %s\n", rrc->get_rb_name(lcid).c_str()); pdcp_log->info("Added bearer %s\n", get_rb_name(lcid));
} else { } else {
pdcp_log->warning("Bearer %s already configured. Reconfiguration not supported\n", rrc->get_rb_name(lcid).c_str()); pdcp_log->warning("Bearer %s already configured. Reconfiguration not supported\n", get_rb_name(lcid));
} }
} }
void pdcp::config_security(uint32_t lcid, void pdcp::config_security(uint32_t lcid,
uint8_t *k_rrc_enc, uint8_t *k_enc,
uint8_t *k_rrc_int, uint8_t *k_int,
CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo)
{
if(valid_lcid(lcid))
pdcp_array[lcid].config_security(k_enc, k_int, cipher_algo, integ_algo);
}
void pdcp::config_security_all(uint8_t *k_enc,
uint8_t *k_int,
CIPHERING_ALGORITHM_ID_ENUM cipher_algo, CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo) INTEGRITY_ALGORITHM_ID_ENUM integ_algo)
{
for(uint32_t i=0;i<SRSLTE_N_RADIO_BEARERS;i++) {
if (pdcp_array[i].is_active()) {
pdcp_array[i].config_security(k_enc, k_int, cipher_algo, integ_algo);
}
}
}
void pdcp::enable_integrity(uint32_t lcid)
{
if(valid_lcid(lcid))
pdcp_array[lcid].enable_integrity();
}
void pdcp::enable_encryption(uint32_t lcid)
{ {
if(valid_lcid(lcid)) if(valid_lcid(lcid))
pdcp_array[lcid].config_security(k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); pdcp_array[lcid].enable_encryption();
} }
/******************************************************************************* /*******************************************************************************

@ -33,7 +33,6 @@ namespace srslte {
pdcp_entity::pdcp_entity() pdcp_entity::pdcp_entity()
:active(false) :active(false)
,tx_count(0) ,tx_count(0)
,rx_count(0)
{ {
pool = byte_buffer_pool::get_instance(); pool = byte_buffer_pool::get_instance();
} }
@ -52,18 +51,50 @@ void pdcp_entity::init(srsue::rlc_interface_pdcp *rlc_,
lcid = lcid_; lcid = lcid_;
cfg = cfg_; cfg = cfg_;
active = true; active = true;
tx_count = 0; tx_count = 0;
rx_count = 0; rx_count = 0;
do_integrity = false;
do_encryption = false;
if(cfg.is_control) {
cfg.sn_len = 5;
sn_len_bytes = 1;
} else {
sn_len_bytes = (cfg.sn_len+7)/8;
}
start(PDCP_THREAD_PRIO);
log->debug("Init %s\n", get_rb_name(lcid));
}
void pdcp_entity::stop()
{
if(running) {
running = false;
thread_cancel();
wait_thread_finish();
}
}
log->debug("Init %s\n", rrc->get_rb_name(lcid).c_str()); // Reestablishment procedure: 36.323 5.2
void pdcp_entity::reestablish() {
// For SRBs
if (cfg.is_control) {
tx_count = 0;
rx_count = 0;
} else {
if (rlc->rb_is_um(lcid)) {
tx_count = 0;
rx_count = 0;
}
}
} }
void pdcp_entity::reset() void pdcp_entity::reset()
{ {
active = false; active = false;
if(log) if(log)
log->debug("Reset %s\n", rrc->get_rb_name(lcid).c_str()); log->debug("Reset %s\n", get_rb_name(lcid));
} }
bool pdcp_entity::is_active() bool pdcp_entity::is_active()
@ -74,116 +105,309 @@ bool pdcp_entity::is_active()
// RRC interface // RRC interface
void pdcp_entity::write_sdu(byte_buffer_t *sdu) void pdcp_entity::write_sdu(byte_buffer_t *sdu)
{ {
log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU, do_security = %s", rrc->get_rb_name(lcid).c_str(), (cfg.do_security)?"true":"false"); log->info_hex(sdu->msg, sdu->N_bytes,
"TX %s SDU, SN: %d, do_integrity = %s, do_encryption = %s",
get_rb_name(lcid), tx_count,
(do_integrity) ? "true" : "false", (do_encryption) ? "true" : "false");
if (cfg.is_control) { if (cfg.is_control) {
pdcp_pack_control_pdu(tx_count, sdu); pdcp_pack_control_pdu(tx_count, sdu);
if(cfg.do_security) if(do_integrity) {
{ integrity_generate(sdu->msg,
integrity_generate(&k_rrc_int[16],
tx_count,
lcid-1,
cfg.direction,
sdu->msg,
sdu->N_bytes-4, sdu->N_bytes-4,
&sdu->msg[sdu->N_bytes-4]); &sdu->msg[sdu->N_bytes-4]);
} }
tx_count++;
} }
if (cfg.is_data) { if (cfg.is_data) {
if(12 == cfg.sn_len) { if(12 == cfg.sn_len) {
pdcp_pack_data_pdu_long_sn(tx_count++, sdu); pdcp_pack_data_pdu_long_sn(tx_count, sdu);
} else { } else {
pdcp_pack_data_pdu_short_sn(tx_count++, sdu); pdcp_pack_data_pdu_short_sn(tx_count, sdu);
} }
} }
if(do_encryption) {
cipher_encrypt(&sdu->msg[sn_len_bytes],
sdu->N_bytes-sn_len_bytes,
&sdu->msg[sn_len_bytes]);
log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU (encrypted)", get_rb_name(lcid));
}
tx_count++;
rlc->write_sdu(lcid, sdu); rlc->write_sdu(lcid, sdu);
} }
void pdcp_entity::config_security(uint8_t *k_rrc_enc_, void pdcp_entity::config_security(uint8_t *k_enc_,
uint8_t *k_rrc_int_, uint8_t *k_int_,
CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) INTEGRITY_ALGORITHM_ID_ENUM integ_algo_)
{ {
cfg.do_security = true;
for(int i=0; i<32; i++) for(int i=0; i<32; i++)
{ {
k_rrc_enc[i] = k_rrc_enc_[i]; k_enc[i] = k_enc_[i];
k_rrc_int[i] = k_rrc_int_[i]; k_int[i] = k_int_[i];
} }
cipher_algo = cipher_algo_; cipher_algo = cipher_algo_;
integ_algo = integ_algo_; integ_algo = integ_algo_;
} }
// RLC interface void pdcp_entity::enable_integrity()
void pdcp_entity::write_pdu(byte_buffer_t *pdu)
{ {
do_integrity = true;
}
void pdcp_entity::enable_encryption()
{
do_encryption = true;
}
// RLC interface
void pdcp_entity::write_pdu(byte_buffer_t *pdu)
{
rx_pdu_queue.write(pdu);
}
void pdcp_entity::integrity_generate( uint8_t *msg,
uint32_t msg_len,
uint8_t *mac)
{
uint8_t bearer;
switch(integ_algo)
if (cfg.is_data) {
uint32_t sn;
if(12 == cfg.sn_len)
{ {
pdcp_unpack_data_pdu_long_sn(pdu, &sn); case INTEGRITY_ALGORITHM_ID_EIA0:
} else { break;
pdcp_unpack_data_pdu_short_sn(pdu, &sn); case INTEGRITY_ALGORITHM_ID_128_EIA1:
} security_128_eia1(&k_int[16],
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU: %d", rrc->get_rb_name(lcid).c_str(), sn); tx_count,
gw->write_pdu(lcid, pdu); get_bearer_id(lcid),
} else { cfg.direction,
if (cfg.is_control) { msg,
uint32_t sn; msg_len,
pdcp_unpack_control_pdu(pdu, &sn); mac);
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s SDU SN: %d", break;
rrc->get_rb_name(lcid).c_str(), sn); case INTEGRITY_ALGORITHM_ID_128_EIA2:
} else { security_128_eia2(&k_int[16],
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", rrc->get_rb_name(lcid).c_str()); tx_count,
} get_bearer_id(lcid),
// pass to RRC cfg.direction,
rrc->write_pdu(lcid, pdu); msg,
msg_len,
mac);
break;
default:
break;
} }
} }
void pdcp_entity::integrity_generate( uint8_t *key_128, bool pdcp_entity::integrity_verify(uint8_t *msg,
uint32_t count, uint32_t count,
uint8_t rb_id,
uint8_t direction,
uint8_t *msg,
uint32_t msg_len, uint32_t msg_len,
uint8_t *mac) uint8_t *mac)
{ {
uint8_t mac_exp[4] = {0x00};
uint8_t i = 0;
bool isValid = true;
switch(integ_algo) switch(integ_algo)
{ {
case INTEGRITY_ALGORITHM_ID_EIA0: case INTEGRITY_ALGORITHM_ID_EIA0:
break; break;
case INTEGRITY_ALGORITHM_ID_128_EIA1: case INTEGRITY_ALGORITHM_ID_128_EIA1:
security_128_eia1(key_128, security_128_eia1(&k_int[16],
count, count,
rb_id, get_bearer_id(lcid),
direction, (cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK),
msg, msg,
msg_len, msg_len,
mac); mac_exp);
break; break;
case INTEGRITY_ALGORITHM_ID_128_EIA2: case INTEGRITY_ALGORITHM_ID_128_EIA2:
security_128_eia2(key_128, security_128_eia2(&k_int[16],
count, count,
rb_id, get_bearer_id(lcid),
direction, (cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK),
msg, msg,
msg_len, msg_len,
mac); mac_exp);
break;
default:
break;
}
switch(integ_algo)
{
case INTEGRITY_ALGORITHM_ID_EIA0:
break;
case INTEGRITY_ALGORITHM_ID_128_EIA1: // Intentional fall-through
case INTEGRITY_ALGORITHM_ID_128_EIA2:
for(i=0; i<4; i++){
if(mac[i] != mac_exp[i]){
log->error_hex(mac_exp, 4, "MAC mismatch (expected)");
log->error_hex(mac, 4, "MAC mismatch (found)");
isValid = false;
break;
}
}
if (isValid){
log->info_hex(mac_exp, 4, "MAC match (expected)");
log->info_hex(mac, 4, "MAC match (found)");
}
break;
default:
break;
}
return isValid;
}
void pdcp_entity::cipher_encrypt(uint8_t *msg,
uint32_t msg_len,
uint8_t *ct)
{
byte_buffer_t ct_tmp;
switch(cipher_algo)
{
case CIPHERING_ALGORITHM_ID_EEA0:
break;
case CIPHERING_ALGORITHM_ID_128_EEA1:
security_128_eea1(&(k_enc[16]),
tx_count,
get_bearer_id(lcid),
cfg.direction,
msg,
msg_len,
ct_tmp.msg);
memcpy(ct, ct_tmp.msg, msg_len);
break;
case CIPHERING_ALGORITHM_ID_128_EEA2:
security_128_eea2(&(k_enc[16]),
tx_count,
get_bearer_id(lcid),
cfg.direction,
msg,
msg_len,
ct_tmp.msg);
memcpy(ct, ct_tmp.msg, msg_len);
break;
default:
break;
}
}
void pdcp_entity::cipher_decrypt(uint8_t *ct,
uint32_t count,
uint32_t ct_len,
uint8_t *msg)
{
byte_buffer_t msg_tmp;
switch(cipher_algo)
{
case CIPHERING_ALGORITHM_ID_EEA0:
break;
case CIPHERING_ALGORITHM_ID_128_EEA1:
security_128_eea1(&(k_enc[16]),
count,
get_bearer_id(lcid),
(cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK),
ct,
ct_len,
msg_tmp.msg);
memcpy(msg, msg_tmp.msg, ct_len);
break;
case CIPHERING_ALGORITHM_ID_128_EEA2:
security_128_eea2(&(k_enc[16]),
count,
get_bearer_id(lcid),
(cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK),
ct,
ct_len,
msg_tmp.msg);
memcpy(msg, msg_tmp.msg, ct_len);
break; break;
default: default:
break; break;
} }
} }
void pdcp_entity::run_thread()
{
byte_buffer_t *pdu;
running = true;
while(running) {
rx_pdu_queue.read(&pdu);
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU, do_integrity = %s, do_encryption = %s",
get_rb_name(lcid), (do_integrity) ? "true" : "false", (do_encryption) ? "true" : "false");
// Handle SRB messages
switch(lcid)
{
case RB_ID_SRB0:
// Simply pass on to RRC
rrc->write_pdu(RB_ID_SRB0, pdu);
break;
case RB_ID_SRB1: // Intentional fall-through
case RB_ID_SRB2:
uint32_t sn;
if (do_encryption) {
cipher_decrypt(&(pdu->msg[sn_len_bytes]),
rx_count,
pdu->N_bytes - sn_len_bytes,
&(pdu->msg[sn_len_bytes]));
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU (decrypted)", get_rb_name(lcid));
}
if (do_integrity) {
integrity_verify(pdu->msg,
rx_count,
pdu->N_bytes - 4,
&(pdu->msg[pdu->N_bytes - 4]));
}
pdcp_unpack_control_pdu(pdu, &sn);
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU SN: %d", get_rb_name(lcid), sn);
rrc->write_pdu(lcid, pdu);
break;
}
// Handle DRB messages
if(lcid >= RB_ID_DRB1)
{
uint32_t sn;
if (do_encryption) {
cipher_decrypt(&(pdu->msg[sn_len_bytes]),
rx_count,
pdu->N_bytes - sn_len_bytes,
&(pdu->msg[sn_len_bytes]));
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU (decrypted)", get_rb_name(lcid));
}
if(12 == cfg.sn_len)
{
pdcp_unpack_data_pdu_long_sn(pdu, &sn);
} else {
pdcp_unpack_data_pdu_short_sn(pdu, &sn);
}
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU SN: %d", get_rb_name(lcid), sn);
gw->write_pdu(lcid, pdu);
}
rx_count++;
}
}
uint8_t pdcp_entity::get_bearer_id(uint8_t lcid)
{
if(lcid <= RB_ID_SRB2) {
return lcid - 1;
} else {
return lcid - RB_ID_SRB2 - 1;
}
}
/**************************************************************************** /****************************************************************************
* Pack/Unpack helper functions * Pack/Unpack helper functions
* Ref: 3GPP TS 36.323 v10.1.0 * Ref: 3GPP TS 36.323 v10.1.0

@ -95,6 +95,14 @@ void rlc::get_metrics(rlc_metrics_t &m)
reset_metrics(); reset_metrics();
} }
void rlc::reestablish() {
for(uint32_t i=0; i<SRSLTE_N_RADIO_BEARERS; i++) {
if(rlc_array[i].active()) {
rlc_array[i].reestablish();
}
}
}
void rlc::reset() void rlc::reset()
{ {
for(uint32_t i=0; i<SRSLTE_N_RADIO_BEARERS; i++) { for(uint32_t i=0; i<SRSLTE_N_RADIO_BEARERS; i++) {
@ -123,9 +131,8 @@ void rlc::write_sdu(uint32_t lcid, byte_buffer_t *sdu)
} }
} }
std::string rlc::get_rb_name(uint32_t lcid) bool rlc::rb_is_um(uint32_t lcid) {
{ return rlc_array[lcid].get_mode()==RLC_MODE_UM;
return rrc->get_rb_name(lcid);
} }
/******************************************************************************* /*******************************************************************************
@ -217,11 +224,10 @@ void rlc::add_bearer(uint32_t lcid)
cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS0; cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS0;
add_bearer(lcid, srslte_rlc_config_t(&cnfg)); add_bearer(lcid, srslte_rlc_config_t(&cnfg));
} else { } else {
rlc_log->warning("Bearer %s already configured. Reconfiguration not supported\n", get_rb_name(lcid).c_str()); rlc_log->warning("Bearer %s already configured. Reconfiguration not supported\n", get_rb_name(lcid));
} }
}else{ }else{
rlc_log->error("Radio bearer %s does not support default RLC configuration.\n", rlc_log->error("Radio bearer %s does not support default RLC configuration.\n", get_rb_name(lcid));
get_rb_name(lcid).c_str());
} }
} }
@ -234,7 +240,7 @@ void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg)
if (!rlc_array[lcid].active()) { if (!rlc_array[lcid].active()) {
rlc_log->info("Adding radio bearer %s with mode %s\n", rlc_log->info("Adding radio bearer %s with mode %s\n",
get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg.rlc_mode]); get_rb_name(lcid), liblte_rrc_rlc_mode_text[cnfg.rlc_mode]);
switch(cnfg.rlc_mode) switch(cnfg.rlc_mode)
{ {
case LIBLTE_RRC_RLC_MODE_AM: case LIBLTE_RRC_RLC_MODE_AM:
@ -254,7 +260,7 @@ void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg)
return; return;
} }
} else { } else {
rlc_log->warning("Bearer %s already created.\n", get_rb_name(lcid).c_str()); rlc_log->warning("Bearer %s already created.\n", get_rb_name(lcid));
} }
rlc_array[lcid].configure(cnfg); rlc_array[lcid].configure(cnfg);

@ -79,7 +79,7 @@ void rlc_am::configure(srslte_rlc_config_t cfg_)
cfg = cfg_.am; cfg = cfg_.am;
log->info("%s configured: t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, " log->info("%s configured: t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, "
"t_reordering=%d, t_status_prohibit=%d\n", "t_reordering=%d, t_status_prohibit=%d\n",
rrc->get_rb_name(lcid).c_str(), cfg.t_poll_retx, cfg.poll_pdu, cfg.poll_byte, cfg.max_retx_thresh, get_rb_name(lcid), cfg.t_poll_retx, cfg.poll_pdu, cfg.poll_byte, cfg.max_retx_thresh,
cfg.t_reordering, cfg.t_status_prohibit); cfg.t_reordering, cfg.t_status_prohibit);
} }
@ -175,7 +175,7 @@ uint32_t rlc_am::get_bearer()
void rlc_am::write_sdu(byte_buffer_t *sdu) void rlc_am::write_sdu(byte_buffer_t *sdu)
{ {
log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rrc->get_rb_name(lcid).c_str()); log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", get_rb_name(lcid));
tx_sdu_queue.write(sdu); tx_sdu_queue.write(sdu);
} }
@ -359,7 +359,7 @@ void rlc_am::check_reordering_timeout()
if(reordering_timeout.is_running() && reordering_timeout.expired()) if(reordering_timeout.is_running() && reordering_timeout.expired())
{ {
reordering_timeout.reset(); reordering_timeout.reset();
log->debug("%s reordering timeout expiry - updating vr_ms\n", rrc->get_rb_name(lcid).c_str()); log->debug("%s reordering timeout expiry - updating vr_ms\n", get_rb_name(lcid));
// 36.322 v10 Section 5.1.3.2.4 // 36.322 v10 Section 5.1.3.2.4
vr_ms = vr_x; vr_ms = vr_x;
@ -433,7 +433,7 @@ int rlc_am::build_status_pdu(uint8_t *payload, uint32_t nof_bytes)
if(pdu_len > 0 && nof_bytes >= (uint32_t)pdu_len) if(pdu_len > 0 && nof_bytes >= (uint32_t)pdu_len)
{ {
log->info("%s Tx status PDU - %s\n", log->info("%s Tx status PDU - %s\n",
rrc->get_rb_name(lcid).c_str(), rlc_am_to_string(&status).c_str()); get_rb_name(lcid), rlc_am_to_string(&status).c_str());
do_status = false; do_status = false;
poll_received = false; poll_received = false;
@ -444,7 +444,7 @@ int rlc_am::build_status_pdu(uint8_t *payload, uint32_t nof_bytes)
return rlc_am_write_status_pdu(&status, payload); return rlc_am_write_status_pdu(&status, payload);
}else{ }else{
log->warning("%s Cannot tx status PDU - %d bytes available, %d bytes required\n", log->warning("%s Cannot tx status PDU - %d bytes available, %d bytes required\n",
rrc->get_rb_name(lcid).c_str(), nof_bytes, pdu_len); get_rb_name(lcid), nof_bytes, pdu_len);
return 0; return 0;
} }
} }
@ -478,7 +478,7 @@ int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes)
return -1; return -1;
} }
if(retx.is_segment || req_size > (int)nof_bytes) { if(retx.is_segment || req_size > (int)nof_bytes) {
log->debug("%s build_retx_pdu - resegmentation required\n", rrc->get_rb_name(lcid).c_str()); log->debug("%s build_retx_pdu - resegmentation required\n", get_rb_name(lcid));
return build_segment(payload, nof_bytes, retx); return build_segment(payload, nof_bytes, retx);
} }
@ -503,7 +503,7 @@ int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes)
if(tx_window[retx.sn].retx_count >= cfg.max_retx_thresh) if(tx_window[retx.sn].retx_count >= cfg.max_retx_thresh)
rrc->max_retx_attempted(); rrc->max_retx_attempted();
log->info("%s Retx PDU scheduled for tx. SN: %d, retx count: %d\n", log->info("%s Retx PDU scheduled for tx. SN: %d, retx count: %d\n",
rrc->get_rb_name(lcid).c_str(), retx.sn, tx_window[retx.sn].retx_count); get_rb_name(lcid), retx.sn, tx_window[retx.sn].retx_count);
debug_state(); debug_state();
return (ptr-payload) + tx_window[retx.sn].buf->N_bytes; return (ptr-payload) + tx_window[retx.sn].buf->N_bytes;
@ -540,7 +540,7 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r
if(nof_bytes <= head_len) if(nof_bytes <= head_len)
{ {
log->warning("%s Cannot build a PDU segment - %d bytes available, %d bytes required for header\n", log->warning("%s Cannot build a PDU segment - %d bytes available, %d bytes required for header\n",
rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len); get_rb_name(lcid), nof_bytes, head_len);
return 0; return 0;
} }
pdu_space = nof_bytes-head_len; pdu_space = nof_bytes-head_len;
@ -606,15 +606,15 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r
memcpy(ptr, data, len); memcpy(ptr, data, len);
log->info("%s Retx PDU segment scheduled for tx. SN: %d, SO: %d\n", log->info("%s Retx PDU segment scheduled for tx. SN: %d, SO: %d\n",
rrc->get_rb_name(lcid).c_str(), retx.sn, retx.so_start); get_rb_name(lcid), retx.sn, retx.so_start);
debug_state(); debug_state();
int pdu_len = (ptr-payload) + len; int pdu_len = (ptr-payload) + len;
if(pdu_len > (int)nof_bytes) { if(pdu_len > (int)nof_bytes) {
log->error("%s Retx PDU segment length error. Available: %d, Used: %d\n", log->error("%s Retx PDU segment length error. Available: %d, Used: %d\n",
rrc->get_rb_name(lcid).c_str(), nof_bytes, pdu_len); get_rb_name(lcid), nof_bytes, pdu_len);
log->debug("%s Retx PDU segment length error. Header len: %d, Payload len: %d, N_li: %d\n", log->debug("%s Retx PDU segment length error. Header len: %d, Payload len: %d, N_li: %d\n",
rrc->get_rb_name(lcid).c_str(), (ptr-payload), len, new_header.N_li); get_rb_name(lcid), (ptr-payload), len, new_header.N_li);
} }
return pdu_len; return pdu_len;
@ -662,13 +662,13 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
if(pdu_space <= head_len + 1) if(pdu_space <= head_len + 1)
{ {
log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n", log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n",
rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len); get_rb_name(lcid), nof_bytes, head_len);
pool->deallocate(pdu); pool->deallocate(pdu);
return 0; return 0;
} }
log->debug("%s Building PDU - pdu_space: %d, head_len: %d \n", log->debug("%s Building PDU - pdu_space: %d, head_len: %d \n",
rrc->get_rb_name(lcid).c_str(), pdu_space, head_len); get_rb_name(lcid), pdu_space, head_len);
// Check for SDU segment // Check for SDU segment
if(tx_sdu) if(tx_sdu)
@ -683,7 +683,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
if(tx_sdu->N_bytes == 0) if(tx_sdu->N_bytes == 0)
{ {
log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); get_rb_name(lcid), tx_sdu->get_latency_us());
pool->deallocate(tx_sdu); pool->deallocate(tx_sdu);
tx_sdu = NULL; tx_sdu = NULL;
} }
@ -694,7 +694,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU
log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n", log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n",
rrc->get_rb_name(lcid).c_str(), to_move, pdu_space, head_len); get_rb_name(lcid), to_move, pdu_space, head_len);
} }
// Pull SDUs from queue // Pull SDUs from queue
@ -718,7 +718,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
if(tx_sdu->N_bytes == 0) if(tx_sdu->N_bytes == 0)
{ {
log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); get_rb_name(lcid), tx_sdu->get_latency_us());
pool->deallocate(tx_sdu); pool->deallocate(tx_sdu);
tx_sdu = NULL; tx_sdu = NULL;
} }
@ -728,7 +728,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
pdu_space = 0; pdu_space = 0;
log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n", log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n",
rrc->get_rb_name(lcid).c_str(), to_move, pdu_space, head_len); get_rb_name(lcid), to_move, pdu_space, head_len);
} }
if(tx_sdu) if(tx_sdu)
@ -737,11 +737,11 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
// Set Poll bit // Set Poll bit
pdu_without_poll++; pdu_without_poll++;
byte_without_poll += (pdu->N_bytes + head_len); byte_without_poll += (pdu->N_bytes + head_len);
log->debug("%s pdu_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), pdu_without_poll); log->debug("%s pdu_without_poll: %d\n", get_rb_name(lcid), pdu_without_poll);
log->debug("%s byte_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), byte_without_poll); log->debug("%s byte_without_poll: %d\n", get_rb_name(lcid), byte_without_poll);
if(poll_required()) if(poll_required())
{ {
log->debug("%s setting poll bit to request status\n", rrc->get_rb_name(lcid).c_str()); log->debug("%s setting poll bit to request status\n", get_rb_name(lcid));
header.p = 1; header.p = 1;
poll_sn = vt_s; poll_sn = vt_s;
pdu_without_poll = 0; pdu_without_poll = 0;
@ -752,7 +752,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
// Set SN // Set SN
header.sn = vt_s; header.sn = vt_s;
vt_s = (vt_s + 1)%MOD; vt_s = (vt_s + 1)%MOD;
log->info("%s PDU scheduled for tx. SN: %d\n", rrc->get_rb_name(lcid).c_str(), header.sn); log->info("%s PDU scheduled for tx. SN: %d\n", get_rb_name(lcid), header.sn);
// Place PDU in tx_window, write header and TX // Place PDU in tx_window, write header and TX
tx_window[header.sn].buf = pdu; tx_window[header.sn].buf = pdu;
@ -773,26 +773,26 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h
std::map<uint32_t, rlc_amd_rx_pdu_t>::iterator it; std::map<uint32_t, rlc_amd_rx_pdu_t>::iterator it;
log->info_hex(payload, nof_bytes, "%s Rx data PDU SN: %d", log->info_hex(payload, nof_bytes, "%s Rx data PDU SN: %d",
rrc->get_rb_name(lcid).c_str(), header.sn); get_rb_name(lcid), header.sn);
if(!inside_rx_window(header.sn)) { if(!inside_rx_window(header.sn)) {
if(header.p) { if(header.p) {
log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid));
do_status = true; do_status = true;
} }
log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", log->info("%s SN: %d outside rx window [%d:%d] - discarding\n",
rrc->get_rb_name(lcid).c_str(), header.sn, vr_r, vr_mr); get_rb_name(lcid), header.sn, vr_r, vr_mr);
return; return;
} }
it = rx_window.find(header.sn); it = rx_window.find(header.sn);
if(rx_window.end() != it) { if(rx_window.end() != it) {
if(header.p) { if(header.p) {
log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid));
do_status = true; do_status = true;
} }
log->info("%s Discarding duplicate SN: %d\n", log->info("%s Discarding duplicate SN: %d\n",
rrc->get_rb_name(lcid).c_str(), header.sn); get_rb_name(lcid), header.sn);
return; return;
} }
@ -825,7 +825,7 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h
// Check poll bit // Check poll bit
if(header.p) if(header.p)
{ {
log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid));
poll_received = true; poll_received = true;
// 36.322 v10 Section 5.2.3 // 36.322 v10 Section 5.2.3
@ -870,16 +870,16 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a
std::map<uint32_t, rlc_amd_rx_pdu_segments_t>::iterator it; std::map<uint32_t, rlc_amd_rx_pdu_segments_t>::iterator it;
log->info_hex(payload, nof_bytes, "%s Rx data PDU segment. SN: %d, SO: %d", log->info_hex(payload, nof_bytes, "%s Rx data PDU segment. SN: %d, SO: %d",
rrc->get_rb_name(lcid).c_str(), header.sn, header.so); get_rb_name(lcid), header.sn, header.so);
// Check inside rx window // Check inside rx window
if(!inside_rx_window(header.sn)) { if(!inside_rx_window(header.sn)) {
if(header.p) { if(header.p) {
log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid));
do_status = true; do_status = true;
} }
log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", log->info("%s SN: %d outside rx window [%d:%d] - discarding\n",
rrc->get_rb_name(lcid).c_str(), header.sn, vr_r, vr_mr); get_rb_name(lcid), header.sn, vr_r, vr_mr);
return; return;
} }
@ -898,7 +898,7 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a
if(rx_segments.end() != it) { if(rx_segments.end() != it) {
if(header.p) { if(header.p) {
log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid));
do_status = true; do_status = true;
} }
@ -928,7 +928,7 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a
// Check poll bit // Check poll bit
if(header.p) if(header.p)
{ {
log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid));
poll_received = true; poll_received = true;
// 36.322 v10 Section 5.2.3 // 36.322 v10 Section 5.2.3
@ -946,12 +946,12 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a
void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes)
{ {
log->info_hex(payload, nof_bytes, "%s Rx control PDU", rrc->get_rb_name(lcid).c_str()); log->info_hex(payload, nof_bytes, "%s Rx control PDU", get_rb_name(lcid));
rlc_status_pdu_t status; rlc_status_pdu_t status;
rlc_am_read_status_pdu(payload, nof_bytes, &status); rlc_am_read_status_pdu(payload, nof_bytes, &status);
log->info("%s Rx Status PDU: %s\n", rrc->get_rb_name(lcid).c_str(), rlc_am_to_string(&status).c_str()); log->info("%s Rx Status PDU: %s\n", get_rb_name(lcid), rlc_am_to_string(&status).c_str());
poll_retx_timeout.reset(); poll_retx_timeout.reset();
@ -989,7 +989,7 @@ void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes)
} }
} else { } else {
log->warning("%s invalid segment NACK received for SN %d. so_start: %d, so_end: %d, N_bytes: %d\n", log->warning("%s invalid segment NACK received for SN %d. so_start: %d, so_end: %d, N_bytes: %d\n",
rrc->get_rb_name(lcid).c_str(), i, status.nacks[j].so_start, status.nacks[j].so_end, it->second.buf->N_bytes); get_rb_name(lcid), i, status.nacks[j].so_start, status.nacks[j].so_end, it->second.buf->N_bytes);
} }
} }
@ -1043,7 +1043,7 @@ void rlc_am::reassemble_rx_sdus()
rx_sdu->N_bytes += len; rx_sdu->N_bytes += len;
rx_window[vr_r].buf->msg += len; rx_window[vr_r].buf->msg += len;
rx_window[vr_r].buf->N_bytes -= len; rx_window[vr_r].buf->N_bytes -= len;
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rrc->get_rb_name(lcid).c_str()); log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", get_rb_name(lcid));
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
@ -1059,7 +1059,7 @@ void rlc_am::reassemble_rx_sdus()
rx_sdu->N_bytes += rx_window[vr_r].buf->N_bytes; rx_sdu->N_bytes += rx_window[vr_r].buf->N_bytes;
if(rlc_am_end_aligned(rx_window[vr_r].header.fi)) if(rlc_am_end_aligned(rx_window[vr_r].header.fi))
{ {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rrc->get_rb_name(lcid).c_str()); log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", get_rb_name(lcid));
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
@ -1103,7 +1103,7 @@ void rlc_am::debug_state()
{ {
log->debug("%s vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d " log->debug("%s vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d "
"vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d\n", "vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d\n",
rrc->get_rb_name(lcid).c_str(), vt_a, vt_ms, vt_s, poll_sn, get_rb_name(lcid), vt_a, vt_ms, vt_s, poll_sn,
vr_r, vr_mr, vr_x, vr_ms, vr_h); vr_r, vr_mr, vr_x, vr_ms, vr_h);
} }

@ -70,6 +70,10 @@ void rlc_entity::configure(srslte_rlc_config_t cnfg)
rlc->configure(cnfg); rlc->configure(cnfg);
} }
void rlc_entity::reestablish() {
rlc->reset();
}
void rlc_entity::reset() void rlc_entity::reset()
{ {
rlc->reset(); rlc->reset();

@ -84,7 +84,7 @@ uint32_t rlc_tm::get_bearer()
// PDCP interface // PDCP interface
void rlc_tm::write_sdu(byte_buffer_t *sdu) void rlc_tm::write_sdu(byte_buffer_t *sdu)
{ {
log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rrc->get_rb_name(lcid).c_str()); log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", get_rb_name(lcid));
ul_queue.write(sdu); ul_queue.write(sdu);
} }
@ -104,7 +104,7 @@ int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes)
uint32_t pdu_size = ul_queue.size_tail_bytes(); uint32_t pdu_size = ul_queue.size_tail_bytes();
if(pdu_size > nof_bytes) if(pdu_size > nof_bytes)
{ {
log->error("TX %s PDU size larger than MAC opportunity\n", rrc->get_rb_name(lcid).c_str()); log->error("TX %s PDU size larger than MAC opportunity\n", get_rb_name(lcid));
return 0; return 0;
} }
byte_buffer_t *buf; byte_buffer_t *buf;
@ -112,9 +112,9 @@ int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes)
pdu_size = buf->N_bytes; pdu_size = buf->N_bytes;
memcpy(payload, buf->msg, buf->N_bytes); memcpy(payload, buf->msg, buf->N_bytes);
log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rrc->get_rb_name(lcid).c_str(), buf->get_latency_us()); get_rb_name(lcid), buf->get_latency_us());
pool->deallocate(buf); pool->deallocate(buf);
log->info_hex(payload, pdu_size, "TX %s, %s PDU", rrc->get_rb_name(lcid).c_str(), rlc_mode_text[RLC_MODE_TM]); log->info_hex(payload, pdu_size, "TX %s, %s PDU", get_rb_name(lcid), rlc_mode_text[RLC_MODE_TM]);
return pdu_size; return pdu_size;
} }

@ -75,18 +75,18 @@ void rlc_um::configure(srslte_rlc_config_t cnfg_)
case LIBLTE_RRC_RLC_MODE_UM_BI: case LIBLTE_RRC_RLC_MODE_UM_BI:
log->info("%s configured in %s mode: " log->info("%s configured in %s mode: "
"t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n", "t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n",
rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], get_rb_name(lcid), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length], rlc_umd_sn_size_num[cfg.rx_sn_field_length]); cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length], rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
break; break;
case LIBLTE_RRC_RLC_MODE_UM_UNI_UL: case LIBLTE_RRC_RLC_MODE_UM_UNI_UL:
log->info("%s configured in %s mode: tx_sn_field_length=%u bits\n", log->info("%s configured in %s mode: tx_sn_field_length=%u bits\n",
rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], get_rb_name(lcid), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
rlc_umd_sn_size_num[cfg.rx_sn_field_length]); rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
break; break;
case LIBLTE_RRC_RLC_MODE_UM_UNI_DL: case LIBLTE_RRC_RLC_MODE_UM_UNI_DL:
log->info("%s configured in %s mode: " log->info("%s configured in %s mode: "
"t_reordering=%d ms, rx_sn_field_length=%u bits\n", "t_reordering=%d ms, rx_sn_field_length=%u bits\n",
rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], get_rb_name(lcid), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length]); cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
break; break;
default: default:
@ -153,7 +153,7 @@ uint32_t rlc_um::get_bearer()
void rlc_um::write_sdu(byte_buffer_t *sdu) void rlc_um::write_sdu(byte_buffer_t *sdu)
{ {
log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rrc->get_rb_name(lcid).c_str()); log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", get_rb_name(lcid));
tx_sdu_queue.write(sdu); tx_sdu_queue.write(sdu);
} }
@ -216,7 +216,7 @@ void rlc_um::timer_expired(uint32_t timeout_id)
// 36.322 v10 Section 5.1.2.2.4 // 36.322 v10 Section 5.1.2.2.4
log->info("%s reordering timeout expiry - updating vr_ur and reassembling\n", log->info("%s reordering timeout expiry - updating vr_ur and reassembling\n",
rrc->get_rb_name(lcid).c_str()); get_rb_name(lcid));
log->warning("Lost PDU SN: %d\n", vr_ur); log->warning("Lost PDU SN: %d\n", vr_ur);
pdu_lost = true; pdu_lost = true;
@ -281,7 +281,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
{ {
pool->deallocate(pdu); pool->deallocate(pdu);
log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n", log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n",
rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len); get_rb_name(lcid), nof_bytes, head_len);
return 0; return 0;
} }
@ -291,7 +291,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
uint32_t space = pdu_space-head_len; uint32_t space = pdu_space-head_len;
to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n", log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n",
rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes); get_rb_name(lcid), to_move, tx_sdu->N_bytes);
memcpy(pdu_ptr, tx_sdu->msg, to_move); memcpy(pdu_ptr, tx_sdu->msg, to_move);
last_li = to_move; last_li = to_move;
pdu_ptr += to_move; pdu_ptr += to_move;
@ -301,7 +301,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
if(tx_sdu->N_bytes == 0) if(tx_sdu->N_bytes == 0)
{ {
log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); get_rb_name(lcid), tx_sdu->get_latency_us());
pool->deallocate(tx_sdu); pool->deallocate(tx_sdu);
tx_sdu = NULL; tx_sdu = NULL;
} }
@ -320,7 +320,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
uint32_t space = pdu_space-head_len; uint32_t space = pdu_space-head_len;
to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
log->debug("%s adding new SDU segment - %d bytes of %d remaining\n", log->debug("%s adding new SDU segment - %d bytes of %d remaining\n",
rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes); get_rb_name(lcid), to_move, tx_sdu->N_bytes);
memcpy(pdu_ptr, tx_sdu->msg, to_move); memcpy(pdu_ptr, tx_sdu->msg, to_move);
last_li = to_move; last_li = to_move;
pdu_ptr += to_move; pdu_ptr += to_move;
@ -330,7 +330,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
if(tx_sdu->N_bytes == 0) if(tx_sdu->N_bytes == 0)
{ {
log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); get_rb_name(lcid), tx_sdu->get_latency_us());
pool->deallocate(tx_sdu); pool->deallocate(tx_sdu);
tx_sdu = NULL; tx_sdu = NULL;
} }
@ -345,11 +345,11 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
vt_us = (vt_us + 1)%cfg.tx_mod; vt_us = (vt_us + 1)%cfg.tx_mod;
// Add header and TX // Add header and TX
log->debug("%s packing PDU with length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes); log->debug("%s packing PDU with length %d\n", get_rb_name(lcid), pdu->N_bytes);
rlc_um_write_data_pdu_header(&header, pdu); rlc_um_write_data_pdu_header(&header, pdu);
memcpy(payload, pdu->msg, pdu->N_bytes); memcpy(payload, pdu->msg, pdu->N_bytes);
uint32_t ret = pdu->N_bytes; uint32_t ret = pdu->N_bytes;
log->debug("%s returning length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes); log->debug("%s returning length %d\n", get_rb_name(lcid), pdu->N_bytes);
pool->deallocate(pdu); pool->deallocate(pdu);
debug_state(); debug_state();
@ -363,20 +363,20 @@ void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes)
rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.rx_sn_field_length, &header); rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.rx_sn_field_length, &header);
log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d", log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d",
rrc->get_rb_name(lcid).c_str(), header.sn); get_rb_name(lcid), header.sn);
if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) && if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) &&
RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ur)) RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ur))
{ {
log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", log->info("%s SN: %d outside rx window [%d:%d] - discarding\n",
rrc->get_rb_name(lcid).c_str(), header.sn, vr_ur, vr_uh); get_rb_name(lcid), header.sn, vr_ur, vr_uh);
return; return;
} }
it = rx_window.find(header.sn); it = rx_window.find(header.sn);
if(rx_window.end() != it) if(rx_window.end() != it)
{ {
log->info("%s Discarding duplicate SN: %d\n", log->info("%s Discarding duplicate SN: %d\n",
rrc->get_rb_name(lcid).c_str(), header.sn); get_rb_name(lcid), header.sn);
return; return;
} }
@ -451,7 +451,7 @@ void rlc_um::reassemble_rx_sdus()
log->warning("Dropping remainder of lost PDU (lower edge middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); log->warning("Dropping remainder of lost PDU (lower edge middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu);
rx_sdu->reset(); rx_sdu->reset();
} else { } else {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i); log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", get_rb_name(lcid), vr_ur, i);
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
@ -471,7 +471,7 @@ void rlc_um::reassemble_rx_sdus()
log->warning("Dropping remainder of lost PDU (lower edge last segments)\n"); log->warning("Dropping remainder of lost PDU (lower edge last segments)\n");
rx_sdu->reset(); rx_sdu->reset();
} else { } else {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (lower edge last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur); log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (lower edge last segments)", get_rb_name(lcid), vr_ur);
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
@ -505,7 +505,7 @@ void rlc_um::reassemble_rx_sdus()
log->warning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); log->warning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu);
rx_sdu->reset(); rx_sdu->reset();
} else { } else {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i); log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", get_rb_name(lcid), vr_ur, i);
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
@ -534,7 +534,7 @@ void rlc_um::reassemble_rx_sdus()
log->warning("Dropping remainder of lost PDU (update vr_ur last segments)\n"); log->warning("Dropping remainder of lost PDU (update vr_ur last segments)\n");
rx_sdu->reset(); rx_sdu->reset();
} else { } else {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur); log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", get_rb_name(lcid), vr_ur);
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
@ -564,7 +564,7 @@ bool rlc_um::inside_reordering_window(uint16_t sn)
void rlc_um::debug_state() void rlc_um::debug_state()
{ {
log->debug("%s vt_us = %d, vr_ur = %d, vr_ux = %d, vr_uh = %d \n", log->debug("%s vt_us = %d, vr_ur = %d, vr_ux = %d, vr_uh = %d \n",
rrc->get_rb_name(lcid).c_str(), vt_us, vr_ur, vr_ux, vr_uh); get_rb_name(lcid), vt_us, vr_ur, vr_ux, vr_uh);
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save