From e8da7160f09b5b00d5f7de4e6432d440fc9a775a Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 10 Oct 2017 13:24:23 +0200 Subject: [PATCH 01/14] eNB transmits diversity by default if two cell ports are configured --- lib/include/srslte/phy/enb/enb_dl.h | 6 ++--- lib/include/srslte/phy/rf/rf.h | 10 +++---- lib/include/srslte/radio/radio.h | 8 +++--- lib/src/phy/enb/enb_dl.c | 11 ++++---- lib/src/phy/rf/rf_imp.c | 12 +++------ lib/src/radio/radio.cc | 30 +++++++++++++-------- lib/src/radio/radio_multi.cc | 2 +- srsenb/hdr/enb.h | 2 ++ srsenb/hdr/phy/phch_common.h | 2 +- srsenb/hdr/phy/phch_worker.h | 6 ++--- srsenb/hdr/upper/rrc.h | 1 + srsenb/src/enb.cc | 2 +- srsenb/src/enb_cfg_parser.cc | 26 +++++++++++++++++- srsenb/src/mac/mac.cc | 24 ++++++++--------- srsenb/src/main.cc | 6 +++-- srsenb/src/phy/phch_common.cc | 6 ++--- srsenb/src/phy/phch_worker.cc | 41 +++++++++++++++-------------- srsenb/src/phy/txrx.cc | 12 +++++---- srsue/hdr/phy/prach.h | 4 +-- srsue/src/phy/phch_common.cc | 4 +-- srsue/src/phy/prach.cc | 22 +++++++++------- 21 files changed, 137 insertions(+), 100 deletions(-) diff --git a/lib/include/srslte/phy/enb/enb_dl.h b/lib/include/srslte/phy/enb/enb_dl.h index 7c3166e5c..b63cb6416 100644 --- a/lib/include/srslte/phy/enb/enb_dl.h +++ b/lib/include/srslte/phy/enb/enb_dl.h @@ -97,8 +97,8 @@ typedef struct { uint16_t rnti; 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 { @@ -147,7 +147,7 @@ SRSLTE_API void srslte_enb_dl_put_base(srslte_enb_dl_t *q, uint32_t tti); SRSLTE_API void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q, - cf_t *signal_buffer); + cf_t *signal_buffer[SRSLTE_MAX_PORTS]); SRSLTE_API int srslte_enb_dl_add_rnti(srslte_enb_dl_t *q, uint16_t rnti); diff --git a/lib/include/srslte/phy/rf/rf.h b/lib/include/srslte/phy/rf/rf.h index 860e0a257..c171e69d1 100644 --- a/lib/include/srslte/phy/rf/rf.h +++ b/lib/include/srslte/phy/rf/rf.h @@ -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); diff --git a/lib/include/srslte/radio/radio.h b/lib/include/srslte/radio/radio.h index 329dd825a..2a34bd9a9 100644 --- a/lib/include/srslte/radio/radio.h +++ b/lib/include/srslte/radio/radio.h @@ -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]; diff --git a/lib/src/phy/enb/enb_dl.c b/lib/src/phy/enb/enb_dl.c index 2ba179399..7b2723765 100644 --- a/lib/src/phy/enb/enb_dl.c +++ b/lib/src/phy/enb/enb_dl.c @@ -264,14 +264,15 @@ void srslte_enb_dl_put_base(srslte_enb_dl_t *q, uint32_t tti) } -void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q, cf_t *signal_buffer) +void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q, cf_t *signal_buffer[SRSLTE_MAX_PORTS]) { - - srslte_ofdm_tx_sf(&q->ifft, q->sf_symbols[0], signal_buffer); - // TODO: PAPR control float norm_factor = (float) sqrt(q->cell.nof_prb)/15; - srslte_vec_sc_prod_cfc(signal_buffer, q->tx_amp*norm_factor, signal_buffer, SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); + + for (int p = 0; p < SRSLTE_MAX_PORTS; p++) { + srslte_ofdm_tx_sf(&q->ifft, q->sf_symbols[p], signal_buffer[p]); + srslte_vec_sc_prod_cfc(signal_buffer[p], q->tx_amp*norm_factor, signal_buffer[p], (uint32_t) SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); + } } int srslte_enb_dl_add_rnti(srslte_enb_dl_t *q, uint16_t rnti) diff --git a/lib/src/phy/rf/rf_imp.c b/lib/src/phy/rf/rf_imp.c index c1074ebc5..7149cec9d 100644 --- a/lib/src/phy/rf/rf_imp.c +++ b/lib/src/phy/rf/rf_imp.c @@ -98,11 +98,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') { @@ -186,12 +182,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) diff --git a/lib/src/radio/radio.cc b/lib/src/radio/radio.cc index b393a3ff4..c6abb8642 100644 --- a/lib/src/radio/radio.cc +++ b/lib/src/radio/radio.cc @@ -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; } @@ -68,6 +68,7 @@ bool radio::init(char *args, char *devname) if (devname) { strncpy(saved_devname, devname, 128); } + saved_nof_channels = nof_channels; return true; } @@ -82,7 +83,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"); } } @@ -137,9 +138,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 { @@ -186,10 +187,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 { @@ -202,7 +211,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; } } @@ -212,8 +221,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; diff --git a/lib/src/radio/radio_multi.cc b/lib/src/radio/radio_multi.cc index 018a675ac..2ec7f891c 100644 --- a/lib/src/radio/radio_multi.cc +++ b/lib/src/radio/radio_multi.cc @@ -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; } diff --git a/srsenb/hdr/enb.h b/srsenb/hdr/enb.h index 7b1681cd6..c40fcebf4 100644 --- a/srsenb/hdr/enb.h +++ b/srsenb/hdr/enb.h @@ -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 { diff --git a/srsenb/hdr/phy/phch_common.h b/srsenb/hdr/phy/phch_common.h index 00a59d969..391d8932e 100644 --- a/srsenb/hdr/phy/phch_common.h +++ b/srsenb/hdr/phy/phch_common.h @@ -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; diff --git a/srsenb/hdr/phy/phch_worker.h b/srsenb/hdr/phy/phch_worker.h index 906e8b9d0..42e36113d 100644 --- a/srsenb/hdr/phy/phch_worker.h +++ b/srsenb/hdr/phy/phch_worker.h @@ -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); @@ -87,8 +87,8 @@ private: bool initiated; bool running; - cf_t *signal_buffer_rx; - cf_t *signal_buffer_tx; + cf_t *signal_buffer_rx[SRSLTE_MAX_PORTS]; + cf_t *signal_buffer_tx[SRSLTE_MAX_PORTS]; uint32_t tti_rx, tti_tx, tti_sched_ul, sf_rx, sf_tx, sf_sched_ul, tx_mutex_cnt; srslte_enb_dl_t enb_dl; diff --git a/srsenb/hdr/upper/rrc.h b/srsenb/hdr/upper/rrc.h index e0b9dd158..2ea07a749 100644 --- a/srsenb/hdr/upper/rrc.h +++ b/srsenb/hdr/upper/rrc.h @@ -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]; diff --git a/srsenb/src/enb.cc b/srsenb/src/enb.cc index 82b4e8145..fad7e1528 100644 --- a/srsenb/src/enb.cc +++ b/srsenb/src/enb.cc @@ -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()); diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 3beb85a65..a7734cd0c 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -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"); diff --git a/srsenb/src/mac/mac.cc b/srsenb/src/mac/mac.cc index 6c8458540..796d08025 100644 --- a/srsenb/src/mac/mac.cc +++ b/srsenb/src/mac/mac.cc @@ -434,20 +434,20 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) 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); + dl_sched_res->sched_grants[n].softbuffers[0] = 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, + dl_sched_res->sched_grants[n].data[0] = 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); + pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data[0], sched_result.data[i].tbs, rnti, true, tti); } } else { - dl_sched_res->sched_grants[n].data = NULL; + dl_sched_res->sched_grants[n].data[0] = NULL; } n++; } @@ -460,14 +460,14 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) 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, dl_sched_res->sched_grants[n].rnti, true, tti); } n++; @@ -482,20 +482,20 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) // 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); } } diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 528878388..7978e6ddc 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -75,9 +75,11 @@ void parse_args(all_args_t *args, int argc, char* argv[]) { ("enb.mnc", bpo::value(&mnc)->default_value("01"), "Mobile Network Code") ("enb.mme_addr", bpo::value(&args->enb.s1ap.mme_addr)->default_value("127.0.0.1"),"IP address of MME for S1 connnection") ("enb.gtp_bind_addr", bpo::value(&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(&args->enb.pci)->default_value(0), "Physical Cell Identity (PCI)") + ("enb.phy_cell_id", bpo::value(&args->enb.pci)->default_value(0), "Physical Cell Identity (PCI)") ("enb.n_prb", bpo::value(&args->enb.n_prb)->default_value(25), "Number of PRB") - + ("enb.nof_ports", bpo::value(&args->enb.nof_ports)->default_value(1), "Number of ports") + ("enb.tm", bpo::value(&args->enb.transmission_mode)->default_value(1), "Transmission mode (1-8)") + ("enb_files.sib_config", bpo::value(&args->enb_files.sib_config)->default_value("sib.conf"), "SIB configuration files") ("enb_files.rr_config", bpo::value(&args->enb_files.rr_config)->default_value("rr.conf"), "RR configuration files") ("enb_files.drb_config", bpo::value(&args->enb_files.drb_config)->default_value("drb.conf"), "DRB configuration files") diff --git a/srsenb/src/phy/phch_common.cc b/srsenb/src/phy/phch_common.cc index e4d91581e..545ad576e 100644 --- a/srsenb/src/phy/phch_common.cc +++ b/srsenb/src/phy/phch_common.cc @@ -74,7 +74,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 +84,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]); diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc index 3a1fb8ca4..7b547c944 100644 --- a/srsenb/src/phy/phch_worker.cc +++ b/srsenb/src/phy/phch_worker.cc @@ -88,15 +88,17 @@ 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; - } - signal_buffer_tx = (cf_t*) srslte_vec_malloc(2*SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t)); - if (!signal_buffer_tx) { - 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) { + fprintf(stderr, "Error allocating memory\n"); + return; + } + 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) { + fprintf(stderr, "Error allocating memory\n"); + return; + } } if (srslte_enb_dl_init(&enb_dl, phy->cell.nof_prb)) { fprintf(stderr, "Error initiating ENB DL\n"); @@ -168,9 +170,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_) @@ -287,7 +289,7 @@ void phch_worker::work_imp() } // Process UL signal - srslte_enb_ul_fft(&enb_ul, signal_buffer_rx); + srslte_enb_ul_fft(&enb_ul, signal_buffer_rx[0]); // Decode pending UL grants for the tti they were scheduled decode_pusch(ul_grants[sf_rx].sched_grants, ul_grants[sf_rx].nof_grants, sf_rx); @@ -649,6 +651,9 @@ int phch_worker::encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_gra int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants, uint32_t sf_idx) { + /* FIXME: currently, it assumes TM1, TM2 or TM3 */ + srslte_mimo_type_t mimo_type = (enb_dl.cell.nof_ports == 1) ? SRSLTE_MIMO_TYPE_SINGLE_ANTENNA : SRSLTE_MIMO_TYPE_TX_DIVERSITY; + for (uint32_t i=0;iinfo_hex(ptr, len, - "PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tbs=%d, mcs=%d, rv=%d, tti_tx=%d\n", + "PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tbs=%d, mcs=%d, rv=%d, tti_tx=%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); } - 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_idx, d, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0)) - { + if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, grants[i].softbuffers, rnti, rv, sf_idx, grants[i].data, mimo_type, 0)) { fprintf(stderr, "Error putting PDSCH %d\n",i); return SRSLTE_ERROR; } diff --git a/srsenb/src/phy/txrx.cc b/srsenb/src/phy/txrx.cc index 9427e3459..2a6929a20 100644 --- a/srsenb/src/phy/txrx.cc +++ b/srsenb/src/phy/txrx.cc @@ -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 diff --git a/srsue/hdr/phy/prach.h b/srsue/hdr/phy/prach.h index 67ccc0c94..2872c374c 100644 --- a/srsue/hdr/phy/prach.h +++ b/srsue/hdr/phy/prach.h @@ -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; diff --git a/srsue/src/phy/phch_common.cc b/srsue/src/phy/phch_common.cc index d49b1ced2..4a2f8a441 100644 --- a/srsue/src/phy/phch_common.cc +++ b/srsue/src/phy/phch_common.cc @@ -237,12 +237,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) { diff --git a/srsue/src/phy/prach.cc b/srsue/src/phy/prach.cc index 7c693fe7a..bd7550457 100644 --- a/srsue/src/phy/prach.cc +++ b/srsue/src/phy/prach.cc @@ -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", From 95897ceb719c519490818feba4220732cc03b92d Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 10 Oct 2017 17:01:40 +0200 Subject: [PATCH 02/14] Added TM2 (Tx diversity) support for eNB --- lib/src/phy/enb/enb_dl.c | 14 +++++++++----- srsenb/src/phy/phch_worker.cc | 16 +++++++++------- srsenb/src/upper/rrc.cc | 3 +++ 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/lib/src/phy/enb/enb_dl.c b/lib/src/phy/enb/enb_dl.c index 7b2723765..d0db1f553 100644 --- a/lib/src/phy/enb/enb_dl.c +++ b/lib/src/phy/enb/enb_dl.c @@ -219,15 +219,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) @@ -256,7 +260,7 @@ void srslte_enb_dl_put_phich(srslte_enb_dl_t *q, uint8_t ack, uint32_t n_prb_low void srslte_enb_dl_put_base(srslte_enb_dl_t *q, uint32_t tti) { uint32_t sf_idx = tti%10; - + srslte_enb_dl_put_sync(q, sf_idx); srslte_enb_dl_put_refs(q, sf_idx); srslte_enb_dl_put_mib(q, tti); diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc index 7b547c944..73d284c2c 100644 --- a/srsenb/src/phy/phch_worker.cc +++ b/srsenb/src/phy/phch_worker.cc @@ -90,12 +90,12 @@ void phch_worker::init(phch_common* phy_, srslte::log *log_h_) // Init cell here 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) { + if (!signal_buffer_rx[p]) { fprintf(stderr, "Error allocating memory\n"); return; } 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) { + if (!signal_buffer_tx[p]) { fprintf(stderr, "Error allocating memory\n"); return; } @@ -155,11 +155,13 @@ void phch_worker::stop() srslte_enb_dl_free(&enb_dl); srslte_enb_ul_free(&enb_ul); - if (signal_buffer_rx) { - free(signal_buffer_rx); - } - if (signal_buffer_tx) { - free(signal_buffer_tx); + 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); pthread_mutex_destroy(&mutex); diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index 4a432b394..6d8ec168f 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -1114,6 +1114,9 @@ void rrc::ue::send_connection_setup(bool is_setup) 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; + 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)) { From 21355de77e5eb429312609aa5d2e6c41780223a1 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 11 Oct 2017 17:00:49 +0200 Subject: [PATCH 03/14] Added TM3 (1 layer only) eNB support at RRC --- .../srslte/interfaces/enb_interfaces.h | 3 +- srsenb/hdr/phy/phch_worker.h | 11 ++++-- srsenb/hdr/phy/phy.h | 1 + srsenb/src/phy/phch_worker.cc | 38 ++++++++++++++++--- srsenb/src/phy/phy.cc | 13 ++++--- srsenb/src/upper/rrc.cc | 4 ++ srsue/src/upper/rrc.cc | 4 +- 7 files changed, 59 insertions(+), 15 deletions(-) diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index 9c85814f8..0cb3d18d6 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -93,7 +93,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; }; diff --git a/srsenb/hdr/phy/phch_worker.h b/srsenb/hdr/phy/phch_worker.h index 42e36113d..2d773345c 100644 --- a/srsenb/hdr/phy/phch_worker.h +++ b/srsenb/hdr/phy/phch_worker.h @@ -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]); @@ -99,13 +101,16 @@ 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; bool I_sr_en; bool cqi_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); diff --git a/srsenb/hdr/phy/phy.h b/srsenb/hdr/phy/phy.h index 9ab1efd74..a1616c268 100644 --- a/srsenb/hdr/phy/phy.h +++ b/srsenb/hdr/phy/phy.h @@ -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]); diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc index 73d284c2c..d38242782 100644 --- a/srsenb/src/phy/phch_worker.cc +++ b/srsenb/src/phy/phch_worker.cc @@ -210,13 +210,28 @@ uint32_t phch_worker::get_nof_rnti() { return ue_db.size(); } +void phch_worker::set_conf_dedicated_ack(uint16_t rnti, bool ack){ + pthread_mutex_lock(&mutex); + if (ue_db.count(rnti)) { + ue_db[rnti].dedicated_ack = ack; + } else { + Error("Setting dedicated ack: rnti=0x%x does not exist\n"); + } + pthread_mutex_unlock(&mutex); +} + void phch_worker::set_config_dedicated(uint16_t rnti, srslte_uci_cfg_t *uci_cfg, srslte_pucch_sched_t *pucch_sched, srslte_refsignal_srs_cfg_t *srs_cfg, - uint32_t I_sr, bool pucch_cqi, uint32_t pmi_idx, bool pucch_cqi_ack) + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated) { - pthread_mutex_lock(&mutex); + 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; + + pthread_mutex_lock(&mutex); if (ue_db.count(rnti)) { pucch_sched->N_pucch_1 = phy->pucch_cfg.n1_pucch_an; srslte_enb_ul_cfg_ue(&enb_ul, rnti, uci_cfg, pucch_sched, srs_cfg); @@ -232,7 +247,9 @@ void phch_worker::set_config_dedicated(uint16_t rnti, ue_db[rnti].pmi_idx = 0; ue_db[rnti].cqi_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"); } @@ -624,14 +641,25 @@ 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, uint32_t sf_idx) { + /* For each grant... */ for (uint32_t i=0;iPHY 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;isched_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); } } diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index 6d8ec168f..7b20209a5 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -862,6 +862,9 @@ 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); + if(has_tmsi) { parent->s1ap->initial_ue(rnti, pdu, m_tmsi, mmec); } else { @@ -1197,6 +1200,7 @@ void rrc::ue::send_connection_setup(bool is_setup) // Configure PHY layer parent->phy->set_config_dedicated(rnti, phy_cfg); + parent->phy->set_conf_dedicated_ack(rnti, false); parent->mac->phy_config_enabled(rnti, true); rr_cfg->drb_to_add_mod_list_size = 0; diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 7b78bd774..679cd29ee 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -1438,7 +1438,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]); } From 6657892b80c026855724524bc2f38340fd967efd Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 16 Oct 2017 17:33:30 +0200 Subject: [PATCH 04/14] Added UCI CQI decoder for variable number of bits --- lib/include/srslte/phy/phch/uci.h | 9 ++++- lib/src/phy/phch/test/pucch_test.c | 64 +++++++++++++++++++++++++++++- lib/src/phy/phch/uci.c | 52 ++++++++++++++++-------- 3 files changed, 106 insertions(+), 19 deletions(-) diff --git a/lib/include/srslte/phy/phch/uci.h b/lib/include/srslte/phy/phch/uci.h index ff315384e..dc2030517 100644 --- a/lib/include/srslte/phy/phch/uci.h +++ b/lib/include/srslte/phy/phch/uci.h @@ -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 { @@ -95,6 +95,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, diff --git a/lib/src/phy/phch/test/pucch_test.c b/lib/src/phy/phch/test/pucch_test.c index 43aaca953..b1d66c013 100644 --- a/lib/src/phy/phch/test/pucch_test.c +++ b/lib/src/phy/phch/test/pucch_test.c @@ -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 <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;jcqi_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;wcqi_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;wcqi_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; From af669a6cbba7ccb92704604bd5b3dde31dde5625 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 24 Oct 2017 10:07:54 +0200 Subject: [PATCH 05/14] Added RI reporting in enb and optimised RI computing calling time --- .../srslte/interfaces/enb_interfaces.h | 1 + .../srslte/interfaces/sched_interface.h | 1 + lib/include/srslte/phy/phch/pucch.h | 3 +- lib/src/phy/enb/enb_ul.c | 33 +++++-- lib/src/phy/phch/pucch.c | 6 +- lib/src/phy/phch/test/CMakeLists.txt | 1 + lib/src/phy/ue/ue_ul.c | 24 +++-- srsenb/hdr/mac/mac.h | 1 + srsenb/hdr/mac/mac_metrics.h | 1 + srsenb/hdr/mac/scheduler.h | 1 + srsenb/hdr/mac/scheduler_ue.h | 3 + srsenb/hdr/mac/ue.h | 2 + srsenb/src/mac/mac.cc | 16 +++- srsenb/src/mac/scheduler.cc | 18 +++- srsenb/src/mac/scheduler_ue.cc | 6 ++ srsenb/src/mac/ue.cc | 5 + srsenb/src/phy/phch_worker.cc | 27 ++++-- srsenb/src/upper/rrc.cc | 24 +++-- srsue/hdr/phy/phch_worker.h | 3 +- srsue/src/phy/phch_worker.cc | 91 ++++++++++--------- 20 files changed, 188 insertions(+), 79 deletions(-) diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index 0cb3d18d6..6050babeb 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -64,6 +64,7 @@ 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 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; diff --git a/lib/include/srslte/interfaces/sched_interface.h b/lib/include/srslte/interfaces/sched_interface.h index a717b4293..7a375e16e 100644 --- a/lib/include/srslte/interfaces/sched_interface.h +++ b/lib/include/srslte/interfaces/sched_interface.h @@ -227,6 +227,7 @@ public: /* DL information */ virtual int dl_ack_info(uint32_t tti, uint16_t rnti, 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_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) = 0; /* UL information */ diff --git a/lib/include/srslte/phy/phch/pucch.h b/lib/include/srslte/phy/phch/pucch.h index 8aa1495c8..29785c09a 100644 --- a/lib/include/srslte/phy/phch/pucch.h +++ b/lib/include/srslte/phy/phch/pucch.h @@ -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, diff --git a/lib/src/phy/enb/enb_ul.c b/lib/src/phy/enb/enb_ul.c index db05d44ea..b669b31e1 100644 --- a/lib/src/phy/enb/enb_ul.c +++ b/lib/src/phy/enb/enb_ul.c @@ -259,11 +259,15 @@ void srslte_enb_ul_fft(srslte_enb_ul_t *q, cf_t *signal_buffer) 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); @@ -272,7 +276,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; @@ -285,16 +289,19 @@ 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]) { + uint8_t *pucch_bits_ptr = pucch_bits; - 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->uci_ri_len > 0) ? 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 @@ -304,12 +311,24 @@ 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_ptr++); + } + + if (uci_data->uci_ack_len > 1) { + uci_data->uci_ack_2 = *(pucch_bits_ptr++); } // 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_ri_len) { + uint8_t *ptr = pucch_bits; + uci_data->uci_ri = (uint8_t) srslte_bit_pack(&ptr, uci_data->uci_ri_len); + } + + 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]; } diff --git a/lib/src/phy/phch/pucch.c b/lib/src/phy/phch/pucch.c index 498d34f3a..10c785177 100644 --- a/lib/src/phy/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -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 && @@ -838,7 +838,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"); diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index 6e6b8c024..e63243d18 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -218,6 +218,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 diff --git a/lib/src/phy/ue/ue_ul.c b/lib/src/phy/ue/ue_ul.c index 37dfecd93..479299bd7 100644 --- a/lib/src/phy/ue/ue_ul.c +++ b/lib/src/phy/ue/ue_ul.c @@ -271,21 +271,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 RI */ + uint8_t *ptr = uci_buffer; + srslte_bit_unpack(uci_data->uci_ri, &ptr, uci_data->uci_ri_len); + uci_buffer_len += uci_data->uci_ri_len; + + /* Append CQI */ + memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_cqi, uci_data->uci_cqi_len); + uci_buffer_len += uci_data->uci_cqi_len; + /* Append Differential CQI */ - memcpy(&uci_data->uci_cqi[uci_data->uci_cqi_len], uci_data->uci_dif_cqi, uci_data->uci_dif_cqi_len); - uci_data->uci_cqi_len += uci_data->uci_dif_cqi_len; + memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_dif_cqi, uci_data->uci_dif_cqi_len); + uci_buffer_len += uci_data->uci_dif_cqi_len; /* Append PMI */ - memcpy(&uci_data->uci_cqi[uci_data->uci_cqi_len], uci_data->uci_pmi, uci_data->uci_pmi_len); - uci_data->uci_cqi_len += uci_data->uci_pmi_len; + 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_data->uci_cqi, uci_data->uci_cqi_len, pucch_bits); + srslte_uci_encode_cqi_pucch(uci_buffer, uci_buffer_len, pucch_bits); if (format > SRSLTE_PUCCH_FORMAT_2) { pucch2_bits[0] = uci_data->uci_ack; pucch2_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 2a diff --git a/srsenb/hdr/mac/mac.h b/srsenb/hdr/mac/mac.h index d71245e89..c3df1c9be 100644 --- a/srsenb/hdr/mac/mac.h +++ b/srsenb/hdr/mac/mac.h @@ -72,6 +72,7 @@ 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 ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_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); diff --git a/srsenb/hdr/mac/mac_metrics.h b/srsenb/hdr/mac/mac_metrics.h index 35a65f8ae..ba5821ea9 100644 --- a/srsenb/hdr/mac/mac_metrics.h +++ b/srsenb/hdr/mac/mac_metrics.h @@ -44,6 +44,7 @@ struct mac_metrics_t int ul_buffer; int dl_buffer; float dl_cqi; + float dl_ri; float phr; }; diff --git a/srsenb/hdr/mac/scheduler.h b/srsenb/hdr/mac/scheduler.h index 231239285..f9316b139 100644 --- a/srsenb/hdr/mac/scheduler.h +++ b/srsenb/hdr/mac/scheduler.h @@ -105,6 +105,7 @@ public: int dl_ack_info(uint32_t tti, uint16_t rnti, 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_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value); int ul_crc_info(uint32_t tti, uint16_t rnti, bool crc); diff --git a/srsenb/hdr/mac/scheduler_ue.h b/srsenb/hdr/mac/scheduler_ue.h index 3653ff65c..4e4b28698 100644 --- a/srsenb/hdr/mac/scheduler_ue.h +++ b/srsenb/hdr/mac/scheduler_ue.h @@ -69,6 +69,7 @@ public: void mac_buffer_state(uint32_t ce_code); void ul_recv_len(uint32_t lcid, uint32_t len); 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_cqi(uint32_t tti, uint32_t cqi); int set_ack_info(uint32_t tti, bool ack); void set_ul_crc(uint32_t tti, bool crc_res); @@ -155,6 +156,8 @@ private: ue_bearer_t lch[sched_interface::MAX_LC]; int power_headroom; + uint32_t dl_ri; + uint32_t dl_ri_tti; uint32_t dl_cqi; uint32_t dl_cqi_tti; uint32_t cqi_request_tti; diff --git a/srsenb/hdr/mac/ue.h b/srsenb/hdr/mac/ue.h index b879d040b..4b65063d5 100644 --- a/srsenb/hdr/mac/ue.h +++ b/srsenb/hdr/mac/ue.h @@ -93,6 +93,7 @@ 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_cqi(uint32_t dl_cqi); @@ -108,6 +109,7 @@ private: uint32_t phr_counter; uint32_t dl_cqi_counter; + uint32_t dl_ri_counter; mac_metrics_t metrics; srslte::mac_pcap* pcap; diff --git a/srsenb/src/mac/mac.cc b/srsenb/src/mac/mac.cc index 796d08025..23c2557ba 100644 --- a/srsenb/src/mac/mac.cc +++ b/srsenb/src/mac/mac.cc @@ -305,11 +305,25 @@ 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::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::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 { diff --git a/srsenb/src/mac/scheduler.cc b/srsenb/src/mac/scheduler.cc index 801b68d38..298ce9625 100644 --- a/srsenb/src/mac/scheduler.cc +++ b/srsenb/src/mac/scheduler.cc @@ -266,12 +266,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 +280,20 @@ int sched::dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) 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;iset_ack(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_cqi(uint32_t tti, uint32_t cqi) { dl_cqi = cqi; diff --git a/srsenb/src/mac/ue.cc b/srsenb/src/mac/ue.cc index 14944b6d4..a46b11cf6 100644 --- a/srsenb/src/mac/ue.cc +++ b/srsenb/src/mac/ue.cc @@ -407,6 +407,11 @@ void ue::metrics_phr(float phr) { phr_counter++; } +void ue::metrics_dl_ri(uint32_t dl_ri) { + metrics.dl_ri = SRSLTE_VEC_CMA((float) dl_ri, metrics.dl_ri, dl_ri_counter); + dl_ri_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++; diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc index d38242782..fd04ce438 100644 --- a/srsenb/src/phy/phch_worker.cc +++ b/srsenb/src/phy/phch_worker.cc @@ -533,7 +533,7 @@ int phch_worker::decode_pucch(uint32_t tti_rx) 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=false, needs_sr=false, needs_cqi=false, needs_ri=false; uint32_t last_n_pdcch = 0; bzero(&uci_data, sizeof(srslte_uci_data_t)); @@ -550,8 +550,18 @@ int phch_worker::decode_pucch(uint32_t tti_rx) uci_data.uci_ack_len = 1; } srslte_cqi_value_t cqi_value; + 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; + bool ri_report_present = dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx_present; + uint32_t pmi_idx = dedicated->cqi_report_cnfg.report_periodic.pmi_cnfg_idx; + uint32_t ri_idx = dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx; + 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)) { + if (ri_report_present && srslte_ri_send(pmi_idx, ri_idx, tti_rx)) { + needs_pucch = true; + needs_ri = true; + uci_data.uci_ri_len = 1; + } 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; @@ -571,11 +581,14 @@ int phch_worker::decode_pucch(uint32_t tti_rx) phy->mac->sr_detected(tti_rx, rnti); } - char cqi_str[64]; - if (uci_data.uci_cqi_len) { + char cqi_ri_str[64]; + if (uci_data.uci_ri_len && needs_ri) { + phy->mac->ri_info(tti_rx, rnti, uci_data.uci_ri); + sprintf(cqi_ri_str, ", ri=%d", uci_data.uci_ri); + } else if (uci_data.uci_cqi_len && needs_cqi) { srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value); phy->mac->cqi_info(tti_rx, rnti, cqi_value.wideband.wideband_cqi); - sprintf(cqi_str, ", cqi=%d", cqi_value.wideband.wideband_cqi); + sprintf(cqi_ri_str, ", cqi=%d", cqi_value.wideband.wideband_cqi); } log_h->info("PUCCH: rnti=0x%x, corr=%.2f, n_pucch=%d, n_prb=%d%s%s%s\n", rnti, @@ -583,7 +596,7 @@ int phch_worker::decode_pucch(uint32_t tti_rx) enb_ul.pucch.last_n_pucch, enb_ul.pucch.last_n_prb, needs_ack?(uci_data.uci_ack?", ack=1":", ack=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 @@ -709,7 +722,7 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants break; } - if (LOG_THIS(rnti)) { + if (LOG_THIS(rnti)) { uint8_t x = 0; uint8_t *ptr = grants[i].data[0]; uint32_t len = phy_grant.mcs[0].tbs / (uint32_t) 8; diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index 7b20209a5..90e175095 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -1109,17 +1109,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; - 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; + 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)) { @@ -1149,8 +1153,14 @@ void rrc::ue::send_connection_setup(bool is_setup) 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, diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index 0811723e0..74af27752 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -74,7 +74,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); diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index c0fec2ba2..312ec57b1 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -258,41 +258,10 @@ void phch_worker::work_imp() 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); - } - } + compute_ri(); } } - + // Decode PHICH bool ul_ack = false; bool ul_ack_available = decode_phich(&ul_ack); @@ -338,7 +307,7 @@ void phch_worker::work_imp() phy->set_pending_ack(tti + 8, 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()) { @@ -387,6 +356,40 @@ void phch_worker::work_imp() #endif } +void phch_worker::compute_ri() { + /* 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); + 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); + srslte_bit_unpack_vector(&packed_pmi, uci_data.uci_pmi, 2); + 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); + } + uci_data.uci_ri_len = 1; + } +} bool phch_worker::extract_fft_and_pdcch_llr() { bool decode_pdcch = false; @@ -612,8 +615,8 @@ 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))); + snprintf(commonstr, 128, "PDSCH: l_crb=%2d, harq=%d, snr=%.1f dB, tx_scheme=%s", grant->nof_prb, harq_pid, + 10 * log10(srslte_chest_dl_get_snr(&ue_dl.chest)), srslte_mimotype2str(mimo_type)); for (int i=0;itb_en[i]) { @@ -794,14 +797,14 @@ 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+4)%10240)) { - 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]); + /* If the RI is not computed, compute it */ + if (uci_data.uci_ri_len < 1) { + compute_ri(); } + uci_data.uci_cqi_len = 0; + uci_data.uci_dif_cqi_len = 0; + uci_data.uci_pmi_len = 0; + Info("PUCCH: Periodic RI=%d\n", uci_data.uci_ri); } else if (srslte_cqi_send(period_cqi.pmi_idx, (tti+4)%10240)) { srslte_cqi_value_t cqi_report; if (period_cqi.format_is_subband) { @@ -937,7 +940,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 From 6985682ef0876285b93f4524cee26f8973d2d996 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 26 Oct 2017 17:09:28 +0200 Subject: [PATCH 06/14] Added 2nd Codeword interface in scheduler, plus pmi close loop reporting --- .../srslte/interfaces/enb_interfaces.h | 2 + .../srslte/interfaces/sched_interface.h | 4 +- lib/include/srslte/phy/enb/enb_dl.h | 4 +- lib/src/phy/enb/enb_dl.c | 24 +- lib/src/phy/enb/enb_ul.c | 12 +- lib/src/phy/ue/ue_dl.c | 4 +- lib/src/phy/ue/ue_ul.c | 5 +- srsenb/hdr/mac/mac.h | 3 + srsenb/hdr/mac/mac_metrics.h | 1 + srsenb/hdr/mac/scheduler.h | 2 + srsenb/hdr/mac/scheduler_harq.h | 40 +-- srsenb/hdr/mac/scheduler_ue.h | 16 +- srsenb/hdr/mac/ue.h | 2 + srsenb/src/mac/mac.cc | 39 ++- srsenb/src/mac/scheduler.cc | 62 ++++- srsenb/src/mac/scheduler_harq.cc | 98 ++++---- srsenb/src/mac/scheduler_metric.cc | 8 +- srsenb/src/mac/scheduler_ue.cc | 233 ++++++++++++++++-- srsenb/src/mac/ue.cc | 5 + srsenb/src/phy/phch_worker.cc | 99 +++++--- srsenb/src/upper/rrc.cc | 4 +- srsue/src/phy/phch_worker.cc | 21 +- 22 files changed, 523 insertions(+), 165 deletions(-) diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index 6050babeb..6f9db923a 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -65,6 +65,7 @@ public: 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; @@ -113,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; }; diff --git a/lib/include/srslte/interfaces/sched_interface.h b/lib/include/srslte/interfaces/sched_interface.h index 7a375e16e..5e4b68acf 100644 --- a/lib/include/srslte/interfaces/sched_interface.h +++ b/lib/include/srslte/interfaces/sched_interface.h @@ -131,9 +131,10 @@ 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; @@ -228,6 +229,7 @@ public: virtual int dl_ack_info(uint32_t tti, uint16_t rnti, 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 */ diff --git a/lib/include/srslte/phy/enb/enb_dl.h b/lib/include/srslte/phy/enb/enb_dl.h index b63cb6416..581b98e23 100644 --- a/lib/include/srslte/phy/enb/enb_dl.h +++ b/lib/include/srslte/phy/enb/enb_dl.h @@ -95,6 +95,7 @@ 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 *softbuffers[SRSLTE_MAX_TB]; @@ -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, diff --git a/lib/src/phy/enb/enb_dl.c b/lib/src/phy/enb/enb_dl.c index d0db1f553..b845b4c8a 100644 --- a/lib/src/phy/enb/enb_dl.c +++ b/lib/src/phy/enb/enb_dl.c @@ -326,8 +326,30 @@ 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) { + if (nof_tb == 1) { + 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; + } + } else { + if (grant->pinfo < 2) { + pmi = grant->pinfo; + } else { + 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"); diff --git a/lib/src/phy/enb/enb_ul.c b/lib/src/phy/enb/enb_ul.c index b669b31e1..c9c557a02 100644 --- a/lib/src/phy/enb/enb_ul.c +++ b/lib/src/phy/enb/enb_ul.c @@ -323,9 +323,17 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti, 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) { - uint8_t *ptr = pucch_bits; - uci_data->uci_ri = (uint8_t) srslte_bit_pack(&ptr, 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) { diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index c4e2d3f6c..1bef04981 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -677,6 +677,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; } @@ -712,9 +713,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; diff --git a/lib/src/phy/ue/ue_ul.c b/lib/src/phy/ue/ue_ul.c index 479299bd7..03b53c40a 100644 --- a/lib/src/phy/ue/ue_ul.c +++ b/lib/src/phy/ue/ue_ul.c @@ -281,8 +281,9 @@ void pucch_encode_bits(srslte_uci_data_t *uci_data, srslte_pucch_format_t format } if (format >= SRSLTE_PUCCH_FORMAT_2) { /* Append RI */ - uint8_t *ptr = uci_buffer; - srslte_bit_unpack(uci_data->uci_ri, &ptr, uci_data->uci_ri_len); + if (uci_data->uci_ri_len) { + uci_data->uci_ri = uci_buffer[0]; // It assumes only 1 bit of RI + } uci_buffer_len += uci_data->uci_ri_len; /* Append CQI */ diff --git a/srsenb/hdr/mac/mac.h b/srsenb/hdr/mac/mac.h index c3df1c9be..14269b0eb 100644 --- a/srsenb/hdr/mac/mac.h +++ b/srsenb/hdr/mac/mac.h @@ -72,7 +72,10 @@ 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); diff --git a/srsenb/hdr/mac/mac_metrics.h b/srsenb/hdr/mac/mac_metrics.h index ba5821ea9..e11eda350 100644 --- a/srsenb/hdr/mac/mac_metrics.h +++ b/srsenb/hdr/mac/mac_metrics.h @@ -45,6 +45,7 @@ struct mac_metrics_t int dl_buffer; float dl_cqi; float dl_ri; + float dl_pmi; float phr; }; diff --git a/srsenb/hdr/mac/scheduler.h b/srsenb/hdr/mac/scheduler.h index f9316b139..898997449 100644 --- a/srsenb/hdr/mac/scheduler.h +++ b/srsenb/hdr/mac/scheduler.h @@ -103,9 +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_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dedicated); int dl_ack_info(uint32_t tti, uint16_t rnti, 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); diff --git a/srsenb/hdr/mac/scheduler_harq.h b/srsenb/hdr/mac/scheduler_harq.h index 2e09136f9..9e1c65c78 100644 --- a/srsenb/hdr/mac/scheduler_harq.h +++ b/srsenb/hdr/mac/scheduler_harq.h @@ -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 ack[SRSLTE_MAX_TB]; bool active; - bool ndi; + 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; diff --git a/srsenb/hdr/mac/scheduler_ue.h b/srsenb/hdr/mac/scheduler_ue.h index 4e4b28698..8b0304b09 100644 --- a/srsenb/hdr/mac/scheduler_ue.h +++ b/srsenb/hdr/mac/scheduler_ue.h @@ -68,8 +68,10 @@ 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); void set_ul_crc(uint32_t tti, bool crc_res); @@ -107,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); @@ -158,6 +163,8 @@ private: 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; @@ -180,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; + }; } diff --git a/srsenb/hdr/mac/ue.h b/srsenb/hdr/mac/ue.h index 4b65063d5..3974ca52b 100644 --- a/srsenb/hdr/mac/ue.h +++ b/srsenb/hdr/mac/ue.h @@ -94,6 +94,7 @@ public: 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); @@ -110,6 +111,7 @@ 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; diff --git a/srsenb/src/mac/mac.cc b/srsenb/src/mac/mac.cc index 23c2557ba..d1e6e01b4 100644 --- a/srsenb/src/mac/mac.cc +++ b/srsenb/src/mac/mac.cc @@ -305,6 +305,18 @@ int mac::crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc) } } +int mac::set_dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dl_ant_info) { + log_h->step(tti); + + if (ue_db.count(rnti)) { + scheduler.dl_ant_info(rnti, dl_ant_info); + } else { + Error("User rnti=0x%x not found\n", rnti); + return -1; + } + return 0; +} + int mac::ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value) { log_h->step(tti); @@ -319,6 +331,20 @@ int mac::ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value) 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); @@ -445,6 +471,7 @@ 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)); @@ -454,10 +481,10 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) if (sched_result.data[i].nof_pdu_elems > 0) { dl_sched_res->sched_grants[n].data[0] = ue_db[rnti]->generate_pdu(sched_result.data[i].pdu, sched_result.data[i].nof_pdu_elems, - sched_result.data[i].tbs); + sched_result.data[i].tbs[0]); if (pcap) { - pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data[0], sched_result.data[i].tbs, rnti, true, tti); + pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data[0], sched_result.data[i].tbs[0], rnti, true, tti); } } else { @@ -469,7 +496,8 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) // Copy RAR grants for (uint32_t i=0;isched_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)); @@ -481,7 +509,7 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) if (pcap) { - pcap->write_dl_ranti(dl_sched_res->sched_grants[n].data[0], 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++; @@ -490,7 +518,8 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) // Copy SI and Paging grants for (uint32_t i=0;isched_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)); diff --git a/srsenb/src/mac/scheduler.cc b/srsenb/src/mac/scheduler.cc index 298ce9625..dd787a28d 100644 --- a/srsenb/src/mac/scheduler.cc +++ b/srsenb/src/mac/scheduler.cc @@ -238,6 +238,19 @@ int sched::dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code) return ret; } +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, bool ack) { pthread_mutex_lock(&mutex); @@ -280,6 +293,20 @@ int sched::dl_ri_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); @@ -611,19 +638,34 @@ 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; + if (h) { // Try to schedule DCI first if (generate_dci(&data[nof_data_elems].dci_location, user->get_locations(current_cfi, sf_idx), - user->get_aggr_level(srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1, cfg.cell.nof_prb, cfg.cell.nof_ports)), user)) + user->get_aggr_level(srslte_dci_format_sizeof(dci_format, cfg.cell.nof_prb, cfg.cell.nof_ports)), 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", !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(), + data[nof_data_elems].dci_location.L, data[nof_data_elems].dci_location.ncce, h->nof_retx(0), tbs, user->get_pending_dl_new_data(current_tti)); nof_data_elems++; } else { @@ -633,7 +675,7 @@ 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(); + h->reset(0); Warning("SCHED: Could not schedule DL DCI for rnti=0x%x, pid=%d\n", rnti, h->get_id()); } } @@ -721,7 +763,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++; } @@ -778,7 +820,7 @@ 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 is_newtx = h->is_empty(0); bool needs_pdcch = !h->is_adaptive_retx() && !is_rar; // Set number of retx @@ -797,7 +839,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; @@ -824,7 +866,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++; diff --git a/srsenb/src/mac/scheduler_harq.cc b/srsenb/src/mac/scheduler_harq.cc index a6ae70d19..cbb66c669 100644 --- a/srsenb/src/mac/scheduler_harq.cc +++ b/srsenb/src/mac/scheduler_harq.cc @@ -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,57 +65,57 @@ 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; + 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 || (active && 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); + 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 = 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; @@ -122,42 +124,42 @@ void harq_proc::new_tx_common(uint32_t tti_, int mcs, int tbs) } } -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) >= 8 && has_pending_retx_common(); + return srslte_tti_interval(current_tti, tti) >= 8 && 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]; } @@ -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,7 +227,7 @@ bool ul_harq_proc::has_pending_ack() bool ret = need_ack; // Reset if already received a positive ACK - if (active && ack) { + if (active && ack[0]) { active = false; } if (!active) { @@ -244,9 +246,9 @@ void ul_harq_proc::reset_pending_data() } - uint32_t ul_harq_proc::get_pending_data() +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) diff --git a/srsenb/src/mac/scheduler_metric.cc b/srsenb/src/mac/scheduler_metric.cc index 708ab2dd8..ee3f44e6f 100644 --- a/srsenb/src/mac/scheduler_metric.cc +++ b/srsenb/src/mac/scheduler_metric.cc @@ -212,7 +212,7 @@ void ul_metric_rr::new_tti(std::map &ue_db, uint32_t nof_rb_, nof_users_with_data = 0; for(std::map::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++; } @@ -284,7 +284,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; @@ -294,7 +294,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(); @@ -313,7 +313,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); diff --git a/srsenb/src/mac/scheduler_ue.cc b/srsenb/src/mac/scheduler_ue.cc index 8abb86d88..974791957 100644 --- a/srsenb/src/mac/scheduler_ue.cc +++ b/srsenb/src/mac/scheduler_ue.cc @@ -109,8 +109,8 @@ void sched_ue::reset() ul_cqi_tti = 0; cqi_request_tti = 0; for (int i=0;iset_ack(crc_res); + get_ul_harq(tti)->set_ack(0, crc_res); } void sched_ue::set_dl_ri(uint32_t tti, uint32_t ri) @@ -329,10 +329,21 @@ void sched_ue::set_dl_ri(uint32_t tti, uint32_t 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) @@ -363,10 +374,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)); @@ -385,7 +396,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); @@ -401,11 +412,11 @@ 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); 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); } @@ -431,19 +442,159 @@ 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->rv_idx = sched::get_rvidx(h->nof_retx(0)); + dci->ndi = h->get_ndi(0); + dci->tpc_pucch = next_tpc_pucch; next_tpc_pucch = 1; - data->tbs = tbs; + data->tbs[0] = tbs; 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) +{ + srslte_ra_dl_dci_t *dci = &data->dci; + bzero(dci, sizeof(srslte_ra_dl_dci_t)); + + uint32_t sf_idx = tti%10; + + int mcs = 0; + int tbs = 0; + + dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0; + dci->type0_alloc.rbg_bitmask = h->get_rbgmask(); + + if (h->is_empty(0)) { + + uint32_t req_bytes = get_pending_dl_new_data(tti); + + uint32_t nof_prb = format1_count_prb(h->get_rbgmask(), cell.nof_prb); + srslte_ra_dl_grant_t grant; + srslte_ra_dl_dci_to_grant_prb_allocation(dci, &grant, cell.nof_prb); + uint32_t nof_ctrl_symbols = cfi+(cell.nof_prb<10?1:0); + uint32_t nof_re = srslte_ra_dl_grant_nof_re(&grant, cell, sf_idx, nof_ctrl_symbols); + if (fixed_mcs_dl < 0) { + tbs = alloc_tbs_dl(nof_prb, nof_re, req_bytes, &mcs); + } else { + tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_dl), nof_prb)/8; + mcs = fixed_mcs_dl; + } + + h->new_tx(0, tti, mcs, tbs, data->dci_location.ncce); + + 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(0, tti, &mcs, &tbs); + Debug("SCHED: Alloc format1 previous mcs=%d, tbs=%d\n", mcs, tbs); + } + + int rem_tbs = tbs; + int x = 0; + do { + x = alloc_pdu(rem_tbs, &data->pdu[data->nof_pdu_elems]); + rem_tbs -= x; + if (x) { + data->nof_pdu_elems++; + } + } while(rem_tbs > 0 && x > 0); + + data->rnti = rnti; + + if (tbs > 0) { + dci->harq_process = h->get_id(); + dci->mcs_idx = mcs; + dci->rv_idx = sched::get_rvidx(h->nof_retx(0)); + dci->ndi = h->get_ndi(0); + dci->tpc_pucch = next_tpc_pucch; + next_tpc_pucch = 1; + data->tbs[0] = tbs; + dci->tb_en[0] = true; + dci->tb_en[1] = false; + } + return tbs; +} -int sched_ue::generate_format0(ul_harq_proc *h, +// 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) +{ + srslte_ra_dl_dci_t *dci = &data->dci; + bzero(dci, sizeof(srslte_ra_dl_dci_t)); + + uint32_t sf_idx = tti%10; + + int mcs = 0; + int tbs = 0; + + dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0; + dci->type0_alloc.rbg_bitmask = h->get_rbgmask(); + + if (h->is_empty(0)) { + + uint32_t req_bytes = get_pending_dl_new_data(tti); + + uint32_t nof_prb = format1_count_prb(h->get_rbgmask(), cell.nof_prb); + srslte_ra_dl_grant_t grant; + srslte_ra_dl_dci_to_grant_prb_allocation(dci, &grant, cell.nof_prb); + uint32_t nof_ctrl_symbols = cfi+(cell.nof_prb<10?1:0); + uint32_t nof_re = srslte_ra_dl_grant_nof_re(&grant, cell, sf_idx, nof_ctrl_symbols); + if (fixed_mcs_dl < 0) { + tbs = alloc_tbs_dl(nof_prb, nof_re, req_bytes, &mcs); + } else { + tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_dl), nof_prb)/8; + mcs = fixed_mcs_dl; + } + + h->new_tx(0, tti, mcs, tbs, data->dci_location.ncce); + + Debug("SCHED: Alloc format2 new mcs=%d, tbs=%d, nof_prb=%d, req_bytes=%d\n", mcs, tbs, nof_prb, req_bytes); + } else { + h->new_retx(0, tti, &mcs, &tbs); + Debug("SCHED: Alloc format2 previous mcs=%d, tbs=%d\n", mcs, tbs); + } + + int rem_tbs = tbs; + int x = 0; + do { + x = alloc_pdu(rem_tbs, &data->pdu[data->nof_pdu_elems]); + rem_tbs -= x; + if (x) { + data->nof_pdu_elems++; + } + } while(rem_tbs > 0 && x > 0); + + data->rnti = rnti; + + if (tbs > 0) { + dci->pinfo = (uint8_t) (dl_pmi + 1); +/* if (SRSLTE_RA_DL_GRANT_NOF_TB(dci) == 1) { + dci->pinfo = (uint8_t) (dl_pmi + 1); + } else { + dci->pinfo = (uint8_t) (dl_pmi & 1); + }*/ + dci->harq_process = h->get_id(); + dci->mcs_idx = mcs; + dci->rv_idx = sched::get_rvidx(h->nof_retx(0)); + dci->ndi = h->get_ndi(0); + dci->tpc_pucch = next_tpc_pucch; + next_tpc_pucch = 1; + data->tbs[0] = tbs; + dci->tb_en[0] = true; + dci->tb_en[1] = false; + } + return tbs; +} + + +int sched_ue::generate_format0(ul_harq_proc *h, sched_interface::ul_sched_data_t *data, uint32_t tti, bool cqi_request) @@ -459,7 +610,7 @@ int sched_ue::generate_format0(ul_harq_proc *h, 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); @@ -475,7 +626,7 @@ int sched_ue::generate_format0(ul_harq_proc *h, h->new_tx(tti, mcs, tbs); } else { - h->new_retx(tti, &mcs, NULL); + h->new_retx(0, tti, &mcs, NULL); tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs), allocation.L)/8; } @@ -486,8 +637,8 @@ int sched_ue::generate_format0(ul_harq_proc *h, dci->type2_alloc.L_crb = allocation.L; dci->type2_alloc.RB_start = allocation.RB_start; dci->mcs_idx = mcs; - dci->rv_idx = sched::get_rvidx(h->nof_retx()); - dci->ndi = h->get_ndi(); + dci->rv_idx = sched::get_rvidx(h->nof_retx(0)); + dci->ndi = h->get_ndi(0); dci->cqi_request = cqi_request; dci->freq_hop_fl = srslte_ra_ul_dci_t::SRSLTE_RA_PUSCH_HOP_DISABLED; dci->tpc_pusch = next_tpc_pusch; @@ -518,7 +669,7 @@ uint32_t sched_ue::get_max_retx() { bool sched_ue::is_first_dl_tx() { for (int i=0;i 0) { + if (dl_harq[i].nof_tx(0) > 0) { return false; } } @@ -666,7 +817,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 oldest_tti) { oldest_idx = i; @@ -684,7 +835,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;icell.nof_prb) * sizeof(cf_t)); } if (srslte_enb_dl_init(&enb_dl, phy->cell.nof_prb)) { fprintf(stderr, "Error initiating ENB DL\n"); @@ -566,6 +567,10 @@ int phch_worker::decode_pucch(uint32_t tti_rx) 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; + } } } @@ -589,6 +594,17 @@ int phch_worker::decode_pucch(uint32_t tti_rx) 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); + + if (uci_data.uci_pmi_len) { + uint8_t *ptr = uci_data.uci_pmi; + 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", rnti, @@ -656,35 +672,16 @@ int phch_worker::encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_gra { /* For each grant... */ for (uint32_t i=0;irnti; if (rnti) { - bool dedicated_acknowledged = ue_db[grants[i].rnti].dedicated_ack; - bool antenna_info_present = ue_db[grants[i].rnti].dedicated.antenna_info_present; - LIBLTE_RRC_TRANSMISSION_MODE_ENUM tx_mode = ue_db[grants[i].rnti].dedicated.antenna_info_explicit_value.tx_mode; - - srslte_dci_format_t format = SRSLTE_DCI_FORMAT1; - switch(grants[i].grant.alloc_type) { - case SRSLTE_RA_ALLOC_TYPE0: - case SRSLTE_RA_ALLOC_TYPE1: - if (dedicated_acknowledged && antenna_info_present && tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3) { - format = SRSLTE_DCI_FORMAT2A; - } else if (dedicated_acknowledged && antenna_info_present && tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { - format = SRSLTE_DCI_FORMAT2; - } else { - 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_idx)) { + if (srslte_enb_dl_put_pdcch_dl(&enb_dl, &grants[i].grant, grant->dci_format, grants[i].location, rnti, sf_idx)) { 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=%d\n", srslte_dci_format_string(format), + Info("PDCCH: DL DCI %s rnti=0x%x, cce_index=%d, L=%d, tti_tx=%d\n", srslte_dci_format_string(grant->dci_format), rnti, grants[i].location.ncce, (1<info_hex(ptr, len, - "PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tbs=%d, mcs=%d, rv=%d, tti_tx=%d\n", + "PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tbs=%d, mcs=%d, rv=%d, tti_tx=%d, tx_scheme=%s%s\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); + phy_grant.mcs[0].tbs/8, phy_grant.mcs[0].idx, grants[i].grant.rv_idx, tti_tx, srslte_mimotype2str(mimo_type), pinfo_str); } 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, grants[i].softbuffers, rnti, rv, sf_idx, grants[i].data, mimo_type, 0)) { + if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, grants[i].softbuffers, rnti, rv, sf_idx, grants[i].data, mimo_type)) { fprintf(stderr, "Error putting PDSCH %d\n",i); return SRSLTE_ERROR; } diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index 90e175095..54a8b2663 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -864,6 +864,7 @@ void rrc::ue::handle_rrc_con_setup_complete(LIBLTE_RRC_CONNECTION_SETUP_COMPLETE // 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); @@ -1211,7 +1212,8 @@ void rrc::ue::send_connection_setup(bool is_setup) // Configure PHY layer parent->phy->set_config_dedicated(rnti, phy_cfg); parent->phy->set_conf_dedicated_ack(rnti, false); - parent->mac->phy_config_enabled(rnti, true); + 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; diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 312ec57b1..4ccbbae69 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -374,7 +374,6 @@ void phch_worker::compute_ri() { 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); if (uci_data.uci_ri == 0) { uci_data.uci_pmi_len = 2; uci_data.uci_dif_cqi_len = 0; @@ -382,6 +381,8 @@ void phch_worker::compute_ri() { 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("pmi=%d\n", packed_pmi); /* If only one antenna in TM4 print limitation warning */ if (ue_dl.nof_rx_antennas < 2) { @@ -615,9 +616,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, tx_scheme=%s", grant->nof_prb, harq_pid, - 10 * log10(srslte_chest_dl_get_snr(&ue_dl.chest)), srslte_mimotype2str(mimo_type)); + 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;itb_en[i]) { snprintf(tbstr[i], 128, ", TB%d: tbs=%d, mcs=%d, rv=%d, crc=%s, it=%d", @@ -826,6 +831,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; } From f9e428ef68eee9a3feb9ffecf202c0af8a9e26c8 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 30 Oct 2017 14:25:03 +0100 Subject: [PATCH 07/14] Optimised RI/PMI calculation call --- lib/include/srslte/phy/phch/uci.h | 1 + lib/src/phy/ue/ue_ul.c | 31 +++++++++++++++---------------- srsue/src/phy/phch_worker.cc | 18 +++++++----------- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/lib/include/srslte/phy/phch/uci.h b/lib/include/srslte/phy/phch/uci.h index dc2030517..c20fca239 100644 --- a/lib/include/srslte/phy/phch/uci.h +++ b/lib/include/srslte/phy/phch/uci.h @@ -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; diff --git a/lib/src/phy/ue/ue_ul.c b/lib/src/phy/ue/ue_ul.c index cb2a6277a..1351cfca6 100644 --- a/lib/src/phy/ue/ue_ul.c +++ b/lib/src/phy/ue/ue_ul.c @@ -282,24 +282,23 @@ void pucch_encode_bits(srslte_uci_data_t *uci_data, srslte_pucch_format_t format pucch_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 1a } if (format >= SRSLTE_PUCCH_FORMAT_2) { - /* Append RI */ - if (uci_data->uci_ri_len) { - uci_data->uci_ri = uci_buffer[0]; // It assumes only 1 bit of RI - } - uci_buffer_len += uci_data->uci_ri_len; - - /* Append CQI */ - memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_cqi, uci_data->uci_cqi_len); - uci_buffer_len += uci_data->uci_cqi_len; - - /* Append Differential CQI */ - memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_dif_cqi, uci_data->uci_dif_cqi_len); - uci_buffer_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_buffer[uci_buffer_len], uci_data->uci_pmi, uci_data->uci_pmi_len); - uci_buffer_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; + /* 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; diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 1a6c67ef2..45b89ca82 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -256,8 +256,6 @@ void phch_worker::work_imp() if (dl_action.generate_ack) { set_uci_ack(dl_ack, dl_mac_grant.tb_en); } - - compute_ri(); } } @@ -306,6 +304,8 @@ void phch_worker::work_imp() /* Transmit PUSCH, PUCCH or SRS */ bool signal_ready = false; if (ul_action.tx_enabled) { + compute_ri(); + encode_pusch(&ul_action.phy_grant.ul, ul_action.payload_ptr[0], ul_action.current_tx_nb, &ul_action.softbuffers[0], ul_action.rv[0], ul_action.rnti, ul_mac_grant.is_from_rar); signal_ready = true; @@ -363,8 +363,9 @@ void phch_worker::work_imp() } void phch_worker::compute_ri() { - /* Select Rank Indicator by computing Condition Number */ - if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3) { + 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; @@ -834,13 +835,8 @@ 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 the RI is not computed, compute it */ - if (uci_data.uci_ri_len < 1) { - compute_ri(); - } - uci_data.uci_cqi_len = 0; - uci_data.uci_dif_cqi_len = 0; - uci_data.uci_pmi_len = 0; + 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; From 75957d41d712bf3b34526e0e43bae78496b6299e Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 8 Nov 2017 17:10:16 +0100 Subject: [PATCH 08/14] Added DCI formats 2 and 2a inScheduler. Improved UE PHCH, corrected some MIMO bugs on both sides. --- lib/examples/pdsch_enodeb.c | 2 +- .../srslte/interfaces/enb_interfaces.h | 2 +- .../srslte/interfaces/sched_interface.h | 6 +- lib/include/srslte/phy/phch/pdsch_cfg.h | 1 + lib/include/srslte/phy/phch/ra.h | 2 +- lib/include/srslte/phy/utils/debug.h | 2 +- lib/src/phy/enb/enb_dl.c | 34 +-- lib/src/phy/phch/pdsch.c | 94 +++++--- lib/src/phy/phch/pucch.c | 28 ++- lib/src/phy/phch/ra.c | 20 +- lib/src/phy/phch/test/pmch_test.c | 1 - lib/src/phy/phch/uci.c | 4 +- lib/src/phy/ue/ue_dl.c | 1 - srsenb/hdr/mac/mac.h | 2 +- srsenb/hdr/mac/scheduler.h | 2 +- srsenb/hdr/mac/scheduler_harq.h | 2 +- srsenb/hdr/mac/scheduler_ue.h | 2 +- srsenb/hdr/mac/ue.h | 8 +- srsenb/hdr/phy/phch_common.h | 6 +- srsenb/hdr/phy/phch_worker.h | 2 + srsenb/src/mac/mac.cc | 46 ++-- srsenb/src/mac/scheduler.cc | 15 +- srsenb/src/mac/scheduler_harq.cc | 18 +- srsenb/src/mac/scheduler_ue.cc | 221 ++++++++---------- srsenb/src/mac/ue.cc | 4 +- srsenb/src/phy/phch_common.cc | 22 +- srsenb/src/phy/phch_worker.cc | 137 +++++++---- srsue/src/phy/phch_worker.cc | 27 +-- 28 files changed, 406 insertions(+), 305 deletions(-) diff --git a/lib/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c index f7f17bc2b..afa47c9d4 100644 --- a/lib/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -942,7 +942,7 @@ int main(int argc, char **argv) { } /* Configure pmch_cfg parameters */ srslte_ra_dl_grant_t grant; - grant.nof_tb = 1; + grant.tb_en[0] = true; grant.mcs[0].idx = 2; grant.mcs[0].mod = SRSLTE_MOD_QPSK; grant.nof_prb = cell.nof_prb; diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index 6f9db923a..175f99f59 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -68,7 +68,7 @@ public: 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; diff --git a/lib/include/srslte/interfaces/sched_interface.h b/lib/include/srslte/interfaces/sched_interface.h index 5e4b68acf..562499dfb 100644 --- a/lib/include/srslte/interfaces/sched_interface.h +++ b/lib/include/srslte/interfaces/sched_interface.h @@ -137,8 +137,8 @@ public: 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 { @@ -226,7 +226,7 @@ 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; diff --git a/lib/include/srslte/phy/phch/pdsch_cfg.h b/lib/include/srslte/phy/phch/pdsch_cfg.h index eb4927fbb..63b3fefcc 100644 --- a/lib/include/srslte/phy/phch/pdsch_cfg.h +++ b/lib/include/srslte/phy/phch/pdsch_cfg.h @@ -48,6 +48,7 @@ typedef struct SRSLTE_API { uint32_t nof_layers; uint32_t codebook_idx; srslte_mimo_type_t mimo_type; + bool tb_cw_swap; } srslte_pdsch_cfg_t; #endif diff --git a/lib/include/srslte/phy/phch/ra.h b/lib/include/srslte/phy/phch/ra.h index aef8f4751..f4274e416 100644 --- a/lib/include/srslte/phy/phch/ra.h +++ b/lib/include/srslte/phy/phch/ra.h @@ -104,10 +104,10 @@ typedef struct SRSLTE_API { uint32_t nof_prb; uint32_t Qm[SRSLTE_MAX_CODEWORDS]; srslte_ra_mcs_t mcs[SRSLTE_MAX_CODEWORDS]; - uint32_t nof_tb; srslte_sf_t sf_type; bool tb_en[SRSLTE_MAX_CODEWORDS]; uint32_t pinfo; + bool tb_cw_swap; } srslte_ra_dl_grant_t; #define SRSLTE_RA_DL_GRANT_NOF_TB(G) ((((G)->tb_en[0])?1:0)+(((G)->tb_en[1])?1:0)) diff --git a/lib/include/srslte/phy/utils/debug.h b/lib/include/srslte/phy/utils/debug.h index c88e1a3ce..00588ca84 100644 --- a/lib/include/srslte/phy/utils/debug.h +++ b/lib/include/srslte/phy/utils/debug.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 */ diff --git a/lib/src/phy/enb/enb_dl.c b/lib/src/phy/enb/enb_dl.c index fbc22212d..5bb8c476d 100644 --- a/lib/src/phy/enb/enb_dl.c +++ b/lib/src/phy/enb/enb_dl.c @@ -341,26 +341,34 @@ int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srs /* 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) { - if (nof_tb == 1) { - 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; - } - } else { - if (grant->pinfo < 2) { - pmi = grant->pinfo; - } else { + 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; } diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index b438a2957..6479b5abd 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -467,7 +467,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; } } @@ -477,6 +477,7 @@ int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra cfg->sf_idx = sf_idx; memcpy(cfg->rv, rvidx, sizeof(uint32_t) * SRSLTE_MAX_CODEWORDS); cfg->mimo_type = mimo_type; + cfg->tb_cw_swap = grant->tb_cw_swap; /* Check and configure PDSCH transmission modes */ switch(mimo_type) { @@ -492,7 +493,7 @@ int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra ERROR("Wrong number of transport blocks (%d) for transmit diversity.", nof_tb); return SRSLTE_ERROR; } - cfg->nof_layers = 2; + cfg->nof_layers = cell.nof_ports; break; case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: if (nof_tb == 1) { @@ -543,19 +544,30 @@ static srslte_sequence_t *get_user_sequence(srslte_pdsch_t *q, uint16_t rnti, static int srslte_pdsch_codeword_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, uint16_t rnti, uint8_t *data, - uint32_t codeword_idx) { - srslte_ra_nbits_t *nbits = &cfg->nbits[codeword_idx]; - srslte_ra_mcs_t *mcs = &cfg->grant.mcs[codeword_idx]; - uint32_t rv = cfg->rv[codeword_idx]; - - if (nbits->nof_bits) { - INFO("Encoding PDSCH SF: %d (TB %d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", - cfg->sf_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs, + uint32_t codeword_idx, uint32_t tb_idx) { + 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 (!softbuffer) { + ERROR("Error encoding (TB%d -> CW%d), softbuffer=NULL", tb_idx, codeword_idx); + valid_inputs = false; + } + + if (!data) { + ERROR("Error encoding (TB%d -> CW%d), data=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); /* Channel coding */ - if (srslte_dlsch_encode2(&q->dl_sch, cfg, softbuffer, data, q->e[codeword_idx], codeword_idx)) { - ERROR("Error encoding TB %d", codeword_idx); + if (srslte_dlsch_encode2(&q->dl_sch, cfg, softbuffer, data, q->e[codeword_idx], tb_idx)) { + ERROR("Error encoding (TB%d -> CW%d)", tb_idx, codeword_idx); return SRSLTE_ERROR; } @@ -570,6 +582,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; @@ -577,15 +591,15 @@ static int srslte_pdsch_codeword_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, uint16_t rnti, uint8_t *data, - uint32_t codeword_idx, bool *ack) { - srslte_ra_nbits_t *nbits = &cfg->nbits[codeword_idx]; - srslte_ra_mcs_t *mcs = &cfg->grant.mcs[codeword_idx]; - uint32_t rv = cfg->rv[codeword_idx]; + uint32_t codeword_idx, uint32_t tb_idx, bool *ack) { + 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]; int ret = SRSLTE_ERROR_INVALID_INPUTS; if (softbuffer && data && ack) { - INFO("Decoding PDSCH SF: %d (TB %d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", - cfg->sf_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs, + INFO("Decoding PDSCH SF: %d (CW%d -> TB%d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", + cfg->sf_idx, codeword_idx, tb_idx, srslte_mod_string(mcs->mod), mcs->tbs, nbits->nof_re, nbits->nof_bits, rv); /* demodulate symbols @@ -601,7 +615,7 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c srslte_scrambling_s_offset(seq, q->e[codeword_idx], 0, nbits->nof_bits); /* Return */ - ret = srslte_dlsch_decode2(&q->dl_sch, cfg, softbuffer, q->e[codeword_idx], data, codeword_idx); + ret = srslte_dlsch_decode2(&q->dl_sch, cfg, softbuffer, q->e[codeword_idx], data, tb_idx); q->last_nof_iterations[codeword_idx] = srslte_sch_last_noi(&q->dl_sch); @@ -610,6 +624,9 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c } else if (ret == SRSLTE_ERROR) { *ack = false; ret = SRSLTE_SUCCESS; + } else if (ret == SRSLTE_ERROR_INVALID_INPUTS) { + *ack = false; + ret = SRSLTE_ERROR; } } else { ERROR("Detected NULL pointer in TB%d &softbuffer=%p &data=%p &ack=%p", codeword_idx, softbuffer, (void*)data, ack); @@ -677,24 +694,32 @@ int srslte_pdsch_decode(srslte_pdsch_t *q, } // Pre-decoder - srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, - cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, noise_estimate); + if (srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, + cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, noise_estimate)<0) { + return -1; + } // Layer demapping only if necessary if (cfg->nof_layers != nof_tb) { srslte_layerdemap_type(x, q->d, cfg->nof_layers, nof_tb, nof_symbols[0], nof_symbols, cfg->mimo_type); } - // Codeword decoding - for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb ++) { + + /* Codeword decoding: Implementation of 3GPP 36.212 Table 5.3.3.1.5-1 and Table 5.3.3.1.5-2 */ + uint32_t cw_idx = (nof_tb == SRSLTE_MAX_TB && cfg->tb_cw_swap) ? 1 : 0; + for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) { /* Decode only if transport block is enabled and the default ACK is not true */ - if (cfg->grant.tb_en[tb] && !acks[tb]) { - int ret = srslte_pdsch_codeword_decode(q, cfg, softbuffers[tb], rnti, data[tb], tb, &acks[tb]); + if (cfg->grant.tb_en[tb_idx]) { + if (!acks[tb_idx]) { + int ret = srslte_pdsch_codeword_decode(q, cfg, softbuffers[tb_idx], rnti, data[tb_idx], cw_idx, tb_idx, &acks[tb_idx]); - /* Check if there has been any execution error */ - if (ret) { - return ret; + /* Check if there has been any execution error */ + if (ret) { + return ret; + } } + + cw_idx = (cw_idx + 1) % SRSLTE_MAX_CODEWORDS; } } @@ -767,20 +792,23 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, } /* If both transport block size is zero return error */ - if (cfg->grant.mcs[0].tbs == 0) { + if (!nof_tb) { return SRSLTE_ERROR_INVALID_INPUTS; } - if (cfg->nbits[0].nof_re > q->max_re) { + if (cfg->nbits[0].nof_re > q->max_re || cfg->nbits[1].nof_re > q->max_re) { fprintf(stderr, "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", cfg->nbits[0].nof_re, q->max_re, q->cell.nof_prb); return SRSLTE_ERROR_INVALID_INPUTS; } - for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb ++) { - if (cfg->grant.tb_en[tb]) { - ret |= srslte_pdsch_codeword_encode(q, cfg, softbuffers[tb], rnti, data[tb], tb); + /* Implementation of 3GPP 36.212 Table 5.3.3.1.5-1 and Table 5.3.3.1.5-2 */ + uint32_t cw_idx = (nof_tb == SRSLTE_MAX_TB && cfg->tb_cw_swap) ? 1 : 0; + for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) { + if (cfg->grant.tb_en[tb_idx]) { + ret |= srslte_pdsch_codeword_encode(q, cfg, softbuffers[tb_idx], rnti, data[tb_idx], cw_idx, tb_idx); + cw_idx = (cw_idx + 1) % SRSLTE_MAX_CODEWORDS; } } diff --git a/lib/src/phy/phch/pucch.c b/lib/src/phy/phch/pucch.c index 10c785177..91445f99a 100644 --- a/lib/src/phy/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -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: diff --git a/lib/src/phy/phch/ra.c b/lib/src/phy/phch/ra.c index 913bd9548..e37266858 100644 --- a/lib/src/phy/phch/ra.c +++ b/lib/src/phy/phch/ra.c @@ -526,11 +526,9 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr grant->mcs[0].tbs = (uint32_t) tbs; } else { n_prb = grant->nof_prb; - grant->nof_tb = 0; if (dci->tb_en[0]) { grant->mcs[0].idx = dci->mcs_idx; grant->mcs[0].tbs = srslte_dl_fill_ra_mcs(&grant->mcs[0], n_prb); - grant->nof_tb++; } else { grant->mcs[0].tbs = 0; } @@ -560,16 +558,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 */ - 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; - } nbits[i].nof_bits = nbits[i].nof_re * grant->Qm[i]; } } diff --git a/lib/src/phy/phch/test/pmch_test.c b/lib/src/phy/phch/test/pmch_test.c index a9c29ef64..bf415e692 100644 --- a/lib/src/phy/phch/test/pmch_test.c +++ b/lib/src/phy/phch/test/pmch_test.c @@ -167,7 +167,6 @@ int main(int argc, char **argv) { /* If transport block 0 is enabled */ grant.tb_en[0] = true; grant.tb_en[1] = false; - grant.nof_tb = 1; grant.mcs[0].idx = mcs_idx; grant.nof_prb = cell.nof_prb; diff --git a/lib/src/phy/phch/uci.c b/lib/src/phy/phch/uci.c index 4345824a7..0b9a54058 100644 --- a/lib/src/phy/phch/uci.c +++ b/lib/src/phy/phch/uci.c @@ -686,7 +686,9 @@ int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_s } } - if (acks) { + if (nof_acks == 1 && acks) { + acks[0] = (uint8_t)(acks_sum[0] + acks_sum[1] + acks_sum[2] > 0); + } else 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] diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 0f0307b0d..a677aa70d 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -608,7 +608,6 @@ int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q, //float noise_estimate = 0; grant.sf_type = SRSLTE_SF_MBSFN; - grant.nof_tb = 1; grant.mcs[0].idx = 2; grant.tb_en[0] = true; grant.tb_en[1] = false; diff --git a/srsenb/hdr/mac/mac.h b/srsenb/hdr/mac/mac.h index 14269b0eb..4e37d439f 100644 --- a/srsenb/hdr/mac/mac.h +++ b/srsenb/hdr/mac/mac.h @@ -78,7 +78,7 @@ public: 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); diff --git a/srsenb/hdr/mac/scheduler.h b/srsenb/hdr/mac/scheduler.h index 898997449..c3ca7d624 100644 --- a/srsenb/hdr/mac/scheduler.h +++ b/srsenb/hdr/mac/scheduler.h @@ -104,7 +104,7 @@ public: int dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code); int dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dedicated); - int dl_ack_info(uint32_t tti, uint16_t rnti, bool ack); + 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); diff --git a/srsenb/hdr/mac/scheduler_harq.h b/srsenb/hdr/mac/scheduler_harq.h index 9e1c65c78..211ec7d8d 100644 --- a/srsenb/hdr/mac/scheduler_harq.h +++ b/srsenb/hdr/mac/scheduler_harq.h @@ -58,7 +58,7 @@ protected: bool has_pending_retx_common(uint32_t tb_idx); bool ack[SRSLTE_MAX_TB]; - bool active; + bool active[SRSLTE_MAX_TB]; bool ndi[SRSLTE_MAX_TB]; uint32_t id; uint32_t max_retx; diff --git a/srsenb/hdr/mac/scheduler_ue.h b/srsenb/hdr/mac/scheduler_ue.h index 24ac06659..448e01954 100644 --- a/srsenb/hdr/mac/scheduler_ue.h +++ b/srsenb/hdr/mac/scheduler_ue.h @@ -73,7 +73,7 @@ public: 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); /******************************************************* diff --git a/srsenb/hdr/mac/ue.h b/srsenb/hdr/mac/ue.h index 33ec7150a..3550519e8 100644 --- a/srsenb/hdr/mac/ue.h +++ b/srsenb/hdr/mac/ue.h @@ -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(); @@ -122,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]; diff --git a/srsenb/hdr/phy/phch_common.h b/srsenb/hdr/phy/phch_common.h index c11a47938..950fd8fa1 100644 --- a/srsenb/hdr/phy/phch_common.h +++ b/srsenb/hdr/phy/phch_common.h @@ -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 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 tx_mutex; diff --git a/srsenb/hdr/phy/phch_worker.h b/srsenb/hdr/phy/phch_worker.h index 29483d961..2ffc090b6 100644 --- a/srsenb/hdr/phy/phch_worker.h +++ b/srsenb/hdr/phy/phch_worker.h @@ -106,8 +106,10 @@ private: 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; diff --git a/srsenb/src/mac/mac.cc b/srsenb/src/mac/mac.cc index 0b6f65983..69ed37728 100644 --- a/srsenb/src/mac/mac.cc +++ b/srsenb/src/mac/mac.cc @@ -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) { @@ -474,25 +474,39 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) 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].softbuffers[0] = 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[0] = ue_db[rnti]->generate_pdu(sched_result.data[i].pdu, - sched_result.data[i].nof_pdu_elems, - sched_result.data[i].tbs[0]); - if (pcap) { - pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data[0], sched_result.data[i].tbs[0], rnti, true, tti); + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + if (sched_result.data[i].dci.tb_en[tb] && sched_result.data[i].nof_pdu_elems[tb] > 0) { + dl_sched_res->sched_grants[n].softbuffers[tb] = + ue_db[rnti]->get_tx_softbuffer(sched_result.data[i].dci.harq_process, tb); + + /* 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].softbuffers[tb] = NULL; + dl_sched_res->sched_grants[n].data[tb] = NULL; + if (sched_result.data[i].dci.tb_en[tb]) { + Warning("Transport block without PDU elements (rnti: %04x)\n", rnti); + sched_result.data[i].dci.tb_en[tb] = false; + } } - - } else { - dl_sched_res->sched_grants[n].data[0] = NULL; } n++; } - + // Copy RAR grants for (uint32_t i=0;i= 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(0), - 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", @@ -675,7 +676,9 @@ 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(0); + 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()); } } diff --git a/srsenb/src/mac/scheduler_harq.cc b/srsenb/src/mac/scheduler_harq.cc index 85be81406..6e1596850 100644 --- a/srsenb/src/mac/scheduler_harq.cc +++ b/srsenb/src/mac/scheduler_harq.cc @@ -67,7 +67,7 @@ uint32_t harq_proc::get_id() void harq_proc::reset(uint32_t tb_idx) { - active = false; + active[tb_idx] = false; ack[tb_idx] = true; ack_received[tb_idx] = false; n_rtx[tb_idx] = 0; @@ -79,7 +79,7 @@ void harq_proc::reset(uint32_t tb_idx) bool harq_proc::is_empty(uint32_t tb_idx) { - return !active || (active && ack[tb_idx] && ack_received[tb_idx]); + return !active[tb_idx] || (active[tb_idx] && ack[tb_idx] && ack_received[tb_idx]); } bool harq_proc::has_pending_retx_common(uint32_t tb_idx) @@ -104,7 +104,7 @@ void harq_proc::set_ack(uint32_t tb_idx, bool ack_) 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 = false; + active[tb_idx] = false; } } @@ -118,9 +118,9 @@ void harq_proc::new_tx_common(uint32_t tb_idx, uint32_t tti_, int mcs, int tbs) 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 } } @@ -227,10 +227,10 @@ bool ul_harq_proc::has_pending_ack() bool ret = need_ack; // Reset if already received a positive ACK - if (active && ack[0]) { - active = false; + if (active[0] && ack[0]) { + active[0] = false; } - if (!active) { + if (!active[0]) { need_ack = false; } return ret; @@ -240,7 +240,7 @@ bool ul_harq_proc::has_pending_ack() void ul_harq_proc::reset_pending_data() { - if (!active) { + if (!active[0]) { pending_data = 0; } } diff --git a/srsenb/src/mac/scheduler_ue.cc b/srsenb/src/mac/scheduler_ue.cc index 53d4c30cd..f7a1cc407 100644 --- a/srsenb/src/mac/scheduler_ue.cc +++ b/srsenb/src/mac/scheduler_ue.cc @@ -27,11 +27,7 @@ #include #include #include -#include -#include -#include -#include "srslte/srslte.h" #include "srslte/common/pdu.h" #include "mac/scheduler_ue.h" #include "mac/scheduler.h" @@ -109,8 +105,10 @@ void sched_ue::reset() ul_cqi_tti = 0; cqi_request_tti = 0; for (int i=0;ipdu[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); @@ -441,13 +439,14 @@ int sched_ue::generate_format1(dl_harq_proc *h, if (tbs > 0) { dci->harq_process = h->get_id(); - dci->mcs_idx = mcs; + 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 = next_tpc_pucch; + dci->tpc_pucch = (uint8_t) next_tpc_pucch; next_tpc_pucch = 1; - data->tbs[0] = 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; @@ -464,60 +463,90 @@ int sched_ue::generate_format2a(dl_harq_proc *h, uint32_t sf_idx = tti%10; - int mcs = 0; - int tbs = 0; - dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0; dci->type0_alloc.rbg_bitmask = h->get_rbgmask(); - if (h->is_empty(0)) { + 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); + + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + int mcs = 0; + int tbs = 0; + + /* + * If one layer (RI = 0) Then + * If TB1 has pending harq + * Send TB1 only + * Else + * Send TB0 Only + * End If + * Else (RI != 0) + * Send TB0 and TB1 + * End If + */ + if (dl_ri == 1 || (dl_ri == 0 && ((tb == 0 && h->is_empty(1)) || (tb == 1 && !h->is_empty(1))))) { + 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; + } - uint32_t req_bytes = get_pending_dl_new_data(tti); + h->new_tx(tb, tti, mcs, tbs, data->dci_location.ncce); - uint32_t nof_prb = format1_count_prb(h->get_rbgmask(), cell.nof_prb); - srslte_ra_dl_grant_t grant; - srslte_ra_dl_dci_to_grant_prb_allocation(dci, &grant, cell.nof_prb); - uint32_t nof_ctrl_symbols = cfi+(cell.nof_prb<10?1:0); - uint32_t nof_re = srslte_ra_dl_grant_nof_re(&grant, cell, sf_idx, nof_ctrl_symbols); - if (fixed_mcs_dl < 0) { - tbs = alloc_tbs_dl(nof_prb, nof_re, req_bytes, &mcs); - } else { - tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_dl), nof_prb)/8; - mcs = fixed_mcs_dl; + 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); + } } - h->new_tx(0, 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 format1 new mcs=%d, tbs=%d, nof_prb=%d, req_bytes=%d\n", mcs, tbs, nof_prb, req_bytes); - } else { - h->new_retx(0, tti, &mcs, &tbs); - Debug("SCHED: Alloc format1 previous mcs=%d, tbs=%d\n", mcs, tbs); - } + data->rnti = rnti; - int rem_tbs = tbs; - int x = 0; - do { - x = alloc_pdu(rem_tbs, &data->pdu[data->nof_pdu_elems]); - rem_tbs -= x; - if (x) { - data->nof_pdu_elems++; + if (tbs > 0 && data->nof_pdu_elems[tb]) { + 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; } - } while(rem_tbs > 0 && x > 0); - data->rnti = rnti; - - if (tbs > 0) { - dci->harq_process = h->get_id(); - dci->mcs_idx = mcs; - dci->rv_idx = sched::get_rvidx(h->nof_retx(0)); - dci->ndi = h->get_ndi(0); - dci->tpc_pucch = next_tpc_pucch; - next_tpc_pucch = 1; - data->tbs[0] = tbs; - dci->tb_en[0] = true; - dci->tb_en[1] = false; + if ( req_bytes > (uint32_t) tbs) { + req_bytes -= tbs; + } else { + req_bytes = 0; + } } - return tbs; + + 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 @@ -526,71 +555,17 @@ int sched_ue::generate_format2(dl_harq_proc *h, uint32_t tti, uint32_t cfi) { - srslte_ra_dl_dci_t *dci = &data->dci; - bzero(dci, sizeof(srslte_ra_dl_dci_t)); - - uint32_t sf_idx = tti%10; - - int mcs = 0; - int tbs = 0; - - dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0; - dci->type0_alloc.rbg_bitmask = h->get_rbgmask(); - - if (h->is_empty(0)) { - - uint32_t req_bytes = get_pending_dl_new_data(tti); - - uint32_t nof_prb = format1_count_prb(h->get_rbgmask(), cell.nof_prb); - srslte_ra_dl_grant_t grant; - srslte_ra_dl_dci_to_grant_prb_allocation(dci, &grant, cell.nof_prb); - uint32_t nof_ctrl_symbols = cfi+(cell.nof_prb<10?1:0); - uint32_t nof_re = srslte_ra_dl_grant_nof_re(&grant, cell, sf_idx, nof_ctrl_symbols); - if (fixed_mcs_dl < 0) { - tbs = alloc_tbs_dl(nof_prb, nof_re, req_bytes, &mcs); - } else { - tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_dl), nof_prb)/8; - mcs = fixed_mcs_dl; - } + /* Call Format 2a (common) */ + int ret = generate_format2a(h, data, tti, cfi); - h->new_tx(0, tti, mcs, tbs, data->dci_location.ncce); - - Debug("SCHED: Alloc format2 new mcs=%d, tbs=%d, nof_prb=%d, req_bytes=%d\n", mcs, tbs, nof_prb, req_bytes); + /* 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 { - h->new_retx(0, tti, &mcs, &tbs); - Debug("SCHED: Alloc format2 previous mcs=%d, tbs=%d\n", mcs, tbs); + data->dci.pinfo = (uint8_t) (dl_pmi & 1); } - int rem_tbs = tbs; - int x = 0; - do { - x = alloc_pdu(rem_tbs, &data->pdu[data->nof_pdu_elems]); - rem_tbs -= x; - if (x) { - data->nof_pdu_elems++; - } - } while(rem_tbs > 0 && x > 0); - - data->rnti = rnti; - - if (tbs > 0) { - dci->pinfo = (uint8_t) (dl_pmi + 1); -/* if (SRSLTE_RA_DL_GRANT_NOF_TB(dci) == 1) { - dci->pinfo = (uint8_t) (dl_pmi + 1); - } else { - dci->pinfo = (uint8_t) (dl_pmi & 1); - }*/ - dci->harq_process = h->get_id(); - dci->mcs_idx = mcs; - dci->rv_idx = sched::get_rvidx(h->nof_retx(0)); - dci->ndi = h->get_ndi(0); - dci->tpc_pucch = next_tpc_pucch; - next_tpc_pucch = 1; - data->tbs[0] = tbs; - dci->tb_en[0] = true; - dci->tb_en[1] = false; - } - return tbs; + return ret; } @@ -818,7 +793,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 oldest_tti) { oldest_idx = i; @@ -839,7 +814,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 -#include #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__) @@ -98,14 +97,18 @@ void phch_common::ack_clear(uint32_t sf_idx) { for(std::map::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_idxcqi_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)) { @@ -255,6 +257,14 @@ 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 { @@ -355,8 +365,15 @@ void phch_worker::work_imp() phy->ack_clear(TTIMOD(TTI_TX(t_tx_dl))); for (uint32_t i=0;i= 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); + } + } } } @@ -407,17 +424,33 @@ 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; - bool cqi_enabled = false; - if (ue_db[rnti].cqi_en && srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { + bool cqi_enabled = false, ri_enabled = false; +#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_enabled = true; @@ -485,14 +518,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 @@ -507,8 +542,13 @@ 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 @@ -536,7 +576,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, needs_ri=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)); @@ -548,23 +589,23 @@ 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; 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; - bool ri_report_present = dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx_present; - uint32_t pmi_idx = dedicated->cqi_report_cnfg.report_periodic.pmi_cnfg_idx; - uint32_t ri_idx = dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx; - if (ue_db[rnti].cqi_en && (ue_db[rnti].pucch_cqi_ack || !needs_ack)) { - if (ri_report_present && srslte_ri_send(pmi_idx, ri_idx, tti_rx)) { + 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; @@ -582,8 +623,14 @@ 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); @@ -609,12 +656,13 @@ int phch_worker::decode_pucch() } } - 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"):"", - needs_sr?(uci_data.scheduling_request?", sr=yes":", sr=no"):"", + (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 || needs_ri)?cqi_ri_str:""); @@ -728,7 +776,7 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants break; case SRSLTE_DCI_FORMAT2A: if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 1) { - mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; + mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; } else if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 2) { mimo_type = SRSLTE_MIMO_TYPE_CDD; } @@ -765,26 +813,29 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants 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, tx_scheme=%s%s\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, - srslte_mimotype2str(mimo_type), pinfo_str); - } - - srslte_softbuffer_tx_t *sb[SRSLTE_MAX_CODEWORDS]; - uint8_t *d[SRSLTE_MAX_CODEWORDS]; - int rv[SRSLTE_MAX_CODEWORDS]; - - for (int tb = 0; tb < 2; tb++) { - sb[tb] = grants[tb].softbuffers[tb]; - d[tb] = grants[tb].data[tb]; + "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]); } - rv[0] = grants[i].grant.rv_idx; - rv[1] = grants[i].grant.rv_idx_1; + 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, mimo_type)) { + 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; } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 45b89ca82..0f9dd6602 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -389,7 +389,7 @@ void phch_worker::compute_ri() { uci_data.uci_dif_cqi_len = 3; } srslte_bit_unpack_vector(&packed_pmi, uci_data.uci_pmi, uci_data.uci_pmi_len); - Info("pmi=%d\n", packed_pmi); + 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) { @@ -604,7 +604,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); @@ -796,21 +797,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; - } - - if (tb_en[1]) { - uci_data.uci_ack_2 = (uint8_t) ((ack[1]) ? 1 : 0); - nof_tb = 2; + /* 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++; + } } - - uci_data.uci_ack_len = nof_tb; - + uci_data.uci_ack_len = nof_ack; } void phch_worker::set_uci_sr() From 69682d488b1abd2919b81ad736cc81ce9f19c20d Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 9 Nov 2017 15:08:46 +0100 Subject: [PATCH 09/14] eNB: Do not consider CQI/RI if PUCCH has low correlation --- srsenb/src/phy/phch_worker.cc | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc index 4d70853b5..abd7961ce 100644 --- a/srsenb/src/phy/phch_worker.cc +++ b/srsenb/src/phy/phch_worker.cc @@ -637,24 +637,25 @@ int phch_worker::decode_pucch() } char cqi_ri_str[64]; - 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); - - if (uci_data.uci_pmi_len) { - uint8_t *ptr = uci_data.uci_pmi; - 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]; + 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); + + 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); } - 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%s\n", rnti, From 42626a112032eadf32ed29c4d4cb682a749dba6d Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 9 Nov 2017 15:10:03 +0100 Subject: [PATCH 10/14] eNB: retransmissions in Diversity mode --- srsenb/src/mac/scheduler_ue.cc | 38 +++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/srsenb/src/mac/scheduler_ue.cc b/srsenb/src/mac/scheduler_ue.cc index f7a1cc407..1d84031a1 100644 --- a/srsenb/src/mac/scheduler_ue.cc +++ b/srsenb/src/mac/scheduler_ue.cc @@ -458,6 +458,7 @@ int sched_ue::generate_format2a(dl_harq_proc *h, 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)); @@ -473,22 +474,35 @@ int sched_ue::generate_format2a(dl_harq_proc *h, 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 one layer (RI = 0) Then - * If TB1 has pending harq - * Send TB1 only - * Else - * Send TB0 Only - * End If - * Else (RI != 0) - * Send TB0 and TB1 - * End If - */ - if (dl_ri == 1 || (dl_ri == 0 && ((tb == 0 && h->is_empty(1)) || (tb == 1 && !h->is_empty(1))))) { + 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); From 650cc0788cace56760bab0d7d38234c020543245 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 9 Nov 2017 15:10:49 +0100 Subject: [PATCH 11/14] eNB: Added RI metrics trace --- srsenb/src/mac/ue.cc | 2 +- srsenb/src/metrics_stdout.cc | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/srsenb/src/mac/ue.cc b/srsenb/src/mac/ue.cc index a389e7aeb..d41afaf73 100644 --- a/srsenb/src/mac/ue.cc +++ b/srsenb/src/mac/ue.cc @@ -408,7 +408,7 @@ void ue::metrics_phr(float phr) { } void ue::metrics_dl_ri(uint32_t dl_ri) { - metrics.dl_ri = SRSLTE_VEC_CMA((float) dl_ri, metrics.dl_ri, dl_ri_counter); + metrics.dl_ri = SRSLTE_VEC_EMA((float) dl_ri, metrics.dl_ri, 0.5f); dl_ri_counter++; } diff --git a/srsenb/src/metrics_stdout.cc b/srsenb/src/metrics_stdout.cc index ec55b0dcf..efea243f1 100644 --- a/srsenb/src/metrics_stdout.cc +++ b/srsenb/src/metrics_stdout.cc @@ -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); From 2b0a4fa2d05c19f05d7f1017db1393e7befd5536 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 9 Nov 2017 15:42:02 +0100 Subject: [PATCH 12/14] eNB: solved sched-pdsch bug --- lib/src/phy/phch/pdsch.c | 5 ----- srsenb/src/mac/mac.cc | 11 +++-------- srsenb/src/mac/scheduler_ue.cc | 27 ++++++++++++++------------- 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 6479b5abd..1b3a3859d 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -555,11 +555,6 @@ static int srslte_pdsch_codeword_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c valid_inputs = false; } - if (!data) { - ERROR("Error encoding (TB%d -> CW%d), data=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, diff --git a/srsenb/src/mac/mac.cc b/srsenb/src/mac/mac.cc index 69ed37728..80c5e1ddf 100644 --- a/srsenb/src/mac/mac.cc +++ b/srsenb/src/mac/mac.cc @@ -476,10 +476,10 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.data[i].dci_location, sizeof(srslte_dci_location_t)); for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - if (sched_result.data[i].dci.tb_en[tb] && sched_result.data[i].nof_pdu_elems[tb] > 0) { - dl_sched_res->sched_grants[n].softbuffers[tb] = - ue_db[rnti]->get_tx_softbuffer(sched_result.data[i].dci.harq_process, 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], @@ -496,12 +496,7 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) } else { /* TB not enabled OR no data to send: set pointers to NULL */ - dl_sched_res->sched_grants[n].softbuffers[tb] = NULL; dl_sched_res->sched_grants[n].data[tb] = NULL; - if (sched_result.data[i].dci.tb_en[tb]) { - Warning("Transport block without PDU elements (rnti: %04x)\n", rnti); - sched_result.data[i].dci.tb_en[tb] = false; - } } } n++; diff --git a/srsenb/src/mac/scheduler_ue.cc b/srsenb/src/mac/scheduler_ue.cc index 1d84031a1..44c3d3185 100644 --- a/srsenb/src/mac/scheduler_ue.cc +++ b/srsenb/src/mac/scheduler_ue.cc @@ -513,6 +513,16 @@ int sched_ue::generate_format2a(dl_harq_proc *h, 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); @@ -520,19 +530,8 @@ int sched_ue::generate_format2a(dl_harq_proc *h, } } - 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); - - data->rnti = rnti; - - if (tbs > 0 && data->nof_pdu_elems[tb]) { + /* 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)); @@ -556,6 +555,8 @@ int sched_ue::generate_format2a(dl_harq_proc *h, } } + /* Fill common fields */ + data->rnti = rnti; dci->harq_process = h->get_id(); dci->tpc_pucch = (uint8_t) next_tpc_pucch; next_tpc_pucch = 1; From b084b153cf151e96c9144fdfa90a3f0edae32a7f Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 14 Nov 2017 17:11:48 +0100 Subject: [PATCH 13/14] Added UE Mode 3-1 aperiodic reporting --- lib/include/srslte/phy/phch/cqi.h | 21 +++- lib/include/srslte/phy/phch/uci.h | 1 + lib/src/phy/phch/cqi.c | 73 +++++++++++-- lib/src/phy/phch/pucch.c | 2 +- lib/src/phy/ue/ue_dl.c | 4 +- lib/src/phy/ue/ue_ul.c | 28 +++-- srsenb/src/phy/phch_worker.cc | 2 +- srsue/hdr/phy/phch_worker.h | 3 +- srsue/src/phy/phch_worker.cc | 175 ++++++++++++++++++++---------- 9 files changed, 221 insertions(+), 88 deletions(-) diff --git a/lib/include/srslte/phy/phch/cqi.h b/lib/include/srslte/phy/phch/cqi.h index cfc9e92e7..0d0c17fec 100644 --- a/lib/include/srslte/phy/phch/cqi.h +++ b/lib/include/srslte/phy/phch/cqi.h @@ -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 diff --git a/lib/include/srslte/phy/phch/uci.h b/lib/include/srslte/phy/phch/uci.h index ff315384e..91592501f 100644 --- a/lib/include/srslte/phy/phch/uci.h +++ b/lib/include/srslte/phy/phch/uci.h @@ -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; diff --git a/lib/src/phy/phch/cqi.c b/lib/src/phy/phch/cqi.c index 0041c3fcb..2c0940af5 100644 --- a/lib/src/phy/phch/cqi.c +++ b/lib/src/phy/phch/cqi.c @@ -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) diff --git a/lib/src/phy/phch/pucch.c b/lib/src/phy/phch/pucch.c index 498d34f3a..8e60f9f2c 100644 --- a/lib/src/phy/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -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; diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 1c3b79440..a677aa70d 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -684,6 +684,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; } @@ -719,9 +720,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; diff --git a/lib/src/phy/ue/ue_ul.c b/lib/src/phy/ue/ue_ul.c index 853937f7c..1351cfca6 100644 --- a/lib/src/phy/ue/ue_ul.c +++ b/lib/src/phy/ue/ue_ul.c @@ -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 diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc index 103017fcc..fd7501547 100644 --- a/srsenb/src/phy/phch_worker.cc +++ b/srsenb/src/phy/phch_worker.cc @@ -445,7 +445,7 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) 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; } snprintf(cqi_str, 64, ", cqi=%d", wideband_cqi_value); } diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index c26966c17..12d14756c 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -74,7 +74,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); diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index ff7412d77..2a489e7c2 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -255,39 +255,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); - } - } } } @@ -343,7 +310,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()) { @@ -392,6 +359,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 = false; @@ -797,21 +800,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; - } - - if (tb_en[1]) { - uci_data.uci_ack_2 = (uint8_t) ((ack[1]) ? 1 : 0); - nof_tb = 2; + /* 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++; + } } - - uci_data.uci_ack_len = nof_tb; - + uci_data.uci_ack_len = nof_ack; } void phch_worker::set_uci_sr() @@ -836,14 +833,9 @@ 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(); + 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) { @@ -865,6 +857,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; } @@ -886,18 +888,71 @@ 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) { + /* Compute RI, PMI and SINR */ + compute_ri(); + + /* 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=%d/%d, SINR=%2.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; 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]); @@ -979,7 +1034,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 From e2a61af462a9d4a4c75c531c0aedc520ddeed105 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 16 Nov 2017 14:48:03 +0100 Subject: [PATCH 14/14] Added Aperiodic mode 3-1 in enb and some more optimizations --- lib/include/srslte/phy/enb/enb_ul.h | 1 + lib/include/srslte/phy/phch/pusch.h | 1 + lib/include/srslte/phy/phch/uci.h | 36 +++--- lib/src/phy/enb/enb_ul.c | 10 +- lib/src/phy/phch/cqi.c | 37 +++++- lib/src/phy/phch/pusch.c | 35 +++++- lib/src/phy/phch/sch.c | 19 +-- lib/src/phy/phch/test/pusch_test.c | 2 +- lib/src/phy/phch/uci.c | 180 ++++++++++------------------ lib/src/phy/ue/ue_dl.c | 3 +- srsenb/src/phy/phch_worker.cc | 35 ++++-- srsenb/src/upper/rrc.cc | 6 +- srsue/src/phy/phch_worker.cc | 16 +-- 13 files changed, 200 insertions(+), 181 deletions(-) diff --git a/lib/include/srslte/phy/enb/enb_ul.h b/lib/include/srslte/phy/enb/enb_ul.h index 6839cfc9e..8699a2a37 100644 --- a/lib/include/srslte/phy/enb/enb_ul.h +++ b/lib/include/srslte/phy/enb/enb_ul.h @@ -140,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); diff --git a/lib/include/srslte/phy/phch/pusch.h b/lib/include/srslte/phy/phch/pusch.h index 2328c8ff3..01db068a5 100644 --- a/lib/include/srslte/phy/phch/pusch.h +++ b/lib/include/srslte/phy/phch/pusch.h @@ -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); diff --git a/lib/include/srslte/phy/phch/uci.h b/lib/include/srslte/phy/phch/uci.h index c20fca239..6ea00c5d1 100644 --- a/lib/include/srslte/phy/phch/uci.h +++ b/lib/include/srslte/phy/phch/uci.h @@ -136,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 diff --git a/lib/src/phy/enb/enb_ul.c b/lib/src/phy/enb/enb_ul.c index c492369dc..8ea5dd3e4 100644 --- a/lib/src/phy/enb/enb_ul.c +++ b/lib/src/phy/enb/enb_ul.c @@ -290,10 +290,9 @@ 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]; - uint8_t *pucch_bits_ptr = pucch_bits; if (q->users[rnti]) { - uint32_t nof_uci_bits = (uci_data->uci_ri_len > 0) ? uci_data->uci_ri_len : (uci_data->uci_cqi_len + + 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); @@ -312,11 +311,11 @@ 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_ptr++); + uci_data->uci_ack = pucch_bits[0]; } if (uci_data->uci_ack_len > 1) { - uci_data->uci_ack_2 = *(pucch_bits_ptr++); + uci_data->uci_ack_2 = pucch_bits[1]; } // PUCCH2 CQI bits are decoded inside srslte_pucch_decode() @@ -355,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, @@ -391,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); } diff --git a/lib/src/phy/phch/cqi.c b/lib/src/phy/phch/cqi.c index 2c0940af5..8589ee51a 100644 --- a/lib/src/phy/phch/cqi.c +++ b/lib/src/phy/phch/cqi.c @@ -199,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) { diff --git a/lib/src/phy/phch/pusch.c b/lib/src/phy/phch/pusch.c index ba1195507..c3e4e45f8 100644 --- a/lib/src/phy/phch/pusch.c +++ b/lib/src/phy/phch/pusch.c @@ -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) { diff --git a/lib/src/phy/phch/sch.c b/lib/src/phy/phch/sch.c index 930364725..1e972594d 100644 --- a/lib/src/phy/phch/sch.c +++ b/lib/src/phy/phch/sch.c @@ -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; } diff --git a/lib/src/phy/phch/test/pusch_test.c b/lib/src/phy/phch/test/pusch_test.c index cf0be75c3..651803617 100644 --- a/lib/src/phy/phch/test/pusch_test.c +++ b/lib/src/phy/phch/test/pusch_test.c @@ -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) { diff --git a/lib/src/phy/phch/uci.c b/lib/src/phy/phch/uci.c index 0b9a54058..8a1a36544 100644 --- a/lib/src/phy/phch/uci.c +++ b/lib/src/phy/phch/uci.c @@ -606,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; @@ -618,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;igrant.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; @@ -665,120 +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 (nof_acks == 1 && acks) { - acks[0] = (uint8_t)(acks_sum[0] + acks_sum[1] + acks_sum[2] > 0); - } else 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;igrant.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;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]); - if ((i % 3 == 0) && i > 0) { - //decode_ri_ack(q_bits, &c_seq[0], &ri_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, ri_sum); - } - } + for (uint32_t i = 0; i < Qprime; i++) { + if (is_ri) { + uci_ulsch_interleave_ri_gen(i, + cfg->grant.Qm, + H_prime_total, + cfg->nbits.nof_symb, + cfg->cp, + &ack_ri_bits[cfg->grant.Qm * i]); + } else { + uci_ulsch_interleave_ack_gen(i, + cfg->grant.Qm, + H_prime_total, + cfg->nbits.nof_symb, + cfg->cp, + &ack_ri_bits[cfg->grant.Qm * i]); - if (data) { - *data = (uint8_t) ((ri_sum[0] + ri_sum[1] + ri_sum[2]) > 0); + } + 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]); + } } - 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; + data[0] = (uint8_t) (sum[0] > 0); + if (nof_bits == 2) { + data[1] = (uint8_t) (sum[1] > 0); } - 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;igrant.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; } - diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index a677aa70d..3a3198dea 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -669,7 +669,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); diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc index 8ed6428ef..990633aa7 100644 --- a/srsenb/src/phy/phch_worker.cc +++ b/srsenb/src/phy/phch_worker.cc @@ -435,8 +435,8 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) } // Configure PUSCH CQI channel - srslte_cqi_value_t cqi_value; - bool cqi_enabled = false, ri_enabled = false; + srslte_cqi_value_t cqi_value = {0}; + bool cqi_enabled = false; #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 */ @@ -450,14 +450,13 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) } } else #endif - if (grants[i].grant.cqi_request) { + 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; @@ -473,6 +472,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 { @@ -494,11 +494,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_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); } @@ -551,13 +564,19 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) } } - // 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)); diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index 4dde48be1..6bf5bc698 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -1153,7 +1153,11 @@ 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; diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 088c4a22c..f4dd2a8b5 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -303,8 +303,6 @@ void phch_worker::work_imp() /* Transmit PUSCH, PUCCH or SRS */ bool signal_ready = false; if (ul_action.tx_enabled) { - compute_ri(); - encode_pusch(&ul_action.phy_grant.ul, ul_action.payload_ptr[0], ul_action.current_tx_nb, &ul_action.softbuffers[0], ul_action.rv[0], ul_action.rnti, ul_mac_grant.is_from_rar); signal_ready = true; @@ -841,7 +839,9 @@ 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))) { + /* 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))) { @@ -884,6 +884,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 @@ -921,9 +924,6 @@ void phch_worker::set_uci_aperiodic_cqi() other transmission modes they are reported conditioned on rank 1. */ if (rnti_is_set) { - /* Compute RI, PMI and SINR */ - compute_ri(); - /* 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 @@ -954,9 +954,9 @@ void phch_worker::set_uci_aperiodic_cqi() 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=%d/%d, SINR=%2.1f dB, for %d subbands\n", - cqi_report.wideband.wideband_cqi, - phy->avg_snr_db, cqi_report.subband_hl.N); + 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); }