From aeb16a5b7a24f4af9554c56df0ad7c80db0a003f Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Thu, 9 Nov 2017 17:43:13 +0100 Subject: [PATCH 01/15] Fixed TA command when negative offset --- srsue/src/phy/phy.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index fe5528d79..6dfb2c6d7 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -199,9 +199,10 @@ void phy::set_timeadv_rar(uint32_t ta_cmd) { } void phy::set_timeadv(uint32_t ta_cmd) { - n_ta = srslte_N_ta_new(n_ta, ta_cmd); - sf_recv.set_time_adv_sec(((float) n_ta)*SRSLTE_LTE_TS); - Info("PHY: Set TA: ta_cmd: %d, n_ta: %d, ta_usec: %.1f\n", ta_cmd, n_ta, ((float) n_ta)*SRSLTE_LTE_TS*1e6); + uint32_t new_nta = srslte_N_ta_new(n_ta, ta_cmd); + sf_recv.set_time_adv_sec(((float) (new_nta - n_ta))*SRSLTE_LTE_TS); + Info("PHY: Set TA: ta_cmd: %d, n_ta: %d, old_n_ta: %d, ta_usec: %.1f\n", ta_cmd, new_nta, n_ta, ((float) new_nta)*SRSLTE_LTE_TS*1e6); + n_ta = new_nta; } void phy::configure_prach_params() From a992fcf6079ce6f3391be2f1f0aab9dc389246e7 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 10 Nov 2017 07:42:45 +0100 Subject: [PATCH 02/15] Fix concurrent access segfault in RLC AM --- lib/src/upper/rlc_am.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index 05f35ad76..96405e22a 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -296,8 +296,9 @@ int rlc_am::read_pdu(uint8_t *payload, uint32_t nof_bytes) } // RETX if required if(retx_queue.size() > 0) { + int ret = build_retx_pdu(payload, nof_bytes); pthread_mutex_unlock(&mutex); - return build_retx_pdu(payload, nof_bytes); + return ret; } // Build a PDU from SDUs From bf32d45b6fbfc0ba7b1ba88994cbf06d5f38d8b3 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 10 Nov 2017 07:54:30 +0100 Subject: [PATCH 03/15] Check valid nof_tb before call to pdsch and log instead of print --- srsue/src/phy/phch_worker.cc | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 3629424ac..a8ffeabcb 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -539,10 +539,15 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL } } + uint32_t nof_tb = SRSLTE_RA_DL_GRANT_NOF_TB(grant); switch(phy->config->dedicated.antenna_info_explicit_value.tx_mode) { /* Implemented Tx Modes */ case LIBLTE_RRC_TRANSMISSION_MODE_1: mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + if (nof_tb != 1) { + Error("Wrong number of transport blocks (%d) for single antenna.", nof_tb); + valid_config = false; + } break; case LIBLTE_RRC_TRANSMISSION_MODE_2: if (cell.nof_ports > 1) { @@ -550,26 +555,30 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL } else { mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; } + if (nof_tb != 1) { + Error("Wrong number of transport blocks (%d) for transmit diversity.", nof_tb); + valid_config = false; + } break; case LIBLTE_RRC_TRANSMISSION_MODE_3: - if (SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 1) { + if (nof_tb == 1) { mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - } else if (ue_dl.nof_rx_antennas > 1 && SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 2) { + } else if (ue_dl.nof_rx_antennas > 1 && nof_tb == 2) { mimo_type = SRSLTE_MIMO_TYPE_CDD; } else { Error("Wrong combination of antennas (%d) or transport blocks (%d) for TM3\n", ue_dl.nof_rx_antennas, - SRSLTE_RA_DL_GRANT_NOF_TB(grant)); + nof_tb); valid_config = false; } break; case LIBLTE_RRC_TRANSMISSION_MODE_4: - if (SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 1) { + if (nof_tb == 1) { mimo_type = (grant->pinfo == 0) ? SRSLTE_MIMO_TYPE_TX_DIVERSITY : SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - } else if (ue_dl.nof_rx_antennas > 1 && SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 2) { + } else if (ue_dl.nof_rx_antennas > 1 && nof_tb == 2) { mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; } else { Error("Wrong combination of antennas (%d) or transport blocks (%d) for TM3\n", ue_dl.nof_rx_antennas, - SRSLTE_RA_DL_GRANT_NOF_TB(grant)); + nof_tb); valid_config = false; } break; From e983987563128be7ff70da3cbc1d9fddb03bfe3a Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 10 Nov 2017 09:09:46 +0100 Subject: [PATCH 04/15] Check retx.sn exists in tx_window in required buffer size --- lib/src/upper/rlc_am.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index 96405e22a..0d3d8e426 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -1148,7 +1148,13 @@ bool rlc_am::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pd int rlc_am::required_buffer_size(rlc_amd_retx_t retx) { if(!retx.is_segment){ - return rlc_am_packed_length(&tx_window[retx.sn].header) + tx_window[retx.sn].buf->N_bytes; + if (tx_window.count(retx.sn)) { + return rlc_am_packed_length(&tx_window[retx.sn].header) + tx_window[retx.sn].buf->N_bytes; + } else { + log->console("retx.sn=%d does not exist\n"); + log->warning("retx.sn=%d does not exist in required_buffer_size()\n"); + return -1; + } } // Construct new header From 05973790ba8d800b811a86a6821523b4d1de5bfe Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 10 Nov 2017 12:39:28 +0100 Subject: [PATCH 05/15] Add checks for existence of retx buffer and remove from queue if not --- lib/src/upper/rlc_am.cc | 53 +++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index 0d3d8e426..b6599f24a 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -201,8 +201,14 @@ uint32_t rlc_am::get_total_buffer_state() rlc_amd_retx_t retx = retx_queue.front(); log->debug("Buffer state - retx - SN: %d, Segment: %s, %d:%d\n", retx.sn, retx.is_segment ? "true" : "false", retx.so_start, retx.so_end); if(tx_window.end() != tx_window.find(retx.sn)) { - n_bytes += required_buffer_size(retx); + int req_bytes = required_buffer_size(retx); + if (req_bytes < 0) { + log->error("In get_total_buffer_state(): Removing retx.sn=%d from queue\n", retx.sn); + retx_queue.pop_front(); + } else { + n_bytes += req_bytes; log->debug("Buffer state - retx: %d bytes\n", n_bytes); + } } } @@ -250,7 +256,13 @@ uint32_t rlc_am::get_buffer_state() rlc_amd_retx_t retx = retx_queue.front(); log->debug("Buffer state - retx - SN: %d, Segment: %s, %d:%d\n", retx.sn, retx.is_segment ? "true" : "false", retx.so_start, retx.so_end); if(tx_window.end() != tx_window.find(retx.sn)) { - n_bytes = required_buffer_size(retx); + int req_bytes = required_buffer_size(retx); + if (req_bytes < 0) { + log->error("In get_buffer_state(): Removing retx.sn=%d from queue\n", retx.sn); + retx_queue.pop_front(); + goto unlock_and_return; + } + n_bytes = (uint32_t) req_bytes; log->debug("Buffer state - retx: %d bytes\n", n_bytes); goto unlock_and_return; } @@ -439,16 +451,33 @@ int rlc_am::build_status_pdu(uint8_t *payload, uint32_t nof_bytes) int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) { + // Check there is at least 1 element before calling front() + if (retx_queue.empty()) { + log->error("In build_retx_pdu(): retx_queue is empty\n"); + return -1; + } + rlc_amd_retx_t retx = retx_queue.front(); // Sanity check - drop any retx SNs not present in tx_window while(tx_window.end() == tx_window.find(retx.sn)) { retx_queue.pop_front(); - retx = retx_queue.front(); + if (!retx_queue.empty()) { + retx = retx_queue.front(); + } else { + log->error("In build_retx_pdu(): retx_queue is empty during sanity check\n"); + return -1; + } } // Is resegmentation needed? - if(retx.is_segment || required_buffer_size(retx) > (int)nof_bytes) { + int req_size = required_buffer_size(retx); + if (req_size < 0) { + log->error("In build_retx_pdu(): Removing retx.sn=%d from queue\n", retx.sn); + retx_queue.pop_front(); + return -1; + } + if(retx.is_segment || req_size > (int)nof_bytes) { log->debug("%s build_retx_pdu - resegmentation required\n", rrc->get_rb_name(lcid).c_str()); return build_segment(payload, nof_bytes, retx); } @@ -482,6 +511,10 @@ int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t retx) { + if (!tx_window[retx.sn].buf) { + log->error("In build_segment: retx.sn=%d has null buffer\n", retx.sn); + return 0; + } if(!retx.is_segment){ retx.so_start = 0; retx.so_end = tx_window[retx.sn].buf->N_bytes; @@ -1149,10 +1182,16 @@ int rlc_am::required_buffer_size(rlc_amd_retx_t retx) { if(!retx.is_segment){ if (tx_window.count(retx.sn)) { - return rlc_am_packed_length(&tx_window[retx.sn].header) + tx_window[retx.sn].buf->N_bytes; + if (tx_window[retx.sn].buf) { + return rlc_am_packed_length(&tx_window[retx.sn].header) + tx_window[retx.sn].buf->N_bytes; + } else { + log->console("retx.sn=%d has null ptr\n", retx.sn); + log->warning("retx.sn=%d has null ptr in required_buffer_size()\n", retx.sn); + return -1; + } } else { - log->console("retx.sn=%d does not exist\n"); - log->warning("retx.sn=%d does not exist in required_buffer_size()\n"); + log->console("retx.sn=%d does not exist\n", retx.sn); + log->warning("retx.sn=%d does not exist in required_buffer_size()\n", retx.sn); return -1; } } From 42d08046d372ce2446547a95cbf41663ddd37a64 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 10 Nov 2017 17:59:35 +0100 Subject: [PATCH 06/15] Fixed bug with UL adaptive retx --- lib/include/srslte/common/common.h | 1 + srsue/hdr/mac/ul_harq.h | 6 ++++-- srsue/src/phy/phch_worker.cc | 26 +++++++++++++++----------- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/lib/include/srslte/common/common.h b/lib/include/srslte/common/common.h index 6372af73e..c450fc1d0 100644 --- a/lib/include/srslte/common/common.h +++ b/lib/include/srslte/common/common.h @@ -46,6 +46,7 @@ #define HARQ_DELAY_MS 4 #define MSG3_DELAY_MS 2 // Delay added to HARQ_DELAY_MS +#define TTI_RX(tti) (tti>HARQ_DELAY_MS?((tti-HARQ_DELAY_MS)%10240):(10240+tti-HARQ_DELAY_MS)) #define TTI_TX(tti) ((tti+HARQ_DELAY_MS)%10240) #define TTI_RX_ACK(tti) ((tti+(2*HARQ_DELAY_MS))%10240) diff --git a/srsue/hdr/mac/ul_harq.h b/srsue/hdr/mac/ul_harq.h index 4749971b6..50143a571 100644 --- a/srsue/hdr/mac/ul_harq.h +++ b/srsue/hdr/mac/ul_harq.h @@ -219,7 +219,7 @@ private: // Receive and route HARQ feedbacks if (grant) { - if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi[0] != get_ndi()) || + if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi[0] != get_ndi() && grant->phy_grant.ul.mcs.idx < 29) || (grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) || grant->is_from_rar) { @@ -245,7 +245,7 @@ private: Warning("Uplink grant but no MAC PDU in Multiplex Unit buffer\n"); } } - } else { + } else if (has_grant()) { // Adaptive Re-TX if (current_tx_nb >= max_retx) { Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx); @@ -254,6 +254,8 @@ private: } else { generate_retx(tti_tx, grant, action); } + } else { + Warning("UL %d: Received mcs=%d but no previous grant available for this PID.\n", pid, grant->phy_grant.ul.mcs.idx); } } else if (has_grant()) { // Non-Adaptive Re-Tx diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index a8ffeabcb..ff7412d77 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -27,6 +27,7 @@ #include #include #include "phy/phch_worker.h" +#include "srslte/srslte.h" #include "srslte/interfaces/ue_interfaces.h" #include "srslte/asn1/liblte_rrc.h" @@ -40,8 +41,6 @@ #ifdef ENABLE_GUI #include "srsgui/srsgui.h" #include -#include "srslte/srslte.h" -#include "srslte/interfaces/ue_interfaces.h" void init_plots(srsue::phch_worker *worker); pthread_t plot_thread; @@ -323,9 +322,9 @@ void phch_worker::work_imp() ul_action.tti_offset = HARQ_DELAY_MS; /* Send UL grant or HARQ information (from PHICH) to MAC */ - if (ul_grant_available && ul_ack_available) { + if (ul_grant_available && ul_ack_available && ul_mac_grant.phy_grant.ul.mcs.idx < 29) { phy->mac->new_grant_ul_ack(ul_mac_grant, ul_ack, &ul_action); - } else if (ul_grant_available && !ul_ack_available) { + } else if (ul_grant_available && (!ul_ack_available || ul_mac_grant.phy_grant.ul.mcs.idx < 29)) { phy->mac->new_grant_ul(ul_mac_grant, &ul_action); } else if (!ul_grant_available && ul_ack_available) { phy->mac->harq_recv(tti, ul_ack, &ul_action); @@ -480,11 +479,15 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant) grant->pid = ASYNC_DL_SCHED?dci_unpacked.harq_process:(tti%(2*HARQ_DELAY_MS)); - // Set last TBS for this TB (pid) in case of mcs>29 (7.1.7.2 of 36.213) + // Set last TBS for this TB (pid) in case of mcs>28 (7.1.7.2 of 36.213) for (int i=0;iphy_grant.dl.mcs[i].tbs < 0) { + if (grant->phy_grant.dl.mcs[i].idx > 28) { grant->phy_grant.dl.mcs[i].tbs = last_dl_tbs[grant->pid%(2*HARQ_DELAY_MS)][i]; } + if(grant->phy_grant.dl.mcs[i].tbs < 0) { + Info("Invalid TBS size for PDSCH grant\n"); + grant->phy_grant.dl.mcs[i].tbs = 0; + } // save it last_dl_tbs[grant->pid%(2*HARQ_DELAY_MS)][i] = grant->phy_grant.dl.mcs[i].tbs; } @@ -743,16 +746,17 @@ bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant) if (ret) { // Use last TBS for this TB in case of mcs>28 - if (grant->phy_grant.ul.mcs.tbs < 0) { - grant->phy_grant.ul.mcs.tbs = last_ul_tbs[tti%(2*HARQ_DELAY_MS)]; + if (grant->phy_grant.ul.mcs.idx > 28) { + grant->phy_grant.ul.mcs.tbs = last_ul_tbs[TTI_RX(tti)%(2*HARQ_DELAY_MS)]; + Info("RETX: mcs=%d, old_tbs=%d pid=%d\n", grant->phy_grant.ul.mcs.idx, grant->phy_grant.ul.mcs.tbs, TTI_TX(tti)%(2*HARQ_DELAY_MS)); } - last_ul_tbs[tti%(2*HARQ_DELAY_MS)] = grant->phy_grant.ul.mcs.tbs; + last_ul_tbs[TTI_RX(tti)%(2*HARQ_DELAY_MS)] = grant->phy_grant.ul.mcs.tbs; if (grant->phy_grant.ul.mcs.mod == SRSLTE_MOD_LAST) { - grant->phy_grant.ul.mcs.mod = last_ul_mod[tti%(2*HARQ_DELAY_MS)]; + grant->phy_grant.ul.mcs.mod = last_ul_mod[TTI_RX(tti)%(2*HARQ_DELAY_MS)]; grant->phy_grant.ul.Qm = srslte_mod_bits_x_symbol(grant->phy_grant.ul.mcs.mod); } - last_ul_mod[tti%(2*HARQ_DELAY_MS)] = grant->phy_grant.ul.mcs.mod; + last_ul_mod[TTI_RX(tti)%(2*HARQ_DELAY_MS)] = grant->phy_grant.ul.mcs.mod; } /* Limit UL modulation if not supported by the UE or disabled by higher layers */ From 9389cc1957116784b2ff0670bd3793d36087784e Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 10 Nov 2017 17:59:43 +0100 Subject: [PATCH 07/15] Removed deallocating unkown buffer error --- lib/include/srslte/common/buffer_pool.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/include/srslte/common/buffer_pool.h b/lib/include/srslte/common/buffer_pool.h index 1c6dfc53a..567203c75 100644 --- a/lib/include/srslte/common/buffer_pool.h +++ b/lib/include/srslte/common/buffer_pool.h @@ -123,8 +123,6 @@ public: used.erase(elem); available.push(b); ret = true; - } else { - printf("Error deallocating from buffer pool: buffer not created in this pool.\n"); } pthread_mutex_unlock(&mutex); return ret; From 9cf95f5c32c90044eb33cb659430145aff68cbab Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 10 Nov 2017 18:00:05 +0100 Subject: [PATCH 08/15] Attempt to reset timer regardless of N310 --- srsue/hdr/upper/rrc.h | 2 ++ srsue/src/upper/rrc.cc | 13 ++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index 3e2fb70dd..0e123e988 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -127,6 +127,8 @@ private: // RRC constants and timers srslte::mac_interface_timers *mac_timers; + uint32_t sync_reset_cnt; + const static uint32_t SYNC_RESET_TIMEOUT = 10; uint32_t n310_cnt, N310; uint32_t n311_cnt, N311; uint32_t t301, t310, t311; diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 10373dcf2..7b4bef710 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -48,6 +48,9 @@ rrc::rrc() :state(RRC_STATE_IDLE) ,drb_up(false) { + sync_reset_cnt = 0; + n310_cnt = 0; + n311_cnt = 0; } static void liblte_rrc_handler(void *ctx, char *str) { @@ -489,13 +492,17 @@ void rrc::earfcn_end() { // Detection of physical layer problems (5.3.11.1) void rrc::out_of_sync() { + // attempt resync + sync_reset_cnt++; + if (sync_reset_cnt >= SYNC_RESET_TIMEOUT) { + rrc_log->info("Detected %d out-of-sync from PHY. Resynchronizing PHY.\n", sync_reset_cnt); + phy->sync_reset(); + sync_reset_cnt = 0; + } current_cell->in_sync = false; if (!mac_timers->timer_get(t311)->is_running() && !mac_timers->timer_get(t310)->is_running()) { n310_cnt++; if (n310_cnt == N310) { - // attempt resync - //phy->sync_reset(); - mac_timers->timer_get(t310)->reset(); mac_timers->timer_get(t310)->run(); n310_cnt = 0; From 4eb5ee5c582e5fa83bfc9e4ce8f754495d9b94ad Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 10 Nov 2017 18:01:32 +0100 Subject: [PATCH 09/15] Removed console debugging messages --- lib/src/upper/rlc_am.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index b6599f24a..f8abc0aef 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -1185,12 +1185,10 @@ int rlc_am::required_buffer_size(rlc_amd_retx_t retx) if (tx_window[retx.sn].buf) { return rlc_am_packed_length(&tx_window[retx.sn].header) + tx_window[retx.sn].buf->N_bytes; } else { - log->console("retx.sn=%d has null ptr\n", retx.sn); log->warning("retx.sn=%d has null ptr in required_buffer_size()\n", retx.sn); return -1; } } else { - log->console("retx.sn=%d does not exist\n", retx.sn); log->warning("retx.sn=%d does not exist in required_buffer_size()\n", retx.sn); return -1; } From 710cb583b0fe696a3b403c8ed0f838ba2a83b7a9 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 10 Nov 2017 18:02:34 +0100 Subject: [PATCH 10/15] Make last pdu in grant to use all available space. Fixes when 1 byte is in RLC AM but grant is 3 bytes (header is 2) --- srsue/src/mac/mux.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/srsue/src/mac/mux.cc b/srsue/src/mac/mux.cc index e38300b87..957c257a1 100644 --- a/srsue/src/mac/mux.cc +++ b/srsue/src/mac/mux.cc @@ -286,7 +286,7 @@ bool mux::sched_sdu(lchid_t *ch, int *sdu_space, int max_sdu_sz) } log_h->info("SDU: scheduled lcid=%d, rlc_buffer=%d, allocated=%d/%d\n", - ch->id, ch->buffer_len, sched_len, *sdu_space); + ch->id, ch->buffer_len, sched_len, sdu_space?*sdu_space:0); *sdu_space -= sched_len; ch->buffer_len -= sched_len; @@ -309,12 +309,11 @@ bool mux::allocate_sdu(uint32_t lcid, srslte::sch_pdu* pdu_msg, int max_sdu_sz) sdu_len = max_sdu_sz; } int sdu_space = pdu_msg->get_sdu_space(); - if (sdu_len > sdu_space) { + if (sdu_len > sdu_space || max_sdu_sz < 0) { sdu_len = sdu_space; - } + } if (sdu_len > MIN_RLC_SDU_LEN) { if (pdu_msg->new_subh()) { // there is space for a new subheader - int sdu_len2 = sdu_len; sdu_len = pdu_msg->get()->set_sdu(lcid, sdu_len, rlc); if (sdu_len > 0) { // new SDU could be added From e5f78b16204bbe9f5a0b7bc14590827a73fe352c Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 10 Nov 2017 19:11:15 +0100 Subject: [PATCH 11/15] Print error to console if security/integrity not supported --- srsue/src/upper/nas.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 110c8c78e..d8bd40c6e 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -480,6 +480,7 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) { sec_mode_cmd.nas_ksi.tsc_flag != LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE) { sec_mode_rej.emm_cause = LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH; nas_log->warning("Sending Security Mode Reject due to security capabilities mismatch\n"); + nas_log->console("Unsupported Security Mode Command settings: use ciphering algorithm EEA0 and integrity check EIA1 or EIA2.\n"); success = false; } else { // Generate NAS encryption key and integrity protection key From b23be658cc2efdd84f290164360871037fb38d70 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 13 Nov 2017 10:14:11 +0100 Subject: [PATCH 12/15] Added PDSCH decoder maximum bitrate (from DSP execution time) --- lib/examples/pdsch_ue.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index bf4414f08..681b75566 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -326,7 +326,8 @@ srslte_netsink_t net_sink, net_sink_signal; #define PRINT_LINE_ADVANCE_CURSOR() printf("\033[%dB", prev_nof_lines + 1) int main(int argc, char **argv) { - int ret; + struct timeval t[3]; + int ret; int decimate = 1; srslte_cell_t cell; int64_t sf_cnt; @@ -559,7 +560,7 @@ int main(int argc, char **argv) { // Variables for measurements uint32_t nframes=0; uint8_t ri = 0, pmi = 0; - float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0, enodebrate = 0.0, uerate = 0.0, + float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0, enodebrate = 0.0, uerate = 0.0, procrate = 0.0, sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS], cn = 0.0; bool decode_pdsch = false; @@ -655,6 +656,7 @@ int main(int argc, char **argv) { decode_pdsch = false; } } + gettimeofday(&t[1], NULL); if (decode_pdsch) { if(sfidx != 1 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe if (cell.nof_ports == 1) { @@ -690,6 +692,8 @@ int main(int argc, char **argv) { INFO("mbsfn PDU size is %d\n", n); } } + gettimeofday(&t[2], NULL); + get_time_interval(t); if (n < 0) { // fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); } else if (n > 0) { @@ -723,16 +727,19 @@ int main(int argc, char **argv) { } - nof_trials++; - - + nof_trials++; + + uint32_t nof_bits = ((acks[0]?ue_dl.pdsch_cfg.grant.mcs[0].tbs:0) + (acks[1]?ue_dl.pdsch_cfg.grant.mcs[1].tbs:0)); rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1f); rsrp0 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 0), rsrp0, 0.05f); rsrp1 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 1), rsrp1, 0.05f); noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05f); - enodebrate = SRSLTE_VEC_EMA((ue_dl.pdsch_cfg.grant.mcs[0].tbs + ue_dl.pdsch_cfg.grant.mcs[1].tbs)/1000.0f, enodebrate, 0.05f); - uerate = SRSLTE_VEC_EMA(((acks[0]?ue_dl.pdsch_cfg.grant.mcs[0].tbs:0) + (acks[1]?ue_dl.pdsch_cfg.grant.mcs[1].tbs:0))/1000.0f, uerate, 0.01f); - + enodebrate = SRSLTE_VEC_EMA(nof_bits/1000.0f, enodebrate, 0.05f); + uerate = SRSLTE_VEC_EMA(nof_bits/1000.0f, uerate, 0.001f); + float elapsed = (float) t[0].tv_usec + t[0].tv_sec*1.0e+6f; + if (elapsed != 0.0f) { + procrate = SRSLTE_VEC_EMA(nof_bits/elapsed, procrate, 0.01f); + } nframes++; if (isnan(rsrq)) { @@ -769,7 +776,7 @@ int main(int argc, char **argv) { PRINT_LINE("nof codewords: %d", SRSLTE_RA_DL_GRANT_NOF_TB(&ue_dl.pdsch_cfg.grant)); PRINT_LINE(" CFO: %+5.2f kHz", srslte_ue_sync_get_cfo(&ue_sync) / 1000); PRINT_LINE(" SNR: %+5.1f dB | %+5.1f dB", 10 * log10(rsrp0 / noise), 10 * log10(rsrp1 / noise)); - PRINT_LINE(" Rb: %6.2f / %6.2f Mbps (net/maximum)", uerate, enodebrate); + PRINT_LINE(" Rb: %6.2f / %6.2f / %6.2f Mbps (net/maximum/processing)", uerate, enodebrate, procrate); PRINT_LINE(" PDCCH-Miss: %5.2f%%", 100 * (1 - (float) ue_dl.nof_detected / nof_trials)); PRINT_LINE(" PDSCH-BLER: %5.2f%%", (float) 100 * ue_dl.pdsch_pkt_errors / ue_dl.pdsch_pkts_total); if(prog_args.mbsfn_area_id > -1){ From ca07f0064dcf3d7cde67a8bfb1be722a9aeeac03 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 13 Nov 2017 10:47:02 +0100 Subject: [PATCH 13/15] Remove otw_format=sc12/sc16 from device args, also commas. --- lib/src/phy/rf/rf_uhd_imp.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/src/phy/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c index 29aec5b44..cfe8418b8 100644 --- a/lib/src/phy/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -291,6 +291,13 @@ int rf_uhd_open(char *args, void **h) return rf_uhd_open_multi(args, h, 1); } +#define REMOVE_SUBSTRING_WITHCOMAS(S, TOREMOVE) \ + remove_substring(args, TOREMOVE ",");\ + remove_substring(args, TOREMOVE ", ");\ + remove_substring(args, "," TOREMOVE);\ + remove_substring(args, ", " TOREMOVE);\ + remove_substring(args, TOREMOVE); + static void remove_substring(char *s,const char *toremove) { while((s=strstr(s,toremove))) { @@ -336,11 +343,11 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) // Check external clock argument enum {DEFAULT, EXTERNAL, GPSDO} clock_src; if (strstr(args, "clock=external")) { - remove_substring(args, "clock=external"); + REMOVE_SUBSTRING_WITHCOMAS(args, "clock=external"); clock_src = EXTERNAL; } else if (strstr(args, "clock=gpsdo")) { printf("Using GPSDO clock\n"); - remove_substring(args, "clock=gpsdo"); + REMOVE_SUBSTRING_WITHCOMAS(args, "clock=gpsdo"); clock_src = GPSDO; } else { clock_src = DEFAULT; @@ -349,8 +356,10 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) // Set over the wire format char *otw_format = "sc16"; if (strstr(args, "otw_format=sc12")) { + REMOVE_SUBSTRING_WITHCOMAS(args, "otw_format=sc12"); otw_format = "sc12"; } else if (strstr(args, "otw_format=sc16")) { + REMOVE_SUBSTRING_WITHCOMAS(args, "otw_format=sc16"); /* Do nothing */ } else if (strstr(args, "otw_format=")) { fprintf(stderr, "Wrong over the wire format. Valid formats: sc12, sc16\n"); From 861d65b070454c532a95310f636937d335710035 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 13 Nov 2017 16:01:01 +0100 Subject: [PATCH 14/15] Added subdev RF arguments. It fixes #95 --- lib/src/phy/rf/rf_uhd_imp.c | 65 +++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/lib/src/phy/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c index cfe8418b8..729d96e11 100644 --- a/lib/src/phy/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -292,11 +292,11 @@ int rf_uhd_open(char *args, void **h) } #define REMOVE_SUBSTRING_WITHCOMAS(S, TOREMOVE) \ - remove_substring(args, TOREMOVE ",");\ - remove_substring(args, TOREMOVE ", ");\ - remove_substring(args, "," TOREMOVE);\ - remove_substring(args, ", " TOREMOVE);\ - remove_substring(args, TOREMOVE); + remove_substring(S, TOREMOVE ",");\ + remove_substring(S, TOREMOVE ", ");\ + remove_substring(S, "," TOREMOVE);\ + remove_substring(S, ", " TOREMOVE);\ + remove_substring(S, TOREMOVE) static void remove_substring(char *s,const char *toremove) { @@ -305,6 +305,17 @@ static void remove_substring(char *s,const char *toremove) } } +static void copy_subdev_string(char *dst, char *src) { + int n = 0; + size_t len = strlen(src); + /* Copy until end of string or comma */ + while (n < len && src != '\0' && src[n] != ',') { + dst[n] = src[n]; + n++; + } + dst[n] = '\0'; +} + int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) { if (h) { @@ -366,6 +377,26 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) return -1; } + // Set transmitter subdevice spec string + const char tx_subdev_arg[] = "tx_subdev_spec="; + char tx_subdev_str[64] = {0}; + char *tx_subdev_ptr = strstr(args, tx_subdev_arg); + if (tx_subdev_ptr) { + copy_subdev_string(tx_subdev_str, tx_subdev_ptr + strlen(tx_subdev_arg)); + remove_substring(args, tx_subdev_arg); + remove_substring(args, tx_subdev_str); + } + + // Set receiver subdevice spec string + const char rx_subdev_arg[] = "rx_subdev_spec="; + char rx_subdev_str[64] = {0}; + char *rx_subdev_ptr = strstr(args, rx_subdev_arg); + if (rx_subdev_ptr) { + copy_subdev_string(rx_subdev_str, rx_subdev_ptr + strlen(rx_subdev_arg)); + remove_substring(args, rx_subdev_arg); + remove_substring(args, rx_subdev_str); + } + /* If device type or name not given in args, choose a B200 */ if (args[0]=='\0') { if (find_string(devices_str, "type=b200") && !strstr(args, "recv_frame_size")) { @@ -405,7 +436,29 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) fprintf(stderr, "Error opening UHD: code %d\n", error); return -1; } - + + /* Set transmitter subdev spec if specified */ + if (strlen(tx_subdev_str)) { + uhd_subdev_spec_handle subdev_spec_handle = {0}; + + printf("Setting tx_subdev_spec to '%s'\n", tx_subdev_str); + + uhd_subdev_spec_make(&subdev_spec_handle, tx_subdev_str); + uhd_usrp_set_tx_subdev_spec(handler->usrp, subdev_spec_handle, 0); + uhd_subdev_spec_free(&subdev_spec_handle); + } + + /* Set receiver subdev spec if specified */ + if (strlen(rx_subdev_str)) { + uhd_subdev_spec_handle subdev_spec_handle = {0}; + + printf("Setting rx_subdev_spec to '%s'\n", rx_subdev_str); + + uhd_subdev_spec_make(&subdev_spec_handle, rx_subdev_str); + uhd_usrp_set_rx_subdev_spec(handler->usrp, subdev_spec_handle, 0); + uhd_subdev_spec_free(&subdev_spec_handle); + } + if (!handler->devname) { char dev_str[1024]; uhd_usrp_get_mboard_name(handler->usrp, 0, dev_str, 1024); From b084b153cf151e96c9144fdfa90a3f0edae32a7f Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 14 Nov 2017 17:11:48 +0100 Subject: [PATCH 15/15] 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