Merge branch 'next' into agpl_next

# Conflicts:
#	lib/include/srsran/common/basic_pnf.h
#	lib/include/srsran/common/basic_vnf.h
#	lib/include/srsran/common/basic_vnf_api.h
#	lib/src/common/basic_vnf.cc
#	lib/test/common/pnf_bridge.cc
#	lib/test/common/pnf_dummy.cc
#	srsenb/hdr/phy/vnf_phy_nr.h
#	srsenb/hdr/stack/mac/nr/sched_nr_common.h
#	srsenb/hdr/stack/mac/nr/sched_nr_phy_helpers.h
#	srsenb/src/phy/vnf_phy_nr.cc
#	srsenb/src/stack/mac/nr/sched_nr_common.cc
#	srsenb/src/stack/mac/nr/sched_nr_phy_helpers.cc
#	srsue/hdr/phy/vnf_phy_nr.h
#	srsue/src/phy/vnf_phy_nr.cc
master
Codebot 3 years ago committed by Your Name
commit ccf8cfb65f

@ -24,4 +24,4 @@ set(CTEST_DROP_METHOD "http")
set(CTEST_DROP_SITE "my.cdash.org")
set(CTEST_DROP_LOCATION "/submit.php?project=srsRAN")
set(CTEST_DROP_SITE_CDASH TRUE)
set(VALGRIND_COMMAND_OPTIONS "--error-exitcode=1 --trace-children=yes --leak-check=full --show-reachable=yes --vex-guest-max-insns=25")
set(VALGRIND_COMMAND_OPTIONS "--error-exitcode=1 --trace-children=yes --leak-check=full --show-leak-kinds=all --track-origins=yes --show-reachable=yes --vex-guest-max-insns=25")

@ -105,7 +105,7 @@ install_file "ue.conf.example"
install_file "enb.conf.example"
install_file "sib.conf.example"
install_file "rr.conf.example"
install_file "drb.conf.example"
install_file "rb.conf.example"
install_file "epc.conf.example"
install_file "mbms.conf.example"
install_file "user_db.csv.example"

@ -2127,264 +2127,352 @@ public:
registration_request_t& set_registration_request()
{
set(msg_types::options::registration_request);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{registration_request_t()};
return *srslog::detail::any_cast<registration_request_t>(&msg_container);
}
registration_accept_t& set_registration_accept()
{
set(msg_types::options::registration_accept);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{registration_accept_t()};
return *srslog::detail::any_cast<registration_accept_t>(&msg_container);
}
registration_complete_t& set_registration_complete()
{
set(msg_types::options::registration_complete);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{registration_complete_t()};
return *srslog::detail::any_cast<registration_complete_t>(&msg_container);
}
registration_reject_t& set_registration_reject()
{
set(msg_types::options::registration_reject);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{registration_reject_t()};
return *srslog::detail::any_cast<registration_reject_t>(&msg_container);
}
deregistration_request_ue_originating_t& set_deregistration_request_ue_originating()
{
set(msg_types::options::deregistration_request_ue_originating);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{deregistration_request_ue_originating_t()};
return *srslog::detail::any_cast<deregistration_request_ue_originating_t>(&msg_container);
}
deregistration_accept_ue_originating_t& set_deregistration_accept_ue_originating()
{
set(msg_types::options::deregistration_accept_ue_originating);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{deregistration_accept_ue_originating_t()};
return *srslog::detail::any_cast<deregistration_accept_ue_originating_t>(&msg_container);
}
deregistration_request_ue_terminated_t& set_deregistration_request_ue_terminated()
{
set(msg_types::options::deregistration_request_ue_terminated);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{deregistration_request_ue_terminated_t()};
return *srslog::detail::any_cast<deregistration_request_ue_terminated_t>(&msg_container);
}
deregistration_accept_ue_terminated_t& set_deregistration_accept_ue_terminated()
{
set(msg_types::options::deregistration_accept_ue_terminated);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{deregistration_accept_ue_terminated_t()};
return *srslog::detail::any_cast<deregistration_accept_ue_terminated_t>(&msg_container);
}
service_request_t& set_service_request()
{
set(msg_types::options::service_request);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{service_request_t()};
return *srslog::detail::any_cast<service_request_t>(&msg_container);
}
service_reject_t& set_service_reject()
{
set(msg_types::options::service_reject);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{service_reject_t()};
return *srslog::detail::any_cast<service_reject_t>(&msg_container);
}
service_accept_t& set_service_accept()
{
set(msg_types::options::service_accept);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{service_accept_t()};
return *srslog::detail::any_cast<service_accept_t>(&msg_container);
}
configuration_update_command_t& set_configuration_update_command()
{
set(msg_types::options::configuration_update_command);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{configuration_update_command_t()};
return *srslog::detail::any_cast<configuration_update_command_t>(&msg_container);
}
configuration_update_complete_t& set_configuration_update_complete()
{
set(msg_types::options::configuration_update_complete);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{configuration_update_complete_t()};
return *srslog::detail::any_cast<configuration_update_complete_t>(&msg_container);
}
authentication_request_t& set_authentication_request()
{
set(msg_types::options::authentication_request);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{authentication_request_t()};
return *srslog::detail::any_cast<authentication_request_t>(&msg_container);
}
authentication_response_t& set_authentication_response()
{
set(msg_types::options::authentication_response);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{authentication_response_t()};
return *srslog::detail::any_cast<authentication_response_t>(&msg_container);
}
authentication_reject_t& set_authentication_reject()
{
set(msg_types::options::authentication_reject);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{authentication_reject_t()};
return *srslog::detail::any_cast<authentication_reject_t>(&msg_container);
}
authentication_failure_t& set_authentication_failure()
{
set(msg_types::options::authentication_failure);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{authentication_failure_t()};
return *srslog::detail::any_cast<authentication_failure_t>(&msg_container);
}
authentication_result_t& set_authentication_result()
{
set(msg_types::options::authentication_result);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{authentication_result_t()};
return *srslog::detail::any_cast<authentication_result_t>(&msg_container);
}
identity_request_t& set_identity_request()
{
set(msg_types::options::identity_request);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{identity_request_t()};
return *srslog::detail::any_cast<identity_request_t>(&msg_container);
}
identity_response_t& set_identity_response()
{
set(msg_types::options::identity_response);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{identity_response_t()};
return *srslog::detail::any_cast<identity_response_t>(&msg_container);
}
security_mode_command_t& set_security_mode_command()
{
set(msg_types::options::security_mode_command);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{security_mode_command_t()};
return *srslog::detail::any_cast<security_mode_command_t>(&msg_container);
}
security_mode_complete_t& set_security_mode_complete()
{
set(msg_types::options::security_mode_complete);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{security_mode_complete_t()};
return *srslog::detail::any_cast<security_mode_complete_t>(&msg_container);
}
security_mode_reject_t& set_security_mode_reject()
{
set(msg_types::options::security_mode_reject);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{security_mode_reject_t()};
return *srslog::detail::any_cast<security_mode_reject_t>(&msg_container);
}
status_5gmm_t& set_status_5gmm()
{
set(msg_types::options::status_5gmm);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{status_5gmm_t()};
return *srslog::detail::any_cast<status_5gmm_t>(&msg_container);
}
notification_t& set_notification()
{
set(msg_types::options::notification);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{notification_t()};
return *srslog::detail::any_cast<notification_t>(&msg_container);
}
notification_response_t& set_notification_response()
{
set(msg_types::options::notification_response);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{notification_response_t()};
return *srslog::detail::any_cast<notification_response_t>(&msg_container);
}
ul_nas_transport_t& set_ul_nas_transport()
{
set(msg_types::options::ul_nas_transport);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{ul_nas_transport_t()};
return *srslog::detail::any_cast<ul_nas_transport_t>(&msg_container);
}
dl_nas_transport_t& set_dl_nas_transport()
{
set(msg_types::options::dl_nas_transport);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gmm;
msg_container = srslog::detail::any{dl_nas_transport_t()};
return *srslog::detail::any_cast<dl_nas_transport_t>(&msg_container);
}
pdu_session_establishment_request_t& set_pdu_session_establishment_request()
{
set(msg_types::options::pdu_session_establishment_request);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
msg_container = srslog::detail::any{pdu_session_establishment_request_t()};
return *srslog::detail::any_cast<pdu_session_establishment_request_t>(&msg_container);
}
pdu_session_establishment_accept_t& set_pdu_session_establishment_accept()
{
set(msg_types::options::pdu_session_establishment_accept);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
msg_container = srslog::detail::any{pdu_session_establishment_accept_t()};
return *srslog::detail::any_cast<pdu_session_establishment_accept_t>(&msg_container);
}
pdu_session_establishment_reject_t& set_pdu_session_establishment_reject()
{
set(msg_types::options::pdu_session_establishment_reject);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
msg_container = srslog::detail::any{pdu_session_establishment_reject_t()};
return *srslog::detail::any_cast<pdu_session_establishment_reject_t>(&msg_container);
}
pdu_session_authentication_command_t& set_pdu_session_authentication_command()
{
set(msg_types::options::pdu_session_authentication_command);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
msg_container = srslog::detail::any{pdu_session_authentication_command_t()};
return *srslog::detail::any_cast<pdu_session_authentication_command_t>(&msg_container);
}
pdu_session_authentication_complete_t& set_pdu_session_authentication_complete()
{
set(msg_types::options::pdu_session_authentication_complete);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
msg_container = srslog::detail::any{pdu_session_authentication_complete_t()};
return *srslog::detail::any_cast<pdu_session_authentication_complete_t>(&msg_container);
}
pdu_session_authentication_result_t& set_pdu_session_authentication_result()
{
set(msg_types::options::pdu_session_authentication_result);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
msg_container = srslog::detail::any{pdu_session_authentication_result_t()};
return *srslog::detail::any_cast<pdu_session_authentication_result_t>(&msg_container);
}
pdu_session_modification_request_t& set_pdu_session_modification_request()
{
set(msg_types::options::pdu_session_modification_request);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
msg_container = srslog::detail::any{pdu_session_modification_request_t()};
return *srslog::detail::any_cast<pdu_session_modification_request_t>(&msg_container);
}
pdu_session_modification_reject_t& set_pdu_session_modification_reject()
{
set(msg_types::options::pdu_session_modification_reject);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
msg_container = srslog::detail::any{pdu_session_modification_reject_t()};
return *srslog::detail::any_cast<pdu_session_modification_reject_t>(&msg_container);
}
pdu_session_modification_command_t& set_pdu_session_modification_command()
{
set(msg_types::options::pdu_session_modification_command);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
msg_container = srslog::detail::any{pdu_session_modification_command_t()};
return *srslog::detail::any_cast<pdu_session_modification_command_t>(&msg_container);
}
pdu_session_modification_complete_t& set_pdu_session_modification_complete()
{
set(msg_types::options::pdu_session_modification_complete);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
msg_container = srslog::detail::any{pdu_session_modification_complete_t()};
return *srslog::detail::any_cast<pdu_session_modification_complete_t>(&msg_container);
}
pdu_session_modification_command_reject_t& set_pdu_session_modification_command_reject()
{
set(msg_types::options::pdu_session_modification_command_reject);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
msg_container = srslog::detail::any{pdu_session_modification_command_reject_t()};
return *srslog::detail::any_cast<pdu_session_modification_command_reject_t>(&msg_container);
}
pdu_session_release_request_t& set_pdu_session_release_request()
{
set(msg_types::options::pdu_session_release_request);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
msg_container = srslog::detail::any{pdu_session_release_request_t()};
return *srslog::detail::any_cast<pdu_session_release_request_t>(&msg_container);
}
pdu_session_release_reject_t& set_pdu_session_release_reject()
{
set(msg_types::options::pdu_session_release_reject);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
msg_container = srslog::detail::any{pdu_session_release_reject_t()};
return *srslog::detail::any_cast<pdu_session_release_reject_t>(&msg_container);
}
pdu_session_release_command_t& set_pdu_session_release_command()
{
set(msg_types::options::pdu_session_release_command);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
msg_container = srslog::detail::any{pdu_session_release_command_t()};
return *srslog::detail::any_cast<pdu_session_release_command_t>(&msg_container);
}
pdu_session_release_complete_t& set_pdu_session_release_complete()
{
set(msg_types::options::pdu_session_release_complete);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
msg_container = srslog::detail::any{pdu_session_release_complete_t()};
return *srslog::detail::any_cast<pdu_session_release_complete_t>(&msg_container);
}
status_5gsm_t& set_status_5gsm()
{
set(msg_types::options::status_5gsm);
hdr.extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
hdr.inner_extended_protocol_discriminator = nas_5gs_hdr::extended_protocol_discriminator_5gsm;
msg_container = srslog::detail::any{status_5gsm_t()};
return *srslog::detail::any_cast<status_5gsm_t>(&msg_container);
}

@ -1,558 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN 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.
*
* srsRAN 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 SRSRAN_BASIC_PNF_H
#define SRSRAN_BASIC_PNF_H
#include "basic_vnf_api.h"
#include "common.h"
#include "srsran/adt/choice_type.h"
#include "srsran/common/block_queue.h"
#include "srsran/common/buffer_pool.h"
#include "srsran/srslog/srslog.h"
#include <arpa/inet.h>
#include <atomic>
#include <errno.h>
#include <fcntl.h>
#include <iostream>
#include <mutex>
#include <netinet/in.h>
#include <poll.h>
#include <random>
#include <strings.h>
#include <sys/socket.h>
#include <thread>
#include <unistd.h>
#define RAND_SEED (12384)
#define RX_TIMEOUT_MS (500)
#define MIN_TB_LEN (100) // MAX_TB_LEN defined in api.h
#define PING_REQUEST_PDU 1
namespace srsran {
struct pnf_metrics_t {
uint32_t avg_rtt_us;
uint32_t num_timing_errors;
uint32_t num_pdus;
uint32_t tb_size;
};
class srsran_basic_pnf
{
using msg_header_t = basic_vnf_api::msg_header_t;
const static size_t buffer_size =
srsran::static_max<sizeof(basic_vnf_api::dl_conf_msg_t), sizeof(basic_vnf_api::tx_request_msg_t)>::value;
using msg_buffer_t = std::array<uint8_t, buffer_size>;
public:
srsran_basic_pnf(const std::string& type_,
const std::string& vnf_p5_addr,
const uint16_t& vnf_p5_port,
const uint32_t& sf_interval,
const int32_t& num_sf_,
const uint32_t& tb_len_) :
running(false),
type(type_),
tti(100), ///< Random start TTI
vnf_addr(vnf_p5_addr),
vnf_port(vnf_p5_port),
sf_interval_us(sf_interval),
num_sf(num_sf_),
tb_len(tb_len_),
rand_gen(RAND_SEED),
rand_dist(MIN_TB_LEN, MAX_TB_LEN)
{
logger.set_level(srslog::basic_levels::warning);
logger.set_hex_dump_max_size(-1);
}
~srsran_basic_pnf() { stop(); };
bool start()
{
// create socket
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
return false;
}
int enable = 1;
#if defined(SO_REUSEADDR)
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
perror("setsockopt(SO_REUSEADDR) failed");
}
#endif
#if defined(SO_REUSEPORT)
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) {
perror("setsockopt(SO_REUSEPORT) failed");
}
#endif
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(vnf_addr.c_str());
servaddr.sin_port = htons(vnf_port);
// start main thread
running = true;
if (type == "gnb") {
rx_thread = std::unique_ptr<std::thread>(new std::thread(&srsran_basic_pnf::dl_handler_thread, this));
tx_thread = std::unique_ptr<std::thread>(new std::thread(&srsran_basic_pnf::ul_handler_thread, this));
} else {
tx_thread = std::unique_ptr<std::thread>(new std::thread(&srsran_basic_pnf::ue_dl_handler_thread, this));
}
return true;
};
bool stop()
{
running = false;
if (rx_thread) {
if (rx_thread->joinable()) {
rx_thread->join();
}
}
if (tx_thread) {
if (tx_thread->joinable()) {
tx_thread->join();
}
}
return true;
};
pnf_metrics_t get_metrics()
{
pnf_metrics_t tmp = metrics;
metrics = {};
return tmp;
}
void connect_out_rf_queue(srsran::block_queue<srsran::unique_byte_buffer_t>* rf_queue_)
{
rf_out_queue = rf_queue_;
policy = bridge;
}
srsran::block_queue<srsran::unique_byte_buffer_t>* get_in_rf_queue()
{
policy = bridge;
return &rf_in_queue;
}
private:
//! Waits for DL Config or Tx Request Msg from VNF and forwards to RF
void dl_handler_thread()
{
pthread_setname_np(pthread_self(), rx_thread_name.c_str());
// set_rt_prio();
struct pollfd fd;
fd.fd = sockfd;
fd.events = POLLIN;
std::unique_ptr<msg_buffer_t> rx_buffer{new msg_buffer_t{}};
while (running) {
// receive response
int ret = poll(&fd, 1, RX_TIMEOUT_MS);
switch (ret) {
case -1:
printf("Error occurred.\n");
running = false;
break;
case 0:
// Timeout
printf("Error: Didn't receive response after %dms\n", RX_TIMEOUT_MS);
break;
default:
int recv_ret = recv(sockfd, rx_buffer->data(), sizeof(*rx_buffer), 0);
handle_msg(rx_buffer->data(), recv_ret);
break;
}
std::lock_guard<std::mutex> lock(mutex);
auto rtt =
std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - tti_start_time)
.count();
// TODO: add averaging
metrics.avg_rtt_us = rtt;
}
};
void ul_handler_thread()
{
pthread_setname_np(pthread_self(), tx_thread_name.c_str());
// set_rt_prio();
struct pollfd fd;
fd.fd = sockfd;
fd.events = POLLIN;
const uint32_t max_basic_api_pdu = sizeof(basic_vnf_api::dl_conf_msg_t) + 32; // larger than biggest message
std::unique_ptr<std::array<uint8_t, max_basic_api_pdu> > rx_buffer =
std::unique_ptr<std::array<uint8_t, max_basic_api_pdu> >(new std::array<uint8_t, max_basic_api_pdu>);
int32_t sf_counter = 0;
while (running && (num_sf > 0 ? sf_counter < num_sf : true)) {
{
std::lock_guard<std::mutex> lock(mutex);
// Increase TTI
tti = (tti + 1) % 10240;
// Take time before sending the SF indication
tti_start_time = std::chrono::steady_clock::now();
// Send request
send_sf_ind(tti);
if (policy == bridge) {
// send_rx_data_ind(tti);
} else {
// provide UL data every 2nd TTI
if (tti % 2 == 0) {
send_rx_data_ind(tti);
}
}
sf_counter++;
}
std::this_thread::sleep_for(std::chrono::microseconds(sf_interval_us));
}
printf("Leaving Tx thread after %d subframes\n", sf_counter);
};
void ue_dl_handler_thread()
{
pthread_setname_np(pthread_self(), tx_thread_name.c_str());
// set_rt_prio();
struct pollfd fd;
fd.fd = sockfd;
fd.events = POLLIN;
const uint32_t max_basic_api_pdu = sizeof(basic_vnf_api::dl_conf_msg_t) + 32; // larger than biggest message
std::unique_ptr<std::array<uint8_t, max_basic_api_pdu> > rx_buffer =
std::unique_ptr<std::array<uint8_t, max_basic_api_pdu> >(new std::array<uint8_t, max_basic_api_pdu>);
int32_t sf_counter = 0;
while (running && (num_sf > 0 ? sf_counter < num_sf : true)) {
{
std::lock_guard<std::mutex> lock(mutex);
// Increase TTI
tti = (tti + 1) % 10240;
// Take time before sending the SF indication
tti_start_time = std::chrono::steady_clock::now();
// Send SF indication
send_sf_ind(tti);
if (policy == bridge) {
srsran::unique_byte_buffer_t tb;
if (rf_in_queue.try_pop(&tb)) {
send_dl_ind(tti, std::move(tb));
}
} else {
// provide DL grant every even TTI, and UL grant every odd
if (tti % 2 == 0) {
send_dl_ind(tti);
} else {
send_ul_ind(tti);
}
}
sf_counter++;
}
std::this_thread::sleep_for(std::chrono::microseconds(sf_interval_us));
}
printf("Leaving Tx thread after %d subframes\n", sf_counter);
};
void send_sf_ind(uint32_t tti_)
{
basic_vnf_api::sf_ind_msg_t sf_ind;
bzero(&sf_ind, sizeof(sf_ind));
sf_ind.header.type = basic_vnf_api::SF_IND;
sf_ind.header.msg_len = sizeof(sf_ind) - sizeof(basic_vnf_api::msg_header_t);
sf_ind.tti = tti_;
sf_ind.t1 = 0;
sf_ind.tb_len = tb_len > 0 ? tb_len : rand_dist(rand_gen);
int n = 0;
if ((n = sendto(sockfd, &sf_ind, sizeof(sf_ind), 0, (struct sockaddr*)&servaddr, sizeof(servaddr))) < 0) {
printf("sendto failed, ret=%d\n", n);
}
}
int handle_msg(const uint8_t* buffer, const uint32_t len)
{
basic_vnf_api::msg_header_t* header = (basic_vnf_api::msg_header_t*)buffer;
logger.debug("Received %s (%d B) in TTI", basic_vnf_api::msg_type_text[header->type], len);
switch (header->type) {
case basic_vnf_api::SF_IND:
printf("Error: %s not handled by VNF\n", basic_vnf_api::msg_type_text[header->type]);
break;
case basic_vnf_api::DL_CONFIG:
handle_dl_config((basic_vnf_api::dl_conf_msg_t*)header);
break;
case basic_vnf_api::TX_REQUEST:
handle_tx_request((basic_vnf_api::tx_request_msg_t*)header);
break;
default:
printf("Unknown msg type.\n");
break;
}
return 0;
}
int handle_dl_config(basic_vnf_api::dl_conf_msg_t* msg)
{
// printf("Received DL config for TTI=%d\n", msg->tti);
if (msg->tti != tti) {
metrics.num_timing_errors++;
// printf("Received DL config for TTI=%d but current TTI is %d\n", msg->tti, tti.load());
return -1;
}
return 0;
}
int handle_tx_request(basic_vnf_api::tx_request_msg_t* msg)
{
if (msg->tti != tti) {
metrics.num_timing_errors++;
}
for (uint32_t i = 0; i < msg->nof_pdus; ++i) {
metrics.tb_size += msg->pdus[i].length;
}
metrics.num_pdus += msg->nof_pdus;
if (rf_out_queue != nullptr) {
uint32_t len = sizeof(*msg) - sizeof(msg->pdus->data) + msg->pdus->length;
srsran::unique_byte_buffer_t tx = srsran::make_byte_buffer();
if (tx == nullptr) {
return -1;
}
memcpy(tx->msg, msg, len);
rf_out_queue->push(std::move(tx));
}
return 0;
}
void send_rx_data_ind(const uint32_t tti_)
{
// MAC PDU for UL-SCH with IPv6 router solicitation
static uint8_t tv[] = {0x04, 0x38, 0x00, 0x80, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x44, 0x4b, 0x0f, 0x2c, 0x33, 0x98, 0xf2,
0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x85, 0x00, 0x4b, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x7f, 0x00, 0x00, 0x3f, 0x00};
basic_vnf_api::rx_data_ind_msg_t rx_ind = {};
rx_ind.header.type = basic_vnf_api::RX_DATA_IND;
rx_ind.header.msg_len = sizeof(rx_ind) - sizeof(basic_vnf_api::msg_header_t);
rx_ind.sfn = tti_;
rx_ind.t1 = 0;
rx_ind.nof_pdus = 1;
rx_ind.pdus[0].type = basic_vnf_api::PUSCH;
rx_ind.pdus[0].length = tb_len > 0 ? tb_len : rand_dist(rand_gen);
if (rx_ind.pdus[0].length >= sizeof(tv)) {
// copy TV
memcpy(rx_ind.pdus[0].data, tv, sizeof(tv));
// set remaining bytes to zero
memset(rx_ind.pdus[0].data + sizeof(tv), 0xaa, rx_ind.pdus[0].length - sizeof(tv));
} else {
// just fill with dummy bytes
memset(rx_ind.pdus[0].data, 0xab, rx_ind.pdus[0].length);
}
int n = 0;
if ((n = sendto(sockfd, &rx_ind, sizeof(rx_ind), 0, (struct sockaddr*)&servaddr, sizeof(servaddr))) < 0) {
printf("sendto failed, ret=%d\n", n);
}
}
void send_dl_ind(uint32_t tti_, srsran::unique_byte_buffer_t tb = {})
{
#if PING_REQUEST_PDU
static uint8_t tv[] = {
0x04, 0x5c, 0x00, 0x80, 0x00, 0x00, 0x45, 0x00, 0x00, 0x54, 0x15, 0x02, 0x40, 0x00, 0x40, 0x01, 0xa2, 0x52,
0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0x03, 0x08, 0x00, 0x26, 0x40, 0x5e, 0x8f, 0x00, 0xb3, 0x04, 0x55,
0xc4, 0x5d, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xf7, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13,
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x4f, 0x7f, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
#else
// MAC PDU with a single LCID with padding only
static uint8_t tv[] = {
0x01,
0x08,
0x11,
0x22,
0x33,
0x44,
0x55,
0x66,
0x77,
0x88,
0x3f,
};
#endif // PING_REQUEST_PDU
basic_vnf_api::dl_ind_msg_t dl_ind = {};
dl_ind.header.type = basic_vnf_api::DL_IND;
dl_ind.header.msg_len = sizeof(dl_ind) - sizeof(basic_vnf_api::msg_header_t);
dl_ind.tti = tti_;
dl_ind.t1 = 0;
uint32_t tot_bytes = 0;
uint32_t tb_size = tb_len > 0 ? tb_len : rand_dist(rand_gen);
if (tb != nullptr) {
auto* header = (basic_vnf_api::msg_header_t*)tb->msg;
if (header->type == basic_vnf_api::TX_REQUEST) {
auto* tx_req = (basic_vnf_api::tx_request_msg_t*)tb->msg;
dl_ind.nof_pdus = tx_req->nof_pdus;
// dl_ind.tti = tx_req->tti;
for (uint32_t i = 0; i < dl_ind.nof_pdus; ++i) {
dl_ind.pdus[i].length = tx_req->pdus[i].length;
dl_ind.pdus[i].type = tx_req->pdus[i].type;
memcpy(dl_ind.pdus[i].data, tx_req->pdus[i].data, dl_ind.pdus[i].length);
tot_bytes += dl_ind.pdus[i].length;
logger.info(
dl_ind.pdus[i].data, dl_ind.pdus[i].length, "Sending to UE a PDU (%d bytes)", dl_ind.pdus[i].length);
}
}
} else {
uint32_t N_bytes = sizeof(tv);
// Create default
dl_ind.nof_pdus = 1;
dl_ind.pdus[0].type = basic_vnf_api::PDSCH;
dl_ind.pdus[0].length = tb_size;
if (dl_ind.pdus[0].length >= N_bytes) {
// copy TV
memcpy(dl_ind.pdus[0].data, tv, N_bytes);
tot_bytes = N_bytes;
}
logger.info(dl_ind.pdus[0].data, N_bytes, "Sending to UE a TB (%d bytes)", N_bytes);
}
if (tot_bytes > 0 and tot_bytes < tb_size) {
uint8_t* offset = &dl_ind.pdus[dl_ind.nof_pdus - 1].data[dl_ind.pdus[dl_ind.nof_pdus - 1].length];
memset(offset, 0xaa, tb_size - tot_bytes);
} else if (tot_bytes == 0) {
// just fill with dummy bytes
dl_ind.nof_pdus = 1;
memset(dl_ind.pdus[0].data, 0xab, tb_size);
}
int n = 0;
if ((n = sendto(sockfd, &dl_ind, sizeof(dl_ind), 0, (struct sockaddr*)&servaddr, sizeof(servaddr))) < 0) {
printf("sendto failed, ret=%d\n", n);
}
}
void send_ul_ind(uint32_t tti_)
{
basic_vnf_api::ul_ind_msg_t ul_ind = {};
ul_ind.header.type = basic_vnf_api::UL_IND;
ul_ind.header.msg_len = sizeof(ul_ind) - sizeof(basic_vnf_api::msg_header_t);
ul_ind.tti = tti_;
ul_ind.t1 = 0;
ul_ind.pdus.type = basic_vnf_api::PUSCH;
ul_ind.pdus.length = tb_len > 0 ? tb_len : rand_dist(rand_gen);
int n = 0;
if ((n = sendto(sockfd, &ul_ind, sizeof(ul_ind), 0, (struct sockaddr*)&servaddr, sizeof(servaddr))) < 0) {
printf("sendto failed, ret=%d\n", n);
}
}
std::unique_ptr<std::thread> tx_thread, rx_thread;
std::string tx_thread_name = "TX_PNF", rx_thread_name = "RX_PNF";
bool running = false;
srslog::basic_logger& logger = srslog::fetch_basic_logger("PNF", false);
std::mutex mutex;
std::atomic<std::uint32_t> tti;
std::chrono::steady_clock::time_point tti_start_time;
std::string type;
std::string vnf_addr;
uint16_t vnf_port = 3333;
uint32_t sf_interval_us = 1000;
int32_t num_sf = -1;
uint32_t tb_len = 100;
pnf_metrics_t metrics = {};
int sockfd = 0;
struct sockaddr_in servaddr = {};
// For random number generation
std::mt19937 rand_gen;
std::uniform_int_distribution<uint16_t> rand_dist;
// two policies possible: dummy packets generated by the PNF class, or bridge between UE and gNB PNFs with TBs
// entering/exiting each PNF via the rf_in_queue/rf_out_queue.
srsran::block_queue<srsran::unique_byte_buffer_t>* rf_out_queue = nullptr;
srsran::block_queue<srsran::unique_byte_buffer_t> rf_in_queue;
enum data_policy_t { self_gen, bridge } policy = self_gen;
};
} // namespace srsran
#endif // SRSRAN_BASIC_PNF_H

@ -1,90 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN 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.
*
* srsRAN 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 SRSRAN_BASIC_VNF_H
#define SRSRAN_BASIC_VNF_H
#include "basic_vnf_api.h"
#include "common.h"
#include "srsran/common/threads.h"
#include "srsran/interfaces/gnb_interfaces.h"
#include "srsran/interfaces/ue_nr_interfaces.h"
#include "srsran/srslog/srslog.h"
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <iostream>
#include <netinet/in.h>
#include <random>
#include <strings.h>
#include <sys/socket.h>
#include <thread>
#include <unistd.h>
namespace srsran {
class srsran_basic_vnf : public thread
{
public:
srsran_basic_vnf(const vnf_args_t& args_, stack_interface_phy_nr* stack_);
~srsran_basic_vnf();
bool stop();
int dl_config_request(const srsenb::phy_interface_stack_nr::dl_config_request_t& request);
int tx_request(const srsenb::phy_interface_stack_nr::tx_request_t& request);
int tx_request(const srsue::phy_interface_stack_nr::tx_request_t& request);
private:
void run_thread();
// handlers
int handle_msg(const uint8_t* buffer, const uint32_t len);
int handle_sf_ind(basic_vnf_api::sf_ind_msg_t* msg);
int handle_dl_ind(basic_vnf_api::dl_ind_msg_t* msg);
int handle_ul_ind(basic_vnf_api::ul_ind_msg_t* msg);
int handle_rx_data_ind(basic_vnf_api::rx_data_ind_msg_t* msg);
// senders
int send_dl_config_request();
// helpers
uint32_t calc_full_msg_len(const basic_vnf_api::tx_request_msg_t& msg);
srslog::basic_logger& logger = srslog::fetch_basic_logger("VNF", false);
srsenb::stack_interface_phy_nr* m_gnb_stack = nullptr;
srsue::stack_interface_phy_nr* m_ue_stack = nullptr;
std::unique_ptr<basic_vnf_api::tx_request_msg_t> m_tx_req_msg;
bool running = false;
vnf_args_t m_args = {};
int sockfd = 0;
struct sockaddr_in servaddr = {}, client_addr = {};
uint32_t last_sf_indication_time = 0;
};
} // namespace srsran
#endif // SRSRAN_BASIC_VNF_H

@ -1,168 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN 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.
*
* srsRAN 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 SRSRAN_BASIC_VNF_API_H
#define SRSRAN_BASIC_VNF_API_H
#include <thread>
namespace basic_vnf_api {
// PNF (the PHY) VNF (the L2/L3)
// | |
// | |
// | - |
// | \ sf_ind_msg_t
// | \ |
// | \ |
// | \ |
// | \ |
// | \ |
// | \|
// | |
// | | DL_CONFIG.request
// | /|
// | / |
// | / |
// | / |
// | / |
// | / dl_conf_msg_t
// | / |
// |/ | TX.request
// | /|
// | / |
// | / |
// | / |
// | / |
// | / tx_request_msg_t
// | / |
// |/ |
// | |
// Primitive API messages for basic testing basic VNF/PNF interaction
enum msg_type_t {
SF_IND, ///< To signal start of new subframe (later slot) for both UE and gNB
DL_CONFIG, ///< To configure the DL for gNB
TX_REQUEST, ///< For DL data for gNB
RX_DATA_IND, ///< For UL Data for gNB
DL_IND, ///< For the UE for DL data
UL_IND, ///< For the UE for UL Data
MSG_TYPE_NITEMS
};
static const char* msg_type_text[MSG_TYPE_NITEMS] =
{"SF Indication", "DL_CONFIG.Request", "TX.Request", "RX_Data.indication", "DL_Indication", "UL_Indication"};
enum pdu_type_t { MAC_PBCH, PHY_PBCH, PDCCH, PDSCH, PUSCH };
struct msg_header_t {
msg_type_t type;
uint32_t msg_len;
};
struct sf_ind_msg_t {
msg_header_t header;
uint32_t t1; // Timestamp taken at PNF
uint32_t tti; // TTI of requested subframe
uint32_t tb_len; // Length of the TB
};
#define MAX_TB_LEN (16 * 1024)
#define MAX_PDU_SIZE (16 * 1024)
#define MAX_NUM_PDUS (1)
struct phy_pbch_pdu_t {
uint16_t phy_cell_id; // 0 - 1007
uint8_t ss_block_index; // 0-63
uint8_t ssb_sc_offset; // 0-15
uint8_t dmrs_pos; // 0-1
uint8_t pdcch_config; // 0-255
};
struct dl_conf_msg_t {
msg_header_t header;
uint32_t t1; // Replayed timestamp
uint32_t t2; // Timestamp taken at VNF
uint32_t tti; // TTI
uint16_t beam_id; // tx beam id for the slot
};
struct tx_request_pdu_t {
uint16_t length;
uint16_t index; // index indicated in dl_config
pdu_type_t type; // physical chan of pdu/tb
uint8_t data[MAX_PDU_SIZE];
};
struct tx_request_msg_t {
msg_header_t header;
uint32_t tti; // TTI
uint32_t tb_len; // actual TB len
uint32_t nof_pdus;
tx_request_pdu_t pdus[MAX_NUM_PDUS];
};
struct rx_data_ind_pdu_t {
uint16_t length;
pdu_type_t type; // physical chan of pdu/tb
uint8_t data[MAX_PDU_SIZE];
};
struct rx_data_ind_msg_t {
msg_header_t header;
uint32_t t1; // Timestamp taken at PNF
uint32_t sfn; ///< SFN (0-1023)
uint32_t slot; ///< Slot (0-319)
uint32_t tb_len; ///< actual TB len
uint32_t nof_pdus; //
rx_data_ind_pdu_t pdus[MAX_NUM_PDUS];
};
// UE specific messages
struct dl_ind_pdu_t {
pdu_type_t type; // physical chan of pdu/tb
uint16_t length;
uint8_t data[MAX_PDU_SIZE];
};
struct dl_ind_msg_t {
msg_header_t header;
uint32_t t1; // Timestamp taken at PNF
uint32_t tti; // tti or slot?
uint32_t nof_pdus;
dl_ind_pdu_t pdus[MAX_NUM_PDUS];
};
///< Messages for UL (only one PDU)
struct ul_ind_pdu_t {
pdu_type_t type; // physical chan of pdu/tb
uint16_t length;
};
struct ul_ind_msg_t {
msg_header_t header;
uint32_t t1; // Timestamp taken at PNF
uint32_t tti; // tti or slot?
uint32_t rnti; ///< RNTI of this grant
ul_ind_pdu_t pdus;
};
} // namespace basic_vnf_api
#endif // SRSRAN_BASIC_VNF_API_H

@ -40,7 +40,7 @@ extern "C" {
// static vars required by signal handling
static srslog::sink* log_sink = nullptr;
static bool running = true;
static std::atomic<bool> running = {true};
static void srsran_signal_handler(int signal)
{

@ -34,6 +34,7 @@ struct mac_args_t {
int nr_tb_size = -1;
uint32_t nof_prealloc_ues; ///< Number of UE resources to pre-allocate at eNB startup
uint32_t max_nof_kos;
int rlf_min_ul_snr_estim;
};
/* Interface PHY -> MAC */

@ -171,42 +171,31 @@ public:
virtual void notify_pdcp_integrity_error(uint16_t rnti, uint32_t lcid) = 0;
};
class phy_interface_stack_nr
class phy_interface_rrc_nr
{
public:
const static int MAX_DL_GRANTS = 4;
typedef struct {
// TODO: include NR related fields
} dl_sched_grant_t;
/**
* @brief Describes physical layer configuration common among all the UEs for a given cell
*/
struct common_cfg_t {
srsran_carrier_nr_t carrier;
srsran_pdcch_cfg_nr_t pdcch;
srsran_prach_cfg_t prach;
};
typedef struct {
bool mib_present;
} bch_sched_t;
virtual int set_common_cfg(const common_cfg_t& common_cfg) = 0;
};
typedef struct {
uint32_t tti;
uint32_t nof_grants;
dl_sched_grant_t pdsch[MAX_DL_GRANTS];
int beam_id;
} dl_config_request_t;
typedef struct {
bch_sched_t pbch;
uint16_t length;
uint16_t index; // index indicated in dl_config
uint8_t* data[SRSRAN_MAX_TB]; // always a pointer in our case
} tx_request_pdu_t;
typedef struct {
uint32_t tti;
uint32_t tb_len;
uint32_t nof_pdus;
tx_request_pdu_t pdus[MAX_DL_GRANTS];
} tx_request_t;
class phy_interface_mac_nr
{
public:
// TBD
};
virtual int dl_config_request(const dl_config_request_t& request) = 0;
virtual int tx_request(const tx_request_t& request) = 0;
class phy_interface_stack_nr : public phy_interface_rrc_nr, public phy_interface_mac_nr
{
public:
// TBD
};
class stack_interface_mac
@ -280,11 +269,17 @@ public:
// ... add signal measurements here
};
struct rach_info_t {
uint32_t preamble;
uint32_t time_adv;
};
virtual int slot_indication(const srsran_slot_cfg_t& slot_cfg) = 0;
virtual int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) = 0;
virtual int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) = 0;
virtual int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) = 0;
virtual int pusch_info(const srsran_slot_cfg_t& slot_cfg, const pusch_info_t& pusch_info) = 0;
virtual void rach_detected(const rach_info_t& rach_info) = 0;
};
class stack_interface_phy_nr : public mac_interface_phy_nr, public srsran::stack_interface_phy_nr

