From 3e5b064a0868d7c2a01f123603fac9f5495609a0 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Wed, 24 Nov 2021 10:12:35 +0000 Subject: [PATCH] lib,rlc_am_nr: starting to add build_sdu_segment() function. Also adding write_header function that receives as argument uint8_t* so we can write the header straight to the payload. --- lib/include/srsran/rlc/rlc_am_nr.h | 22 ++++++--- lib/include/srsran/rlc/rlc_am_nr_packing.h | 1 + lib/src/rlc/rlc_am_nr.cc | 57 +++++++++++++++++++--- lib/src/rlc/rlc_am_nr_packing.cc | 17 ++++--- 4 files changed, 77 insertions(+), 20 deletions(-) diff --git a/lib/include/srsran/rlc/rlc_am_nr.h b/lib/include/srsran/rlc/rlc_am_nr.h index c69a921f6..62e56d061 100644 --- a/lib/include/srsran/rlc/rlc_am_nr.h +++ b/lib/include/srsran/rlc/rlc_am_nr.h @@ -85,19 +85,29 @@ public: bool sdu_queue_is_full() final; void reestablish() final; - int write_sdu(unique_byte_buffer_t sdu); - void empty_queue() final; + int write_sdu(unique_byte_buffer_t sdu); + void empty_queue() final; + + // Data PDU helpers + using rlc_amd_tx_pdu_nr = rlc_amd_tx_pdu; + int build_new_sdu_segment(const unique_byte_buffer_t& tx_sdu, + rlc_amd_tx_pdu_nr& tx_pdu, + uint8_t* payload, + uint32_t nof_bytes); + int build_retx_pdu(unique_byte_buffer_t& tx_pdu, uint32_t nof_bytes); + + // Buffer State bool has_data() final; uint32_t get_buffer_state() final; void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue) final; + // Status PDU bool do_status(); uint32_t build_status_pdu(byte_buffer_t* payload, uint32_t nof_bytes); + // Polling uint8_t get_pdu_poll(); - int build_retx_pdu(unique_byte_buffer_t& tx_pdu, uint32_t nof_bytes); - void stop() final; bool inside_tx_window(uint32_t sn); @@ -119,9 +129,7 @@ private: * Tx state variables * Ref: 3GPP TS 38.322 v16.2.0 Section 7.1 ***************************************************************************/ - struct rlc_am_nr_tx_state_t st = {}; - - using rlc_amd_tx_pdu_nr = rlc_amd_tx_pdu; + struct rlc_am_nr_tx_state_t st = {}; rlc_ringbuffer_t tx_window; pdu_retx_queue retx_queue; diff --git a/lib/include/srsran/rlc/rlc_am_nr_packing.h b/lib/include/srsran/rlc/rlc_am_nr_packing.h index cb6b9343e..73564665e 100644 --- a/lib/include/srsran/rlc/rlc_am_nr_packing.h +++ b/lib/include/srsran/rlc/rlc_am_nr_packing.h @@ -82,6 +82,7 @@ uint32_t rlc_am_nr_read_data_pdu_header(const uint8_t* payload, const rlc_am_nr_sn_size_t sn_size, rlc_am_nr_pdu_header_t* header); +uint32_t rlc_am_nr_write_data_pdu_header(const rlc_am_nr_pdu_header_t& header, uint8_t* payload); uint32_t rlc_am_nr_write_data_pdu_header(const rlc_am_nr_pdu_header_t& header, byte_buffer_t* pdu); uint32_t rlc_am_nr_packed_length(const rlc_am_nr_pdu_header_t& header); diff --git a/lib/src/rlc/rlc_am_nr.cc b/lib/src/rlc/rlc_am_nr.cc index ef71562ba..c282a07de 100644 --- a/lib/src/rlc/rlc_am_nr.cc +++ b/lib/src/rlc/rlc_am_nr.cc @@ -105,12 +105,13 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) } } - // Read new SDU from TX queue + // Check wether there is something to TX if (tx_sdu_queue.is_empty()) { logger->info("No data available to be sent"); return 0; } + // Read new SDU from TX queue unique_byte_buffer_t tx_sdu; logger->debug("Reading from RLC SDU queue. Queue size %d", tx_sdu_queue.size()); do { @@ -119,11 +120,8 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) if (tx_sdu != nullptr) { logger->debug("Read RLC SDU - %d bytes", tx_sdu->N_bytes); - } - - uint16_t hdr_size = 2; - if (tx_sdu->N_bytes + hdr_size > nof_bytes) { - logger->warning("Segmentation not supported yet"); + } else { + logger->info("No SDUs left in the tx queue."); return 0; } @@ -136,6 +134,16 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) return 0; } + // Segment new SDU if necessary + uint16_t hdr_size = 2; + if (tx_sdu->N_bytes + hdr_size > nof_bytes) { + logger->info("Trying to build PDU segment from SDU."); + if (build_new_sdu_segment(tx_sdu, tx_pdu, payload, nof_bytes) != SRSRAN_SUCCESS) { + return 0; + } + return tx_pdu.buf->N_bytes; + } + memcpy(tx_pdu.buf->msg, tx_sdu->msg, tx_sdu->N_bytes); tx_pdu.buf->N_bytes = tx_sdu->N_bytes; @@ -164,6 +172,43 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) return tx_sdu->N_bytes; } +int rlc_am_nr_tx::build_new_sdu_segment(const unique_byte_buffer_t& tx_sdu, + rlc_amd_tx_pdu_nr& tx_pdu, + uint8_t* payload, + uint32_t nof_bytes) +{ + // Sanity check: can this SDU be sent this in a single PDU? + if (tx_sdu->N_bytes + 2 >= nof_bytes) { + logger->error("Calling build_new_sdu_segment(), but there are enough bytes to tx in a single PDU."); + return SRSRAN_ERROR; + } + + // Sanity check: can this SDU be sent considering header overhead? + if (1 + 2 >= nof_bytes) { // Only two bytes, as SO is 0 + logger->error("Cannot build new sdu_segment, but there are not enough bytes to tx header plus data."); + return SRSRAN_ERROR; + } + + // Prepare header + rlc_am_nr_pdu_header_t hdr = {}; + hdr.dc = RLC_DC_FIELD_DATA_PDU; + hdr.p = get_pdu_poll(); + hdr.si = rlc_nr_si_field_t::first_segment; + hdr.sn_size = rlc_am_nr_sn_size_t::size12bits; + hdr.sn = st.tx_next; + hdr.so = 0; + tx_pdu.header = hdr; + log_rlc_am_nr_pdu_header_to_string(logger->info, hdr); + + // Write header + uint32_t len = rlc_am_nr_write_data_pdu_header(hdr, payload); + if (len > nof_bytes) { + logger->error("Error writing AMD PDU header"); + } + + return SRSRAN_SUCCESS; +} + int rlc_am_nr_tx::build_retx_pdu(unique_byte_buffer_t& tx_pdu, uint32_t nof_bytes) { // Check there is at least 1 element before calling front() diff --git a/lib/src/rlc/rlc_am_nr_packing.cc b/lib/src/rlc/rlc_am_nr_packing.cc index 1f82b6722..8a6e8fb37 100644 --- a/lib/src/rlc/rlc_am_nr_packing.cc +++ b/lib/src/rlc/rlc_am_nr_packing.cc @@ -96,12 +96,9 @@ uint32_t rlc_am_nr_packed_length(const rlc_am_nr_pdu_header_t& header) return len; } -uint32_t rlc_am_nr_write_data_pdu_header(const rlc_am_nr_pdu_header_t& header, byte_buffer_t* pdu) +uint32_t rlc_am_nr_write_data_pdu_header(const rlc_am_nr_pdu_header_t& header, uint8_t* payload) { - // Make room for the header - uint32_t len = rlc_am_nr_packed_length(header); - pdu->msg -= len; - uint8_t* ptr = pdu->msg; + uint8_t* ptr = payload; // fixed header part *ptr = (header.dc & 0x01) << 7; ///< 1 bit D/C field @@ -131,9 +128,15 @@ uint32_t rlc_am_nr_write_data_pdu_header(const rlc_am_nr_pdu_header_t& header, b *ptr = (header.so & 0xff); // second part of SO ptr++; } + return rlc_am_nr_packed_length(header); +} - pdu->N_bytes += ptr - pdu->msg; - +uint32_t rlc_am_nr_write_data_pdu_header(const rlc_am_nr_pdu_header_t& header, byte_buffer_t* pdu) +{ + // Make room for the header + uint32_t len = rlc_am_nr_packed_length(header); + pdu->msg -= len; + rlc_am_nr_write_data_pdu_header(header, pdu->msg); return len; }