Moved RLC AM LTE and NR packing functions to their own file.

master
Pedro Alvarez 3 years ago
parent f93d428e49
commit 2bb249bf09

@ -23,6 +23,7 @@
#include "srsran/interfaces/pdcp_interface_types.h" #include "srsran/interfaces/pdcp_interface_types.h"
#include "srsran/rlc/rlc_am_base.h" #include "srsran/rlc/rlc_am_base.h"
#include "srsran/rlc/rlc_am_data_structs.h" #include "srsran/rlc/rlc_am_data_structs.h"
#include "srsran/rlc/rlc_am_lte_packing.h"
#include "srsran/rlc/rlc_common.h" #include "srsran/rlc/rlc_common.h"
#include "srsran/support/srsran_assert.h" #include "srsran/support/srsran_assert.h"
#include "srsran/upper/byte_buffer_queue.h" #include "srsran/upper/byte_buffer_queue.h"
@ -34,63 +35,6 @@ namespace srsran {
#undef RLC_AM_BUFFER_DEBUG #undef RLC_AM_BUFFER_DEBUG
struct rlc_amd_rx_pdu {
rlc_amd_pdu_header_t header;
unique_byte_buffer_t buf;
uint32_t rlc_sn;
rlc_amd_rx_pdu() = default;
explicit rlc_amd_rx_pdu(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {}
};
struct rlc_amd_rx_pdu_segments_t {
std::list<rlc_amd_rx_pdu> segments;
};
/// Class that contains the parameters and state (e.g. segments) of a RLC PDU
class rlc_amd_tx_pdu
{
using list_type = intrusive_forward_list<rlc_am_pdu_segment>;
const static uint32_t invalid_rlc_sn = std::numeric_limits<uint32_t>::max();
list_type list;
public:
using iterator = typename list_type::iterator;
using const_iterator = typename list_type::const_iterator;
const uint32_t rlc_sn = invalid_rlc_sn;
uint32_t retx_count = 0;
rlc_amd_pdu_header_t header;
unique_byte_buffer_t buf;
explicit rlc_amd_tx_pdu(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {}
rlc_amd_tx_pdu(const rlc_amd_tx_pdu&) = delete;
rlc_amd_tx_pdu(rlc_amd_tx_pdu&& other) noexcept = default;
rlc_amd_tx_pdu& operator=(const rlc_amd_tx_pdu& other) = delete;
rlc_amd_tx_pdu& operator=(rlc_amd_tx_pdu&& other) = delete;
~rlc_amd_tx_pdu();
// Segment List Interface
void add_segment(rlc_am_pdu_segment& segment) { list.push_front(&segment); }
const_iterator begin() const { return list.begin(); }
const_iterator end() const { return list.end(); }
iterator begin() { return list.begin(); }
iterator end() { return list.end(); }
};
struct rlc_amd_retx_t {
uint32_t sn;
bool is_segment;
uint32_t so_start;
uint32_t so_end;
};
struct rlc_sn_info_t {
uint32_t sn;
bool is_acked;
};
class pdu_retx_queue class pdu_retx_queue
{ {
public: public:
@ -383,31 +327,6 @@ private:
rlc_bearer_metrics_t metrics = {}; rlc_bearer_metrics_t metrics = {};
}; };
/****************************************************************************
* Header pack/unpack helper functions
* Ref: 3GPP TS 36.322 v10.0.0 Section 6.2.1
***************************************************************************/
void rlc_am_read_data_pdu_header(byte_buffer_t* pdu, rlc_amd_pdu_header_t* header);
void rlc_am_read_data_pdu_header(uint8_t** payload, uint32_t* nof_bytes, rlc_amd_pdu_header_t* header);
void rlc_am_write_data_pdu_header(rlc_amd_pdu_header_t* header, byte_buffer_t* pdu);
void rlc_am_write_data_pdu_header(rlc_amd_pdu_header_t* header, uint8_t** payload);
void rlc_am_read_status_pdu(byte_buffer_t* pdu, rlc_status_pdu_t* status);
void rlc_am_read_status_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_status_pdu_t* status);
void rlc_am_write_status_pdu(rlc_status_pdu_t* status, byte_buffer_t* pdu);
int rlc_am_write_status_pdu(rlc_status_pdu_t* status, uint8_t* payload);
uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t* header);
uint32_t rlc_am_packed_length(rlc_status_pdu_t* status);
uint32_t rlc_am_packed_length(rlc_amd_retx_t retx);
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_min = 0);
bool rlc_am_is_pdu_segment(uint8_t* payload);
std::string rlc_am_undelivered_sdu_info_to_string(const std::map<uint32_t, pdcp_pdu_info>& info_queue);
void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header);
bool rlc_am_start_aligned(const uint8_t fi);
bool rlc_am_end_aligned(const uint8_t fi);
bool rlc_am_is_unaligned(const uint8_t fi);
bool rlc_am_not_start_aligned(const uint8_t fi);
} // namespace srsran } // namespace srsran
#endif // SRSRAN_RLC_AM_LTE_H #endif // SRSRAN_RLC_AM_LTE_H