@ -75,6 +75,7 @@ public:
int init_ul_snr_value = 5;
int init_dl_cqi = 5;
float max_sib_coderate = 0.8;
int pdcch_cqi_offset = 0;
};
struct cell_cfg_t {

@ -48,6 +48,17 @@ public:
virtual bool connection_request_completed(bool outcome) = 0;
};
class nas_5g_interface_rrc_nr
{
public:
};
class nas_5g_interface_procedures
{
public:
virtual int send_registration_request() = 0;
};
} // namespace srsue
#endif // SRSRAN_UE_NAS_INTERFACES_H

@ -184,6 +184,7 @@ struct phy_args_nr_t {
srsran_ue_ul_nr_args_t ul = {};
std::set<uint32_t> fixed_sr = {1};
uint32_t fix_wideband_cqi = 15; // Set to a non-zero value for fixing the wide-band CQI report
bool store_pdsch_ko = false;
phy_args_nr_t()
{

@ -95,6 +95,8 @@ struct phy_args_t {
float force_ul_amplitude = 0.0f;
bool detect_cp = false;
bool nr_store_pdsch_ko = false;
float in_sync_rsrp_dbm_th = -130.0f;
float in_sync_snr_db_th = 1.0f;
uint32_t nof_in_sync_events = 10;

@ -122,6 +122,10 @@ public:
virtual bool is_config_pending() = 0;
};
class rrc_nr_interface_nas_5g
{
public:
};
} // namespace srsue
#endif // SRSRAN_UE_RRC_INTERFACES_H

@ -156,8 +156,14 @@ typedef struct SRSRAN_API {
uint32_t pid; ///< HARQ process number
uint32_t dai; ///< Downlink assignment index
uint32_t tpc; ///< TPC command for scheduled PUCCH
uint32_t pucch_resource; ///< PUCCH resource indicator
uint32_t pucch_resource; ///< PUCCH resource indicator for HARQ feedback
///< @note PUCCH resource is selected from PUCCH-ResourceSet if available, otherwise the UE
///< shall pick a pucch-ResourceCommon from Table 9.2.1-1.
uint32_t harq_feedback; ///< PDSCH-to-HARQ_feedback timing indicator
///< @note harq_feedback for format 1_0 indicates the delay between the PDSCH reception and
///< the UL transmission timing
///< @note harq_feedback for format 1_1 is index of the delay indicated in DL data to UL ACK
///< dedicated configuration table
// P-RNTI specific fields
uint32_t smi; ///< Short Messages Indicator

@ -49,7 +49,6 @@ typedef struct {
uint32_t n_cce_0; ///< index of a first CCE for the PDCCH reception
uint32_t N_cce; ///< number of CCEs in a CORESET of a PDCCH reception with DCI format 1_0 or 1_1
uint32_t sr_resource_id; ///< Scheduling request resource identifier, only valid if positive SR
bool sr_positive_present; ///< Set to true if there is at least one positive SR
} srsran_uci_nr_pucch_cfg_t;
/**
@ -79,6 +78,7 @@ typedef struct SRSRAN_API {
/// Common Parameters
srsran_harq_ack_cfg_t ack; ///< HARQ-ACK configuration
uint32_t o_sr; ///< Number of SR bits
bool sr_positive_present; ///< Set to true if there is at least one positive SR
srsran_csi_report_cfg_t csi[SRSRAN_CSI_MAX_NOF_REPORT]; ///< CSI report configuration
uint32_t nof_csi; ///< Number of CSI reports
union {

@ -99,6 +99,7 @@ private:
std::vector<srsran_rf_info_t> rf_info = {};
std::vector<int32_t> rx_offset_n = {};
rf_metrics_t rf_metrics = {};
std::mutex metrics_mutex;
srslog::basic_logger& logger = srslog::fetch_basic_logger("RF", false);
phy_interface_radio* phy = nullptr;
cf_t* zeros = nullptr;

@ -23,6 +23,7 @@
#define SRSLOG_SHARED_TYPES_H
#include <functional>
#include <string>
namespace srslog {
@ -30,8 +31,7 @@ namespace srslog {
using error_handler = std::function<void(const std::string&)>;
/// Backend priority levels.
enum class backend_priority
{
enum class backend_priority {
/// Default priority of the operating system.
normal,
/// Thread will be given a high priority.
@ -40,6 +40,18 @@ enum class backend_priority
very_high
};
/// syslog log local types
enum class syslog_local_type {
local0,
local1,
local2,
local3,
local4,
local5,
local6,
local7,
};
} // namespace srslog
#endif // SRSLOG_SHARED_TYPES_H

@ -193,6 +193,14 @@ sink& fetch_file_sink(const std::string& path,
size_t max_size = 0,
std::unique_ptr<log_formatter> f = get_default_log_formatter());
/// Returns an instance of a sink that writes into syslog
/// preamble: The string prepended to every message, If ident is "", the program name is used.
/// log_local: custom unused facilities that syslog provides which can be used by the user
/// NOTE: Any '#' characters in the path will get removed.
sink& fetch_syslog_sink(const std::string& preamble_ = "",
syslog_local_type log_local_ = syslog_local_type::local0,
std::unique_ptr<log_formatter> f = get_default_log_formatter());
/// Installs a custom user defined sink in the framework getting associated to
/// the specified id. Returns true on success, otherwise false.
/// WARNING: This function is an advanced feature and users should really know

@ -441,7 +441,7 @@ SRSASN_CODE capability_5gmm_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(cag, 1));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 1 || length > 13) {
asn1::log_error("Encoding Failed (5GMM capability): Packed length (%d) is not in range of min: 1 and max 13 bytes",
@ -541,7 +541,7 @@ SRSASN_CODE ue_security_capability_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(eia7_supported, 1));
}
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 2 || length > 8) {
asn1::log_error(
@ -617,7 +617,7 @@ SRSASN_CODE nssai_t::pack(asn1::bit_ref& bref)
}
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 2 || length > 144) {
asn1::log_error("Encoding Failed (NSSAI): Packed length (%d) is not in range of min: 2 and max 144 bytes", length);
@ -742,7 +742,7 @@ SRSASN_CODE s1_ue_network_capability_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(racs_supported, 1));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 2 || length > 13) {
asn1::log_error(
@ -887,7 +887,7 @@ SRSASN_CODE uplink_data_status_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(psi_8, 1));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 2 || length > 32) {
asn1::log_error(
@ -957,7 +957,7 @@ SRSASN_CODE pdu_session_status_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(psi_8, 1));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 2 || length > 32) {
asn1::log_error(
@ -1037,7 +1037,7 @@ SRSASN_CODE ue_status_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(s1_mode_reg, 1));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 1) {
asn1::log_error("Encoding Failed (UE status): Packed length (%d) does not equal expected length 1", length);
@ -1089,7 +1089,7 @@ SRSASN_CODE allowed_pdu_session_status_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(psi_8, 1));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 2 || length > 32) {
asn1::log_error(
@ -1147,7 +1147,7 @@ SRSASN_CODE ue_usage_setting_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(ue_usage_setting.pack(bref));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 1) {
asn1::log_error("Encoding Failed (UE usage setting): Packed length (%d) does not equal expected length 1", length);
@ -1185,7 +1185,7 @@ SRSASN_CODE drx_parameters_5gs_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(drx_value.pack(bref));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 1) {
asn1::log_error("Encoding Failed (5GS DRX parameters): Packed length (%d) does not equal expected length 1",
@ -1221,7 +1221,7 @@ SRSASN_CODE eps_nas_message_container_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack_bytes(eps_nas_message_container.data(), eps_nas_message_container.size()));
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
HANDLE_CODE(bref_length.pack(length, 16));
return SRSASN_SUCCESS;
@ -1250,7 +1250,7 @@ SRSASN_CODE ladn_indication_t::pack(asn1::bit_ref& bref)
}
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
// MIN 0 not check because auf uint underflow
if (length > 808) {
@ -1306,7 +1306,7 @@ SRSASN_CODE payload_container_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack_bytes(payload_container_contents.data(), payload_container_contents.size()));
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
// MAX 65535 not check because auf uint overflow
if (length < 1) {
@ -1370,7 +1370,7 @@ SRSASN_CODE update_type_5gs_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(sms_requested.pack(bref));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
HANDLE_CODE(bref_length.pack(length, 8));
return SRSASN_SUCCESS;
@ -1400,7 +1400,7 @@ SRSASN_CODE mobile_station_classmark_2_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 3) {
asn1::log_error("Encoding Failed (Mobile station classmark 2): Packed length (%d) does not equal expected length 3",
@ -1438,7 +1438,7 @@ SRSASN_CODE supported_codec_list_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 3) {
asn1::log_error("Encoding Failed (Supported codec list): Packed length (%d) is not in range of min: 3 bytes",
@ -1474,7 +1474,7 @@ SRSASN_CODE message_container_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack_bytes(nas_message_container.data(), nas_message_container.size()));
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
if (length < 1 || length > 65532) {
asn1::log_error(
@ -1527,7 +1527,7 @@ SRSASN_CODE eps_bearer_context_status_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(ebi_8, 1));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 2) {
asn1::log_error("Encoding Failed (EPS bearer context status): Packed length (%d) does not equal expected length 2",
@ -1579,7 +1579,7 @@ SRSASN_CODE extended_drx_parameters_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(e_drx_value.pack(bref));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 1) {
asn1::log_error("Encoding Failed (Extended DRX parameters): Packed length (%d) does not equal expected length 1",
@ -1616,7 +1616,7 @@ SRSASN_CODE gprs_timer_3_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(timer_value, 5));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 1) {
asn1::log_error("Encoding Failed (GPRS timer 3): Packed length (%d) does not equal expected length 1", length);
@ -1650,7 +1650,7 @@ SRSASN_CODE ue_radio_capability_id_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack_bytes(ue_radio_capability_id.data(), ue_radio_capability_id.size()));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
HANDLE_CODE(bref_length.pack(length, 8));
return SRSASN_SUCCESS;
@ -1677,7 +1677,7 @@ SRSASN_CODE mapped_nssai_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 2 || length > 40) {
asn1::log_error("Encoding Failed (Mapped NSSAI): Packed length (%d) is not in range of min: 2 and max 40 bytes",
@ -1716,7 +1716,7 @@ SRSASN_CODE additional_information_requested_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(cipher_key, 1));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
HANDLE_CODE(bref_length.pack(length, 8));
return SRSASN_SUCCESS;
@ -1743,7 +1743,7 @@ SRSASN_CODE wus_assistance_information_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 1) {
asn1::log_error("Encoding Failed (WUS assistance information): Packed length (%d) is not in range of min: 1 bytes",
@ -1803,7 +1803,7 @@ SRSASN_CODE nb_n1_mode_drx_parameters_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(nb_n1_mode_drx_value.pack(bref));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 1) {
asn1::log_error("Encoding Failed (NB-N1 mode DRX parameters): Packed length (%d) does not equal expected length 1",
@ -1846,7 +1846,7 @@ SRSASN_CODE registration_result_5gs_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(registration_result.pack(bref));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 1) {
asn1::log_error("Encoding Failed (5GS registration result): Packed length (%d) does not equal expected length 1",
@ -1886,7 +1886,7 @@ SRSASN_CODE plmn_list_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
HANDLE_CODE(bref_length.pack(length, 8));
return SRSASN_SUCCESS;
@ -1913,7 +1913,7 @@ SRSASN_CODE tracking_area_identity_list_5gs_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 7) {
asn1::log_error(
@ -1952,7 +1952,7 @@ SRSASN_CODE rejected_nssai_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
HANDLE_CODE(bref_length.pack(length, 8));
return SRSASN_SUCCESS;
@ -1979,7 +1979,7 @@ SRSASN_CODE network_feature_support_5gs_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 1 || length > 3) {
asn1::log_error(
@ -2033,7 +2033,7 @@ SRSASN_CODE pdu_session_reactivation_result_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(psi_8, 1));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 2 || length > 32) {
asn1::log_error("Encoding Failed (PDU session reactivation result): Packed length (%d) is not in range of min: 2 "
@ -2092,7 +2092,7 @@ SRSASN_CODE pdu_session_reactivation_result_error_cause_t::pack(asn1::bit_ref& b
// TODO proper packing
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
if (length < 2 || length > 512) {
asn1::log_error("Encoding Failed (PDU session reactivation result error cause): Packed length (%d) is not in range "
@ -2132,7 +2132,7 @@ SRSASN_CODE ladn_information_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
// MIN 0 not check because auf uint underflow
if (length > 1712) {
@ -2170,7 +2170,7 @@ SRSASN_CODE service_area_list_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
HANDLE_CODE(bref_length.pack(length, 8));
return SRSASN_SUCCESS;
@ -2197,7 +2197,7 @@ SRSASN_CODE gprs_timer_2_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(timer_value, 8));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 1) {
asn1::log_error("Encoding Failed (GPRS timer 2): Packed length (%d) does not equal expected length 1", length);
@ -2231,7 +2231,7 @@ SRSASN_CODE emergency_number_list_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 3 || length > 48) {
asn1::log_error(
@ -2270,7 +2270,7 @@ SRSASN_CODE extended_emergency_number_list_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
// MAX 65535 not check because auf uint overflow
if (length < 4) {
@ -2310,7 +2310,7 @@ SRSASN_CODE sor_transparent_container_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
if (length < 17) {
asn1::log_error("Encoding Failed (SOR transparent container): Packed length (%d) is not in range of min: 17 bytes",
@ -2347,7 +2347,7 @@ SRSASN_CODE eap_message_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack_bytes(eap_message.data(), eap_message.size()));
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
if (length < 4 || length > 1500) {
asn1::log_error("Encoding Failed (EAP message): Packed length (%d) is not in range of min: 4 and max 1500 bytes",
@ -2403,7 +2403,7 @@ SRSASN_CODE operator_defined_access_category_definitions_t::pack(asn1::bit_ref&
// TODO proper packing
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
HANDLE_CODE(bref_length.pack(length, 16));
return SRSASN_SUCCESS;
@ -2470,7 +2470,7 @@ SRSASN_CODE ciphering_key_data_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
if (length < 31 || length > 2672) {
asn1::log_error(
@ -2509,7 +2509,7 @@ SRSASN_CODE cag_information_list_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
HANDLE_CODE(bref_length.pack(length, 16));
return SRSASN_SUCCESS;
@ -2537,7 +2537,7 @@ SRSASN_CODE truncated_5g_s_tmsi_configuration_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(truncated_amf__pointer_value, 4));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 1) {
asn1::log_error(
@ -2665,7 +2665,7 @@ SRSASN_CODE network_name_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
HANDLE_CODE(bref_length.pack(length, 8));
return SRSASN_SUCCESS;
@ -2734,7 +2734,7 @@ SRSASN_CODE daylight_saving_time_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(value.pack(bref));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 1) {
asn1::log_error("Encoding Failed (Daylight saving time): Packed length (%d) does not equal expected length 1",
@ -2808,7 +2808,7 @@ SRSASN_CODE abba_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack_bytes(abba_contents.data(), abba_contents.size()));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 2) {
asn1::log_error("Encoding Failed (ABBA): Packed length (%d) is not in range of min: 2 bytes", length);
@ -2858,7 +2858,7 @@ SRSASN_CODE authentication_parameter_autn_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack_bytes(autn.data(), autn.size()));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 16) {
asn1::log_error(
@ -2895,7 +2895,7 @@ SRSASN_CODE authentication_response_parameter_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack_bytes(res.data(), res.size()));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 16) {
asn1::log_error(
@ -2932,7 +2932,7 @@ SRSASN_CODE authentication_failure_parameter_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack_bytes(auth_failure.data(), auth_failure.size()));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 14) {
asn1::log_error(
@ -3058,7 +3058,7 @@ SRSASN_CODE additional_5g_security_information_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(hdp, 1));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 1) {
asn1::log_error(
@ -3141,7 +3141,7 @@ SRSASN_CODE s1_ue_security_capability_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(gea7, 1));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 2 || length > 5) {
asn1::log_error(
@ -3305,7 +3305,7 @@ SRSASN_CODE s_nssai_t::pack(asn1::bit_ref& bref)
}
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 1 || length > 8) {
asn1::log_error("Encoding Failed (S-NSSAI): Packed length (%d) is not in range of min: 1 and max 8 bytes", length);
@ -3354,7 +3354,7 @@ SRSASN_CODE dnn_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack_bytes(dnn_value.data(), dnn_value.size()));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 1 || length > 100) {
asn1::log_error("Encoding Failed (DNN): Packed length (%d) is not in range of min: 1 and max 100 bytes", length);
@ -3388,7 +3388,7 @@ SRSASN_CODE additional_information_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack_bytes(additional_information_value.data(), additional_information_value.size()));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 1) {
asn1::log_error("Encoding Failed (Additional information): Packed length (%d) is not in range of min: 1 bytes",
@ -3518,7 +3518,7 @@ SRSASN_CODE capability_5gsm_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 1 || length > 13) {
asn1::log_error("Encoding Failed (5GSM capability): Packed length (%d) is not in range of min: 1 and max 13 bytes",
@ -3596,7 +3596,7 @@ SRSASN_CODE sm_pdu_dn_request_container_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack_bytes(dn_specific_identity.data(), dn_specific_identity.size()));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 1 || length > 253) {
asn1::log_error(
@ -3635,7 +3635,7 @@ SRSASN_CODE extended_protocol_configuration_options_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
// MAX 65535 not check because auf uint overflow
if (length < 1) {
@ -3677,7 +3677,7 @@ SRSASN_CODE ip_header_compression_configuration_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
// MAX 255 not check because auf uint overflow
if (length < 3) {
@ -3718,7 +3718,7 @@ SRSASN_CODE ds_tt__ethernet_port_mac_address_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack_bytes(ds_tt__ethernet_port_mac_address_contents.data(), 6));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 6) {
asn1::log_error(
@ -3755,7 +3755,7 @@ SRSASN_CODE ue_ds_tt_residence_time_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack_bytes(ue_ds_tt_residence_time_contents.data(), 8));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 8) {
asn1::log_error("Encoding Failed (UE-DS-TT residence time): Packed length (%d) does not equal expected length 8",
@ -3790,7 +3790,7 @@ SRSASN_CODE port_management_information_container_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(
bref.pack_bytes(port_management_information_container.data(), port_management_information_container.size()));
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
// MAX 65535 not check because auf uint overflow
if (length < 1) {
@ -3832,7 +3832,7 @@ SRSASN_CODE ethernet_header_compression_configuration_t::pack(asn1::bit_ref& bre
HANDLE_CODE(cid__length.pack(bref));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 1) {
asn1::log_error("Encoding Failed (Ethernet header compression configuration): Packed length (%d) does not equal "
@ -3888,7 +3888,7 @@ SRSASN_CODE pdu_address_t::pack(asn1::bit_ref& bref)
}
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 5 || length > 29) {
asn1::log_error("Encoding Failed (PDU address): Packed length (%d) is not in range of min: 5 and max 29 bytes",
@ -3947,7 +3947,7 @@ SRSASN_CODE qo_s_rules_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.advance_bits(16));
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
// MAX 65535 not check because auf uint overflow
if (length < 4) {
@ -3986,7 +3986,7 @@ SRSASN_CODE session_ambr_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(session_ambr_for_uplink, 16));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 6) {
asn1::log_error("Encoding Failed (Session-AMBR): Packed length (%d) does not equal expected length 6", length);
@ -4077,7 +4077,7 @@ SRSASN_CODE mapped_eps_bearer_contexts_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
// MAX 65535 not check because auf uint overflow
if (length < 4) {
@ -4117,7 +4117,7 @@ SRSASN_CODE qo_s_flow_descriptions_t::pack(asn1::bit_ref& bref)
// TODO proper packing
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
// MAX 65535 not check because auf uint overflow
if (length < 3) {
@ -4158,7 +4158,7 @@ SRSASN_CODE network_feature_support_5gsm_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(ept_s1.pack(bref));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length < 1 || length > 13) {
asn1::log_error(
@ -4201,7 +4201,7 @@ SRSASN_CODE serving_plmn_rate_control_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(serving_plmn_rate_control_value, 16));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 2) {
asn1::log_error("Encoding Failed (Serving PLMN rate control): Packed length (%d) does not equal expected length 2",
@ -4236,7 +4236,7 @@ SRSASN_CODE atsss_container_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack_bytes(nas_message_container.data(), nas_message_container.size()));
bref.align_bytes_zero();
uint16_t length = (uint16_t)(ceilf(bref.distance(bref_length) / 8) - 2);
uint16_t length = (uint16_t)(ceilf((float)bref.distance(bref_length) / 8) - 2);
// MIN 0 not check because auf uint underflow
// MAX 65535 not check because auf uint overflow
@ -4337,7 +4337,7 @@ SRSASN_CODE re_attempt_indicator_t::pack(asn1::bit_ref& bref)
HANDLE_CODE(bref.pack(ratc, 1));
bref.align_bytes_zero();
uint8_t length = (uint8_t)(ceilf(bref.distance(bref_length) / 8) - 1);
uint8_t length = (uint8_t)(ceilf((float)bref.distance(bref_length) / 8) - 1);
if (length != 1) {
asn1::log_error("Encoding Failed (Re-attempt indicator): Packed length (%d) does not equal expected length 1",

@ -141,7 +141,9 @@ srsran::rlc_config_t make_rlc_config_t(const asn1::rrc::rlc_cfg_c& asn1_type)
rlc_cfg.rlc_mode = rlc_mode_t::am;
rlc_cfg.am.t_poll_retx = asn1_type.am().ul_am_rlc.t_poll_retx.to_number();
rlc_cfg.am.poll_pdu = asn1_type.am().ul_am_rlc.poll_pdu.to_number();
rlc_cfg.am.poll_byte = asn1_type.am().ul_am_rlc.poll_byte.to_number() * 1000; // KB
rlc_cfg.am.poll_byte = asn1_type.am().ul_am_rlc.poll_byte.to_number() < 0
? -1
: asn1_type.am().ul_am_rlc.poll_byte.to_number() * 1000; // KB
rlc_cfg.am.max_retx_thresh = asn1_type.am().ul_am_rlc.max_retx_thres.to_number();
rlc_cfg.am.t_reordering = asn1_type.am().dl_am_rlc.t_reordering.to_number();
rlc_cfg.am.t_status_prohibit = asn1_type.am().dl_am_rlc.t_status_prohibit.to_number();

@ -46,8 +46,7 @@ set(SOURCES arch_select.cc
time_prof.cc
version.c
zuc.cc
s3g.cc
basic_vnf.cc)
s3g.cc)
# Avoid warnings caused by libmbedtls about deprecated functions
set_source_files_properties(security.cc PROPERTIES COMPILE_FLAGS -Wno-deprecated-declarations)

@ -1,408 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN 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.
*
* srsRAN 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 "srsran/common/basic_vnf.h"
#include "srsran/common/buffer_pool.h"
#include "srsran/interfaces/ue_nr_interfaces.h"
#include <algorithm>
#include <chrono>
#include <poll.h>
#define RAND_SEED (12314)
#define RX_TIMEOUT_MS (1000)
namespace srsran {
struct srsran_pnf_info_t {
// TODO: fill when needed
};
struct srsran_vnf_info_t {};
srsran_basic_vnf::srsran_basic_vnf(const vnf_args_t& args_, stack_interface_phy_nr* stack_) :
m_args(args_), thread("BASIC_VNF_P7"), m_tx_req_msg(new basic_vnf_api::tx_request_msg_t)
{
logger.set_level(srslog::str_to_basic_level(m_args.log_level));
logger.set_hex_dump_max_size(m_args.log_hex_limit);
if (m_args.type == "gnb" || m_args.type == "ue") {
if (m_args.type == "gnb") {
m_gnb_stack = (srsenb::stack_interface_phy_nr*)stack_;
} else {
m_ue_stack = (srsue::stack_interface_phy_nr*)stack_;
}
logger.info("Initializing VNF for gNB");
start();
} else {
logger.error("Unknown VNF type. Exiting.");
}
}
srsran_basic_vnf::~srsran_basic_vnf()
{
stop();
}
void srsran_basic_vnf::run_thread()
{
// Bind to UDP socket
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
return;
}
// Make sockets reusable
int enable = 1;
#if defined(SO_REUSEADDR)
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
perror("setsockopt(SO_REUSEADDR) failed");
}
#endif
#if defined(SO_REUSEPORT)
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) {
perror("setsockopt(SO_REUSEPORT) failed");
}
#endif
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(m_args.bind_port);
if (bind(sockfd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in))) {
perror("bind");
return;
}
struct pollfd fd;
fd.fd = sockfd;
fd.events = POLLIN;
const uint32_t max_basic_api_pdu = sizeof(basic_vnf_api::dl_ind_msg_t) + 32; // larger than biggest message
std::unique_ptr<std::array<uint8_t, max_basic_api_pdu> > rx_buffer =
std::unique_ptr<std::array<uint8_t, max_basic_api_pdu> >(new std::array<uint8_t, max_basic_api_pdu>);
running = true;
logger.info("Started VNF handler listening on %s:%d", m_args.bind_addr.c_str(), m_args.bind_port);
while (running) {
int ret = poll(&fd, 1, RX_TIMEOUT_MS);
switch (ret) {
case -1:
printf("Error occured.\n");
break;
case 0:
// Timeout
break;
default:
socklen_t len = sizeof(client_addr);
ret = recvfrom(sockfd, rx_buffer->data(), rx_buffer->size(), MSG_WAITALL, (struct sockaddr*)&client_addr, &len);
handle_msg(rx_buffer->data(), ret);
break;
}
}
logger.info("VNF thread stopped");
}
int srsran_basic_vnf::handle_msg(const uint8_t* buffer, const uint32_t len)
{
basic_vnf_api::msg_header_t* header = (basic_vnf_api::msg_header_t*)buffer;
logger.info("Received %s (%d B)", basic_vnf_api::msg_type_text[header->type], len);
switch (header->type) {
case basic_vnf_api::SF_IND:
handle_sf_ind((basic_vnf_api::sf_ind_msg_t*)header);
break;
case basic_vnf_api::DL_CONFIG:
printf("Error: %s not handled by VNF\n", basic_vnf_api::msg_type_text[header->type]);
break;
case basic_vnf_api::DL_IND:
handle_dl_ind((basic_vnf_api::dl_ind_msg_t*)header);
break;
case basic_vnf_api::UL_IND:
handle_ul_ind((basic_vnf_api::ul_ind_msg_t*)header);
break;
case basic_vnf_api::RX_DATA_IND:
handle_rx_data_ind((basic_vnf_api::rx_data_ind_msg_t*)header);
break;
default:
printf("Unknown msg type.\n");
break;
}
return 0;
}
int srsran_basic_vnf::handle_sf_ind(basic_vnf_api::sf_ind_msg_t* msg)
{
int ret = SRSRAN_SUCCESS;
logger.info("Received %s for TTI=%d", basic_vnf_api::msg_type_text[msg->header.type], msg->tti);
// store Rx timestamp
last_sf_indication_time = msg->t1;
if (m_gnb_stack != nullptr) {
srsran_slot_cfg_t slot_cfg = {};
slot_cfg.idx = msg->tti;
m_gnb_stack->slot_indication(slot_cfg);
} else if (m_ue_stack != nullptr) {
m_ue_stack->sf_indication(msg->tti);
} else {
ret = SRSRAN_ERROR;
}
return ret;
}
int srsran_basic_vnf::handle_dl_ind(basic_vnf_api::dl_ind_msg_t* msg)
{
int ret = SRSRAN_ERROR;
logger.info("Received %s for TTI=%d", basic_vnf_api::msg_type_text[msg->header.type], msg->tti);
uint32_t cc_idx = 0;
// fill DL struct
srsue::stack_interface_phy_nr::mac_nr_grant_dl_t dl_grant = {};
dl_grant.tti = msg->tti;
if (msg->nof_pdus > SRSRAN_MAX_TB) {
logger.error("Too many TBs (%d > %d)", msg->nof_pdus, SRSRAN_MAX_TB);
goto exit;
}
for (uint32_t i = 0; i < msg->nof_pdus; ++i) {
srsue::stack_interface_phy_nr::tb_action_dl_result_t result = {};
result.payload = srsran::make_byte_buffer();
if (result.payload != nullptr && result.payload->get_tailroom() >= msg->pdus[i].length) {
result.ack = true;
memcpy(result.payload->msg, msg->pdus[i].data, msg->pdus[i].length);
result.payload->N_bytes = msg->pdus[i].length;
if (msg->pdus[i].type == basic_vnf_api::PDSCH) {
m_ue_stack->tb_decoded(cc_idx, dl_grant, std::move(result));
}
} else {
logger.error("TB too big to fit into buffer (%d)", msg->pdus[i].length);
return SRSRAN_ERROR;
}
}
ret = SRSRAN_SUCCESS;
exit:
return ret;
}
int srsran_basic_vnf::handle_ul_ind(basic_vnf_api::ul_ind_msg_t* msg)
{
logger.info("Received %s for TTI=%d", basic_vnf_api::msg_type_text[msg->header.type], msg->tti);
if (msg->pdus.type != basic_vnf_api::PUSCH) {
logger.error("Received UL indication for wrong PDU type");
return SRSRAN_ERROR;
}
uint32_t cc_idx = 0;
// fill DL struct
srsue::stack_interface_phy_nr::mac_nr_grant_ul_t ul_grant = {};
ul_grant.tti = msg->tti;
ul_grant.tbs = msg->pdus.length;
ul_grant.rnti = msg->rnti;
srsue::stack_interface_phy_nr::tb_action_ul_t ul_action = {};
m_ue_stack->new_grant_ul(cc_idx, ul_grant, &ul_action);
return SRSRAN_SUCCESS;
}
int srsran_basic_vnf::handle_rx_data_ind(basic_vnf_api::rx_data_ind_msg_t* msg)
{
logger.info("Received %s for TTI=%d", basic_vnf_api::msg_type_text[msg->header.type], msg->sfn);
if (msg->nof_pdus != 1 || msg->pdus[0].type != basic_vnf_api::PUSCH) {
logger.error("Received UL indication for wrong PDU type");
return SRSRAN_ERROR;
}
// fill struct
srsenb::stack_interface_phy_nr::rx_data_ind_t rx_data = {};
rx_data.tti = msg->sfn;
rx_data.tb = srsran::make_byte_buffer();
if (rx_data.tb->get_tailroom() >= msg->pdus[0].length) {
// copy actual data
memcpy(rx_data.tb->msg, msg->pdus[0].data, msg->pdus[0].length);
rx_data.tb->N_bytes = msg->pdus[0].length;
if (msg->pdus[0].type == basic_vnf_api::PUSCH) {
m_gnb_stack->rx_data_indication(rx_data);
}
}
return SRSRAN_SUCCESS;
}
int srsran_basic_vnf::dl_config_request(const srsenb::phy_interface_stack_nr::dl_config_request_t& request)
{
// Generate DL Config
basic_vnf_api::dl_conf_msg_t dl_conf = {};
dl_conf.header.type = basic_vnf_api::DL_CONFIG;
dl_conf.header.msg_len = sizeof(dl_conf) - sizeof(basic_vnf_api::msg_header_t);
dl_conf.t1 = last_sf_indication_time; // play back the time
dl_conf.t2 = 0xaa; // TODO: add timestamp
dl_conf.tti = request.tti;
dl_conf.beam_id = request.beam_id;
// Send entire struct
uint32_t len = sizeof(dl_conf);
// Send it to PNF
logger.info("Sending %s (%d B)", basic_vnf_api::msg_type_text[dl_conf.header.type], len);
int n = 0;
if ((n = sendto(sockfd, &dl_conf, len, MSG_CONFIRM, (struct sockaddr*)&client_addr, sizeof(client_addr))) < 0) {
logger.error("sendto failed, ret=%d", n);
}
return 0;
}
/// Tx request from UE, i.e. UL transmission
int srsran_basic_vnf::tx_request(const srsue::phy_interface_stack_nr::tx_request_t& request)
{
// Generate Tx request
m_tx_req_msg->header.type = basic_vnf_api::TX_REQUEST;
m_tx_req_msg->header.msg_len = 0; // set further down
m_tx_req_msg->tti = request.tti;
m_tx_req_msg->nof_pdus = 1;
m_tx_req_msg->pdus[0].index = 0;
m_tx_req_msg->pdus[0].type = basic_vnf_api::PUSCH;
m_tx_req_msg->pdus[0].length = request.tb_len;
if (request.tb_len <= MAX_PDU_SIZE) {
// copy data from TB0
memcpy(m_tx_req_msg->pdus[0].data, request.data, request.tb_len);
} else {
logger.error("Trying to send %d B PDU. Maximum size is %d B", request.tb_len, MAX_PDU_SIZE);
}
// calculate actual length of
uint32_t len = calc_full_msg_len(*m_tx_req_msg.get());
// update msg header length field
m_tx_req_msg->header.msg_len = len - sizeof(basic_vnf_api::msg_header_t);
// Send it to PNF
logger.info("Sending %s (%d B)", basic_vnf_api::msg_type_text[m_tx_req_msg->header.type], len);
int n = 0;
if ((n = sendto(sockfd, m_tx_req_msg.get(), len, MSG_CONFIRM, (struct sockaddr*)&client_addr, sizeof(client_addr))) <
0) {
logger.error("sendto failed, ret=%d", n);
}
return 0;
}
int srsran_basic_vnf::tx_request(const srsenb::phy_interface_stack_nr::tx_request_t& request)
{
if (request.nof_pdus > MAX_NUM_PDUS) {
logger.error("Trying to send %d PDUs but only %d supported", request.nof_pdus, MAX_NUM_PDUS);
return SRSRAN_ERROR;
}
if (request.nof_pdus == 0) {
return SRSRAN_SUCCESS;
}
// Generate Tx request
m_tx_req_msg->header.type = basic_vnf_api::TX_REQUEST;
m_tx_req_msg->header.msg_len = 0; // set further down
m_tx_req_msg->nof_pdus = request.nof_pdus;
m_tx_req_msg->tti = request.tti;
for (uint32_t i = 0; i < m_tx_req_msg->nof_pdus; ++i) {
if (request.pdus[i].length <= MAX_PDU_SIZE) {
m_tx_req_msg->pdus[i].index = i;
m_tx_req_msg->pdus[i].type = request.pdus[i].pbch.mib_present ? basic_vnf_api::MAC_PBCH : basic_vnf_api::PDSCH;
m_tx_req_msg->pdus[i].length = request.pdus[i].length;
// copy data from TB0
memcpy(m_tx_req_msg->pdus[i].data, request.pdus[i].data[0], m_tx_req_msg->pdus[i].length);
} else {
logger.error("Trying to send %d B PDU. Maximum size is %d B", request.pdus[i].length, MAX_PDU_SIZE);
}
}
// calculate actual length of message
uint32_t len = calc_full_msg_len(*m_tx_req_msg.get());
// update msg header length field
m_tx_req_msg->header.msg_len = len - sizeof(basic_vnf_api::msg_header_t);
// Send it to PNF
logger.info("Sending %s (%d B)", basic_vnf_api::msg_type_text[m_tx_req_msg->header.type], len);
if (logger.debug.enabled()) {
for (uint32_t i = 0; i < m_tx_req_msg->nof_pdus; ++i) {
logger.debug(m_tx_req_msg->pdus[i].data,
m_tx_req_msg->pdus[i].length,
"Sending PDU %s:%d (%d bytes)",
basic_vnf_api::msg_type_text[m_tx_req_msg->header.type],
m_tx_req_msg->pdus[i].index,
m_tx_req_msg->pdus[i].length);
}
}
int n = 0;
if ((n = sendto(sockfd, m_tx_req_msg.get(), len, MSG_CONFIRM, (struct sockaddr*)&client_addr, sizeof(client_addr))) <
0) {
logger.error("sendto failed, ret=%d", n);
}
return 0;
}
uint32_t srsran_basic_vnf::calc_full_msg_len(const basic_vnf_api::tx_request_msg_t& msg)
{
// start with mandatory part
uint32_t len = sizeof(basic_vnf_api::msg_header_t) + 3 * sizeof(uint32_t);
// add all PDUs
for (uint32_t i = 0; i < msg.nof_pdus; ++i) {
len += 2 * sizeof(uint16_t) + sizeof(basic_vnf_api::pdu_type_t) + msg.pdus[i].length;
}
return len;
}
bool srsran_basic_vnf::stop()
{
if (running) {
running = false;
wait_thread_finish();
}
return true;
}
} // namespace srsran

@ -172,7 +172,7 @@ void phy_cfg_nr_default_t::make_harq_auto(srsran_harq_ack_cfg_hl_t& harq,
const srsran_tdd_config_nr_t& tdd_cfg)
{
// Generate as many entries as DL slots
harq.nof_dl_data_to_ul_ack = SRSRAN_MAX(tdd_cfg.pattern1.nof_dl_slots, SRSRAN_MAX_NOF_DL_DATA_TO_UL);
harq.nof_dl_data_to_ul_ack = SRSRAN_MIN(tdd_cfg.pattern1.nof_dl_slots, SRSRAN_MAX_NOF_DL_DATA_TO_UL);
// Set PDSCH to ACK timing delay to 4 or more
for (uint32_t n = 0; n < harq.nof_dl_data_to_ul_ack; n++) {
@ -206,6 +206,7 @@ void phy_cfg_nr_default_t::make_prach_default_lte(srsran_prach_cfg_t& prach)
prach.config_idx = 0;
prach.freq_offset = 2;
prach.root_seq_idx = 0;
prach.is_nr = true;
}
phy_cfg_nr_default_t::phy_cfg_nr_default_t(const reference_cfg_t& reference_cfg)

@ -848,6 +848,13 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
// Demultiplex UCI only if necessary
if (q->uci_mux) {
// As it can be HARQ-ACK takes LLRs from ULSCH, demultiplex HARQ-ACK first
int8_t* g_ack = (int8_t*)q->g_ack;
for (uint32_t i = 0; i < q->G_ack; i++) {
g_ack[i] = llr[q->pos_ack[i]];
llr[q->pos_ack[i]] = 0;
}
// Demultiplex UL-SCH, change sign
int8_t* g_ulsch = (int8_t*)q->g_ulsch;
for (uint32_t i = 0; i < q->G_ulsch; i++) {
@ -857,12 +864,6 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
g_ulsch[i] = 0;
}
// Demultiplex HARQ-ACK
int8_t* g_ack = (int8_t*)q->g_ack;
for (uint32_t i = 0; i < q->G_ack; i++) {
g_ack[i] = llr[q->pos_ack[i]];
}
// Demultiplex CSI part 1
int8_t* g_csi1 = (int8_t*)q->g_csi1;
for (uint32_t i = 0; i < q->G_csi1; i++) {

@ -1049,6 +1049,12 @@ int srsran_ra_ul_set_grant_uci_nr(const srsran_carrier_nr_t* carrier,
for (uint32_t i = 0; i < SRSRAN_MAX_TB; i++) {
pusch_cfg->grant.tb[i].nof_bits =
pusch_cfg->grant.tb[i].nof_re * srsran_mod_bits_x_symbol(pusch_cfg->grant.tb[i].mod) - Gack - Gcsi1 - Gcsi2;
if (pusch_cfg->grant.tb[i].nof_bits > 0) {
pusch_cfg->grant.tb[i].R_prime = (double)pusch_cfg->grant.tb[i].tbs / (double)pusch_cfg->grant.tb[i].nof_bits;
} else {
pusch_cfg->grant.tb[i].R_prime = NAN;
}
}
return SRSRAN_SUCCESS;

@ -539,7 +539,7 @@ int srsran_ra_ul_nr_pucch_resource(const srsran_pucch_nr_hl_cfg_t* pucch_cfg,
// - At least one positive SR
// - up to 2 HARQ-ACK
// - No CSI report
if (uci_cfg->pucch.sr_positive_present > 0 && uci_cfg->ack.count <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS &&
if (uci_cfg->sr_positive_present > 0 && uci_cfg->ack.count <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS &&
uci_cfg->nof_csi == 0) {
uint32_t sr_resource_id = uci_cfg->pucch.sr_resource_id;
if (sr_resource_id >= SRSRAN_PUCCH_MAX_NOF_SR_RESOURCES) {

@ -656,18 +656,9 @@ static int sch_nr_decode(srsran_sch_nr_t* q,
// Check if CB is all zeros
uint32_t cb_len = cfg.Kp - cfg.L_cb;
bool all_zeros = true;
for (uint32_t i = 0; i < cb_len && all_zeros; i++) {
all_zeros = (q->temp_cb[i] == 0);
}
tb->softbuffer.rx->cb_crc[r] = (ret != 0) && (!all_zeros);
SCH_INFO_RX("CB %d/%d iter=%d CRC=%s all_zeros=%s",
r,
cfg.C,
n_iter_cb,
tb->softbuffer.rx->cb_crc[r] ? "OK" : "KO",
all_zeros ? "yes" : "no");
tb->softbuffer.rx->cb_crc[r] = (ret != 0);
SCH_INFO_RX("CB %d/%d iter=%d CRC=%s", r, cfg.C, n_iter_cb, tb->softbuffer.rx->cb_crc[r] ? "OK" : "KO");
// CB Debug trace
if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) {
@ -789,7 +780,7 @@ int srsran_sch_nr_tb_info(const srsran_sch_tb_t* tb, const srsran_sch_tb_res_nr_
tb->cw_idx,
srsran_mod_string(tb->mod),
tb->tbs / 8,
tb->R,
tb->R_prime,
tb->rv);
if (res != NULL) {

@ -286,16 +286,16 @@ int main(int argc, char** argv)
goto clean_exit;
}
float mse = 0.0f;
// Check symbols Mean Square Error (MSE)
uint32_t nof_re = srsran_ra_dl_nr_slot_nof_re(&pusch_cfg, &pusch_cfg.grant);
if (nof_re * pusch_cfg.grant.nof_layers > 0) {
float mse = 0.0f;
for (uint32_t i = 0; i < pusch_cfg.grant.nof_layers; i++) {
for (uint32_t j = 0; j < nof_re; j++) {
mse += cabsf(pusch_tx.d[i][j] - pusch_rx.d[i][j]);
}
}
if (nof_re * pusch_cfg.grant.nof_layers > 0) {
mse = mse / (nof_re * pusch_cfg.grant.nof_layers);
}
if (mse > 0.001) {
ERROR("MSE error (%f) is too high", mse);
for (uint32_t i = 0; i < pusch_cfg.grant.nof_layers; i++) {
@ -306,6 +306,28 @@ int main(int argc, char** argv)
}
goto clean_exit;
}
}
// Check Received SCH LLR match
if (pusch_rx.G_ulsch > 0) {
for (uint32_t i = 0; i < pusch_rx.G_ulsch; i++) {
uint8_t rx_bit = (((int8_t*)pusch_rx.g_ulsch)[i]) < 0 ? 1 : 0;
if (rx_bit == 0) {
pusch_rx.g_ulsch[i] = pusch_tx.g_ulsch[i];
} else {
pusch_rx.g_ulsch[i] = rx_bit;
}
}
if (memcmp(pusch_tx.g_ulsch, pusch_rx.g_ulsch, pusch_tx.G_ulsch) != 0) {
printf("g_ulsch_tx=");
srsran_vec_fprint_byte(stdout, pusch_tx.g_ulsch, pusch_tx.G_ulsch);
printf("g_ulsch_rx=");
srsran_vec_fprint_byte(stdout, pusch_rx.g_ulsch, pusch_tx.G_ulsch);
// srsran_vec_fprint_bs(stdout, (int8_t*)pusch_rx.g_ulsch, pusch_rx.G_ulsch);
goto clean_exit;
}
}
// Validate UL-SCH CRC check
if (!data_rx.tb[0].crc) {

@ -989,7 +989,16 @@ uint32_t srsran_uci_nr_total_bits(const srsran_uci_cfg_nr_t* uci_cfg)
return 0;
}
return uci_cfg->ack.count + uci_cfg->o_sr + srsran_csi_part1_nof_bits(uci_cfg->csi, uci_cfg->nof_csi);
uint32_t o_csi = srsran_csi_part1_nof_bits(uci_cfg->csi, uci_cfg->nof_csi);
// According to 38.213 9.2.4 UE procedure for reporting SR
// The UE transmits a PUCCH in the PUCCH resource for the corresponding SR configuration only when the UE transmits a
// positive SR
if (uci_cfg->ack.count == 0 && o_csi == 0 && !uci_cfg->sr_positive_present) {
return 0;
}
return uci_cfg->ack.count + uci_cfg->o_sr + o_csi;
}
uint32_t srsran_uci_nr_info(const srsran_uci_data_nr_t* uci_data, char* str, uint32_t str_len)

@ -183,13 +183,13 @@ int srsran_rf_open_multi(srsran_rf_t* h, char* args, uint32_t nof_channels)
int srsran_rf_close(srsran_rf_t* rf)
{
// Stop gain thread
if (rf->thread_gain_run) {
pthread_mutex_lock(&rf->mutex);
if (rf->thread_gain_run) {
rf->thread_gain_run = false;
}
pthread_mutex_unlock(&rf->mutex);
pthread_cond_signal(&rf->cond);
pthread_join(rf->thread_gain, NULL);
}
return ((rf_dev_t*)rf->dev)->srsran_rf_close(rf->handler);
}

@ -29,6 +29,7 @@
#include "rf_helper.h"
#include "srsran/phy/utils/debug.h"
#include "srsran/phy/utils/vector.h"
#include "rf_uhd_generic.h"
#include "rf_uhd_imp.h"
@ -197,10 +198,12 @@ void suppress_handler(const char* x)
// do nothing
}
static cf_t zero_mem[64 * 1024] = {};
static std::array<cf_t, 64 * 1024> zero_mem = {}; // For transmitting zeros
static std::array<cf_t, 64 * 1024> dummy_mem = {}; // For receiving
static void log_overflow(rf_uhd_handler_t* h)
{
std::unique_lock<std::mutex> lock(h->tx_mutex);
if (h->tx_state == RF_UHD_IMP_TX_STATE_BURST) {
h->tx_state = RF_UHD_IMP_TX_STATE_END_OF_BURST;
}
@ -215,6 +218,7 @@ static void log_overflow(rf_uhd_handler_t* h)
static void log_late(rf_uhd_handler_t* h, bool is_rx)
{
std::unique_lock<std::mutex> lock(h->tx_mutex);
if (h->tx_state == RF_UHD_IMP_TX_STATE_BURST) {
h->tx_state = RF_UHD_IMP_TX_STATE_END_OF_BURST;
}
@ -563,13 +567,14 @@ void rf_uhd_flush_buffer(void* h)
// Set all pointers to zero buffer
for (auto& i : data) {
i = zero_mem;
i = dummy_mem.data();
}
// Receive until time out
uhd::rx_metadata_t md;
do {
if (handler->uhd->receive(data, handler->rx_nof_samples, md, 0.0, false, rxd_samples) != UHD_ERROR_NONE) {
uint32_t nsamples = SRSRAN_MIN(handler->rx_nof_samples, (uint32_t)dummy_mem.size());
if (handler->uhd->receive(data, nsamples, md, 0.0, false, rxd_samples) != UHD_ERROR_NONE) {
log_rx_error(handler);
return;
}
@ -958,7 +963,7 @@ static inline int rf_uhd_imp_end_burst(rf_uhd_handler_t* handler)
// Set buffer pointers
for (int i = 0; i < SRSRAN_MAX_CHANNELS; i++) {
buffs_ptr[i] = zero_mem;
buffs_ptr[i] = zero_mem.data();
}
// Set metadata
@ -1270,13 +1275,19 @@ int rf_uhd_recv_with_time_multi(void* h,
// Receive stream in multiple blocks
while (rxd_samples_total < nsamples and trials < RF_UHD_IMP_MAX_RX_TRIALS) {
void* buffs_ptr[SRSRAN_MAX_CHANNELS] = {};
size_t num_samps_left = nsamples - rxd_samples_total;
size_t num_rx_samples = SRSRAN_MIN(handler->rx_nof_samples, num_samps_left);
for (uint32_t i = 0; i < handler->nof_rx_channels; i++) {
if (data[i] != nullptr) {
cf_t* data_c = (cf_t*)data[i];
buffs_ptr[i] = &data_c[rxd_samples_total];
} else {
buffs_ptr[i] = dummy_mem.data();
num_rx_samples = SRSRAN_MIN(num_rx_samples, (uint32_t)dummy_mem.size());
}
}
size_t num_samps_left = nsamples - rxd_samples_total;
size_t num_rx_samples = (num_samps_left > handler->rx_nof_samples) ? handler->rx_nof_samples : num_samps_left;
if (handler->uhd->receive(buffs_ptr, num_rx_samples, md, 1.0, false, rxd_samples) != UHD_ERROR_NONE) {
log_rx_error(handler);
@ -1388,9 +1399,9 @@ int rf_uhd_send_timed_multi(void* h,
cf_t* data_c[SRSRAN_MAX_CHANNELS] = {};
for (uint32_t i = 0; i < SRSRAN_MAX_CHANNELS; i++) {
if (i < handler->nof_tx_channels) {
data_c[i] = (data[i] != nullptr) ? (cf_t*)(data[i]) : zero_mem;
data_c[i] = (data[i] != nullptr) ? (cf_t*)(data[i]) : zero_mem.data();
} else {
data_c[i] = zero_mem;
data_c[i] = zero_mem.data();
}
}

@ -988,6 +988,7 @@ srsran_rf_info_t* radio::get_info()
bool radio::get_metrics(rf_metrics_t* metrics)
{
std::lock_guard<std::mutex> lock(metrics_mutex);
*metrics = rf_metrics;
rf_metrics = {};
return true;
@ -999,8 +1000,11 @@ void radio::handle_rf_msg(srsran_rf_error_t error)
return;
}
if (error.type == srsran_rf_error_t::SRSRAN_RF_ERROR_OVERFLOW) {
{
std::lock_guard<std::mutex> lock(metrics_mutex);
rf_metrics.rf_o++;
rf_metrics.rf_error = true;
}
logger.info("Overflow");
// inform PHY about overflow
@ -1008,13 +1012,15 @@ void radio::handle_rf_msg(srsran_rf_error_t error)
phy->radio_overflow();
}
} else if (error.type == srsran_rf_error_t::SRSRAN_RF_ERROR_UNDERFLOW) {
logger.info("Underflow");
std::lock_guard<std::mutex> lock(metrics_mutex);
rf_metrics.rf_u++;
rf_metrics.rf_error = true;
logger.info("Underflow");
} else if (error.type == srsran_rf_error_t::SRSRAN_RF_ERROR_LATE) {
logger.info("Late (detected in %s)", error.opt ? "rx call" : "asynchronous thread");
std::lock_guard<std::mutex> lock(metrics_mutex);
rf_metrics.rf_l++;
rf_metrics.rf_error = true;
logger.info("Late (detected in %s)", error.opt ? "rx call" : "asynchronous thread");
} else if (error.type == srsran_rf_error_t::SRSRAN_RF_ERROR_RX) {
logger.error("Fatal radio error occured.");
phy->radio_failure();

@ -52,7 +52,7 @@ static void format_metadata(const detail::log_entry_metadata& metadata, fmt::mem
std::tm current_time = fmt::gmtime(std::chrono::high_resolution_clock::to_time_t(metadata.tp));
auto us_fraction =
std::chrono::duration_cast<std::chrono::microseconds>(metadata.tp.time_since_epoch()).count() % 1000000u;
fmt::format_to(buffer, "{:%H:%M:%S}.{:06} ", current_time, us_fraction);
fmt::format_to(buffer, "{:%F}T{:%H:%M:%S}.{:06} ", current_time, current_time, us_fraction);
// Format optional fields if present.
if (!metadata.log_name.empty()) {

@ -0,0 +1,97 @@
/**
*
* \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 SRSLOG_SYSLOG_SINK_H
#define SRSLOG_SYSLOG_SINK_H
#include "srsran/srslog/shared_types.h"
#include "srsran/srslog/sink.h"
#include <syslog.h>
namespace srslog {
/// This sink implementation writes to syslog.
class syslog_sink : public sink
{
public:
syslog_sink(std::unique_ptr<log_formatter> f,
std::string preamble_ = "",
syslog_local_type log_local_ = syslog_local_type::local0) :
sink(std::move(f))
{
create_syslog(preamble_, syslog_translate(log_local_));
}
syslog_sink(const syslog_sink& other) = delete;
syslog_sink& operator=(const syslog_sink& other) = delete;
detail::error_string write(detail::memory_buffer buffer) override
{
std::string entry(buffer.data(), buffer.size());
if (entry.find("[E]") != std::string::npos) {
syslog(LOG_ERR, "%s", buffer.data());
} else if (entry.find("[W]") != std::string::npos) {
syslog(LOG_WARNING, "%s", buffer.data());
} else if (entry.find("[I]") != std::string::npos) {
syslog(LOG_INFO, "%s", buffer.data());
} else if (entry.find("[D]") != std::string::npos) {
syslog(LOG_DEBUG, "%s", buffer.data());
} else {
syslog(LOG_ERR, "%s", buffer.data());
}
// openlog syslog does not return any value.
return {};
}
detail::error_string flush() override { return {}; }
private:
/// Creates a new syslog
detail::error_string create_syslog(std::string preamble, int log_local)
{
if (preamble == "") {
openlog(NULL, LOG_CONS | LOG_PID | LOG_NDELAY, log_local);
} else {
openlog(preamble.c_str(), LOG_CONS | LOG_PID | LOG_NDELAY, log_local);
}
return {};
}
static int syslog_translate(syslog_local_type log_local)
{
switch (log_local) {
case syslog_local_type::local0:
return LOG_LOCAL0;
case syslog_local_type::local1:
return LOG_LOCAL1;
case syslog_local_type::local2:
return LOG_LOCAL2;
case syslog_local_type::local3:
return LOG_LOCAL3;
case syslog_local_type::local4:
return LOG_LOCAL4;
case syslog_local_type::local5:
return LOG_LOCAL5;
case syslog_local_type::local6:
return LOG_LOCAL6;
case syslog_local_type::local7:
return LOG_LOCAL7;
default:
return LOG_LOCAL0;
break;
}
};
};
} // namespace srslog
#endif // SRSLOG_SYSLOG_SINK_H

@ -22,6 +22,7 @@
#include "srsran/srslog/srslog.h"
#include "formatters/json_formatter.h"
#include "sinks/file_sink.h"
#include "sinks/syslog_sink.h"
#include "srslog_instance.h"
using namespace srslog;
@ -174,6 +175,25 @@ sink& srslog::fetch_file_sink(const std::string& path, size_t max_size, std::uni
return *s;
}
sink& srslog::fetch_syslog_sink(const std::string& preamble_,
syslog_local_type log_local_,
std::unique_ptr<log_formatter> f)
{
std::string sink_id = preamble_ + std::to_string(static_cast<int>(log_local_));
if (auto* s = find_sink(sink_id)) {
return *s;
}
//: TODO: GCC5 or lower versions emits an error if we use the new() expression
// directly, use redundant piecewise_construct instead.
auto& s = srslog_instance::get().get_sink_repo().emplace(
std::piecewise_construct,
std::forward_as_tuple(sink_id),
std::forward_as_tuple(new syslog_sink(std::move(f), preamble_, log_local_)));
return *s;
}
bool srslog::install_custom_sink(const std::string& id, std::unique_ptr<sink> s)
{
assert(!id.empty() && "Empty path string");

@ -85,11 +85,5 @@ add_executable(task_scheduler_test task_scheduler_test.cc)
target_link_libraries(task_scheduler_test srsran_common ${ATOMIC_LIBS})
add_test(task_scheduler_test task_scheduler_test)
add_executable(pnf_dummy pnf_dummy.cc)
target_link_libraries(pnf_dummy srsran_common ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
add_executable(pnf_bridge pnf_bridge.cc)
target_link_libraries(pnf_bridge srsran_common ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
add_executable(mac_pcap_net_test mac_pcap_net_test.cc)
target_link_libraries(mac_pcap_net_test srsran_common ${SCTP_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})

@ -1,127 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN 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.
*
* srsRAN 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 <assert.h>
#include <boost/program_options.hpp>
#include <boost/program_options/parsers.hpp>
#include <chrono>
#include <iostream>
#include <signal.h>
#include <thread>
#include "srsran/common/basic_pnf.h"
using namespace std;
namespace bpo = boost::program_options;
struct pnf_args_t {
std::string gnb_vnf_addr;
std::string ue_vnf_addr;
uint16_t gnb_vnf_port;
uint16_t ue_vnf_port;
uint32_t sf_interval;
int32_t num_sf;
uint32_t tb_len;
};
void parse_args(pnf_args_t* args, int argc, char* argv[])
{
// Command line only options
bpo::options_description general("General options");
general.add_options()("help,h", "Produce help message")("version,v", "Print version information and exit");
// Command line or config file options
bpo::options_description common("Configuration options");
// clang-format off
common.add_options()
("vnf.gnb_addr", bpo::value<string>(&args->gnb_vnf_addr)->default_value("127.0.0.1"), "VNF address")
("vnf.ue_addr", bpo::value<string>(&args->ue_vnf_addr)->default_value("127.0.0.1"), "VNF address")
("vnf.gnb_port", bpo::value<uint16_t>(&args->gnb_vnf_port)->default_value(3333), "gNB VNF port")
("vnf.ue_port", bpo::value<uint16_t>(&args->ue_vnf_port)->default_value(3334), "UE VNF port")
("sf_interval", bpo::value<uint32_t>(&args->sf_interval)->default_value(1000), "Interval between subframes in us")
("num_sf", bpo::value<int32_t>(&args->num_sf)->default_value(-1), "Number of subframes to signal (-1 infinity)")
("tb_len", bpo::value<uint32_t>(&args->tb_len)->default_value(1600), "TB lenth (0 for random size)");
// clang-format on
// these options are allowed on the command line
bpo::options_description cmdline_options;
cmdline_options.add(common).add(general);
// parse the command line and store result in vm
bpo::variables_map vm;
bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).run(), vm);
bpo::notify(vm);
// help option was given - print usage and exit
if (vm.count("help")) {
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
cout << common << endl << general << endl;
exit(0);
}
}
bool running = true;
void sig_int_handler(int signo)
{
printf("SIGINT received. Exiting...\n");
if (signo == SIGINT) {
running = false;
}
}
int main(int argc, char** argv)
{
signal(SIGINT, sig_int_handler);
pnf_args_t args;
parse_args(&args, argc, argv);
srsran::srsran_basic_pnf ue_pnf("ue", args.ue_vnf_addr, args.ue_vnf_port, args.sf_interval, args.num_sf, args.tb_len);
srsran::srsran_basic_pnf gnb_pnf(
"gnb", args.gnb_vnf_addr, args.gnb_vnf_port, args.sf_interval, args.num_sf, args.tb_len);
gnb_pnf.connect_out_rf_queue(ue_pnf.get_in_rf_queue());
ue_pnf.start();
gnb_pnf.start();
while (running) {
for (uint32_t i = 0; i < 2; ++i) {
srsran::pnf_metrics_t metrics = (i == 0) ? ue_pnf.get_metrics() : gnb_pnf.get_metrics();
printf("%s: RTT=%d, #Error=%d, #PDUs=%d, Total TB size=%d, Rate=%.2f Mbit/s\n",
i == 0 ? "UE" : "gNB",
metrics.avg_rtt_us,
metrics.num_timing_errors,
metrics.num_pdus,
metrics.tb_size,
metrics.tb_size * 8 / 1.0e6);
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
ue_pnf.stop();
gnb_pnf.stop();
return 0;
}

@ -1,117 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN 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.
*
* srsRAN 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 <assert.h>
#include <boost/program_options.hpp>
#include <boost/program_options/parsers.hpp>
#include <chrono>
#include <iostream>
#include <signal.h>
#include <thread>
#include "srsran/common/basic_pnf.h"
using namespace std;
namespace bpo = boost::program_options;
struct pnf_args_t {
std::string type;
std::string vnf_addr;
uint16_t vnf_port;
uint32_t sf_interval;
int32_t num_sf;
uint32_t tb_len;
};
void parse_args(pnf_args_t* args, int argc, char* argv[])
{
// Command line only options
bpo::options_description general("General options");
general.add_options()("help,h", "Produce help message")("version,v", "Print version information and exit");
// Command line or config file options
bpo::options_description common("Configuration options");
// clang-format off
common.add_options()
("vnf.type", bpo::value<string>(&args->type)->default_value("gnb"), "VNF instance type [gnb,ue]")
("vnf.addr", bpo::value<string>(&args->vnf_addr)->default_value("127.0.0.1"), "VNF address")
("vnf.port", bpo::value<uint16_t>(&args->vnf_port)->default_value(3333), "VNF port")
("sf_interval", bpo::value<uint32_t>(&args->sf_interval)->default_value(1000), "Interval between subframes in us")
("num_sf", bpo::value<int32_t>(&args->num_sf)->default_value(-1), "Number of subframes to signal (-1 infinity)")
("tb_len", bpo::value<uint32_t>(&args->tb_len)->default_value(0), "TB lenth (0 for random size)");
// clang-format on
// these options are allowed on the command line
bpo::options_description cmdline_options;
cmdline_options.add(common).add(general);
// parse the command line and store result in vm
bpo::variables_map vm;
bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).run(), vm);
bpo::notify(vm);
// help option was given - print usage and exit
if (vm.count("help")) {
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
cout << common << endl << general << endl;
exit(0);
}
}
bool running = true;
void sig_int_handler(int signo)
{
printf("SIGINT received. Exiting...\n");
if (signo == SIGINT) {
running = false;
}
}
int main(int argc, char** argv)
{
signal(SIGINT, sig_int_handler);
pnf_args_t args;
parse_args(&args, argc, argv);
srsran::srsran_basic_pnf pnf(args.type, args.vnf_addr, args.vnf_port, args.sf_interval, args.num_sf, args.tb_len);
pnf.start();
while (running) {
srsran::pnf_metrics_t metrics = pnf.get_metrics();
printf("RTT=%d, #Error=%d, #PDUs=%d, Total TB size=%d, Rate=%.2f Mbit/s\n",
metrics.avg_rtt_us,
metrics.num_timing_errors,
metrics.num_pdus,
metrics.tb_size,
metrics.tb_size * 8 / 1e6);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
pnf.stop();
return 0;
}

@ -47,6 +47,10 @@ target_include_directories(file_sink_test PUBLIC ../../)
target_link_libraries(file_sink_test srslog)
add_test(file_sink_test file_sink_test)
add_executable(syslog_sink_test syslog_sink_test.cpp)
target_include_directories(syslog_sink_test PUBLIC ../../)
target_link_libraries(syslog_sink_test srslog)
add_executable(file_utils_test file_utils_test.cpp)
target_include_directories(file_utils_test PUBLIC ../../)
target_link_libraries(file_utils_test srslog)

@ -0,0 +1,63 @@
/**
*
* \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 "src/srslog/sinks/syslog_sink.h"
#include "srsran/srslog/srslog.h"
#include "test_dummies.h"
#include "testing_helpers.h"
#include <fstream>
#include <sstream>
using namespace srslog;
/// Syslog sink name.
static constexpr char sink_name[] = "srslog_syslog_sink";
static bool find_string_infile(std::string filename, std::string pattern)
{
std::ifstream file(filename);
std::string line;
bool found = false;
if (file.is_open()) {
while (std::getline(file, line)) {
if (line.find(pattern) != std::string::npos) { // WILL SEARCH 2015-1113 in file
found = true;
}
}
} else {
printf("WARNING: Could not open file %s", filename.c_str());
}
return found;
}
static bool syslog_basic_test()
{
syslog_sink syslog_sink(get_default_log_formatter());
// Build a 1000 byte entry.
std::string entry(1000, 'a');
syslog_sink.write(detail::memory_buffer(entry));
syslog_sink.flush();
ASSERT_EQ(find_string_infile("/var/log/syslog", entry), true);
return true;
}
int main()
{
TEST_FUNCTION(syslog_basic_test);
return 0;
}

@ -46,7 +46,7 @@ static bool when_fully_filled_log_entry_then_everything_is_formatted()
fmt::dynamic_format_arg_store<fmt::printf_context> store;
text_formatter{}.format(build_log_entry_metadata(&store), buffer);
std::string result = fmt::to_string(buffer);
std::string expected = "00:00:00.050000 [ABC ] [Z] [ 10] Text 88\n";
std::string expected = "1970-01-01T00:00:00.050000 [ABC ] [Z] [ 10] Text 88\n";
ASSERT_EQ(result, expected);
@ -62,7 +62,7 @@ static bool when_log_entry_without_name_is_passed_then_name_is_not_formatted()
fmt::memory_buffer buffer;
text_formatter{}.format(std::move(entry), buffer);
std::string result = fmt::to_string(buffer);
std::string expected = "00:00:00.050000 [Z] [ 10] Text 88\n";
std::string expected = "1970-01-01T00:00:00.050000 [Z] [ 10] Text 88\n";
ASSERT_EQ(result, expected);
@ -78,7 +78,7 @@ static bool when_log_entry_without_tag_is_passed_then_tag_is_not_formatted()
fmt::memory_buffer buffer;
text_formatter{}.format(std::move(entry), buffer);
std::string result = fmt::to_string(buffer);
std::string expected = "00:00:00.050000 [ABC ] [ 10] Text 88\n";
std::string expected = "1970-01-01T00:00:00.050000 [ABC ] [ 10] Text 88\n";
ASSERT_EQ(result, expected);
@ -94,7 +94,7 @@ static bool when_log_entry_without_context_is_passed_then_context_is_not_formatt
fmt::memory_buffer buffer;
text_formatter{}.format(std::move(entry), buffer);
std::string result = fmt::to_string(buffer);
std::string expected = "00:00:00.050000 [ABC ] [Z] Text 88\n";
std::string expected = "1970-01-01T00:00:00.050000 [ABC ] [Z] Text 88\n";
ASSERT_EQ(result, expected);
@ -111,7 +111,7 @@ static bool when_log_entry_with_hex_dump_is_passed_then_hex_dump_is_formatted()
fmt::memory_buffer buffer;
text_formatter{}.format(std::move(entry), buffer);
std::string result = fmt::to_string(buffer);
std::string expected = "00:00:00.050000 [ABC ] [Z] [ 10] Text 88\n"
std::string expected = "1970-01-01T00:00:00.050000 [ABC ] [Z] [ 10] Text 88\n"
" 0000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"
" 0010: 10 11 12 13\n";
@ -185,7 +185,7 @@ static bool when_log_entry_with_only_context_is_passed_then_context_is_formatted
fmt::memory_buffer buffer;
text_formatter{}.format_ctx(ctx, std::move(entry), buffer);
std::string result = fmt::to_string(buffer);
std::string expected = "00:00:00.050000 [ABC ] [Z] [ 10] Context dump for "
std::string expected = "1970-01-01T00:00:00.050000 [ABC ] [Z] [ 10] Context dump for "
"\"Complex Context\"\n"
" > List: sector_list\n"
" > Set: sector_metrics\n"
@ -227,7 +227,7 @@ static bool when_log_entry_with_context_and_message_is_passed_then_context_is_fo
fmt::memory_buffer buffer;
text_formatter{}.format_ctx(ctx, std::move(entry), buffer);
std::string result = fmt::to_string(buffer);
std::string expected = "00:00:00.050000 [ABC ] [Z] [ 10] [[sector_metrics_type: event, "
std::string expected = "1970-01-01T00:00:00.050000 [ABC ] [Z] [ 10] [[sector_metrics_type: event, "
"sector_metrics_sector_id: 1, [ue_container_Throughput: 1.2 MB/s, "
"ue_container_Address: 10.20.30.40, [RF_SNR: 5.1 dB, RF_PWR: -11 "
"dBm][RF_SNR: 10.1 dB, RF_PWR: -20 dBm]][ue_container_Throughput: 10.2 "

@ -53,6 +53,6 @@ add_subdirectory(test)
# Default configuration files
########################################################################
install(FILES enb.conf.example DESTINATION ${DATA_DIR})
install(FILES drb.conf.example DESTINATION ${DATA_DIR})
install(FILES rb.conf.example DESTINATION ${DATA_DIR})
install(FILES rr.conf.example DESTINATION ${DATA_DIR})
install(FILES sib.conf.example DESTINATION ${DATA_DIR})

@ -36,12 +36,12 @@ n_prb = 50
# sib_config: SIB1, SIB2 and SIB3 configuration file
# note: when enabling mbms, use the sib.conf.mbsfn configuration file which includes SIB13
# rr_config: Radio Resources configuration file
# drb_config: DRB configuration file
# rb_config: SRB/DRB configuration file
#####################################################################
[enb_files]
sib_config = sib.conf
rr_config = rr.conf
drb_config = drb.conf
rb_config = rb.conf
#####################################################################
# RF configuration
@ -180,6 +180,7 @@ enable = false
# init_ul_snr_value: Initial UL SNR value used for computing MCS in the first UL grant
# init_dl_cqi: DL CQI value used before any CQI report is available to the eNB
# max_sib_coderate: Upper bound on SIB and RAR grants coderate
# pdcch_cqi_offset: CQI offset in derivation of PDCCH aggregation level
#
#####################################################################
[scheduler]
@ -204,6 +205,7 @@ enable = false
#init_ul_snr_value=5
#init_dl_cqi=5
#max_sib_coderate=0.3
#pdcch_cqi_offset=0
#####################################################################
# eMBMS configuration options
@ -324,6 +326,7 @@ enable = false
# tracing_enable: Write source code tracing information to a file.
# tracing_filename: File path to use for tracing information.
# tracing_buffcapacity: Maximum capacity in bytes the tracing framework can store.
# stdout_ts_enable: Prints once per second the timestamp into stdout.
# pregenerate_signals: Pregenerate uplink signals after attach. Improves CPU performance.
# tx_amplitude: Transmit amplitude factor (set 0-1 to reduce PAPR)
# rrc_inactivity_timer Inactivity timeout used to remove UE context from RRC (in milliseconds).
@ -335,6 +338,8 @@ enable = false
# gtpu_tunnel_timeout: Time that GTPU takes to release indirect forwarding tunnel since the last received GTPU PDU (0 for no timer).
#ts1_reloc_prep_timeout: S1AP TS 36.413 TS1RelocPrep Expiry Timeout value in milliseconds
#ts1_reloc_overall_timeout: S1AP TS 36.413 TS1RelocOverall Expiry Timeout value in milliseconds
# rlf_release_timer_ms: Time taken by eNB to release UE context after it detects an RLF
# rlf_min_ul_snr_estim: SNR threshold in dB below which the enb is notified with rlf ko
#
#####################################################################
[expert]
@ -351,6 +356,7 @@ enable = false
#tracing_enable = true
#tracing_filename = /tmp/enb_tracing.log
#tracing_buffcapacity = 1000000
#stdout_ts_enable = false
#pregenerate_signals = false
#tx_amplitude = 0.6
#rrc_inactivity_timer = 30000
@ -365,3 +371,5 @@ enable = false
#extended_cp = false
#ts1_reloc_prep_timeout = 10000
#ts1_reloc_overall_timeout = 10000
#rlf_release_timer_ms = 4000
#rlf_min_ul_snr_estim = -2

@ -71,7 +71,7 @@ struct enb_args_t {
struct enb_files_t {
std::string sib_config;
std::string rr_config;
std::string drb_config;
std::string rb_config;
};
struct log_args_t {

@ -42,11 +42,10 @@ class slot_worker final : public srsran::thread_pool::worker
public:
struct args_t {
uint32_t cell_index = 0;
srsran_carrier_nr_t carrier = {};
uint32_t nof_max_prb = SRSRAN_MAX_PRB_NR;
uint32_t nof_tx_ports = 1;
uint32_t nof_rx_ports = 1;
uint32_t pusch_max_nof_iter = 10;
srsran_pdcch_cfg_nr_t pdcch_cfg = {}; ///< PDCCH configuration
};
slot_worker(srsran::phy_common_interface& common_, stack_interface_phy_nr& stack_, srslog::basic_logger& logger);
@ -54,6 +53,8 @@ public:
bool init(const args_t& args);
bool set_common_cfg(const srsran_carrier_nr_t& carrier, const srsran_pdcch_cfg_nr_t& pdcch_cfg_);
/* Functions used by main PHY thread */
cf_t* get_buffer_rx(uint32_t antenna_idx);
cf_t* get_buffer_tx(uint32_t antenna_idx);

@ -24,7 +24,9 @@
#include "slot_worker.h"
#include "srsenb/hdr/phy/phy_interfaces.h"
#include "srsenb/hdr/phy/prach_worker.h"
#include "srsran/common/thread_pool.h"
#include "srsran/interfaces/enb_mac_interfaces.h"
#include "srsran/interfaces/gnb_interfaces.h"
namespace srsenb {
@ -32,20 +34,71 @@ namespace nr {
class worker_pool
{
private:
class prach_stack_adaptor_t : public stack_interface_phy_lte
{
private:
stack_interface_phy_nr& stack;
public:
prach_stack_adaptor_t(stack_interface_phy_nr& stack_) : stack(stack_)
{
// Do nothing
}
int sr_detected(uint32_t tti, uint16_t rnti) override { return 0; }
void rach_detected(uint32_t tti, uint32_t primary_cc_idx, uint32_t preamble_idx, uint32_t time_adv) override
{
stack_interface_phy_nr::rach_info_t rach_info = {};
rach_info.preamble = preamble_idx;
rach_info.time_adv = time_adv;
stack.rach_detected(rach_info);
}
int ri_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t ri_value) override { return 0; }
int pmi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t pmi_value) override { return 0; }
int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t cqi_value) override { return 0; }
int snr_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, float snr_db, ul_channel_t ch) override { return 0; }
int ta_info(uint32_t tti, uint16_t rnti, float ta_us) override { return 0; }
int ack_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t tb_idx, bool ack) override { return 0; }
int crc_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t nof_bytes, bool crc_res) override { return 0; }
int push_pdu(uint32_t tti_rx,
uint16_t rnti,
uint32_t enb_cc_idx,
uint32_t nof_bytes,
bool crc_res,
uint32_t ul_nof_prbs) override
{
return 0;
}
int get_dl_sched(uint32_t tti, dl_sched_list_t& dl_sched_res) override { return 0; }
int get_mch_sched(uint32_t tti, bool is_mcch, dl_sched_list_t& dl_sched_res) override { return 0; }
int get_ul_sched(uint32_t tti, ul_sched_list_t& ul_sched_res) override { return 0; }
void set_sched_dl_tti_mask(uint8_t* tti_mask, uint32_t nof_sfs) override {}
void tti_clock() override {}
};
srsran::phy_common_interface& common;
stack_interface_phy_nr& stack;
srslog::sink& log_sink;
srsran::thread_pool pool;
std::vector<std::unique_ptr<slot_worker> > workers;
prach_worker_pool prach;
uint32_t current_tti = 0; ///< Current TTI, read and write from same thread
srslog::basic_logger& logger;
prach_stack_adaptor_t prach_stack_adaptor;
// Current configuration
std::mutex common_cfg_mutex;
srsran_carrier_nr_t carrier = {};
srsran_pdcch_cfg_nr_t pdcch_cfg = {};
public:
struct args_t {
uint32_t nof_phy_threads = 3;
uint32_t prio = 52;
std::string log_level = "info";
uint32_t log_hex_limit = 64;
std::string log_id_preamble = "";
uint32_t pusch_max_nof_iter = 10;
srsran::phy_log_args_t log = {};
};
slot_worker* operator[](std::size_t pos) { return workers.at(pos).get(); }
@ -58,6 +111,7 @@ public:
slot_worker* wait_worker_id(uint32_t id);
void start_worker(slot_worker* w);
void stop();
int set_common_cfg(const phy_interface_rrc_nr::common_cfg_t& common_cfg);
};
} // namespace nr

