Merge branch 'enbmimo' into mob_crypto_mimo

master
Ismael Gomez 7 years ago
commit b0a2fa3b0b

@ -64,9 +64,11 @@ public:
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 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 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 get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) = 0;
@ -93,6 +95,7 @@ public:
class phy_interface_rrc
{
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;
};
@ -111,6 +114,7 @@ public:
/* 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_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;
};

@ -131,13 +131,14 @@ public:
typedef struct {
uint32_t rnti;
srslte_dci_format_t dci_format;
srslte_ra_dl_dci_t dci;
srslte_dci_location_t dci_location;
uint32_t tbs;
uint32_t tbs[SRSLTE_MAX_TB];
bool mac_ce_ta;
bool mac_ce_rnti;
uint32_t nof_pdu_elems;
dl_sched_pdu_t pdu[MAX_RLC_PDU_LIST];
uint32_t nof_pdu_elems[SRSLTE_MAX_TB];
dl_sched_pdu_t pdu[SRSLTE_MAX_TB][MAX_RLC_PDU_LIST];
} dl_sched_data_t;
typedef struct {
@ -225,8 +226,10 @@ public:
virtual int dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code) = 0;
/* 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_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;
/* UL information */

@ -95,10 +95,11 @@ typedef struct SRSLTE_API {
typedef struct {
uint16_t rnti;
srslte_dci_format_t dci_format;
srslte_ra_dl_dci_t grant;
srslte_dci_location_t location;
srslte_softbuffer_tx_t *softbuffer;
uint8_t *data;
srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_TB];
uint8_t *data[SRSLTE_MAX_TB];
} srslte_enb_dl_pdsch_t;
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],
uint32_t sf_idx,
uint8_t *data[SRSLTE_MAX_CODEWORDS],
srslte_mimo_type_t mimo_type,
uint32_t pmi);
srslte_mimo_type_t mimo_type);
SRSLTE_API int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q,
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_API void srslte_enb_ul_fft(srslte_enb_ul_t *q,
cf_t *signal_buffer);
SRSLTE_API void srslte_enb_ul_fft(srslte_enb_ul_t *q);
SRSLTE_API int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q,
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 current_tx_nb,
uint8_t *data,
srslte_cqi_value_t *cqi_value,
srslte_uci_data_t *uci_data,
uint32_t tti);

@ -55,13 +55,22 @@ typedef struct {
} srslte_cqi_periodic_cfg_t;
/* Table 5.2.2.6.2-1: Fields for channel quality information feedback for higher layer configured subband
CQI reports
(transmission mode 1, transmission mode 2, transmission mode 3, transmission mode 7 and
transmission mode 8 configured without PMI/RI reporting). */
CQI reports (transmission mode 1, transmission mode 2, transmission mode 3, transmission mode 7 and
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 {
uint8_t wideband_cqi; // 4-bit width
uint32_t subband_diff_cqi; // 2N-bit width
uint8_t wideband_cqi_cw0; // 4-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;
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;
/* 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 *ce,
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_pucch_cfg_t *cfg,

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

@ -57,8 +57,8 @@ typedef struct SRSLTE_API {
} srslte_uci_cqi_pusch_t;
typedef struct SRSLTE_API {
uint8_t *cqi_table[16];
int16_t *cqi_table_s[16];
uint8_t **cqi_table;
int16_t **cqi_table_s;
} srslte_uci_cqi_pucch_t;
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_2; // 2st codeword bit for HARQ-ACK
uint32_t uci_ack_len;
bool ri_periodic_report;
bool scheduling_request;
bool channel_selection;
bool cqi_ack;
@ -95,6 +96,11 @@ SRSLTE_API int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data,
uint32_t cqi_len,
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,
int16_t b_bits[32], // aligned for simd
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,
srslte_uci_bit_t *ri_bits);
SRSLTE_API 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);
SRSLTE_API int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg,
uint8_t data,
SRSLTE_API 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,
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,
uint8_t *c_seq,
float beta,
uint32_t H_prime_total,
uint32_t O_cqi,
srslte_uci_bit_t *ri_bits,
uint8_t *data);
srslte_uci_bit_t *ack_ri_bits,
uint8_t data[2],
uint32_t nof_bits,
bool is_ri);
#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,
char *args,
uint32_t nof_rx_antennas);
uint32_t nof_channels);
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 *args,
uint32_t nof_rx_antennas);
uint32_t nof_channels);
SRSLTE_API const char *srslte_rf_name(srslte_rf_t *h);

@ -65,7 +65,7 @@ SRSLTE_API extern int srslte_verbose;
#if CMAKE_BUILD_TYPE==Debug
/* 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
#define ERROR(_fmt, ...) fprintf(stderr, "[ERROR in %s]:" _fmt "\n", __FUNCTION__, ##__VA_ARGS__)
#endif /* CMAKE_BUILD_TYPE==Debug */

@ -74,7 +74,7 @@ namespace srslte {
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 reset();
bool start_agc(bool tx_gain_same_rx);
@ -86,9 +86,10 @@ namespace srslte {
void set_manual_calibration(rf_cal_t *calibration);
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();
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);
void set_tx_gain(float gain);
@ -166,6 +167,7 @@ namespace srslte {
uint32_t tti;
bool agc_enabled;
uint32_t saved_nof_channels;
char saved_args[128];
char saved_devname[128];

@ -31,7 +31,6 @@
#include <string.h>
#include <srslte/phy/common/phy_common.h>
#include <srslte/srslte.h>
#include <srslte/phy/dft/ofdm.h>
#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)
{
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);
srslte_sss_put_slot(sf_idx ? q->sss_signal5 : q->sss_signal0, q->sf_symbols[0],
for (int p = 0; p < q->cell.nof_ports; p++) {
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);
}
}
}
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)
@ -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],
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 */
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;
}

@ -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);
}
int get_pucch(srslte_enb_ul_t *q, uint16_t rnti,
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);
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);
@ -273,7 +277,7 @@ int get_pucch(srslte_enb_ul_t *q, uint16_t rnti,
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) {
fprintf(stderr,"Error decoding PUCCH\n");
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];
if (q->users[rnti]) {
int ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits);
uint32_t nof_uci_bits = uci_data->ri_periodic_report ? uci_data->uci_ri_len : (uci_data->uci_cqi_len +
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.
// try again to decode ACK only
if (uci_data->scheduling_request && uci_data->uci_ack_len && ret_val != 1) {
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
@ -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];
}
if (uci_data->uci_ack_len > 1) {
uci_data->uci_ack_2 = pucch_bits[1];
}
// PUCCH2 CQI bits are decoded inside srslte_pucch_decode()
if (uci_data->uci_cqi_len) {
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) {
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,
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 (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,
q->ce, noise_power,
rnti, data,
cqi_value,
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])
{
uint8_t *body_ptr = buff;
srslte_bit_unpack(msg->wideband_cqi, &body_ptr, 4);
srslte_bit_unpack(msg->subband_diff_cqi, &body_ptr, 2*msg->N);
uint32_t bit_count = 0;
/* 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])
@ -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)
{
uint8_t *body_ptr = buff;
msg->wideband_cqi = srslte_bit_pack(&body_ptr, 4);
msg->subband_diff_cqi = srslte_bit_pack(&body_ptr, 2*msg->N);
uint32_t bit_count = 0;
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;
/* 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;
}
return 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)
@ -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 size = 0;
switch(value->type) {
case SRSLTE_CQI_TYPE_WIDEBAND:
return 4;
size = 4;
break;
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:
return 4+2+value->subband_ue.L;
size = 4 + 2 + value->subband_ue.L;
break;
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) {

@ -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++) {
if (grant->tb_en[cw]) {
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;
}
}
@ -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_mcs_t *mcs = &cfg->grant.mcs[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",
cfg->sf_idx, tb_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs,
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],
q->d[codeword_idx], nbits->nof_bits);
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
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;
// 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
if (uci_data->uci_ack_len == 1) {
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 */
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,
uint8_t bits[SRSLTE_PUCCH_MAX_BITS])
uint8_t bits[SRSLTE_PUCCH_MAX_BITS], uint32_t nof_bits)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
@ -791,7 +791,7 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format,
// Perform ML-decoding
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) {
case SRSLTE_PUCCH_FORMAT_1:
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:
bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t));
ret = 0;
for (int b=0;b<2;b++) {
for (uint8_t b=0;b<2;b++) {
bits[0] = b;
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);
@ -824,6 +824,30 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format,
q->last_corr = corr_max;
bits[0] = b_max;
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_2A:
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_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;
} else {
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,
cf_t *sf_symbols,
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;
if (q != NULL &&
@ -607,19 +607,42 @@ int srslte_pusch_decode(srslte_pusch_t *q,
// Generate scrambling sequence if not pre-generated
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
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");
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
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);
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
// Decode
ret = srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data);
// 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) {

@ -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])
{
// 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].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) {
nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart;
} else if (SRSLTE_SF_MBSFN == grant->sf_type) {
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];
}
}

@ -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) {
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) {
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) {
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) {
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 Qm = cfg->grant.Qm;
// Encode RI
if (uci_data.uci_ri_len > 0) {
// Encode RI if CQI enabled
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];
if (cfg->cb_segm.tbs == 0) {
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) {
return ret;
}
@ -809,8 +814,8 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q,
if (cfg->cb_segm.tbs == 0) {
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,
beta, nb_q / Qm, &q->ack_ri_bits[Q_prime_ri * Qm]);
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], false);
if (ret < 0) {
return ret;
}

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

@ -43,18 +43,20 @@ srslte_cell_t cell = {
};
uint32_t subframe = 0;
bool test_cqi_only = false;
void usage(char *prog) {
printf("Usage: %s [csNnv]\n", prog);
printf("\t-c cell id [Default %d]\n", cell.id);
printf("\t-s subframe [Default %d]\n", subframe);
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");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "csNnv")) != -1) {
while ((opt = getopt(argc, argv, "csNnqv")) != -1) {
switch(opt) {
case 's':
subframe = atoi(argv[optind]);
@ -65,6 +67,9 @@ void parse_args(int argc, char **argv) {
case 'c':
cell.id = atoi(argv[optind]);
break;
case 'q':
test_cqi_only = true;
break;
case 'v':
srslte_verbose++;
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) {
srslte_pucch_t pucch;
srslte_pucch_cfg_t pucch_cfg;
@ -87,6 +145,10 @@ int main(int argc, char **argv) {
parse_args(argc,argv);
if (test_cqi_only) {
return test_uci_cqi_pucch();
}
if (srslte_pucch_init(&pucch)) {
fprintf(stderr, "Error creating PDSCH object\n");
exit(-1);

@ -252,7 +252,7 @@ int main(int argc, char **argv) {
}
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);
get_time_interval(t);
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) {
uint8_t word[16];
uint32_t nwords = 16;
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_s[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B*sizeof(int16_t));
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++) {
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));
uint8_t *ptr = word;
srslte_bit_unpack(w, &ptr, 4);
srslte_uci_encode_cqi_pucch(word, 4, q->cqi_table[w]);
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;
srslte_bit_unpack(w, &ptr, SRSLTE_UCI_MAX_CQI_LEN_PUCCH);
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++) {
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) {
uint32_t nwords = 16;
uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH;
for (uint32_t w=0;w<nwords;w++) {
if (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);
free(q->cqi_table_s);
}
/* 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
*/
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 &&
cqi_data != NULL)
{
uint32_t max_w = 0;
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
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
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);
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
* Currently only supporting 1-bit HARQ
*/
#ifndef MIMO_ENB
static int32_t decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos)
static int32_t decode_ri_ack_1bit(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos)
{
uint32_t p0 = pos[0].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);
}
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) {
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])
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])
{
uint32_t p0 = pos[Qm * 0 + 0].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;
}
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 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
/* Encode UCI ACK/RI bits as described in 5.2.2.6 of 36.212
* Currently only supporting 1-bit RI
*/
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,
srslte_uci_bit_t *ack_bits)
{
srslte_uci_bit_t *bits, bool ack_ri) {
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);
uint32_t Qprime = Q_prime_ri_ack(cfg, data_len, O_cqi, beta);
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++) {
uci_ulsch_interleave_ack_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]);
uci_ulsch_interleave_put(&q_encoded_bits[(i*cfg->grant.Qm)%nof_encoded_bits], cfg->grant.Qm, &ack_bits[cfg->grant.Qm*i]);
for (uint32_t i = 0; i < Qprime; i++) {
if (ack_ri) {
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;
}
/* 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
*/
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,
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) {
fprintf(stderr, "Error beta is reserved\n");
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++) {
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 ((i % 3 == 0) && i > 0) {
//decode_ri_ack(q_bits, &c_seq[0], &ri_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, ri_sum);
}
}
for (uint32_t i = 0; i < Qprime; i++) {
if (is_ri) {
uci_ulsch_interleave_ri_gen(i,
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);
}
return (int) Qprime;
}
/* 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;
if (nof_bits == 2 && (i % 3 == 0) && i > 0) {
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]);
}
}
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++) {
uci_ulsch_interleave_ri_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]);
uci_ulsch_interleave_put(&q_encoded_bits[(i*cfg->grant.Qm)%nof_encoded_bits], cfg->grant.Qm, &ri_bits[cfg->grant.Qm*i]);
data[0] = (uint8_t) (sum[0] > 0);
if (nof_bits == 2) {
data[1] = (uint8_t) (sum[1] > 0);
}
return (int) Qprime;
}

@ -99,11 +99,7 @@ const char* srslte_rf_get_devname(srslte_rf_t *rf) {
return ((rf_dev_t*) rf->dev)->name;
}
int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args) {
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) {
int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args, uint32_t nof_channels) {
/* Try to open the device if name is provided */
if (devname) {
if (devname[0] != '\0') {
@ -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)
{
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)

@ -725,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) */
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;
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_pmi = (uint8_t) q->pmi[nof_layers - 1];
best_ri = (uint8_t) (nof_layers - 1);
@ -740,6 +741,7 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo
}
/* Set RI */
q->ri = best_ri;
if (ri != NULL) {
*ri = best_ri;
}
@ -775,9 +777,10 @@ int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, uint8_t *ri, float *cn) {
*cn = _cn;
}
q->ri = (uint8_t)((_cn < 17.0f)? 1:0);
/* Set rank indicator */
if (!ret && ri) {
*ri = (uint8_t)((_cn < 17.0f)? 1:0);
*ri = (uint8_t) q->ri;
}
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 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) {
pucch_bits[0] = uci_data->uci_ack;
pucch_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 1a
}
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 */
memcpy(&uci_data->uci_cqi[uci_data->uci_cqi_len], uci_data->uci_dif_cqi, uci_data->uci_dif_cqi_len);
uci_data->uci_cqi_len += uci_data->uci_dif_cqi_len;
memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_dif_cqi, uci_data->uci_dif_cqi_len);
uci_buffer_len += uci_data->uci_dif_cqi_len;
/* Append PMI */
memcpy(&uci_data->uci_cqi[uci_data->uci_cqi_len], uci_data->uci_pmi, uci_data->uci_pmi_len);
uci_data->uci_cqi_len += uci_data->uci_pmi_len;
srslte_uci_encode_cqi_pucch(uci_data->uci_cqi, uci_data->uci_cqi_len, pucch_bits);
memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_pmi, uci_data->uci_pmi_len);
uci_buffer_len += uci_data->uci_pmi_len;
}
srslte_uci_encode_cqi_pucch(uci_buffer, uci_buffer_len, pucch_bits);
if (format > SRSLTE_PUCCH_FORMAT_2) {
pucch2_bits[0] = uci_data->uci_ack;
pucch2_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 2a

@ -34,9 +34,9 @@ extern "C" {
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");
return false;
}
@ -69,6 +69,7 @@ bool radio::init(char *args, char *devname)
if (devname) {
strncpy(saved_devname, devname, 127);
}
saved_nof_channels = nof_channels;
return true;
}
@ -83,7 +84,7 @@ void radio::reset()
printf("Resetting Radio...\n");
srslte_rf_close(&rf_device);
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");
}
}
@ -138,9 +139,9 @@ bool radio::rx_at(void* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time
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) {
return true;
} else {
@ -187,10 +188,18 @@ bool radio::is_first_of_burst() {
#define BLOCKING_TX true
bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time)
{
void *iq_samples[4] = {(void *) zeros, (void *) zeros, (void *) zeros, (void *) zeros};
bool radio::tx_single(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) {
void *_buffer[SRSLTE_MAX_PORTS];
_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) {
srslte_timestamp_sub(&tx_time, 0, tx_adv_sec);
} 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_sub(&tx_time_pad, 0, burst_preamble_time_rounded);
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;
}
}
@ -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);
save_trace(0, &tx_time);
iq_samples[0] = buffer;
int ret = srslte_rf_send_timed_multi(&rf_device, (void**) iq_samples, nof_samples,
int ret = srslte_rf_send_timed_multi(&rf_device, buffer, nof_samples,
tx_time.full_secs, tx_time.frac_secs,
BLOCKING_TX, is_start_of_burst, false);
is_start_of_burst = false;

@ -4,7 +4,7 @@ namespace srslte {
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");
return false;
}

@ -66,6 +66,8 @@ typedef struct {
s1ap_args_t s1ap;
uint32_t n_prb;
uint32_t pci;
uint32_t nof_ports;
uint32_t transmission_mode;
}enb_args_t;
typedef struct {

@ -72,9 +72,13 @@ public:
int sr_detected(uint32_t tti, uint16_t rnti);
int rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv);
int set_dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dl_ant_info);
int ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value);
int pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value);
int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value);
int snr_info(uint32_t tti, uint16_t rnti, float snr);
int ack_info(uint32_t tti, uint16_t rnti, bool ack);
int ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack);
int crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc_res);
int get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res);