@ -0,0 +1,135 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSRAN_RLC_AM_LTE_PACKING_H
#define SRSRAN_RLC_AM_LTE_PACKING_H
#include "srsran/common/string_helpers.h"
#include "srsran/rlc/rlc_am_base.h"
#include "srsran/rlc/rlc_am_data_structs.h" // required for rlc_am_pdu_segment
#include <list>
namespace srsran {
/// Class that contains the parameters and state (e.g. segments) of a RLC PDU
class rlc_amd_tx_pdu
{
using list_type = intrusive_forward_list<rlc_am_pdu_segment>;
const static uint32_t invalid_rlc_sn = std::numeric_limits<uint32_t>::max();
list_type list;
public:
using iterator = typename list_type::iterator;
using const_iterator = typename list_type::const_iterator;
const uint32_t rlc_sn = invalid_rlc_sn;
uint32_t retx_count = 0;
rlc_amd_pdu_header_t header;
unique_byte_buffer_t buf;
explicit rlc_amd_tx_pdu(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {}
rlc_amd_tx_pdu(const rlc_amd_tx_pdu&) = delete;
rlc_amd_tx_pdu(rlc_amd_tx_pdu&& other) noexcept = default;
rlc_amd_tx_pdu& operator=(const rlc_amd_tx_pdu& other) = delete;
rlc_amd_tx_pdu& operator=(rlc_amd_tx_pdu&& other) = delete;
~rlc_amd_tx_pdu();
// Segment List Interface
void add_segment(rlc_am_pdu_segment& segment) { list.push_front(&segment); }
const_iterator begin() const { return list.begin(); }
const_iterator end() const { return list.end(); }
iterator begin() { return list.begin(); }
iterator end() { return list.end(); }
};
struct rlc_amd_retx_t {
uint32_t sn;
bool is_segment;
uint32_t so_start;
uint32_t so_end;
};
struct rlc_sn_info_t {
uint32_t sn;
bool is_acked;
};
struct rlc_amd_rx_pdu {
rlc_amd_pdu_header_t header;
unique_byte_buffer_t buf;
uint32_t rlc_sn;
rlc_amd_rx_pdu() = default;
explicit rlc_amd_rx_pdu(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {}
};
struct rlc_amd_rx_pdu_segments_t {
std::list<rlc_amd_rx_pdu> segments;
};
/****************************************************************************
* Header pack/unpack helper functions
* Ref: 3GPP TS 36.322 v10.0.0 Section 6.2.1
***************************************************************************/
void rlc_am_read_data_pdu_header(byte_buffer_t* pdu, rlc_amd_pdu_header_t* header);
void rlc_am_read_data_pdu_header(uint8_t** payload, uint32_t* nof_bytes, rlc_amd_pdu_header_t* header);
void rlc_am_write_data_pdu_header(rlc_amd_pdu_header_t* header, byte_buffer_t* pdu);
void rlc_am_write_data_pdu_header(rlc_amd_pdu_header_t* header, uint8_t** payload);
void rlc_am_read_status_pdu(byte_buffer_t* pdu, rlc_status_pdu_t* status);
void rlc_am_read_status_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_status_pdu_t* status);
void rlc_am_write_status_pdu(rlc_status_pdu_t* status, byte_buffer_t* pdu);
int rlc_am_write_status_pdu(rlc_status_pdu_t* status, uint8_t* payload);
uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t* header);
uint32_t rlc_am_packed_length(rlc_status_pdu_t* status);
uint32_t rlc_am_packed_length(rlc_amd_retx_t retx);
bool rlc_am_is_pdu_segment(uint8_t* payload);
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_min = 0);
std::string rlc_am_undelivered_sdu_info_to_string(const std::map<uint32_t, pdcp_pdu_info>& info_queue);
void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header);
bool rlc_am_start_aligned(const uint8_t fi);
bool rlc_am_end_aligned(const uint8_t fi);
bool rlc_am_is_unaligned(const uint8_t fi);
bool rlc_am_not_start_aligned(const uint8_t fi);
/**
* Logs Status PDU into provided log channel, using fmt_str as format string
*/
template <typename... Args>
void log_rlc_am_status_pdu_to_string(srslog::log_channel& log_ch,
const char* fmt_str,
rlc_status_pdu_t* status,
Args&&... args)
{
if (not log_ch.enabled()) {
return;
}
fmt::memory_buffer buffer;
fmt::format_to(buffer, "ACK_SN = {}, N_nack = {}", status->ack_sn, status->N_nack);
if (status->N_nack > 0) {
fmt::format_to(buffer, ", NACK_SN = ");
for (uint32_t i = 0; i < status->N_nack; ++i) {
if (status->nacks[i].has_so) {
fmt::format_to(
buffer, "[{} {}:{}]", status->nacks[i].nack_sn, status->nacks[i].so_start, status->nacks[i].so_end);
} else {
fmt::format_to(buffer, "[{}]", status->nacks[i].nack_sn);
}
}
}
log_ch(fmt_str, std::forward<Args>(args)..., to_c_str(buffer));
}
} // namespace srsran
#endif // SRSRAN_RLC_AM_NR_H