@ -1,72 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN 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.
*
* srsRAN 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 SRSGNB_NR_VNF_PHY_H
#define SRSGNB_NR_VNF_PHY_H
#include "srsenb/hdr/phy/enb_phy_base.h"
#include "srsenb/hdr/phy/phy_common.h"
#include "srsran/common/basic_vnf.h"
#include "srsran/interfaces/enb_metrics_interface.h"
#include "srsran/interfaces/gnb_interfaces.h"
#include "srsran/interfaces/radio_interfaces.h"
namespace srsenb {
struct nr_phy_cfg_t {
// TODO: add cell and RRC configs
};
class vnf_phy_nr : public srsenb::enb_phy_base, public srsenb::phy_interface_stack_nr
{
public:
vnf_phy_nr() = default;
~vnf_phy_nr();
int init(const srsenb::phy_args_t& args, const nr_phy_cfg_t& cfg, srsenb::stack_interface_phy_nr* stack_);
void stop() override;
std::string get_type() override { return "vnf"; };
void start_plot() override;
void get_metrics(std::vector<srsenb::phy_metrics_t>& metrics) override;
// MAC interface
int dl_config_request(const dl_config_request_t& request) override;
int tx_request(const tx_request_t& request) override;
void cmd_cell_gain(uint32_t cell_idx, float gain_db) override
{
// Do nothing
}
private:
std::unique_ptr<srsran::srsran_basic_vnf> vnf = nullptr;
bool initialized = false;
void parse_config(const nr_phy_cfg_t& cfg);
};
} // namespace srsenb
#endif // SRSGNB_NR_VNF_PHY_H

@ -86,6 +86,7 @@ public:
int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override;
int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override;
int pusch_info(const srsran_slot_cfg_t& slot_cfg, const pusch_info_t& pusch_info) override;
void rach_detected(const rach_info_t& rach_info) override;
private:
void run_thread() final;

@ -80,12 +80,9 @@ public:
int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override;
int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override;
int pusch_info(const srsran_slot_cfg_t& slot_cfg, const pusch_info_t& pusch_info) override;
void rach_detected(const rach_info_t& rach_info) override;
private:
void get_dl_config(const uint32_t tti,
phy_interface_stack_nr::dl_config_request_t& config_request,
phy_interface_stack_nr::tx_request_t& tx_request);
// PDU processing
int handle_pdu(srsran::unique_byte_buffer_t pdu);

