Merge branch 'enbmimo' into mob_crypto_mimo
This commit is contained in:
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,7 +95,8 @@ public:
|
|||
class phy_interface_rrc
|
||||
{
|
||||
public:
|
||||
virtual void set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated) = 0;
|
||||
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
|
||||
uint32_t N;
|
||||
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_API int srslte_uci_decode_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);
|
||||
bool is_ri);
|
||||
|
||||
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 *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);
|
||||
char *args,
|
||||
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],
|
||||
q->cell.nof_prb, SRSLTE_CP_NORM);
|
||||
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;
|
||||
|
@ -286,16 +290,18 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti,
|
|||
srslte_uci_data_t *uci_data)
|
||||
{
|
||||
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);
|
||||
if (q->users[rnti]) {
|
||||
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
|
||||
|
@ -305,12 +311,32 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti,
|
|||
|
||||
// Save ACK bits
|
||||
if (uci_data->uci_ack_len > 0) {
|
||||
uci_data->uci_ack = pucch_bits[0];
|
||||
uci_data->uci_ack = pucch_bits[0];
|
||||
}
|
||||
|
||||
if (uci_data->uci_ack_len > 1) {
|
||||
uci_data->uci_ack_2 = pucch_bits[1];
|
||||
}
|
||||
|
||||
// PUCCH2 CQI bits are decoded inside srslte_pucch_decode()
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -44,11 +44,38 @@
|
|||
*******************************************************/
|
||||
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);
|
||||
|
||||
return 4+2*msg->N;
|
||||
uint8_t *body_ptr = buff;
|
||||
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 bit_count;
|
||||
}
|
||||
|
||||
int srslte_cqi_ue_subband_pack(srslte_cqi_ue_subband_t *msg, uint8_t buff[SRSLTE_CQI_MAX_BITS])
|
||||
|
@ -98,11 +125,37 @@ 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);
|
||||
|
||||
return 4+2*msg->N;
|
||||
uint8_t *body_ptr = buff;
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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 -1;
|
||||
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 (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]) {
|
||||
/* 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;
|
||||
}
|
||||
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) {
|
||||
|
|
|
@ -103,26 +103,29 @@ static uint8_t M_basis_seq_pucch[20][13]={
|
|||
{1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1},
|
||||
{1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
|
||||
{1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0},
|
||||
};
|
||||
};
|
||||
|
||||
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));
|
||||
uint8_t word[16];
|
||||
|
||||
uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH;
|
||||
q->cqi_table = srslte_vec_malloc(nwords * sizeof(int8_t *));
|
||||
q->cqi_table_s = srslte_vec_malloc(nwords * sizeof(int16_t *));
|
||||
|
||||
for (uint32_t w = 0; w < nwords; w++) {
|
||||
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++) {
|
||||
int32_t max_corr = INT32_MIN;
|
||||
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};
|
||||
|
||||
/* 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_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 *bits, bool ack_ri) {
|
||||
if (beta < 0) {
|
||||
fprintf(stderr, "Error beta is reserved\n");
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
uint32_t Qprime = Q_prime_ri_ack(cfg, data_len, O_cqi, beta);
|
||||
srslte_uci_bit_type_t q_encoded_bits[18];
|
||||
|
||||
uint32_t Qprime = Q_prime_ri_ack(cfg, nof_acks, O_cqi, beta);
|
||||
uint32_t nof_encoded_bits = encode_ri_ack(data, data_len, q_encoded_bits, cfg->grant.Qm);
|
||||
|
||||
// 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 (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]);
|
||||
}
|
||||
|
||||
if (acks) {
|
||||
acks[0] = (uint8_t)(acks_sum[0] > 0);
|
||||
acks[1] = (uint8_t)(acks_sum[1] > 0);
|
||||
// TODO: Do something with acks_sum[2]
|
||||
}
|
||||
return (int) Qprime;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Encode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212
|
||||
* Currently only supporting 1-bit HARQ
|
||||
*/
|
||||
int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, uint8_t acks[2], uint32_t nof_acks,
|
||||
uint32_t O_cqi, float beta, uint32_t H_prime_total,
|
||||
srslte_uci_bit_t *ack_bits)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
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,
|
||||
float beta, uint32_t H_prime_total,
|
||||
uint32_t O_cqi, srslte_uci_bit_t *ri_bits, uint8_t *data)
|
||||
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 *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;
|
||||
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 (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]);
|
||||
}
|
||||
}
|
||||
|
||||
if (data) {
|
||||
*data = (uint8_t) ((ri_sum[0] + ri_sum[1] + ri_sum[2]) > 0);
|
||||
data[0] = (uint8_t) (sum[0] > 0);
|
||||
if (nof_bits == 2) {
|
||||
data[1] = (uint8_t) (sum[1] > 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;
|
||||
}
|
||||
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]);
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -273,21 +273,33 @@ int srslte_ue_ul_cfg_grant(srslte_ue_ul_t *q, srslte_ra_ul_grant_t *grant,
|
|||
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) {
|
||||
/* 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;
|
||||
/* 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 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;
|
||||
/* Append Differential CQI */
|
||||
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;
|
||||
|
||||
srslte_uci_encode_cqi_pucch(uci_data->uci_cqi, uci_data->uci_cqi_len, pucch_bits);
|
||||
/* Append PMI */
|
||||
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);
|
||||
|
||||
/*******************************************************
|
||||
|
@ -106,9 +109,12 @@ public:
|
|||
void set_sr();
|
||||
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_format0(ul_harq_proc *h, sched_interface::ul_sched_data_t *data, uint32_t tti, bool cqi_request);
|
||||
|
||||
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,7 +187,8 @@ 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;
|
||||
|
@ -118,9 +122,9 @@ private:
|
|||
|
||||
uint32_t last_tti;
|
||||
|
||||
uint32_t nof_failures;
|
||||
|
||||
const static int NOF_HARQ_PROCESSES = 2*HARQ_DELAY_MS;
|
||||
uint32_t nof_failures;
|
||||
|
||||
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);
|
||||
|
@ -56,13 +56,15 @@ public:
|
|||
int read_ce_abs(float *ce_abs);
|
||||
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,11 +305,51 @@ int mac::crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc)
|
|||
}
|
||||
}
|
||||
|
||||
int mac::cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value)
|
||||
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);
|
||||
|
||||
if (ue_db.count(rnti)) {
|
||||
scheduler.dl_cqi_info(tti, rnti, cqi_value);
|
||||
ue_db[rnti]->metrics_dl_cqi(cqi_value);
|
||||
} else {
|
||||
|
@ -431,43 +471,54 @@ 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);
|
||||
|
||||
// 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 (pcap) {
|
||||
pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data, sched_result.data[i].tbs, rnti, true, tti);
|
||||
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]);
|
||||
|
||||
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[tb], sched_result.data[i].tbs[tb], rnti, true, tti);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* TB not enabled OR no data to send: set pointers to NULL */
|
||||
dl_sched_res->sched_grants[n].data[tb] = NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
dl_sched_res->sched_grants[n].data = NULL;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
|
||||
// Copy RAR grants
|
||||
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].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++;
|
||||
|
@ -476,26 +527,27 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
|
|||
// Copy SI and Paging grants
|
||||
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].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,12 +279,12 @@ int sched::ul_crc_info(uint32_t tti, uint16_t rnti, bool crc)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int sched::dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value)
|
||||
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_cqi(tti, cqi_value);
|
||||
ue_db[rnti].set_dl_ri(tti, cqi_value);
|
||||
} else {
|
||||
Error("User rnti=0x%x not found\n", rnti);
|
||||
ret = -1;
|
||||
|
@ -280,6 +293,34 @@ int sched::dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value)
|
|||
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);
|
||||
int ret = 0;
|
||||
if (ue_db.count(rnti)) {
|
||||
ue_db[rnti].set_dl_cqi(tti, cqi_value);
|
||||
} else {
|
||||
Error("User rnti=0x%x not found\n", rnti);
|
||||
ret = -1;
|
||||
}
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sched::dl_rach_info(uint32_t tti, uint32_t ra_id, uint16_t rnti, uint32_t estimated_size)
|
||||
{
|
||||
for (int i=0;i<SCHED_MAX_PENDING_RAR;i++) {
|
||||
|
@ -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,13 +317,30 @@ 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)
|
||||
{
|
||||
dl_cqi = cqi;
|
||||
dl_cqi_tti = tti;
|
||||
dl_cqi = 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)
|
||||
|
@ -352,10 +371,10 @@ void sched_ue::tpc_dec() {
|
|||
|
||||
|
||||
// Generates a Format1 grant
|
||||
int sched_ue::generate_format1(dl_harq_proc *h,
|
||||
sched_interface::dl_sched_data_t *data,
|
||||
uint32_t tti,
|
||||
uint32_t cfi)
|
||||
int sched_ue::generate_format1(dl_harq_proc *h,
|
||||
sched_interface::dl_sched_data_t *data,
|
||||
uint32_t tti,
|
||||
uint32_t cfi)
|
||||
{
|
||||
srslte_ra_dl_dci_t *dci = &data->dci;
|
||||
bzero(dci, sizeof(srslte_ra_dl_dci_t));
|
||||
|
@ -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,20 +438,152 @@ 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;
|
||||
dci->tb_en[0] = true;
|
||||
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));
|
||||
|
||||
int sched_ue::generate_format0(ul_harq_proc *h,
|
||||
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,
|
||||
uint32_t tti,
|
||||
bool cqi_request)
|
||||
|
@ -444,12 +595,11 @@ int sched_ue::generate_format0(ul_harq_proc *h,
|
|||
int tbs = 0;
|
||||
|
||||
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);
|
||||
|
||||
|
@ -464,9 +614,8 @@ 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);
|
||||
} else {
|
||||
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->mcs_idx = mcs;
|
||||
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++;
|
||||
|
|
|
@ -75,9 +75,11 @@ void parse_args(all_args_t *args, int argc, char* argv[]) {
|
|||
("enb.mnc", bpo::value<string>(&mnc)->default_value("01"), "Mobile Network Code")
|
||||
("enb.mme_addr", bpo::value<string>(&args->enb.s1ap.mme_addr)->default_value("127.0.0.1"),"IP address of MME for S1 connnection")
|
||||
("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.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")
|
||||
("enb_files.drb_config", bpo::value<string>(&args->enb_files.drb_config)->default_value("drb.conf"), "DRB 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
|
||||
|
@ -84,8 +83,8 @@ void phch_common::worker_end(uint32_t tx_mutex_cnt, cf_t* buffer, uint32_t nof_s
|
|||
pthread_mutex_lock(&tx_mutex[tx_mutex_cnt%nof_mutex]);
|
||||
}
|
||||
|
||||
radio->set_tti(tx_mutex_cnt);
|
||||
radio->tx(buffer, nof_samples, tx_time);
|
||||
radio->set_tti(tx_mutex_cnt);
|
||||
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,16 +88,19 @@ 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) {
|
||||
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]) {
|
||||
fprintf(stderr, "Error allocating memory\n");
|
||||
return;
|
||||
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_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");
|
||||
|
@ -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 i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
if (signal_buffer_tx[i]) {
|
||||
free(signal_buffer_tx[i]);
|
||||
for (int p = 0; p < SRSLTE_MAX_PORTS; p++) {
|
||||
if (signal_buffer_rx[p]) {
|
||||
free(signal_buffer_rx[p]);
|
||||
}
|
||||
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)
|
||||
srslte_refsignal_srs_cfg_t *srs_cfg,
|
||||
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");
|
||||
}
|
||||
|
@ -278,7 +308,7 @@ void phch_worker::work_imp()
|
|||
}
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
|
||||
mac_interface_phy::ul_sched_t *ul_grants = phy->ul_grants;
|
||||
mac_interface_phy::dl_sched_t *dl_grants = phy->dl_grants;
|
||||
mac_interface_phy *mac = phy->mac;
|
||||
|
@ -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)) {
|
||||
needs_pucch = true;
|
||||
needs_ack = true;
|
||||
uci_data.uci_ack_len = 1;
|
||||
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;
|
||||
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_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_ri_str, ", cqi=%d", cqi_value.wideband.wideband_cqi);
|
||||
|
||||
char cqi_str[64];
|
||||
if (uci_data.uci_cqi_len) {
|
||||
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);
|
||||
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,53 +784,103 @@ 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);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
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);
|
||||
return SRSLTE_ERROR;
|
||||
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;
|
||||
}
|
||||
|
||||
// Save metrics stats
|
||||
// Save metrics stats
|
||||
ue_db[rnti].metrics_dl(phy_grant.mcs[0].idx);
|
||||
}
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -108,10 +108,12 @@ void txrx::run_thread()
|
|||
while (running) {
|
||||
tti = (tti+1)%10240;
|
||||
worker = (phch_worker*) workers_pool->wait_worker(tti);
|
||||
if (worker) {
|
||||
buffer = worker->get_buffer_rx();
|
||||
if (worker) {
|
||||
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 {
|
||||
|
@ -1110,14 +1114,21 @@ void rrc::ue::send_connection_setup(bool is_setup)
|
|||
mac_cfg->time_alignment_timer = parent->cfg.mac_cnfg.time_alignment_timer;
|
||||
|
||||
// physicalConfigDedicated
|
||||
rr_cfg->phy_cnfg_ded_present = true;
|
||||
rr_cfg->phy_cnfg_ded_present = true;
|
||||
LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cfg = &rr_cfg->phy_cnfg_ded;
|
||||
bzero(phy_cfg, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT));
|
||||
phy_cfg->pusch_cnfg_ded_present = true;
|
||||
memcpy(&phy_cfg->pusch_cnfg_ded, &parent->cfg.pusch_cfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_DEDICATED_STRUCT));
|
||||
phy_cfg->sched_request_cnfg_present = true;
|
||||
phy_cfg->sched_request_cnfg.setup_present = true;
|
||||
phy_cfg->sched_request_cnfg.dsr_trans_max = parent->cfg.sr_cfg.dsr_max;
|
||||
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)) {
|
||||
|
@ -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;
|
||||
phy_cfg->cqi_report_cnfg.report_mode_aperiodic = LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30;
|
||||
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;
|
||||
phy_cfg->cqi_report_cnfg.report_periodic.ri_cnfg_idx_present = false;
|
||||
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,7 +76,8 @@ 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);
|
||||
bool decode_pdcch_dl(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,10 +75,12 @@ 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) {
|
||||
perror("malloc");
|
||||
return;
|
||||
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");
|
||||
|
@ -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);
|
||||
|
||||
|
@ -207,8 +209,8 @@ 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…
Reference in New Issue