@ -15,6 +15,7 @@
#include "srsran/common/buffer_pool.h" #include "srsran/common/buffer_pool.h"
#include "srsran/common/common.h" #include "srsran/common/common.h"
#include "srsran/common/timers.h"
#include "srsran/rlc/rlc_am_base.h" #include "srsran/rlc/rlc_am_base.h"
#include "srsran/upper/byte_buffer_queue.h" #include "srsran/upper/byte_buffer_queue.h"
#include <map> #include <map>
@ -24,41 +25,7 @@
namespace srsran { namespace srsran {
typedef struct { // TODO
rlc_am_nr_pdu_header_t header;
unique_byte_buffer_t buf;
} rlc_amd_pdu_nr_t;
///< add class here
/****************************************************************************
* Header pack/unpack helper functions for NR
* Ref: 3GPP TS 38.322 v15.3.0 Section 6.2.2.3
***************************************************************************/
uint32_t rlc_am_nr_read_data_pdu_header(const byte_buffer_t* pdu,
const rlc_am_nr_sn_size_t sn_size,
rlc_am_nr_pdu_header_t* header);
uint32_t rlc_am_nr_read_data_pdu_header(const uint8_t* payload,
const uint32_t nof_bytes,
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, byte_buffer_t* pdu);
uint32_t rlc_am_nr_packed_length(const rlc_am_nr_pdu_header_t& header);
uint32_t
rlc_am_nr_read_status_pdu(const byte_buffer_t* pdu, const rlc_am_nr_sn_size_t sn_size, rlc_am_nr_status_pdu_t* status);
uint32_t rlc_am_nr_read_status_pdu(const uint8_t* payload,
const uint32_t nof_bytes,
const rlc_am_nr_sn_size_t sn_size,
rlc_am_nr_status_pdu_t* status);
int32_t rlc_am_nr_write_status_pdu(const rlc_am_nr_status_pdu_t& status_pdu,
const rlc_am_nr_sn_size_t sn_size,
byte_buffer_t* pdu);
} // namespace srsran } // namespace srsran

@ -0,0 +1,75 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSRAN_RLC_AM_NR_PACKING_H
#define SRSRAN_RLC_AM_NR_PACKING_H
#include "srsran/rlc/rlc_am_base.h"
namespace srsran {
///< AM NR PDU header
typedef struct {
rlc_dc_field_t dc; ///< Data/Control (D/C) field
uint8_t p; ///< Polling bit
rlc_nr_si_field_t si; ///< Segmentation info
rlc_am_nr_sn_size_t sn_size; ///< Sequence number size (12 or 18 bits)
uint32_t sn; ///< Sequence number
uint16_t so; ///< Sequence offset
} rlc_am_nr_pdu_header_t;
struct rlc_amd_pdu_nr_t {
rlc_am_nr_pdu_header_t header;
unique_byte_buffer_t buf;
};
///< AM NR Status PDU header (perhaps merge with LTE version)
typedef struct {
rlc_am_nr_control_pdu_type_t cpt;
uint32_t ack_sn; ///< SN of the next not received RLC Data PDU
uint16_t N_nack; ///< number of NACKs
uint8_t nack_range; ///< number of consecutively lost RLC SDUs starting from and including NACK_SN
rlc_status_nack_t nacks[RLC_AM_WINDOW_SIZE];
} rlc_am_nr_status_pdu_t;
/****************************************************************************
* Header pack/unpack helper functions for NR
* Ref: 3GPP TS 38.322 v15.3.0 Section 6.2.2.3
***************************************************************************/
uint32_t rlc_am_nr_read_data_pdu_header(const byte_buffer_t* pdu,
const rlc_am_nr_sn_size_t sn_size,
rlc_am_nr_pdu_header_t* header);
uint32_t rlc_am_nr_read_data_pdu_header(const uint8_t* payload,
const uint32_t nof_bytes,
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, byte_buffer_t* pdu);
uint32_t rlc_am_nr_packed_length(const rlc_am_nr_pdu_header_t& header);
uint32_t
rlc_am_nr_read_status_pdu(const byte_buffer_t* pdu, const rlc_am_nr_sn_size_t sn_size, rlc_am_nr_status_pdu_t* status);
uint32_t rlc_am_nr_read_status_pdu(const uint8_t* payload,
const uint32_t nof_bytes,
const rlc_am_nr_sn_size_t sn_size,
rlc_am_nr_status_pdu_t* status);
int32_t rlc_am_nr_write_status_pdu(const rlc_am_nr_status_pdu_t& status_pdu,
const rlc_am_nr_sn_size_t sn_size,
byte_buffer_t* pdu);
} // namespace srsran
#endif // SRSRAN_RLC_AM_NR_H

@ -176,27 +176,6 @@ struct rlc_status_pdu_t {
} }
}; };
/** RLC AM NR structs */
///< AM NR PDU header
typedef struct {
rlc_dc_field_t dc; ///< Data/Control (D/C) field
uint8_t p; ///< Polling bit
rlc_nr_si_field_t si; ///< Segmentation info
rlc_am_nr_sn_size_t sn_size; ///< Sequence number size (12 or 18 bits)
uint32_t sn; ///< Sequence number
uint16_t so; ///< Sequence offset
} rlc_am_nr_pdu_header_t;
///< AM NR Status PDU header (perhaps merge with LTE version)
typedef struct {
rlc_am_nr_control_pdu_type_t cpt;
uint32_t ack_sn; ///< SN of the next not received RLC Data PDU
uint16_t N_nack; ///< number of NACKs
uint8_t nack_range; ///< number of consecutively lost RLC SDUs starting from and including NACK_SN
rlc_status_nack_t nacks[RLC_AM_WINDOW_SIZE];
} rlc_am_nr_status_pdu_t;
typedef std::function<void(uint32_t, uint32_t, uint32_t)> bsr_callback_t; typedef std::function<void(uint32_t, uint32_t, uint32_t)> bsr_callback_t;
/**************************************************************************** /****************************************************************************

@ -10,10 +10,12 @@ set(SOURCES rlc.cc
rlc_tm.cc rlc_tm.cc
rlc_um_base.cc rlc_um_base.cc
rlc_um_lte.cc rlc_um_lte.cc
rlc_um_nr.cc
rlc_am_base.cc rlc_am_base.cc
rlc_am_lte.cc rlc_am_lte.cc
rlc_um_nr.cc
rlc_am_nr.cc rlc_am_nr.cc
rlc_am_lte_packing.cc
rlc_am_nr_packing.cc
bearer_mem_pool.cc) bearer_mem_pool.cc)
add_library(srsran_rlc STATIC ${SOURCES}) add_library(srsran_rlc STATIC ${SOURCES})

@ -11,9 +11,9 @@
*/ */
#include "srsran/rlc/rlc_am_lte.h" #include "srsran/rlc/rlc_am_lte.h"
#include "srsran/common/string_helpers.h"
#include "srsran/interfaces/ue_pdcp_interfaces.h" #include "srsran/interfaces/ue_pdcp_interfaces.h"
#include "srsran/interfaces/ue_rrc_interfaces.h" #include "srsran/interfaces/ue_rrc_interfaces.h"
#include "srsran/rlc/rlc_am_lte_packing.h"
#include "srsran/srslog/event_trace.h" #include "srsran/srslog/event_trace.h"
#include <iostream> #include <iostream>
@ -25,38 +25,6 @@
namespace srsran { namespace srsran {
/*******************************
* Helper methods
******************************/
/**
* Logs Status PDU into provided log channel, using fmt_str as format string
*/
template <typename... Args>
void log_rlc_am_status_pdu_to_string(srslog::log_channel& log_ch,
const char* fmt_str,
rlc_status_pdu_t* status,
Args&&... args)
{
if (not log_ch.enabled()) {
return;
}
fmt::memory_buffer buffer;
fmt::format_to(buffer, "ACK_SN = {}, N_nack = {}", status->ack_sn, status->N_nack);
if (status->N_nack > 0) {
fmt::format_to(buffer, ", NACK_SN = ");
for (uint32_t i = 0; i < status->N_nack; ++i) {
if (status->nacks[i].has_so) {
fmt::format_to(
buffer, "[{} {}:{}]", status->nacks[i].nack_sn, status->nacks[i].so_start, status->nacks[i].so_end);
} else {
fmt::format_to(buffer, "[{}]", status->nacks[i].nack_sn);
}
}
}
log_ch(fmt_str, std::forward<Args>(args)..., to_c_str(buffer));
}
/******************************* /*******************************
* RLC AM Segments * RLC AM Segments
******************************/ ******************************/
@ -2259,325 +2227,4 @@ void rlc_am_lte::rlc_am_lte_rx::debug_state()
logger.debug("%s vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d", RB_NAME, vr_r, vr_mr, vr_x, vr_ms, vr_h); logger.debug("%s vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d", RB_NAME, vr_r, vr_mr, vr_x, vr_ms, vr_h);
} }
/****************************************************************************
* Header pack/unpack helper functions
* Ref: 3GPP TS 36.322 v10.0.0 Section 6.2.1
***************************************************************************/
// Read header from pdu struct, don't strip header
void rlc_am_read_data_pdu_header(byte_buffer_t* pdu, rlc_amd_pdu_header_t* header)
{
uint8_t* ptr = pdu->msg;
uint32_t n = 0;
rlc_am_read_data_pdu_header(&ptr, &n, header);
}
// Read header from raw pointer, strip header
void rlc_am_read_data_pdu_header(uint8_t** payload, uint32_t* nof_bytes, rlc_amd_pdu_header_t* header)
{
uint8_t ext;
uint8_t* ptr = *payload;
header->dc = static_cast<rlc_dc_field_t>((*ptr >> 7) & 0x01);
if (RLC_DC_FIELD_DATA_PDU == header->dc) {
// Fixed part
header->rf = ((*ptr >> 6) & 0x01);
header->p = ((*ptr >> 5) & 0x01);
header->fi = static_cast<rlc_fi_field_t>((*ptr >> 3) & 0x03);
ext = ((*ptr >> 2) & 0x01);
header->sn = (*ptr & 0x03) << 8; // 2 bits SN
ptr++;
header->sn |= (*ptr & 0xFF); // 8 bits SN
ptr++;
if (header->rf) {
header->lsf = ((*ptr >> 7) & 0x01);
header->so = (*ptr & 0x7F) << 8; // 7 bits of SO
ptr++;
header->so |= (*ptr & 0xFF); // 8 bits of SO
ptr++;
}
// Extension part
header->N_li = 0;
while (ext) {
if (header->N_li % 2 == 0) {
ext = ((*ptr >> 7) & 0x01);
header->li[header->N_li] = (*ptr & 0x7F) << 4; // 7 bits of LI
ptr++;
header->li[header->N_li] |= (*ptr & 0xF0) >> 4; // 4 bits of LI
header->N_li++;
} else {
ext = (*ptr >> 3) & 0x01;
header->li[header->N_li] = (*ptr & 0x07) << 8; // 3 bits of LI
ptr++;
header->li[header->N_li] |= (*ptr & 0xFF); // 8 bits of LI
header->N_li++;
ptr++;
}
}
// Account for padding if N_li is odd
if (header->N_li % 2 == 1) {
ptr++;
}
*nof_bytes -= ptr - *payload;
*payload = ptr;
}
}
// Write header to pdu struct
void rlc_am_write_data_pdu_header(rlc_amd_pdu_header_t* header, byte_buffer_t* pdu)
{
uint8_t* ptr = pdu->msg;
rlc_am_write_data_pdu_header(header, &ptr);
pdu->N_bytes += ptr - pdu->msg;
}
// Write header to pointer & move pointer
void rlc_am_write_data_pdu_header(rlc_amd_pdu_header_t* header, uint8_t** payload)
{
uint32_t i;
uint8_t ext = (header->N_li > 0) ? 1 : 0;
uint8_t* ptr = *payload;
// Fixed part
*ptr = (header->dc & 0x01) << 7;
*ptr |= (header->rf & 0x01) << 6;
*ptr |= (header->p & 0x01) << 5;
*ptr |= (header->fi & 0x03) << 3;
*ptr |= (ext & 0x01) << 2;
*ptr |= (header->sn & 0x300) >> 8; // 2 bits SN
ptr++;
*ptr = (header->sn & 0xFF); // 8 bits SN
ptr++;
// Segment part
if (header->rf) {
*ptr = (header->lsf & 0x01) << 7;
*ptr |= (header->so & 0x7F00) >> 8; // 7 bits of SO
ptr++;
*ptr = (header->so & 0x00FF); // 8 bits of SO
ptr++;
}
// Extension part
i = 0;
while (i < header->N_li) {
ext = ((i + 1) == header->N_li) ? 0 : 1;
*ptr = (ext & 0x01) << 7; // 1 bit header
*ptr |= (header->li[i] & 0x7F0) >> 4; // 7 bits of LI
ptr++;
*ptr = (header->li[i] & 0x00F) << 4; // 4 bits of LI
i++;
if (i < header->N_li) {
ext = ((i + 1) == header->N_li) ? 0 : 1;
*ptr |= (ext & 0x01) << 3; // 1 bit header
*ptr |= (header->li[i] & 0x700) >> 8; // 3 bits of LI
ptr++;
*ptr = (header->li[i] & 0x0FF); // 8 bits of LI
ptr++;
i++;
}
}
// Pad if N_li is odd
if (header->N_li % 2 == 1) {
ptr++;
}
*payload = ptr;
}
void rlc_am_read_status_pdu(byte_buffer_t* pdu, rlc_status_pdu_t* status)
{
rlc_am_read_status_pdu(pdu->msg, pdu->N_bytes, status);
}
void rlc_am_read_status_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_status_pdu_t* status)
{
uint32_t i;
uint8_t ext1, ext2;
bit_buffer_t tmp;
uint8_t* ptr = tmp.msg;
srsran_bit_unpack_vector(payload, tmp.msg, nof_bytes * 8);
tmp.N_bits = nof_bytes * 8;
rlc_dc_field_t dc = static_cast<rlc_dc_field_t>(srsran_bit_pack(&ptr, 1));
if (RLC_DC_FIELD_CONTROL_PDU == dc) {
uint8_t cpt = srsran_bit_pack(&ptr, 3); // 3-bit Control PDU Type (0 == status)
if (0 == cpt) {
status->ack_sn = srsran_bit_pack(&ptr, 10); // 10 bits ACK_SN
ext1 = srsran_bit_pack(&ptr, 1); // 1 bits E1
status->N_nack = 0;
while (ext1) {
status->nacks[status->N_nack].nack_sn = srsran_bit_pack(&ptr, 10);
ext1 = srsran_bit_pack(&ptr, 1); // 1 bits E1
ext2 = srsran_bit_pack(&ptr, 1); // 1 bits E2
if (ext2) {
status->nacks[status->N_nack].has_so = true;
status->nacks[status->N_nack].so_start = srsran_bit_pack(&ptr, 15);
status->nacks[status->N_nack].so_end = srsran_bit_pack(&ptr, 15);
}
status->N_nack++;
}
}
}
}
void rlc_am_write_status_pdu(rlc_status_pdu_t* status, byte_buffer_t* pdu)
{
pdu->N_bytes = rlc_am_write_status_pdu(status, pdu->msg);
}
int rlc_am_write_status_pdu(rlc_status_pdu_t* status, uint8_t* payload)
{
uint32_t i;
uint8_t ext1;
bit_buffer_t tmp;
uint8_t* ptr = tmp.msg;
srsran_bit_unpack(RLC_DC_FIELD_CONTROL_PDU, &ptr, 1); // D/C
srsran_bit_unpack(0, &ptr, 3); // CPT (0 == STATUS)
srsran_bit_unpack(status->ack_sn, &ptr, 10); // 10 bit ACK_SN
ext1 = (status->N_nack == 0) ? 0 : 1;
srsran_bit_unpack(ext1, &ptr, 1); // E1
for (i = 0; i < status->N_nack; i++) {
srsran_bit_unpack(status->nacks[i].nack_sn, &ptr, 10); // 10 bit NACK_SN
ext1 = ((status->N_nack - 1) == i) ? 0 : 1;
srsran_bit_unpack(ext1, &ptr, 1); // E1
if (status->nacks[i].has_so) {
srsran_bit_unpack(1, &ptr, 1); // E2
srsran_bit_unpack(status->nacks[i].so_start, &ptr, 15);
srsran_bit_unpack(status->nacks[i].so_end, &ptr, 15);
} else {
srsran_bit_unpack(0, &ptr, 1); // E2
}
}
// Pad
tmp.N_bits = ptr - tmp.msg;
uint8_t n_pad = 8 - (tmp.N_bits % 8);
srsran_bit_unpack(0, &ptr, n_pad);
tmp.N_bits = ptr - tmp.msg;
// Pack bits
srsran_bit_pack_vector(tmp.msg, payload, tmp.N_bits);
return tmp.N_bits / 8;
}
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_min)
{
// check if ACK_SN is inside Rx window
if ((MOD + status.ack_sn - rx_win_min) % MOD > RLC_AM_WINDOW_SIZE) {
return false;
}
for (uint32_t i = 0; i < status.N_nack; ++i) {
// NACK can't be larger than ACK
if ((MOD + status.ack_sn - status.nacks[i].nack_sn) % MOD > RLC_AM_WINDOW_SIZE) {
return false;
}
// Don't NACK the ACK SN
if (status.nacks[i].nack_sn == status.ack_sn) {
return false;
}
}
return true;
}
uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t* header)
{
uint32_t len = 2; // Fixed part is 2 bytes
if (header->rf) {
len += 2; // Segment header is 2 bytes
}
len += header->N_li * 1.5 + 0.5; // Extension part - integer rounding up
return len;
}
uint32_t rlc_am_packed_length(rlc_status_pdu_t* status)
{
uint32_t len_bits = 15; // Fixed part is 15 bits
for (uint32_t i = 0; i < status->N_nack; i++) {
if (status->nacks[i].has_so) {
len_bits += 42; // 10 bits SN, 2 bits ext, 15 bits so_start, 15 bits so_end
} else {
len_bits += 12; // 10 bits SN, 2 bits ext
}
}
return (len_bits + 7) / 8; // Convert to bytes - integer rounding up
}
bool rlc_am_is_pdu_segment(uint8_t* payload)
{
return ((*(payload) >> 6) & 0x01) == 1;
}
void rlc_am_undelivered_sdu_info_to_string(fmt::memory_buffer& buffer, const std::vector<pdcp_pdu_info>& info_queue)
{
fmt::format_to(buffer, "\n");
for (const auto& pdcp_pdu : info_queue) {
fmt::format_to(buffer, "\tPDCP_SN = {}, undelivered RLC SNs = [", pdcp_pdu.sn);
for (const auto& nacked_segment : pdcp_pdu) {
fmt::format_to(buffer, "{} ", nacked_segment.rlc_sn());
}
fmt::format_to(buffer, "]\n");
}
}
void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header)
{
if (not log_ch.enabled()) {
return;
}
fmt::memory_buffer buffer;
fmt::format_to(buffer,
"[{}, RF={}, P={}, FI={}, SN={}, LSF={}, SO={}, N_li={}",
rlc_dc_field_text[header.dc],
(header.rf ? "1" : "0"),
(header.p ? "1" : "0"),
(header.fi ? "1" : "0"),
header.sn,
(header.lsf ? "1" : "0"),
header.so,
header.N_li);
if (header.N_li > 0) {
fmt::format_to(buffer, " ({}", header.li[0]);
for (uint32_t i = 1; i < header.N_li; ++i) {
fmt::format_to(buffer, ", {}", header.li[i]);
}
fmt::format_to(buffer, ")");
}
fmt::format_to(buffer, "]");
log_ch("%s", to_c_str(buffer));
}
bool rlc_am_start_aligned(const uint8_t fi)
{
return (fi == RLC_FI_FIELD_START_AND_END_ALIGNED || fi == RLC_FI_FIELD_NOT_END_ALIGNED);
}
bool rlc_am_end_aligned(const uint8_t fi)
{
return (fi == RLC_FI_FIELD_START_AND_END_ALIGNED || fi == RLC_FI_FIELD_NOT_START_ALIGNED);
}
bool rlc_am_is_unaligned(const uint8_t fi)
{
return (fi == RLC_FI_FIELD_NOT_START_OR_END_ALIGNED);
}
bool rlc_am_not_start_aligned(const uint8_t fi)
{
return (fi == RLC_FI_FIELD_NOT_START_ALIGNED || fi == RLC_FI_FIELD_NOT_START_OR_END_ALIGNED);
}
} // namespace srsran } // namespace srsran