@ -0,0 +1,132 @@
/**
*
* \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_HARQ_SOFTBUFFER_H
#define SRSRAN_HARQ_SOFTBUFFER_H
#include "srsran/adt/pool/pool_interface.h"
#include "srsran/adt/span.h"
extern "C" {
#include "srsran/phy/common/phy_common_nr.h"
#include "srsran/phy/fec/softbuffer.h"
}
namespace srsenb {
class tx_harq_softbuffer
{
public:
tx_harq_softbuffer() { bzero(&buffer, sizeof(buffer)); }
explicit tx_harq_softbuffer(uint32_t nof_prb_) { srsran_softbuffer_tx_init(&buffer, nof_prb_); }
tx_harq_softbuffer(const tx_harq_softbuffer&) = delete;
tx_harq_softbuffer(tx_harq_softbuffer&& other) noexcept
{
memcpy(&buffer, &other.buffer, sizeof(other.buffer));
bzero(&other.buffer, sizeof(other.buffer));
}
tx_harq_softbuffer& operator=(const tx_harq_softbuffer&) = delete;
tx_harq_softbuffer& operator =(tx_harq_softbuffer&& other) noexcept
{
if (this != &other) {
destroy();
memcpy(&buffer, &other.buffer, sizeof(other.buffer));
bzero(&other.buffer, sizeof(other.buffer));
}
return *this;
}
~tx_harq_softbuffer() { destroy(); }
void reset() { srsran_softbuffer_tx_reset(&buffer); }
srsran_softbuffer_tx_t& operator*() { return buffer; }
const srsran_softbuffer_tx_t& operator*() const { return buffer; }
srsran_softbuffer_tx_t* operator->() { return &buffer; }
const srsran_softbuffer_tx_t* operator->() const { return &buffer; }
srsran_softbuffer_tx_t* get() { return &buffer; }
const srsran_softbuffer_tx_t* get() const { return &buffer; }
private:
void destroy() { srsran_softbuffer_tx_free(&buffer); }
srsran_softbuffer_tx_t buffer;
};
class rx_harq_softbuffer
{
public:
rx_harq_softbuffer() { bzero(&buffer, sizeof(buffer)); }
explicit rx_harq_softbuffer(uint32_t nof_prb_) { srsran_softbuffer_rx_init(&buffer, nof_prb_); }
rx_harq_softbuffer(const rx_harq_softbuffer&) = delete;
rx_harq_softbuffer(rx_harq_softbuffer&& other) noexcept
{
memcpy(&buffer, &other.buffer, sizeof(other.buffer));
bzero(&other.buffer, sizeof(other.buffer));
}
rx_harq_softbuffer& operator=(const rx_harq_softbuffer&) = delete;
rx_harq_softbuffer& operator =(rx_harq_softbuffer&& other) noexcept
{
if (this != &other) {
destroy();
memcpy(&buffer, &other.buffer, sizeof(other.buffer));
bzero(&other.buffer, sizeof(other.buffer));
}
return *this;
}
~rx_harq_softbuffer() { destroy(); }
void reset() { srsran_softbuffer_rx_reset(&buffer); }
void reset(uint32_t tbs_bits) { srsran_softbuffer_rx_reset_tbs(&buffer, tbs_bits); }
srsran_softbuffer_rx_t& operator*() { return buffer; }
const srsran_softbuffer_rx_t& operator*() const { return buffer; }
srsran_softbuffer_rx_t* operator->() { return &buffer; }
const srsran_softbuffer_rx_t* operator->() const { return &buffer; }
srsran_softbuffer_rx_t* get() { return &buffer; }
const srsran_softbuffer_rx_t* get() const { return &buffer; }
private:
void destroy() { srsran_softbuffer_rx_free(&buffer); }
srsran_softbuffer_rx_t buffer;
};
class harq_softbuffer_pool
{
public:
harq_softbuffer_pool(const harq_softbuffer_pool&) = delete;
harq_softbuffer_pool(harq_softbuffer_pool&&) = delete;
harq_softbuffer_pool& operator=(const harq_softbuffer_pool&) = delete;
harq_softbuffer_pool& operator=(harq_softbuffer_pool&&) = delete;
void init_pool(uint32_t nof_prb, uint32_t batch_size = MAX_HARQ * 4, uint32_t thres = 0, uint32_t init_size = 0);
srsran::unique_pool_ptr<tx_harq_softbuffer> get_tx(uint32_t nof_prb);
srsran::unique_pool_ptr<rx_harq_softbuffer> get_rx(uint32_t nof_prb);
static harq_softbuffer_pool& get_instance()
{
static harq_softbuffer_pool pool;
return pool;
}
private:
const static uint32_t MAX_HARQ = 16;
harq_softbuffer_pool() = default;
std::array<std::unique_ptr<srsran::obj_pool_itf<tx_harq_softbuffer> >, SRSRAN_MAX_PRB_NR> tx_pool;
std::array<std::unique_ptr<srsran::obj_pool_itf<rx_harq_softbuffer> >, SRSRAN_MAX_PRB_NR> rx_pool;
};
} // namespace srsenb
#endif // SRSRAN_HARQ_SOFTBUFFER_H

@ -22,7 +22,7 @@
#ifndef SRSRAN_SCHED_NR_H
#define SRSRAN_SCHED_NR_H
#include "sched_nr_common.h"
#include "sched_nr_cfg.h"
#include "sched_nr_interface.h"
#include "sched_nr_ue.h"
#include "srsran/adt/pool/cached_alloc.h"
@ -36,9 +36,11 @@ namespace srsenb {
namespace sched_nr_impl {
class sched_worker_manager;
}
class serv_cell_ctxt;
} // namespace sched_nr_impl
class ue_event_manager;
class sched_result_manager;
class sched_nr final : public sched_nr_interface
{
@ -48,17 +50,19 @@ public:
int cell_cfg(srsran::const_span<cell_cfg_t> cell_list) override;
void ue_cfg(uint16_t rnti, const ue_cfg_t& cfg) override;
void slot_indication(tti_point tti_rx) override;
int generate_sched_result(tti_point tti_rx, uint32_t cc, tti_request_t& tti_req) override;
void dl_ack_info(uint16_t rnti, uint32_t cc, uint32_t pid, uint32_t tb_idx, bool ack) override;
void ul_sr_info(tti_point tti_rx, uint16_t rnti) override;
int get_dl_sched(tti_point pdsch_tti, uint32_t cc, dl_sched_t& result) override;
int get_ul_sched(tti_point pdcch_tti, uint32_t cc, ul_sched_t& result) override;
private:
int generate_slot_result(tti_point pdcch_tti, uint32_t cc);
void ue_cfg_impl(uint16_t rnti, const ue_cfg_t& cfg);
// args
sched_nr_impl::sched_params cfg;
srslog::basic_logger& logger;
using sched_worker_manager = sched_nr_impl::sched_worker_manager;
std::unique_ptr<sched_worker_manager> sched_workers;
@ -67,8 +71,14 @@ private:
std::mutex ue_db_mutex;
ue_map_t ue_db;
// management of PHY UE feedback
// management of UE feedback
std::unique_ptr<ue_event_manager> pending_events;
// management of Sched Result buffering
std::unique_ptr<sched_result_manager> pending_results;
// management of cell resources
std::vector<std::unique_ptr<sched_nr_impl::serv_cell_ctxt> > cells;
};
} // namespace srsenb

@ -0,0 +1,78 @@
/**
*
* \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_SCHED_NR_BWP_H
#define SRSRAN_SCHED_NR_BWP_H
#include "sched_nr_cfg.h"
#include "sched_nr_rb_grid.h"
#include "srsran/adt/pool/cached_alloc.h"
namespace srsenb {
namespace sched_nr_impl {
using dl_sched_rar_info_t = sched_nr_interface::dl_sched_rar_info_t;
struct pending_rar_t {
uint16_t ra_rnti = 0;
tti_point prach_tti;
srsran::bounded_vector<dl_sched_rar_info_t, sched_interface::MAX_RAR_LIST> msg3_grant;
};
/// RAR/Msg3 scheduler
class ra_sched
{
public:
explicit ra_sched(const bwp_params& bwp_cfg_);
int dl_rach_info(const dl_sched_rar_info_t& rar_info);
void run_slot(bwp_slot_allocator& slot_grid);
size_t empty() const { return pending_rars.empty(); }
private:
alloc_result
allocate_pending_rar(bwp_slot_allocator& slot_grid, const pending_rar_t& rar, uint32_t& nof_grants_alloc);
const bwp_params* bwp_cfg = nullptr;
srslog::basic_logger& logger;
srsran::deque<pending_rar_t> pending_rars;
};
class bwp_ctxt
{
public:
explicit bwp_ctxt(const bwp_params& bwp_cfg);
const bwp_params* cfg;
// channel-specific schedulers
ra_sched ra;
// Stores pending allocations and PRB bitmaps
bwp_res_grid grid;
};
class serv_cell_ctxt
{
public:
srsran::bounded_vector<bwp_ctxt, SCHED_NR_MAX_BWP_PER_CELL> bwps;
explicit serv_cell_ctxt(const sched_cell_params& cell_cfg_);
const sched_cell_params* cfg;
};
} // namespace sched_nr_impl
} // namespace srsenb
#endif // SRSRAN_SCHED_NR_BWP_H

@ -0,0 +1,190 @@
/**
*
* \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_SCHED_NR_CFG_H
#define SRSRAN_SCHED_NR_CFG_H
#include "sched_nr_interface.h"
#include "sched_nr_rb.h"
namespace srsenb {
const static size_t SCHED_NR_MAX_USERS = 4;
const static size_t SCHED_NR_NOF_SUBFRAMES = 10;
const static size_t SCHED_NR_NOF_HARQS = 16;
static const size_t MAX_NOF_AGGR_LEVELS = 5;
namespace sched_nr_impl {
const static size_t MAX_GRANTS = sched_nr_interface::MAX_GRANTS;
using pucch_t = mac_interface_phy_nr::pucch_t;
using pucch_list_t = srsran::bounded_vector<pucch_t, MAX_GRANTS>;
using pusch_t = mac_interface_phy_nr::pusch_t;
using pusch_list_t = srsran::bounded_vector<pusch_t, MAX_GRANTS>;
using sched_cfg_t = sched_nr_interface::sched_cfg_t;
using cell_cfg_t = sched_nr_interface::cell_cfg_t;
using bwp_cfg_t = sched_nr_interface::bwp_cfg_t;
struct bwp_params {
const uint32_t bwp_id;
const uint32_t cc;
const bwp_cfg_t& cfg;
const cell_cfg_t& cell_cfg;
const sched_cfg_t& sched_cfg;
// derived params
uint32_t P;
uint32_t N_rbg;
bwp_params(const cell_cfg_t& cell, const sched_cfg_t& sched_cfg_, uint32_t cc, uint32_t bwp_id);
};
struct sched_cell_params {
const uint32_t cc;
const cell_cfg_t cell_cfg;
const sched_cfg_t& sched_cfg;
std::vector<bwp_params> bwps;
sched_cell_params(uint32_t cc_, const cell_cfg_t& cell, const sched_cfg_t& sched_cfg_);
uint32_t nof_prb() const { return cell_cfg.carrier.nof_prb; }
};
struct sched_params {
const sched_cfg_t sched_cfg;
std::vector<sched_cell_params> cells;
explicit sched_params(const sched_cfg_t& sched_cfg_);
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
using prb_bitmap = srsran::bounded_bitset<SRSRAN_MAX_PRB_NR, true>;
using rbgmask_t = srsran::bounded_bitset<SCHED_NR_MAX_NOF_RBGS, true>;
using pdcchmask_t = srsran::bounded_bitset<SCHED_NR_MAX_NOF_RBGS, true>;
using pdcch_cce_pos_list = srsran::bounded_vector<uint32_t, SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR>;
using bwp_cce_pos_list = std::array<std::array<pdcch_cce_pos_list, MAX_NOF_AGGR_LEVELS>, SRSRAN_NOF_SF_X_FRAME>;
void get_dci_locs(const srsran_coreset_t& coreset,
const srsran_search_space_t& search_space,
uint16_t rnti,
bwp_cce_pos_list& cce_locs);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
using ue_cfg_t = sched_nr_interface::ue_cfg_t;
using ue_cc_cfg_t = sched_nr_interface::ue_cc_cfg_t;
class bwp_ue_cfg
{
public:
bwp_ue_cfg() = default;
explicit bwp_ue_cfg(uint16_t rnti, const bwp_params& bwp_cfg, const ue_cfg_t& uecfg_);
const ue_cfg_t* ue_cfg() const { return cfg_; }
const srsran::phy_cfg_nr_t& phy() const { return cfg_->phy_cfg; }
const bwp_params& active_bwp() const { return *bwp_cfg; }
const bwp_cce_pos_list& cce_pos_list(uint32_t search_id) const
{
return cce_positions_list[ss_id_to_cce_idx[search_id]];
}
private:
uint16_t rnti = SRSRAN_INVALID_RNTI;
const ue_cfg_t* cfg_ = nullptr;
const bwp_params* bwp_cfg = nullptr;
std::vector<bwp_cce_pos_list> cce_positions_list;
std::array<uint32_t, SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE> ss_id_to_cce_idx;
};
class ue_cfg_extended : public ue_cfg_t
{
public:
struct search_space_params {
const srsran_search_space_t* cfg;
bwp_cce_pos_list cce_positions;
};
struct coreset_params {
srsran_coreset_t* cfg = nullptr;
std::vector<uint32_t> ss_list;
};
struct bwp_params {
std::array<srsran::optional<search_space_params>, SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE> ss_list;
std::vector<coreset_params> coresets;
};
struct cc_params {
srsran::bounded_vector<bwp_params, SCHED_NR_MAX_BWP_PER_CELL> bwps;
};
ue_cfg_extended() = default;
explicit ue_cfg_extended(uint16_t rnti, const ue_cfg_t& uecfg);
const bwp_cce_pos_list& get_dci_pos_list(uint32_t cc, uint32_t bwp_id, uint32_t search_space_id) const
{
return cc_params[cc].bwps[bwp_id].ss_list[search_space_id]->cce_positions;
}
uint16_t rnti;
std::vector<cc_params> cc_params;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct resource_guard {
public:
resource_guard() = default;
resource_guard(const resource_guard& other) = delete;
resource_guard(resource_guard&& other) = delete;
resource_guard& operator=(const resource_guard& other) = delete;
resource_guard& operator=(resource_guard&& other) = delete;
bool busy() const { return flag; }
struct token {
token() = default;
token(resource_guard& parent) : flag(parent.busy() ? nullptr : &parent.flag)
{
if (flag != nullptr) {
*flag = true;
}
}
token(token&&) noexcept = default;
token& operator=(token&&) noexcept = default;
void release() { flag.reset(); }
bool owns_token() const { return flag != nullptr; }
bool empty() const { return flag == nullptr; }
private:
struct release_deleter {
void operator()(bool* ptr)
{
if (ptr != nullptr) {
srsran_assert(*ptr == true, "resource token: detected inconsistency token state");
*ptr = false;
}
}
};
std::unique_ptr<bool, release_deleter> flag;
};
private:
bool flag = false;
};
} // namespace sched_nr_impl
} // namespace srsenb
#endif // SRSRAN_SCHED_NR_CFG_H

@ -1,111 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN 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.
*
* srsRAN 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 SRSRAN_SCHED_NR_COMMON_H
#define SRSRAN_SCHED_NR_COMMON_H
#include "sched_nr_interface.h"
#include "srsran/adt/bounded_bitset.h"
namespace srsenb {
const static size_t SCHED_NR_MAX_USERS = 4;
const static size_t SCHED_NR_NOF_SUBFRAMES = 10;
const static size_t SCHED_NR_NOF_HARQS = 16;
static const size_t MAX_NOF_AGGR_LEVELS = 5;
namespace sched_nr_impl {
const static size_t MAX_GRANTS = sched_nr_interface::MAX_GRANTS;
using sched_cfg_t = sched_nr_interface::sched_cfg_t;
using cell_cfg_t = sched_nr_interface::cell_cfg_t;
struct sched_cell_params {
const uint32_t cc;
const cell_cfg_t cell_cfg;
const sched_cfg_t& sched_cfg;
sched_cell_params(uint32_t cc_, const cell_cfg_t& cell, const sched_cfg_t& sched_cfg_);
};
struct sched_params {
const sched_cfg_t sched_cfg;
std::vector<sched_cell_params> cells;
explicit sched_params(const sched_cfg_t& sched_cfg_);
};
using pdcchmask_t = srsran::bounded_bitset<SCHED_NR_MAX_NOF_RBGS, true>;
using rbgmask_t = srsran::bounded_bitset<SCHED_NR_MAX_NOF_RBGS, true>;
struct resource_guard {
public:
resource_guard() = default;
resource_guard(const resource_guard& other) = delete;
resource_guard(resource_guard&& other) = delete;
resource_guard& operator=(const resource_guard& other) = delete;
resource_guard& operator=(resource_guard&& other) = delete;
bool busy() const { return flag; }
struct token {
token() = default;
token(resource_guard& parent) : flag(parent.busy() ? nullptr : &parent.flag)
{
if (flag != nullptr) {
*flag = true;
}
}
token(token&&) noexcept = default;
token& operator=(token&&) noexcept = default;
void release() { flag.reset(); }
bool owns_token() const { return flag != nullptr; }
bool empty() const { return flag == nullptr; }
private:
struct release_deleter {
void operator()(bool* ptr)
{
if (ptr != nullptr) {
srsran_assert(*ptr == true, "resource token: detected inconsistency token state");
*ptr = false;
}
}
};
std::unique_ptr<bool, release_deleter> flag;
};
private:
bool flag = false;
};
using pdcch_cce_pos_list = srsran::bounded_vector<uint32_t, SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR>;
using bwp_cce_pos_list = std::array<std::array<pdcch_cce_pos_list, MAX_NOF_AGGR_LEVELS>, SRSRAN_NOF_SF_X_FRAME>;
void get_dci_locs(const srsran_coreset_t& coreset,
const srsran_search_space_t& search_space,
uint16_t rnti,
bwp_cce_pos_list& cce_locs);
} // namespace sched_nr_impl
} // namespace srsenb
#endif // SRSRAN_SCHED_NR_COMMON_H

@ -22,7 +22,8 @@
#ifndef SRSRAN_SCHED_NR_HARQ_H
#define SRSRAN_SCHED_NR_HARQ_H
#include "sched_nr_common.h"
#include "sched_nr_cfg.h"
#include "srsenb/hdr/stack/mac/nr/harq_softbuffer.h"
#include "srsran/common/tti_point.h"
#include <array>
@ -45,14 +46,20 @@ public:
uint32_t tbs() const { return tb[0].tbs; }
uint32_t ndi() const { return tb[0].ndi; }
uint32_t mcs() const { return tb[0].mcs; }
const prb_grant& prbs() const { return prbs_; }
tti_point harq_tti_ack() const { return tti_ack; }
bool ack_info(uint32_t tb_idx, bool ack);
void new_tti(tti_point tti_rx);
void reset();
bool
new_tx(tti_point tti_tx, tti_point tti_ack, const rbgmask_t& rbgmask, uint32_t mcs, uint32_t tbs, uint32_t max_retx);
bool new_retx(tti_point tti_tx, tti_point tti_ack, const rbgmask_t& rbgmask, int* mcs, int* tbs);
new_tx(tti_point tti_tx, tti_point tti_ack, const prb_grant& grant, uint32_t mcs, uint32_t tbs, uint32_t max_retx);
bool new_retx(tti_point tti_tx, tti_point tti_ack, const prb_grant& grant);
bool new_retx(tti_point tti_tx, tti_point tti_ack);
// NOTE: Has to be used before first tx is dispatched
bool set_tbs(uint32_t tbs);
const uint32_t pid;
@ -69,27 +76,59 @@ private:
uint32_t max_retx = 1;
tti_point tti_tx;
tti_point tti_ack;
rbgmask_t rbgmask;
prb_grant prbs_;
std::array<tb_t, SCHED_NR_MAX_TB> tb;
};
class dl_harq_proc : public harq_proc
{
public:
dl_harq_proc(uint32_t id_, uint32_t nprb) :
harq_proc(id_), softbuffer(harq_softbuffer_pool::get_instance().get_tx(nprb))
{}
tx_harq_softbuffer& get_softbuffer() { return *softbuffer; }
private:
srsran::unique_pool_ptr<tx_harq_softbuffer> softbuffer;
};
class ul_harq_proc : public harq_proc
{
public:
ul_harq_proc(uint32_t id_, uint32_t nprb) :
harq_proc(id_), softbuffer(harq_softbuffer_pool::get_instance().get_rx(nprb))
{}
rx_harq_softbuffer& get_softbuffer() { return *softbuffer; }
bool set_tbs(uint32_t tbs)
{
softbuffer->reset(tbs * 8u);
return harq_proc::set_tbs(tbs);
}
private:
srsran::unique_pool_ptr<rx_harq_softbuffer> softbuffer;
};
class harq_entity
{
public:
explicit harq_entity(uint32_t nof_harq_procs = SCHED_NR_MAX_HARQ);
explicit harq_entity(uint32_t nprb, uint32_t nof_harq_procs = SCHED_NR_MAX_HARQ);
void new_tti(tti_point tti_rx_);
void dl_ack_info(uint32_t pid, uint32_t tb_idx, bool ack) { dl_harqs[pid].ack_info(tb_idx, ack); }
harq_proc* find_pending_dl_retx()
dl_harq_proc* find_pending_dl_retx()
{
return find_dl([this](const harq_proc& h) { return h.has_pending_retx(tti_rx); });
return find_dl([this](const dl_harq_proc& h) { return h.has_pending_retx(tti_rx); });
}
harq_proc* find_pending_ul_retx()
{
return find_ul([this](const harq_proc& h) { return h.has_pending_retx(tti_rx); });
}
harq_proc* find_empty_dl_harq()
dl_harq_proc* find_empty_dl_harq()
{
return find_dl([](const harq_proc& h) { return h.empty(); });
}
@ -100,7 +139,7 @@ public:
private:
template <typename Predicate>
harq_proc* find_dl(Predicate p)
dl_harq_proc* find_dl(Predicate p)
{
auto it = std::find_if(dl_harqs.begin(), dl_harqs.end(), p);
return (it == dl_harqs.end()) ? nullptr : &(*it);
@ -113,8 +152,8 @@ private:
}
tti_point tti_rx;
std::vector<harq_proc> dl_harqs;
std::vector<harq_proc> ul_harqs;
std::vector<dl_harq_proc> dl_harqs;
std::vector<ul_harq_proc> ul_harqs;
};
} // namespace sched_nr_impl

@ -0,0 +1,44 @@
/**
*
* \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_SCHED_NR_HELPERS_H
#define SRSRAN_SCHED_NR_HELPERS_H
#include "sched_nr_cfg.h"
namespace srsenb {
namespace sched_nr_impl {
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool fill_dci_rar(prb_interval interv, const bwp_params& bwp_cfg, srsran_dci_dl_nr_t& dci);
class slot_ue;
/// Generate PDCCH DL DCI fields
void fill_dl_dci_ue_fields(const slot_ue& ue,
const bwp_params& bwp_cfg,
uint32_t ss_id,
srsran_dci_location_t dci_pos,
srsran_dci_dl_nr_t& dci);
/// Generate PDCCH UL DCI fields
void fill_ul_dci_ue_fields(const slot_ue& ue,
const bwp_params& bwp_cfg,
uint32_t ss_id,
srsran_dci_location_t dci_pos,
srsran_dci_ul_nr_t& dci);
} // namespace sched_nr_impl
} // namespace srsenb
#endif // SRSRAN_SCHED_NR_HELPERS_H

@ -24,6 +24,7 @@
#include "srsran/adt/bounded_bitset.h"
#include "srsran/adt/bounded_vector.h"
#include "srsran/adt/optional.h"
#include "srsran/adt/span.h"
#include "srsran/common/phy_cfg_nr.h"
#include "srsran/common/tti_point.h"
@ -34,18 +35,15 @@ namespace srsenb {
const static size_t SCHED_NR_MAX_CARRIERS = 4;
const static uint16_t SCHED_NR_INVALID_RNTI = 0;
const static size_t SCHED_NR_MAX_PDSCH_DATA = 16;
const static size_t SCHED_NR_MAX_NOF_RBGS = 25;
const static size_t SCHED_NR_MAX_UL_ALLOCS = 16;
const static size_t SCHED_NR_MAX_NOF_RBGS = 18;
const static size_t SCHED_NR_MAX_TB = 1;
const static size_t SCHED_NR_MAX_HARQ = 16;
const static size_t SCHED_NR_MAX_BWP_PER_CELL = 1;
const static size_t SCHED_NR_MAX_BWP_PER_CELL = 2;
class sched_nr_interface
{
public:
using pdcch_bitmap = srsran::bounded_bitset<SCHED_NR_MAX_NOF_RBGS, true>;
using rbg_bitmap = srsran::bounded_bitset<SCHED_NR_MAX_NOF_RBGS, true>;
static const size_t MAX_GRANTS = mac_interface_phy_nr::MAX_GRANTS;
///// Configuration /////
@ -53,21 +51,25 @@ public:
uint8_t k0 = 0; // 0..32
uint8_t k1 = 4; // 0..32
};
using pdsch_td_res_alloc_list = srsran::bounded_vector<pdsch_td_res_alloc, SCHED_NR_MAX_UL_ALLOCS>;
using pdsch_td_res_alloc_list = srsran::bounded_vector<pdsch_td_res_alloc, MAX_GRANTS>;
struct pusch_td_res_alloc {
uint8_t k2 = 4; // 0..32
};
using pusch_td_res_alloc_list = srsran::bounded_vector<pusch_td_res_alloc, SCHED_NR_MAX_UL_ALLOCS>;
using pusch_td_res_alloc_list = srsran::bounded_vector<pusch_td_res_alloc, MAX_GRANTS>;
struct bwp_cfg_t {
uint32_t start_rb = 0;
uint32_t rb_width = 100;
srsran_pdcch_cfg_nr_t pdcch = {};
srsran_sch_hl_cfg_nr_t pdsch = {};
srsran_sch_hl_cfg_nr_t pusch = {};
uint32_t rar_window_size = 3;
};
struct cell_cfg_t {
uint32_t nof_prb = 100;
uint32_t nof_rbg = 25;
srsran::bounded_vector<bwp_cfg_t, SCHED_NR_MAX_BWP_PER_CELL> bwps{1};
srsran_carrier_nr_t carrier = {};
srsran_tdd_config_nr_t tdd = {};
srsran::bounded_vector<bwp_cfg_t, SCHED_NR_MAX_BWP_PER_CELL> bwps{1}; // idx0 for BWP-common
};
struct sched_cfg_t {
@ -76,8 +78,7 @@ public:
struct ue_cc_cfg_t {
bool active = false;
pdsch_td_res_alloc_list pdsch_res_list{1};
pusch_td_res_alloc_list pusch_res_list{1};
uint32_t cc = 0;
};
struct ue_cfg_t {
@ -86,47 +87,26 @@ public:
srsran::phy_cfg_nr_t phy_cfg = {};
};
///// Sched Result /////
const static int MAX_GRANTS = 64;
using pdcch_dl_t = mac_interface_phy_nr::pdcch_dl_t;
using pdcch_ul_t = mac_interface_phy_nr::pdcch_ul_t;
using pdcch_dl_list_t = srsran::bounded_vector<pdcch_dl_t, MAX_GRANTS>;
using pdcch_ul_list_t = srsran::bounded_vector<pdcch_ul_t, MAX_GRANTS>;
struct pdsch_t {
srsran_sch_cfg_nr_t sch = {}; ///< PDSCH configuration
};
using pdsch_list_t = srsran::bounded_vector<pdsch_t, SCHED_NR_MAX_PDSCH_DATA>;
////// RACH //////
struct dl_tti_request_t {
tti_point pdsch_tti;
pdcch_dl_list_t pdcchs;
pdsch_list_t pdschs;
struct dl_sched_rar_info_t {
uint32_t preamble_idx;
uint32_t ta_cmd;
uint16_t temp_crnti;
uint32_t msg3_size;
uint32_t prach_tti;
};
struct pusch_grant {
srsran_dci_ul_nr_t dci;
rbg_bitmap bitmap;
};
using pusch_list = srsran::bounded_vector<pusch_grant, SCHED_NR_MAX_PDSCH_DATA>;
struct ul_tti_request_t {
tti_point pusch_tti;
srsran::bounded_vector<pusch_grant, SCHED_NR_MAX_UL_ALLOCS> pusch;
};
///// Sched Result /////
struct tti_request_t {
dl_tti_request_t dl_res;
ul_tti_request_t ul_res;
};
using dl_sched_t = mac_interface_phy_nr::dl_sched_t;
using ul_sched_t = mac_interface_phy_nr::ul_sched_t;
virtual ~sched_nr_interface() = default;
virtual int cell_cfg(srsran::const_span<sched_nr_interface::cell_cfg_t> ue_cfg) = 0;
virtual void ue_cfg(uint16_t rnti, const ue_cfg_t& ue_cfg) = 0;
virtual void slot_indication(tti_point tti_rx) = 0;
virtual int generate_sched_result(tti_point tti_rx, uint32_t cc, tti_request_t& result) = 0;
virtual int get_dl_sched(tti_point tti_rx, uint32_t cc, dl_sched_t& result) = 0;
virtual int get_ul_sched(tti_point tti_rx, uint32_t cc, ul_sched_t& result) = 0;
virtual void dl_ack_info(uint16_t rnti, uint32_t cc, uint32_t pid, uint32_t tb_idx, bool ack) = 0;
virtual void ul_sr_info(tti_point, uint16_t rnti) = 0;

@ -22,7 +22,7 @@
#ifndef SRSRAN_SCHED_NR_PDCCH_H
#define SRSRAN_SCHED_NR_PDCCH_H
#include "srsenb/hdr/stack/mac/nr/sched_nr_common.h"
#include "srsenb/hdr/stack/mac/nr/sched_nr_cfg.h"
#include "srsran/adt/bounded_bitset.h"
#include "srsran/adt/bounded_vector.h"
#include "srsran/phy/common/phy_common_nr.h"
@ -34,23 +34,24 @@ namespace sched_nr_impl {
using coreset_bitmap = srsran::bounded_bitset<SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE * SRSRAN_CORESET_DURATION_MAX, true>;
enum class pdcch_grant_type_t { sib, dl_data, ul_data };
enum class pdcch_grant_type_t { sib, rar, dl_data, ul_data };
class slot_ue;
using pdcch_dl_t = sched_nr_interface::pdcch_dl_t;
using pdcch_dl_list_t = sched_nr_interface::pdcch_dl_list_t;
using pdcch_ul_t = sched_nr_interface::pdcch_ul_t;
using pdcch_ul_list_t = sched_nr_interface::pdcch_ul_list_t;
using bwp_cfg_t = sched_nr_interface::bwp_cfg_t;
using pdcch_dl_t = mac_interface_phy_nr::pdcch_dl_t;
using pdcch_ul_t = mac_interface_phy_nr::pdcch_ul_t;
using pdcch_dl_list_t = srsran::bounded_vector<pdcch_dl_t, MAX_GRANTS>;
using pdcch_ul_list_t = srsran::bounded_vector<pdcch_ul_t, MAX_GRANTS>;
class coreset_region
{
public:
coreset_region(uint32_t bwp_id_,
coreset_region(const bwp_params& bwp_cfg_,
uint32_t coreset_id_,
uint32_t slot_idx,
uint32_t nof_td_symbols,
uint32_t nof_freq_resources,
pdcch_dl_list_t& pdcch_list);
pdcch_dl_list_t& pdcch_dl_list,
pdcch_ul_list_t& pdcch_ul_list);
void reset();
/**
@ -60,31 +61,32 @@ public:
* @param user UE object or null in case of broadcast/RAR/paging allocation
* @return if the allocation was successful
*/
bool alloc_dci(pdcch_grant_type_t alloc_type, uint32_t aggr_idx, uint32_t coreset_id, slot_ue* user = nullptr);
bool alloc_dci(pdcch_grant_type_t alloc_type, uint32_t aggr_idx, uint32_t search_space_id, slot_ue* user = nullptr);
void rem_last_dci();
uint32_t get_td_symbols() const { return nof_symbols; }
uint32_t get_td_symbols() const { return coreset_cfg->duration; }
uint32_t get_freq_resources() const { return nof_freq_res; }
uint32_t nof_cces() const { return nof_freq_res * nof_symbols; }
uint32_t nof_cces() const { return nof_freq_res * get_td_symbols(); }
size_t nof_allocs() const { return dfs_tree.size(); }
private:
uint32_t bwp_id;
const srsran_coreset_t* coreset_cfg;
uint32_t coreset_id;
uint32_t slot_idx;
uint32_t nof_symbols;
uint32_t nof_freq_res;
uint32_t nof_freq_res = 0;
// List of PDCCH grants
struct alloc_record {
uint32_t coreset_id;
uint32_t aggr_idx;
uint32_t ss_id;
uint32_t idx;
pdcch_grant_type_t alloc_type;
slot_ue* ue;
};
srsran::bounded_vector<alloc_record, MAX_GRANTS> dci_list;
pdcch_dl_list_t& pdcch_dl_list;
pdcch_ul_list_t& pdcch_ul_list;
// DFS decision tree of PDCCH grants
struct tree_node {

@ -1,42 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN 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.
*
* srsRAN 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 SRSRAN_SCHED_NR_PHY_HELPERS_H
#define SRSRAN_SCHED_NR_PHY_HELPERS_H
#include "sched_nr_common.h"
namespace srsenb {
namespace sched_nr_impl {
uint32_t get_P(uint32_t bwp_nof_prb, bool config_1_or_2);
uint32_t get_nof_rbgs(uint32_t bwp_nof_prb, uint32_t bwp_start, bool config1_or_2);
void bitmap_to_prb_array(const rbgmask_t& bitmap, uint32_t bwp_nof_prb, srsran_sch_grant_nr_t& grant);
class slot_ue;
void fill_dci_ue_cfg(const slot_ue& ue, srsran_dci_dl_nr_t& dci);
void fill_dci_ue_cfg(const slot_ue& ue, srsran_dci_ul_nr_t& dci);
} // namespace sched_nr_impl
} // namespace srsenb
#endif // SRSRAN_SCHED_NR_PHY_HELPERS_H

@ -0,0 +1,237 @@
/**
*
* \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_SCHED_NR_RB_H
#define SRSRAN_SCHED_NR_RB_H
#include "srsenb/hdr/stack/mac/nr/sched_nr_interface.h"
#include "srsran/adt/bounded_bitset.h"
#include "srsran/phy/common/phy_common_nr.h"
namespace srsenb {
namespace sched_nr_impl {
using prb_bitmap = srsran::bounded_bitset<SRSRAN_MAX_PRB_NR, true>;
using rbg_bitmap = srsran::bounded_bitset<SCHED_NR_MAX_NOF_RBGS, true>;
/// TS 38.214, Table 6.1.2.2.1-1 - Nominal RBG size P
uint32_t get_P(uint32_t bwp_nof_prb, bool config_1_or_2);
/// TS 38.214 - total number of RBGs for a uplink bandwidth part of size "bwp_nof_prb" PRBs
uint32_t get_nof_rbgs(uint32_t bwp_nof_prb, uint32_t bwp_start, bool config1_or_2);
/// Struct to express a {min,...,max} range of PRBs
struct prb_interval : public srsran::interval<uint32_t> {
using interval::interval;
};
struct prb_grant {
prb_grant() = default;
prb_grant(const prb_interval& other) noexcept : alloc_type_0(false), alloc(other) {}
prb_grant(const rbg_bitmap& other) noexcept : alloc_type_0(true), alloc(other) {}
prb_grant(const prb_grant& other) noexcept : alloc_type_0(other.alloc_type_0), alloc(other.alloc_type_0, other.alloc)
{}
prb_grant& operator=(const prb_grant& other) noexcept
{
if (this == &other) {
return *this;
}
if (other.alloc_type_0) {
*this = other.rbgs();
} else {
*this = other.prbs();
}
return *this;
}
prb_grant& operator=(const prb_interval& prbs)
{
if (alloc_type_0) {
alloc_type_0 = false;
alloc.rbgs.~rbg_bitmap();
new (&alloc.interv) prb_interval(prbs);
} else {
alloc.interv = alloc.interv;
}
return *this;
}
prb_grant& operator=(const rbg_bitmap& rbgs)
{
if (alloc_type_0) {
alloc.rbgs = rbgs;
} else {
alloc_type_0 = true;
alloc.interv.~prb_interval();
new (&alloc.rbgs) rbg_bitmap(rbgs);
}
return *this;
}
~prb_grant()
{
if (is_alloc_type0()) {
alloc.rbgs.~rbg_bitmap();
} else {
alloc.interv.~prb_interval();
}
}
bool is_alloc_type0() const { return alloc_type_0; }
bool is_alloc_type1() const { return not is_alloc_type0(); }
const rbg_bitmap& rbgs() const
{
srsran_assert(is_alloc_type0(), "Invalid access to rbgs() field of grant with alloc type 1");
return alloc.rbgs;
}
const prb_interval& prbs() const
{
srsran_assert(is_alloc_type1(), "Invalid access to prbs() field of grant with alloc type 0");
return alloc.interv;
}
rbg_bitmap& rbgs()
{
srsran_assert(is_alloc_type0(), "Invalid access to rbgs() field of grant with alloc type 1");
return alloc.rbgs;
}
prb_interval& prbs()
{
srsran_assert(is_alloc_type1(), "Invalid access to prbs() field of grant with alloc type 0");
return alloc.interv;
}
private:
bool alloc_type_0 = false;
union alloc_t {
rbg_bitmap rbgs;
prb_interval interv;
alloc_t() : interv(0, 0) {}
explicit alloc_t(const prb_interval& prbs) : interv(prbs) {}
explicit alloc_t(const rbg_bitmap& rbgs_) : rbgs(rbgs_) {}
alloc_t(bool type0, const alloc_t& other)
{
if (type0) {
new (&rbgs) rbg_bitmap(other.rbgs);
} else {
new (&interv) prb_interval(other.interv);
}
}
} alloc;
};
struct bwp_rb_bitmap {
public:
bwp_rb_bitmap() = default;
bwp_rb_bitmap(uint32_t bwp_nof_prbs, uint32_t bwp_prb_start_, bool config1_or_2);
void reset()
{
prbs_.reset();
rbgs_.reset();
}
template <typename T>
void operator|=(const T& grant)
{
add(grant);
}
void add(const prb_interval& prbs)
{
prbs_.fill(prbs.start(), prbs.stop());
add_prbs_to_rbgs(prbs);
}
void add(const prb_bitmap& grant)
{
prbs_ |= grant;
add_prbs_to_rbgs(grant);
}
void add(const rbg_bitmap& grant)
{
rbgs_ |= grant;
add_rbgs_to_prbs(grant);
}
void add(const prb_grant& grant)
{
if (grant.is_alloc_type0()) {
add(grant.rbgs());
} else {
add(grant.prbs());
}
}
bool collides(const prb_grant& grant) const
{
if (grant.is_alloc_type0()) {
return (rbgs() & grant.rbgs()).any();
}
return prbs().any(grant.prbs().start(), grant.prbs().stop());
}
bool test(uint32_t prb_idx) { return prbs().test(prb_idx); }
void set(uint32_t prb_idx)
{
prbs_.set(prb_idx);
rbgs_.set(prb_to_rbg_idx(prb_idx));
}
const prb_bitmap& prbs() const { return prbs_; }
const rbg_bitmap& rbgs() const { return rbgs_; }
uint32_t P() const { return P_; }
uint32_t nof_prbs() const { return prbs_.size(); }
uint32_t nof_rbgs() const { return rbgs_.size(); }
uint32_t prb_to_rbg_idx(uint32_t prb_idx) const;
private:
prb_bitmap prbs_;
rbg_bitmap rbgs_;
uint32_t P_ = 0;
uint32_t Pnofbits = 0;
uint32_t first_rbg_size = 0;
void add_prbs_to_rbgs(const prb_bitmap& grant);
void add_prbs_to_rbgs(const prb_interval& grant);
void add_rbgs_to_prbs(const rbg_bitmap& grant);
};
inline prb_interval
find_next_empty_interval(const prb_bitmap& mask, size_t start_prb_idx = 0, size_t last_prb_idx = SRSRAN_MAX_PRB_NR)
{
int rb_start = mask.find_lowest(start_prb_idx, std::min(mask.size(), last_prb_idx), false);
if (rb_start != -1) {
int rb_end = mask.find_lowest(rb_start + 1, std::min(mask.size(), last_prb_idx), true);
return {(uint32_t)rb_start, (uint32_t)(rb_end < 0 ? mask.size() : rb_end)};
}
return {};
}
inline prb_interval find_empty_interval_of_length(const prb_bitmap& mask, size_t nof_prbs, uint32_t start_prb_idx = 0)
{
prb_interval max_interv;
do {
prb_interval interv = find_next_empty_interval(mask, start_prb_idx, mask.size());
if (interv.empty()) {
break;
}
if (interv.length() >= nof_prbs) {
max_interv.set(interv.start(), interv.start() + nof_prbs);
break;
}
if (interv.length() > max_interv.length()) {
max_interv = interv;
}
start_prb_idx = interv.stop() + 1;
} while (start_prb_idx < mask.size());
return max_interv;
}
} // namespace sched_nr_impl
} // namespace srsenb
#endif // SRSRAN_SCHED_NR_RB_H

@ -24,6 +24,7 @@
#include "../sched_common.h"
#include "lib/include/srsran/adt/circular_array.h"
#include "sched_nr_helpers.h"
#include "sched_nr_interface.h"
#include "sched_nr_pdcch.h"
#include "sched_nr_ue.h"
@ -31,71 +32,76 @@
namespace srsenb {
namespace sched_nr_impl {
using pdsch_bitmap = srsran::bounded_bitset<25, true>;
using pusch_bitmap = srsran::bounded_bitset<25, true>;
struct pending_rar_t;
using pdsch_t = sched_nr_interface::pdsch_t;
using pdsch_list_t = sched_nr_interface::pdsch_list_t;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
using pusch_list = sched_nr_interface::pusch_list;
const static size_t MAX_CORESET_PER_BWP = 3;
using slot_coreset_list = std::array<srsran::optional<coreset_region>, MAX_CORESET_PER_BWP>;
struct pucch_t {};
using pdsch_t = mac_interface_phy_nr::pdsch_t;
using pdsch_list_t = srsran::bounded_vector<pdsch_t, MAX_GRANTS>;
const static size_t MAX_CORESET_PER_BWP = 3;
using slot_coreset_list = srsran::bounded_vector<coreset_region, MAX_CORESET_PER_BWP>;
struct harq_ack_t {
const srsran::phy_cfg_nr_t* phy_cfg;
srsran_harq_ack_resource_t res;
};
using harq_ack_list_t = srsran::bounded_vector<harq_ack_t, MAX_GRANTS>;
struct bwp_slot_grid {
pdcch_dl_list_t pdcch_dl_list;
pdcch_ul_list_t pdcch_ul_list;
uint32_t slot_idx;
const bwp_params* cfg;
bool is_dl, is_ul;
bwp_rb_bitmap dl_prbs;
bwp_rb_bitmap ul_prbs;
pdcch_dl_list_t dl_pdcchs;
pdcch_ul_list_t ul_pdcchs;
pdsch_list_t pdschs;
slot_coreset_list coresets;
pdsch_bitmap dl_rbgs;
pdsch_list_t pdsch_grants;
pusch_bitmap ul_rbgs;
pusch_list pusch_grants;
srsran::bounded_vector<pucch_t, SCHED_NR_MAX_PDSCH_DATA> pucch_grants;
pusch_list_t puschs;
harq_ack_list_t pending_acks;
bwp_slot_grid() = default;
explicit bwp_slot_grid(const sched_cell_params& cell_params, uint32_t bwp_id_, uint32_t slot_idx_);
explicit bwp_slot_grid(const bwp_params& bwp_params, uint32_t slot_idx_);
void reset();
};
struct bwp_res_grid {
bwp_res_grid(const sched_cell_params& cell_cfg_, uint32_t bwp_id_);
bwp_res_grid(const bwp_params& bwp_cfg_);
bwp_slot_grid& operator[](tti_point tti) { return slots[tti.sf_idx()]; };
const bwp_slot_grid& operator[](tti_point tti) const { return slots[tti.sf_idx()]; };
uint32_t id() const { return bwp_id; }
uint32_t nof_prbs() const { return cell_cfg->cell_cfg.nof_prb; }
bwp_slot_grid& operator[](tti_point tti) { return slots[tti.to_uint() % slots.capacity()]; };
const bwp_slot_grid& operator[](tti_point tti) const { return slots[tti.to_uint() % slots.capacity()]; };
uint32_t id() const { return cfg->bwp_id; }
uint32_t nof_prbs() const { return cfg->cfg.rb_width; }
private:
uint32_t bwp_id;
const sched_cell_params* cell_cfg = nullptr;
const bwp_params* cfg = nullptr;
private:
srsran::bounded_vector<bwp_slot_grid, TTIMOD_SZ> slots;
};
struct cell_res_grid {
const sched_cell_params* cell_cfg = nullptr;
srsran::bounded_vector<bwp_res_grid, SCHED_NR_MAX_BWP_PER_CELL> bwps;
explicit cell_res_grid(const sched_cell_params& cell_cfg);
};
class slot_bwp_sched
class bwp_slot_allocator
{
public:
explicit slot_bwp_sched(uint32_t bwp_id, cell_res_grid& phy_grid_);
explicit bwp_slot_allocator(bwp_res_grid& bwp_grid_);
alloc_result alloc_pdsch(slot_ue& ue, const rbgmask_t& dl_mask);
void new_slot(tti_point pdcch_tti_) { pdcch_tti = pdcch_tti_; }
alloc_result alloc_rar(uint32_t aggr_idx, const pending_rar_t& rar, prb_interval interv, uint32_t max_nof_grants);
alloc_result alloc_pdsch(slot_ue& ue, const prb_grant& dl_grant);
alloc_result alloc_pusch(slot_ue& ue, const rbgmask_t& dl_mask);
const sched_cell_params& cfg;
tti_point get_pdcch_tti() const { return pdcch_tti; }
const bwp_res_grid& res_grid() const { return bwp_grid; }
const bwp_params& cfg;
private:
srslog::basic_logger& logger;
bwp_res_grid& bwp_grid;
tti_point tti_rx;
tti_point pdcch_tti;
};
} // namespace sched_nr_impl

@ -22,7 +22,7 @@
#ifndef SRSRAN_SCHED_NR_UE_H
#define SRSRAN_SCHED_NR_UE_H
#include "sched_nr_common.h"
#include "sched_nr_cfg.h"
#include "sched_nr_harq.h"
#include "sched_nr_interface.h"
#include "srsran/adt/circular_map.h"
@ -33,35 +33,6 @@ namespace srsenb {
namespace sched_nr_impl {
using ue_cfg_t = sched_nr_interface::ue_cfg_t;
using ue_cc_cfg_t = sched_nr_interface::ue_cc_cfg_t;
class ue_cfg_extended : public ue_cfg_t
{
public:
struct search_space_params {
srsran_search_space_t* cfg = nullptr;
};
struct coreset_params {
srsran_coreset_t* cfg = nullptr;
std::vector<search_space_params*> ss_list;
bwp_cce_pos_list cce_positions;
};
struct bwp_params {
std::vector<search_space_params> search_spaces;
std::vector<coreset_params> coresets;
};
struct cc_params {
srsran::bounded_vector<bwp_params, SCHED_NR_MAX_BWP_PER_CELL> bwps;
};
uint16_t rnti;
std::vector<cc_params> cc_params;
ue_cfg_extended() = default;
explicit ue_cfg_extended(uint16_t rnti, const ue_cfg_t& uecfg);
};
class ue_carrier;
class slot_ue
@ -79,19 +50,18 @@ public:
uint32_t cc = SCHED_NR_MAX_CARRIERS;
// UE parameters common to all sectors
const ue_cfg_extended* cfg = nullptr;
const bwp_ue_cfg* cfg = nullptr;
bool pending_sr;
// UE parameters that are sector specific
const ue_cc_cfg_t* cc_cfg = nullptr;
uint32_t bwp_id;
tti_point pdcch_tti;
tti_point pdsch_tti;
tti_point pusch_tti;
tti_point uci_tti;
uint32_t dl_cqi;
uint32_t ul_cqi;
harq_proc* h_dl = nullptr;
dl_harq_proc* h_dl = nullptr;
harq_proc* h_ul = nullptr;
private:
@ -101,8 +71,8 @@ private:
class ue_carrier
{
public:
ue_carrier(uint16_t rnti, uint32_t cc, const ue_cfg_t& cfg);
slot_ue try_reserve(tti_point pdcch_tti, const ue_cfg_extended& cfg);
ue_carrier(uint16_t rnti, const ue_cfg_t& cfg, const sched_cell_params& cell_params_);
slot_ue try_reserve(tti_point pdcch_tti, const ue_cfg_t& cfg);
void push_feedback(srsran::move_callback<void(ue_carrier&)> callback);
const uint16_t rnti;
@ -115,7 +85,8 @@ public:
harq_entity harq_ent;
private:
const ue_cfg_t* cfg = nullptr;
bwp_ue_cfg bwp_cfg;
const sched_cell_params& cell_params;
resource_guard busy;
tti_point last_tti_rx;
@ -126,7 +97,7 @@ private:
class ue
{
public:
ue(uint16_t rnti, const ue_cfg_t& cfg);
ue(uint16_t rnti, const ue_cfg_t& cfg, const sched_params& sched_cfg_);
slot_ue try_reserve(tti_point tti_rx, uint32_t cc);
@ -138,11 +109,12 @@ public:
private:
const uint16_t rnti;
const sched_params& sched_cfg;
bool pending_sr = false;
int current_idx = 0;
std::array<ue_cfg_extended, 4> ue_cfgs;
std::array<ue_cfg_t, 4> ue_cfgs;
};
using ue_map_t = srsran::static_circular_map<uint16_t, std::unique_ptr<ue>, SCHED_NR_MAX_USERS>;

@ -22,7 +22,8 @@
#ifndef SRSRAN_SCHED_NR_WORKER_H
#define SRSRAN_SCHED_NR_WORKER_H
#include "sched_nr_common.h"
#include "sched_nr_bwp.h"
#include "sched_nr_cfg.h"
#include "sched_nr_rb_grid.h"
#include "sched_nr_ue.h"
#include "srsran/adt/circular_array.h"
@ -31,19 +32,17 @@
#include "srsran/adt/span.h"
#include <condition_variable>
#include <mutex>
#include <semaphore.h>
namespace srsenb {
namespace sched_nr_impl {
using slot_res_t = sched_nr_interface::tti_request_t;
using dl_sched_t = sched_nr_interface::dl_sched_t;
using ul_sched_t = sched_nr_interface::ul_sched_t;
class slot_cc_worker
{
public:
explicit slot_cc_worker(const sched_cell_params& cell_params, cell_res_grid& phy_grid) :
cfg(cell_params), res_grid(0, phy_grid)
{}
explicit slot_cc_worker(serv_cell_ctxt& sched);
void start(tti_point tti_rx_, ue_map_t& ue_db_);
void run();
@ -53,41 +52,50 @@ public:
private:
void alloc_dl_ues();
void alloc_ul_ues();
void log_result() const;
const sched_cell_params& cfg;
serv_cell_ctxt& cell;
srslog::basic_logger& logger;
tti_point tti_rx;
slot_bwp_sched res_grid;
bwp_slot_allocator bwp_alloc;
srsran::static_circular_map<uint16_t, slot_ue, SCHED_NR_MAX_USERS> slot_ues;
};
class sched_worker_manager
{
struct slot_worker_ctxt {
std::mutex slot_mutex; // lock of all workers of the same slot.
std::condition_variable cvar;
tti_point tti_rx;
int nof_workers_waiting = 0;
std::atomic<int> worker_count{0}; // variable shared across slot_cc_workers
std::vector<slot_cc_worker> workers;
};
public:
explicit sched_worker_manager(ue_map_t& ue_db_, const sched_params& cfg_);
sched_worker_manager(const sched_worker_manager&) = delete;
sched_worker_manager(sched_worker_manager&&) = delete;
~sched_worker_manager();
void reserve_workers(tti_point tti_rx);
void start_tti(tti_point tti_rx);
bool run_tti(tti_point tti_rx, uint32_t cc, sched_nr_interface::tti_request_t& req);
void end_tti(tti_point tti_rx);
void start_slot(tti_point tti_rx, srsran::move_callback<void()> process_feedback);
bool run_slot(tti_point tti_rx, uint32_t cc);
void release_slot(tti_point tti_rx);
bool save_sched_result(tti_point pdcch_tti, uint32_t cc, dl_sched_t& dl_res, ul_sched_t& ul_res);
private:
const sched_params& cfg;
ue_map_t& ue_db;
srslog::basic_logger& logger;
struct slot_worker_ctxt {
sem_t sf_sem; // lock of all workers of the same slot. unlocked by last slot_cc_worker
tti_point tti_rx;
std::atomic<int> worker_count{0}; // variable shared across slot_cc_workers
std::vector<slot_cc_worker> workers;
};
std::vector<std::unique_ptr<slot_worker_ctxt> > slot_ctxts;
std::mutex ue_db_mutex;
std::vector<std::unique_ptr<slot_worker_ctxt> > slot_worker_ctxts;
srsran::bounded_vector<cell_res_grid, SCHED_NR_MAX_CARRIERS> cell_grid_list;
srsran::bounded_vector<serv_cell_ctxt, SCHED_NR_MAX_CARRIERS> cell_grid_list;
slot_worker_ctxt& get_sf(tti_point tti_rx);
};

@ -90,6 +90,7 @@ public:
private:
srslog::basic_logger* logger;
std::mutex mutex;
srsran::static_circular_map<uint32_t, srsran::unique_byte_buffer_t, SRSRAN_FDD_NOF_HARQ * 8> pdu_map;
};
@ -224,7 +225,6 @@ private:
// Mutexes
std::mutex mutex;
std::mutex rx_buffers_mutex;
};
} // namespace srsenb

@ -41,11 +41,17 @@ struct rrc_cfg_sr_t {
struct rrc_cfg_qci_t {
bool configured = false;
int enb_dl_max_retx_thres = -1;
asn1::rrc::lc_ch_cfg_s::ul_specific_params_s_ lc_cfg;
asn1::rrc::pdcp_cfg_s pdcp_cfg;
asn1::rrc::rlc_cfg_c rlc_cfg;
};
struct srb_cfg_t {
int enb_dl_max_retx_thres = -1;
asn1::rrc::srb_to_add_mod_s::rlc_cfg_c_ rlc_cfg;
};
struct rrc_cfg_t {
uint32_t enb_id; ///< Required to pack SIB1
// Per eNB SIBs
@ -71,6 +77,8 @@ struct rrc_cfg_t {
uint32_t max_mac_dl_kos;
uint32_t max_mac_ul_kos;
uint32_t rlf_release_timer_ms;
srb_cfg_t srb1_cfg;
srb_cfg_t srb2_cfg;
};
constexpr uint32_t UE_PCELL_CC_IDX = 0;

@ -40,6 +40,8 @@ struct rrc_cfg_cqi_t {
uint32_t nof_prb;
uint32_t period;
uint32_t m_ri;
bool is_subband_enabled;
uint32_t subband_k;
bool simultaneousAckCQI;
rrc_cfg_cqi_mode_t mode;
};

@ -1,6 +1,41 @@
// All times are in ms. Use -1 for infinity, where available
// srb1_config = {
// rlc_config = {
// ul_am = {
// t_poll_retx = 45;
// poll_pdu = -1;
// poll_byte = -1;
// max_retx_thresh = 4;
// };
// dl_am = {
// t_reordering = 35;
// t_status_prohibit = 0;
// };
// };
// enb_specific = {
// dl_max_retx_thresh = 32;
// };
// }
// srb2_config = {
// rlc_config = {
// ul_am = {
// t_poll_retx = 45;
// poll_pdu = -1;
// poll_byte = -1;
// max_retx_thresh = 4;
// };
// dl_am = {
// t_reordering = 35;
// t_status_prohibit = 0;
// };
// };
// enb_specific = {
// dl_max_retx_thresh = 32;
// };
// }
qci_config = (
{
@ -24,6 +59,9 @@ qci_config = (
bucket_size_duration = 100;
log_chan_group = 2;
};
enb_specific = {
dl_max_retx_thresh = 32;
};
},
{
qci=9;
@ -49,6 +87,9 @@ qci_config = (
bucket_size_duration = 100;
log_chan_group = 3;
};
enb_specific = {
dl_max_retx_thresh = 32;
};
}
);

@ -47,6 +47,7 @@ phy_cnfg =
//subframe = [0, 10, 20, 30]; // Optional vector of subframe indices every period where CQI resources will be allocated (default uses all)
nof_prb = 1;
m_ri = 8; // RI period in CQI period
//subband_k = 1; // If enabled and > 0, configures sub-band CQI reporting and defines K (see 36.213 7.2.2). If disabled, configures wideband CQI
};
};

@ -41,7 +41,7 @@ add_executable(srsenb main.cc enb.cc metrics_stdout.cc metrics_csv.cc metrics_js
set(SRSENB_SOURCES srsenb_phy srsenb_stack srsenb_common srsenb_s1ap srsenb_upper srsenb_mac srsenb_rrc srslog system)
set(SRSRAN_SOURCES srsran_common srsran_mac srsran_phy srsran_gtpu srsran_rlc srsran_pdcp srsran_radio rrc_asn1 s1ap_asn1 enb_cfg_parser srslog system)
set(SRSENB_SOURCES ${SRSENB_SOURCES} srsgnb_phy srsgnb_stack srsgnb_ngap srsgnb_upper srsgnb_mac srsgnb_rrc)
set(SRSENB_SOURCES ${SRSENB_SOURCES} srsgnb_stack srsgnb_ngap srsgnb_upper srsgnb_mac srsgnb_rrc)
set(SRSRAN_SOURCES ${SRSRAN_SOURCES} rrc_nr_asn1 ngap_nr_asn1)
target_link_libraries(srsenb ${SRSENB_SOURCES}

@ -20,7 +20,6 @@
*/
#include "srsenb/hdr/enb.h"
#include "srsenb/hdr/phy/vnf_phy_nr.h"
#include "srsenb/hdr/stack/enb_stack_lte.h"
#include "srsenb/hdr/stack/gnb_stack_nr.h"
#include "srsenb/src/enb_cfg_parser.h"
@ -104,42 +103,11 @@ int enb::init(const all_args_t& args_)
phy = std::move(lte_phy);
radio = std::move(lte_radio);
} else if (args.stack.type == "nr") {
std::unique_ptr<srsenb::gnb_stack_nr> nr_stack(new srsenb::gnb_stack_nr);
std::unique_ptr<srsran::radio_null> nr_radio(new srsran::radio_null);
std::unique_ptr<srsenb::vnf_phy_nr> nr_phy(new srsenb::vnf_phy_nr);
// Init layers
if (nr_radio->init(args.rf, nullptr)) {
srsran::console("Error initializing radio.\n");
return SRSRAN_ERROR;
}
// TODO: where do we put this?
srsenb::nr_phy_cfg_t nr_phy_cfg = {};
args.phy.vnf_args.type = "gnb";
args.phy.vnf_args.log_level = args.phy.log.phy_level;
args.phy.vnf_args.log_hex_limit = args.phy.log.phy_hex_limit;
if (nr_phy->init(args.phy, nr_phy_cfg, nr_stack.get())) {
srsran::console("Error initializing PHY.\n");
return SRSRAN_ERROR;
}
// Same here, where do we put this?
srsenb::rrc_nr_cfg_t rrc_nr_cfg = {};
rrc_nr_cfg.coreless = args.stack.coreless;
if (nr_stack->init(args.stack, rrc_nr_cfg, nr_phy.get())) {
srsran::console("Error initializing stack.\n");
} else {
srsran::console("Stack type %s not supported.\n", args.stack.type.c_str());
return SRSRAN_ERROR;
}
stack = std::move(nr_stack);
phy = std::move(nr_phy);
radio = std::move(nr_radio);
}
started = true; // set to true in any case to allow stopping the eNB if an error happened
// Now that everything is setup, log sector start events.