@ -44,6 +44,8 @@ struct mac_metrics_t
int ul_buffer;
int dl_buffer;
float dl_cqi;
float dl_ri;
float dl_pmi;
float phr;
};

@ -103,8 +103,11 @@ public:
int dl_rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue);
int dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code);
int dl_ack_info(uint32_t tti, uint16_t rnti, bool ack);
int dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dedicated);
int dl_ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack);
int dl_rach_info(uint32_t tti, uint32_t ra_id, uint16_t rnti, uint32_t estimated_size);
int dl_ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value);
int dl_pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value);
int dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value);
int ul_crc_info(uint32_t tti, uint16_t rnti, bool crc);

@ -38,50 +38,50 @@ class harq_proc
public:
void config(uint32_t id, uint32_t max_retx, srslte::log* log_h);
void set_max_retx(uint32_t max_retx);
void reset();
void reset(uint32_t tb_idx);
uint32_t get_id();
bool is_empty();
bool is_empty(uint32_t tb_idx);
void new_retx(uint32_t tti, int *mcs, int *tbs);
void new_retx(uint32_t tb_idx, uint32_t tti, int *mcs, int *tbs);
bool get_ack();
void set_ack(bool ack);
bool get_ack(uint32_t tb_idx);
void set_ack(uint32_t tb_idx, bool ack);
uint32_t nof_tx();
uint32_t nof_retx();
uint32_t nof_tx(uint32_t tb_idx);
uint32_t nof_retx(uint32_t tb_idx);
uint32_t get_tti();
bool get_ndi();
bool get_ndi(uint32_t tb_idx);
protected:
void new_tx_common(uint32_t tti, int mcs, int tbs);
bool has_pending_retx_common();
void new_tx_common(uint32_t tb_idx, uint32_t tti, int mcs, int tbs);
bool has_pending_retx_common(uint32_t tb_idx);
bool ack;
bool active;
bool ndi;
bool ack[SRSLTE_MAX_TB];
bool active[SRSLTE_MAX_TB];
bool ndi[SRSLTE_MAX_TB];
uint32_t id;
uint32_t max_retx;
uint32_t n_rtx;
uint32_t tx_cnt;
uint32_t n_rtx[SRSLTE_MAX_TB];
uint32_t tx_cnt[SRSLTE_MAX_TB];
int tti;
int last_mcs;
int last_tbs;
int last_mcs[SRSLTE_MAX_TB];
int last_tbs[SRSLTE_MAX_TB];
srslte::log* log_h;
private:
bool ack_received;
bool ack_received[SRSLTE_MAX_TB];
};
class dl_harq_proc : public harq_proc
{
public:
void new_tx(uint32_t tti, int mcs, int tbs, uint32_t n_cce);
void new_tx(uint32_t tb_idx, uint32_t tti, int mcs, int tbs, uint32_t n_cce);
uint32_t get_rbgmask();
void set_rbgmask(uint32_t new_mask);
bool has_pending_retx(uint32_t tti);
int get_tbs();
bool has_pending_retx(uint32_t tb_idx, uint32_t tti);
int get_tbs(uint32_t tb_idx);
uint32_t get_n_cce();
private:
uint32_t rbgmask;

@ -68,9 +68,12 @@ public:
void ul_phr(int phr);
void mac_buffer_state(uint32_t ce_code);
void ul_recv_len(uint32_t lcid, uint32_t len);
void set_dl_ant_info(LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dedicated);
void set_ul_cqi(uint32_t tti, uint32_t cqi, uint32_t ul_ch_code);
void set_dl_ri(uint32_t tti, uint32_t ri);
void set_dl_pmi(uint32_t tti, uint32_t ri);
void set_dl_cqi(uint32_t tti, uint32_t cqi);
int set_ack_info(uint32_t tti, bool ack);
int set_ack_info(uint32_t tti, uint32_t tb_idx, bool ack);
void set_ul_crc(uint32_t tti, bool crc_res);
/*******************************************************
@ -107,8 +110,11 @@ public:
void unset_sr();
int generate_format1(dl_harq_proc *h, sched_interface::dl_sched_data_t *data, uint32_t tti, uint32_t cfi);
int generate_format2a(dl_harq_proc *h, sched_interface::dl_sched_data_t *data, uint32_t tti, uint32_t cfi);
int generate_format2(dl_harq_proc *h, sched_interface::dl_sched_data_t *data, uint32_t tti, uint32_t cfi);
int generate_format0(ul_harq_proc *h, sched_interface::ul_sched_data_t *data, uint32_t tti, bool cqi_request);
srslte_dci_format_t get_dci_format();
uint32_t get_aggr_level(uint32_t nof_bits);
sched_dci_cce_t *get_locations(uint32_t current_cfi, uint32_t sf_idx);
@ -155,6 +161,10 @@ private:
ue_bearer_t lch[sched_interface::MAX_LC];
int power_headroom;
uint32_t dl_ri;
uint32_t dl_ri_tti;
uint32_t dl_pmi;
uint32_t dl_pmi_tti;
uint32_t dl_cqi;
uint32_t dl_cqi_tti;
uint32_t cqi_request_tti;
@ -177,6 +187,7 @@ private:
ul_harq_proc ul_harq[SCHED_MAX_HARQ_PROC];
bool phy_config_dedicated_enabled;
LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT dl_ant_info;
};

@ -75,7 +75,7 @@ public:
uint8_t* generate_pdu(sched_interface::dl_sched_pdu_t pdu[sched_interface::MAX_RLC_PDU_LIST],
uint32_t nof_pdu_elems, uint32_t grant_size);
srslte_softbuffer_tx_t* get_tx_softbuffer(uint32_t harq_process);
srslte_softbuffer_tx_t* get_tx_softbuffer(uint32_t harq_process, uint32_t tb_idx);
srslte_softbuffer_rx_t* get_rx_softbuffer(uint32_t tti);
bool process_pdus();
@ -93,6 +93,8 @@ public:
void metrics_rx(bool crc, uint32_t tbs);
void metrics_tx(bool crc, uint32_t tbs);
void metrics_phr(float phr);
void metrics_dl_ri(uint32_t dl_cqi);
void metrics_dl_pmi(uint32_t dl_cqi);
void metrics_dl_cqi(uint32_t dl_cqi);
@ -108,6 +110,8 @@ private:
uint32_t phr_counter;
uint32_t dl_cqi_counter;
uint32_t dl_ri_counter;
uint32_t dl_pmi_counter;
mac_metrics_t metrics;
srslte::mac_pcap* pcap;
@ -120,7 +124,7 @@ private:
uint32_t nof_failures;
const static int NOF_HARQ_PROCESSES = 2*HARQ_DELAY_MS;
const static int NOF_HARQ_PROCESSES = 2 * HARQ_DELAY_MS * SRSLTE_MAX_TB;
srslte_softbuffer_tx_t softbuffer_tx[NOF_HARQ_PROCESSES];
srslte_softbuffer_rx_t softbuffer_rx[NOF_HARQ_PROCESSES];

@ -65,7 +65,7 @@ public:
void set_nof_mutex(uint32_t nof_mutex);
void worker_end(uint32_t tx_mutex_cnt, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
void worker_end(uint32_t tx_mutex_cnt, cf_t *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time);
// Common objects
srslte_cell_t cell;
@ -83,7 +83,7 @@ public:
// Map of pending ACKs for each user
typedef struct {
bool is_pending[TTIMOD_SZ];
bool is_pending[TTIMOD_SZ][SRSLTE_MAX_TB];
uint16_t n_pdcch[TTIMOD_SZ];
} pending_ack_t;
std::map<uint16_t,pending_ack_t> pending_ack;
@ -91,8 +91,8 @@ public:
void ack_add_rnti(uint16_t rnti);
void ack_rem_rnti(uint16_t rnti);
void ack_clear(uint32_t sf_idx);
void ack_set_pending(uint32_t sf_idx, uint16_t rnti, uint32_t n_pdcch);
bool ack_is_pending(uint32_t sf_idx, uint16_t rnti, uint32_t *last_n_pdcch = NULL);
void ack_set_pending(uint32_t sf_idx, uint16_t rnti, uint32_t tb_idx, uint32_t n_pdcch);
bool ack_is_pending(uint32_t sf_idx, uint16_t rnti, uint32_t tb_idx, uint32_t *last_n_pdcch = NULL);
private:
std::vector<pthread_mutex_t> tx_mutex;

@ -45,7 +45,7 @@ public:
void stop();
void reset();
cf_t *get_buffer_rx();
cf_t *get_buffer_rx(uint32_t antenna_idx);
void set_time(uint32_t tti, uint32_t tx_mutex_cnt, srslte_timestamp_t tx_time);
int add_rnti(uint16_t rnti);
@ -57,12 +57,14 @@ public:
int read_pusch_d(cf_t *pusch_d);
void start_plot();
void set_conf_dedicated_ack(uint16_t rnti,
bool rrc_completed);
void set_config_dedicated(uint16_t rnti,
srslte_uci_cfg_t *uci_cfg,
srslte_pucch_sched_t *pucch_sched,
srslte_refsignal_srs_cfg_t *srs_cfg,
uint32_t I_sr, bool pucch_cqi, uint32_t pmi_idx, bool pucch_cqi_ack);
LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated);
uint32_t get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]);
@ -87,7 +89,7 @@ private:
bool initiated;
bool running;
cf_t *signal_buffer_rx;
cf_t *signal_buffer_rx[SRSLTE_MAX_PORTS];
cf_t *signal_buffer_tx[SRSLTE_MAX_PORTS];
uint32_t tti_rx, tti_tx_dl, tti_tx_ul;
uint32_t sf_rx, sf_tx, tx_mutex_cnt;
@ -100,13 +102,18 @@ private:
// Class to store user information
class ue {
public:
ue() : I_sr(0), I_sr_en(false), cqi_en(false), pucch_cqi_ack(false), pmi_idx(0), has_grant_tti(0) {bzero(&metrics, sizeof(phy_metrics_t));}
ue() : I_sr(0), I_sr_en(false), cqi_en(false), pucch_cqi_ack(false), pmi_idx(0), has_grant_tti(0),
dedicated_ack(false) {bzero(&metrics, sizeof(phy_metrics_t));}
uint32_t I_sr;
uint32_t pmi_idx;
uint32_t ri_idx;
bool I_sr_en;
bool cqi_en;
bool ri_en;
bool pucch_cqi_ack;
int has_grant_tti;
LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT dedicated;
bool dedicated_ack;
uint32_t rnti;
srslte_enb_ul_phich_info_t phich_info;
void metrics_read(phy_metrics_t *metrics);

@ -66,6 +66,7 @@ public:
static uint32_t tti_to_subf(uint32_t tti);
void start_plot();
void set_conf_dedicated_ack(uint16_t rnti, bool dedicated_ack);
void set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated);
void get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]);

@ -79,6 +79,7 @@ typedef struct {
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_STRUCT sibs[LIBLTE_RRC_MAX_SIB];
LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT mac_cnfg;
LIBLTE_RRC_PUSCH_CONFIG_DEDICATED_STRUCT pusch_cfg;
LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT antenna_info;
rrc_cfg_sr_t sr_cfg;
rrc_cfg_cqi_t cqi_cfg;
rrc_cfg_qci_t qci_cfg[MAX_NOF_QCI];

@ -136,7 +136,7 @@ bool enb::init(all_args_t *args_)
dev_args = (char*) args->rf.device_args.c_str();
}
if(!radio.init(dev_args, dev_name))
if(!radio.init(dev_args, dev_name, args->enb.nof_ports))
{
printf("Failed to find device %s with args %s\n",
args->rf.device_name.c_str(), args->rf.device_args.c_str());

@ -37,7 +37,7 @@ namespace srsenb {
int enb::parse_cell_cfg(all_args_t *args, srslte_cell_t *cell) {
cell->id = args->enb.pci;
cell->cp = SRSLTE_CP_NORM;
cell->nof_ports = 1;
cell->nof_ports = args->enb.nof_ports;
cell->nof_prb = args->enb.n_prb;
LIBLTE_RRC_PHICH_CONFIG_STRUCT phichcfg;
@ -842,6 +842,30 @@ bool enb::sib_is_present(LIBLTE_RRC_SCHEDULING_INFO_STRUCT *sched_info, uint32_t
int enb::parse_rr(all_args_t* args, rrc_cfg_t* rrc_cfg)
{
/* Transmission mode config section */
if (args->enb.transmission_mode < 0 || args->enb.transmission_mode > LIBLTE_RRC_TRANSMISSION_MODE_N_ITEMS) {
ERROR("Invalid transmission mode (%d). Only indexes 1-4 are implemented.\n", args->enb.transmission_mode);
return SRSLTE_ERROR;
}
bzero(&rrc_cfg->antenna_info, sizeof(LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT));
rrc_cfg->antenna_info.tx_mode = (LIBLTE_RRC_TRANSMISSION_MODE_ENUM) (args->enb.transmission_mode - 1);
if (rrc_cfg->antenna_info.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3) {
rrc_cfg->antenna_info.ue_tx_antenna_selection_setup = LIBLTE_RRC_UE_TX_ANTENNA_SELECTION_OPEN_LOOP;
rrc_cfg->antenna_info.ue_tx_antenna_selection_setup_present = true;
rrc_cfg->antenna_info.codebook_subset_restriction_choice = LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM3;
} else if (rrc_cfg->antenna_info.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) {
rrc_cfg->antenna_info.ue_tx_antenna_selection_setup = LIBLTE_RRC_UE_TX_ANTENNA_SELECTION_CLOSED_LOOP;
rrc_cfg->antenna_info.ue_tx_antenna_selection_setup_present = true;
rrc_cfg->antenna_info.codebook_subset_restriction_choice = LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM4;
rrc_cfg->antenna_info.codebook_subset_restriction = 0b111111;
rrc_cfg->antenna_info.codebook_subset_restriction_present = true;
}
/* MAC config section */
parser::section mac_cnfg("mac_cnfg");

@ -262,10 +262,10 @@ void mac::rl_ok(uint16_t rnti)
}
}
int mac::ack_info(uint32_t tti, uint16_t rnti, bool ack)
int mac::ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack)
{
log_h->step(tti);
uint32_t nof_bytes = scheduler.dl_ack_info(tti, rnti, ack);
uint32_t nof_bytes = scheduler.dl_ack_info(tti, rnti, tb_idx, ack);
ue_db[rnti]->metrics_tx(ack, nof_bytes);
if (ack) {
@ -305,6 +305,46 @@ int mac::crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc)
}
}
int mac::set_dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dl_ant_info) {
log_h->step(tti);
if (ue_db.count(rnti)) {
scheduler.dl_ant_info(rnti, dl_ant_info);
} else {
Error("User rnti=0x%x not found\n", rnti);
return -1;
}
return 0;
}
int mac::ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value)
{
log_h->step(tti);
if (ue_db.count(rnti)) {
scheduler.dl_ri_info(tti, rnti, ri_value);
ue_db[rnti]->metrics_dl_ri(ri_value);
} else {
Error("User rnti=0x%x not found\n", rnti);
return -1;
}
return 0;
}
int mac::pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value)
{
log_h->step(tti);
if (ue_db.count(rnti)) {
scheduler.dl_pmi_info(tti, rnti, pmi_value);
ue_db[rnti]->metrics_dl_pmi(pmi_value);
} else {
Error("User rnti=0x%x not found\n", rnti);
return -1;
}
return 0;
}
int mac::cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value)
{
log_h->step(tti);
@ -431,23 +471,33 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
// Copy grant info
dl_sched_res->sched_grants[n].rnti = rnti;
dl_sched_res->sched_grants[n].dci_format = sched_result.data[i].dci_format;
memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.data[i].dci, sizeof(srslte_ra_dl_dci_t));
memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.data[i].dci_location, sizeof(srslte_dci_location_t));
dl_sched_res->sched_grants[n].softbuffer = ue_db[rnti]->get_tx_softbuffer(sched_result.data[i].dci.harq_process);
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
dl_sched_res->sched_grants[n].softbuffers[tb] =
ue_db[rnti]->get_tx_softbuffer(sched_result.data[i].dci.harq_process, tb);
if (sched_result.data[i].nof_pdu_elems[tb] > 0) {
/* Get PDU if it's a new transmission */
dl_sched_res->sched_grants[n].data[tb] = ue_db[rnti]->generate_pdu(sched_result.data[i].pdu[tb],
sched_result.data[i].nof_pdu_elems[tb],
sched_result.data[i].tbs[tb]);
// Get PDU if it's a new transmission
if (sched_result.data[i].nof_pdu_elems > 0) {
dl_sched_res->sched_grants[n].data = ue_db[rnti]->generate_pdu(sched_result.data[i].pdu,
sched_result.data[i].nof_pdu_elems,
sched_result.data[i].tbs);
if (!dl_sched_res->sched_grants[n].data[tb]) {
Error("Error! PDU was not generated (rnti=0x%04x, tb=%d)\n", rnti, tb);
sched_result.data[i].dci.tb_en[tb] = false;
}
if (pcap) {
pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data, sched_result.data[i].tbs, rnti, true, tti);
pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data[tb], sched_result.data[i].tbs[tb], rnti, true, tti);
}
} else {
dl_sched_res->sched_grants[n].data = NULL;
/* TB not enabled OR no data to send: set pointers to NULL */
dl_sched_res->sched_grants[n].data[tb] = NULL;
}
}
n++;
}
@ -456,18 +506,19 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
for (uint32_t i=0;i<sched_result.nof_rar_elems;i++) {
// Copy grant info
dl_sched_res->sched_grants[n].rnti = sched_result.rar[i].rarnti;
dl_sched_res->sched_grants[n].dci_format = SRSLTE_DCI_FORMAT1A; // Force Format 1A
memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.rar[i].dci, sizeof(srslte_ra_dl_dci_t));
memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.rar[i].dci_location, sizeof(srslte_dci_location_t));
// Set softbuffer (there are no retx in RAR but a softbuffer is required)
dl_sched_res->sched_grants[n].softbuffer = &rar_softbuffer_tx;
dl_sched_res->sched_grants[n].softbuffers[0] = &rar_softbuffer_tx;
// Assemble PDU
dl_sched_res->sched_grants[n].data = assemble_rar(sched_result.rar[i].grants, sched_result.rar[i].nof_grants, i, sched_result.rar[i].tbs);
dl_sched_res->sched_grants[n].data[0] = assemble_rar(sched_result.rar[i].grants, sched_result.rar[i].nof_grants, i, sched_result.rar[i].tbs);
if (pcap) {
pcap->write_dl_ranti(dl_sched_res->sched_grants[n].data, sched_result.data[i].tbs, dl_sched_res->sched_grants[n].rnti, true, tti);
pcap->write_dl_ranti(dl_sched_res->sched_grants[n].data[0], sched_result.data[i].tbs[0], dl_sched_res->sched_grants[n].rnti, true, tti);
}
n++;
@ -477,25 +528,26 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
for (uint32_t i=0;i<sched_result.nof_bc_elems;i++) {
// Copy grant info
dl_sched_res->sched_grants[n].rnti = (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH ) ? SRSLTE_SIRNTI : SRSLTE_PRNTI;
dl_sched_res->sched_grants[n].dci_format = SRSLTE_DCI_FORMAT1A; // Force Format 1A
memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.bc[i].dci, sizeof(srslte_ra_dl_dci_t));
memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.bc[i].dci_location, sizeof(srslte_dci_location_t));
// Set softbuffer
if (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH) {
dl_sched_res->sched_grants[n].softbuffer = &bcch_softbuffer_tx[sched_result.bc[i].index];
dl_sched_res->sched_grants[n].data = assemble_si(sched_result.bc[i].index);
dl_sched_res->sched_grants[n].softbuffers[0] = &bcch_softbuffer_tx[sched_result.bc[i].index];
dl_sched_res->sched_grants[n].data[0] = assemble_si(sched_result.bc[i].index);
#ifdef WRITE_SIB_PCAP
if (pcap) {
pcap->write_dl_sirnti(dl_sched_res->sched_grants[n].data, sched_result.bc[i].tbs, true, tti);
}
#endif
} else {
dl_sched_res->sched_grants[n].softbuffer = &pcch_softbuffer_tx;
dl_sched_res->sched_grants[n].data = pcch_payload_buffer;
dl_sched_res->sched_grants[n].softbuffers[0] = &pcch_softbuffer_tx;
dl_sched_res->sched_grants[n].data[0] = pcch_payload_buffer;
rlc_h->read_pdu_pcch(pcch_payload_buffer, pcch_payload_buffer_len);
if (pcap) {
pcap->write_dl_pch(dl_sched_res->sched_grants[n].data, sched_result.bc[i].tbs, true, tti);
pcap->write_dl_pch(dl_sched_res->sched_grants[n].data[0], sched_result.bc[i].tbs, true, tti);
}
}