@ -0,0 +1,339 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srsran/rlc/rlc_am_lte_packing.h"
#include <sstream>
namespace srsran {
/****************************************************************************
* Header pack/unpack helper functions
* Ref: 3GPP TS 36.322 v10.0.0 Section 6.2.1
***************************************************************************/
// Read header from pdu struct, don't strip header
void rlc_am_read_data_pdu_header(byte_buffer_t* pdu, rlc_amd_pdu_header_t* header)
{
uint8_t* ptr = pdu->msg;
uint32_t n = 0;
rlc_am_read_data_pdu_header(&ptr, &n, header);
}
// Read header from raw pointer, strip header
void rlc_am_read_data_pdu_header(uint8_t** payload, uint32_t* nof_bytes, rlc_amd_pdu_header_t* header)
{
uint8_t ext;
uint8_t* ptr = *payload;
header->dc = static_cast<rlc_dc_field_t>((*ptr >> 7) & 0x01);
if (RLC_DC_FIELD_DATA_PDU == header->dc) {
// Fixed part
header->rf = ((*ptr >> 6) & 0x01);
header->p = ((*ptr >> 5) & 0x01);
header->fi = static_cast<rlc_fi_field_t>((*ptr >> 3) & 0x03);
ext = ((*ptr >> 2) & 0x01);
header->sn = (*ptr & 0x03) << 8; // 2 bits SN
ptr++;
header->sn |= (*ptr & 0xFF); // 8 bits SN
ptr++;
if (header->rf) {
header->lsf = ((*ptr >> 7) & 0x01);
header->so = (*ptr & 0x7F) << 8; // 7 bits of SO
ptr++;
header->so |= (*ptr & 0xFF); // 8 bits of SO
ptr++;
}
// Extension part
header->N_li = 0;
while (ext) {
if (header->N_li % 2 == 0) {
ext = ((*ptr >> 7) & 0x01);
header->li[header->N_li] = (*ptr & 0x7F) << 4; // 7 bits of LI
ptr++;
header->li[header->N_li] |= (*ptr & 0xF0) >> 4; // 4 bits of LI
header->N_li++;
} else {
ext = (*ptr >> 3) & 0x01;
header->li[header->N_li] = (*ptr & 0x07) << 8; // 3 bits of LI
ptr++;
header->li[header->N_li] |= (*ptr & 0xFF); // 8 bits of LI
header->N_li++;
ptr++;
}
}
// Account for padding if N_li is odd
if (header->N_li % 2 == 1) {
ptr++;
}
*nof_bytes -= ptr - *payload;
*payload = ptr;
}
}
// Write header to pdu struct
void rlc_am_write_data_pdu_header(rlc_amd_pdu_header_t* header, byte_buffer_t* pdu)
{
uint8_t* ptr = pdu->msg;
rlc_am_write_data_pdu_header(header, &ptr);
pdu->N_bytes += ptr - pdu->msg;
}
// Write header to pointer & move pointer
void rlc_am_write_data_pdu_header(rlc_amd_pdu_header_t* header, uint8_t** payload)
{
uint32_t i;
uint8_t ext = (header->N_li > 0) ? 1 : 0;
uint8_t* ptr = *payload;
// Fixed part
*ptr = (header->dc & 0x01) << 7;
*ptr |= (header->rf & 0x01) << 6;
*ptr |= (header->p & 0x01) << 5;
*ptr |= (header->fi & 0x03) << 3;
*ptr |= (ext & 0x01) << 2;
*ptr |= (header->sn & 0x300) >> 8; // 2 bits SN
ptr++;
*ptr = (header->sn & 0xFF); // 8 bits SN
ptr++;
// Segment part
if (header->rf) {
*ptr = (header->lsf & 0x01) << 7;
*ptr |= (header->so & 0x7F00) >> 8; // 7 bits of SO
ptr++;
*ptr = (header->so & 0x00FF); // 8 bits of SO
ptr++;
}
// Extension part
i = 0;
while (i < header->N_li) {
ext = ((i + 1) == header->N_li) ? 0 : 1;
*ptr = (ext & 0x01) << 7; // 1 bit header
*ptr |= (header->li[i] & 0x7F0) >> 4; // 7 bits of LI
ptr++;
*ptr = (header->li[i] & 0x00F) << 4; // 4 bits of LI
i++;
if (i < header->N_li) {
ext = ((i + 1) == header->N_li) ? 0 : 1;
*ptr |= (ext & 0x01) << 3; // 1 bit header
*ptr |= (header->li[i] & 0x700) >> 8; // 3 bits of LI
ptr++;
*ptr = (header->li[i] & 0x0FF); // 8 bits of LI
ptr++;
i++;
}
}
// Pad if N_li is odd
if (header->N_li % 2 == 1) {
ptr++;
}
*payload = ptr;
}
void rlc_am_read_status_pdu(byte_buffer_t* pdu, rlc_status_pdu_t* status)
{
rlc_am_read_status_pdu(pdu->msg, pdu->N_bytes, status);
}
void rlc_am_read_status_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_status_pdu_t* status)
{
uint32_t i;
uint8_t ext1, ext2;
bit_buffer_t tmp;
uint8_t* ptr = tmp.msg;
srsran_bit_unpack_vector(payload, tmp.msg, nof_bytes * 8);
tmp.N_bits = nof_bytes * 8;
rlc_dc_field_t dc = static_cast<rlc_dc_field_t>(srsran_bit_pack(&ptr, 1));
if (RLC_DC_FIELD_CONTROL_PDU == dc) {
uint8_t cpt = srsran_bit_pack(&ptr, 3); // 3-bit Control PDU Type (0 == status)
if (0 == cpt) {
status->ack_sn = srsran_bit_pack(&ptr, 10); // 10 bits ACK_SN
ext1 = srsran_bit_pack(&ptr, 1); // 1 bits E1
status->N_nack = 0;
while (ext1) {
status->nacks[status->N_nack].nack_sn = srsran_bit_pack(&ptr, 10);
ext1 = srsran_bit_pack(&ptr, 1); // 1 bits E1
ext2 = srsran_bit_pack(&ptr, 1); // 1 bits E2
if (ext2) {
status->nacks[status->N_nack].has_so = true;
status->nacks[status->N_nack].so_start = srsran_bit_pack(&ptr, 15);
status->nacks[status->N_nack].so_end = srsran_bit_pack(&ptr, 15);
}
status->N_nack++;
}
}
}
}
void rlc_am_write_status_pdu(rlc_status_pdu_t* status, byte_buffer_t* pdu)
{
pdu->N_bytes = rlc_am_write_status_pdu(status, pdu->msg);
}
int rlc_am_write_status_pdu(rlc_status_pdu_t* status, uint8_t* payload)
{
uint32_t i;
uint8_t ext1;
bit_buffer_t tmp;
uint8_t* ptr = tmp.msg;
srsran_bit_unpack(RLC_DC_FIELD_CONTROL_PDU, &ptr, 1); // D/C
srsran_bit_unpack(0, &ptr, 3); // CPT (0 == STATUS)
srsran_bit_unpack(status->ack_sn, &ptr, 10); // 10 bit ACK_SN
ext1 = (status->N_nack == 0) ? 0 : 1;
srsran_bit_unpack(ext1, &ptr, 1); // E1
for (i = 0; i < status->N_nack; i++) {
srsran_bit_unpack(status->nacks[i].nack_sn, &ptr, 10); // 10 bit NACK_SN
ext1 = ((status->N_nack - 1) == i) ? 0 : 1;
srsran_bit_unpack(ext1, &ptr, 1); // E1
if (status->nacks[i].has_so) {
srsran_bit_unpack(1, &ptr, 1); // E2
srsran_bit_unpack(status->nacks[i].so_start, &ptr, 15);
srsran_bit_unpack(status->nacks[i].so_end, &ptr, 15);
} else {
srsran_bit_unpack(0, &ptr, 1); // E2
}
}
// Pad
tmp.N_bits = ptr - tmp.msg;
uint8_t n_pad = 8 - (tmp.N_bits % 8);
srsran_bit_unpack(0, &ptr, n_pad);
tmp.N_bits = ptr - tmp.msg;
// Pack bits
srsran_bit_pack_vector(tmp.msg, payload, tmp.N_bits);
return tmp.N_bits / 8;
}
uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t* header)
{
uint32_t len = 2; // Fixed part is 2 bytes
if (header->rf) {
len += 2; // Segment header is 2 bytes
}
len += header->N_li * 1.5 + 0.5; // Extension part - integer rounding up
return len;
}
uint32_t rlc_am_packed_length(rlc_status_pdu_t* status)
{
uint32_t len_bits = 15; // Fixed part is 15 bits
for (uint32_t i = 0; i < status->N_nack; i++) {
if (status->nacks[i].has_so) {
len_bits += 42; // 10 bits SN, 2 bits ext, 15 bits so_start, 15 bits so_end
} else {
len_bits += 12; // 10 bits SN, 2 bits ext
}
}
return (len_bits + 7) / 8; // Convert to bytes - integer rounding up
}
bool rlc_am_is_pdu_segment(uint8_t* payload)
{
return ((*(payload) >> 6) & 0x01) == 1;
}
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_min)
{
// check if ACK_SN is inside Rx window
if ((MOD + status.ack_sn - rx_win_min) % MOD > RLC_AM_WINDOW_SIZE) {
return false;
}
for (uint32_t i = 0; i < status.N_nack; ++i) {
// NACK can't be larger than ACK
if ((MOD + status.ack_sn - status.nacks[i].nack_sn) % MOD > RLC_AM_WINDOW_SIZE) {
return false;
}
// Don't NACK the ACK SN
if (status.nacks[i].nack_sn == status.ack_sn) {
return false;
}
}
return true;
}
void rlc_am_undelivered_sdu_info_to_string(fmt::memory_buffer& buffer, const std::vector<pdcp_pdu_info>& info_queue)
{
fmt::format_to(buffer, "\n");
for (const auto& pdcp_pdu : info_queue) {
fmt::format_to(buffer, "\tPDCP_SN = {}, undelivered RLC SNs = [", pdcp_pdu.sn);
for (const auto& nacked_segment : pdcp_pdu) {
fmt::format_to(buffer, "{} ", nacked_segment.rlc_sn());
}
fmt::format_to(buffer, "]\n");
}
}
bool rlc_am_start_aligned(const uint8_t fi)
{
return (fi == RLC_FI_FIELD_START_AND_END_ALIGNED || fi == RLC_FI_FIELD_NOT_END_ALIGNED);
}
bool rlc_am_end_aligned(const uint8_t fi)
{
return (fi == RLC_FI_FIELD_START_AND_END_ALIGNED || fi == RLC_FI_FIELD_NOT_START_ALIGNED);
}
bool rlc_am_is_unaligned(const uint8_t fi)
{
return (fi == RLC_FI_FIELD_NOT_START_OR_END_ALIGNED);
}
bool rlc_am_not_start_aligned(const uint8_t fi)
{
return (fi == RLC_FI_FIELD_NOT_START_ALIGNED || fi == RLC_FI_FIELD_NOT_START_OR_END_ALIGNED);
}
void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header)
{
if (not log_ch.enabled()) {
return;
}
fmt::memory_buffer buffer;
fmt::format_to(buffer,
"[{}, RF={}, P={}, FI={}, SN={}, LSF={}, SO={}, N_li={}",
rlc_dc_field_text[header.dc],
(header.rf ? "1" : "0"),
(header.p ? "1" : "0"),
(header.fi ? "1" : "0"),
header.sn,
(header.lsf ? "1" : "0"),
header.so,
header.N_li);
if (header.N_li > 0) {
fmt::format_to(buffer, " ({}", header.li[0]);
for (uint32_t i = 1; i < header.N_li; ++i) {
fmt::format_to(buffer, ", {}", header.li[i]);
}
fmt::format_to(buffer, ")");
}
fmt::format_to(buffer, "]");
log_ch("%s", to_c_str(buffer));
}
} // namespace srsran