@ -82,7 +82,7 @@ int field_sched_info::parse(libconfig::Setting& root)
for (uint32_t i = 0; i < data->sched_info_list.size(); i++) {
if (not parse_enum_by_number(data->sched_info_list[i].si_periodicity, "si_periodicity", root[i])) {
fprintf(stderr, "Missing field si_periodicity in sched_info=%d\n", i);
return -1;
return SRSRAN_ERROR;
}
if (root[i].exists("si_mapping_info")) {
data->sched_info_list[i].sib_map_info.resize((uint32_t)root[i]["si_mapping_info"].getLength());
@ -93,12 +93,12 @@ int field_sched_info::parse(libconfig::Setting& root)
data->sched_info_list[i].sib_map_info[j].value = (sib_type_e::options)(sib_index - 3);
} else {
fprintf(stderr, "Invalid SIB index %d for si_mapping_info=%d in sched_info=%d\n", sib_index, j, i);
return -1;
return SRSRAN_ERROR;
}
}
} else {
fprintf(stderr, "Number of si_mapping_info values exceeds maximum (%d)\n", ASN1_RRC_MAX_SIB);
return -1;
return SRSRAN_ERROR;
}
} else {
data->sched_info_list[i].sib_map_info.resize(0);
@ -114,13 +114,13 @@ int field_intra_neigh_cell_list::parse(libconfig::Setting& root)
for (uint32_t i = 0; i < data->intra_freq_neigh_cell_list.size() && i < ASN1_RRC_MAX_CELL_INTRA; i++) {
if (not parse_enum_by_number(data->intra_freq_neigh_cell_list[i].q_offset_cell, "q_offset_range", root[i])) {
fprintf(stderr, "Missing field q_offset_range in neigh_cell=%d\n", i);
return -1;
return SRSRAN_ERROR;
}
int phys_cell_id = 0;
if (!root[i].lookupValue("phys_cell_id", phys_cell_id)) {
fprintf(stderr, "Missing field phys_cell_id in neigh_cell=%d\n", i);
return -1;
return SRSRAN_ERROR;
}
data->intra_freq_neigh_cell_list[i].pci = (uint16)phys_cell_id;
}
@ -134,14 +134,14 @@ int field_intra_black_cell_list::parse(libconfig::Setting& root)
for (uint32_t i = 0; i < data->intra_freq_black_cell_list.size() && i < ASN1_RRC_MAX_CELL_BLACK; i++) {
if (not parse_enum_by_number(data->intra_freq_black_cell_list[i].range, "range", root[i])) {
fprintf(stderr, "Missing field range in black_cell=%d\n", i);
return -1;
return SRSRAN_ERROR;
}
data->intra_freq_black_cell_list[i].range_present = true;
int start = 0;
if (!root[i].lookupValue("start", start)) {
fprintf(stderr, "Missing field start in black_cell=%d\n", i);
return -1;
return SRSRAN_ERROR;
}
data->intra_freq_black_cell_list[i].start = (uint16)start;
}
@ -154,7 +154,7 @@ int field_carrier_freqs_info_list::parse(libconfig::Setting& root)
data->carrier_freqs_info_list_present = data->carrier_freqs_info_list.size() > 0;
if (data->carrier_freqs_info_list.size() > ASN1_RRC_MAX_GNFG) {
ERROR("CarrierFreqsInfoGERAN cannot have more than %d entries", ASN1_RRC_MAX_GNFG);
return -1;
return SRSRAN_ERROR;
}
for (uint32_t i = 0; i < data->carrier_freqs_info_list.size(); i++) {
int cell_resel_prio;
@ -173,27 +173,27 @@ int field_carrier_freqs_info_list::parse(libconfig::Setting& root)
"ncc_permitted", &data->carrier_freqs_info_list[i].common_info.ncc_permitted);
if (ncc_permitted.parse(root[i])) {
ERROR("Error parsing `ncc_permitted` in carrier_freqs_info_lsit=%d", i);
return -1;
return SRSRAN_ERROR;
}
int q_rx_lev_min = 0;
if (!root[i].lookupValue("q_rx_lev_min", q_rx_lev_min)) {
ERROR("Missing field `q_rx_lev_min` in carrier_freqs_info_list=%d", i);
return -1;
return SRSRAN_ERROR;
}
data->carrier_freqs_info_list[i].common_info.q_rx_lev_min = q_rx_lev_min;
int thresh_x_high = 0;
if (!root[i].lookupValue("thresh_x_high", thresh_x_high)) {
ERROR("Missing field `thresh_x_high` in carrier_freqs_info_list=%d", i);
return -1;
return SRSRAN_ERROR;
}
data->carrier_freqs_info_list[i].common_info.thresh_x_high = thresh_x_high;
int thresh_x_low = 0;
if (!root[i].lookupValue("thresh_x_low", thresh_x_low)) {
ERROR("Missing field `thresh_x_low` in carrier_freqs_info_list=%d", i);
return -1;
return SRSRAN_ERROR;
}
data->carrier_freqs_info_list[i].common_info.thresh_x_low = thresh_x_low;
@ -206,7 +206,7 @@ int field_carrier_freqs_info_list::parse(libconfig::Setting& root)
&data->carrier_freqs_info_list[i].carrier_freqs.band_ind);
if (band_ind.parse(root[i])) {
ERROR("Error parsing `band_ind` in carrier_freqs_info_list=%d", i);
return -1;
return SRSRAN_ERROR;
}
data->carrier_freqs_info_list[i].carrier_freqs.following_arfcns.set_explicit_list_of_arfcns();
@ -222,12 +222,12 @@ int field_carrier_freqs_info_list::parse(libconfig::Setting& root)
exp_l[j] = (short unsigned int)arfcn;
} else {
fprintf(stderr, "Invalid ARFCN %d in for carrier_freqs_info_list=%d explicit_list_of_arfcns\n", i, j);
return -1;
return SRSRAN_ERROR;
}
}
} else {
fprintf(stderr, "Number of ARFCN in explicit_list_of_arfcns exceeds maximum (%d)\n", 31);
return -1;
return SRSRAN_ERROR;
}
} else {
exp_l.resize(0);
@ -273,7 +273,7 @@ int mbsfn_sf_cfg_list_parser::parse(Setting& root)
}
if (len > 1) {
fprintf(stderr, "Only mbsfnSubframeConfigListLengths of size 1 are supported\n");
return -1;
return SRSRAN_ERROR;
}
*enabled = true;
mbsfn_list->resize(len);
@ -315,53 +315,53 @@ int mbsfn_area_info_list_parser::parse(Setting& root)
&mbsfn_item->non_mbsfn_region_len);
if (fieldlen.parse(root["mbsfn_area_info_list"])) {
fprintf(stderr, "Error parsing non_mbsfn_region_length\n");
return -1;
return SRSRAN_ERROR;
}
field_asn1_enum_str<mbsfn_area_info_r9_s::mcch_cfg_r9_s_::mcch_repeat_period_r9_e_> repeat(
"mcch_repetition_period", &mbsfn_item->mcch_cfg_r9.mcch_repeat_period_r9);
if (repeat.parse(root["mbsfn_area_info_list"])) {
fprintf(stderr, "Error parsing mcch_repetition_period\n");
return -1;
return SRSRAN_ERROR;
}
field_asn1_enum_str<mbsfn_area_info_r9_s::mcch_cfg_r9_s_::mcch_mod_period_r9_e_> mod(
"mcch_modification_period", &mbsfn_item->mcch_cfg_r9.mcch_mod_period_r9);
if (mod.parse(root["mbsfn_area_info_list"])) {
fprintf(stderr, "Error parsing mcch_modification_period\n");
return -1;
return SRSRAN_ERROR;
}
field_asn1_enum_str<mbsfn_area_info_r9_s::mcch_cfg_r9_s_::sig_mcs_r9_e_> sig("signalling_mcs",
&mbsfn_item->mcch_cfg_r9.sig_mcs_r9);
if (sig.parse(root["mbsfn_area_info_list"])) {
fprintf(stderr, "Error parsing signalling_mcs\n");
return -1;
return SRSRAN_ERROR;
}
parser::field<uint16_t> areaid("mbsfn_area_id", &mbsfn_item->mbsfn_area_id_r9);
if (areaid.parse(root["mbsfn_area_info_list"])) {
fprintf(stderr, "Error parsing mbsfn_area_id\n");
return -1;
return SRSRAN_ERROR;
}
parser::field<uint8_t> notif_ind("notification_indicator", &mbsfn_item->notif_ind_r9);
if (notif_ind.parse(root["mbsfn_area_info_list"])) {
fprintf(stderr, "Error parsing notification_indicator\n");
return -1;
return SRSRAN_ERROR;
}
parser::field<uint8_t> offset("mcch_offset", &mbsfn_item->mcch_cfg_r9.mcch_offset_r9);
if (offset.parse(root["mbsfn_area_info_list"])) {
fprintf(stderr, "Error parsing mcch_offset\n");
return -1;
return SRSRAN_ERROR;
}
field_asn1_bitstring_number<asn1::fixed_bitstring<6>, uint8_t> alloc_info("sf_alloc_info",
&mbsfn_item->mcch_cfg_r9.sf_alloc_info_r9);
if (alloc_info.parse(root["mbsfn_area_info_list"])) {
fprintf(stderr, "Error parsing mbsfn_area_info_list\n");
return -1;
return SRSRAN_ERROR;
}
return 0;
@ -395,17 +395,83 @@ int phr_cnfg_parser::parse(libconfig::Setting& root)
mac_main_cfg_s::phr_cfg_c_::setup_s_& s = phr_cfg->setup();
if (not parse_enum_by_str(s.dl_pathloss_change, "dl_pathloss_change", root["phr_cnfg"])) {
return -1;
return SRSRAN_ERROR;
}
if (not parse_enum_by_number(s.periodic_phr_timer, "periodic_phr_timer", root["phr_cnfg"])) {
return -1;
return SRSRAN_ERROR;
}
if (not parse_enum_by_number(s.prohibit_phr_timer, "prohibit_phr_timer", root["phr_cnfg"])) {
return -1;
return SRSRAN_ERROR;
}
return 0;
}
int field_srb::parse(libconfig::Setting& root)
{
// Parse RLC AM section
rlc_cfg_c* rlc_cfg = &cfg.rlc_cfg.set_explicit_value();
if (root.exists("ul_am") && root.exists("dl_am")) {
rlc_cfg->set_am();
}
// RLC-UM Should not exist section
if (root.exists("ul_um") || root.exists("dl_um")) {
ERROR("Error SRBs must be AM.");
return SRSRAN_ERROR;
}
// Parse RLC-AM section
if (root.exists("ul_am")) {
ul_am_rlc_s* am_rlc = &rlc_cfg->am().ul_am_rlc;
field_asn1_enum_number<t_poll_retx_e> t_poll_retx("t_poll_retx", &am_rlc->t_poll_retx);
if (t_poll_retx.parse(root["ul_am"])) {
ERROR("Error can't find t_poll_retx in section ul_am");
return SRSRAN_ERROR;
}
field_asn1_enum_number<poll_pdu_e> poll_pdu("poll_pdu", &am_rlc->poll_pdu);
if (poll_pdu.parse(root["ul_am"])) {
ERROR("Error can't find poll_pdu in section ul_am");
return SRSRAN_ERROR;
}
field_asn1_enum_number<poll_byte_e> poll_byte("poll_byte", &am_rlc->poll_byte);
if (poll_byte.parse(root["ul_am"])) {
ERROR("Error can't find poll_byte in section ul_am");
return SRSRAN_ERROR;
}
field_asn1_enum_number<ul_am_rlc_s::max_retx_thres_e_> max_retx_thresh("max_retx_thresh", &am_rlc->max_retx_thres);
if (max_retx_thresh.parse(root["ul_am"])) {
ERROR("Error can't find max_retx_thresh in section ul_am");
return SRSRAN_ERROR;
}
}
if (root.exists("dl_am")) {
dl_am_rlc_s* am_rlc = &rlc_cfg->am().dl_am_rlc;
field_asn1_enum_number<t_reordering_e> t_reordering("t_reordering", &am_rlc->t_reordering);
if (t_reordering.parse(root["dl_am"])) {
ERROR("Error can't find t_reordering in section dl_am");
return SRSRAN_ERROR;
}
field_asn1_enum_number<t_status_prohibit_e> t_status_prohibit("t_status_prohibit", &am_rlc->t_status_prohibit);
if (t_status_prohibit.parse(root["dl_am"])) {
ERROR("Error can't find t_status_prohibit in section dl_am");
return SRSRAN_ERROR;
}
}
if (root.exists("enb_specific")) {
cfg.enb_dl_max_retx_thres = (int)root["enb_specific"]["dl_max_retx_thresh"];
}
return 0;
}
int field_qci::parse(libconfig::Setting& root)
{
auto nof_qci = (uint32_t)root.getLength();
@ -418,7 +484,7 @@ int field_qci::parse(libconfig::Setting& root)
// Parse PDCP section
if (!q.exists("pdcp_config")) {
fprintf(stderr, "Error section pdcp_config not found for qci=%d\n", qci);
return -1;
return SRSRAN_ERROR;
}
rrc_cfg_qci_t qcicfg;
@ -447,7 +513,7 @@ int field_qci::parse(libconfig::Setting& root)
rlc_cfg->set_um_uni_dir_dl();
} else {
fprintf(stderr, "Invalid combination of UL/DL UM/AM for qci=%d\n", qci);
return -1;
return SRSRAN_ERROR;
}
// Parse RLC-UM section
@ -462,7 +528,7 @@ int field_qci::parse(libconfig::Setting& root)
field_asn1_enum_number<sn_field_len_e> sn_field_len("sn_field_length", &um_rlc->sn_field_len);
if (sn_field_len.parse(q["rlc_config"]["ul_um"])) {
ERROR("Error can't find sn_field_length in section ul_um");
return -1;
return SRSRAN_ERROR;
}
}
@ -477,13 +543,13 @@ int field_qci::parse(libconfig::Setting& root)
field_asn1_enum_number<sn_field_len_e> sn_field_len("sn_field_length", &um_rlc->sn_field_len);
if (sn_field_len.parse(q["rlc_config"]["dl_um"])) {
ERROR("Error can't find sn_field_length in section dl_um");
return -1;
return SRSRAN_ERROR;
}
field_asn1_enum_number<t_reordering_e> t_reordering("t_reordering", &um_rlc->t_reordering);
if (t_reordering.parse(q["rlc_config"]["dl_um"])) {
ERROR("Error can't find t_reordering in section dl_um");
return -1;
return SRSRAN_ERROR;
}
}
@ -494,26 +560,26 @@ int field_qci::parse(libconfig::Setting& root)
field_asn1_enum_number<t_poll_retx_e> t_poll_retx("t_poll_retx", &am_rlc->t_poll_retx);
if (t_poll_retx.parse(q["rlc_config"]["ul_am"])) {
ERROR("Error can't find t_poll_retx in section ul_am");
return -1;
return SRSRAN_ERROR;
}
field_asn1_enum_number<poll_pdu_e> poll_pdu("poll_pdu", &am_rlc->poll_pdu);
if (poll_pdu.parse(q["rlc_config"]["ul_am"])) {
ERROR("Error can't find poll_pdu in section ul_am");
return -1;
return SRSRAN_ERROR;
}
field_asn1_enum_number<poll_byte_e> poll_byte("poll_byte", &am_rlc->poll_byte);
if (poll_byte.parse(q["rlc_config"]["ul_am"])) {
ERROR("Error can't find poll_byte in section ul_am");
return -1;
return SRSRAN_ERROR;
}
field_asn1_enum_number<ul_am_rlc_s::max_retx_thres_e_> max_retx_thresh("max_retx_thresh",
&am_rlc->max_retx_thres);
if (max_retx_thresh.parse(q["rlc_config"]["ul_am"])) {
ERROR("Error can't find max_retx_thresh in section ul_am");
return -1;
return SRSRAN_ERROR;
}
}
@ -523,20 +589,20 @@ int field_qci::parse(libconfig::Setting& root)
field_asn1_enum_number<t_reordering_e> t_reordering("t_reordering", &am_rlc->t_reordering);
if (t_reordering.parse(q["rlc_config"]["dl_am"])) {
ERROR("Error can't find t_reordering in section dl_am");
return -1;
return SRSRAN_ERROR;
}
field_asn1_enum_number<t_status_prohibit_e> t_status_prohibit("t_status_prohibit", &am_rlc->t_status_prohibit);
if (t_status_prohibit.parse(q["rlc_config"]["dl_am"])) {
ERROR("Error can't find t_status_prohibit in section dl_am");
return -1;
return SRSRAN_ERROR;
}
}
// Parse logical channel configuration section
if (!q.exists("logical_channel_config")) {
fprintf(stderr, "Error section logical_channel_config not found for qci=%d\n", qci);
return -1;
return SRSRAN_ERROR;
}
lc_ch_cfg_s::ul_specific_params_s_* lc_cfg = &qcicfg.lc_cfg;
@ -544,26 +610,31 @@ int field_qci::parse(libconfig::Setting& root)
parser::field<uint8> priority("priority", &lc_cfg->prio);
if (priority.parse(q["logical_channel_config"])) {
ERROR("Error can't find logical_channel_config in section priority");
return -1;
return SRSRAN_ERROR;
}
field_asn1_enum_number<lc_ch_cfg_s::ul_specific_params_s_::prioritised_bit_rate_e_> prioritised_bit_rate(
"prioritized_bit_rate", &lc_cfg->prioritised_bit_rate);
if (prioritised_bit_rate.parse(q["logical_channel_config"])) {
fprintf(stderr, "Error can't find prioritized_bit_rate in section logical_channel_config\n");
return -1;
return SRSRAN_ERROR;
}
field_asn1_enum_number<lc_ch_cfg_s::ul_specific_params_s_::bucket_size_dur_e_> bucket_size_duration(
"bucket_size_duration", &lc_cfg->bucket_size_dur);
if (bucket_size_duration.parse(q["logical_channel_config"])) {
ERROR("Error can't find bucket_size_duration in section logical_channel_config");
return -1;
return SRSRAN_ERROR;
}
parser::field<uint8> log_chan_group("log_chan_group", &lc_cfg->lc_ch_group);
lc_cfg->lc_ch_group_present = not log_chan_group.parse(q["logical_channel_config"]);
qcicfg.configured = true;
if (q.exists("enb_specific")) {
qcicfg.enb_dl_max_retx_thres = (int)q["enb_specific"]["dl_max_retx_thresh"];
}
cfg.insert(std::make_pair(qci, qcicfg));
}
@ -674,6 +745,8 @@ int parse_rr(all_args_t* args_, rrc_cfg_t* rrc_cfg_)
cqi_report_cnfg.add_field(new parser::field<uint32>("period", &rrc_cfg_->cqi_cfg.period));
cqi_report_cnfg.add_field(new parser::field<uint32>("m_ri", &rrc_cfg_->cqi_cfg.m_ri));
cqi_report_cnfg.add_field(new parser::field<uint32>("nof_prb", &rrc_cfg_->cqi_cfg.nof_prb));
cqi_report_cnfg.add_field(
new parser::field<uint32>("subband_k", &rrc_cfg_->cqi_cfg.subband_k, &rrc_cfg_->cqi_cfg.is_subband_enabled));
cqi_report_cnfg.add_field(new parser::field<bool>("simultaneousAckCQI", &rrc_cfg_->cqi_cfg.simultaneousAckCQI));
cqi_report_cnfg.add_field(new field_sf_mapping(rrc_cfg_->cqi_cfg.sf_mapping, &rrc_cfg_->cqi_cfg.nof_subframes, 1));
@ -789,7 +862,7 @@ static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root)
HANDLEPARSERCODE(parse_meas_cell_list(&cell_cfg.meas_cfg, cellroot["meas_cell_list"]));
if (not cellroot.exists("meas_report_desc")) {
ERROR("PARSER ERROR: \"ho_active\" is set to true, but field \"meas_report_desc\" doesn't exist.\n");
return -1;
return SRSRAN_ERROR;
}
HANDLEPARSERCODE(parse_meas_report_desc(&cell_cfg.meas_cfg, cellroot["meas_report_desc"]));
}
@ -815,13 +888,13 @@ static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root)
// Check RF port is not repeated
if (it->rf_port == it2->rf_port) {
ERROR("Repeated RF port for multiple cells");
return -1;
return SRSRAN_ERROR;
}
// Check cell ID is not repeated
if (it->cell_id == it2->cell_id) {
ERROR("Repeated Cell identifier");
return -1;
return SRSRAN_ERROR;
}
}
}
@ -1535,7 +1608,7 @@ int parse_sib9(std::string filename, sib_type9_s* data)
}
return 0;
} else {
return -1;
return SRSRAN_ERROR;
}
}
@ -1581,19 +1654,19 @@ int parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, srsenb::phy_cfg_t* phy_co
std::string mnc_str;
if (not srsran::mnc_to_string(args_->stack.s1ap.mnc, &mnc_str)) {
ERROR("The provided mnc=%d is not valid", args_->stack.s1ap.mnc);
return -1;
return SRSRAN_ERROR;
}
std::string mcc_str;
if (not srsran::mcc_to_string(args_->stack.s1ap.mcc, &mcc_str)) {
ERROR("The provided mnc=%d is not valid", args_->stack.s1ap.mcc);
return -1;
return SRSRAN_ERROR;
}
sib_type1_s::cell_access_related_info_s_* cell_access = &sib1->cell_access_related_info;
cell_access->plmn_id_list.resize(1);
srsran::plmn_id_t plmn;
if (plmn.from_string(mcc_str + mnc_str) == SRSRAN_ERROR) {
ERROR("Could not convert %s to a plmn_id", (mcc_str + mnc_str).c_str());
return -1;
return SRSRAN_ERROR;
}
srsran::to_asn1(&cell_access->plmn_id_list[0].plmn_id, plmn);
cell_access->plmn_id_list[0].cell_reserved_for_oper = plmn_id_info_s::cell_reserved_for_oper_e_::not_reserved;
@ -1619,7 +1692,7 @@ int parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, srsenb::phy_cfg_t* phy_co
// verify SIB13 is available
if (not sib_is_present(sib1->sched_info_list, sib_type_e::sib_type13_v920)) {
fprintf(stderr, "SIB13 not present in sched_info.\n");
return -1;
return SRSRAN_ERROR;
}
}
@ -1673,9 +1746,40 @@ namespace drb_sections {
int parse_drb(all_args_t* args_, rrc_cfg_t* rrc_cfg_)
{
parser::section srb1("srb1_config");
bool srb1_present = false;
srb1.set_optional(&srb1_present);
parser::section srb1_rlc_cfg("rlc_config");
srb1.add_subsection(&srb1_rlc_cfg);
srb1_rlc_cfg.add_field(new field_srb(rrc_cfg_->srb1_cfg));
parser::section srb2("srb2_config");
bool srb2_present = false;
srb2.set_optional(&srb2_present);
parser::section srb2_rlc_cfg("rlc_config");
srb2.add_subsection(&srb2_rlc_cfg);
srb2_rlc_cfg.add_field(new field_srb(rrc_cfg_->srb2_cfg));
parser::section qci("qci_config");
qci.add_field(new field_qci(rrc_cfg_->qci_cfg));
return parser::parse_section(args_->enb_files.drb_config, &qci);
// Run parser with two sections
parser p(args_->enb_files.rb_config);
p.add_section(&srb1);
p.add_section(&srb2);
p.add_section(&qci);
int ret = p.parse();
if (not srb1_present) {
rrc_cfg_->srb1_cfg.rlc_cfg.set_default_value();
}
if (not srb2_present) {
rrc_cfg_->srb2_cfg.rlc_cfg.set_default_value();
}
return ret;
}
} // namespace drb_sections