@ -238,12 +238,25 @@ int sched::dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code)
return ret;
}
int sched::dl_ack_info(uint32_t tti, uint16_t rnti, bool ack)
int sched::dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dl_ant_info) {
pthread_mutex_lock(&mutex);
int ret = 0;
if (ue_db.count(rnti)) {
ue_db[rnti].set_dl_ant_info(dl_ant_info);
} else {
Error("User rnti=0x%x not found\n", rnti);
ret = -1;
}
pthread_mutex_unlock(&mutex);
return ret;
}
int sched::dl_ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack)
{
pthread_mutex_lock(&mutex);
int ret = 0;
if (ue_db.count(rnti)) {
ret = ue_db[rnti].set_ack_info(tti, ack);
ret = ue_db[rnti].set_ack_info(tti, tb_idx, ack);
} else {
Error("User rnti=0x%x not found\n", rnti);
ret = -1;
@ -266,6 +279,34 @@ int sched::ul_crc_info(uint32_t tti, uint16_t rnti, bool crc)
return ret;
}
int sched::dl_ri_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value)
{
pthread_mutex_lock(&mutex);
int ret = 0;
if (ue_db.count(rnti)) {
ue_db[rnti].set_dl_ri(tti, cqi_value);
} else {
Error("User rnti=0x%x not found\n", rnti);
ret = -1;
}
pthread_mutex_unlock(&mutex);
return ret;
}
int sched::dl_pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value)
{
pthread_mutex_lock(&mutex);
int ret = 0;
if (ue_db.count(rnti)) {
ue_db[rnti].set_dl_pmi(tti, pmi_value);
} else {
Error("User rnti=0x%x not found\n", rnti);
ret = -1;
}
pthread_mutex_unlock(&mutex);
return ret;
}
int sched::dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value)
{
pthread_mutex_lock(&mutex);
@ -597,6 +638,8 @@ int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST])
uint16_t rnti = (uint16_t) iter->first;
dl_harq_proc *h = dl_metric->get_user_allocation(user);
srslte_dci_format_t dci_format = user->get_dci_format();
data[nof_data_elems].dci_format = dci_format;
uint32_t aggr_level = user->get_aggr_level(srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1, cfg.cell.nof_prb, cfg.cell.nof_ports));
if (h) {
@ -605,13 +648,27 @@ int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST])
user->get_locations(current_cfi, sf_idx),
aggr_level, user))
{
bool is_newtx = h->is_empty();
int tbs = user->generate_format1(h, &data[nof_data_elems], current_tti, current_cfi);
bool is_newtx = h->is_empty(0);
int tbs = 0;
switch(dci_format) {
case SRSLTE_DCI_FORMAT1:
tbs = user->generate_format1(h, &data[nof_data_elems], current_tti, current_cfi);
break;
case SRSLTE_DCI_FORMAT2:
tbs = user->generate_format2(h, &data[nof_data_elems], current_tti, current_cfi);
break;
case SRSLTE_DCI_FORMAT2A:
tbs = user->generate_format2a(h, &data[nof_data_elems], current_tti, current_cfi);
break;
default:
Error("DCI format (%d) not implemented\n", dci_format);
}
if (tbs >= 0) {
log_h->info("SCHED: DL %s rnti=0x%x, pid=%d, mask=0x%x, dci=%d,%d, n_rtx=%d, tbs=%d, buffer=%d\n",
log_h->info("SCHED: DL %s rnti=0x%x, pid=%d, mask=0x%x, dci=%d,%d, n_rtx=%d, tbs=%d, buffer=%d, tb_en={%s,%s}\n",
!is_newtx?"retx":"tx", rnti, h->get_id(), h->get_rbgmask(),
data[nof_data_elems].dci_location.L, data[nof_data_elems].dci_location.ncce, h->nof_retx(),
tbs, user->get_pending_dl_new_data(current_tti));
data[nof_data_elems].dci_location.L, data[nof_data_elems].dci_location.ncce, h->nof_retx(0) + h->nof_retx(1),
tbs, user->get_pending_dl_new_data(current_tti), data[nof_data_elems].dci.tb_en[0]?"y":"n",
data[nof_data_elems].dci.tb_en[1]?"y":"n");
nof_data_elems++;
} else {
log_h->warning("SCHED: Error DL %s rnti=0x%x, pid=%d, mask=0x%x, dci=%d,%d, tbs=%d, buffer=%d\n",
@ -620,9 +677,10 @@ int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST])
tbs, user->get_pending_dl_new_data(current_tti));
}
} else {
h->reset();
Warning("SCHED: Could not schedule DL DCI for rnti=0x%x, pid=%d, L=%d, nof_candidates=%d\n",
rnti, h->get_id(), aggr_level, user->get_locations(current_cfi, sf_idx)->nof_loc[aggr_level] );
for(uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
h->reset(tb);
}
Warning("SCHED: Could not schedule DL DCI for rnti=0x%x, pid=%d\n", rnti, h->get_id());
}
}
}
@ -709,7 +767,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
/* Indicate PHICH acknowledgment if needed */
if (h->has_pending_ack()) {
sched_result->phich[nof_phich_elems].phich = h->get_ack()?ul_sched_phich_t::ACK:ul_sched_phich_t::NACK;
sched_result->phich[nof_phich_elems].phich = h->get_ack(0)?ul_sched_phich_t::ACK:ul_sched_phich_t::NACK;
sched_result->phich[nof_phich_elems].rnti = rnti;
nof_phich_elems++;
}
@ -766,8 +824,8 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
if (h)
{
ul_harq_proc::ul_alloc_t alloc = h->get_alloc();
bool is_newtx = h->is_empty();
bool needs_pdcch = h->is_adaptive_retx() && !is_rar;
bool is_newtx = h->is_empty(0);
bool needs_pdcch = !h->is_adaptive_retx() && !is_rar;
// Set number of retx
if (is_newtx) {
@ -785,7 +843,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
user->get_locations(current_cfi, sf_idx),
aggr_level))
{
h->reset();
h->reset(0);
log_h->warning("SCHED: Could not schedule UL DCI rnti=0x%x, pid=%d, L=%d\n",
rnti, h->get_id(), aggr_level);
sched_result->pusch[nof_dci_elems].needs_pdcch = false;
@ -812,7 +870,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
is_newtx?"tx":"retx",
rnti, h->get_id(),
sched_result->pusch[nof_dci_elems].dci_location.L, sched_result->pusch[nof_dci_elems].dci_location.ncce,
alloc.RB_start, alloc.RB_start+alloc.L, h->nof_retx(), sched_result->pusch[nof_dci_elems].tbs,
alloc.RB_start, alloc.RB_start+alloc.L, h->nof_retx(0), sched_result->pusch[nof_dci_elems].tbs,
user->get_pending_ul_new_data(current_tti),pending_data_before, user->get_pending_ul_old_data());
nof_dci_elems++;