@ -11,240 +11,17 @@
*/ */
#include "srsran/rlc/rlc_am_nr.h" #include "srsran/rlc/rlc_am_nr.h"
#include <sstream> #include "srsran/common/string_helpers.h"
#include "srsran/interfaces/ue_pdcp_interfaces.h"
#include "srsran/interfaces/ue_rrc_interfaces.h"
#include "srsran/srslog/event_trace.h"
#include <iostream>
namespace srsran { namespace srsran {
/**************************************************************************** /*******************************
* Header pack/unpack helper functions * RLC AM NR class
* Ref: 3GPP TS 38.322 v15.3.0 Section 6.2.2.4 ******************************/
***************************************************************************/ // TODO
uint32_t rlc_am_nr_read_data_pdu_header(const byte_buffer_t* pdu,
const rlc_am_nr_sn_size_t sn_size,
rlc_am_nr_pdu_header_t* header)
{
return rlc_am_nr_read_data_pdu_header(pdu->msg, pdu->N_bytes, sn_size, header);
}
uint32_t rlc_am_nr_read_data_pdu_header(const uint8_t* payload,
const uint32_t nof_bytes,
const rlc_am_nr_sn_size_t sn_size,
rlc_am_nr_pdu_header_t* header)
{
uint8_t* ptr = const_cast<uint8_t*>(payload);
header->sn_size = sn_size;
// Fixed part
header->dc = (rlc_dc_field_t)((*ptr >> 7) & 0x01); // 1 bit D/C field
header->p = (*ptr >> 6) & 0x01; // 1 bit P flag
header->si = (rlc_nr_si_field_t)((*ptr >> 4) & 0x03); // 2 bits SI
if (sn_size == rlc_am_nr_sn_size_t::size12bits) {
header->sn = (*ptr & 0x0F) << 8; // first 4 bits SN
ptr++;
header->sn |= (*ptr & 0xFF); // last 8 bits SN
ptr++;
} else if (sn_size == rlc_am_nr_sn_size_t::size18bits) {
// sanity check
if ((*ptr & 0x0c) != 0) {
fprintf(stderr, "Malformed PDU, reserved bits are set.\n");
return 0;
}
header->sn = (*ptr & 0x03) << 16; // first 4 bits SN
ptr++;
header->sn |= (*ptr & 0xFF) << 8; // bit 2-10 of SN
ptr++;
header->sn |= (*ptr & 0xFF); // last 8 bits SN
ptr++;
} else {
fprintf(stderr, "Unsupported SN length\n");
return 0;
}
// Read optional part
if (header->si == rlc_nr_si_field_t::last_segment ||
header->si == rlc_nr_si_field_t::neither_first_nor_last_segment) {
// read SO
header->so = (*ptr & 0xFF) << 8;
ptr++;
header->so |= (*ptr & 0xFF);
ptr++;
}
// return consumed bytes
return (ptr - payload);
}
uint32_t rlc_am_nr_packed_length(const rlc_am_nr_pdu_header_t& header)
{
uint32_t len = 0;
if (header.si == rlc_nr_si_field_t::full_sdu || header.si == rlc_nr_si_field_t::first_segment) {
len = 2;
if (header.sn_size == rlc_am_nr_sn_size_t::size18bits) {
len++;
}
} else {
// PDU contains SO
len = 4;
if (header.sn_size == rlc_am_nr_sn_size_t::size18bits) {
len++;
}
}
return len;
}
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;
uint8_t* ptr = pdu->msg;
// fixed header part
*ptr = (header.dc & 0x01) << 7; ///< 1 bit D/C field
*ptr |= (header.p & 0x01) << 6; ///< 1 bit P flag
*ptr |= (header.si & 0x03) << 4; ///< 2 bits SI
if (header.sn_size == rlc_am_nr_sn_size_t::size12bits) {
// write first 4 bit of SN
*ptr |= (header.sn >> 8) & 0x0f; // 4 bit SN
ptr++;
*ptr = header.sn & 0xff; // remaining 8 bit of SN
ptr++;
} else {
// 18bit SN
*ptr |= (header.sn >> 16) & 0x3; // 2 bit SN
ptr++;
*ptr = header.sn >> 8; // bit 3 - 10 of SN
ptr++;
*ptr = (header.sn & 0xff); // remaining 8 bit of SN
ptr++;
}
if (header.so) {
// write SO
*ptr = header.so >> 8; // first part of SO
ptr++;
*ptr = (header.so & 0xff); // second part of SO
ptr++;
}
pdu->N_bytes += ptr - pdu->msg;
return len;
}
uint32_t
rlc_am_nr_read_status_pdu(const byte_buffer_t* pdu, const rlc_am_nr_sn_size_t sn_size, rlc_am_nr_status_pdu_t* status)
{
return rlc_am_nr_read_status_pdu(pdu->msg, pdu->N_bytes, sn_size, status);
}
uint32_t rlc_am_nr_read_status_pdu(const uint8_t* payload,
const uint32_t nof_bytes,
const rlc_am_nr_sn_size_t sn_size,
rlc_am_nr_status_pdu_t* status)
{
uint8_t* ptr = const_cast<uint8_t*>(payload);
// fixed part
status->cpt = (rlc_am_nr_control_pdu_type_t)((*ptr >> 4) & 0x07); // 3 bits CPT
// sanity check
if (status->cpt != rlc_am_nr_control_pdu_type_t::status_pdu) {
fprintf(stderr, "Malformed PDU, reserved bits are set.\n");
return 0;
}
if (sn_size == rlc_am_nr_sn_size_t::size12bits) {
status->ack_sn = (*ptr & 0x0F) << 8; // first 4 bits SN
ptr++;
status->ack_sn |= (*ptr & 0xFF); // last 8 bits SN
ptr++;
// read E1 flag
uint8_t e1 = *ptr & 0x80;
// sanity check for reserved bits
if ((*ptr & 0x7f) != 0) {
fprintf(stderr, "Malformed PDU, reserved bits are set.\n");
return 0;
}
// all good, continue with next byte depending on E1
ptr++;
// reset number of acks
status->N_nack = 0;
if (e1) {
// E1 flag set, read a NACK_SN
rlc_status_nack_t nack = {};
nack.nack_sn = (*ptr & 0xff) << 4;
ptr++;
// uint8_t len2 = (*ptr & 0xF0) >> 4;
nack.nack_sn |= (*ptr & 0xF0) >> 4;
status->nacks[status->N_nack] = nack;
status->N_nack++;
}
}
return SRSRAN_SUCCESS;
}
/**
* Write a RLC AM NR status PDU to a PDU buffer and eets the length of the generate PDU accordingly
* @param status_pdu The status PDU
* @param pdu A pointer to a unique bytebuffer
* @return SRSRAN_SUCCESS if PDU was written, SRSRAN_ERROR otherwise
*/
int32_t rlc_am_nr_write_status_pdu(const rlc_am_nr_status_pdu_t& status_pdu,
const rlc_am_nr_sn_size_t sn_size,
byte_buffer_t* pdu)
{
uint8_t* ptr = pdu->msg;
// fixed header part
*ptr = 0; ///< 1 bit D/C field and 3bit CPT are all zero
if (sn_size == rlc_am_nr_sn_size_t::size12bits) {
// write first 4 bit of ACK_SN
*ptr |= (status_pdu.ack_sn >> 8) & 0x0f; // 4 bit ACK_SN
ptr++;
*ptr = status_pdu.ack_sn & 0xff; // remaining 8 bit of SN
ptr++;
// write E1 flag in octet 3
*ptr = (status_pdu.N_nack > 0) ? 0x80 : 0x00;
ptr++;
if (status_pdu.N_nack > 0) {
// write first 8 bit of NACK_SN
*ptr = (status_pdu.nacks[0].nack_sn >> 4) & 0xff;
ptr++;
// write remaining 4 bits of NACK_SN
*ptr = status_pdu.nacks[0].nack_sn & 0xf0;
ptr++;
}
} else {
// 18bit SN
*ptr |= (status_pdu.ack_sn >> 14) & 0x0f; // 4 bit ACK_SN
ptr++;
*ptr = status_pdu.ack_sn >> 8; // bit 3 - 10 of SN
ptr++;
*ptr = (status_pdu.ack_sn & 0xff); // remaining 6 bit of SN
ptr++;
}
pdu->N_bytes = ptr - pdu->msg;
return SRSRAN_SUCCESS;
}
} // namespace srsran } // namespace srsran