@ -155,6 +155,18 @@ private:
uint32_t default_offset;
};
class field_srb final : public parser::field_itf
{
public:
explicit field_srb(srb_cfg_t& cfg_) : cfg(cfg_) {}
const char* get_name() override { return "field_srb"; }
int parse(Setting& root) override;
private:
srb_cfg_t& cfg;
};
class field_qci final : public parser::field_itf
{
public:

@ -55,6 +55,7 @@ namespace bpo = boost::program_options;
* Program arguments processing
***********************************************************************/
string config_file;
static bool stdout_ts_enable = false;
void parse_args(all_args_t* args, int argc, char* argv[])
{
@ -92,7 +93,7 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("enb_files.sib_config", bpo::value<string>(&args->enb_files.sib_config)->default_value("sib.conf"), "SIB configuration files")
("enb_files.rr_config", bpo::value<string>(&args->enb_files.rr_config)->default_value("rr.conf"), "RR configuration files")
("enb_files.drb_config", bpo::value<string>(&args->enb_files.drb_config)->default_value("drb.conf"), "DRB configuration files")
("enb_files.rb_config", bpo::value<string>(&args->enb_files.rb_config)->default_value("rb.conf"), "SRB/DRB configuration files")
("rf.dl_earfcn", bpo::value<uint32_t>(&args->enb.dl_earfcn)->default_value(0), "Force Downlink EARFCN for single cell")
("rf.srate", bpo::value<double>(&args->rf.srate_hz)->default_value(0.0), "Force Tx and Rx sampling rate in Hz")
@ -171,6 +172,8 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("scheduler.init_ul_snr_value", bpo::value<int>(&args->stack.mac.sched.init_ul_snr_value)->default_value(5), "Initial UL SNR value used for computing MCS in the first UL grant")
("scheduler.init_dl_cqi", bpo::value<int>(&args->stack.mac.sched.init_dl_cqi)->default_value(5), "DL CQI value used before any CQI report is available to the eNB")
("scheduler.max_sib_coderate", bpo::value<float>(&args->stack.mac.sched.max_sib_coderate)->default_value(0.8), "Upper bound on SIB and RAR grants coderate")
("scheduler.pdcch_cqi_offset", bpo::value<int>(&args->stack.mac.sched.pdcch_cqi_offset)->default_value(0), "CQI offset in derivation of PDCCH aggregation level")
/* Downlink Channel emulator section */
@ -233,6 +236,7 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("expert.tracing_enable", bpo::value<bool>(&args->general.tracing_enable)->default_value(false), "Events tracing")
("expert.tracing_filename", bpo::value<string>(&args->general.tracing_filename)->default_value("/tmp/enb_tracing.log"), "Tracing events filename")
("expert.tracing_buffcapacity", bpo::value<std::size_t>(&args->general.tracing_buffcapacity)->default_value(1000000), "Tracing buffer capcity")
("expert.stdout_ts_enable", bpo::value<bool>(&stdout_ts_enable)->default_value(false), "Prints once per second the timestamp into stdout")
("expert.rrc_inactivity_timer", bpo::value<uint32_t>(&args->general.rrc_inactivity_timer)->default_value(30000), "Inactivity timer in ms.")
("expert.print_buffer_state", bpo::value<bool>(&args->general.print_buffer_state)->default_value(false), "Prints on the console the buffer state every 10 seconds")
("expert.eea_pref_list", bpo::value<string>(&args->general.eea_pref_list)->default_value("EEA0, EEA2, EEA1"), "Ordered preference list for the selection of encryption algorithm (EEA) (default: EEA0, EEA2, EEA1).")
@ -246,6 +250,7 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("expert.extended_cp", bpo::value<bool>(&args->phy.extended_cp)->default_value(false), "Use extended cyclic prefix")
("expert.ts1_reloc_prep_timeout", bpo::value<uint32_t>(&args->stack.s1ap.ts1_reloc_prep_timeout)->default_value(10000), "S1AP TS 36.413 TS1RelocPrep Expiry Timeout value in milliseconds")
("expert.ts1_reloc_overall_timeout", bpo::value<uint32_t>(&args->stack.s1ap.ts1_reloc_overall_timeout)->default_value(10000), "S1AP TS 36.413 TS1RelocOverall Expiry Timeout value in milliseconds")
("expert.rlf_min_ul_snr_estim", bpo::value<int>(&args->stack.mac.rlf_min_ul_snr_estim)->default_value(-2), "SNR threshold in dB below which the eNB is notified with rlf ko.")
// eMBMS section
@ -445,8 +450,8 @@ void parse_args(all_args_t* args, int argc, char* argv[])
exit(1);
}
if (!config_exists(args->enb_files.drb_config, "drb.conf")) {
cout << "Failed to read DRB configuration file " << args->enb_files.drb_config << " - exiting" << endl;
if (!config_exists(args->enb_files.rb_config, "rb.conf")) {
cout << "Failed to read DRB configuration file " << args->enb_files.rb_config << " - exiting" << endl;
exit(1);
}
@ -630,6 +635,7 @@ int main(int argc, char* argv[])
}
}
int cnt = 0;
int ts_cnt = 0;
while (running) {
if (args.general.print_buffer_state) {
cnt++;
@ -638,6 +644,16 @@ int main(int argc, char* argv[])
enb->print_pool();
}
}
if (stdout_ts_enable) {
if (++ts_cnt == 100) {
ts_cnt = 0;
char buff[64];
std::time_t t = std::time(nullptr);
if (std::strftime(buff, sizeof(buff), "%FT%T", std::gmtime(&t))) {
std::cout << buff << '\n';
}
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
input.join();

@ -31,8 +31,6 @@ set(SOURCES
txrx.cc)
add_library(srsenb_phy STATIC ${SOURCES})
add_library(srsgnb_phy STATIC vnf_phy_nr.cc)
if (ENABLE_GUI AND SRSGUI_FOUND)
target_link_libraries(srsenb_phy ${SRSGUI_LIBRARIES})
endif ()

@ -35,11 +35,12 @@ slot_worker::slot_worker(srsran::phy_common_interface& common_,
bool slot_worker::init(const args_t& args)
{
// Calculate subframe length
sf_len = SRSRAN_SF_LEN_PRB_NR(args.carrier.nof_prb);
sf_len = SRSRAN_SF_LEN_PRB_NR(args.nof_max_prb);
// Copy common configurations
cell_index = args.cell_index;
pdcch_cfg = args.pdcch_cfg;
// FIXME:
// pdcch_cfg = args.pdcch_cfg;
// Allocate Tx buffers
tx_buffer.resize(args.nof_tx_ports);
@ -64,10 +65,10 @@ bool slot_worker::init(const args_t& args)
// Prepare DL arguments
srsran_gnb_dl_args_t dl_args = {};
dl_args.pdsch.measure_time = true;
dl_args.pdsch.max_layers = args.carrier.max_mimo_layers;
dl_args.pdsch.max_prb = args.carrier.nof_prb;
dl_args.pdsch.max_layers = args.nof_tx_ports;
dl_args.pdsch.max_prb = args.nof_max_prb;
dl_args.nof_tx_antennas = args.nof_tx_ports;
dl_args.nof_max_prb = args.carrier.nof_prb;
dl_args.nof_max_prb = args.nof_max_prb;
// Initialise DL
if (srsran_gnb_dl_init(&gnb_dl, tx_buffer.data(), &dl_args) < SRSRAN_SUCCESS) {
@ -75,18 +76,13 @@ bool slot_worker::init(const args_t& args)
return false;
}
// Set gNb DL carrier
if (srsran_gnb_dl_set_carrier(&gnb_dl, &args.carrier) < SRSRAN_SUCCESS) {
logger.error("Error setting DL carrier");
return false;
}
// Prepare UL arguments
srsran_gnb_ul_args_t ul_args = {};
ul_args.pusch.measure_time = true;
ul_args.pusch.max_layers = args.carrier.max_mimo_layers;
ul_args.pusch.max_prb = args.carrier.nof_prb;
ul_args.nof_max_prb = args.carrier.nof_prb;
ul_args.pusch.max_layers = args.nof_rx_ports;
ul_args.pusch.max_prb = args.nof_max_prb;
ul_args.nof_max_prb = args.nof_max_prb;
// Initialise UL
if (srsran_gnb_ul_init(&gnb_ul, rx_buffer[0], &ul_args) < SRSRAN_SUCCESS) {
@ -94,12 +90,6 @@ bool slot_worker::init(const args_t& args)
return false;
}
// Set gNb UL carrier
if (srsran_gnb_ul_set_carrier(&gnb_ul, &args.carrier) < SRSRAN_SUCCESS) {
logger.error("Error setting UL carrier");
return false;
}
return true;
}
@ -166,7 +156,7 @@ bool slot_worker::work_ul()
return false;
}
// Decode PUCCH
// For each PUCCH...
for (stack_interface_phy_nr::pucch_t& pucch : ul_sched.pucch) {
stack_interface_phy_nr::pucch_info_t pucch_info = {};
pucch_info.uci_data.cfg = pucch.uci_cfg;
@ -197,7 +187,7 @@ bool slot_worker::work_ul()
}
}
// Decode PUSCH
// For each PUSCH...
for (stack_interface_phy_nr::pusch_t& pusch : ul_sched.pusch) {
// Get payload PDU
stack_interface_phy_nr::pusch_info_t pusch_info = {};
@ -206,7 +196,7 @@ bool slot_worker::work_ul()
pusch_info.pusch_data.tb[0].payload = pusch.data[0];
pusch_info.pusch_data.tb[1].payload = pusch.data[1];
// Decode PUCCH
// Decode PUSCH
if (srsran_gnb_ul_get_pusch(&gnb_ul, &ul_slot_cfg, &pusch.sch, &pusch.sch.grant, &pusch_info.pusch_data) <
SRSRAN_SUCCESS) {
logger.error("Error getting PUSCH");
@ -349,6 +339,27 @@ void slot_worker::work_imp()
common.worker_end(this, true, tx_rf_buffer, tx_time, true);
}
bool slot_worker::set_common_cfg(const srsran_carrier_nr_t& carrier, const srsran_pdcch_cfg_nr_t& pdcch_cfg_)
{
// Set gNb DL carrier
if (srsran_gnb_dl_set_carrier(&gnb_dl, &carrier) < SRSRAN_SUCCESS) {
logger.error("Error setting DL carrier");
return false;
}
// Set gNb UL carrier
if (srsran_gnb_ul_set_carrier(&gnb_ul, &carrier) < SRSRAN_SUCCESS) {
logger.error("Error setting UL carrier");
return false;
}
pdcch_cfg = pdcch_cfg_;
// Update subframe length
sf_len = SRSRAN_SF_LEN_PRB_NR(carrier.nof_prb);
return true;
}
} // namespace nr
} // namespace srsenb

