From b32a4cf294146132ab24311529dd9404cc4c396a Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 14 Nov 2019 21:29:17 +0100 Subject: [PATCH] add RLC AM NR PDU packing and unpacking --- .../srslte/interfaces/rrc_interface_types.h | 14 ++ lib/include/srslte/upper/rlc_am_base.h | 42 +++++ lib/include/srslte/upper/rlc_am_nr.h | 64 ++++++++ lib/include/srslte/upper/rlc_common.h | 16 +- lib/src/upper/CMakeLists.txt | 3 +- lib/src/upper/rlc_am_nr.cc | 147 ++++++++++++++++++ 6 files changed, 283 insertions(+), 3 deletions(-) create mode 100644 lib/include/srslte/upper/rlc_am_base.h create mode 100644 lib/include/srslte/upper/rlc_am_nr.h create mode 100644 lib/src/upper/rlc_am_nr.cc diff --git a/lib/include/srslte/interfaces/rrc_interface_types.h b/lib/include/srslte/interfaces/rrc_interface_types.h index 10f97fcb8..6f4459c66 100644 --- a/lib/include/srslte/interfaces/rrc_interface_types.h +++ b/lib/include/srslte/interfaces/rrc_interface_types.h @@ -203,6 +203,7 @@ inline uint16_t to_number(const rlc_umd_sn_size_t& sn_size) return enum_to_number(options, (uint32_t)rlc_mode_t::nulltype, (uint32_t)sn_size); } +///< RLC UM NR sequence number field enum class rlc_um_nr_sn_size_t { size6bits, size12bits, nulltype }; inline std::string to_string(const rlc_um_nr_sn_size_t& sn_size) { @@ -215,6 +216,19 @@ inline uint16_t to_number(const rlc_um_nr_sn_size_t& sn_size) return enum_to_number(options, (uint32_t)rlc_mode_t::nulltype, (uint32_t)sn_size); } +///< RLC AM NR sequence number field +enum class rlc_am_nr_sn_size_t { size12bits, size18bits, nulltype }; +inline std::string to_string(const rlc_am_nr_sn_size_t& sn_size) +{ + constexpr static const char* options[] = {"12 bits", "18 bits"}; + return enum_to_text(options, (uint32_t)rlc_mode_t::nulltype, (uint32_t)sn_size); +} +inline uint16_t to_number(const rlc_am_nr_sn_size_t& sn_size) +{ + constexpr static uint16_t options[] = {12, 18}; + return enum_to_number(options, (uint32_t)rlc_mode_t::nulltype, (uint32_t)sn_size); +} + struct rlc_am_config_t { /**************************************************************************** * Configurable parameters diff --git a/lib/include/srslte/upper/rlc_am_base.h b/lib/include/srslte/upper/rlc_am_base.h new file mode 100644 index 000000000..d29264ed1 --- /dev/null +++ b/lib/include/srslte/upper/rlc_am_base.h @@ -0,0 +1,42 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSLTE_RLC_AM_BASE_H +#define SRSLTE_RLC_AM_BASE_H + +#include "srslte/common/buffer_pool.h" +#include "srslte/common/common.h" +#include "srslte/common/log.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/upper/rlc_common.h" +#include "srslte/upper/rlc_tx_queue.h" +#include +#include +#include +#include + +namespace srslte { + +///< Add rlc_am_base here + +} // namespace srslte + +#endif // SRSLTE_RLC_AM_BASE_H diff --git a/lib/include/srslte/upper/rlc_am_nr.h b/lib/include/srslte/upper/rlc_am_nr.h new file mode 100644 index 000000000..aaf4a3468 --- /dev/null +++ b/lib/include/srslte/upper/rlc_am_nr.h @@ -0,0 +1,64 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSLTE_RLC_AM_NR_H +#define SRSLTE_RLC_AM_NR_H + +#include "srslte/common/buffer_pool.h" +#include "srslte/common/common.h" +#include "srslte/common/log.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/upper/rlc_am_base.h" +#include "srslte/upper/rlc_tx_queue.h" +#include +#include +#include +#include + +namespace srslte { + +typedef struct { + 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); + +} // namespace srslte + +#endif // SRSLTE_RLC_AM_NR_H diff --git a/lib/include/srslte/upper/rlc_common.h b/lib/include/srslte/upper/rlc_common.h index ede2dabf9..3b1286852 100644 --- a/lib/include/srslte/upper/rlc_common.h +++ b/lib/include/srslte/upper/rlc_common.h @@ -77,11 +77,11 @@ static inline uint8_t operator&(rlc_nr_si_field_t lhs, int rhs) static_cast::type>(rhs)); } -typedef enum{ +typedef enum { RLC_DC_FIELD_CONTROL_PDU = 0, RLC_DC_FIELD_DATA_PDU, RLC_DC_FIELD_N_ITEMS, -}rlc_dc_field_t; +} rlc_dc_field_t; static const char rlc_dc_field_text[RLC_DC_FIELD_N_ITEMS][20] = {"Control PDU", "Data PDU"}; @@ -169,6 +169,18 @@ struct rlc_status_pdu_t{ rlc_status_pdu_t(){N_nack=0; ack_sn=0;} }; +/** 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; + /**************************************************************************** * RLC Common interface * Common interface for all RLC entities diff --git a/lib/src/upper/CMakeLists.txt b/lib/src/upper/CMakeLists.txt index 364b1ceb4..9bac16c28 100644 --- a/lib/src/upper/CMakeLists.txt +++ b/lib/src/upper/CMakeLists.txt @@ -28,7 +28,8 @@ set(SOURCES gtpu.cc rlc_um_base.cc rlc_um_lte.cc rlc_um_nr.cc - rlc_am_lte.cc) + rlc_am_lte.cc + rlc_am_nr.cc) add_library(srslte_upper STATIC ${SOURCES}) target_link_libraries(srslte_upper srslte_common srslte_asn1) install(TARGETS srslte_upper DESTINATION ${LIBRARY_DIR}) \ No newline at end of file diff --git a/lib/src/upper/rlc_am_nr.cc b/lib/src/upper/rlc_am_nr.cc new file mode 100644 index 000000000..f4b887ad7 --- /dev/null +++ b/lib/src/upper/rlc_am_nr.cc @@ -0,0 +1,147 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "srslte/upper/rlc_am_nr.h" +#include + +namespace srslte { + +/**************************************************************************** + * 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(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 (header->sn > 3) { + fprintf(stderr, "Malformed PDU, reserved bits are set.\n"); + return 0; + } + header->sn |= (*ptr & 0xFF); // 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 & 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; +} + +} // namespace srslte