@ -0,0 +1,250 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srsran/rlc/rlc_am_nr_packing.h"
#include <sstream>
namespace srsran {
/****************************************************************************
* Header pack/unpack helper functions
* Ref: 3GPP TS 38.322 v15.3.0 Section 6.2.2.4
***************************************************************************/
uint32_t rlc_am_nr_read_data_pdu_header(const byte_buffer_t* pdu,
const rlc_am_nr_sn_size_t sn_size,
rlc_am_nr_pdu_header_t* header)
{
return rlc_am_nr_read_data_pdu_header(pdu->msg, pdu->N_bytes, sn_size, header);
}
uint32_t rlc_am_nr_read_data_pdu_header(const uint8_t* payload,
const uint32_t nof_bytes,
const rlc_am_nr_sn_size_t sn_size,
rlc_am_nr_pdu_header_t* header)
{
uint8_t* ptr = const_cast<uint8_t*>(payload);
header->sn_size = sn_size;
// Fixed part
header->dc = (rlc_dc_field_t)((*ptr >> 7) & 0x01); // 1 bit D/C field
header->p = (*ptr >> 6) & 0x01; // 1 bit P flag
header->si = (rlc_nr_si_field_t)((*ptr >> 4) & 0x03); // 2 bits SI
if (sn_size == rlc_am_nr_sn_size_t::size12bits) {
header->sn = (*ptr & 0x0F) << 8; // first 4 bits SN
ptr++;
header->sn |= (*ptr & 0xFF); // last 8 bits SN
ptr++;
} else if (sn_size == rlc_am_nr_sn_size_t::size18bits) {
// sanity check
if ((*ptr & 0x0c) != 0) {
fprintf(stderr, "Malformed PDU, reserved bits are set.\n");
return 0;
}
header->sn = (*ptr & 0x03) << 16; // first 4 bits SN
ptr++;
header->sn |= (*ptr & 0xFF) << 8; // bit 2-10 of SN
ptr++;
header->sn |= (*ptr & 0xFF); // last 8 bits SN
ptr++;
} else {
fprintf(stderr, "Unsupported SN length\n");
return 0;
}
// Read optional part
if (header->si == rlc_nr_si_field_t::last_segment ||
header->si == rlc_nr_si_field_t::neither_first_nor_last_segment) {
// read SO
header->so = (*ptr & 0xFF) << 8;
ptr++;
header->so |= (*ptr & 0xFF);
ptr++;
}
// return consumed bytes
return (ptr - payload);
}
uint32_t rlc_am_nr_packed_length(const rlc_am_nr_pdu_header_t& header)
{
uint32_t len = 0;
if (header.si == rlc_nr_si_field_t::full_sdu || header.si == rlc_nr_si_field_t::first_segment) {
len = 2;
if (header.sn_size == rlc_am_nr_sn_size_t::size18bits) {
len++;
}
} else {
// PDU contains SO
len = 4;
if (header.sn_size == rlc_am_nr_sn_size_t::size18bits) {
len++;
}
}
return len;
}
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;
uint8_t* ptr = pdu->msg;
// fixed header part
*ptr = (header.dc & 0x01) << 7; ///< 1 bit D/C field
*ptr |= (header.p & 0x01) << 6; ///< 1 bit P flag
*ptr |= (header.si & 0x03) << 4; ///< 2 bits SI
if (header.sn_size == rlc_am_nr_sn_size_t::size12bits) {
// write first 4 bit of SN
*ptr |= (header.sn >> 8) & 0x0f; // 4 bit SN
ptr++;
*ptr = header.sn & 0xff; // remaining 8 bit of SN
ptr++;
} else {
// 18bit SN
*ptr |= (header.sn >> 16) & 0x3; // 2 bit SN
ptr++;
*ptr = header.sn >> 8; // bit 3 - 10 of SN
ptr++;
*ptr = (header.sn & 0xff); // remaining 8 bit of SN
ptr++;
}
if (header.so) {
// write SO
*ptr = header.so >> 8; // first part of SO
ptr++;
*ptr = (header.so & 0xff); // second part of SO
ptr++;
}
pdu->N_bytes += ptr - pdu->msg;
return len;
}
uint32_t
rlc_am_nr_read_status_pdu(const byte_buffer_t* pdu, const rlc_am_nr_sn_size_t sn_size, rlc_am_nr_status_pdu_t* status)
{
return rlc_am_nr_read_status_pdu(pdu->msg, pdu->N_bytes, sn_size, status);
}
uint32_t rlc_am_nr_read_status_pdu(const uint8_t* payload,
const uint32_t nof_bytes,
const rlc_am_nr_sn_size_t sn_size,
rlc_am_nr_status_pdu_t* status)
{
uint8_t* ptr = const_cast<uint8_t*>(payload);
// fixed part
status->cpt = (rlc_am_nr_control_pdu_type_t)((*ptr >> 4) & 0x07); // 3 bits CPT
// sanity check
if (status->cpt != rlc_am_nr_control_pdu_type_t::status_pdu) {
fprintf(stderr, "Malformed PDU, reserved bits are set.\n");
return 0;
}
if (sn_size == rlc_am_nr_sn_size_t::size12bits) {
status->ack_sn = (*ptr & 0x0F) << 8; // first 4 bits SN
ptr++;
status->ack_sn |= (*ptr & 0xFF); // last 8 bits SN
ptr++;
// read E1 flag
uint8_t e1 = *ptr & 0x80;
// sanity check for reserved bits
if ((*ptr & 0x7f) != 0) {
fprintf(stderr, "Malformed PDU, reserved bits are set.\n");
return 0;
}
// all good, continue with next byte depending on E1
ptr++;
// reset number of acks
status->N_nack = 0;
if (e1) {
// E1 flag set, read a NACK_SN
rlc_status_nack_t nack = {};
nack.nack_sn = (*ptr & 0xff) << 4;
ptr++;
// uint8_t len2 = (*ptr & 0xF0) >> 4;
nack.nack_sn |= (*ptr & 0xF0) >> 4;
status->nacks[status->N_nack] = nack;
status->N_nack++;
}
}
return SRSRAN_SUCCESS;
}
/**
* Write a RLC AM NR status PDU to a PDU buffer and eets the length of the generate PDU accordingly
* @param status_pdu The status PDU
* @param pdu A pointer to a unique bytebuffer
* @return SRSRAN_SUCCESS if PDU was written, SRSRAN_ERROR otherwise
*/
int32_t rlc_am_nr_write_status_pdu(const rlc_am_nr_status_pdu_t& status_pdu,
const rlc_am_nr_sn_size_t sn_size,
byte_buffer_t* pdu)
{
uint8_t* ptr = pdu->msg;
// fixed header part
*ptr = 0; ///< 1 bit D/C field and 3bit CPT are all zero
if (sn_size == rlc_am_nr_sn_size_t::size12bits) {
// write first 4 bit of ACK_SN
*ptr |= (status_pdu.ack_sn >> 8) & 0x0f; // 4 bit ACK_SN
ptr++;
*ptr = status_pdu.ack_sn & 0xff; // remaining 8 bit of SN
ptr++;
// write E1 flag in octet 3
*ptr = (status_pdu.N_nack > 0) ? 0x80 : 0x00;
ptr++;
if (status_pdu.N_nack > 0) {
// write first 8 bit of NACK_SN
*ptr = (status_pdu.nacks[0].nack_sn >> 4) & 0xff;
ptr++;
// write remaining 4 bits of NACK_SN
*ptr = status_pdu.nacks[0].nack_sn & 0xf0;
ptr++;
}
} else {
// 18bit SN
*ptr |= (status_pdu.ack_sn >> 14) & 0x0f; // 4 bit ACK_SN
ptr++;
*ptr = status_pdu.ack_sn >> 8; // bit 3 - 10 of SN
ptr++;
*ptr = (status_pdu.ack_sn & 0xff); // remaining 6 bit of SN
ptr++;
}
pdu->N_bytes = ptr - pdu->msg;
return SRSRAN_SUCCESS;
}
} // namespace srsran

@ -12,7 +12,7 @@
#include "srsran/config.h" #include "srsran/config.h"
#include "srsran/rlc/rlc.h" #include "srsran/rlc/rlc.h"
#include "srsran/rlc/rlc_am_nr.h" #include "srsran/rlc/rlc_am_nr_packing.h"
#include <array> #include <array>
#include <iostream> #include <iostream>

Loading…
Cancel
Save