@ -27,19 +27,27 @@ worker_pool::worker_pool(srsran::phy_common_interface& common_,
stack_interface_phy_nr& stack_,
srslog::sink& log_sink_,
uint32_t max_workers) :
pool(max_workers), common(common_), stack(stack_), log_sink(log_sink_)
pool(max_workers),
common(common_),
stack(stack_),
log_sink(log_sink_),
logger(srslog::fetch_basic_logger("PHY-NR", log_sink)),
prach_stack_adaptor(stack_)
{
// Do nothing
}
bool worker_pool::init(const args_t& args, const phy_cell_cfg_list_nr_t& cell_list)
{
// Configure logger
srslog::basic_levels log_level = srslog::str_to_basic_level(args.log.phy_level);
logger.set_level(log_level);
// Add workers to workers pool and start threads
srslog::basic_levels log_level = srslog::str_to_basic_level(args.log_level);
for (uint32_t i = 0; i < args.nof_phy_threads; i++) {
auto& log = srslog::fetch_basic_logger(fmt::format("{}PHY{}-NR", args.log_id_preamble, i), log_sink);
auto& log = srslog::fetch_basic_logger(fmt::format("{}PHY{}-NR", args.log.id_preamble, i), log_sink);
log.set_level(log_level);
log.set_hex_dump_max_size(args.log_hex_limit);
log.set_hex_dump_max_size(args.log.phy_hex_limit);
auto w = new slot_worker(common, stack, log);
pool.init_worker(i, w, args.prio);
@ -48,11 +56,10 @@ bool worker_pool::init(const args_t& args, const phy_cell_cfg_list_nr_t& cell_li
slot_worker::args_t w_args = {};
uint32_t cell_index = 0;
w_args.cell_index = cell_index;
w_args.carrier = cell_list[cell_index].carrier;
w_args.nof_max_prb = cell_list[cell_index].carrier.nof_prb;
w_args.nof_tx_ports = cell_list[cell_index].carrier.max_mimo_layers;
w_args.nof_rx_ports = cell_list[cell_index].carrier.max_mimo_layers;
w_args.pusch_max_nof_iter = args.pusch_max_nof_iter;
w_args.pdcch_cfg = cell_list[cell_index].pdcch;
if (not w->init(w_args)) {
return false;
@ -64,12 +71,41 @@ bool worker_pool::init(const args_t& args, const phy_cell_cfg_list_nr_t& cell_li
void worker_pool::start_worker(slot_worker* w)
{
// Feed PRACH detection before start processing
prach.new_tti(0, current_tti, w->get_buffer_rx(0));
// Start actual worker
pool.start_worker(w);
}
slot_worker* worker_pool::wait_worker(uint32_t tti)
{
return (slot_worker*)pool.wait_worker(tti);
slot_worker* w = (slot_worker*)pool.wait_worker(tti);
// Only if a worker was available
if (w != nullptr) {
srsran_carrier_nr_t carrier_;
srsran_pdcch_cfg_nr_t pdcch_cfg_;
// Copy configuration
{
std::unique_lock<std::mutex> lock(common_cfg_mutex);
carrier_ = carrier;
pdcch_cfg_ = pdcch_cfg;
}
// Set worker configuration
if (not w->set_common_cfg(carrier_, pdcch_cfg_)) {
logger.error("Error setting common config");
return nullptr;
}
}
// Save current TTI
current_tti = tti;
// Return worker
return w;
}
slot_worker* worker_pool::wait_worker_id(uint32_t id)
@ -80,6 +116,41 @@ slot_worker* worker_pool::wait_worker_id(uint32_t id)
void worker_pool::stop()
{
pool.stop();
prach.stop();
}
int worker_pool::set_common_cfg(const phy_interface_rrc_nr::common_cfg_t& common_cfg)
{
// Best effort to convert NR carrier into LTE cell
srsran_cell_t cell = {};
int ret = srsran_carrier_to_cell(&common_cfg.carrier, &cell);
if (ret < SRSRAN_SUCCESS) {
logger.error("Converting carrier to cell for PRACH (%d)", ret);
return SRSRAN_ERROR;
}
// Best effort to set up NR-PRACH config reused for NR
srsran_prach_cfg_t prach_cfg = common_cfg.prach;
uint32_t lte_nr_prach_offset = (common_cfg.carrier.nof_prb - cell.nof_prb) / 2;
if (prach_cfg.freq_offset < lte_nr_prach_offset) {
logger.error("prach_cfg.freq_offset=%d is not compatible with LTE", prach_cfg.freq_offset);
return SRSRAN_ERROR;
}
prach_cfg.freq_offset -= lte_nr_prach_offset;
prach_cfg.is_nr = true;
// Set the PRACH configuration
prach.init(0, cell, prach_cfg, &prach_stack_adaptor, logger, 0, 1);
prach.set_max_prach_offset_us(1000);
// Save current configuration
{
std::unique_lock<std::mutex> lock(common_cfg_mutex);
carrier = common_cfg.carrier;
pdcch_cfg = common_cfg.pdcch;
}
return SRSRAN_SUCCESS;
}
} // namespace nr

@ -1,76 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN 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.
*
* srsRAN 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 <string>
#include <sys/mman.h>
#include "srsenb/hdr/phy/vnf_phy_nr.h"
#include "srsran/common/basic_vnf_api.h"
using namespace std;
namespace srsenb {
vnf_phy_nr::~vnf_phy_nr()
{
stop();
}
void vnf_phy_nr::parse_config(const nr_phy_cfg_t& cfg) {}
int vnf_phy_nr::init(const srsenb::phy_args_t& args, const nr_phy_cfg_t& cfg, srsenb::stack_interface_phy_nr* stack_)
{
mlockall(MCL_CURRENT | MCL_FUTURE);
// create VNF
vnf = std::unique_ptr<srsran::srsran_basic_vnf>(new srsran::srsran_basic_vnf(args.vnf_args, stack_));
initialized = true;
return SRSRAN_SUCCESS;
}
void vnf_phy_nr::stop()
{
if (initialized) {
vnf->stop();
initialized = false;
}
}
// Start GUI
void vnf_phy_nr::start_plot() {}
void vnf_phy_nr::get_metrics(std::vector<srsenb::phy_metrics_t>& metrics) {}
int vnf_phy_nr::dl_config_request(const dl_config_request_t& request)
{
// prepare DL config request over basic API and send
return vnf->dl_config_request(request);
}
int vnf_phy_nr::tx_request(const tx_request_t& request)
{
// send Tx request over basic API
return vnf->tx_request(request);
}
} // namespace srsenb

@ -207,4 +207,6 @@ int gnb_stack_nr::pusch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interf
return m_mac->pusch_info(slot_cfg, pusch_info);
}
void gnb_stack_nr::rach_detected(const rach_info_t& rach_info) {}
} // namespace srsenb

@ -410,7 +410,7 @@ int mac::snr_info(uint32_t tti_rx, uint16_t rnti, uint32_t enb_cc_idx, float snr
return SRSRAN_ERROR;
}
rrc_h->set_radiolink_ul_state(rnti, snr > 0);
rrc_h->set_radiolink_ul_state(rnti, snr >= args.rlf_min_ul_snr_estim);
return scheduler.ul_snr_info(tti_rx, rnti, enb_cc_idx, snr, (uint32_t)ch);
}

@ -18,6 +18,7 @@
# and at http://www.gnu.org/licenses/.
#
set(SOURCES mac_nr.cc sched_nr.cc sched_nr_ue.cc sched_nr_worker.cc sched_nr_rb_grid.cc sched_nr_harq.cc sched_nr_pdcch.cc sched_nr_common.cc sched_nr_phy_helpers.cc)
set(SOURCES mac_nr.cc sched_nr.cc sched_nr_ue.cc sched_nr_worker.cc sched_nr_rb_grid.cc sched_nr_harq.cc
sched_nr_pdcch.cc sched_nr_cfg.cc sched_nr_helpers.cc sched_nr_bwp.cc sched_nr_rb.cc harq_softbuffer.cc)
add_library(srsgnb_mac STATIC ${SOURCES})

@ -0,0 +1,62 @@
/**
*
* \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 "srsenb/hdr/stack/mac/nr/harq_softbuffer.h"
#include "srsran/adt/pool/obj_pool.h"
namespace srsenb {
void harq_softbuffer_pool::init_pool(uint32_t nof_prb, uint32_t batch_size, uint32_t thres, uint32_t init_size)
{
srsran_assert(nof_prb <= SRSRAN_MAX_PRB_NR, "Invalid nof prb=%d", nof_prb);
size_t idx = nof_prb - 1;
if (tx_pool[idx] != nullptr) {
return;
}
if (thres == 0) {
thres = batch_size;
}
if (init_size == 0) {
init_size = batch_size;
}
auto init_tx_softbuffers = [nof_prb](void* ptr) { new (ptr) tx_harq_softbuffer(nof_prb); };
auto recycle_tx_softbuffers = [](tx_harq_softbuffer& softbuffer) { softbuffer.reset(); };
tx_pool[idx].reset(new srsran::background_obj_pool<tx_harq_softbuffer>(
batch_size, thres, init_size, init_tx_softbuffers, recycle_tx_softbuffers));
auto init_rx_softbuffers = [nof_prb](void* ptr) { new (ptr) rx_harq_softbuffer(nof_prb); };
auto recycle_rx_softbuffers = [](rx_harq_softbuffer& softbuffer) { softbuffer.reset(); };
rx_pool[idx].reset(new srsran::background_obj_pool<rx_harq_softbuffer>(
batch_size, thres, init_size, init_rx_softbuffers, recycle_rx_softbuffers));
}
srsran::unique_pool_ptr<tx_harq_softbuffer> harq_softbuffer_pool::get_tx(uint32_t nof_prb)
{
srsran_assert(nof_prb <= SRSRAN_MAX_PRB_NR, "Invalid Nprb=%d", nof_prb);
size_t idx = nof_prb - 1;
if (tx_pool[idx] == nullptr) {
init_pool(nof_prb);
}
return tx_pool[idx]->make();
}
srsran::unique_pool_ptr<rx_harq_softbuffer> harq_softbuffer_pool::get_rx(uint32_t nof_prb)
{
srsran_assert(nof_prb <= SRSRAN_MAX_PRB_NR, "Invalid Nprb=%d", nof_prb);
size_t idx = nof_prb - 1;
if (rx_pool[idx] == nullptr) {
init_pool(nof_prb);
}
return rx_pool[idx]->make();
}
} // namespace srsenb

@ -98,114 +98,6 @@ void mac_nr::stop()
void mac_nr::get_metrics(srsenb::mac_metrics_t& metrics) {}
// Fills both, DL_CONFIG.request and TX.request structs
void mac_nr::get_dl_config(const uint32_t tti,
phy_interface_stack_nr::dl_config_request_t& config_request,
phy_interface_stack_nr::tx_request_t& tx_request)
{
// send MIB over BCH every 80ms
if (tti % 80 == 0) {
// try to read BCH PDU from RRC
if (rrc_h->read_pdu_bcch_bch(tti, bcch_bch_payload) == SRSRAN_SUCCESS) {
logger.info("Adding BCH in TTI=%d", tti);
tx_request.pdus[tx_request.nof_pdus].pbch.mib_present = true;
tx_request.pdus[tx_request.nof_pdus].data[0] = bcch_bch_payload->msg;
tx_request.pdus[tx_request.nof_pdus].length = bcch_bch_payload->N_bytes;
tx_request.pdus[tx_request.nof_pdus].index = tx_request.nof_pdus;
tx_request.nof_pdus++;
if (pcap) {
pcap->write_dl_bch(bcch_bch_payload->msg, bcch_bch_payload->N_bytes, 0xffff, 0, tti);
}
} else {
logger.error("Couldn't read BCH payload from RRC");
}
}
// Schedule SIBs
for (auto& sib : bcch_dlsch_payload) {
if (sib.payload->N_bytes > 0) {
if (tti % (sib.periodicity * 10) == 0) {
logger.info("Adding SIB %d in TTI=%d", sib.index, tti);
tx_request.pdus[tx_request.nof_pdus].data[0] = sib.payload->msg;
tx_request.pdus[tx_request.nof_pdus].length = sib.payload->N_bytes;
tx_request.pdus[tx_request.nof_pdus].index = tx_request.nof_pdus;
if (pcap) {
pcap->write_dl_si_rnti_nr(sib.payload->msg, sib.payload->N_bytes, 0xffff, 0, tti);
}
tx_request.nof_pdus++;
}
}
}
// Add MAC padding if TTI is empty
if (tx_request.nof_pdus == 0) {
uint32_t buffer_index = tti % SRSRAN_FDD_NOF_HARQ;
ue_tx_buffer.at(buffer_index)->clear();
ue_tx_pdu.init_tx(ue_tx_buffer.at(buffer_index).get(), args.tb_size);
// read RLC PDU
ue_rlc_buffer->clear();
int pdu_len = rlc_h->read_pdu(args.rnti, 4, ue_rlc_buffer->msg, args.tb_size - 2);
// Only create PDU if RLC has something to tx
if (pdu_len > 0) {
logger.info("Adding MAC PDU for RNTI=%d", args.rnti);
ue_rlc_buffer->N_bytes = pdu_len;
logger.info(ue_rlc_buffer->msg, ue_rlc_buffer->N_bytes, "Read %d B from RLC", ue_rlc_buffer->N_bytes);
// add to MAC PDU and pack
ue_tx_pdu.add_sdu(4, ue_rlc_buffer->msg, ue_rlc_buffer->N_bytes);
ue_tx_pdu.pack();
logger.debug(ue_tx_buffer.at(buffer_index)->msg,
ue_tx_buffer.at(buffer_index)->N_bytes,
"Generated MAC PDU (%d B)",
ue_tx_buffer.at(buffer_index)->N_bytes);
tx_request.pdus[tx_request.nof_pdus].data[0] = ue_tx_buffer.at(buffer_index)->msg;
tx_request.pdus[tx_request.nof_pdus].length = ue_tx_buffer.at(buffer_index)->N_bytes;
tx_request.pdus[tx_request.nof_pdus].index = tx_request.nof_pdus;
if (pcap) {
pcap->write_dl_crnti_nr(tx_request.pdus[tx_request.nof_pdus].data[0],
tx_request.pdus[tx_request.nof_pdus].length,
args.rnti,
buffer_index,
tti);
}
tx_request.nof_pdus++;
}
}
config_request.tti = tti;
tx_request.tti = tti;
}
int mac_nr::slot_indication(const srsran_slot_cfg_t& slot_cfg)
{
phy_interface_stack_nr::dl_config_request_t config_request = {};
phy_interface_stack_nr::tx_request_t tx_request = {};
// step MAC TTI
logger.set_context(slot_cfg.idx);
get_dl_config(slot_cfg.idx, config_request, tx_request);
// send DL_CONFIG.request
phy_h->dl_config_request(config_request);
// send TX.request
phy_h->tx_request(tx_request);
return SRSRAN_SUCCESS;
}
int mac_nr::rx_data_indication(stack_interface_phy_nr::rx_data_ind_t& rx_data)
{
// push received PDU on queue
@ -279,6 +171,11 @@ int mac_nr::cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg)
return SRSRAN_SUCCESS;
}
int mac_nr::slot_indication(const srsran_slot_cfg_t& slot_cfg)
{
return 0;
}
int mac_nr::get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched)
{
return 0;
@ -295,5 +192,6 @@ int mac_nr::pusch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_ph
{
return 0;
}
void mac_nr::rach_detected(const mac_interface_phy_nr::rach_info_t& rach_info) {}
} // namespace srsenb

@ -20,15 +20,14 @@
*/
#include "srsenb/hdr/stack/mac/nr/sched_nr.h"
#include "srsenb/hdr/stack/mac/nr/harq_softbuffer.h"
#include "srsenb/hdr/stack/mac/nr/sched_nr_bwp.h"
#include "srsenb/hdr/stack/mac/nr/sched_nr_worker.h"
#include "srsran/common/thread_pool.h"
namespace srsenb {
using sched_nr_impl::sched_worker_manager;
using sched_nr_impl::ue;
using sched_nr_impl::ue_carrier;
using sched_nr_impl::ue_map_t;
using namespace sched_nr_impl;
static int assert_ue_cfg_valid(uint16_t rnti, const sched_nr_interface::ue_cfg_t& uecfg);
@ -53,7 +52,7 @@ public:
feedback_list.back().cc = cc;
feedback_list.back().callback = std::move(event);
}
void new_tti()
void new_slot()
{
{
std::lock_guard<std::mutex> lock(common_mutex);
@ -90,7 +89,71 @@ private:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
sched_nr::sched_nr(const sched_cfg_t& sched_cfg) : cfg(sched_cfg), pending_events(new ue_event_manager(ue_db)) {}
class sched_result_manager
{
public:
explicit sched_result_manager(uint32_t nof_cc_)
{
for (auto& v : results) {
v.resize(nof_cc_);
}
}
dl_sched_t& add_dl_result(tti_point tti, uint32_t cc)
{
if (not has_dl_result(tti, cc)) {
results[tti.to_uint()][cc].tti_dl = tti;
results[tti.to_uint()][cc].dl_res = {};
}
return results[tti.to_uint()][cc].dl_res;
}
ul_sched_t& add_ul_result(tti_point tti, uint32_t cc)
{
if (not has_ul_result(tti, cc)) {
results[tti.to_uint()][cc].tti_ul = tti;
results[tti.to_uint()][cc].ul_res = {};
}
return results[tti.to_uint()][cc].ul_res;
}
bool has_dl_result(tti_point tti, uint32_t cc) const { return results[tti.to_uint()][cc].tti_dl == tti; }
bool has_ul_result(tti_point tti, uint32_t cc) const { return results[tti.to_uint()][cc].tti_ul == tti; }
dl_sched_t pop_dl_result(tti_point tti, uint32_t cc)
{
if (has_dl_result(tti, cc)) {
results[tti.to_uint()][cc].tti_dl.reset();
return results[tti.to_uint()][cc].dl_res;
}
return {};
}
ul_sched_t pop_ul_result(tti_point tti, uint32_t cc)
{
if (has_ul_result(tti, cc)) {
results[tti.to_uint()][cc].tti_ul.reset();
return results[tti.to_uint()][cc].ul_res;
}
return {};
}
private:
struct slot_result_t {
tti_point tti_dl;
tti_point tti_ul;
dl_sched_t dl_res;
ul_sched_t ul_res;
};
srsran::circular_array<std::vector<slot_result_t>, TTIMOD_SZ> results;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
sched_nr::sched_nr(const sched_cfg_t& sched_cfg) :
cfg(sched_cfg), pending_events(new ue_event_manager(ue_db)), logger(srslog::fetch_basic_logger("MAC"))
{}
sched_nr::~sched_nr() {}
@ -101,7 +164,9 @@ int sched_nr::cell_cfg(srsran::const_span<cell_cfg_t> cell_list)
cfg.cells.emplace_back(cc, cell_list[cc], cfg.sched_cfg);
}
pending_results.reset(new sched_result_manager(cell_list.size()));
sched_workers.reset(new sched_nr_impl::sched_worker_manager(ue_db, cfg));
return SRSRAN_SUCCESS;
}
@ -114,39 +179,56 @@ void sched_nr::ue_cfg(uint16_t rnti, const ue_cfg_t& uecfg)
void sched_nr::ue_cfg_impl(uint16_t rnti, const ue_cfg_t& uecfg)
{
if (not ue_db.contains(rnti)) {
ue_db.insert(rnti, std::unique_ptr<ue>(new ue{rnti, uecfg}));
ue_db.insert(rnti, std::unique_ptr<ue>(new ue{rnti, uecfg, cfg}));
} else {
ue_db[rnti]->set_cfg(uecfg);
}
}
void sched_nr::slot_indication(tti_point tti_rx)
/// Generate {tti,cc} scheduling decision
int sched_nr::generate_slot_result(tti_point pdcch_tti, uint32_t cc)
{
// Lock slot workers for provided tti_rx
sched_workers->reserve_workers(tti_rx);
tti_point tti_rx = pdcch_tti - TX_ENB_DELAY;
{
// Lock carrier workers for provided tti_rx
sched_workers->start_slot(tti_rx, [this]() {
// In case it is first worker for the given slot
// synchronize {tti,cc} state. e.g. reserve UE resources for {tti,cc} decision, process feedback
std::lock_guard<std::mutex> lock(ue_db_mutex);
// Process pending events
pending_events->new_tti();
pending_events->new_slot();
});
sched_workers->start_tti(tti_rx);
// unlocked, parallel region
bool all_workers_finished = sched_workers->run_slot(tti_rx, cc);
if (all_workers_finished) {
// once all workers of the same subframe finished, synchronize sched outcome with ue_db
sched_workers->release_slot(tti_rx);
}
// Copy results to intermediate buffer
dl_sched_t& dl_res = pending_results->add_dl_result(pdcch_tti, cc);
ul_sched_t& ul_res = pending_results->add_ul_result(pdcch_tti, cc);
sched_workers->save_sched_result(pdcch_tti, cc, dl_res, ul_res);
return SRSRAN_SUCCESS;
}
/// Generate {tti,cc} scheduling decision
int sched_nr::generate_sched_result(tti_point tti_rx, uint32_t cc, tti_request_t& req)
int sched_nr::get_dl_sched(tti_point tti_tx, uint32_t cc, dl_sched_t& result)
{
// unlocked, parallel region
bool all_workers_finished = sched_workers->run_tti(tti_rx, cc, req);
if (not pending_results->has_dl_result(tti_tx, cc)) {
generate_slot_result(tti_tx, cc);
}
if (all_workers_finished) {
// once all workers of the same subframe finished, synchronize sched outcome with ue_db
std::lock_guard<std::mutex> lock(ue_db_mutex);
sched_workers->end_tti(tti_rx);
result = pending_results->pop_dl_result(tti_tx, cc);
return SRSRAN_SUCCESS;
}
int sched_nr::get_ul_sched(tti_point tti_rx, uint32_t cc, ul_sched_t& result)
{
if (not pending_results->has_ul_result(tti_rx, cc)) {
return SRSRAN_ERROR;
}
result = pending_results->pop_ul_result(tti_rx, cc);
return SRSRAN_SUCCESS;
}
@ -165,15 +247,21 @@ void sched_nr::ul_sr_info(tti_point tti_rx, uint16_t rnti)
});
}
#define VERIFY_INPUT(cond, msg, ...) \
do { \
if (not(cond)) { \
srslog::fetch_basic_logger("MAC").warning(msg, ##__VA_ARGS__); \
return SRSRAN_ERROR; \
} \
} while (0)
int assert_ue_cfg_valid(uint16_t rnti, const sched_nr_interface::ue_cfg_t& uecfg)
{
const srslog::basic_logger& logger = srslog::fetch_basic_logger("MAC");
if (std::count(&uecfg.phy_cfg.pdcch.coreset_present[0],
VERIFY_INPUT(std::count(&uecfg.phy_cfg.pdcch.coreset_present[0],
&uecfg.phy_cfg.pdcch.coreset_present[SRSRAN_UE_DL_NR_MAX_NOF_CORESET],
true) == 0) {
logger.warning("Provided rnti=0x%x configuration does not contain any coreset", rnti);
return SRSRAN_ERROR;
}
true) > 0,
"Provided rnti=0x%x configuration does not contain any coreset",
rnti);
return SRSRAN_SUCCESS;
}

@ -0,0 +1,161 @@
/**
*
* \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 "srsenb/hdr/stack/mac/nr/sched_nr_bwp.h"
#include "srsran/common/standard_streams.h"
#include "srsran/common/string_helpers.h"
namespace srsenb {
namespace sched_nr_impl {
ra_sched::ra_sched(const bwp_params& bwp_cfg_) : bwp_cfg(&bwp_cfg_), logger(srslog::fetch_basic_logger("MAC")) {}
alloc_result
ra_sched::allocate_pending_rar(bwp_slot_allocator& slot_grid, const pending_rar_t& rar, uint32_t& nof_grants_alloc)
{
const uint32_t rar_aggr_level = 2;
const prb_bitmap& prbs = slot_grid.res_grid()[slot_grid.get_pdcch_tti()].dl_prbs.prbs();
alloc_result ret = alloc_result::other_cause;
for (nof_grants_alloc = rar.msg3_grant.size(); nof_grants_alloc > 0; nof_grants_alloc--) {
ret = alloc_result::invalid_coderate;
uint32_t start_prb_idx = 0;
for (uint32_t nprb = 1; nprb < bwp_cfg->cfg.rb_width and ret == alloc_result::invalid_coderate; ++nprb) {
prb_interval interv = find_empty_interval_of_length(prbs, nprb, start_prb_idx);
start_prb_idx = interv.stop();
if (interv.length() == nprb) {
ret = slot_grid.alloc_rar(rar_aggr_level, rar, interv, nof_grants_alloc);
} else {
ret = alloc_result::no_sch_space;
}
}
// If allocation was not successful because there were not enough RBGs, try allocating fewer Msg3 grants
if (ret != alloc_result::invalid_coderate and ret != alloc_result::no_sch_space) {
break;
}
}
if (ret != alloc_result::success) {
logger.info("SCHED: RAR allocation for L=%d was postponed. Cause=%s", rar_aggr_level, to_string(ret));
}
return ret;
}
void ra_sched::run_slot(bwp_slot_allocator& slot_grid)
{
static const uint32_t PRACH_RAR_OFFSET = 3;
tti_point pdcch_tti = slot_grid.get_pdcch_tti();
for (auto it = pending_rars.begin(); it != pending_rars.end();) {
pending_rar_t& rar = *it;
// In case of RAR outside RAR window:
// - if window has passed, discard RAR
// - if window hasn't started, stop loop, as RARs are ordered by TTI
tti_interval rar_window{rar.prach_tti + PRACH_RAR_OFFSET,
rar.prach_tti + PRACH_RAR_OFFSET + bwp_cfg->cfg.rar_window_size};
if (not rar_window.contains(pdcch_tti)) {
if (pdcch_tti >= rar_window.stop()) {
fmt::memory_buffer str_buffer;
fmt::format_to(str_buffer,
"SCHED: Could not transmit RAR within the window (RA={}, Window={}, RAR={}",
rar.prach_tti,
rar_window,
pdcch_tti);
srsran::console("%s\n", srsran::to_c_str(str_buffer));
logger.warning("%s", srsran::to_c_str(str_buffer));
it = pending_rars.erase(it);
continue;
}
return;
}
// Try to schedule DCI + RBGs for RAR Grant
uint32_t nof_rar_allocs = 0;
alloc_result ret = allocate_pending_rar(slot_grid, rar, nof_rar_allocs);
if (ret == alloc_result::success) {
// If RAR allocation was successful:
// - in case all Msg3 grants were allocated, remove pending RAR, and continue with following RAR
// - otherwise, erase only Msg3 grants that were allocated, and stop iteration
if (nof_rar_allocs == rar.msg3_grant.size()) {
it = pending_rars.erase(it);
} else {
std::copy(rar.msg3_grant.begin() + nof_rar_allocs, rar.msg3_grant.end(), rar.msg3_grant.begin());
rar.msg3_grant.resize(rar.msg3_grant.size() - nof_rar_allocs);
break;
}
} else {
// If RAR allocation was not successful:
// - in case of unavailable PDCCH space, try next pending RAR allocation
// - otherwise, stop iteration
if (ret != alloc_result::no_cch_space) {
break;
}
++it;
}
}
}
int ra_sched::dl_rach_info(const dl_sched_rar_info_t& rar_info)
{
logger.info("SCHED: New PRACH tti=%d, preamble=%d, temp_crnti=0x%x, ta_cmd=%d, msg3_size=%d",
rar_info.prach_tti,
rar_info.preamble_idx,
rar_info.temp_crnti,
rar_info.ta_cmd,
rar_info.msg3_size);
// RA-RNTI = 1 + t_id + f_id
// t_id = index of first subframe specified by PRACH (0<=t_id<10)
// f_id = index of the PRACH within subframe, in ascending order of freq domain (0<=f_id<6) (for FDD, f_id=0)
uint16_t ra_rnti = 1 + (uint16_t)(rar_info.prach_tti % 10u);
// find pending rar with same RA-RNTI
for (pending_rar_t& r : pending_rars) {
if (r.prach_tti.to_uint() == rar_info.prach_tti and ra_rnti == r.ra_rnti) {
if (r.msg3_grant.size() >= sched_interface::MAX_RAR_LIST) {
logger.warning("PRACH ignored, as the the maximum number of RAR grants per tti has been reached");
return SRSRAN_ERROR;
}
r.msg3_grant.push_back(rar_info);
return SRSRAN_SUCCESS;
}
}
// create new RAR
pending_rar_t p;
p.ra_rnti = ra_rnti;
p.prach_tti = tti_point{rar_info.prach_tti};
p.msg3_grant.push_back(rar_info);
pending_rars.push_back(p);
return SRSRAN_SUCCESS;
}
bwp_ctxt::bwp_ctxt(const bwp_params& bwp_cfg) : cfg(&bwp_cfg), ra(bwp_cfg), grid(bwp_cfg) {}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
serv_cell_ctxt::serv_cell_ctxt(const sched_cell_params& cell_cfg_) : cfg(&cell_cfg_)
{
for (uint32_t bwp_id = 0; bwp_id < cfg->cell_cfg.bwps.size(); ++bwp_id) {
bwps.emplace_back(cell_cfg_.bwps[bwp_id]);
}
// Pre-allocate HARQs in common pool of softbuffers
harq_softbuffer_pool::get_instance().init_pool(cfg->nof_prb());
}
} // namespace sched_nr_impl
} // namespace srsenb

@ -0,0 +1,110 @@
/**
*
* \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 "srsenb/hdr/stack/mac/nr/sched_nr_cfg.h"
#include "srsenb/hdr/stack/mac/nr/sched_nr_helpers.h"
namespace srsenb {
namespace sched_nr_impl {
bwp_params::bwp_params(const cell_cfg_t& cell, const sched_cfg_t& sched_cfg_, uint32_t cc_, uint32_t bwp_id_) :
cell_cfg(cell), sched_cfg(sched_cfg_), cc(cc_), bwp_id(bwp_id_), cfg(cell.bwps[bwp_id_])
{
P = get_P(cfg.rb_width, cfg.pdsch.rbg_size_cfg_1);
N_rbg = get_nof_rbgs(cfg.rb_width, cfg.start_rb, cfg.pdsch.rbg_size_cfg_1);
srsran_assert(bwp_id != 0 or cfg.pdcch.coreset_present[0], "CORESET#0 has to be active for initial BWP");
}
sched_cell_params::sched_cell_params(uint32_t cc_, const cell_cfg_t& cell, const sched_cfg_t& sched_cfg_) :
cc(cc_), cell_cfg(cell), sched_cfg(sched_cfg_)
{
bwps.reserve(cell.bwps.size());
for (uint32_t i = 0; i < cell.bwps.size(); ++i) {
bwps.emplace_back(cell, sched_cfg_, cc, i);
}
srsran_assert(not bwps.empty(), "No BWPs were configured");
}
sched_params::sched_params(const sched_cfg_t& sched_cfg_) : sched_cfg(sched_cfg_) {}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void get_dci_locs(const srsran_coreset_t& coreset,
const srsran_search_space_t& search_space,
uint16_t rnti,
bwp_cce_pos_list& cce_locs)
{
for (uint32_t sl = 0; sl < SRSRAN_NOF_SF_X_FRAME; ++sl) {
for (uint32_t agg_idx = 0; agg_idx < MAX_NOF_AGGR_LEVELS; ++agg_idx) {
pdcch_cce_pos_list pdcch_locs;
cce_locs[sl][agg_idx].resize(pdcch_locs.capacity());
uint32_t n =
srsran_pdcch_nr_locations_coreset(&coreset, &search_space, rnti, agg_idx, sl, cce_locs[sl][agg_idx].data());
cce_locs[sl][agg_idx].resize(n);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bwp_ue_cfg::bwp_ue_cfg(uint16_t rnti_, const bwp_params& bwp_cfg_, const ue_cfg_t& uecfg_) :
rnti(rnti_), cfg_(&uecfg_), bwp_cfg(&bwp_cfg_)
{
std::fill(ss_id_to_cce_idx.begin(), ss_id_to_cce_idx.end(), SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE);
const auto& pdcch = phy().pdcch;
for (uint32_t i = 0; i < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE; ++i) {
if (pdcch.search_space_present[i]) {
const auto& ss = pdcch.search_space[i];
srsran_assert(pdcch.coreset_present[ss.coreset_id],
"Invalid mapping search space id=%d to coreset id=%d",
ss.id,
ss.coreset_id);
const auto& coreset = pdcch.coreset[ss.coreset_id];
cce_positions_list.emplace_back();
get_dci_locs(coreset, ss, rnti, cce_positions_list.back());
ss_id_to_cce_idx[ss.id] = cce_positions_list.size() - 1;
}
}
}
ue_cfg_extended::ue_cfg_extended(uint16_t rnti_, const ue_cfg_t& uecfg) : ue_cfg_t(uecfg), rnti(rnti_)
{
cc_params.resize(carriers.size());
for (uint32_t cc = 0; cc < cc_params.size(); ++cc) {
cc_params[cc].bwps.resize(1);
auto& bwp = cc_params[cc].bwps[0];
for (uint32_t ssid = 0; ssid < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE; ++ssid) {
if (phy_cfg.pdcch.search_space_present[ssid]) {
auto& ss = phy_cfg.pdcch.search_space[ssid];
bwp.ss_list[ss.id].emplace();
bwp.ss_list[ss.id]->cfg = &ss;
get_dci_locs(phy_cfg.pdcch.coreset[ss.coreset_id], ss, rnti, bwp.ss_list[ss.id]->cce_positions);
}
}
for (uint32_t idx = 0; idx < SRSRAN_UE_DL_NR_MAX_NOF_CORESET; ++idx) {
if (phy_cfg.pdcch.coreset_present[idx]) {
bwp.coresets.emplace_back();
auto& coreset = bwp.coresets.back();
coreset.cfg = &phy_cfg.pdcch.coreset[idx];
for (auto& ss : bwp.ss_list) {
if (ss.has_value() and ss->cfg->coreset_id == coreset.cfg->id) {
coreset.ss_list.push_back(ss->cfg->id);
}
}
}
}
}
}
} // namespace sched_nr_impl
} // namespace srsenb

@ -1,52 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN 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.
*
* srsRAN 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 "srsenb/hdr/stack/mac/nr/sched_nr_common.h"
namespace srsenb {
namespace sched_nr_impl {
sched_cell_params::sched_cell_params(uint32_t cc_, const cell_cfg_t& cell, const sched_cfg_t& sched_cfg_) :
cc(cc_), cell_cfg(cell), sched_cfg(sched_cfg_)
{}
sched_params::sched_params(const sched_cfg_t& sched_cfg_) : sched_cfg(sched_cfg_) {}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void get_dci_locs(const srsran_coreset_t& coreset,
const srsran_search_space_t& search_space,
uint16_t rnti,
bwp_cce_pos_list& cce_locs)
{
for (uint32_t sl = 0; sl < SRSRAN_NOF_SF_X_FRAME; ++sl) {
for (uint32_t agg_idx = 0; agg_idx < MAX_NOF_AGGR_LEVELS; ++agg_idx) {
pdcch_cce_pos_list pdcch_locs;
cce_locs[sl][agg_idx].resize(pdcch_locs.capacity());
uint32_t n =
srsran_pdcch_nr_locations_coreset(&coreset, &search_space, rnti, agg_idx, sl, cce_locs[sl][agg_idx].data());
cce_locs[sl][agg_idx].resize(n);
}
}
}
} // namespace sched_nr_impl
} // namespace srsenb

@ -54,7 +54,7 @@ void harq_proc::reset()
bool harq_proc::new_tx(tti_point tti_tx_,
tti_point tti_ack_,
const rbgmask_t& rbgmask_,
const prb_grant& grant,
uint32_t mcs,
uint32_t tbs,
uint32_t max_retx_)
@ -66,7 +66,7 @@ bool harq_proc::new_tx(tti_point tti_tx_,
max_retx = max_retx_;
tti_tx = tti_tx_;
tti_ack = tti_ack_;
rbgmask = rbgmask_;
prbs_ = grant;
tb[0].ndi = !tb[0].ndi;
tb[0].mcs = mcs;
tb[0].tbs = tbs;
@ -74,32 +74,49 @@ bool harq_proc::new_tx(tti_point tti_tx_,
return true;
}
bool harq_proc::new_retx(tti_point tti_tx_, tti_point tti_ack_, const rbgmask_t& rbgmask_, int* mcs, int* tbs)
bool harq_proc::set_tbs(uint32_t tbs)
{
if (empty() or rbgmask.count() != rbgmask.count()) {
if (empty() or nof_retx() > 0) {
return false;
}
tb[0].tbs = tbs;
return true;
}
bool harq_proc::new_retx(tti_point tti_tx_, tti_point tti_ack_, const prb_grant& grant)
{
if (grant.is_alloc_type0() != prbs_.is_alloc_type0() or
(grant.is_alloc_type0() and grant.rbgs().count() != prbs_.rbgs().count()) or
(grant.is_alloc_type1() and grant.prbs().length() == prbs_.prbs().length())) {
return false;
}
if (new_retx(tti_tx_, tti_ack_)) {
prbs_ = grant;
return true;
}
return false;
}
bool harq_proc::new_retx(tti_point tti_tx_, tti_point tti_ack_)
{
if (empty()) {
return false;
}
tti_tx = tti_tx_;
tti_ack = tti_ack_;
rbgmask = rbgmask_;
tb[0].ack_state = false;
tb[0].n_rtx++;
if (mcs != nullptr) {
*mcs = tb[0].mcs;
}
if (tbs != nullptr) {
*tbs = tb[0].tbs;
}
return true;
}
harq_entity::harq_entity(uint32_t nof_harq_procs)
harq_entity::harq_entity(uint32_t nprb, uint32_t nof_harq_procs)
{
// Create HARQs
dl_harqs.reserve(nof_harq_procs);
ul_harqs.reserve(nof_harq_procs);
for (uint32_t pid = 0; pid < nof_harq_procs; ++pid) {
dl_harqs.emplace_back(pid);
ul_harqs.emplace_back(pid);
dl_harqs.emplace_back(pid, nprb);
ul_harqs.emplace_back(pid, nprb);
}
}

@ -0,0 +1,85 @@
/**
*
* \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 "srsenb/hdr/stack/mac/nr/sched_nr_helpers.h"
#include "srsenb/hdr/stack/mac/nr/sched_nr_harq.h"
#include "srsenb/hdr/stack/mac/nr/sched_nr_ue.h"
namespace srsenb {
namespace sched_nr_impl {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool fill_dci_rar(prb_interval interv, const bwp_params& cell, srsran_dci_dl_nr_t& dci)
{
dci.mcs = 5;
return true;
}
template <typename DciDlOrUl>
void fill_dci_common(const slot_ue& ue, const bwp_params& bwp_cfg, DciDlOrUl& dci)
{
const static uint32_t rv_idx[4] = {0, 2, 3, 1};
dci.bwp_id = ue.cfg->active_bwp().bwp_id;
dci.cc_id = ue.cc;
dci.tpc = 1;
// harq
harq_proc* h = std::is_same<DciDlOrUl, srsran_dci_dl_nr_t>::value ? ue.h_dl : ue.h_ul;
dci.pid = h->pid;
dci.ndi = h->ndi();
dci.mcs = h->mcs();
dci.rv = rv_idx[h->nof_retx() % 4];
// PRB assignment
const prb_grant& grant = h->prbs();
if (grant.is_alloc_type0()) {
dci.freq_domain_assigment = grant.rbgs().to_uint64();
} else {
dci.freq_domain_assigment =
srsran_ra_nr_type1_riv(bwp_cfg.cfg.rb_width, grant.prbs().start(), grant.prbs().length());
}
dci.time_domain_assigment = 0;
}
void fill_dl_dci_ue_fields(const slot_ue& ue,
const bwp_params& bwp_cfg,
uint32_t ss_id,
srsran_dci_location_t dci_pos,
srsran_dci_dl_nr_t& dci)
{
// Note: DCI location may not be the final one, as scheduler may rellocate the UE PDCCH. However, the remaining DCI
// params are independent of the exact DCI location
bool ret = ue.cfg->phy().get_dci_ctx_pdsch_rnti_c(ss_id, dci_pos, ue.rnti, dci.ctx);
srsran_assert(ret, "Invalid DL DCI format");
fill_dci_common(ue, bwp_cfg, dci);
if (dci.ctx.format == srsran_dci_format_nr_1_0) {
dci.harq_feedback = ue.cfg->phy().harq_ack.dl_data_to_ul_ack[ue.pdsch_tti.sf_idx()] - 1;
} else {
dci.harq_feedback = ue.pdsch_tti.sf_idx();
}
}
void fill_ul_dci_ue_fields(const slot_ue& ue,
const bwp_params& bwp_cfg,
uint32_t ss_id,
srsran_dci_location_t dci_pos,
srsran_dci_ul_nr_t& dci)
{
bool ret = ue.cfg->phy().get_dci_ctx_pdsch_rnti_c(ss_id, dci_pos, ue.rnti, dci.ctx);
srsran_assert(ret, "Invalid DL DCI format");
fill_dci_common(ue, bwp_cfg, dci);
}
} // namespace sched_nr_impl
} // namespace srsenb

@ -25,22 +25,25 @@
namespace srsenb {
namespace sched_nr_impl {
coreset_region::coreset_region(uint32_t bwp_id_,
coreset_region::coreset_region(const bwp_params& bwp_cfg_,
uint32_t coreset_id_,
uint32_t slot_idx_,
uint32_t nof_td_symbols,
uint32_t nof_freq_resources,
pdcch_dl_list_t& pdcch_list_) :
bwp_id(bwp_id_),
pdcch_dl_list_t& dl_list_,
pdcch_ul_list_t& ul_list_) :
coreset_cfg(&bwp_cfg_.cfg.pdcch.coreset[coreset_id_]),
coreset_id(coreset_id_),
slot_idx(slot_idx_),
nof_symbols(nof_td_symbols),
nof_freq_res(nof_freq_resources),
pdcch_dl_list(pdcch_list_)
pdcch_dl_list(dl_list_),
pdcch_ul_list(ul_list_)
{
srsran_assert(nof_td_symbols <= SRSRAN_CORESET_DURATION_MAX,
const bool* res_active = &coreset_cfg->freq_resources[0];
nof_freq_res = std::count(res_active, res_active + SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE, true);
srsran_assert(get_td_symbols() <= SRSRAN_CORESET_DURATION_MAX,
"Possible number of time-domain OFDM symbols in CORESET must be within {1,2,3}");
srsran_assert(nof_freq_resources <= SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE,
"Provided number of CORESET freq domain resources=%d is too high",
nof_freq_resources);
srsran_assert(nof_freq_res <= bwp_cfg_.cell_cfg.carrier.nof_prb,
"The number of frequency resources=%d of coreset_id=%d exceeds BWP bandwidth",
nof_freq_res,
coreset_id);
}
void coreset_region::reset()
@ -49,9 +52,13 @@ void coreset_region::reset()
saved_dfs_tree.clear();
dci_list.clear();
pdcch_dl_list.clear();
pdcch_ul_list.clear();
}
bool coreset_region::alloc_dci(pdcch_grant_type_t alloc_type, uint32_t aggr_idx, uint32_t coreset_id, slot_ue* user)
bool coreset_region::alloc_dci(pdcch_grant_type_t alloc_type,
uint32_t aggr_idx,
uint32_t search_space_id,
slot_ue* user)
{
srsran_assert(aggr_idx <= 4, "Invalid DCI aggregation level=%d", 1U << aggr_idx);
srsran_assert((user == nullptr) xor
@ -62,10 +69,15 @@ bool coreset_region::alloc_dci(pdcch_grant_type_t alloc_type, uint32_t aggr_idx,
alloc_record record;
record.ue = user;
record.aggr_idx = aggr_idx;
record.ss_id = search_space_id;
record.alloc_type = alloc_type;
if (record.alloc_type == pdcch_grant_type_t::ul_data) {
record.idx = pdcch_ul_list.size();
pdcch_ul_list.emplace_back();
} else {
record.idx = pdcch_dl_list.size();
record.coreset_id = coreset_id;
pdcch_dl_list.emplace_back();
}
// Try to allocate grant. If it fails, attempt the same grant, but using a different permutation of past grant DCI
// positions
@ -83,7 +95,11 @@ bool coreset_region::alloc_dci(pdcch_grant_type_t alloc_type, uint32_t aggr_idx,
// Revert steps to initial state, before dci record allocation was attempted
dfs_tree = saved_dfs_tree;
if (record.alloc_type == pdcch_grant_type_t::ul_data) {
pdcch_ul_list.pop_back();
} else {
pdcch_dl_list.pop_back();
}
return false;
}
@ -93,9 +109,13 @@ void coreset_region::rem_last_dci()
// Remove DCI record
dfs_tree.pop_back();
dci_list.pop_back();
if (dci_list.back().alloc_type == pdcch_grant_type_t::ul_data) {
pdcch_ul_list.pop_back();
} else {
pdcch_dl_list.pop_back();
}
dci_list.pop_back();
}
bool coreset_region::get_next_dfs()
{
@ -150,8 +170,13 @@ bool coreset_region::alloc_dfs_node(const alloc_record& record, uint32_t start_d
// Allocation successful
node.total_mask |= node.current_mask;
alloc_dfs.push_back(node);
if (record.alloc_type == pdcch_grant_type_t::ul_data) {
pdcch_ul_t& pdcch_ul = pdcch_ul_list[record.idx];
pdcch_ul.dci.ctx.location = node.dci_pos;
} else {
pdcch_dl_t& pdcch_dl = pdcch_dl_list[record.idx];
pdcch_dl.dci.ctx.location = node.dci_pos;
}
return true;
}
@ -162,10 +187,9 @@ srsran::span<const uint32_t> coreset_region::get_cce_loc_table(const alloc_recor
{
switch (record.alloc_type) {
case pdcch_grant_type_t::dl_data:
return record.ue->cfg->cc_params[record.ue->cc]
.bwps[bwp_id]
.coresets[record.coreset_id]
.cce_positions[slot_idx][record.aggr_idx];
return record.ue->cfg->cce_pos_list(record.ss_id)[slot_idx][record.aggr_idx];
case pdcch_grant_type_t::ul_data:
return record.ue->cfg->cce_pos_list(record.ss_id)[slot_idx][record.aggr_idx];
default:
break;
}

@ -1,111 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN 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.
*
* srsRAN 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 "srsenb/hdr/stack/mac/nr/sched_nr_phy_helpers.h"
#include "srsenb/hdr/stack/mac/nr/sched_nr_harq.h"
#include "srsenb/hdr/stack/mac/nr/sched_nr_ue.h"
namespace srsenb {
namespace sched_nr_impl {
/// Table 6.1.2.2.1-1 - Nominal RBG size P
uint32_t get_P(uint32_t bwp_nof_prb, bool config_1_or_2)
{
srsran_assert(bwp_nof_prb > 0 and bwp_nof_prb <= 275, "Invalid BWP size");
if (bwp_nof_prb <= 36) {
return config_1_or_2 ? 2 : 4;
}
if (bwp_nof_prb <= 72) {
return config_1_or_2 ? 4 : 8;
}
if (bwp_nof_prb <= 144) {
return config_1_or_2 ? 8 : 16;
}
return 16;
}
uint32_t get_nof_rbgs(uint32_t bwp_nof_prb, uint32_t bwp_start, bool config1_or_2)
{
uint32_t P = get_P(bwp_nof_prb, config1_or_2);
return srsran::ceil_div(bwp_nof_prb + (bwp_start % P), P);
}
uint32_t get_rbg_size(uint32_t bwp_nof_prb, uint32_t bwp_start, bool config1_or_2, uint32_t rbg_idx)
{
uint32_t P = get_P(bwp_nof_prb, config1_or_2);
uint32_t nof_rbgs = get_nof_rbgs(bwp_nof_prb, bwp_start, config1_or_2);
if (rbg_idx == 0) {
return P - (bwp_start % P);
}
if (rbg_idx == nof_rbgs - 1) {
uint32_t ret = (bwp_start + bwp_nof_prb) % P;
return ret > 0 ? ret : P;
}
return P;
}
void bitmap_to_prb_array(const rbgmask_t& bitmap, uint32_t bwp_nof_prb, srsran_sch_grant_nr_t& grant)
{
uint32_t count = 0;
grant.nof_prb = bwp_nof_prb;
for (uint32_t rbg = 0; rbg < bitmap.size(); ++rbg) {
bool val = bitmap.test(rbg);
uint32_t rbg_size = get_rbg_size(bwp_nof_prb, 0, true, rbg);
for (uint32_t prb = count; prb < count + rbg_size; ++prb) {
grant.prb_idx[prb] = val;
}
}
}
void fill_dci_harq(const harq_proc& h, srsran_dci_dl_nr_t& dci)
{
dci.pid = h.pid;
dci.ndi = h.ndi();
dci.mcs = h.mcs();
}
void fill_dci_ue_cfg(const slot_ue& ue, srsran_dci_dl_nr_t& dci)
{
dci.bwp_id = ue.bwp_id;
dci.cc_id = ue.cc;
dci.ctx.rnti = ue.rnti;
dci.tpc = 1;
fill_dci_harq(*ue.h_dl, dci);
}
void fill_dci_harq(const harq_proc& h, srsran_dci_ul_nr_t& dci)
{
dci.pid = h.pid;
dci.ndi = h.ndi();
dci.mcs = h.mcs();
}
void fill_dci_ue_cfg(const slot_ue& ue, srsran_dci_ul_nr_t& dci)
{
dci.bwp_id = ue.bwp_id;
dci.cc_id = ue.cc;
dci.ctx.rnti = ue.rnti;
dci.tpc = 1;
fill_dci_harq(*ue.h_ul, dci);
}
} // namespace sched_nr_impl
} // namespace srsenb

@ -0,0 +1,105 @@
/**
*
* \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 "srsenb/hdr/stack/mac/nr/sched_nr_rb.h"
namespace srsenb {
namespace sched_nr_impl {
/// TS 38.214, Table 6.1.2.2.1-1 - Nominal RBG size P
uint32_t get_P(uint32_t bwp_nof_prb, bool config_1_or_2)
{
srsran_assert(bwp_nof_prb > 0 and bwp_nof_prb <= 275, "Invalid BWP size");
if (bwp_nof_prb <= 36) {
return config_1_or_2 ? 2 : 4;
}
if (bwp_nof_prb <= 72) {
return config_1_or_2 ? 4 : 8;
}
if (bwp_nof_prb <= 144) {
return config_1_or_2 ? 8 : 16;
}
return 16;
}
/// TS 38.214 - total number of RBGs for a uplink bandwidth part of size "bwp_nof_prb" PRBs
uint32_t get_nof_rbgs(uint32_t bwp_nof_prb, uint32_t bwp_start, bool config1_or_2)
{
uint32_t P = get_P(bwp_nof_prb, config1_or_2);
return srsran::ceil_div(bwp_nof_prb + (bwp_start % P), P);
}
uint32_t get_rbg_size(uint32_t bwp_nof_prb, uint32_t bwp_start, bool config1_or_2, uint32_t rbg_idx)
{
uint32_t P = get_P(bwp_nof_prb, config1_or_2);
uint32_t nof_rbgs = get_nof_rbgs(bwp_nof_prb, bwp_start, config1_or_2);
if (rbg_idx == 0) {
return P - (bwp_start % P);
}
if (rbg_idx == nof_rbgs - 1) {
uint32_t ret = (bwp_start + bwp_nof_prb) % P;
return ret > 0 ? ret : P;
}
return P;
}
bwp_rb_bitmap::bwp_rb_bitmap(uint32_t bwp_nof_prbs, uint32_t bwp_prb_start_, bool config1_or_2) :
prbs_(bwp_nof_prbs),
rbgs_(get_nof_rbgs(bwp_nof_prbs, bwp_prb_start_, config1_or_2)),
P_(get_P(bwp_nof_prbs, config1_or_2)),
Pnofbits(log2(P_)),
first_rbg_size(get_rbg_size(bwp_nof_prbs, bwp_prb_start_, config1_or_2, 0))
{}
uint32_t bwp_rb_bitmap::prb_to_rbg_idx(uint32_t prb_idx) const
{
return ((prb_idx + P_ - first_rbg_size) >> Pnofbits);
}
void bwp_rb_bitmap::add_prbs_to_rbgs(const prb_bitmap& grant)
{
int idx = 0;
do {
idx = grant.find_lowest(idx, grant.size(), true);
if (idx < 0) {
return;
}
uint32_t rbg_idx = prb_to_rbg_idx(idx);
rbgs_.set(rbg_idx, true);
idx++;
} while (idx != (int)prbs_.size());
}
void bwp_rb_bitmap::add_prbs_to_rbgs(const prb_interval& grant)
{
uint32_t rbg_start = prb_to_rbg_idx(grant.start());
uint32_t rbg_stop = std::min(prb_to_rbg_idx(grant.stop() - 1) + 1u, (uint32_t)rbgs_.size());
rbgs_.fill(rbg_start, rbg_stop);
}
void bwp_rb_bitmap::add_rbgs_to_prbs(const rbg_bitmap& grant)
{
int idx = 0;
do {
idx = grant.find_lowest(idx, grant.size(), true);
if (idx < 0) {
return;
}
uint32_t prb_idx = (idx - 1) * P_ + first_rbg_size;
uint32_t prb_end = std::min(prb_idx + ((idx == 0) ? first_rbg_size : P_), (uint32_t)prbs_.size());
prbs_.fill(prb_idx, prb_end);
idx++;
} while (idx != (int)prbs_.size());
}
} // namespace sched_nr_impl
} // namespace srsenb

@ -20,138 +20,239 @@
*/
#include "srsenb/hdr/stack/mac/nr/sched_nr_rb_grid.h"
#include "srsenb/hdr/stack/mac/nr/sched_nr_phy_helpers.h"
#include "srsenb/hdr/stack/mac/nr/sched_nr_helpers.h"
namespace srsenb {
namespace sched_nr_impl {
using pusch_grant = sched_nr_interface::pusch_grant;
#define NUMEROLOGY_IDX 0
bwp_slot_grid::bwp_slot_grid(const sched_cell_params& cell_params, uint32_t bwp_id_, uint32_t slot_idx_) :
dl_rbgs(cell_params.cell_cfg.nof_rbg), ul_rbgs(cell_params.cell_cfg.nof_rbg)
bwp_slot_grid::bwp_slot_grid(const bwp_params& bwp_cfg_, uint32_t slot_idx_) :
dl_prbs(bwp_cfg_.cfg.rb_width, bwp_cfg_.cfg.start_rb, bwp_cfg_.cfg.pdsch.rbg_size_cfg_1),
ul_prbs(bwp_cfg_.cfg.rb_width, bwp_cfg_.cfg.start_rb, bwp_cfg_.cfg.pdsch.rbg_size_cfg_1),
slot_idx(slot_idx_),
cfg(&bwp_cfg_),
is_dl(srsran_tdd_nr_is_dl(&bwp_cfg_.cell_cfg.tdd, NUMEROLOGY_IDX, slot_idx_)),
is_ul(srsran_tdd_nr_is_ul(&bwp_cfg_.cell_cfg.tdd, NUMEROLOGY_IDX, slot_idx_))
{
coresets.emplace_back(bwp_id_, slot_idx_, 1, cell_params.cell_cfg.bwps[bwp_id_].rb_width / 6, pdcch_dl_list);
for (uint32_t cs_idx = 0; cs_idx < SRSRAN_UE_DL_NR_MAX_NOF_CORESET; ++cs_idx) {
if (cfg->cfg.pdcch.coreset_present[cs_idx]) {
uint32_t cs_id = cfg->cfg.pdcch.coreset[cs_idx].id;
coresets[cs_id].emplace(*cfg, cs_id, slot_idx_, dl_pdcchs, ul_pdcchs);
}
}
}
void bwp_slot_grid::reset()
{
for (auto& coreset : coresets) {
coreset.reset();
if (coreset.has_value()) {
coreset->reset();
}
}
dl_rbgs.reset();
ul_rbgs.reset();
pdsch_grants.clear();
pdcch_dl_list.clear();
pusch_grants.clear();
pucch_grants.clear();
dl_prbs.reset();
ul_prbs.reset();
dl_pdcchs.clear();
ul_pdcchs.clear();
pending_acks.clear();
}
bwp_res_grid::bwp_res_grid(const sched_cell_params& cell_cfg_, uint32_t bwp_id_) : bwp_id(bwp_id_), cell_cfg(&cell_cfg_)
bwp_res_grid::bwp_res_grid(const bwp_params& bwp_cfg_) : cfg(&bwp_cfg_)
{
for (uint32_t sl = 0; sl < SCHED_NR_NOF_SUBFRAMES; ++sl) {
slots.emplace_back(cell_cfg_, bwp_id, sl);
for (uint32_t sl = 0; sl < slots.capacity(); ++sl) {
slots.emplace_back(*cfg, sl % static_cast<uint32_t>(SRSRAN_NSLOTS_PER_FRAME_NR(0u)));
}
}
cell_res_grid::cell_res_grid(const sched_cell_params& cell_cfg_) : cell_cfg(&cell_cfg_)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bwp_slot_allocator::bwp_slot_allocator(bwp_res_grid& bwp_grid_) :
logger(srslog::fetch_basic_logger("MAC")), cfg(*bwp_grid_.cfg), bwp_grid(bwp_grid_)
{}
alloc_result bwp_slot_allocator::alloc_rar(uint32_t aggr_idx,
const srsenb::sched_nr_impl::pending_rar_t& rar,
prb_interval interv,
uint32_t nof_grants)
{
for (uint32_t bwp_id = 0; bwp_id < cell_cfg->cell_cfg.bwps.size(); ++bwp_id) {
bwps.emplace_back(cell_cfg_, bwp_id);
static const uint32_t msg3_nof_prbs = 3;
bwp_slot_grid& bwp_pdcch_slot = bwp_grid[pdcch_tti];
bwp_slot_grid& bwp_msg3_slot = bwp_grid[pdcch_tti + 4];
if (bwp_pdcch_slot.dl_pdcchs.full()) {
logger.warning("SCHED: Maximum number of DL allocations reached");
return alloc_result::no_grant_space;
}
// Check DL RB collision
const prb_bitmap& pdsch_mask = bwp_pdcch_slot.dl_prbs.prbs();
prb_bitmap dl_mask(pdsch_mask.size());
dl_mask.fill(interv.start(), interv.stop());
if ((pdsch_mask & dl_mask).any()) {
logger.debug("SCHED: Provided RBG mask collides with allocation previously made.");
return alloc_result::sch_collision;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Check Msg3 RB collision
uint32_t total_ul_nof_prbs = msg3_nof_prbs * nof_grants;
uint32_t total_ul_nof_rbgs = srsran::ceil_div(total_ul_nof_prbs, get_P(bwp_grid.nof_prbs(), false));
prb_interval msg3_rbgs = find_empty_interval_of_length(bwp_msg3_slot.ul_prbs.prbs(), total_ul_nof_rbgs);
if (msg3_rbgs.length() < total_ul_nof_rbgs) {
logger.debug("SCHED: No space in PUSCH for Msg3.");
return alloc_result::sch_collision;
}
slot_bwp_sched::slot_bwp_sched(uint32_t bwp_id, cell_res_grid& phy_grid_) :
logger(srslog::fetch_basic_logger("MAC")), cfg(*phy_grid_.cell_cfg), bwp_grid(phy_grid_.bwps[bwp_id])
{}
// Find PDCCH position
const uint32_t coreset_id = cfg.cfg.pdcch.ra_search_space.coreset_id;
const uint32_t search_space_id = cfg.cfg.pdcch.ra_search_space.id;
if (not bwp_pdcch_slot.coresets[coreset_id]->alloc_dci(pdcch_grant_type_t::rar, aggr_idx, search_space_id, nullptr)) {
// Could not find space in PDCCH
logger.debug("SCHED: No space in PDCCH for DL tx.");
return alloc_result::no_cch_space;
}
// Generate DCI for RAR
pdcch_dl_t& pdcch = bwp_pdcch_slot.dl_pdcchs.back();
if (not fill_dci_rar(interv, *bwp_grid.cfg, pdcch.dci)) {
// Cancel on-going PDCCH allocation
bwp_pdcch_slot.coresets[coreset_id]->rem_last_dci();
return alloc_result::invalid_coderate;
}
// RAR allocation successful.
bwp_pdcch_slot.dl_prbs.add(interv);
return alloc_result::success;
}
alloc_result slot_bwp_sched::alloc_pdsch(slot_ue& ue, const rbgmask_t& dl_mask)
alloc_result bwp_slot_allocator::alloc_pdsch(slot_ue& ue, const prb_grant& dl_grant)
{
if (ue.cfg->active_bwp().bwp_id != bwp_grid.cfg->bwp_id) {
logger.warning(
"SCHED: Trying to allocate PDSCH for rnti=0x%x in inactive BWP id=%d", ue.rnti, ue.cfg->active_bwp().bwp_id);
return alloc_result::no_rnti_opportunity;
}
if (ue.h_dl == nullptr) {
logger.warning("SCHED: Trying to allocate PDSCH for rnti=0x%x with no available HARQs", ue.rnti);
return alloc_result::no_rnti_opportunity;
}
pdsch_list_t& pdsch_grants = bwp_grid[ue.pdsch_tti].pdsch_grants;
bwp_slot_grid& bwp_pdcch_slot = bwp_grid[ue.pdcch_tti];
bwp_slot_grid& bwp_pdsch_slot = bwp_grid[ue.pdsch_tti];
bwp_slot_grid& bwp_uci_slot = bwp_grid[ue.uci_tti];
if (not bwp_pdsch_slot.is_dl) {
logger.warning("SCHED: Trying to allocate PDSCH in TDD non-DL slot index=%d", bwp_pdsch_slot.slot_idx);
return alloc_result::no_sch_space;
}
pdcch_dl_list_t& pdsch_grants = bwp_pdsch_slot.dl_pdcchs;
if (pdsch_grants.full()) {
logger.warning("SCHED: Maximum number of DL allocations reached");
return alloc_result::no_grant_space;
}
rbgmask_t& pdsch_mask = bwp_grid[ue.pdsch_tti].dl_rbgs;
if ((pdsch_mask & dl_mask).any()) {
if (bwp_pdcch_slot.dl_prbs.collides(dl_grant)) {
return alloc_result::sch_collision;
}
const uint32_t aggr_idx = 3, coreset_id = 0;
if (not bwp_grid[ue.pdcch_tti].coresets[coreset_id].alloc_dci(
pdcch_grant_type_t::dl_data, aggr_idx, coreset_id, &ue)) {
// Find space in PUCCH
// TODO
// Find space and allocate PDCCH
const uint32_t aggr_idx = 2, ss_id = 1;
uint32_t coreset_id = ue.cfg->phy().pdcch.search_space[ss_id].coreset_id;
if (not bwp_pdcch_slot.coresets[coreset_id]->alloc_dci(pdcch_grant_type_t::dl_data, aggr_idx, ss_id, &ue)) {
// Could not find space in PDCCH
return alloc_result::no_cch_space;
}
int mcs = -1, tbs = -1;
// Allocate HARQ
if (ue.h_dl->empty()) {
mcs = 20;
tbs = 100;
bool ret = ue.h_dl->new_tx(ue.pdsch_tti, ue.uci_tti, dl_mask, mcs, tbs, 4);
int mcs = 20;
int tbs = 100;
bool ret = ue.h_dl->new_tx(ue.pdsch_tti, ue.uci_tti, dl_grant, mcs, tbs, 4);
srsran_assert(ret, "Failed to allocate DL HARQ");
} else {
bool ret = ue.h_dl->new_retx(ue.pdsch_tti, ue.uci_tti, dl_mask, &mcs, &tbs);
bool ret = ue.h_dl->new_retx(ue.pdsch_tti, ue.uci_tti, dl_grant);
srsran_assert(ret, "Failed to allocate DL HARQ retx");
}
// Allocation Successful
pdcch_dl_t& pdcch = bwp_grid[ue.pdcch_tti].pdcch_dl_list.back();
fill_dci_ue_cfg(ue, pdcch.dci);
pdsch_grants.emplace_back();
pdsch_t& grant = pdsch_grants.back();
grant.sch.grant.rnti = ue.rnti;
bitmap_to_prb_array(dl_mask, bwp_grid.nof_prbs(), grant.sch.grant);
pdsch_mask |= dl_mask;
// Generate PDCCH
pdcch_dl_t& pdcch = bwp_pdcch_slot.dl_pdcchs.back();
fill_dl_dci_ue_fields(ue, *bwp_grid.cfg, ss_id, pdcch.dci.ctx.location, pdcch.dci);
pdcch.dci.pucch_resource = 0;
pdcch.dci.dai = std::count_if(bwp_uci_slot.pending_acks.begin(),
bwp_uci_slot.pending_acks.end(),
[&ue](const harq_ack_t& p) { return p.res.rnti == ue.rnti; });
pdcch.dci.dai %= 4;
// Generate PUCCH
bwp_uci_slot.pending_acks.emplace_back();
bwp_uci_slot.pending_acks.back().phy_cfg = &ue.cfg->phy();
srsran_assert(ue.cfg->phy().get_pdsch_ack_resource(pdcch.dci, bwp_uci_slot.pending_acks.back().res),
"Error getting ack resource");
// Generate PDSCH
bwp_pdsch_slot.dl_prbs |= dl_grant;
bwp_pdsch_slot.pdschs.emplace_back();
pdsch_t& pdsch = bwp_pdsch_slot.pdschs.back();
srsran_slot_cfg_t slot_cfg;
slot_cfg.idx = ue.pdsch_tti.sf_idx();
bool ret = ue.cfg->phy().get_pdsch_cfg(slot_cfg, pdcch.dci, pdsch.sch);
srsran_assert(ret, "Error converting DCI to grant");
if (ue.h_dl->nof_retx() == 0) {
ue.h_dl->set_tbs(pdsch.sch.grant.tb[0].tbs); // update HARQ with correct TBS
} else {
srsran_assert(pdsch.sch.grant.tb[0].tbs == (int)ue.h_dl->tbs(), "The TBS did not remain constant in retx");
}
pdsch.sch.grant.tb[0].softbuffer.tx = ue.h_dl->get_softbuffer().get();
return alloc_result::success;
}
alloc_result slot_bwp_sched::alloc_pusch(slot_ue& ue, const rbgmask_t& ul_mask)
alloc_result bwp_slot_allocator::alloc_pusch(slot_ue& ue, const rbg_bitmap& ul_mask)
{
if (ue.h_ul == nullptr) {
logger.warning("SCHED: Trying to allocate PUSCH for rnti=0x%x with no available HARQs", ue.rnti);
return alloc_result::no_rnti_opportunity;
}
pusch_list& pusch_grants = bwp_grid[ue.pusch_tti].pusch_grants;
if (pusch_grants.full()) {
auto& bwp_pdcch_slot = bwp_grid[ue.pdcch_tti];
auto& bwp_pusch_slot = bwp_grid[ue.pusch_tti];
if (not bwp_pusch_slot.is_ul) {
logger.warning("SCHED: Trying to allocate PUSCH in TDD non-UL slot index=%d", bwp_pusch_slot.slot_idx);
return alloc_result::no_sch_space;
}
pdcch_ul_list_t& pdcchs = bwp_pdcch_slot.ul_pdcchs;
if (pdcchs.full()) {
logger.warning("SCHED: Maximum number of UL allocations reached");
return alloc_result::no_grant_space;
}
rbgmask_t& pusch_mask = bwp_grid[ue.pusch_tti].ul_rbgs;
const rbg_bitmap& pusch_mask = bwp_pusch_slot.ul_prbs.rbgs();
if ((pusch_mask & ul_mask).any()) {
return alloc_result::sch_collision;
}
const uint32_t aggr_idx = 3, coreset_id = 0;
if (not bwp_grid[ue.pdcch_tti].coresets[coreset_id].alloc_dci(
pdcch_grant_type_t::ul_data, aggr_idx, coreset_id, &ue)) {
const uint32_t aggr_idx = 2, ss_id = 1;
uint32_t coreset_id = ue.cfg->phy().pdcch.search_space[ss_id].coreset_id;
if (not bwp_pdcch_slot.coresets[coreset_id].value().alloc_dci(pdcch_grant_type_t::ul_data, aggr_idx, ss_id, &ue)) {
// Could not find space in PDCCH
return alloc_result::no_cch_space;
}
int mcs = -1, tbs = -1;
if (ue.h_ul->empty()) {
mcs = 20;
tbs = 100;
bool ret = ue.h_ul->new_tx(ue.pusch_tti, ue.pusch_tti, ul_mask, mcs, tbs, ue.cfg->maxharq_tx);
int mcs = 20;
int tbs = 100;
bool ret = ue.h_ul->new_tx(ue.pusch_tti, ue.pusch_tti, ul_mask, mcs, tbs, ue.cfg->ue_cfg()->maxharq_tx);
srsran_assert(ret, "Failed to allocate UL HARQ");
} else {
srsran_assert(ue.h_ul->new_retx(ue.pusch_tti, ue.pusch_tti, ul_mask, &mcs, &tbs),
"Failed to allocate UL HARQ retx");
srsran_assert(ue.h_ul->new_retx(ue.pusch_tti, ue.pusch_tti, ul_mask), "Failed to allocate UL HARQ retx");
}
// Allocation Successful
pdcch_ul_t& pdcch = bwp_grid[ue.pdcch_tti].pdcch_ul_list.back();
fill_dci_ue_cfg(ue, pdcch.dci);
pusch_grants.emplace_back();
pusch_grant& grant = pusch_grants.back();
grant.dci.ctx.rnti = ue.rnti;
grant.bitmap = ul_mask;
pusch_mask |= ul_mask;
// Generate PDCCH
pdcch_ul_t& pdcch = pdcchs.back();
fill_ul_dci_ue_fields(ue, *bwp_grid.cfg, ss_id, pdcch.dci.ctx.location, pdcch.dci);
// Generate PUSCH
bwp_pusch_slot.ul_prbs.add(ul_mask);
return alloc_result::success;
}

@ -25,57 +25,35 @@
namespace srsenb {
namespace sched_nr_impl {
ue_cfg_extended::ue_cfg_extended(uint16_t rnti_, const ue_cfg_t& uecfg) : ue_cfg_t(uecfg), rnti(rnti_)
{
cc_params.resize(carriers.size());
for (uint32_t cc = 0; cc < cc_params.size(); ++cc) {
cc_params[cc].bwps.resize(1);
auto& bwp = cc_params[cc].bwps[0];
for (uint32_t ssid = 0; ssid < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE; ++ssid) {
if (phy_cfg.pdcch.search_space_present[ssid]) {
bwp.search_spaces.emplace_back();
bwp.search_spaces.back().cfg = &phy_cfg.pdcch.search_space[ssid];
}
}
for (uint32_t csid = 0; csid < SRSRAN_UE_DL_NR_MAX_NOF_CORESET; ++csid) {
if (phy_cfg.pdcch.coreset_present[csid]) {
bwp.coresets.emplace_back();
auto& coreset = bwp.coresets.back();
coreset.cfg = &phy_cfg.pdcch.coreset[csid];
for (auto& ss : bwp.search_spaces) {
if (ss.cfg->coreset_id == csid) {
coreset.ss_list.push_back(&ss);
get_dci_locs(*coreset.cfg, *coreset.ss_list.back()->cfg, rnti, coreset.cce_positions);
}
}
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
slot_ue::slot_ue(resource_guard::token ue_token_, uint16_t rnti_, tti_point tti_rx_, uint32_t cc_) :
ue_token(std::move(ue_token_)), rnti(rnti_), tti_rx(tti_rx_), cc(cc_)
{}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ue_carrier::ue_carrier(uint16_t rnti_, uint32_t cc_, const ue_cfg_t& uecfg_) : rnti(rnti_), cc(cc_), cfg(&uecfg_) {}
ue_carrier::ue_carrier(uint16_t rnti_, const ue_cfg_t& uecfg_, const sched_cell_params& cell_params_) :
rnti(rnti_),
cc(cell_params_.cc),
bwp_cfg(rnti_, cell_params_.bwps[0], uecfg_),
cell_params(cell_params_),
harq_ent(cell_params_.nof_prb())
{}
void ue_carrier::push_feedback(srsran::move_callback<void(ue_carrier&)> callback)
{
pending_feedback.push_back(std::move(callback));
}
slot_ue ue_carrier::try_reserve(tti_point tti_rx, const ue_cfg_extended& uecfg_)
slot_ue ue_carrier::try_reserve(tti_point tti_rx, const ue_cfg_t& uecfg_)
{
slot_ue sfu(busy, rnti, tti_rx, cc);
if (sfu.empty()) {
return sfu;
}
// successfully acquired. Process any CC-specific pending feedback
cfg = &uecfg_;
if (bwp_cfg.ue_cfg() != &uecfg_) {
bwp_cfg = bwp_ue_cfg(rnti, cell_params.bwps[0], uecfg_);
}
while (not pending_feedback.empty()) {
pending_feedback.front()(*this);
pending_feedback.pop_front();
@ -90,24 +68,36 @@ slot_ue ue_carrier::try_reserve(tti_point tti_rx, const ue_cfg_extended& uecfg_)
}
// set UE parameters common to all carriers
sfu.cfg = &uecfg_;
sfu.cfg = &bwp_cfg;
// copy cc-specific parameters and find available HARQs
sfu.cc_cfg = &uecfg_.carriers[cc];
sfu.pdcch_tti = tti_rx + TX_ENB_DELAY;
sfu.pdsch_tti = sfu.pdcch_tti + sfu.cc_cfg->pdsch_res_list[0].k0;
sfu.pusch_tti = sfu.pdcch_tti + sfu.cc_cfg->pusch_res_list[0].k2;
sfu.uci_tti = sfu.pdsch_tti + sfu.cc_cfg->pdsch_res_list[0].k1;
const uint32_t k0 = 0;
sfu.pdsch_tti = sfu.pdcch_tti + k0;
uint32_t k1 =
sfu.cfg->phy().harq_ack.dl_data_to_ul_ack[sfu.pdsch_tti.sf_idx() % sfu.cfg->phy().harq_ack.nof_dl_data_to_ul_ack];
sfu.uci_tti = sfu.pdsch_tti + k1;
uint32_t k2 = k1;
sfu.pusch_tti = sfu.pdcch_tti + k2;
sfu.dl_cqi = dl_cqi;
sfu.ul_cqi = ul_cqi;
const srsran_tdd_config_nr_t& tdd_cfg = cell_params.cell_cfg.tdd;
if (srsran_tdd_nr_is_dl(&tdd_cfg, 0, sfu.pdsch_tti.sf_idx())) {
// If DL enabled
sfu.h_dl = harq_ent.find_pending_dl_retx();
if (sfu.h_dl == nullptr) {
sfu.h_dl = harq_ent.find_empty_dl_harq();
}
}
if (srsran_tdd_nr_is_ul(&tdd_cfg, 0, sfu.pusch_tti.sf_idx())) {
// If UL enabled
sfu.h_ul = harq_ent.find_pending_ul_retx();
if (sfu.h_ul == nullptr) {
sfu.h_ul = harq_ent.find_empty_ul_harq();
}
}
if (sfu.h_dl == nullptr and sfu.h_ul == nullptr) {
// there needs to be at least one available HARQ for newtx/retx
@ -119,12 +109,12 @@ slot_ue ue_carrier::try_reserve(tti_point tti_rx, const ue_cfg_extended& uecfg_)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ue::ue(uint16_t rnti_, const ue_cfg_t& cfg) : rnti(rnti_)
ue::ue(uint16_t rnti_, const ue_cfg_t& cfg, const sched_params& sched_cfg_) : rnti(rnti_), sched_cfg(sched_cfg_)
{
ue_cfgs[0] = ue_cfg_extended(rnti, cfg);
ue_cfgs[0] = cfg;
for (uint32_t cc = 0; cc < cfg.carriers.size(); ++cc) {
if (cfg.carriers[cc].active) {
carriers[cc].reset(new ue_carrier(rnti, cc, cfg));
carriers[cc].reset(new ue_carrier(rnti, cfg, sched_cfg.cells[cc]));
}
}
}

@ -20,10 +20,15 @@
*/
#include "srsenb/hdr/stack/mac/nr/sched_nr_worker.h"
#include "srsran/common/string_helpers.h"
namespace srsenb {
namespace sched_nr_impl {
slot_cc_worker::slot_cc_worker(serv_cell_ctxt& cc_sched) :
cell(cc_sched), cfg(*cc_sched.cfg), bwp_alloc(cc_sched.bwps[0].grid), logger(srslog::fetch_basic_logger("MAC"))
{}
/// Called at the beginning of TTI in a locked context, to reserve available UE resources
void slot_cc_worker::start(tti_point tti_rx_, ue_map_t& ue_db)
{
@ -43,22 +48,23 @@ void slot_cc_worker::start(tti_point tti_rx_, ue_map_t& ue_db)
}
// UE acquired successfully for scheduling in this {tti, cc}
}
tti_rx = tti_rx_;
}
void slot_cc_worker::run()
{
srsran_assert(running(), "scheduler worker::run() called for non-active worker");
// Prioritize PDCCH scheduling for DL and UL data in a RoundRobin fashion
if ((tti_rx.to_uint() & 0x1u) == 0) {
bwp_alloc.new_slot(tti_rx + TX_ENB_DELAY);
// Allocate pending RARs
cell.bwps[0].ra.run_slot(bwp_alloc);
// TODO: Prioritize PDCCH scheduling for DL and UL data in a Round-Robin fashion
alloc_dl_ues();
alloc_ul_ues();
} else {
alloc_ul_ues();
alloc_dl_ues();
}
// Log CC scheduler result
log_result();
}
void slot_cc_worker::end_tti()
@ -81,10 +87,11 @@ void slot_cc_worker::alloc_dl_ues()
return;
}
rbgmask_t dlmask(cfg.cell_cfg.nof_rbg);
rbgmask_t dlmask(cfg.bwps[0].N_rbg);
dlmask.fill(0, dlmask.size(), true);
res_grid.alloc_pdsch(ue, dlmask);
bwp_alloc.alloc_pdsch(ue, dlmask);
}
void slot_cc_worker::alloc_ul_ues()
{
if (slot_ues.empty()) {
@ -95,69 +102,99 @@ void slot_cc_worker::alloc_ul_ues()
return;
}
rbgmask_t ulmask(cfg.cell_cfg.nof_rbg);
rbgmask_t ulmask(cfg.bwps[0].N_rbg);
ulmask.fill(0, ulmask.size(), true);
res_grid.alloc_pusch(ue, ulmask);
bwp_alloc.alloc_pusch(ue, ulmask);
}
void slot_cc_worker::log_result() const
{
const bwp_slot_grid& bwp_slot = cell.bwps[0].grid[tti_rx + TX_ENB_DELAY];
for (const pdcch_dl_t& pdcch : bwp_slot.dl_pdcchs) {
fmt::memory_buffer fmtbuf;
if (pdcch.dci.ctx.rnti_type == srsran_rnti_type_c) {
const slot_ue& ue = slot_ues[pdcch.dci.ctx.rnti];
fmt::format_to(fmtbuf,
"SCHED: DL {}, cc={}, rnti=0x{:x}, pid={}, nrtx={}, dai={}, tti_pdsch={}, tti_ack={}",
ue.h_dl->nof_retx() == 0 ? "tx" : "retx",
cell.cfg->cc,
ue.rnti,
ue.h_dl->pid,
ue.h_dl->nof_retx(),
pdcch.dci.dai,
ue.pdsch_tti,
ue.uci_tti);
} else if (pdcch.dci.ctx.rnti_type == srsran_rnti_type_ra) {
fmt::format_to(fmtbuf, "SCHED: DL RAR, cc={}", cell.cfg->cc);
} else {
fmt::format_to(fmtbuf, "SCHED: unknown format");
}
logger.info("%s", srsran::to_c_str(fmtbuf));
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
sched_worker_manager::sched_worker_manager(ue_map_t& ue_db_, const sched_params& cfg_) : cfg(cfg_), ue_db(ue_db_)
sched_worker_manager::sched_worker_manager(ue_map_t& ue_db_, const sched_params& cfg_) :
cfg(cfg_), ue_db(ue_db_), logger(srslog::fetch_basic_logger("MAC"))
{
for (uint32_t cc = 0; cc < cfg.cells.size(); ++cc) {
cell_grid_list.emplace_back(cfg.cells[cc]);
}
// Note: For now, we only allow parallelism at the sector level
slot_ctxts.resize(cfg.sched_cfg.nof_concurrent_subframes);
slot_worker_ctxts.resize(cfg.sched_cfg.nof_concurrent_subframes);
for (size_t i = 0; i < cfg.sched_cfg.nof_concurrent_subframes; ++i) {
slot_ctxts[i].reset(new slot_worker_ctxt());
sem_init(&slot_ctxts[i]->sf_sem, 0, 1);
slot_ctxts[i]->workers.reserve(cfg.cells.size());
slot_worker_ctxts[i].reset(new slot_worker_ctxt());
slot_worker_ctxts[i]->workers.reserve(cfg.cells.size());
for (uint32_t cc = 0; cc < cfg.cells.size(); ++cc) {
slot_ctxts[i]->workers.emplace_back(cfg.cells[cc], cell_grid_list[cc]);
slot_worker_ctxts[i]->workers.emplace_back(cell_grid_list[cc]);
}
}
}
sched_worker_manager::~sched_worker_manager()
{
// acquire all slot worker contexts
for (auto& slot_ctxt : slot_ctxts) {
sem_wait(&slot_ctxt->sf_sem);
}
// destroy all slot worker contexts
for (auto& slot_ctxt : slot_ctxts) {
sem_destroy(&slot_ctxt->sf_sem);
}
}
sched_worker_manager::~sched_worker_manager() = default;
sched_worker_manager::slot_worker_ctxt& sched_worker_manager::get_sf(tti_point tti_rx)
{
return *slot_ctxts[tti_rx.to_uint() % slot_ctxts.size()];
return *slot_worker_ctxts[tti_rx.to_uint() % slot_worker_ctxts.size()];
}
void sched_worker_manager::reserve_workers(tti_point tti_rx_)
void sched_worker_manager::start_slot(tti_point tti_rx, srsran::move_callback<void()> process_feedback)
{
// lock if slot worker is already being used
auto& sf_worker_ctxt = get_sf(tti_rx_);
sem_wait(&sf_worker_ctxt.sf_sem);
sf_worker_ctxt.tti_rx = tti_rx_;
sf_worker_ctxt.worker_count.store(static_cast<int>(sf_worker_ctxt.workers.size()), std::memory_order_relaxed);
auto& sf_worker_ctxt = get_sf(tti_rx);
std::unique_lock<std::mutex> lock(sf_worker_ctxt.slot_mutex);
while ((sf_worker_ctxt.tti_rx.is_valid() and sf_worker_ctxt.tti_rx != tti_rx)) {
// wait for previous slot to finish
sf_worker_ctxt.nof_workers_waiting++;
sf_worker_ctxt.cvar.wait(lock);
sf_worker_ctxt.nof_workers_waiting--;
}
if (sf_worker_ctxt.tti_rx == tti_rx) {
// another worker with the same slot idx already started
return;
}
void sched_worker_manager::start_tti(tti_point tti_rx_)
{
auto& sf_worker_ctxt = get_sf(tti_rx_);
srsran_assert(sf_worker_ctxt.tti_rx == tti_rx_, "invalid run_tti(tti, cc) arguments");
std::lock_guard<std::mutex> db_lock(ue_db_mutex);
process_feedback();
for (uint32_t cc = 0; cc < sf_worker_ctxt.workers.size(); ++cc) {
sf_worker_ctxt.workers[cc].start(sf_worker_ctxt.tti_rx, ue_db);
sf_worker_ctxt.workers[cc].start(tti_rx, ue_db);
}
}
bool sched_worker_manager::run_tti(tti_point tti_rx_, uint32_t cc, slot_res_t& tti_req)
sf_worker_ctxt.tti_rx = tti_rx;
sf_worker_ctxt.worker_count.store(static_cast<int>(sf_worker_ctxt.workers.size()), std::memory_order_relaxed);
if (sf_worker_ctxt.nof_workers_waiting > 0) {
sf_worker_ctxt.cvar.notify_all();
}
}
bool sched_worker_manager::run_slot(tti_point tti_rx_, uint32_t cc)
{
auto& sf_worker_ctxt = get_sf(tti_rx_);
srsran_assert(sf_worker_ctxt.tti_rx == tti_rx_, "invalid run_tti(tti, cc) arguments");
@ -165,15 +202,6 @@ bool sched_worker_manager::run_tti(tti_point tti_rx_, uint32_t cc, slot_res_t& t
// Get {tti, cc} scheduling decision
sf_worker_ctxt.workers[cc].run();
// Copy requested TTI DL and UL sched result
tti_req.dl_res.pdsch_tti = tti_rx_ + TX_ENB_DELAY;
tti_req.dl_res.pdcchs = cell_grid_list[cc].bwps[0][tti_req.dl_res.pdsch_tti].pdcch_dl_list;
tti_req.dl_res.pdschs = cell_grid_list[cc].bwps[0][tti_req.dl_res.pdsch_tti].pdsch_grants;
cell_grid_list[cc].bwps[0][tti_req.dl_res.pdsch_tti].reset();
tti_req.ul_res.pusch_tti = tti_rx_ + TX_ENB_DELAY;
tti_req.ul_res.pusch = cell_grid_list[cc].bwps[0][tti_req.ul_res.pusch_tti].pusch_grants;
cell_grid_list[cc].bwps[0][tti_req.ul_res.pusch_tti].reset();
// decrement the number of active workers
int rem_workers = sf_worker_ctxt.worker_count.fetch_sub(1, std::memory_order_release) - 1;
srsran_assert(rem_workers >= 0, "invalid number of calls to run_tti(tti, cc)");
@ -181,18 +209,76 @@ bool sched_worker_manager::run_tti(tti_point tti_rx_, uint32_t cc, slot_res_t& t
return rem_workers == 0;
}
void sched_worker_manager::end_tti(tti_point tti_rx_)
void sched_worker_manager::release_slot(tti_point tti_rx_)
{
auto& sf_worker_ctxt = get_sf(tti_rx_);
srsran_assert(sf_worker_ctxt.tti_rx == tti_rx_, "invalid run_tti(tti, cc) arguments");
srsran_assert(sf_worker_ctxt.worker_count == 0, "invalid number of calls to run_tti(tti, cc)");
// All the workers of the same TTI have finished. Synchronize scheduling decisions with UEs state
{
std::lock_guard<std::mutex> lock(ue_db_mutex);
// All the workers of the same slot have finished. Synchronize scheduling decisions with UEs state
for (slot_cc_worker& worker : sf_worker_ctxt.workers) {
worker.end_tti();
}
}
std::unique_lock<std::mutex> lock(sf_worker_ctxt.slot_mutex);
sf_worker_ctxt.tti_rx = {};
if (sf_worker_ctxt.nof_workers_waiting > 0) {
lock.unlock();
sf_worker_ctxt.cvar.notify_one();
}
}
bool sched_worker_manager::save_sched_result(tti_point pdcch_tti, uint32_t cc, dl_sched_t& dl_res, ul_sched_t& ul_res)
{
auto& bwp_slot = cell_grid_list[cc].bwps[0].grid[pdcch_tti];
dl_res.pdcch_dl = bwp_slot.dl_pdcchs;
dl_res.pdcch_ul = bwp_slot.ul_pdcchs;
dl_res.pdsch = bwp_slot.pdschs;
ul_res.pusch = bwp_slot.puschs;
// Group pending HARQ ACKs
srsran_pdsch_ack_nr_t ack = {};
ack.nof_cc = not bwp_slot.pending_acks.empty();
const srsran::phy_cfg_nr_t* phy_cfg = nullptr;
for (const harq_ack_t& pending_ack : bwp_slot.pending_acks) {
srsran_harq_ack_m_t ack_m = {};
ack_m.resource = pending_ack.res;
ack_m.present = true;
srsran_harq_ack_insert_m(&ack, &ack_m);
phy_cfg = pending_ack.phy_cfg;
}
if (phy_cfg != nullptr) {
srsran_slot_cfg_t slot_cfg{};
slot_cfg.idx = pdcch_tti.sf_idx();
srsran_uci_cfg_nr_t uci_cfg = {};
srsran_assert(phy_cfg->get_uci_cfg(slot_cfg, ack, uci_cfg), "Error getting UCI CFG");
if (uci_cfg.ack.count > 0 || uci_cfg.nof_csi > 0 || uci_cfg.o_sr > 0) {
if (not ul_res.pusch.empty()) {
// Put UCI configuration in PUSCH config
srsran_assert(phy_cfg->get_pusch_uci_cfg(slot_cfg, uci_cfg, ul_res.pusch[0].sch),
"Error setting UCI configuration in PUSCH");
} else {
// Put UCI configuration in PUCCH config
ul_res.pucch.emplace_back();
pucch_t& pucch = ul_res.pucch.back();
pucch.uci_cfg = uci_cfg;
srsran_assert(phy_cfg->get_pucch_uci_cfg(slot_cfg, pucch.uci_cfg, pucch.pucch_cfg, pucch.resource),
"Error getting PUCCH UCI cfg");
}
}
}
// clear up BWP slot
bwp_slot.reset();
sem_post(&sf_worker_ctxt.sf_sem);
return true;
}
} // namespace sched_nr_impl

@ -288,6 +288,7 @@ uint32_t sched_ue_cell::get_aggr_level(uint32_t nof_bits) const
} else {
dl_cqi = dl_cqi_ctxt.get_avg_cqi();
}
dl_cqi = std::max(cell_cfg->sched_cfg->pdcch_cqi_offset + (int)dl_cqi, 0);
return srsenb::get_aggr_level(nof_bits,
dl_cqi,
cell_cfg->sched_cfg->min_aggr_level,

@ -80,6 +80,7 @@ cc_used_buffers_map::~cc_used_buffers_map()
srsran::unique_byte_buffer_t cc_used_buffers_map::release_pdu(tti_point tti)
{
std::unique_lock<std::mutex> lock(mutex);
if (not has_tti(tti)) {
return nullptr;
}
@ -94,6 +95,7 @@ srsran::unique_byte_buffer_t cc_used_buffers_map::release_pdu(tti_point tti)
uint8_t* cc_used_buffers_map::request_pdu(tti_point tti, uint32_t len)
{
std::unique_lock<std::mutex> lock(mutex);
if (not pdu_map.has_space(tti.to_uint())) {
logger->error("UE buffers: could not allocate buffer for tti=%d", tti.to_uint());
return nullptr;
@ -114,6 +116,7 @@ uint8_t* cc_used_buffers_map::request_pdu(tti_point tti, uint32_t len)
void cc_used_buffers_map::clear_old_pdus(tti_point current_tti)
{
std::unique_lock<std::mutex> lock(mutex);
static const uint32_t old_tti_threshold = SRSRAN_FDD_NOF_HARQ + 4;
tti_point max_tti{current_tti - old_tti_threshold};
@ -262,13 +265,11 @@ srsran_softbuffer_tx_t* ue::get_tx_softbuffer(uint32_t enb_cc_idx, uint32_t harq
uint8_t* ue::request_buffer(uint32_t tti, uint32_t enb_cc_idx, uint32_t len)
{
srsran_assert(len > 0, "UE buffers: Requesting buffer for zero bytes");
std::unique_lock<std::mutex> lock(rx_buffers_mutex);
return cc_buffers[enb_cc_idx].get_rx_used_buffers().request_pdu(tti_point(tti), len);
}
void ue::clear_old_buffers(uint32_t tti)
{
std::unique_lock<std::mutex> lock(rx_buffers_mutex);
// remove old buffers
for (auto& cc : cc_buffers) {
cc.get_rx_used_buffers().clear_old_pdus(tti_point{tti});
@ -398,7 +399,6 @@ void ue::process_pdu(srsran::unique_byte_buffer_t pdu, uint32_t ue_cc_idx, uint3
srsran::unique_byte_buffer_t ue::release_pdu(uint32_t tti, uint32_t enb_cc_idx)
{
std::lock_guard<std::mutex> lock(rx_buffers_mutex);
return cc_buffers[enb_cc_idx].get_rx_used_buffers().release_pdu(tti_point(tti));
}

@ -112,6 +112,14 @@ int32_t rrc::init(const rrc_cfg_t& cfg_,
running = true;
if (logger.debug.enabled()) {
asn1::json_writer js{};
cfg.srb1_cfg.rlc_cfg.to_json(js);
logger.debug("SRB1 configuration: %s", js.to_string().c_str());
js = {};
cfg.srb2_cfg.rlc_cfg.to_json(js);
logger.debug("SRB2 configuration: %s", js.to_string().c_str());
}
return SRSRAN_SUCCESS;
}

@ -56,18 +56,18 @@ bool rrc::ue::rrc_endc::fill_conn_recfg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn
meas_cfg_s& meas_cfg = conn_recfg->meas_cfg;
meas_cfg.meas_obj_to_add_mod_list_present = true;
meas_cfg.meas_obj_to_add_mod_list.resize(2);
auto& meas_obj = meas_cfg.meas_obj_to_add_mod_list[0];
meas_obj.meas_obj_id = 1;
meas_obj_to_add_mod_s meas_obj = {};
meas_obj.meas_obj_id = meas_cfg.meas_obj_to_add_mod_list.size() + 1;
meas_obj.meas_obj.set_meas_obj_eutra();
meas_obj.meas_obj.meas_obj_eutra().carrier_freq = 300;
meas_obj.meas_obj.meas_obj_eutra().allowed_meas_bw = allowed_meas_bw_opts::mbw50;
meas_obj.meas_obj.meas_obj_eutra().presence_ant_port1 = false;
meas_obj.meas_obj.meas_obj_eutra().neigh_cell_cfg.from_number(0b01);
meas_cfg.meas_obj_to_add_mod_list.push_back(meas_obj);
auto& meas_obj2 = meas_cfg.meas_obj_to_add_mod_list[1];
meas_obj2.meas_obj_id = 2;
meas_obj_to_add_mod_s meas_obj2 = {};
meas_obj2.meas_obj_id = meas_cfg.meas_obj_to_add_mod_list.size() + 1;
meas_obj2.meas_obj.set_meas_obj_nr_r15();
meas_obj2.meas_obj.meas_obj_nr_r15().carrier_freq_r15 = 634176;
meas_obj2.meas_obj.meas_obj_nr_r15().rs_cfg_ssb_r15.meas_timing_cfg_r15.periodicity_and_offset_r15.set_sf20_r15();
@ -78,13 +78,13 @@ bool rrc::ue::rrc_endc::fill_conn_recfg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn
meas_obj2.meas_obj.meas_obj_nr_r15().ext = true;
meas_obj2.meas_obj.meas_obj_nr_r15().band_nr_r15.set_present(true);
meas_obj2.meas_obj.meas_obj_nr_r15().band_nr_r15.get()->set_setup() = 78;
meas_cfg.meas_obj_to_add_mod_list.push_back(meas_obj2);
// report config
meas_cfg.report_cfg_to_add_mod_list_present = true;
meas_cfg.report_cfg_to_add_mod_list.resize(1);
auto& report_cfg = meas_cfg.report_cfg_to_add_mod_list[0];
report_cfg_to_add_mod_s report_cfg = {};
report_cfg.report_cfg_id = 1;
report_cfg.report_cfg_id = meas_cfg.report_cfg_to_add_mod_list.size() + 1;
report_cfg.report_cfg.set_report_cfg_inter_rat();
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.set_event();
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.event().event_id.set_event_b1_nr_r15();
@ -109,14 +109,15 @@ bool rrc::ue::rrc_endc::fill_conn_recfg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn
report_cfg.report_cfg.report_cfg_inter_rat().report_quant_cell_nr_r15.get()->ss_rsrp = true;
report_cfg.report_cfg.report_cfg_inter_rat().report_quant_cell_nr_r15.get()->ss_rsrq = true;
report_cfg.report_cfg.report_cfg_inter_rat().report_quant_cell_nr_r15.get()->ss_sinr = true;
meas_cfg.report_cfg_to_add_mod_list.push_back(report_cfg);
// measIdToAddModList
meas_cfg.meas_id_to_add_mod_list_present = true;
meas_cfg.meas_id_to_add_mod_list.resize(1);
auto& meas_id = meas_cfg.meas_id_to_add_mod_list[0];
meas_id.meas_id = 1;
meas_id.meas_obj_id = 2;
meas_id.report_cfg_id = 1;
meas_id_to_add_mod_s meas_id = {};
meas_id.meas_id = meas_obj.meas_obj_id;
meas_id.meas_obj_id = meas_obj2.meas_obj_id;
meas_id.report_cfg_id = report_cfg.report_cfg_id;
meas_cfg.meas_id_to_add_mod_list.push_back(meas_id);
// quantityConfig
meas_cfg.quant_cfg_present = true;

@ -27,6 +27,7 @@
#include "srsenb/hdr/stack/rrc/ue_rr_cfg.h"
#include "srsran/asn1/rrc_utils.h"
#include "srsran/common/enb_events.h"
#include "srsran/common/srsran_assert.h"
#include "srsran/common/standard_streams.h"
#include "srsran/interfaces/enb_pdcp_interfaces.h"
#include "srsran/interfaces/enb_rlc_interfaces.h"
@ -1420,8 +1421,30 @@ void rrc::ue::apply_pdcp_drb_updates(const rr_cfg_ded_s& pending_rr_cfg)
void rrc::ue::apply_rlc_rb_updates(const rr_cfg_ded_s& pending_rr_cfg)
{
for (const srb_to_add_mod_s& srb : pending_rr_cfg.srb_to_add_mod_list) {
parent->rlc->add_bearer(rnti, srb.srb_id, srsran::rlc_config_t::srb_config(srb.srb_id));
srb_cfg_t* srb_cfg;
if (srb.srb_id == 1) {
srb_cfg = &parent->cfg.srb1_cfg;
} else if (srb.srb_id == 2) {
srb_cfg = &parent->cfg.srb2_cfg;
} else {
srsran_terminate("Invalid LTE SRB id=%d", srb.srb_id);
}
if (srb_cfg->rlc_cfg.type() == srb_to_add_mod_s::rlc_cfg_c_::types_opts::explicit_value) {
srsran::rlc_config_t rlc_cfg = srsran::make_rlc_config_t(srb_cfg->rlc_cfg.explicit_value());
if (rlc_cfg.rlc_mode == srsran::rlc_mode_t::am and srb_cfg->enb_dl_max_retx_thres > 0) {
rlc_cfg.am.max_retx_thresh = srb_cfg->enb_dl_max_retx_thres;
}
parent->rlc->add_bearer(rnti, srb.srb_id, rlc_cfg);
} else {
srsran::rlc_config_t rlc_cfg = srsran::rlc_config_t::srb_config(srb.srb_id);
if (rlc_cfg.rlc_mode == srsran::rlc_mode_t::am and srb_cfg->enb_dl_max_retx_thres > 0) {
rlc_cfg.am.max_retx_thresh = srb_cfg->enb_dl_max_retx_thres;
}
parent->rlc->add_bearer(rnti, srb.srb_id, rlc_cfg);
}
}
if (pending_rr_cfg.drb_to_release_list.size() > 0) {
for (uint8_t drb_id : pending_rr_cfg.drb_to_release_list) {
parent->rlc->del_bearer(rnti, drb_to_lcid((lte_drb)drb_id));
@ -1431,7 +1454,13 @@ void rrc::ue::apply_rlc_rb_updates(const rr_cfg_ded_s& pending_rr_cfg)
if (not drb.rlc_cfg_present) {
parent->logger.warning("Default RLC DRB config not supported");
}
parent->rlc->add_bearer(rnti, drb.lc_ch_id, srsran::make_rlc_config_t(drb.rlc_cfg));
srsran::rlc_config_t rlc_cfg = srsran::make_rlc_config_t(drb.rlc_cfg);
const bearer_cfg_handler::erab_t& erab = bearer_list.get_erabs().at(drb.eps_bearer_id);
if (rlc_cfg.rlc_mode == srsran::rlc_mode_t::am and
parent->cfg.qci_cfg.at(erab.qos_params.qci).enb_dl_max_retx_thres > 0) {
rlc_cfg.am.max_retx_thresh = parent->cfg.qci_cfg.at(erab.qos_params.qci).enb_dl_max_retx_thres;
}
parent->rlc->add_bearer(rnti, drb.lc_ch_id, rlc_cfg);
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save