@ -50,7 +50,9 @@ void harq_proc::config(uint32_t id_, uint32_t max_retx_, srslte::log* log_h_)
log_h = log_h_;
id = id_;
max_retx = max_retx_;
ndi = false;
for (int i = 0; i < SRSLTE_MAX_TB; i++) {
ndi[i] = false;
}
}
void harq_proc::set_max_retx(uint32_t max_retx_) {
@ -63,101 +65,101 @@ uint32_t harq_proc::get_id()
return id;
}
void harq_proc::reset()
void harq_proc::reset(uint32_t tb_idx)
{
active = false;
ack = true;
ack_received = false;
n_rtx = 0;
active[tb_idx] = false;
ack[tb_idx] = true;
ack_received[tb_idx] = false;
n_rtx[tb_idx] = 0;
tti = 0;
last_mcs = -1;
last_tbs = -1;
tx_cnt = 0;
last_mcs[tb_idx] = -1;
last_tbs[tb_idx] = -1;
tx_cnt[tb_idx] = 0;
}
bool harq_proc::is_empty()
bool harq_proc::is_empty(uint32_t tb_idx)
{
return !active || (active && ack && ack_received);
return !active[tb_idx] || (active[tb_idx] && ack[tb_idx] && ack_received[tb_idx]);
}
bool harq_proc::has_pending_retx_common()
bool harq_proc::has_pending_retx_common(uint32_t tb_idx)
{
return !ack && n_rtx < max_retx;
return !ack[tb_idx] && n_rtx[tb_idx] < max_retx;
}
uint32_t harq_proc::get_tti()
{
return tti;
return (uint32_t) tti;
}
bool harq_proc::get_ack()
bool harq_proc::get_ack(uint32_t tb_idx)
{
return ack;
return ack[tb_idx];
}
void harq_proc::set_ack(bool ack_)
void harq_proc::set_ack(uint32_t tb_idx, bool ack_)
{
ack = ack_;
ack_received = true;
log_h->debug("ACK=%d received pid=%d, n_rtx=%d, max_retx=%d\n", ack_, id, n_rtx, max_retx);
if (n_rtx + 1 >= max_retx) {
Warning("SCHED: discarting TB pid=%d, tti=%d, maximum number of retx exceeded (%d)\n", id, tti, max_retx);
active = false;
ack[tb_idx] = ack_;
ack_received[tb_idx] = true;
log_h->debug("ACK=%d received pid=%d, tb_idx=%d, n_rtx=%d, max_retx=%d\n", ack_, id, tb_idx, n_rtx[tb_idx], max_retx);
if (n_rtx[tb_idx] + 1 >= max_retx) {
Warning("SCHED: discarting TB %d pid=%d, tti=%d, maximum number of retx exceeded (%d)\n", tb_idx, id, tti, max_retx);
active[tb_idx] = false;
}
}
void harq_proc::new_tx_common(uint32_t tti_, int mcs, int tbs)
void harq_proc::new_tx_common(uint32_t tb_idx, uint32_t tti_, int mcs, int tbs)
{
reset();
ndi = !ndi;
reset(tb_idx);
ndi[tb_idx] = !ndi[tb_idx];
tti = tti_;
tx_cnt++;
last_mcs = mcs;
last_tbs = tbs;
tx_cnt[tb_idx]++;
last_mcs[tb_idx] = mcs;
last_tbs[tb_idx] = tbs;
if (max_retx) {
active = true;
active[tb_idx] = true;
} else {
active = false; // Can reuse this process if no retx are allowed
active[tb_idx] = false; // Can reuse this process if no retx are allowed
}
}
void harq_proc::new_retx(uint32_t tti_, int *mcs, int *tbs)
void harq_proc::new_retx(uint32_t tb_idx, uint32_t tti_, int *mcs, int *tbs)
{
ack_received = false;
ack_received[tb_idx] = false;
tti = tti_;
n_rtx++;
n_rtx[tb_idx]++;
if (mcs) {
*mcs = last_mcs;
*mcs = last_mcs[tb_idx];
}
if (tbs) {
*tbs = last_tbs;
*tbs = last_tbs[tb_idx];
}
}
uint32_t harq_proc::nof_tx()
uint32_t harq_proc::nof_tx(uint32_t tb_idx)
{
return tx_cnt;
return tx_cnt[tb_idx];
}
uint32_t harq_proc::nof_retx()
uint32_t harq_proc::nof_retx(uint32_t tb_idx)
{
return n_rtx;
return n_rtx[tb_idx];
}
bool harq_proc::get_ndi()
bool harq_proc::get_ndi(uint32_t tb_idx)
{
return ndi;
return ndi[tb_idx];
}
/******************************************************
* UE::DL HARQ class *
******************************************************/
void dl_harq_proc::new_tx(uint32_t tti, int mcs, int tbs, uint32_t n_cce_)
void dl_harq_proc::new_tx(uint32_t tb_idx, uint32_t tti, int mcs, int tbs, uint32_t n_cce_)
{
n_cce = n_cce_;
new_tx_common(tti, mcs, tbs);
new_tx_common(tb_idx, tti, mcs, tbs);
}
uint32_t dl_harq_proc::get_n_cce()
@ -175,14 +177,14 @@ void dl_harq_proc::set_rbgmask(uint32_t new_mask)
rbgmask = new_mask;
}
bool dl_harq_proc::has_pending_retx(uint32_t current_tti)
bool dl_harq_proc::has_pending_retx(uint32_t tb_idx, uint32_t current_tti)
{
return srslte_tti_interval(current_tti, tti) >= (2*HARQ_DELAY_MS) && has_pending_retx_common();
return srslte_tti_interval(current_tti, tti) >= (2*HARQ_DELAY_MS) && has_pending_retx_common(tb_idx);
}
int dl_harq_proc::get_tbs()
int dl_harq_proc::get_tbs(uint32_t tb_idx)
{
return last_tbs;
return last_tbs[tb_idx];
}
@ -198,13 +200,13 @@ ul_harq_proc::ul_alloc_t ul_harq_proc::get_alloc()
void ul_harq_proc::set_alloc(ul_harq_proc::ul_alloc_t alloc)
{
is_adaptive = true;
is_adaptive = false;
memcpy(&allocation, &alloc, sizeof(ul_alloc_t));
}
void ul_harq_proc::same_alloc()
{
is_adaptive = false;
is_adaptive = true;
}
bool ul_harq_proc::is_adaptive_retx()
@ -215,7 +217,7 @@ bool ul_harq_proc::is_adaptive_retx()
void ul_harq_proc::new_tx(uint32_t tti_, int mcs, int tbs)
{
need_ack = true;
new_tx_common(tti_, mcs, tbs);
new_tx_common(0, tti_, mcs, tbs);
pending_data = tbs;
}
@ -225,10 +227,10 @@ bool ul_harq_proc::has_pending_ack()
bool ret = need_ack;
// Reset if already received a positive ACK
if (active && ack) {
active = false;
if (active[0] && ack[0]) {
active[0] = false;
}
if (!active) {
if (!active[0]) {
need_ack = false;
}
return ret;
@ -238,14 +240,15 @@ bool ul_harq_proc::has_pending_ack()
void ul_harq_proc::reset_pending_data()
{
if (!active) {
if (!active[0]) {
pending_data = 0;
}
}
uint32_t ul_harq_proc::get_pending_data()
{
return pending_data;
return (uint32_t) pending_data;
}
void ul_harq_proc::set_rar_mcs(uint32_t mcs)

@ -224,7 +224,7 @@ void ul_metric_rr::new_tti(std::map<uint16_t,sched_ue> &ue_db, uint32_t nof_rb_,
nof_users_with_data = 0;
for(std::map<uint16_t, sched_ue>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
sched_ue *user = (sched_ue*) &iter->second;
if (user->get_pending_ul_new_data(current_tti) || !user->get_ul_harq(current_tti)->is_empty()) {
if (user->get_pending_ul_new_data(current_tti) || !user->get_ul_harq(current_tti)->is_empty(0)) {
user->ue_idx = nof_users_with_data;
nof_users_with_data++;
}
@ -296,7 +296,7 @@ ul_harq_proc* ul_metric_rr::get_user_allocation(sched_ue *user)
uint32_t pending_data = user->get_pending_ul_new_data(current_tti);
ul_harq_proc *h = user->get_ul_harq(current_tti);
if (pending_data || !h->is_empty()) {
if (pending_data || !h->is_empty(0)) {
if (nof_users_with_data) {
if ((current_tti%nof_users_with_data) != user->ue_idx) {
return NULL;
@ -306,7 +306,7 @@ ul_harq_proc* ul_metric_rr::get_user_allocation(sched_ue *user)
// Schedule retx if we have space
if (!h->is_empty()) {
if (!h->is_empty(0)) {
ul_harq_proc::ul_alloc_t alloc = h->get_alloc();
@ -325,7 +325,7 @@ ul_harq_proc* ul_metric_rr::get_user_allocation(sched_ue *user)
}
}
// If could not schedule the reTx, or there wasn't any pending retx, find an empty PID
if (h->is_empty()) {
if (h->is_empty(0)) {
// Allocate resources based on pending data
if (pending_data) {
uint32_t pending_rb = user->get_required_prb_ul(pending_data);

@ -104,8 +104,10 @@ void sched_ue::reset()
ul_cqi_tti = 0;
cqi_request_tti = 0;
for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) {
dl_harq[i].reset();
ul_harq[i].reset();
for(uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
dl_harq[i].reset(tb);
ul_harq[i].reset(tb);
}
}
for (int i=0;i<sched_interface::MAX_LC; i++) {
rem_bearer(i);
@ -281,13 +283,13 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2])
return false;
}
int sched_ue::set_ack_info(uint32_t tti, bool ack)
int sched_ue::set_ack_info(uint32_t tti, uint32_t tb_idx, bool ack)
{
for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) {
if (TTI_TX(dl_harq[i].get_tti()) == tti) {
Debug("SCHED: Set ACK=%d for rnti=0x%x, pid=%d, tti=%d\n", ack, rnti, i, tti);
dl_harq[i].set_ack(ack);
return dl_harq[i].get_tbs();
Debug("SCHED: Set ACK=%d for rnti=0x%x, pid=%d.%d, tti=%d\n", ack, rnti, i, tb_idx, tti);
dl_harq[i].set_ack(tb_idx, ack);
return dl_harq[i].get_tbs(tb_idx);
}
}
Warning("SCHED: Received ACK info for unknown TTI=%d\n", tti);
@ -315,7 +317,19 @@ void sched_ue::ul_recv_len(uint32_t lcid, uint32_t len)
void sched_ue::set_ul_crc(uint32_t tti, bool crc_res)
{
get_ul_harq(tti)->set_ack(crc_res);
get_ul_harq(tti)->set_ack(0, crc_res);
}
void sched_ue::set_dl_ri(uint32_t tti, uint32_t ri)
{
dl_ri = ri;
dl_ri_tti = tti;
}
void sched_ue::set_dl_pmi(uint32_t tti, uint32_t pmi)
{
dl_pmi = pmi;
dl_pmi_tti = tti;
}
void sched_ue::set_dl_cqi(uint32_t tti, uint32_t cqi)
@ -324,6 +338,11 @@ void sched_ue::set_dl_cqi(uint32_t tti, uint32_t cqi)
dl_cqi_tti = tti;
}
void sched_ue::set_dl_ant_info(LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *d)
{
memcpy(&dl_ant_info, d, sizeof(LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT));
}
void sched_ue::set_ul_cqi(uint32_t tti, uint32_t cqi, uint32_t ul_ch_code)
{
ul_cqi = cqi;
@ -374,7 +393,7 @@ int sched_ue::generate_format1(dl_harq_proc *h,
if (is_first_dl_tx()) {
need_conres_ce = true;
}
if (h->is_empty()) {
if (h->is_empty(0)) {
uint32_t req_bytes = get_pending_dl_new_data(tti);
@ -390,28 +409,28 @@ int sched_ue::generate_format1(dl_harq_proc *h,
mcs = fixed_mcs_dl;
}
h->new_tx(tti, mcs, tbs, data->dci_location.ncce);
h->new_tx(0, tti, mcs, tbs, data->dci_location.ncce);
// Allocate MAC ConRes CE
if (need_conres_ce) {
data->pdu[0].lcid = srslte::sch_subh::CON_RES_ID;
data->nof_pdu_elems++;
data->pdu[0][0].lcid = srslte::sch_subh::CON_RES_ID;
data->nof_pdu_elems[0]++;
Info("SCHED: Added MAC Contention Resolution CE for rnti=0x%x\n", rnti);
}
int rem_tbs = tbs;
int x = 0;
do {
x = alloc_pdu(rem_tbs, &data->pdu[data->nof_pdu_elems]);
x = alloc_pdu(rem_tbs, &data->pdu[0][data->nof_pdu_elems[0]]);
rem_tbs -= x;
if (x) {
data->nof_pdu_elems++;
data->nof_pdu_elems[0]++;
}
} while(rem_tbs > 0 && x > 0);
Debug("SCHED: Alloc format1 new mcs=%d, tbs=%d, nof_prb=%d, req_bytes=%d\n", mcs, tbs, nof_prb, req_bytes);
} else {
h->new_retx(tti, &mcs, &tbs);
h->new_retx(0, tti, &mcs, &tbs);
Debug("SCHED: Alloc format1 previous mcs=%d, tbs=%d\n", mcs, tbs);
}
@ -419,18 +438,150 @@ int sched_ue::generate_format1(dl_harq_proc *h,
if (tbs > 0) {
dci->harq_process = h->get_id();
dci->mcs_idx = mcs;
dci->rv_idx = sched::get_rvidx(h->nof_retx());
dci->ndi = h->get_ndi();
dci->tpc_pucch = next_tpc_pucch;
dci->mcs_idx = (uint32_t) mcs;
dci->rv_idx = sched::get_rvidx(h->nof_retx(0));
dci->ndi = h->get_ndi(0);
dci->tpc_pucch = (uint8_t) next_tpc_pucch;
next_tpc_pucch = 1;
data->tbs = tbs;
data->tbs[0] = (uint32_t) tbs;
data->tbs[1] = 0;
dci->tb_en[0] = true;
dci->tb_en[1] = false;
}
return tbs;
}
// Generates a Format2a grant
int sched_ue::generate_format2a(dl_harq_proc *h,
sched_interface::dl_sched_data_t *data,
uint32_t tti,
uint32_t cfi)
{
bool tb_en[SRSLTE_MAX_TB] = {false};
srslte_ra_dl_dci_t *dci = &data->dci;
bzero(dci, sizeof(srslte_ra_dl_dci_t));
uint32_t sf_idx = tti%10;
dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0;
dci->type0_alloc.rbg_bitmask = h->get_rbgmask();
uint32_t nof_prb = format1_count_prb(h->get_rbgmask(), cell.nof_prb);
uint32_t nof_ctrl_symbols = cfi + (cell.nof_prb < 10 ? 1 : 0);
srslte_ra_dl_grant_t grant;
srslte_ra_dl_dci_to_grant_prb_allocation(dci, &grant, cell.nof_prb);
uint32_t nof_re = srslte_ra_dl_grant_nof_re(&grant, cell, sf_idx, nof_ctrl_symbols);
uint32_t req_bytes = get_pending_dl_new_data(tti);
if (dl_ri == 0) {
if (h->is_empty(1)) {
/* One layer, tb1 buffer is empty, send tb0 only */
tb_en[0] = true;
} else {
/* One layer, tb1 buffer is not empty, send tb1 only */
tb_en[1] = true;
}
} else {
/* Two layers, retransmit what TBs that have not been Acknowledged */
bool no_retx = true;
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
if (!h->is_empty(tb)) {
tb_en[tb] = true;
no_retx = false;
}
}
/* Two layers, no retransmissions... */
if (no_retx) {
tb_en[0] = true;
tb_en[1] = true;
}
}
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
int mcs = 0;
int tbs = 0;
if (tb_en[tb]) {
if (h->is_empty(tb)) {
if (fixed_mcs_dl < 0) {
tbs = alloc_tbs_dl(nof_prb, nof_re, req_bytes, &mcs);
} else {
tbs = srslte_ra_tbs_from_idx((uint32_t) srslte_ra_tbs_idx_from_mcs((uint32_t) fixed_mcs_dl), nof_prb) / 8;
mcs = fixed_mcs_dl;
}
h->new_tx(tb, tti, mcs, tbs, data->dci_location.ncce);
int rem_tbs = tbs;
int x = 0;
do {
x = alloc_pdu(rem_tbs, &data->pdu[tb][data->nof_pdu_elems[tb]]);
rem_tbs -= x;
if (x) {
data->nof_pdu_elems[tb]++;
}
} while (rem_tbs > 0 && x > 0);
Debug("SCHED: Alloc format2/2a new mcs=%d, tbs=%d, nof_prb=%d, req_bytes=%d\n", mcs, tbs, nof_prb, req_bytes);
} else {
h->new_retx(tb, tti, &mcs, &tbs);
Debug("SCHED: Alloc format2/2a previous mcs=%d, tbs=%d\n", mcs, tbs);
}
}
/* Fill DCI TB dedicated fields */
if (tbs > 0) {
if (tb == 0) {
dci->mcs_idx = (uint32_t) mcs;
dci->rv_idx = sched::get_rvidx(h->nof_retx(tb));
dci->ndi = h->get_ndi(tb);
} else {
dci->mcs_idx_1 = (uint32_t) mcs;
dci->rv_idx_1 = sched::get_rvidx(h->nof_retx(tb));
dci->ndi_1 = h->get_ndi(tb);
}
data->tbs[tb] = (uint32_t) tbs;
dci->tb_en[tb] = true;
} else {
data->tbs[tb] = 0;
dci->tb_en[tb] = false;
}
if ( req_bytes > (uint32_t) tbs) {
req_bytes -= tbs;
} else {
req_bytes = 0;
}
}
/* Fill common fields */
data->rnti = rnti;
dci->harq_process = h->get_id();
dci->tpc_pucch = (uint8_t) next_tpc_pucch;
next_tpc_pucch = 1;
return data->tbs[0] + data->tbs[1];
}
// Generates a Format2 grant
int sched_ue::generate_format2(dl_harq_proc *h,
sched_interface::dl_sched_data_t *data,
uint32_t tti,
uint32_t cfi)
{
/* Call Format 2a (common) */
int ret = generate_format2a(h, data, tti, cfi);
/* Compute precoding information */
if (SRSLTE_RA_DL_GRANT_NOF_TB(&data->dci) == 1) {
data->dci.pinfo = (uint8_t) (dl_pmi + 1) % (uint8_t) 5;
} else {
data->dci.pinfo = (uint8_t) (dl_pmi & 1);
}
return ret;
}
int sched_ue::generate_format0(ul_harq_proc *h,
sched_interface::ul_sched_data_t *data,
@ -445,11 +596,10 @@ int sched_ue::generate_format0(ul_harq_proc *h,
ul_harq_proc::ul_alloc_t allocation = h->get_alloc();
bool is_newtx = true;
if (h->get_rar_mcs(&mcs)) {
tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs), allocation.L)/8;
h->new_tx(tti, mcs, tbs);
} else if (h->is_empty()) {
} else if (h->is_empty(0)) {
uint32_t req_bytes = get_pending_ul_new_data(tti);
@ -465,8 +615,7 @@ int sched_ue::generate_format0(ul_harq_proc *h,
h->new_tx(tti, mcs, tbs);
} else {
is_newtx = false;
h->new_retx(tti, &mcs, NULL);
h->new_retx(0, tti, &mcs, NULL);
tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs), allocation.L)/8;
}
@ -476,13 +625,9 @@ int sched_ue::generate_format0(ul_harq_proc *h,
if (tbs > 0) {
dci->type2_alloc.L_crb = allocation.L;
dci->type2_alloc.RB_start = allocation.RB_start;
dci->rv_idx = sched::get_rvidx(h->nof_retx());
if (!is_newtx && h->is_adaptive_retx()) {
dci->mcs_idx = 28+dci->rv_idx;
} else {
dci->mcs_idx = mcs;
}
dci->ndi = h->get_ndi();
dci->rv_idx = sched::get_rvidx(h->nof_retx(0));
dci->ndi = h->get_ndi(0);
dci->cqi_request = cqi_request;
dci->freq_hop_fl = srslte_ra_ul_dci_t::SRSLTE_RA_PUSCH_HOP_DISABLED;
dci->tpc_pusch = next_tpc_pusch;
@ -513,7 +658,7 @@ uint32_t sched_ue::get_max_retx() {
bool sched_ue::is_first_dl_tx()
{
for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) {
if (dl_harq[i].nof_tx() > 0) {
if (dl_harq[i].nof_tx(0) > 0) {
return false;
}
}
@ -662,7 +807,7 @@ dl_harq_proc* sched_ue::get_pending_dl_harq(uint32_t tti)
int oldest_idx=-1;
uint32_t oldest_tti = 0;
for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) {
if (dl_harq[i].has_pending_retx(tti)) {
if (dl_harq[i].has_pending_retx(0, tti) || dl_harq[i].has_pending_retx(1, tti)) {
uint32_t x = srslte_tti_interval(tti, dl_harq[i].get_tti());
if (x > oldest_tti) {
oldest_idx = i;
@ -683,7 +828,7 @@ dl_harq_proc* sched_ue::get_pending_dl_harq(uint32_t tti)
dl_harq_proc* sched_ue::get_empty_dl_harq()
{
for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) {
if (dl_harq[i].is_empty()) {
if (dl_harq[i].is_empty(0) && dl_harq[i].is_empty(1)) {
return &dl_harq[i];
}
}
@ -695,6 +840,36 @@ ul_harq_proc* sched_ue::get_ul_harq(uint32_t tti)
return &ul_harq[tti%SCHED_MAX_HARQ_PROC];
}
srslte_dci_format_t sched_ue::get_dci_format() {
srslte_dci_format_t ret = SRSLTE_DCI_FORMAT1;
if (phy_config_dedicated_enabled) {
/* FIXME: Assumes UE-Specific Search Space (Not common) */
switch (dl_ant_info.tx_mode) {
case LIBLTE_RRC_TRANSMISSION_MODE_1:
case LIBLTE_RRC_TRANSMISSION_MODE_2:
ret = SRSLTE_DCI_FORMAT1;
break;
case LIBLTE_RRC_TRANSMISSION_MODE_3:
ret = SRSLTE_DCI_FORMAT2A;
break;
case LIBLTE_RRC_TRANSMISSION_MODE_4:
ret = SRSLTE_DCI_FORMAT2;
break;
case LIBLTE_RRC_TRANSMISSION_MODE_5:
case LIBLTE_RRC_TRANSMISSION_MODE_6:
case LIBLTE_RRC_TRANSMISSION_MODE_7:
case LIBLTE_RRC_TRANSMISSION_MODE_8:
case LIBLTE_RRC_TRANSMISSION_MODE_N_ITEMS:
default:
Warning("Incorrect transmission mode (rnti=%04x)\n", rnti);
}
}
return ret;
}
/* Find lowest DCI aggregation level supported by the UE spectral efficiency */
uint32_t sched_ue::get_aggr_level(uint32_t nof_bits)
{

@ -107,9 +107,9 @@ srslte_softbuffer_rx_t* ue::get_rx_softbuffer(uint32_t tti)
return &softbuffer_rx[tti%NOF_HARQ_PROCESSES];
}
srslte_softbuffer_tx_t* ue::get_tx_softbuffer(uint32_t harq_process)
srslte_softbuffer_tx_t* ue::get_tx_softbuffer(uint32_t harq_process, uint32_t tb_idx)
{
return &softbuffer_tx[harq_process%NOF_HARQ_PROCESSES];
return &softbuffer_tx[(harq_process * SRSLTE_MAX_TB + tb_idx )%NOF_HARQ_PROCESSES];
}
uint8_t* ue::request_buffer(uint32_t tti, uint32_t len)
@ -407,6 +407,16 @@ void ue::metrics_phr(float phr) {
phr_counter++;
}
void ue::metrics_dl_ri(uint32_t dl_ri) {
metrics.dl_ri = SRSLTE_VEC_EMA((float) dl_ri, metrics.dl_ri, 0.5f);
dl_ri_counter++;
}
void ue::metrics_dl_pmi(uint32_t dl_ri) {
metrics.dl_pmi = SRSLTE_VEC_CMA((float) dl_ri, metrics.dl_pmi, dl_pmi_counter);
dl_pmi_counter++;
}
void ue::metrics_dl_cqi(uint32_t dl_cqi) {
metrics.dl_cqi = SRSLTE_VEC_CMA((float) dl_cqi, metrics.dl_cqi, dl_cqi_counter);
dl_cqi_counter++;

@ -77,6 +77,8 @@ void parse_args(all_args_t *args, int argc, char* argv[]) {
("enb.gtp_bind_addr", bpo::value<string>(&args->enb.s1ap.gtp_bind_addr)->default_value("192.168.3.1"), "Local IP address to bind for GTP connection")
("enb.phy_cell_id", bpo::value<uint32_t>(&args->enb.pci)->default_value(0), "Physical Cell Identity (PCI)")
("enb.n_prb", bpo::value<uint32_t>(&args->enb.n_prb)->default_value(25), "Number of PRB")
("enb.nof_ports", bpo::value<uint32_t>(&args->enb.nof_ports)->default_value(1), "Number of ports")
("enb.tm", bpo::value<uint32_t>(&args->enb.transmission_mode)->default_value(1), "Transmission mode (1-8)")
("enb_files.sib_config", bpo::value<string>(&args->enb_files.sib_config)->default_value("sib.conf"), "SIB configuration files")
("enb_files.rr_config", bpo::value<string>(&args->enb_files.rr_config)->default_value("rr.conf"), "RR configuration files")

@ -108,8 +108,8 @@ void metrics_stdout::print_metrics()
{
n_reports = 0;
cout << endl;
cout << "------DL-------------------------UL-------------------------------" << endl;
cout << "rnti cqi mcs brate bler snr phr mcs brate bler bsr" << endl;
cout << "------DL-------------------------------UL--------------------------------" << endl;
cout << "rnti cqi ri mcs brate bler snr phr mcs brate bler bsr" << endl;
}
if (metrics.rrc.n_ues > 0) {
@ -123,6 +123,7 @@ void metrics_stdout::print_metrics()
cout << std::hex << metrics.mac[i].rnti << " ";
cout << float_to_string(metrics.mac[i].dl_cqi, 2);
cout << float_to_string(metrics.mac[i].dl_ri + 1, 3);
cout << float_to_string(metrics.phy[i].dl.mcs, 2);
if (metrics.mac[i].tx_brate > 0 && metrics_report_period) {
cout << float_to_eng_string((float) metrics.mac[i].tx_brate/metrics_report_period, 2);

@ -30,7 +30,6 @@
#include "phy/txrx.h"
#include <assert.h>
#include <string.h>
#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
@ -74,7 +73,7 @@ void phch_common::stop() {
}
}
void phch_common::worker_end(uint32_t tx_mutex_cnt, cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time)
void phch_common::worker_end(uint32_t tx_mutex_cnt, cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time)
{
// Wait previous TTIs to be transmitted
@ -85,7 +84,7 @@ void phch_common::worker_end(uint32_t tx_mutex_cnt, cf_t* buffer, uint32_t nof_s
}
radio->set_tti(tx_mutex_cnt);
radio->tx(buffer, nof_samples, tx_time);
radio->tx((void **) buffer, nof_samples, tx_time);
// Trigger next transmission
pthread_mutex_unlock(&tx_mutex[(tx_mutex_cnt+1)%nof_mutex]);
@ -98,14 +97,18 @@ void phch_common::ack_clear(uint32_t sf_idx)
{
for(std::map<uint16_t,pending_ack_t>::iterator iter=pending_ack.begin(); iter!=pending_ack.end(); ++iter) {
pending_ack_t *p = (pending_ack_t*) &iter->second;
p->is_pending[sf_idx] = false;
for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) {
p->is_pending[sf_idx][tb_idx] = false;
}
}
}
void phch_common::ack_add_rnti(uint16_t rnti)
{
for (int sf_idx=0;sf_idx<TTIMOD_SZ;sf_idx++) {
pending_ack[rnti].is_pending[sf_idx] = false;
for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) {
pending_ack[rnti].is_pending[sf_idx][tb_idx] = false;
}
}
}
@ -114,19 +117,18 @@ void phch_common::ack_rem_rnti(uint16_t rnti)
pending_ack.erase(rnti);
}
void phch_common::ack_set_pending(uint32_t sf_idx, uint16_t rnti, uint32_t last_n_pdcch)
void phch_common::ack_set_pending(uint32_t sf_idx, uint16_t rnti, uint32_t tb_idx, uint32_t last_n_pdcch)
{
if (pending_ack.count(rnti)) {
pending_ack[rnti].is_pending[sf_idx] = true;
pending_ack[rnti].n_pdcch[sf_idx] = last_n_pdcch;
pending_ack[rnti].is_pending[sf_idx][tb_idx] = true;
pending_ack[rnti].n_pdcch[sf_idx] = (uint16_t) last_n_pdcch;
}
}
bool phch_common::ack_is_pending(uint32_t sf_idx, uint16_t rnti, uint32_t *last_n_pdcch)
{
bool phch_common::ack_is_pending(uint32_t sf_idx, uint16_t rnti, uint32_t tb_idx, uint32_t *last_n_pdcch) {
if (pending_ack.count(rnti)) {
bool ret = pending_ack[rnti].is_pending[sf_idx];
pending_ack[rnti].is_pending[sf_idx] = false;
bool ret = pending_ack[rnti].is_pending[sf_idx][tb_idx];
pending_ack[rnti].is_pending[sf_idx][tb_idx] = false;
if (ret && last_n_pdcch) {
*last_n_pdcch = pending_ack[rnti].n_pdcch[sf_idx];

@ -88,17 +88,20 @@ void phch_worker::init(phch_common* phy_, srslte::log *log_h_)
pthread_mutex_init(&mutex, NULL);
// Init cell here
signal_buffer_rx = (cf_t*) srslte_vec_malloc(2*SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t));
if (!signal_buffer_rx) {
for(int p = 0; p < SRSLTE_MAX_PORTS; p++) {
signal_buffer_rx[p] = (cf_t *) srslte_vec_malloc(2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t));
if (!signal_buffer_rx[p]) {
fprintf(stderr, "Error allocating memory\n");
return;
}
bzero(&signal_buffer_tx, sizeof(cf_t *) * SRSLTE_MAX_PORTS);
signal_buffer_tx[0] = (cf_t*) srslte_vec_malloc(2*SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t));
if (!signal_buffer_tx[0]) {
bzero(signal_buffer_rx[p], 2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t));
signal_buffer_tx[p] = (cf_t *) srslte_vec_malloc(2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t));
if (!signal_buffer_tx[p]) {
fprintf(stderr, "Error allocating memory\n");
return;
}
bzero(signal_buffer_tx[p], 2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t));
}
if (srslte_enb_dl_init(&enb_dl, signal_buffer_tx, phy->cell.nof_prb)) {
fprintf(stderr, "Error initiating ENB DL\n");
return;
@ -107,7 +110,7 @@ void phch_worker::init(phch_common* phy_, srslte::log *log_h_)
fprintf(stderr, "Error initiating ENB DL\n");
return;
}
if (srslte_enb_ul_init(&enb_ul, signal_buffer_rx, phy->cell.nof_prb)) {
if (srslte_enb_ul_init(&enb_ul, signal_buffer_rx[0], phy->cell.nof_prb)) {
fprintf(stderr, "Error initiating ENB UL\n");
return;
}
@ -154,12 +157,12 @@ void phch_worker::stop()
srslte_enb_dl_free(&enb_dl);
srslte_enb_ul_free(&enb_ul);
if (signal_buffer_rx) {
free(signal_buffer_rx);
for (int p = 0; p < SRSLTE_MAX_PORTS; p++) {
if (signal_buffer_rx[p]) {
free(signal_buffer_rx[p]);
}
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
if (signal_buffer_tx[i]) {
free(signal_buffer_tx[i]);
if (signal_buffer_tx[p]) {
free(signal_buffer_tx[p]);
}
}
pthread_mutex_unlock(&mutex);
@ -171,9 +174,9 @@ void phch_worker::reset()
ue_db.clear();
}
cf_t* phch_worker::get_buffer_rx()
cf_t* phch_worker::get_buffer_rx(uint32_t antenna_idx)
{
return signal_buffer_rx;
return signal_buffer_rx[antenna_idx];
}
void phch_worker::set_time(uint32_t tti_, uint32_t tx_mutex_cnt_, srslte_timestamp_t tx_time_)
@ -214,12 +217,29 @@ uint32_t phch_worker::get_nof_rnti() {
return ue_db.size();
}
void phch_worker::set_conf_dedicated_ack(uint16_t rnti, bool ack){
pthread_mutex_lock(&mutex);
if (ue_db.count(rnti)) {
ue_db[rnti].dedicated_ack = ack;
} else {
Error("Setting dedicated ack: rnti=0x%x does not exist\n");
}
pthread_mutex_unlock(&mutex);
}
void phch_worker::set_config_dedicated(uint16_t rnti,
srslte_uci_cfg_t *uci_cfg,
srslte_pucch_sched_t *pucch_sched,
srslte_refsignal_srs_cfg_t *srs_cfg,
uint32_t I_sr, bool pucch_cqi, uint32_t pmi_idx, bool pucch_cqi_ack)
LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated)
{
uint32_t I_sr = dedicated->sched_request_cnfg.sr_cnfg_idx;
bool pucch_cqi = dedicated->cqi_report_cnfg.report_periodic_setup_present;
uint32_t pmi_idx = dedicated->cqi_report_cnfg.report_periodic.pmi_cnfg_idx;
bool pucch_cqi_ack = dedicated->cqi_report_cnfg.report_periodic.simult_ack_nack_and_cqi;
bool pucch_ri = dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx_present;
uint32_t ri_idx = dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx;
pthread_mutex_lock(&mutex);
if (ue_db.count(rnti)) {
pucch_sched->N_pucch_1 = phy->pucch_cfg.n1_pucch_an;
@ -237,6 +257,16 @@ void phch_worker::set_config_dedicated(uint16_t rnti,
ue_db[rnti].cqi_en = false;
}
if (pucch_ri) {
ue_db[rnti].ri_idx = ri_idx;
ue_db[rnti].ri_en = true;
} else {
ue_db[rnti].ri_idx = 0;
ue_db[rnti].ri_en = false;
}
/* Copy all dedicated RRC configuration to UE */
memcpy(&ue_db[rnti].dedicated, dedicated, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT));
} else {
Error("Setting config dedicated: rnti=0x%x does not exist\n");
}
@ -293,7 +323,7 @@ void phch_worker::work_imp()
}
// Process UL signal
srslte_enb_ul_fft(&enb_ul, signal_buffer_rx);
srslte_enb_ul_fft(&enb_ul);
// Decode pending UL grants for the tti they were scheduled
decode_pusch(ul_grants[t_rx].sched_grants, ul_grants[t_rx].nof_grants);
@ -335,15 +365,22 @@ void phch_worker::work_imp()
phy->ack_clear(TTIMOD(TTI_TX(t_tx_dl)));
for (uint32_t i=0;i<dl_grants[t_tx_dl].nof_grants;i++) {
// SI-RNTI and RAR-RNTI do not have ACK
if (dl_grants[t_tx_dl].sched_grants[i].rnti >= SRSLTE_CRNTI_START && dl_grants[t_tx_dl].sched_grants[i].rnti <= SRSLTE_CRNTI_END) {
phy->ack_set_pending(TTIMOD(TTI_TX(t_tx_dl)), dl_grants[t_tx_dl].sched_grants[i].rnti, dl_grants[t_tx_dl].sched_grants[i].location.ncce);
uint16_t rnti = dl_grants[t_tx_dl].sched_grants[i].rnti;
if (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END) {
/* For each TB */
for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) {
/* If TB enabled, set pending ACK */
if (dl_grants[t_tx_dl].sched_grants[i].grant.tb_en[tb_idx]) {
phy->ack_set_pending(TTIMOD(TTI_TX(t_tx_dl)), rnti, tb_idx, dl_grants[t_tx_dl].sched_grants[i].location.ncce);
}
}
}
}
// Generate signal and transmit
srslte_enb_dl_gen_signal(&enb_dl);
Debug("Sending to radio\n");
phy->worker_end(tx_mutex_cnt, signal_buffer_tx[0], SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time);
phy->worker_end(tx_mutex_cnt, signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time);
#ifdef DEBUG_WRITE_FILE
fwrite(signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t), 1, f);
@ -387,24 +424,39 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch)
gettimeofday(&t[1], NULL);
#endif
bool acks_pending[SRSLTE_MAX_TB] = {false};
// Get pending ACKs with an associated PUSCH transmission
if (phy->ack_is_pending(t_rx, rnti)) {
uci_data.uci_ack_len = 1;
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
acks_pending[tb] = phy->ack_is_pending(t_rx, rnti, tb);
if (acks_pending[tb]) {
uci_data.uci_ack_len++;
}
}
// Configure PUSCH CQI channel
srslte_cqi_value_t cqi_value;
srslte_cqi_value_t cqi_value = {0};
bool cqi_enabled = false;
if (ue_db[rnti].cqi_en && srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) {
#if 0
if (ue_db[rnti].cqi_en && ue_db[rnti].ri_en && srslte_ri_send(ue_db[rnti].pmi_idx, ue_db[rnti].ri_idx, tti_rx) ) {
uci_data.uci_ri_len = 1; /* Asumes only 1 bit for RI */
ri_enabled = true;
} else if (ue_db[rnti].cqi_en && srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) {
cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND;
cqi_enabled = true;
} else if (grants[i].grant.cqi_request) {
if (ue_db[rnti].dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) {
//uci_data.uci_dif_cqi_len = 3;
uci_data.uci_pmi_len = 2;
}
} else
#endif
if (grants[i].grant.cqi_request) {
cqi_value.type = SRSLTE_CQI_TYPE_SUBBAND_HL;
cqi_value.subband_hl.N = (phy->cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(phy->cell.nof_prb) : 0;
cqi_value.subband_hl.four_antenna_ports = (phy->cell.nof_ports == 4);
cqi_value.subband_hl.pmi_present = (ue_db[rnti].dedicated.cqi_report_cnfg.report_mode_aperiodic == LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31);
cqi_enabled = true;
}
if (cqi_enabled) {
uci_data.uci_cqi_len = srslte_cqi_size(&cqi_value);
}
// mark this tti as having an ul grant to avoid pucch
ue_db[rnti].has_grant_tti = tti_rx;
@ -436,6 +488,7 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch)
rnti, grants[i].rv_idx,
grants[i].current_tx_nb,
grants[i].data,
(cqi_enabled) ? &cqi_value : NULL,
&uci_data,
sf_rx);
} else {
@ -457,11 +510,24 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch)
char cqi_str[64];
if (cqi_enabled) {
srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value);
if (ue_db[rnti].cqi_en) {
wideband_cqi_value = cqi_value.wideband.wideband_cqi;
} else if (grants[i].grant.cqi_request) {
wideband_cqi_value = cqi_value.subband_hl.wideband_cqi;
wideband_cqi_value = cqi_value.subband_hl.wideband_cqi_cw0;
if (cqi_value.subband_hl.pmi_present) {
if (cqi_value.subband_hl.rank_is_not_one) {
Info("PUSCH: Aperiodic ri~1, CQI=%02d/%02d, pmi=%d for %d subbands\n",
cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.wideband_cqi_cw1,
cqi_value.subband_hl.pmi, cqi_value.subband_hl.N);
} else {
Info("PUSCH: Aperiodic ri=1, CQI=%02d, pmi=%d for %d subbands\n",
cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.pmi, cqi_value.subband_hl.N);
}
} else {
Info("PUSCH: Aperiodic ri%s, CQI=%02d for %d subbands\n",
cqi_value.subband_hl.rank_is_not_one?"~1":"=1",
cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.N);
}
}
snprintf(cqi_str, 64, ", cqi=%d", wideband_cqi_value);
}
@ -481,14 +547,16 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch)
}
*/
log_h->info_hex(grants[i].data, phy_grant.mcs.tbs/8,
"PUSCH: rnti=0x%x, prb=(%d,%d), tbs=%d, mcs=%d, rv=%d, snr=%.1f dB, n_iter=%d, crc=%s%s%s%s\n",
"PUSCH: rnti=0x%x, prb=(%d,%d), tbs=%d, mcs=%d, rv=%d, snr=%.1f dB, n_iter=%d, crc=%s%s%s%s%s\n",
rnti, phy_grant.n_prb[0], phy_grant.n_prb[0]+phy_grant.L_prb,
phy_grant.mcs.tbs/8, phy_grant.mcs.idx, grants[i].grant.rv_idx,
snr_db,
srslte_pusch_last_noi(&enb_ul.pusch),
crc_res?"OK":"KO",
uci_data.uci_ack_len>0?(uci_data.uci_ack?", ack=1":", ack=0"):"",
(uci_data.uci_ack_len)?(uci_data.uci_ack?"1":"0"):"",
(uci_data.uci_ack_len > 1)?(uci_data.uci_ack_2?"1":"0"):"",
uci_data.uci_cqi_len>0?cqi_str:"",
uci_data.uci_ri_len>0?(uci_data.uci_ri?", ri=0":", ri=1"):"",
timestr);
// Notify MAC of RL status
@ -503,17 +571,28 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch)
// Notify MAC new received data and HARQ Indication value
phy->mac->crc_info(tti_rx, rnti, phy_grant.mcs.tbs/8, crc_res);
if (uci_data.uci_ack_len) {
phy->mac->ack_info(tti_rx, rnti, uci_data.uci_ack && (crc_res || snr_db > PUSCH_RL_SNR_DB_TH));
uint32_t ack_idx = 0;
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
if (acks_pending[tb]) {
bool ack = ((ack_idx++ == 0) ? uci_data.uci_ack : uci_data.uci_ack_2);
bool valid = (crc_res || snr_db > PUSCH_RL_SNR_DB_TH);
phy->mac->ack_info(tti_rx, rnti, tb, ack && valid);
}
}
// Notify MAC of UL SNR and DL CQI
// Notify MAC of UL SNR, DL CQI and DL RI
if (snr_db >= PUSCH_RL_SNR_DB_TH) {
phy->mac->snr_info(tti_rx, rnti, snr_db);
}
if (uci_data.uci_cqi_len>0 && crc_res) {
phy->mac->cqi_info(tti_rx, rnti, wideband_cqi_value);
}
if (uci_data.uci_ri_len > 0 && crc_res) {
phy->mac->ri_info(tti_rx, rnti, uci_data.uci_ri);
}
if (cqi_value.subband_hl.pmi_present && crc_res) {
phy->mac->pmi_info(tti_rx, rnti, cqi_value.subband_hl.pmi);
}
// Save metrics stats
ue_db[rnti].metrics_ul(phy_grant.mcs.idx, 0, snr_db, srslte_pusch_last_noi(&enb_ul.pusch));
@ -532,7 +611,8 @@ int phch_worker::decode_pucch()
if (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END && ue_db[rnti].has_grant_tti != (int) tti_rx) {
// Check if user needs to receive PUCCH
bool needs_pucch = false, needs_ack=false, needs_sr=false, needs_cqi=false;
bool needs_pucch = false, needs_ack[SRSLTE_MAX_TB] = {false}, needs_sr = false, needs_cqi = false,
needs_ri = false;
uint32_t last_n_pdcch = 0;
bzero(&uci_data, sizeof(srslte_uci_data_t));
@ -544,18 +624,32 @@ int phch_worker::decode_pucch()
}
}
if (phy->ack_is_pending(t_rx, rnti, &last_n_pdcch)) {
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
needs_ack[tb] = phy->ack_is_pending(t_rx, rnti, tb, &last_n_pdcch);
if (needs_ack[tb]) {
needs_pucch = true;
needs_ack = true;
uci_data.uci_ack_len = 1;
uci_data.uci_ack_len++;
}
}
srslte_cqi_value_t cqi_value;
if (ue_db[rnti].cqi_en && (ue_db[rnti].pucch_cqi_ack || !needs_ack)) {
if (srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) {
LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated = &ue_db[rnti].dedicated;
LIBLTE_RRC_TRANSMISSION_MODE_ENUM tx_mode = dedicated->antenna_info_explicit_value.tx_mode;
if (ue_db[rnti].cqi_en && (ue_db[rnti].pucch_cqi_ack || !needs_ack[0] || !needs_ack[1])) {
if (ue_db[rnti].ri_en && srslte_ri_send(ue_db[rnti].pmi_idx, ue_db[rnti].ri_idx, tti_rx)) {
needs_pucch = true;
needs_ri = true;
uci_data.uci_ri_len = 1;
uci_data.ri_periodic_report = true;
} else if (srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) {
needs_pucch = true;
needs_cqi = true;
cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND;
uci_data.uci_cqi_len = srslte_cqi_size(&cqi_value);
if (tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) {
//uci_data.uci_dif_cqi_len = 3;
uci_data.uci_pmi_len = 2;
}
}
}
@ -564,26 +658,48 @@ int phch_worker::decode_pucch()
fprintf(stderr, "Error getting PUCCH\n");
return SRSLTE_ERROR;
}
if (uci_data.uci_ack_len > 0) {
phy->mac->ack_info(tti_rx, rnti, uci_data.uci_ack && (srslte_pucch_get_last_corr(&enb_ul.pucch) >= PUCCH_RL_CORR_TH));
/* If only one ACK is required, it can be for TB0 or TB1 */
uint32_t ack_idx = 0;
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
if (needs_ack[tb]) {
bool ack = ((ack_idx++ == 0) ? uci_data.uci_ack : uci_data.uci_ack_2);
bool valid = srslte_pucch_get_last_corr(&enb_ul.pucch) >= PUCCH_RL_CORR_TH;
phy->mac->ack_info(tti_rx, rnti, tb, ack && valid);
}
}
if (uci_data.scheduling_request) {
phy->mac->sr_detected(tti_rx, rnti);
}
char cqi_str[64];
if (uci_data.uci_cqi_len) {
char cqi_ri_str[64];
if (srslte_pucch_get_last_corr(&enb_ul.pucch) > PUCCH_RL_CORR_TH) {
if (uci_data.uci_ri_len && needs_ri) {
phy->mac->ri_info(tti_rx, rnti, uci_data.uci_ri);
sprintf(cqi_ri_str, ", ri=%d", uci_data.uci_ri);
} else if (uci_data.uci_cqi_len && needs_cqi) {
srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value);
phy->mac->cqi_info(tti_rx, rnti, cqi_value.wideband.wideband_cqi);
sprintf(cqi_str, ", cqi=%d", cqi_value.wideband.wideband_cqi);
sprintf(cqi_ri_str, ", cqi=%d", cqi_value.wideband.wideband_cqi);
if (uci_data.uci_pmi_len) {
uint32_t packed_pmi = uci_data.uci_pmi[0];
if (uci_data.uci_pmi_len > 1) {
packed_pmi = (packed_pmi << 1) + uci_data.uci_pmi[1];
}
phy->mac->pmi_info(tti_rx, rnti, packed_pmi);
sprintf(cqi_ri_str, "%s, pmi=%c", cqi_ri_str, packed_pmi + 0x30);
}
}
}
log_h->info("PUCCH: rnti=0x%x, corr=%.2f, n_pucch=%d, n_prb=%d%s%s%s\n",
log_h->info("PUCCH: rnti=0x%x, corr=%.2f, n_pucch=%d, n_prb=%d%s%s%s%s\n",
rnti,
srslte_pucch_get_last_corr(&enb_ul.pucch),
enb_ul.pucch.last_n_pucch, enb_ul.pucch.last_n_prb,
needs_ack?(uci_data.uci_ack?", ack=1":", ack=0"):"",
(uci_data.uci_ack_len)?(uci_data.uci_ack?", ack=1":", ack=0"):"",
(uci_data.uci_ack_len > 1)?(uci_data.uci_ack_2?"1":"0"):"",
needs_sr?(uci_data.scheduling_request?", sr=yes":", sr=no"):"",
needs_cqi?cqi_str:"");
(needs_cqi || needs_ri)?cqi_ri_str:"");
// Notify MAC of RL status
@ -642,25 +758,16 @@ int phch_worker::encode_pdcch_ul(srslte_enb_ul_pusch_t *grants, uint32_t nof_gra
int phch_worker::encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants)
{
for (uint32_t i=0;i<nof_grants;i++) {
uint16_t rnti = grants[i].rnti;
srslte_enb_dl_pdsch_t *grant = &grants[i];
uint16_t rnti = grant->rnti;
if (rnti) {
srslte_dci_format_t format = SRSLTE_DCI_FORMAT1;
switch(grants[i].grant.alloc_type) {
case SRSLTE_RA_ALLOC_TYPE0:
case SRSLTE_RA_ALLOC_TYPE1:
format = SRSLTE_DCI_FORMAT1;
break;
case SRSLTE_RA_ALLOC_TYPE2:
format = SRSLTE_DCI_FORMAT1A;
break;
}
if (srslte_enb_dl_put_pdcch_dl(&enb_dl, &grants[i].grant, format, grants[i].location, rnti, sf_tx)) {
if (srslte_enb_dl_put_pdcch_dl(&enb_dl, &grants[i].grant, grant->dci_format, grants[i].location, rnti, sf_tx)) {
fprintf(stderr, "Error putting PDCCH %d\n",i);
return SRSLTE_ERROR;
}
if (LOG_THIS(rnti)) {
Info("PDCCH: DL DCI %s rnti=0x%x, cce_index=%d, L=%d, tti_tx_dl=%d\n", srslte_dci_format_string(format),
Info("PDCCH: DL DCI %s rnti=0x%x, cce_index=%d, L=%d, tti_tx_dl=%d\n", srslte_dci_format_string(grant->dci_format),
rnti, grants[i].location.ncce, (1<<grants[i].location.L), tti_tx_dl);
}
}
@ -668,9 +775,8 @@ int phch_worker::encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_gra
return 0;
}
int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants)
{
for (uint32_t i=0;i<nof_grants;i++) {
int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants) {
for (uint32_t i = 0; i < nof_grants; i++) {
uint16_t rnti = grants[i].rnti;
if (rnti) {
@ -678,45 +784,95 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants
if (rnti == SRSLTE_SIRNTI || rnti == SRSLTE_PRNTI || rnti == SRSLTE_MRNTI) {
rnti_is_user = false;
}
/* Mimo type (tx scheme) shall be single or tx diversity by default */
srslte_mimo_type_t mimo_type = (enb_dl.cell.nof_ports == 1) ? SRSLTE_MIMO_TYPE_SINGLE_ANTENNA
: SRSLTE_MIMO_TYPE_TX_DIVERSITY;
srslte_ra_dl_grant_t phy_grant;
srslte_ra_dl_dci_to_grant(&grants[i].grant, enb_dl.cell.nof_prb, rnti, &phy_grant);
char grant_str[64];
switch(grants[i].grant.alloc_type) {
switch (grants[i].grant.alloc_type) {
case SRSLTE_RA_ALLOC_TYPE0:
sprintf(grant_str, "mask=0x%x",grants[i].grant.type0_alloc.rbg_bitmask);
sprintf(grant_str, "mask=0x%x", grants[i].grant.type0_alloc.rbg_bitmask);
break;
case SRSLTE_RA_ALLOC_TYPE1:
sprintf(grant_str, "mask=0x%x",grants[i].grant.type1_alloc.vrb_bitmask);
sprintf(grant_str, "mask=0x%x", grants[i].grant.type1_alloc.vrb_bitmask);
break;
default:
sprintf(grant_str, "rb_start=%d",grants[i].grant.type2_alloc.RB_start);
sprintf(grant_str, "rb_start=%d", grants[i].grant.type2_alloc.RB_start);
break;
}
srslte_dci_format_t dci_format = grants[i].dci_format;
switch (dci_format) {
case SRSLTE_DCI_FORMAT1:
case SRSLTE_DCI_FORMAT1A:
/* Do nothing, it keeps default */
break;
case SRSLTE_DCI_FORMAT2A:
if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 1) {
mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
} else if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 2) {
mimo_type = SRSLTE_MIMO_TYPE_CDD;
}
break;
case SRSLTE_DCI_FORMAT2:
if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 1) {
if (phy_grant.pinfo == 0) {
mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
} else {
mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
}
} else if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 2) {
mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
}
break;
case SRSLTE_DCI_FORMAT0:
case SRSLTE_DCI_FORMAT1C:
case SRSLTE_DCI_FORMAT1B:
case SRSLTE_DCI_FORMAT1D:
case SRSLTE_DCI_FORMAT2B:
default:
Error("Not implemented/Undefined DCI format (%d)\n", dci_format);
}
if (LOG_THIS(rnti)) {
uint8_t x = 0;
uint8_t *ptr = grants[i].data;
uint8_t *ptr = grants[i].data[0];
uint32_t len = phy_grant.mcs[0].tbs / (uint32_t) 8;
if (!ptr) {
ptr = &x;
len = 1;
}
char pinfo_str[16] = {0};
if (dci_format == SRSLTE_DCI_FORMAT2) {
snprintf(pinfo_str, 15, ", pinfo=%x", phy_grant.pinfo);
}
char tbstr[SRSLTE_MAX_TB][128];
for (int tb = 0; tb < SRSLTE_MAX_TB; tb++) {
if (phy_grant.tb_en[tb]) {
snprintf(tbstr[tb], 128, ", TB%d: tbs=%d, mcs=%d, rv=%d%s%s",
tb,
phy_grant.mcs[tb].tbs / 8,
phy_grant.mcs[tb].idx,
(tb == 0) ? grants[i].grant.rv_idx : grants[i].grant.rv_idx_1,
grants[i].softbuffers[tb]==NULL?", \e[31msoftbuffer=NULL\e[0m":"",
grants[i].data[tb]==NULL?", \e[31mdata=NULL\e[0m":"");
} else {
tbstr[tb][0] = '\0';
}
}
log_h->info_hex(ptr, len,
"PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tbs=%d, mcs=%d, rv=%d, tti_tx_dl=%d\n",
rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process,
phy_grant.mcs[0].tbs/8, phy_grant.mcs[0].idx, grants[i].grant.rv_idx, tti_tx_dl);
"PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tti_tx_dl=%d, tx_scheme=%s%s%s%s\n",
rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process, tti_tx_dl,
srslte_mimotype2str(mimo_type), pinfo_str, tbstr[0], tbstr[1]);
}
srslte_softbuffer_tx_t *sb[SRSLTE_MAX_CODEWORDS] = {grants[i].softbuffer, NULL};
uint8_t *d[SRSLTE_MAX_CODEWORDS] = {grants[i].data, NULL};
int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, 0};
int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, grants[i].grant.rv_idx_1};
if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, sb, rnti, rv, sf_tx, d, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0))
{
fprintf(stderr, "Error putting PDSCH %d\n",i);
if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, grants[i].softbuffers, rnti, rv, sf_tx, grants[i].data, mimo_type)) {
fprintf(stderr, "Error putting PDSCH %d\n", i);
return SRSLTE_ERROR;
}

@ -207,6 +207,13 @@ void phy::get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS])
/***** RRC->PHY interface **********/
void phy::set_conf_dedicated_ack(uint16_t rnti, bool ack)
{
for (uint32_t i = 0; i < nof_workers; i++) {
workers[i].set_conf_dedicated_ack(rnti, ack);
}
}
void phy::set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated)
{
// Parse RRC config
@ -225,11 +232,7 @@ void phy::set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICAT
pucch_sched.n_pucch_sr = dedicated->sched_request_cnfg.sr_pucch_resource_idx;
for (uint32_t i=0;i<nof_workers;i++) {
workers[i].set_config_dedicated(rnti, &uci_cfg, &pucch_sched, NULL,
dedicated->sched_request_cnfg.sr_cnfg_idx,
dedicated->cqi_report_cnfg.report_periodic_setup_present,
dedicated->cqi_report_cnfg.report_periodic.pmi_cnfg_idx,
dedicated->cqi_report_cnfg.report_periodic.simult_ack_nack_and_cqi);
workers[i].set_config_dedicated(rnti, &uci_cfg, &pucch_sched, NULL, dedicated);
}
}

@ -77,7 +77,7 @@ void txrx::stop()
void txrx::run_thread()
{
phch_worker *worker = NULL;
cf_t *buffer = NULL;
cf_t *buffer[SRSLTE_MAX_PORTS] = {NULL};
srslte_timestamp_t rx_time, tx_time;
uint32_t sf_len = SRSLTE_SF_LEN_PRB(worker_com->cell.nof_prb);
@ -109,9 +109,11 @@ void txrx::run_thread()
tti = (tti+1)%10240;
worker = (phch_worker*) workers_pool->wait_worker(tti);
if (worker) {
buffer = worker->get_buffer_rx();
for (int p = 0; p < SRSLTE_MAX_PORTS; p++){
buffer[p] = worker->get_buffer_rx(p);
}
radio_h->rx_now(buffer, sf_len, &rx_time);
radio_h->rx_now((void **) buffer, sf_len, &rx_time);
/* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */
srslte_timestamp_copy(&tx_time, &rx_time);
@ -129,7 +131,7 @@ void txrx::run_thread()
workers_pool->start_worker(worker);
// Trigger prach worker execution
prach->new_tti(tti, buffer);
prach->new_tti(tti, buffer[0]);
} else {
// wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here

@ -866,6 +866,10 @@ void rrc::ue::handle_rrc_con_setup_complete(LIBLTE_RRC_CONNECTION_SETUP_COMPLETE
memcpy(pdu->msg, msg->dedicated_info_nas.msg, msg->dedicated_info_nas.N_bytes);
pdu->N_bytes = msg->dedicated_info_nas.N_bytes;
// Acknowledge Dedicated Configuration
parent->phy->set_conf_dedicated_ack(rnti, true);
parent->mac->phy_config_enabled(rnti, true);
if(has_tmsi) {
parent->s1ap->initial_ue(rnti, pdu, m_tmsi, mmec);
} else {
@ -1119,6 +1123,13 @@ void rrc::ue::send_connection_setup(bool is_setup)
phy_cfg->sched_request_cnfg.setup_present = true;
phy_cfg->sched_request_cnfg.dsr_trans_max = parent->cfg.sr_cfg.dsr_max;
if (parent->cfg.antenna_info.tx_mode > LIBLTE_RRC_TRANSMISSION_MODE_1) {
memcpy(&phy_cfg->antenna_info_explicit_value, &parent->cfg.antenna_info,
sizeof(LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT));
phy_cfg->antenna_info_present = true;
phy_cfg->antenna_info_default_value = false;
}
if (is_setup) {
if (sr_allocate(parent->cfg.sr_cfg.period, &phy_cfg->sched_request_cnfg.sr_cnfg_idx, &phy_cfg->sched_request_cnfg.sr_pucch_resource_idx)) {
parent->rrc_log->error("Allocating SR resources for rnti=%d\n", rnti);
@ -1142,13 +1153,23 @@ void rrc::ue::send_connection_setup(bool is_setup)
phy_cfg->cqi_report_cnfg_present = true;
if(parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_APERIODIC) {
phy_cfg->cqi_report_cnfg.report_mode_aperiodic_present = true;
if (phy_cfg->antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) {
phy_cfg->cqi_report_cnfg.report_mode_aperiodic = LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31;
} else {
phy_cfg->cqi_report_cnfg.report_mode_aperiodic = LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30;
}
} else {
phy_cfg->cqi_report_cnfg.report_periodic_present = true;
phy_cfg->cqi_report_cnfg.report_periodic_setup_present = true;
phy_cfg->cqi_report_cnfg.report_periodic.format_ind_periodic = LIBLTE_RRC_CQI_FORMAT_INDICATOR_PERIODIC_WIDEBAND_CQI;
phy_cfg->cqi_report_cnfg.report_periodic.simult_ack_nack_and_cqi = parent->cfg.cqi_cfg.simultaneousAckCQI;
if (phy_cfg->antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3 ||
phy_cfg->antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) {
phy_cfg->cqi_report_cnfg.report_periodic.ri_cnfg_idx_present = true;
phy_cfg->cqi_report_cnfg.report_periodic.ri_cnfg_idx = 483;
} else {
phy_cfg->cqi_report_cnfg.report_periodic.ri_cnfg_idx_present = false;
}
if (is_setup) {
if (cqi_allocate(parent->cfg.cqi_cfg.period,
&phy_cfg->cqi_report_cnfg.report_periodic.pmi_cnfg_idx,
@ -1198,7 +1219,9 @@ void rrc::ue::send_connection_setup(bool is_setup)
// Configure PHY layer
parent->phy->set_config_dedicated(rnti, phy_cfg);
parent->mac->phy_config_enabled(rnti, true);
parent->phy->set_conf_dedicated_ack(rnti, false);
parent->mac->set_dl_ant_info(rnti, &phy_cfg->antenna_info_explicit_value);
parent->mac->phy_config_enabled(rnti, false);
rr_cfg->drb_to_add_mod_list_size = 0;
rr_cfg->drb_to_release_list_size = 0;

@ -76,6 +76,7 @@ private:
/* Internal methods */
bool extract_fft_and_pdcch_llr();
void compute_ri();
/* ... for DL */
bool decode_pdcch_ul(mac_interface_phy::mac_grant_t *grant);

@ -45,11 +45,11 @@ namespace srsue {
args = NULL;
config = NULL;
signal_buffer = NULL;
transmitted_tti = 0;
target_power_dbm = 0;
mem_initiated = false;
cell_initiated = false;
bzero(signal_buffer, sizeof(signal_buffer));
}
~prach();
void init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config, uint32_t max_prb, phy_args_t *args, srslte::log *log_h);
@ -78,7 +78,7 @@ namespace srsue {
srslte_prach_t prach_obj;
int transmitted_tti;
srslte_cell_t cell;
cf_t *signal_buffer;
cf_t *signal_buffer[SRSLTE_MAX_PORTS];
srslte_cfo_t cfo_h;
float target_power_dbm;

@ -241,12 +241,12 @@ void phch_common::worker_end(uint32_t tti, bool tx_enable,
radio_h->set_tti(tti);
if (tx_enable) {
radio_h->tx(buffer, nof_samples, tx_time);
radio_h->tx_single(buffer, nof_samples, tx_time);
is_first_of_burst = false;
} else {
if (TX_MODE_CONTINUOUS) {
if (!is_first_of_burst) {
radio_h->tx(zeros, nof_samples, tx_time);
radio_h->tx_single(zeros, nof_samples, tx_time);
}
} else {
if (!is_first_of_burst) {

@ -272,39 +272,6 @@ void phch_worker::work_imp()
if (dl_action.generate_ack) {
set_uci_ack(dl_ack, dl_mac_grant.tb_en);
}
/* Select Rank Indicator by computing Condition Number */
if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3) {
if (ue_dl.nof_rx_antennas > 1) {
/* If 2 ort more receiving antennas, select RI */
float cn = 0.0f;
srslte_ue_dl_ri_select(&ue_dl, &uci_data.uci_ri, &cn);
uci_data.uci_ri_len = 1;
} else {
/* If only one receiving antenna, force RI for 1 layer */
uci_data.uci_ri = 0;
uci_data.uci_ri_len = 1;
Warning("Only one receiving antenna with TM3. Forcing RI=1 layer.\n");
}
} else if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4){
float sinr = 0.0f;
uint8 packed_pmi = 0;
srslte_ue_dl_ri_pmi_select(&ue_dl, &uci_data.uci_ri, &packed_pmi, &sinr);
srslte_bit_unpack_vector(&packed_pmi, uci_data.uci_pmi, 2);
uci_data.uci_ri_len = 1;
if (uci_data.uci_ri == 0) {
uci_data.uci_pmi_len = 2;
uci_data.uci_dif_cqi_len = 0;
} else {
uci_data.uci_pmi_len = 1;
uci_data.uci_dif_cqi_len = 3;
}
/* If only one antenna in TM4 print limitation warning */
if (ue_dl.nof_rx_antennas < 2) {
Warning("Only one receiving antenna with TM4. Forcing RI=1 layer (PMI=%d).\n", packed_pmi);
}
}
}
}
@ -360,7 +327,7 @@ void phch_worker::work_imp()
phy->set_pending_ack(TTI_RX_ACK(tti), ue_ul.pusch_cfg.grant.n_prb_tilde[0], ul_action.phy_grant.ul.ncs_dmrs);
}
} else if (dl_action.generate_ack || uci_data.scheduling_request || uci_data.uci_cqi_len > 0) {
} else if (dl_action.generate_ack || uci_data.scheduling_request || uci_data.uci_cqi_len > 0 || uci_data.uci_ri_len > 0) {
encode_pucch();
signal_ready = true;
} else if (srs_is_ready_to_send()) {
@ -410,6 +377,42 @@ void phch_worker::work_imp()
#endif
}
void phch_worker::compute_ri() {
if (uci_data.uci_ri_len > 0) {
/* Do nothing */
} else if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3) {
if (ue_dl.nof_rx_antennas > 1) {
/* If 2 ort more receiving antennas, select RI */
float cn = 0.0f;
srslte_ue_dl_ri_select(&ue_dl, &uci_data.uci_ri, &cn);
Info("RI select %d layers, κ=%fdB\n", uci_data.uci_ri + 1, cn);
} else {
/* If only one receiving antenna, force RI for 1 layer */
uci_data.uci_ri = 0;
Warning("Only one receiving antenna with TM3. Forcing RI=1 layer.\n");
}
uci_data.uci_ri_len = 1;
} else if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) {
float sinr = 0.0f;
uint8 packed_pmi = 0;
srslte_ue_dl_ri_pmi_select(&ue_dl, &uci_data.uci_ri, &packed_pmi, &sinr);
if (uci_data.uci_ri == 0) {
uci_data.uci_pmi_len = 2;
uci_data.uci_dif_cqi_len = 0;
} else {
uci_data.uci_pmi_len = 1;
uci_data.uci_dif_cqi_len = 3;
}
srslte_bit_unpack_vector(&packed_pmi, uci_data.uci_pmi, uci_data.uci_pmi_len);
Info("ri=%d; pmi=%d; SINR=%.1fdB\n", ue_dl.ri, ue_dl.pmi[ue_dl.ri], 10*log10f(ue_dl.sinr[ue_dl.ri][ue_dl.pmi[ue_dl.ri]]));
/* If only one antenna in TM4 print limitation warning */
if (ue_dl.nof_rx_antennas < 2) {
Warning("Only one receiving antenna with TM4. Forcing RI=1 layer (PMI=%d).\n", packed_pmi);
}
uci_data.uci_ri_len = 1;
}
}
bool phch_worker::extract_fft_and_pdcch_llr() {
bool decode_pdcch = true;
@ -634,7 +637,8 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL
/* Setup PDSCH configuration for this CFI, SFIDX and RVIDX */
if (valid_config) {
if (!srslte_ue_dl_cfg_grant(&ue_dl, grant, cfi, tti%10, rv, mimo_type)) {
if (ue_dl.pdsch_cfg.grant.mcs[0].mod > 0 && ue_dl.pdsch_cfg.grant.mcs[0].tbs >= 0) {
if ((ue_dl.pdsch_cfg.grant.mcs[0].mod > 0 && ue_dl.pdsch_cfg.grant.mcs[0].tbs >= 0) ||
(ue_dl.pdsch_cfg.grant.mcs[1].mod > 0 && ue_dl.pdsch_cfg.grant.mcs[1].tbs >= 0)) {
float noise_estimate = srslte_chest_dl_get_noise_estimate(&ue_dl.chest);
@ -663,8 +667,13 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL
snprintf(timestr, 64, ", dec_time=%4d us", (int) t[0].tv_usec);
#endif
snprintf(commonstr, 128, "PDSCH: l_crb=%2d, harq=%d, snr=%.1f dB", grant->nof_prb, harq_pid,
10 * log10(srslte_chest_dl_get_snr(&ue_dl.chest)));
char pinfo_str[16] = {0};
if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) {
snprintf(pinfo_str, 15, ", pinfo=%x", grant->pinfo);
}
snprintf(commonstr, 128, "PDSCH: l_crb=%2d, harq=%d, snr=%.1f dB, tx_scheme=%s%s", grant->nof_prb, harq_pid,
10 * log10(srslte_chest_dl_get_snr(&ue_dl.chest)), srslte_mimotype2str(mimo_type), pinfo_str);
for (int i=0;i<SRSLTE_MAX_CODEWORDS;i++) {
if (grant->tb_en[i]) {
@ -823,21 +832,15 @@ void phch_worker::reset_uci()
void phch_worker::set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], bool tb_en[SRSLTE_MAX_CODEWORDS])
{
uint32_t nof_tb = 0;
if (tb_en[0]) {
uci_data.uci_ack = (uint8_t) ((ack[0]) ? 1 : 0);
nof_tb = 1;
} else {
uci_data.uci_ack = 1;
/* Map ACK according to 3GPP 36.212 clause 5.2.3.1 */
uint32_t nof_ack = 0;
for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
if (tb_en[tb]) {
((nof_ack == 0)?uci_data.uci_ack:uci_data.uci_ack_2) = (uint8_t)(ack[tb]?1:0);
nof_ack++;
}
if (tb_en[1]) {
uci_data.uci_ack_2 = (uint8_t) ((ack[1]) ? 1 : 0);
nof_tb = 2;
}
uci_data.uci_ack_len = nof_tb;
uci_data.uci_ack_len = nof_ack;
}
void phch_worker::set_uci_sr()
@ -862,14 +865,11 @@ void phch_worker::set_uci_periodic_cqi()
if (period_cqi.configured && rnti_is_set) {
if (period_cqi.ri_idx_present && srslte_ri_send(period_cqi.pmi_idx, period_cqi.ri_idx, TTI_TX(tti))) {
if (uci_data.uci_ri_len) {
uci_data.uci_cqi[0] = uci_data.uci_ri;
uci_data.uci_cqi_len = uci_data.uci_ri_len;
uci_data.uci_ri_len = 0;
uci_data.uci_dif_cqi_len = 0;
uci_data.uci_pmi_len = 0;
Info("PUCCH: Periodic RI=%d\n", uci_data.uci_cqi[0]);
}
/* Compute RI, PMI and SINR */
compute_ri();
uci_data.ri_periodic_report = true;
Info("PUCCH: Periodic RI=%d\n", uci_data.uci_ri);
} else if (srslte_cqi_send(period_cqi.pmi_idx, TTI_TX(tti))) {
srslte_cqi_value_t cqi_report;
if (period_cqi.format_is_subband) {
@ -891,6 +891,16 @@ void phch_worker::set_uci_periodic_cqi()
}
Info("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db);
}
if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) {
if (ue_dl.ri == 0) {
uci_data.uci_pmi_len = 2;
} else {
uci_data.uci_pmi_len = 1;
uci_data.uci_dif_cqi_len = 3;
}
uint8_t *ptr = uci_data.uci_pmi;
srslte_bit_unpack(ue_dl.pmi[ue_dl.ri], &ptr, uci_data.uci_pmi_len);
}
uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi);
rar_cqi_request = false;
}
@ -900,6 +910,9 @@ void phch_worker::set_uci_periodic_cqi()
void phch_worker::set_uci_aperiodic_cqi()
{
if (phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic_present) {
/* Compute RI, PMI and SINR */
compute_ri();
switch(phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic) {
case LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30:
/* only Higher Layer-configured subband feedback support right now, according to TS36.213 section 7.2.1
@ -912,18 +925,68 @@ void phch_worker::set_uci_aperiodic_cqi()
reported RI. For other transmission modes they are reported conditioned on rank 1.
*/
if (rnti_is_set) {
srslte_cqi_value_t cqi_report;
srslte_cqi_value_t cqi_report = {0};
cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND_HL;
cqi_report.subband_hl.wideband_cqi = srslte_cqi_from_snr(phy->avg_snr_db);
cqi_report.subband_hl.wideband_cqi_cw0 = srslte_cqi_from_snr(phy->avg_snr_db);
// TODO: implement subband CQI properly
cqi_report.subband_hl.subband_diff_cqi = 0; // Always report zero offset on all subbands
cqi_report.subband_hl.subband_diff_cqi_cw0 = 0; // Always report zero offset on all subbands
cqi_report.subband_hl.N = (cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(cell.nof_prb) : 0;
Info("PUSCH: Aperiodic CQI=%d, SNR=%.1f dB, for %d subbands\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db, cqi_report.subband_hl.N);
uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi);
}
break;
case LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31:
/* only Higher Layer-configured subband feedback support right now, according to TS36.213 section 7.2.1
- A single precoding matrix is selected from the codebook subset assuming transmission on set S subbands
- A UE shall report one subband CQI value per codeword for each set S subband which are calculated assuming
the use of the single precoding matrix in all subbands and assuming transmission in the corresponding
subband.
- A UE shall report a wideband CQI value per codeword which is calculated assuming the use of the single
precoding matrix in all subbands and transmission on set S subbands
- The UE shall report the single selected precoding matrix indicator.
- For transmission mode 4 the reported PMI and CQI values are calculated conditioned on the reported RI. For
other transmission modes they are reported conditioned on rank 1.
*/
if (rnti_is_set) {
/* Select RI, PMI and SINR */
uint32_t ri = ue_dl.ri; // Select RI (0: 1 layer, 1: 2 layer, otherwise: not implemented)
uint32_t pmi = ue_dl.pmi[ri]; // Select PMI
float sinr_db = 10 * log10(ue_dl.sinr[ri][pmi]);
/* Fill CQI Report */
srslte_cqi_value_t cqi_report = {0};
cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND_HL;
cqi_report.subband_hl.wideband_cqi_cw0 = srslte_cqi_from_snr(sinr_db);
cqi_report.subband_hl.subband_diff_cqi_cw0 = 0; // Always report zero offset on all subbands
if (ri > 0) {
cqi_report.subband_hl.rank_is_not_one = true;
cqi_report.subband_hl.wideband_cqi_cw1 = srslte_cqi_from_snr(sinr_db);
cqi_report.subband_hl.subband_diff_cqi_cw1 = 0; // Always report zero offset on all subbands
}
cqi_report.subband_hl.pmi = pmi;
cqi_report.subband_hl.pmi_present = true;
cqi_report.subband_hl.four_antenna_ports = (cell.nof_ports == 4);
// TODO: implement subband CQI properly
cqi_report.subband_hl.N = (uint32_t) ((cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(cell.nof_prb) : 0);
if (cqi_report.subband_hl.rank_is_not_one) {
Info("PUSCH: Aperiodic ri~1, CQI=%02d/%02d, SINR=%2.1f/%2.1fdB, pmi=%d for %d subbands\n",
cqi_report.subband_hl.wideband_cqi_cw0, cqi_report.subband_hl.wideband_cqi_cw1,
sinr_db, sinr_db, pmi, cqi_report.subband_hl.N);
} else {
Info("PUSCH: Aperiodic ri=1, CQI=%02d, SINR=%2.1f, pmi=%d for %d subbands\n",
cqi_report.subband_hl.wideband_cqi_cw0,
sinr_db, pmi, cqi_report.subband_hl.N);
}
uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi);
}
break;
default:
Warning("Received CQI request but mode %s is not supported\n",
liblte_rrc_cqi_report_mode_aperiodic_text[phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic]);
@ -1006,7 +1069,7 @@ void phch_worker::encode_pucch()
char timestr[64];
timestr[0]='\0';
if (uci_data.scheduling_request || uci_data.uci_ack_len > 0 || uci_data.uci_cqi_len > 0)
if (uci_data.scheduling_request || uci_data.uci_ack_len > 0 || uci_data.uci_cqi_len > 0 || uci_data.uci_ri_len > 0)
{
// Drop CQI if there is collision with ACK

@ -75,11 +75,13 @@ void prach::init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config_, uint32_t max_prb,
return;
}
srslte_cfo_set_tol(&cfo_h, 0);
signal_buffer = (cf_t*) srslte_vec_malloc(SRSLTE_PRACH_MAX_LEN*sizeof(cf_t));
if (!signal_buffer) {
for (int p = 0; p < SRSLTE_MAX_PORTS; p++) {
signal_buffer[p] = (cf_t *) srslte_vec_malloc(SRSLTE_PRACH_MAX_LEN * sizeof(cf_t));
if (!signal_buffer[p]) {
perror("malloc");
return;
}
}
if (srslte_prach_init(&prach_obj, srslte_symbol_sz(max_prb))) {
Error("Initiating PRACH library\n");
return;
@ -181,8 +183,8 @@ void prach::send(srslte::radio *radio_handler, float cfo, float pathloss, srslte
// Get current TX gain
float old_gain = radio_handler->get_tx_gain();
// Correct CFO before transmission
srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer, cfo / srslte_symbol_sz(cell.nof_prb));
// Correct CFO before transmission FIXME: UL SISO Only
srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer[0], cfo / srslte_symbol_sz(cell.nof_prb));
// If power control is enabled, choose amplitude and power
if (args->ul_pwr_ctrl_en) {
@ -193,10 +195,10 @@ void prach::send(srslte::radio *radio_handler, float cfo, float pathloss, srslte
radio_handler->set_tx_power(tx_power);
// Scale signal
float digital_power = srslte_vec_avg_power_cf(signal_buffer, len);
float digital_power = srslte_vec_avg_power_cf(signal_buffer[0], len);
float scale = sqrtf(pow(10,tx_power/10)/digital_power);
srslte_vec_sc_prod_cfc(signal_buffer, scale, signal_buffer, len);
srslte_vec_sc_prod_cfc(signal_buffer[0], scale, signal_buffer[0], len);
log_h->console("PRACH: Pathloss=%.2f dB, Target power %.2f dBm, TX_power %.2f dBm, TX_gain %.1f dB\n",
pathloss, target_power_dbm, tx_power, radio_handler->get_tx_gain(), scale);
@ -208,7 +210,7 @@ void prach::send(srslte::radio *radio_handler, float cfo, float pathloss, srslte
Debug("TX PRACH: Power control for PRACH is disabled, setting gain to %.0f dB\n", prach_gain);
}
radio_handler->tx(signal_buffer, len, tx_time);
radio_handler->tx((void **) signal_buffer, len, tx_time);
radio_handler->tx_end();
Info("PRACH: Transmitted preamble=%d, CFO=%.2f KHz, tx_time=%f\n",

@ -1866,7 +1866,9 @@ void rrc::apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT
if (phy_cnfg->antenna_info_present) {
if (!phy_cnfg->antenna_info_default_value) {
if (phy_cnfg->antenna_info_explicit_value.tx_mode != LIBLTE_RRC_TRANSMISSION_MODE_1 &&
phy_cnfg->antenna_info_explicit_value.tx_mode != LIBLTE_RRC_TRANSMISSION_MODE_2) {
phy_cnfg->antenna_info_explicit_value.tx_mode != LIBLTE_RRC_TRANSMISSION_MODE_2 &&
phy_cnfg->antenna_info_explicit_value.tx_mode != LIBLTE_RRC_TRANSMISSION_MODE_3 &&
phy_cnfg->antenna_info_explicit_value.tx_mode != LIBLTE_RRC_TRANSMISSION_MODE_4) {
rrc_log->error("Transmission mode TM%s not currently supported by srsUE\n",
liblte_rrc_transmission_mode_text[phy_cnfg->antenna_info_explicit_value.tx_mode]);
}

Loading…
Cancel
Save