mirror of https://github.com/PentHertz/srsLTE.git
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
This commit is contained in:
commit
ccf8cfb65f
|
@ -24,4 +24,4 @@ set(CTEST_DROP_METHOD "http")
|
||||||
set(CTEST_DROP_SITE "my.cdash.org")
|
set(CTEST_DROP_SITE "my.cdash.org")
|
||||||
set(CTEST_DROP_LOCATION "/submit.php?project=srsRAN")
|
set(CTEST_DROP_LOCATION "/submit.php?project=srsRAN")
|
||||||
set(CTEST_DROP_SITE_CDASH TRUE)
|
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 "enb.conf.example"
|
||||||
install_file "sib.conf.example"
|
install_file "sib.conf.example"
|
||||||
install_file "rr.conf.example"
|
install_file "rr.conf.example"
|
||||||
install_file "drb.conf.example"
|
install_file "rb.conf.example"
|
||||||
install_file "epc.conf.example"
|
install_file "epc.conf.example"
|
||||||
install_file "mbms.conf.example"
|
install_file "mbms.conf.example"
|
||||||
install_file "user_db.csv.example"
|
install_file "user_db.csv.example"
|
||||||
|
|
|
@ -2127,265 +2127,353 @@ public:
|
||||||
registration_request_t& set_registration_request()
|
registration_request_t& set_registration_request()
|
||||||
{
|
{
|
||||||
set(msg_types::options::registration_request);
|
set(msg_types::options::registration_request);
|
||||||
msg_container = srslog::detail::any{registration_request_t()};
|
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);
|
return *srslog::detail::any_cast<registration_request_t>(&msg_container);
|
||||||
}
|
}
|
||||||
registration_accept_t& set_registration_accept()
|
registration_accept_t& set_registration_accept()
|
||||||
{
|
{
|
||||||
set(msg_types::options::registration_accept);
|
set(msg_types::options::registration_accept);
|
||||||
msg_container = srslog::detail::any{registration_accept_t()};
|
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);
|
return *srslog::detail::any_cast<registration_accept_t>(&msg_container);
|
||||||
}
|
}
|
||||||
registration_complete_t& set_registration_complete()
|
registration_complete_t& set_registration_complete()
|
||||||
{
|
{
|
||||||
set(msg_types::options::registration_complete);
|
set(msg_types::options::registration_complete);
|
||||||
msg_container = srslog::detail::any{registration_complete_t()};
|
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);
|
return *srslog::detail::any_cast<registration_complete_t>(&msg_container);
|
||||||
}
|
}
|
||||||
registration_reject_t& set_registration_reject()
|
registration_reject_t& set_registration_reject()
|
||||||
{
|
{
|
||||||
set(msg_types::options::registration_reject);
|
set(msg_types::options::registration_reject);
|
||||||
msg_container = srslog::detail::any{registration_reject_t()};
|
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);
|
return *srslog::detail::any_cast<registration_reject_t>(&msg_container);
|
||||||
}
|
}
|
||||||
deregistration_request_ue_originating_t& set_deregistration_request_ue_originating()
|
deregistration_request_ue_originating_t& set_deregistration_request_ue_originating()
|
||||||
{
|
{
|
||||||
set(msg_types::options::deregistration_request_ue_originating);
|
set(msg_types::options::deregistration_request_ue_originating);
|
||||||
msg_container = srslog::detail::any{deregistration_request_ue_originating_t()};
|
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);
|
return *srslog::detail::any_cast<deregistration_request_ue_originating_t>(&msg_container);
|
||||||
}
|
}
|
||||||
deregistration_accept_ue_originating_t& set_deregistration_accept_ue_originating()
|
deregistration_accept_ue_originating_t& set_deregistration_accept_ue_originating()
|
||||||
{
|
{
|
||||||
set(msg_types::options::deregistration_accept_ue_originating);
|
set(msg_types::options::deregistration_accept_ue_originating);
|
||||||
msg_container = srslog::detail::any{deregistration_accept_ue_originating_t()};
|
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);
|
return *srslog::detail::any_cast<deregistration_accept_ue_originating_t>(&msg_container);
|
||||||
}
|
}
|
||||||
deregistration_request_ue_terminated_t& set_deregistration_request_ue_terminated()
|
deregistration_request_ue_terminated_t& set_deregistration_request_ue_terminated()
|
||||||
{
|
{
|
||||||
set(msg_types::options::deregistration_request_ue_terminated);
|
set(msg_types::options::deregistration_request_ue_terminated);
|
||||||
msg_container = srslog::detail::any{deregistration_request_ue_terminated_t()};
|
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);
|
return *srslog::detail::any_cast<deregistration_request_ue_terminated_t>(&msg_container);
|
||||||
}
|
}
|
||||||
deregistration_accept_ue_terminated_t& set_deregistration_accept_ue_terminated()
|
deregistration_accept_ue_terminated_t& set_deregistration_accept_ue_terminated()
|
||||||
{
|
{
|
||||||
set(msg_types::options::deregistration_accept_ue_terminated);
|
set(msg_types::options::deregistration_accept_ue_terminated);
|
||||||
msg_container = srslog::detail::any{deregistration_accept_ue_terminated_t()};
|
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);
|
return *srslog::detail::any_cast<deregistration_accept_ue_terminated_t>(&msg_container);
|
||||||
}
|
}
|
||||||
service_request_t& set_service_request()
|
service_request_t& set_service_request()
|
||||||
{
|
{
|
||||||
set(msg_types::options::service_request);
|
set(msg_types::options::service_request);
|
||||||
msg_container = srslog::detail::any{service_request_t()};
|
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);
|
return *srslog::detail::any_cast<service_request_t>(&msg_container);
|
||||||
}
|
}
|
||||||
service_reject_t& set_service_reject()
|
service_reject_t& set_service_reject()
|
||||||
{
|
{
|
||||||
set(msg_types::options::service_reject);
|
set(msg_types::options::service_reject);
|
||||||
msg_container = srslog::detail::any{service_reject_t()};
|
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);
|
return *srslog::detail::any_cast<service_reject_t>(&msg_container);
|
||||||
}
|
}
|
||||||
service_accept_t& set_service_accept()
|
service_accept_t& set_service_accept()
|
||||||
{
|
{
|
||||||
set(msg_types::options::service_accept);
|
set(msg_types::options::service_accept);
|
||||||
msg_container = srslog::detail::any{service_accept_t()};
|
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);
|
return *srslog::detail::any_cast<service_accept_t>(&msg_container);
|
||||||
}
|
}
|
||||||
configuration_update_command_t& set_configuration_update_command()
|
configuration_update_command_t& set_configuration_update_command()
|
||||||
{
|
{
|
||||||
set(msg_types::options::configuration_update_command);
|
set(msg_types::options::configuration_update_command);
|
||||||
msg_container = srslog::detail::any{configuration_update_command_t()};
|
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);
|
return *srslog::detail::any_cast<configuration_update_command_t>(&msg_container);
|
||||||
}
|
}
|
||||||
configuration_update_complete_t& set_configuration_update_complete()
|
configuration_update_complete_t& set_configuration_update_complete()
|
||||||
{
|
{
|
||||||
set(msg_types::options::configuration_update_complete);
|
set(msg_types::options::configuration_update_complete);
|
||||||
msg_container = srslog::detail::any{configuration_update_complete_t()};
|
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);
|
return *srslog::detail::any_cast<configuration_update_complete_t>(&msg_container);
|
||||||
}
|
}
|
||||||
authentication_request_t& set_authentication_request()
|
authentication_request_t& set_authentication_request()
|
||||||
{
|
{
|
||||||
set(msg_types::options::authentication_request);
|
set(msg_types::options::authentication_request);
|
||||||
msg_container = srslog::detail::any{authentication_request_t()};
|
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);
|
return *srslog::detail::any_cast<authentication_request_t>(&msg_container);
|
||||||
}
|
}
|
||||||
authentication_response_t& set_authentication_response()
|
authentication_response_t& set_authentication_response()
|
||||||
{
|
{
|
||||||
set(msg_types::options::authentication_response);
|
set(msg_types::options::authentication_response);
|
||||||
msg_container = srslog::detail::any{authentication_response_t()};
|
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);
|
return *srslog::detail::any_cast<authentication_response_t>(&msg_container);
|
||||||
}
|
}
|
||||||
authentication_reject_t& set_authentication_reject()
|
authentication_reject_t& set_authentication_reject()
|
||||||
{
|
{
|
||||||
set(msg_types::options::authentication_reject);
|
set(msg_types::options::authentication_reject);
|
||||||
msg_container = srslog::detail::any{authentication_reject_t()};
|
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);
|
return *srslog::detail::any_cast<authentication_reject_t>(&msg_container);
|
||||||
}
|
}
|
||||||
authentication_failure_t& set_authentication_failure()
|
authentication_failure_t& set_authentication_failure()
|
||||||
{
|
{
|
||||||
set(msg_types::options::authentication_failure);
|
set(msg_types::options::authentication_failure);
|
||||||
msg_container = srslog::detail::any{authentication_failure_t()};
|
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);
|
return *srslog::detail::any_cast<authentication_failure_t>(&msg_container);
|
||||||
}
|
}
|
||||||
authentication_result_t& set_authentication_result()
|
authentication_result_t& set_authentication_result()
|
||||||
{
|
{
|
||||||
set(msg_types::options::authentication_result);
|
set(msg_types::options::authentication_result);
|
||||||
msg_container = srslog::detail::any{authentication_result_t()};
|
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);
|
return *srslog::detail::any_cast<authentication_result_t>(&msg_container);
|
||||||
}
|
}
|
||||||
identity_request_t& set_identity_request()
|
identity_request_t& set_identity_request()
|
||||||
{
|
{
|
||||||
set(msg_types::options::identity_request);
|
set(msg_types::options::identity_request);
|
||||||
msg_container = srslog::detail::any{identity_request_t()};
|
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);
|
return *srslog::detail::any_cast<identity_request_t>(&msg_container);
|
||||||
}
|
}
|
||||||
identity_response_t& set_identity_response()
|
identity_response_t& set_identity_response()
|
||||||
{
|
{
|
||||||
set(msg_types::options::identity_response);
|
set(msg_types::options::identity_response);
|
||||||
msg_container = srslog::detail::any{identity_response_t()};
|
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);
|
return *srslog::detail::any_cast<identity_response_t>(&msg_container);
|
||||||
}
|
}
|
||||||
security_mode_command_t& set_security_mode_command()
|
security_mode_command_t& set_security_mode_command()
|
||||||
{
|
{
|
||||||
set(msg_types::options::security_mode_command);
|
set(msg_types::options::security_mode_command);
|
||||||
msg_container = srslog::detail::any{security_mode_command_t()};
|
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);
|
return *srslog::detail::any_cast<security_mode_command_t>(&msg_container);
|
||||||
}
|
}
|
||||||
security_mode_complete_t& set_security_mode_complete()
|
security_mode_complete_t& set_security_mode_complete()
|
||||||
{
|
{
|
||||||
set(msg_types::options::security_mode_complete);
|
set(msg_types::options::security_mode_complete);
|
||||||
msg_container = srslog::detail::any{security_mode_complete_t()};
|
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);
|
return *srslog::detail::any_cast<security_mode_complete_t>(&msg_container);
|
||||||
}
|
}
|
||||||
security_mode_reject_t& set_security_mode_reject()
|
security_mode_reject_t& set_security_mode_reject()
|
||||||
{
|
{
|
||||||
set(msg_types::options::security_mode_reject);
|
set(msg_types::options::security_mode_reject);
|
||||||
msg_container = srslog::detail::any{security_mode_reject_t()};
|
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);
|
return *srslog::detail::any_cast<security_mode_reject_t>(&msg_container);
|
||||||
}
|
}
|
||||||
status_5gmm_t& set_status_5gmm()
|
status_5gmm_t& set_status_5gmm()
|
||||||
{
|
{
|
||||||
set(msg_types::options::status_5gmm);
|
set(msg_types::options::status_5gmm);
|
||||||
msg_container = srslog::detail::any{status_5gmm_t()};
|
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);
|
return *srslog::detail::any_cast<status_5gmm_t>(&msg_container);
|
||||||
}
|
}
|
||||||
notification_t& set_notification()
|
notification_t& set_notification()
|
||||||
{
|
{
|
||||||
set(msg_types::options::notification);
|
set(msg_types::options::notification);
|
||||||
msg_container = srslog::detail::any{notification_t()};
|
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);
|
return *srslog::detail::any_cast<notification_t>(&msg_container);
|
||||||
}
|
}
|
||||||
notification_response_t& set_notification_response()
|
notification_response_t& set_notification_response()
|
||||||
{
|
{
|
||||||
set(msg_types::options::notification_response);
|
set(msg_types::options::notification_response);
|
||||||
msg_container = srslog::detail::any{notification_response_t()};
|
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);
|
return *srslog::detail::any_cast<notification_response_t>(&msg_container);
|
||||||
}
|
}
|
||||||
ul_nas_transport_t& set_ul_nas_transport()
|
ul_nas_transport_t& set_ul_nas_transport()
|
||||||
{
|
{
|
||||||
set(msg_types::options::ul_nas_transport);
|
set(msg_types::options::ul_nas_transport);
|
||||||
msg_container = srslog::detail::any{ul_nas_transport_t()};
|
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);
|
return *srslog::detail::any_cast<ul_nas_transport_t>(&msg_container);
|
||||||
}
|
}
|
||||||
dl_nas_transport_t& set_dl_nas_transport()
|
dl_nas_transport_t& set_dl_nas_transport()
|
||||||
{
|
{
|
||||||
set(msg_types::options::dl_nas_transport);
|
set(msg_types::options::dl_nas_transport);
|
||||||
msg_container = srslog::detail::any{dl_nas_transport_t()};
|
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);
|
return *srslog::detail::any_cast<dl_nas_transport_t>(&msg_container);
|
||||||
}
|
}
|
||||||
pdu_session_establishment_request_t& set_pdu_session_establishment_request()
|
pdu_session_establishment_request_t& set_pdu_session_establishment_request()
|
||||||
{
|
{
|
||||||
set(msg_types::options::pdu_session_establishment_request);
|
set(msg_types::options::pdu_session_establishment_request);
|
||||||
msg_container = srslog::detail::any{pdu_session_establishment_request_t()};
|
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);
|
return *srslog::detail::any_cast<pdu_session_establishment_request_t>(&msg_container);
|
||||||
}
|
}
|
||||||
pdu_session_establishment_accept_t& set_pdu_session_establishment_accept()
|
pdu_session_establishment_accept_t& set_pdu_session_establishment_accept()
|
||||||
{
|
{
|
||||||
set(msg_types::options::pdu_session_establishment_accept);
|
set(msg_types::options::pdu_session_establishment_accept);
|
||||||
msg_container = srslog::detail::any{pdu_session_establishment_accept_t()};
|
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);
|
return *srslog::detail::any_cast<pdu_session_establishment_accept_t>(&msg_container);
|
||||||
}
|
}
|
||||||
pdu_session_establishment_reject_t& set_pdu_session_establishment_reject()
|
pdu_session_establishment_reject_t& set_pdu_session_establishment_reject()
|
||||||
{
|
{
|
||||||
set(msg_types::options::pdu_session_establishment_reject);
|
set(msg_types::options::pdu_session_establishment_reject);
|
||||||
msg_container = srslog::detail::any{pdu_session_establishment_reject_t()};
|
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);
|
return *srslog::detail::any_cast<pdu_session_establishment_reject_t>(&msg_container);
|
||||||
}
|
}
|
||||||
pdu_session_authentication_command_t& set_pdu_session_authentication_command()
|
pdu_session_authentication_command_t& set_pdu_session_authentication_command()
|
||||||
{
|
{
|
||||||
set(msg_types::options::pdu_session_authentication_command);
|
set(msg_types::options::pdu_session_authentication_command);
|
||||||
msg_container = srslog::detail::any{pdu_session_authentication_command_t()};
|
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);
|
return *srslog::detail::any_cast<pdu_session_authentication_command_t>(&msg_container);
|
||||||
}
|
}
|
||||||
pdu_session_authentication_complete_t& set_pdu_session_authentication_complete()
|
pdu_session_authentication_complete_t& set_pdu_session_authentication_complete()
|
||||||
{
|
{
|
||||||
set(msg_types::options::pdu_session_authentication_complete);
|
set(msg_types::options::pdu_session_authentication_complete);
|
||||||
msg_container = srslog::detail::any{pdu_session_authentication_complete_t()};
|
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);
|
return *srslog::detail::any_cast<pdu_session_authentication_complete_t>(&msg_container);
|
||||||
}
|
}
|
||||||
pdu_session_authentication_result_t& set_pdu_session_authentication_result()
|
pdu_session_authentication_result_t& set_pdu_session_authentication_result()
|
||||||
{
|
{
|
||||||
set(msg_types::options::pdu_session_authentication_result);
|
set(msg_types::options::pdu_session_authentication_result);
|
||||||
msg_container = srslog::detail::any{pdu_session_authentication_result_t()};
|
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);
|
return *srslog::detail::any_cast<pdu_session_authentication_result_t>(&msg_container);
|
||||||
}
|
}
|
||||||
pdu_session_modification_request_t& set_pdu_session_modification_request()
|
pdu_session_modification_request_t& set_pdu_session_modification_request()
|
||||||
{
|
{
|
||||||
set(msg_types::options::pdu_session_modification_request);
|
set(msg_types::options::pdu_session_modification_request);
|
||||||
msg_container = srslog::detail::any{pdu_session_modification_request_t()};
|
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);
|
return *srslog::detail::any_cast<pdu_session_modification_request_t>(&msg_container);
|
||||||
}
|
}
|
||||||
pdu_session_modification_reject_t& set_pdu_session_modification_reject()
|
pdu_session_modification_reject_t& set_pdu_session_modification_reject()
|
||||||
{
|
{
|
||||||
set(msg_types::options::pdu_session_modification_reject);
|
set(msg_types::options::pdu_session_modification_reject);
|
||||||
msg_container = srslog::detail::any{pdu_session_modification_reject_t()};
|
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);
|
return *srslog::detail::any_cast<pdu_session_modification_reject_t>(&msg_container);
|
||||||
}
|
}
|
||||||
pdu_session_modification_command_t& set_pdu_session_modification_command()
|
pdu_session_modification_command_t& set_pdu_session_modification_command()
|
||||||
{
|
{
|
||||||
set(msg_types::options::pdu_session_modification_command);
|
set(msg_types::options::pdu_session_modification_command);
|
||||||
msg_container = srslog::detail::any{pdu_session_modification_command_t()};
|
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);
|
return *srslog::detail::any_cast<pdu_session_modification_command_t>(&msg_container);
|
||||||
}
|
}
|
||||||
pdu_session_modification_complete_t& set_pdu_session_modification_complete()
|
pdu_session_modification_complete_t& set_pdu_session_modification_complete()
|
||||||
{
|
{
|
||||||
set(msg_types::options::pdu_session_modification_complete);
|
set(msg_types::options::pdu_session_modification_complete);
|
||||||
msg_container = srslog::detail::any{pdu_session_modification_complete_t()};
|
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);
|
return *srslog::detail::any_cast<pdu_session_modification_complete_t>(&msg_container);
|
||||||
}
|
}
|
||||||
pdu_session_modification_command_reject_t& set_pdu_session_modification_command_reject()
|
pdu_session_modification_command_reject_t& set_pdu_session_modification_command_reject()
|
||||||
{
|
{
|
||||||
set(msg_types::options::pdu_session_modification_command_reject);
|
set(msg_types::options::pdu_session_modification_command_reject);
|
||||||
msg_container = srslog::detail::any{pdu_session_modification_command_reject_t()};
|
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);
|
return *srslog::detail::any_cast<pdu_session_modification_command_reject_t>(&msg_container);
|
||||||
}
|
}
|
||||||
pdu_session_release_request_t& set_pdu_session_release_request()
|
pdu_session_release_request_t& set_pdu_session_release_request()
|
||||||
{
|
{
|
||||||
set(msg_types::options::pdu_session_release_request);
|
set(msg_types::options::pdu_session_release_request);
|
||||||
msg_container = srslog::detail::any{pdu_session_release_request_t()};
|
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);
|
return *srslog::detail::any_cast<pdu_session_release_request_t>(&msg_container);
|
||||||
}
|
}
|
||||||
pdu_session_release_reject_t& set_pdu_session_release_reject()
|
pdu_session_release_reject_t& set_pdu_session_release_reject()
|
||||||
{
|
{
|
||||||
set(msg_types::options::pdu_session_release_reject);
|
set(msg_types::options::pdu_session_release_reject);
|
||||||
msg_container = srslog::detail::any{pdu_session_release_reject_t()};
|
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);
|
return *srslog::detail::any_cast<pdu_session_release_reject_t>(&msg_container);
|
||||||
}
|
}
|
||||||
pdu_session_release_command_t& set_pdu_session_release_command()
|
pdu_session_release_command_t& set_pdu_session_release_command()
|
||||||
{
|
{
|
||||||
set(msg_types::options::pdu_session_release_command);
|
set(msg_types::options::pdu_session_release_command);
|
||||||
msg_container = srslog::detail::any{pdu_session_release_command_t()};
|
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);
|
return *srslog::detail::any_cast<pdu_session_release_command_t>(&msg_container);
|
||||||
}
|
}
|
||||||
pdu_session_release_complete_t& set_pdu_session_release_complete()
|
pdu_session_release_complete_t& set_pdu_session_release_complete()
|
||||||
{
|
{
|
||||||
set(msg_types::options::pdu_session_release_complete);
|
set(msg_types::options::pdu_session_release_complete);
|
||||||
msg_container = srslog::detail::any{pdu_session_release_complete_t()};
|
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);
|
return *srslog::detail::any_cast<pdu_session_release_complete_t>(&msg_container);
|
||||||
}
|
}
|
||||||
status_5gsm_t& set_status_5gsm()
|
status_5gsm_t& set_status_5gsm()
|
||||||
{
|
{
|
||||||
set(msg_types::options::status_5gsm);
|
set(msg_types::options::status_5gsm);
|
||||||
msg_container = srslog::detail::any{status_5gsm_t()};
|
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);
|
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 vars required by signal handling
|
||||||
static srslog::sink* log_sink = nullptr;
|
static srslog::sink* log_sink = nullptr;
|
||||||
static bool running = true;
|
static std::atomic<bool> running = {true};
|
||||||
|
|
||||||
static void srsran_signal_handler(int signal)
|
static void srsran_signal_handler(int signal)
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,6 +34,7 @@ struct mac_args_t {
|
||||||
int nr_tb_size = -1;
|
int nr_tb_size = -1;
|
||||||
uint32_t nof_prealloc_ues; ///< Number of UE resources to pre-allocate at eNB startup
|
uint32_t nof_prealloc_ues; ///< Number of UE resources to pre-allocate at eNB startup
|
||||||
uint32_t max_nof_kos;
|
uint32_t max_nof_kos;
|
||||||
|
int rlf_min_ul_snr_estim;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Interface PHY -> MAC */
|
/* Interface PHY -> MAC */
|
||||||
|
|
|
@ -171,42 +171,31 @@ public:
|
||||||
virtual void notify_pdcp_integrity_error(uint16_t rnti, uint32_t lcid) = 0;
|
virtual void notify_pdcp_integrity_error(uint16_t rnti, uint32_t lcid) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class phy_interface_stack_nr
|
class phy_interface_rrc_nr
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const static int MAX_DL_GRANTS = 4;
|
/**
|
||||||
|
* @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 {
|
virtual int set_common_cfg(const common_cfg_t& common_cfg) = 0;
|
||||||
// TODO: include NR related fields
|
};
|
||||||
} dl_sched_grant_t;
|
|
||||||
|
|
||||||
typedef struct {
|
class phy_interface_mac_nr
|
||||||
bool mib_present;
|
{
|
||||||
} bch_sched_t;
|
public:
|
||||||
|
// TBD
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
class phy_interface_stack_nr : public phy_interface_rrc_nr, public phy_interface_mac_nr
|
||||||
uint32_t tti;
|
{
|
||||||
uint32_t nof_grants;
|
public:
|
||||||
dl_sched_grant_t pdsch[MAX_DL_GRANTS];
|
// TBD
|
||||||
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;
|
|
||||||
|
|
||||||
virtual int dl_config_request(const dl_config_request_t& request) = 0;
|
|
||||||
virtual int tx_request(const tx_request_t& request) = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class stack_interface_mac
|
class stack_interface_mac
|
||||||
|
@ -280,11 +269,17 @@ public:
|
||||||
// ... add signal measurements here
|
// ... add signal measurements here
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual int slot_indication(const srsran_slot_cfg_t& slot_cfg) = 0;
|
struct rach_info_t {
|
||||||
virtual int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) = 0;
|
uint32_t preamble;
|
||||||
virtual int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) = 0;
|
uint32_t time_adv;
|
||||||
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 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
|
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_ul_snr_value = 5;
|
||||||
int init_dl_cqi = 5;
|
int init_dl_cqi = 5;
|
||||||
float max_sib_coderate = 0.8;
|
float max_sib_coderate = 0.8;
|
||||||
|
int pdcch_cqi_offset = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cell_cfg_t {
|
struct cell_cfg_t {
|
||||||
|
|
|
@ -48,6 +48,17 @@ public:
|
||||||
virtual bool connection_request_completed(bool outcome) = 0;
|
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
|
} // namespace srsue
|
||||||
|
|
||||||
#endif // SRSRAN_UE_NAS_INTERFACES_H
|
#endif // SRSRAN_UE_NAS_INTERFACES_H
|
||||||
|
|
|
@ -184,6 +184,7 @@ struct phy_args_nr_t {
|
||||||
srsran_ue_ul_nr_args_t ul = {};
|
srsran_ue_ul_nr_args_t ul = {};
|
||||||
std::set<uint32_t> fixed_sr = {1};
|
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
|
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()
|
phy_args_nr_t()
|
||||||
{
|
{
|
||||||
|
|
|
@ -95,6 +95,8 @@ struct phy_args_t {
|
||||||
float force_ul_amplitude = 0.0f;
|
float force_ul_amplitude = 0.0f;
|
||||||
bool detect_cp = false;
|
bool detect_cp = false;
|
||||||
|
|
||||||
|
bool nr_store_pdsch_ko = false;
|
||||||
|
|
||||||
float in_sync_rsrp_dbm_th = -130.0f;
|
float in_sync_rsrp_dbm_th = -130.0f;
|
||||||
float in_sync_snr_db_th = 1.0f;
|
float in_sync_snr_db_th = 1.0f;
|
||||||
uint32_t nof_in_sync_events = 10;
|
uint32_t nof_in_sync_events = 10;
|
||||||
|
@ -138,8 +140,8 @@ public:
|
||||||
} prach_info_t;
|
} prach_info_t;
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm, float ta_base_sec = 0.0f) = 0;
|
prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm, float ta_base_sec = 0.0f) = 0;
|
||||||
virtual prach_info_t prach_get_info() = 0;
|
virtual prach_info_t prach_get_info() = 0;
|
||||||
|
|
||||||
/* Indicates the transmission of a SR signal in the next opportunity */
|
/* Indicates the transmission of a SR signal in the next opportunity */
|
||||||
virtual void sr_send() = 0;
|
virtual void sr_send() = 0;
|
||||||
|
|
|
@ -122,6 +122,10 @@ public:
|
||||||
virtual bool is_config_pending() = 0;
|
virtual bool is_config_pending() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class rrc_nr_interface_nas_5g
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
};
|
||||||
} // namespace srsue
|
} // namespace srsue
|
||||||
|
|
||||||
#endif // SRSRAN_UE_RRC_INTERFACES_H
|
#endif // SRSRAN_UE_RRC_INTERFACES_H
|
||||||
|
|
|
@ -156,8 +156,14 @@ typedef struct SRSRAN_API {
|
||||||
uint32_t pid; ///< HARQ process number
|
uint32_t pid; ///< HARQ process number
|
||||||
uint32_t dai; ///< Downlink assignment index
|
uint32_t dai; ///< Downlink assignment index
|
||||||
uint32_t tpc; ///< TPC command for scheduled PUCCH
|
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
|
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
|
// P-RNTI specific fields
|
||||||
uint32_t smi; ///< Short Messages Indicator
|
uint32_t smi; ///< Short Messages Indicator
|
||||||
|
|
|
@ -44,12 +44,11 @@
|
||||||
* @brief Uplink Control Information bits configuration for PUCCH transmission
|
* @brief Uplink Control Information bits configuration for PUCCH transmission
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint16_t rnti; ///< RNTI
|
uint16_t rnti; ///< RNTI
|
||||||
uint32_t resource_id; ///< PUCCH resource indicator field in the DCI format 1_0 or DCI format 1_1
|
uint32_t resource_id; ///< PUCCH resource indicator field in the DCI format 1_0 or DCI format 1_1
|
||||||
uint32_t n_cce_0; ///< index of a first CCE for the PDCCH reception
|
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 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
|
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;
|
} srsran_uci_nr_pucch_cfg_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,6 +78,7 @@ typedef struct SRSRAN_API {
|
||||||
/// Common Parameters
|
/// Common Parameters
|
||||||
srsran_harq_ack_cfg_t ack; ///< HARQ-ACK configuration
|
srsran_harq_ack_cfg_t ack; ///< HARQ-ACK configuration
|
||||||
uint32_t o_sr; ///< Number of SR bits
|
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
|
srsran_csi_report_cfg_t csi[SRSRAN_CSI_MAX_NOF_REPORT]; ///< CSI report configuration
|
||||||
uint32_t nof_csi; ///< Number of CSI reports
|
uint32_t nof_csi; ///< Number of CSI reports
|
||||||
union {
|
union {
|
||||||
|
|
|
@ -99,6 +99,7 @@ private:
|
||||||
std::vector<srsran_rf_info_t> rf_info = {};
|
std::vector<srsran_rf_info_t> rf_info = {};
|
||||||
std::vector<int32_t> rx_offset_n = {};
|
std::vector<int32_t> rx_offset_n = {};
|
||||||
rf_metrics_t rf_metrics = {};
|
rf_metrics_t rf_metrics = {};
|
||||||
|
std::mutex metrics_mutex;
|
||||||
srslog::basic_logger& logger = srslog::fetch_basic_logger("RF", false);
|
srslog::basic_logger& logger = srslog::fetch_basic_logger("RF", false);
|
||||||
phy_interface_radio* phy = nullptr;
|
phy_interface_radio* phy = nullptr;
|
||||||
cf_t* zeros = nullptr;
|
cf_t* zeros = nullptr;
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#define SRSLOG_SHARED_TYPES_H
|
#define SRSLOG_SHARED_TYPES_H
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace srslog {
|
namespace srslog {
|
||||||
|
|
||||||
|
@ -30,8 +31,7 @@ namespace srslog {
|
||||||
using error_handler = std::function<void(const std::string&)>;
|
using error_handler = std::function<void(const std::string&)>;
|
||||||
|
|
||||||
/// Backend priority levels.
|
/// Backend priority levels.
|
||||||
enum class backend_priority
|
enum class backend_priority {
|
||||||
{
|
|
||||||
/// Default priority of the operating system.
|
/// Default priority of the operating system.
|
||||||
normal,
|
normal,
|
||||||
/// Thread will be given a high priority.
|
/// Thread will be given a high priority.
|
||||||
|
@ -40,6 +40,18 @@ enum class backend_priority
|
||||||
very_high
|
very_high
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// syslog log local types
|
||||||
|
enum class syslog_local_type {
|
||||||
|
local0,
|
||||||
|
local1,
|
||||||
|
local2,
|
||||||
|
local3,
|
||||||
|
local4,
|
||||||
|
local5,
|
||||||
|
local6,
|
||||||
|
local7,
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace srslog
|
} // namespace srslog
|
||||||
|
|
||||||
#endif // SRSLOG_SHARED_TYPES_H
|
#endif // SRSLOG_SHARED_TYPES_H
|
||||||
|
|
|
@ -193,6 +193,14 @@ sink& fetch_file_sink(const std::string& path,
|
||||||
size_t max_size = 0,
|
size_t max_size = 0,
|
||||||
std::unique_ptr<log_formatter> f = get_default_log_formatter());
|
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
|
/// Installs a custom user defined sink in the framework getting associated to
|
||||||
/// the specified id. Returns true on success, otherwise false.
|
/// the specified id. Returns true on success, otherwise false.
|
||||||
/// WARNING: This function is an advanced feature and users should really know
|
/// 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));
|
HANDLE_CODE(bref.pack(cag, 1));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
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",
|
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));
|
HANDLE_CODE(bref.pack(eia7_supported, 1));
|
||||||
}
|
}
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 2 || length > 8) {
|
||||||
asn1::log_error(
|
asn1::log_error(
|
||||||
|
@ -617,7 +617,7 @@ SRSASN_CODE nssai_t::pack(asn1::bit_ref& bref)
|
||||||
}
|
}
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
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);
|
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));
|
HANDLE_CODE(bref.pack(racs_supported, 1));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 2 || length > 13) {
|
||||||
asn1::log_error(
|
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));
|
HANDLE_CODE(bref.pack(psi_8, 1));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 2 || length > 32) {
|
||||||
asn1::log_error(
|
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));
|
HANDLE_CODE(bref.pack(psi_8, 1));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 2 || length > 32) {
|
||||||
asn1::log_error(
|
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));
|
HANDLE_CODE(bref.pack(s1_mode_reg, 1));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 1) {
|
||||||
asn1::log_error("Encoding Failed (UE status): Packed length (%d) does not equal expected length 1", length);
|
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));
|
HANDLE_CODE(bref.pack(psi_8, 1));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 2 || length > 32) {
|
||||||
asn1::log_error(
|
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));
|
HANDLE_CODE(ue_usage_setting.pack(bref));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 1) {
|
||||||
asn1::log_error("Encoding Failed (UE usage setting): Packed length (%d) does not equal expected length 1", length);
|
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));
|
HANDLE_CODE(drx_value.pack(bref));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 1) {
|
||||||
asn1::log_error("Encoding Failed (5GS DRX parameters): Packed length (%d) does not equal expected 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()));
|
HANDLE_CODE(bref.pack_bytes(eps_nas_message_container.data(), eps_nas_message_container.size()));
|
||||||
bref.align_bytes_zero();
|
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));
|
HANDLE_CODE(bref_length.pack(length, 16));
|
||||||
return SRSASN_SUCCESS;
|
return SRSASN_SUCCESS;
|
||||||
|
@ -1250,7 +1250,7 @@ SRSASN_CODE ladn_indication_t::pack(asn1::bit_ref& bref)
|
||||||
}
|
}
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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
|
// MIN 0 not check because auf uint underflow
|
||||||
if (length > 808) {
|
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()));
|
HANDLE_CODE(bref.pack_bytes(payload_container_contents.data(), payload_container_contents.size()));
|
||||||
bref.align_bytes_zero();
|
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
|
// MAX 65535 not check because auf uint overflow
|
||||||
if (length < 1) {
|
if (length < 1) {
|
||||||
|
@ -1370,7 +1370,7 @@ SRSASN_CODE update_type_5gs_t::pack(asn1::bit_ref& bref)
|
||||||
HANDLE_CODE(sms_requested.pack(bref));
|
HANDLE_CODE(sms_requested.pack(bref));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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));
|
HANDLE_CODE(bref_length.pack(length, 8));
|
||||||
return SRSASN_SUCCESS;
|
return SRSASN_SUCCESS;
|
||||||
|
@ -1400,7 +1400,7 @@ SRSASN_CODE mobile_station_classmark_2_t::pack(asn1::bit_ref& bref)
|
||||||
// TODO proper packing
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 3) {
|
||||||
asn1::log_error("Encoding Failed (Mobile station classmark 2): Packed length (%d) does not equal expected 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
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 3) {
|
||||||
asn1::log_error("Encoding Failed (Supported codec list): Packed length (%d) is not in range of min: 3 bytes",
|
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()));
|
HANDLE_CODE(bref.pack_bytes(nas_message_container.data(), nas_message_container.size()));
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 1 || length > 65532) {
|
||||||
asn1::log_error(
|
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));
|
HANDLE_CODE(bref.pack(ebi_8, 1));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 2) {
|
||||||
asn1::log_error("Encoding Failed (EPS bearer context status): Packed length (%d) does not equal expected 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));
|
HANDLE_CODE(e_drx_value.pack(bref));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 1) {
|
||||||
asn1::log_error("Encoding Failed (Extended DRX parameters): Packed length (%d) does not equal expected 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));
|
HANDLE_CODE(bref.pack(timer_value, 5));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 1) {
|
||||||
asn1::log_error("Encoding Failed (GPRS timer 3): Packed length (%d) does not equal expected length 1", length);
|
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()));
|
HANDLE_CODE(bref.pack_bytes(ue_radio_capability_id.data(), ue_radio_capability_id.size()));
|
||||||
bref.align_bytes_zero();
|
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));
|
HANDLE_CODE(bref_length.pack(length, 8));
|
||||||
return SRSASN_SUCCESS;
|
return SRSASN_SUCCESS;
|
||||||
|
@ -1677,7 +1677,7 @@ SRSASN_CODE mapped_nssai_t::pack(asn1::bit_ref& bref)
|
||||||
// TODO proper packing
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
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",
|
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));
|
HANDLE_CODE(bref.pack(cipher_key, 1));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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));
|
HANDLE_CODE(bref_length.pack(length, 8));
|
||||||
return SRSASN_SUCCESS;
|
return SRSASN_SUCCESS;
|
||||||
|
@ -1743,7 +1743,7 @@ SRSASN_CODE wus_assistance_information_t::pack(asn1::bit_ref& bref)
|
||||||
// TODO proper packing
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 1) {
|
||||||
asn1::log_error("Encoding Failed (WUS assistance information): Packed length (%d) is not in range of min: 1 bytes",
|
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));
|
HANDLE_CODE(nb_n1_mode_drx_value.pack(bref));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 1) {
|
||||||
asn1::log_error("Encoding Failed (NB-N1 mode DRX parameters): Packed length (%d) does not equal expected 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));
|
HANDLE_CODE(registration_result.pack(bref));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 1) {
|
||||||
asn1::log_error("Encoding Failed (5GS registration result): Packed length (%d) does not equal expected 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
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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));
|
HANDLE_CODE(bref_length.pack(length, 8));
|
||||||
return SRSASN_SUCCESS;
|
return SRSASN_SUCCESS;
|
||||||
|
@ -1913,7 +1913,7 @@ SRSASN_CODE tracking_area_identity_list_5gs_t::pack(asn1::bit_ref& bref)
|
||||||
// TODO proper packing
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 7) {
|
||||||
asn1::log_error(
|
asn1::log_error(
|
||||||
|
@ -1952,7 +1952,7 @@ SRSASN_CODE rejected_nssai_t::pack(asn1::bit_ref& bref)
|
||||||
// TODO proper packing
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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));
|
HANDLE_CODE(bref_length.pack(length, 8));
|
||||||
return SRSASN_SUCCESS;
|
return SRSASN_SUCCESS;
|
||||||
|
@ -1979,7 +1979,7 @@ SRSASN_CODE network_feature_support_5gs_t::pack(asn1::bit_ref& bref)
|
||||||
// TODO proper packing
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 1 || length > 3) {
|
||||||
asn1::log_error(
|
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));
|
HANDLE_CODE(bref.pack(psi_8, 1));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 2 || length > 32) {
|
||||||
asn1::log_error("Encoding Failed (PDU session reactivation result): Packed length (%d) is not in range of min: 2 "
|
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
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 2 || length > 512) {
|
||||||
asn1::log_error("Encoding Failed (PDU session reactivation result error cause): Packed length (%d) is not in range "
|
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
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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
|
// MIN 0 not check because auf uint underflow
|
||||||
if (length > 1712) {
|
if (length > 1712) {
|
||||||
|
@ -2170,7 +2170,7 @@ SRSASN_CODE service_area_list_t::pack(asn1::bit_ref& bref)
|
||||||
// TODO proper packing
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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));
|
HANDLE_CODE(bref_length.pack(length, 8));
|
||||||
return SRSASN_SUCCESS;
|
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));
|
HANDLE_CODE(bref.pack(timer_value, 8));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 1) {
|
||||||
asn1::log_error("Encoding Failed (GPRS timer 2): Packed length (%d) does not equal expected length 1", length);
|
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
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 3 || length > 48) {
|
||||||
asn1::log_error(
|
asn1::log_error(
|
||||||
|
@ -2270,7 +2270,7 @@ SRSASN_CODE extended_emergency_number_list_t::pack(asn1::bit_ref& bref)
|
||||||
// TODO proper packing
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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
|
// MAX 65535 not check because auf uint overflow
|
||||||
if (length < 4) {
|
if (length < 4) {
|
||||||
|
@ -2310,7 +2310,7 @@ SRSASN_CODE sor_transparent_container_t::pack(asn1::bit_ref& bref)
|
||||||
// TODO proper packing
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 17) {
|
||||||
asn1::log_error("Encoding Failed (SOR transparent container): Packed length (%d) is not in range of min: 17 bytes",
|
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()));
|
HANDLE_CODE(bref.pack_bytes(eap_message.data(), eap_message.size()));
|
||||||
bref.align_bytes_zero();
|
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) {
|
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",
|
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
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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));
|
HANDLE_CODE(bref_length.pack(length, 16));
|
||||||
return SRSASN_SUCCESS;
|
return SRSASN_SUCCESS;
|
||||||
|
@ -2470,7 +2470,7 @@ SRSASN_CODE ciphering_key_data_t::pack(asn1::bit_ref& bref)
|
||||||
// TODO proper packing
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 31 || length > 2672) {
|
||||||
asn1::log_error(
|
asn1::log_error(
|
||||||
|
@ -2509,7 +2509,7 @@ SRSASN_CODE cag_information_list_t::pack(asn1::bit_ref& bref)
|
||||||
// TODO proper packing
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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));
|
HANDLE_CODE(bref_length.pack(length, 16));
|
||||||
return SRSASN_SUCCESS;
|
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));
|
HANDLE_CODE(bref.pack(truncated_amf__pointer_value, 4));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 1) {
|
||||||
asn1::log_error(
|
asn1::log_error(
|
||||||
|
@ -2665,7 +2665,7 @@ SRSASN_CODE network_name_t::pack(asn1::bit_ref& bref)
|
||||||
// TODO proper packing
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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));
|
HANDLE_CODE(bref_length.pack(length, 8));
|
||||||
return SRSASN_SUCCESS;
|
return SRSASN_SUCCESS;
|
||||||
|
@ -2734,7 +2734,7 @@ SRSASN_CODE daylight_saving_time_t::pack(asn1::bit_ref& bref)
|
||||||
HANDLE_CODE(value.pack(bref));
|
HANDLE_CODE(value.pack(bref));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 1) {
|
||||||
asn1::log_error("Encoding Failed (Daylight saving time): Packed length (%d) does not equal expected 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()));
|
HANDLE_CODE(bref.pack_bytes(abba_contents.data(), abba_contents.size()));
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 2) {
|
||||||
asn1::log_error("Encoding Failed (ABBA): Packed length (%d) is not in range of min: 2 bytes", length);
|
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()));
|
HANDLE_CODE(bref.pack_bytes(autn.data(), autn.size()));
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 16) {
|
||||||
asn1::log_error(
|
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()));
|
HANDLE_CODE(bref.pack_bytes(res.data(), res.size()));
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 16) {
|
||||||
asn1::log_error(
|
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()));
|
HANDLE_CODE(bref.pack_bytes(auth_failure.data(), auth_failure.size()));
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 14) {
|
||||||
asn1::log_error(
|
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));
|
HANDLE_CODE(bref.pack(hdp, 1));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 1) {
|
||||||
asn1::log_error(
|
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));
|
HANDLE_CODE(bref.pack(gea7, 1));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 2 || length > 5) {
|
||||||
asn1::log_error(
|
asn1::log_error(
|
||||||
|
@ -3305,7 +3305,7 @@ SRSASN_CODE s_nssai_t::pack(asn1::bit_ref& bref)
|
||||||
}
|
}
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
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);
|
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()));
|
HANDLE_CODE(bref.pack_bytes(dnn_value.data(), dnn_value.size()));
|
||||||
bref.align_bytes_zero();
|
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) {
|
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);
|
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()));
|
HANDLE_CODE(bref.pack_bytes(additional_information_value.data(), additional_information_value.size()));
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 1) {
|
||||||
asn1::log_error("Encoding Failed (Additional information): Packed length (%d) is not in range of min: 1 bytes",
|
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
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
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",
|
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()));
|
HANDLE_CODE(bref.pack_bytes(dn_specific_identity.data(), dn_specific_identity.size()));
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 1 || length > 253) {
|
||||||
asn1::log_error(
|
asn1::log_error(
|
||||||
|
@ -3635,7 +3635,7 @@ SRSASN_CODE extended_protocol_configuration_options_t::pack(asn1::bit_ref& bref)
|
||||||
// TODO proper packing
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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
|
// MAX 65535 not check because auf uint overflow
|
||||||
if (length < 1) {
|
if (length < 1) {
|
||||||
|
@ -3677,7 +3677,7 @@ SRSASN_CODE ip_header_compression_configuration_t::pack(asn1::bit_ref& bref)
|
||||||
// TODO proper packing
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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
|
// MAX 255 not check because auf uint overflow
|
||||||
if (length < 3) {
|
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));
|
HANDLE_CODE(bref.pack_bytes(ds_tt__ethernet_port_mac_address_contents.data(), 6));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 6) {
|
||||||
asn1::log_error(
|
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));
|
HANDLE_CODE(bref.pack_bytes(ue_ds_tt_residence_time_contents.data(), 8));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 8) {
|
||||||
asn1::log_error("Encoding Failed (UE-DS-TT residence time): Packed length (%d) does not equal expected 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(
|
HANDLE_CODE(
|
||||||
bref.pack_bytes(port_management_information_container.data(), port_management_information_container.size()));
|
bref.pack_bytes(port_management_information_container.data(), port_management_information_container.size()));
|
||||||
bref.align_bytes_zero();
|
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
|
// MAX 65535 not check because auf uint overflow
|
||||||
if (length < 1) {
|
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));
|
HANDLE_CODE(cid__length.pack(bref));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 1) {
|
||||||
asn1::log_error("Encoding Failed (Ethernet header compression configuration): Packed length (%d) does not equal "
|
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();
|
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) {
|
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",
|
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));
|
HANDLE_CODE(bref.advance_bits(16));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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
|
// MAX 65535 not check because auf uint overflow
|
||||||
if (length < 4) {
|
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));
|
HANDLE_CODE(bref.pack(session_ambr_for_uplink, 16));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 6) {
|
||||||
asn1::log_error("Encoding Failed (Session-AMBR): Packed length (%d) does not equal expected length 6", length);
|
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
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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
|
// MAX 65535 not check because auf uint overflow
|
||||||
if (length < 4) {
|
if (length < 4) {
|
||||||
|
@ -4117,7 +4117,7 @@ SRSASN_CODE qo_s_flow_descriptions_t::pack(asn1::bit_ref& bref)
|
||||||
// TODO proper packing
|
// TODO proper packing
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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
|
// MAX 65535 not check because auf uint overflow
|
||||||
if (length < 3) {
|
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));
|
HANDLE_CODE(ept_s1.pack(bref));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length < 1 || length > 13) {
|
||||||
asn1::log_error(
|
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));
|
HANDLE_CODE(bref.pack(serving_plmn_rate_control_value, 16));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 2) {
|
||||||
asn1::log_error("Encoding Failed (Serving PLMN rate control): Packed length (%d) does not equal expected 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()));
|
HANDLE_CODE(bref.pack_bytes(nas_message_container.data(), nas_message_container.size()));
|
||||||
bref.align_bytes_zero();
|
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
|
// MIN 0 not check because auf uint underflow
|
||||||
// MAX 65535 not check because auf uint overflow
|
// 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));
|
HANDLE_CODE(bref.pack(ratc, 1));
|
||||||
|
|
||||||
bref.align_bytes_zero();
|
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) {
|
if (length != 1) {
|
||||||
asn1::log_error("Encoding Failed (Re-attempt indicator): Packed length (%d) does not equal expected 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.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.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_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.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_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();
|
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
|
time_prof.cc
|
||||||
version.c
|
version.c
|
||||||
zuc.cc
|
zuc.cc
|
||||||
s3g.cc
|
s3g.cc)
|
||||||
basic_vnf.cc)
|
|
||||||
|
|
||||||
# Avoid warnings caused by libmbedtls about deprecated functions
|
# Avoid warnings caused by libmbedtls about deprecated functions
|
||||||
set_source_files_properties(security.cc PROPERTIES COMPILE_FLAGS -Wno-deprecated-declarations)
|
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)
|
const srsran_tdd_config_nr_t& tdd_cfg)
|
||||||
{
|
{
|
||||||
// Generate as many entries as DL slots
|
// 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
|
// Set PDSCH to ACK timing delay to 4 or more
|
||||||
for (uint32_t n = 0; n < harq.nof_dl_data_to_ul_ack; n++) {
|
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.config_idx = 0;
|
||||||
prach.freq_offset = 2;
|
prach.freq_offset = 2;
|
||||||
prach.root_seq_idx = 0;
|
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)
|
phy_cfg_nr_default_t::phy_cfg_nr_default_t(const reference_cfg_t& reference_cfg)
|
||||||
|
@ -259,4 +260,4 @@ phy_cfg_nr_default_t::phy_cfg_nr_default_t(const reference_cfg_t& reference_cfg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace srsran
|
} // namespace srsran
|
||||||
|
|
|
@ -848,6 +848,13 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
|
||||||
|
|
||||||
// Demultiplex UCI only if necessary
|
// Demultiplex UCI only if necessary
|
||||||
if (q->uci_mux) {
|
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
|
// Demultiplex UL-SCH, change sign
|
||||||
int8_t* g_ulsch = (int8_t*)q->g_ulsch;
|
int8_t* g_ulsch = (int8_t*)q->g_ulsch;
|
||||||
for (uint32_t i = 0; i < q->G_ulsch; i++) {
|
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;
|
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
|
// Demultiplex CSI part 1
|
||||||
int8_t* g_csi1 = (int8_t*)q->g_csi1;
|
int8_t* g_csi1 = (int8_t*)q->g_csi1;
|
||||||
for (uint32_t i = 0; i < q->G_csi1; i++) {
|
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++) {
|
for (uint32_t i = 0; i < SRSRAN_MAX_TB; i++) {
|
||||||
pusch_cfg->grant.tb[i].nof_bits =
|
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;
|
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;
|
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
|
// - At least one positive SR
|
||||||
// - up to 2 HARQ-ACK
|
// - up to 2 HARQ-ACK
|
||||||
// - No CSI report
|
// - 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) {
|
uci_cfg->nof_csi == 0) {
|
||||||
uint32_t sr_resource_id = uci_cfg->pucch.sr_resource_id;
|
uint32_t sr_resource_id = uci_cfg->pucch.sr_resource_id;
|
||||||
if (sr_resource_id >= SRSRAN_PUCCH_MAX_NOF_SR_RESOURCES) {
|
if (sr_resource_id >= SRSRAN_PUCCH_MAX_NOF_SR_RESOURCES) {
|
||||||
|
|
|
@ -655,19 +655,10 @@ static int sch_nr_decode(srsran_sch_nr_t* q,
|
||||||
nof_iter_sum += n_iter_cb;
|
nof_iter_sum += n_iter_cb;
|
||||||
|
|
||||||
// Check if CB is all zeros
|
// Check if CB is all zeros
|
||||||
uint32_t cb_len = cfg.Kp - cfg.L_cb;
|
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);
|
tb->softbuffer.rx->cb_crc[r] = (ret != 0);
|
||||||
SCH_INFO_RX("CB %d/%d iter=%d CRC=%s all_zeros=%s",
|
SCH_INFO_RX("CB %d/%d iter=%d CRC=%s", r, cfg.C, n_iter_cb, tb->softbuffer.rx->cb_crc[r] ? "OK" : "KO");
|
||||||
r,
|
|
||||||
cfg.C,
|
|
||||||
n_iter_cb,
|
|
||||||
tb->softbuffer.rx->cb_crc[r] ? "OK" : "KO",
|
|
||||||
all_zeros ? "yes" : "no");
|
|
||||||
|
|
||||||
// CB Debug trace
|
// CB Debug trace
|
||||||
if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) {
|
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,
|
tb->cw_idx,
|
||||||
srsran_mod_string(tb->mod),
|
srsran_mod_string(tb->mod),
|
||||||
tb->tbs / 8,
|
tb->tbs / 8,
|
||||||
tb->R,
|
tb->R_prime,
|
||||||
tb->rv);
|
tb->rv);
|
||||||
|
|
||||||
if (res != NULL) {
|
if (res != NULL) {
|
||||||
|
|
|
@ -286,25 +286,47 @@ int main(int argc, char** argv)
|
||||||
goto clean_exit;
|
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);
|
uint32_t nof_re = srsran_ra_dl_nr_slot_nof_re(&pusch_cfg, &pusch_cfg.grant);
|
||||||
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) {
|
if (nof_re * pusch_cfg.grant.nof_layers > 0) {
|
||||||
mse = mse / (nof_re * pusch_cfg.grant.nof_layers);
|
float mse = 0.0f;
|
||||||
}
|
|
||||||
if (mse > 0.001) {
|
|
||||||
ERROR("MSE error (%f) is too high", mse);
|
|
||||||
for (uint32_t i = 0; i < pusch_cfg.grant.nof_layers; i++) {
|
for (uint32_t i = 0; i < pusch_cfg.grant.nof_layers; i++) {
|
||||||
printf("d_tx[%d]=", i);
|
for (uint32_t j = 0; j < nof_re; j++) {
|
||||||
srsran_vec_fprint_c(stdout, pusch_tx.d[i], nof_re);
|
mse += cabsf(pusch_tx.d[i][j] - pusch_rx.d[i][j]);
|
||||||
printf("d_rx[%d]=", i);
|
}
|
||||||
srsran_vec_fprint_c(stdout, pusch_rx.d[i], nof_re);
|
}
|
||||||
|
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++) {
|
||||||
|
printf("d_tx[%d]=", i);
|
||||||
|
srsran_vec_fprint_c(stdout, pusch_tx.d[i], nof_re);
|
||||||
|
printf("d_rx[%d]=", i);
|
||||||
|
srsran_vec_fprint_c(stdout, pusch_rx.d[i], nof_re);
|
||||||
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
goto clean_exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate UL-SCH CRC check
|
// Validate UL-SCH CRC check
|
||||||
|
|
|
@ -989,7 +989,16 @@ uint32_t srsran_uci_nr_total_bits(const srsran_uci_cfg_nr_t* uci_cfg)
|
||||||
return 0;
|
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)
|
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)
|
int srsran_rf_close(srsran_rf_t* rf)
|
||||||
{
|
{
|
||||||
// Stop gain thread
|
// Stop gain thread
|
||||||
|
pthread_mutex_lock(&rf->mutex);
|
||||||
if (rf->thread_gain_run) {
|
if (rf->thread_gain_run) {
|
||||||
pthread_mutex_lock(&rf->mutex);
|
|
||||||
rf->thread_gain_run = false;
|
rf->thread_gain_run = false;
|
||||||
pthread_mutex_unlock(&rf->mutex);
|
|
||||||
pthread_cond_signal(&rf->cond);
|
|
||||||
pthread_join(rf->thread_gain, NULL);
|
|
||||||
}
|
}
|
||||||
|
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);
|
return ((rf_dev_t*)rf->dev)->srsran_rf_close(rf->handler);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
#include "rf_helper.h"
|
#include "rf_helper.h"
|
||||||
#include "srsran/phy/utils/debug.h"
|
#include "srsran/phy/utils/debug.h"
|
||||||
|
#include "srsran/phy/utils/vector.h"
|
||||||
|
|
||||||
#include "rf_uhd_generic.h"
|
#include "rf_uhd_generic.h"
|
||||||
#include "rf_uhd_imp.h"
|
#include "rf_uhd_imp.h"
|
||||||
|
@ -197,10 +198,12 @@ void suppress_handler(const char* x)
|
||||||
// do nothing
|
// 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)
|
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) {
|
if (h->tx_state == RF_UHD_IMP_TX_STATE_BURST) {
|
||||||
h->tx_state = RF_UHD_IMP_TX_STATE_END_OF_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)
|
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) {
|
if (h->tx_state == RF_UHD_IMP_TX_STATE_BURST) {
|
||||||
h->tx_state = RF_UHD_IMP_TX_STATE_END_OF_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
|
// Set all pointers to zero buffer
|
||||||
for (auto& i : data) {
|
for (auto& i : data) {
|
||||||
i = zero_mem;
|
i = dummy_mem.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive until time out
|
// Receive until time out
|
||||||
uhd::rx_metadata_t md;
|
uhd::rx_metadata_t md;
|
||||||
do {
|
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);
|
log_rx_error(handler);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -958,7 +963,7 @@ static inline int rf_uhd_imp_end_burst(rf_uhd_handler_t* handler)
|
||||||
|
|
||||||
// Set buffer pointers
|
// Set buffer pointers
|
||||||
for (int i = 0; i < SRSRAN_MAX_CHANNELS; i++) {
|
for (int i = 0; i < SRSRAN_MAX_CHANNELS; i++) {
|
||||||
buffs_ptr[i] = zero_mem;
|
buffs_ptr[i] = zero_mem.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set metadata
|
// Set metadata
|
||||||
|
@ -1270,13 +1275,19 @@ int rf_uhd_recv_with_time_multi(void* h,
|
||||||
// Receive stream in multiple blocks
|
// Receive stream in multiple blocks
|
||||||
while (rxd_samples_total < nsamples and trials < RF_UHD_IMP_MAX_RX_TRIALS) {
|
while (rxd_samples_total < nsamples and trials < RF_UHD_IMP_MAX_RX_TRIALS) {
|
||||||
void* buffs_ptr[SRSRAN_MAX_CHANNELS] = {};
|
void* buffs_ptr[SRSRAN_MAX_CHANNELS] = {};
|
||||||
for (uint32_t i = 0; i < handler->nof_rx_channels; i++) {
|
|
||||||
cf_t* data_c = (cf_t*)data[i];
|
|
||||||
buffs_ptr[i] = &data_c[rxd_samples_total];
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t num_samps_left = nsamples - rxd_samples_total;
|
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;
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (handler->uhd->receive(buffs_ptr, num_rx_samples, md, 1.0, false, rxd_samples) != UHD_ERROR_NONE) {
|
if (handler->uhd->receive(buffs_ptr, num_rx_samples, md, 1.0, false, rxd_samples) != UHD_ERROR_NONE) {
|
||||||
log_rx_error(handler);
|
log_rx_error(handler);
|
||||||
|
@ -1388,9 +1399,9 @@ int rf_uhd_send_timed_multi(void* h,
|
||||||
cf_t* data_c[SRSRAN_MAX_CHANNELS] = {};
|
cf_t* data_c[SRSRAN_MAX_CHANNELS] = {};
|
||||||
for (uint32_t i = 0; i < SRSRAN_MAX_CHANNELS; i++) {
|
for (uint32_t i = 0; i < SRSRAN_MAX_CHANNELS; i++) {
|
||||||
if (i < handler->nof_tx_channels) {
|
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 {
|
} 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)
|
bool radio::get_metrics(rf_metrics_t* metrics)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(metrics_mutex);
|
||||||
*metrics = rf_metrics;
|
*metrics = rf_metrics;
|
||||||
rf_metrics = {};
|
rf_metrics = {};
|
||||||
return true;
|
return true;
|
||||||
|
@ -999,8 +1000,11 @@ void radio::handle_rf_msg(srsran_rf_error_t error)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (error.type == srsran_rf_error_t::SRSRAN_RF_ERROR_OVERFLOW) {
|
if (error.type == srsran_rf_error_t::SRSRAN_RF_ERROR_OVERFLOW) {
|
||||||
rf_metrics.rf_o++;
|
{
|
||||||
rf_metrics.rf_error = true;
|
std::lock_guard<std::mutex> lock(metrics_mutex);
|
||||||
|
rf_metrics.rf_o++;
|
||||||
|
rf_metrics.rf_error = true;
|
||||||
|
}
|
||||||
logger.info("Overflow");
|
logger.info("Overflow");
|
||||||
|
|
||||||
// inform PHY about overflow
|
// inform PHY about overflow
|
||||||
|
@ -1008,13 +1012,15 @@ void radio::handle_rf_msg(srsran_rf_error_t error)
|
||||||
phy->radio_overflow();
|
phy->radio_overflow();
|
||||||
}
|
}
|
||||||
} else if (error.type == srsran_rf_error_t::SRSRAN_RF_ERROR_UNDERFLOW) {
|
} 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_u++;
|
||||||
rf_metrics.rf_error = true;
|
rf_metrics.rf_error = true;
|
||||||
logger.info("Underflow");
|
|
||||||
} else if (error.type == srsran_rf_error_t::SRSRAN_RF_ERROR_LATE) {
|
} 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_l++;
|
||||||
rf_metrics.rf_error = true;
|
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) {
|
} else if (error.type == srsran_rf_error_t::SRSRAN_RF_ERROR_RX) {
|
||||||
logger.error("Fatal radio error occured.");
|
logger.error("Fatal radio error occured.");
|
||||||
phy->radio_failure();
|
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));
|
std::tm current_time = fmt::gmtime(std::chrono::high_resolution_clock::to_time_t(metadata.tp));
|
||||||
auto us_fraction =
|
auto us_fraction =
|
||||||
std::chrono::duration_cast<std::chrono::microseconds>(metadata.tp.time_since_epoch()).count() % 1000000u;
|
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.
|
// Format optional fields if present.
|
||||||
if (!metadata.log_name.empty()) {
|
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 "srsran/srslog/srslog.h"
|
||||||
#include "formatters/json_formatter.h"
|
#include "formatters/json_formatter.h"
|
||||||
#include "sinks/file_sink.h"
|
#include "sinks/file_sink.h"
|
||||||
|
#include "sinks/syslog_sink.h"
|
||||||
#include "srslog_instance.h"
|
#include "srslog_instance.h"
|
||||||
|
|
||||||
using namespace srslog;
|
using namespace srslog;
|
||||||
|
@ -174,6 +175,25 @@ sink& srslog::fetch_file_sink(const std::string& path, size_t max_size, std::uni
|
||||||
return *s;
|
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)
|
bool srslog::install_custom_sink(const std::string& id, std::unique_ptr<sink> s)
|
||||||
{
|
{
|
||||||
assert(!id.empty() && "Empty path string");
|
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})
|
target_link_libraries(task_scheduler_test srsran_common ${ATOMIC_LIBS})
|
||||||
add_test(task_scheduler_test task_scheduler_test)
|
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)
|
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})
|
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)
|
target_link_libraries(file_sink_test srslog)
|
||||||
add_test(file_sink_test file_sink_test)
|
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)
|
add_executable(file_utils_test file_utils_test.cpp)
|
||||||
target_include_directories(file_utils_test PUBLIC ../../)
|
target_include_directories(file_utils_test PUBLIC ../../)
|
||||||
target_link_libraries(file_utils_test srslog)
|
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;
|
fmt::dynamic_format_arg_store<fmt::printf_context> store;
|
||||||
text_formatter{}.format(build_log_entry_metadata(&store), buffer);
|
text_formatter{}.format(build_log_entry_metadata(&store), buffer);
|
||||||
std::string result = fmt::to_string(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);
|
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;
|
fmt::memory_buffer buffer;
|
||||||
text_formatter{}.format(std::move(entry), buffer);
|
text_formatter{}.format(std::move(entry), buffer);
|
||||||
std::string result = fmt::to_string(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);
|
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;
|
fmt::memory_buffer buffer;
|
||||||
text_formatter{}.format(std::move(entry), buffer);
|
text_formatter{}.format(std::move(entry), buffer);
|
||||||
std::string result = fmt::to_string(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);
|
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;
|
fmt::memory_buffer buffer;
|
||||||
text_formatter{}.format(std::move(entry), buffer);
|
text_formatter{}.format(std::move(entry), buffer);
|
||||||
std::string result = fmt::to_string(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);
|
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;
|
fmt::memory_buffer buffer;
|
||||||
text_formatter{}.format(std::move(entry), buffer);
|
text_formatter{}.format(std::move(entry), buffer);
|
||||||
std::string result = fmt::to_string(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"
|
" 0000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"
|
||||||
" 0010: 10 11 12 13\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;
|
fmt::memory_buffer buffer;
|
||||||
text_formatter{}.format_ctx(ctx, std::move(entry), buffer);
|
text_formatter{}.format_ctx(ctx, std::move(entry), buffer);
|
||||||
std::string result = fmt::to_string(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"
|
"\"Complex Context\"\n"
|
||||||
" > List: sector_list\n"
|
" > List: sector_list\n"
|
||||||
" > Set: sector_metrics\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;
|
fmt::memory_buffer buffer;
|
||||||
text_formatter{}.format_ctx(ctx, std::move(entry), buffer);
|
text_formatter{}.format_ctx(ctx, std::move(entry), buffer);
|
||||||
std::string result = fmt::to_string(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, "
|
"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 "
|
"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 "
|
"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
|
# Default configuration files
|
||||||
########################################################################
|
########################################################################
|
||||||
install(FILES enb.conf.example DESTINATION ${DATA_DIR})
|
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 rr.conf.example DESTINATION ${DATA_DIR})
|
||||||
install(FILES sib.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
|
# sib_config: SIB1, SIB2 and SIB3 configuration file
|
||||||
# note: when enabling mbms, use the sib.conf.mbsfn configuration file which includes SIB13
|
# note: when enabling mbms, use the sib.conf.mbsfn configuration file which includes SIB13
|
||||||
# rr_config: Radio Resources configuration file
|
# rr_config: Radio Resources configuration file
|
||||||
# drb_config: DRB configuration file
|
# rb_config: SRB/DRB configuration file
|
||||||
#####################################################################
|
#####################################################################
|
||||||
[enb_files]
|
[enb_files]
|
||||||
sib_config = sib.conf
|
sib_config = sib.conf
|
||||||
rr_config = rr.conf
|
rr_config = rr.conf
|
||||||
drb_config = drb.conf
|
rb_config = rb.conf
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
# RF configuration
|
# 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_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
|
# 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
|
# max_sib_coderate: Upper bound on SIB and RAR grants coderate
|
||||||
|
# pdcch_cqi_offset: CQI offset in derivation of PDCCH aggregation level
|
||||||
#
|
#
|
||||||
#####################################################################
|
#####################################################################
|
||||||
[scheduler]
|
[scheduler]
|
||||||
|
@ -204,6 +205,7 @@ enable = false
|
||||||
#init_ul_snr_value=5
|
#init_ul_snr_value=5
|
||||||
#init_dl_cqi=5
|
#init_dl_cqi=5
|
||||||
#max_sib_coderate=0.3
|
#max_sib_coderate=0.3
|
||||||
|
#pdcch_cqi_offset=0
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
# eMBMS configuration options
|
# eMBMS configuration options
|
||||||
|
@ -324,6 +326,7 @@ enable = false
|
||||||
# tracing_enable: Write source code tracing information to a file.
|
# tracing_enable: Write source code tracing information to a file.
|
||||||
# tracing_filename: File path to use for tracing information.
|
# tracing_filename: File path to use for tracing information.
|
||||||
# tracing_buffcapacity: Maximum capacity in bytes the tracing framework can store.
|
# 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.
|
# pregenerate_signals: Pregenerate uplink signals after attach. Improves CPU performance.
|
||||||
# tx_amplitude: Transmit amplitude factor (set 0-1 to reduce PAPR)
|
# 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).
|
# 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).
|
# 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_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
|
#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]
|
[expert]
|
||||||
|
@ -351,6 +356,7 @@ enable = false
|
||||||
#tracing_enable = true
|
#tracing_enable = true
|
||||||
#tracing_filename = /tmp/enb_tracing.log
|
#tracing_filename = /tmp/enb_tracing.log
|
||||||
#tracing_buffcapacity = 1000000
|
#tracing_buffcapacity = 1000000
|
||||||
|
#stdout_ts_enable = false
|
||||||
#pregenerate_signals = false
|
#pregenerate_signals = false
|
||||||
#tx_amplitude = 0.6
|
#tx_amplitude = 0.6
|
||||||
#rrc_inactivity_timer = 30000
|
#rrc_inactivity_timer = 30000
|
||||||
|
@ -365,3 +371,5 @@ enable = false
|
||||||
#extended_cp = false
|
#extended_cp = false
|
||||||
#ts1_reloc_prep_timeout = 10000
|
#ts1_reloc_prep_timeout = 10000
|
||||||
#ts1_reloc_overall_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 {
|
struct enb_files_t {
|
||||||
std::string sib_config;
|
std::string sib_config;
|
||||||
std::string rr_config;
|
std::string rr_config;
|
||||||
std::string drb_config;
|
std::string rb_config;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct log_args_t {
|
struct log_args_t {
|
||||||
|
|
|
@ -41,12 +41,11 @@ class slot_worker final : public srsran::thread_pool::worker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct args_t {
|
struct args_t {
|
||||||
uint32_t cell_index = 0;
|
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_tx_ports = 1;
|
||||||
uint32_t nof_rx_ports = 1;
|
uint32_t nof_rx_ports = 1;
|
||||||
uint32_t pusch_max_nof_iter = 10;
|
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);
|
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 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 */
|
/* Functions used by main PHY thread */
|
||||||
cf_t* get_buffer_rx(uint32_t antenna_idx);
|
cf_t* get_buffer_rx(uint32_t antenna_idx);
|
||||||
cf_t* get_buffer_tx(uint32_t antenna_idx);
|
cf_t* get_buffer_tx(uint32_t antenna_idx);
|
||||||
|
|
|
@ -24,7 +24,9 @@
|
||||||
|
|
||||||
#include "slot_worker.h"
|
#include "slot_worker.h"
|
||||||
#include "srsenb/hdr/phy/phy_interfaces.h"
|
#include "srsenb/hdr/phy/phy_interfaces.h"
|
||||||
|
#include "srsenb/hdr/phy/prach_worker.h"
|
||||||
#include "srsran/common/thread_pool.h"
|
#include "srsran/common/thread_pool.h"
|
||||||
|
#include "srsran/interfaces/enb_mac_interfaces.h"
|
||||||
#include "srsran/interfaces/gnb_interfaces.h"
|
#include "srsran/interfaces/gnb_interfaces.h"
|
||||||
|
|
||||||
namespace srsenb {
|
namespace srsenb {
|
||||||
|
@ -32,20 +34,71 @@ namespace nr {
|
||||||
|
|
||||||
class worker_pool
|
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;
|
srsran::phy_common_interface& common;
|
||||||
stack_interface_phy_nr& stack;
|
stack_interface_phy_nr& stack;
|
||||||
srslog::sink& log_sink;
|
srslog::sink& log_sink;
|
||||||
srsran::thread_pool pool;
|
srsran::thread_pool pool;
|
||||||
std::vector<std::unique_ptr<slot_worker> > workers;
|
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:
|
public:
|
||||||
struct args_t {
|
struct args_t {
|
||||||
uint32_t nof_phy_threads = 3;
|
uint32_t nof_phy_threads = 3;
|
||||||
uint32_t prio = 52;
|
uint32_t prio = 52;
|
||||||
std::string log_level = "info";
|
uint32_t pusch_max_nof_iter = 10;
|
||||||
uint32_t log_hex_limit = 64;
|
srsran::phy_log_args_t log = {};
|
||||||
std::string log_id_preamble = "";
|
|
||||||
uint32_t pusch_max_nof_iter = 10;
|
|
||||||
};
|
};
|
||||||
slot_worker* operator[](std::size_t pos) { return workers.at(pos).get(); }
|
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);
|
slot_worker* wait_worker_id(uint32_t id);
|
||||||
void start_worker(slot_worker* w);
|
void start_worker(slot_worker* w);
|
||||||
void stop();
|
void stop();
|
||||||
|
int set_common_cfg(const phy_interface_rrc_nr::common_cfg_t& common_cfg);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace nr
|
} // 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 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 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;
|
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:
|
private:
|
||||||
void run_thread() final;
|
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 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 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;
|
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:
|
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
|
// PDU processing
|
||||||
int handle_pdu(srsran::unique_byte_buffer_t pdu);
|
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
|
#ifndef SRSRAN_SCHED_NR_H
|
||||||
#define 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_interface.h"
|
||||||
#include "sched_nr_ue.h"
|
#include "sched_nr_ue.h"
|
||||||
#include "srsran/adt/pool/cached_alloc.h"
|
#include "srsran/adt/pool/cached_alloc.h"
|
||||||
|
@ -36,9 +36,11 @@ namespace srsenb {
|
||||||
|
|
||||||
namespace sched_nr_impl {
|
namespace sched_nr_impl {
|
||||||
class sched_worker_manager;
|
class sched_worker_manager;
|
||||||
}
|
class serv_cell_ctxt;
|
||||||
|
} // namespace sched_nr_impl
|
||||||
|
|
||||||
class ue_event_manager;
|
class ue_event_manager;
|
||||||
|
class sched_result_manager;
|
||||||
|
|
||||||
class sched_nr final : public sched_nr_interface
|
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;
|
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 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 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;
|
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:
|
private:
|
||||||
|
int generate_slot_result(tti_point pdcch_tti, uint32_t cc);
|
||||||
void ue_cfg_impl(uint16_t rnti, const ue_cfg_t& cfg);
|
void ue_cfg_impl(uint16_t rnti, const ue_cfg_t& cfg);
|
||||||
|
|
||||||
// args
|
// args
|
||||||
sched_nr_impl::sched_params cfg;
|
sched_nr_impl::sched_params cfg;
|
||||||
|
srslog::basic_logger& logger;
|
||||||
|
|
||||||
using sched_worker_manager = sched_nr_impl::sched_worker_manager;
|
using sched_worker_manager = sched_nr_impl::sched_worker_manager;
|
||||||
std::unique_ptr<sched_worker_manager> sched_workers;
|
std::unique_ptr<sched_worker_manager> sched_workers;
|
||||||
|
@ -67,8 +71,14 @@ private:
|
||||||
std::mutex ue_db_mutex;
|
std::mutex ue_db_mutex;
|
||||||
ue_map_t ue_db;
|
ue_map_t ue_db;
|
||||||
|
|
||||||
// management of PHY UE feedback
|
// management of UE feedback
|
||||||
std::unique_ptr<ue_event_manager> pending_events;
|
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
|
} // 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
|
#ifndef SRSRAN_SCHED_NR_HARQ_H
|
||||||
#define 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 "srsran/common/tti_point.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
@ -40,19 +41,25 @@ public:
|
||||||
}
|
}
|
||||||
bool empty(uint32_t tb_idx) const { return not tb[tb_idx].active; }
|
bool empty(uint32_t tb_idx) const { return not tb[tb_idx].active; }
|
||||||
bool has_pending_retx(tti_point tti_rx) const { return not empty() and not tb[0].ack_state and tti_ack <= tti_rx; }
|
bool has_pending_retx(tti_point tti_rx) const { return not empty() and not tb[0].ack_state and tti_ack <= tti_rx; }
|
||||||
uint32_t nof_retx() const { return tb[0].n_rtx; }
|
uint32_t nof_retx() const { return tb[0].n_rtx; }
|
||||||
uint32_t max_nof_retx() const { return max_retx; }
|
uint32_t max_nof_retx() const { return max_retx; }
|
||||||
uint32_t tbs() const { return tb[0].tbs; }
|
uint32_t tbs() const { return tb[0].tbs; }
|
||||||
uint32_t ndi() const { return tb[0].ndi; }
|
uint32_t ndi() const { return tb[0].ndi; }
|
||||||
uint32_t mcs() const { return tb[0].mcs; }
|
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);
|
bool ack_info(uint32_t tb_idx, bool ack);
|
||||||
|
|
||||||
void new_tti(tti_point tti_rx);
|
void new_tti(tti_point tti_rx);
|
||||||
void reset();
|
void reset();
|
||||||
bool
|
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);
|
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 rbgmask_t& rbgmask, int* mcs, int* tbs);
|
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;
|
const uint32_t pid;
|
||||||
|
|
||||||
|
@ -69,27 +76,59 @@ private:
|
||||||
uint32_t max_retx = 1;
|
uint32_t max_retx = 1;
|
||||||
tti_point tti_tx;
|
tti_point tti_tx;
|
||||||
tti_point tti_ack;
|
tti_point tti_ack;
|
||||||
rbgmask_t rbgmask;
|
prb_grant prbs_;
|
||||||
std::array<tb_t, SCHED_NR_MAX_TB> tb;
|
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
|
class harq_entity
|
||||||
{
|
{
|
||||||
public:
|
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 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); }
|
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()
|
harq_proc* find_pending_ul_retx()
|
||||||
{
|
{
|
||||||
return find_ul([this](const harq_proc& h) { return h.has_pending_retx(tti_rx); });
|
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(); });
|
return find_dl([](const harq_proc& h) { return h.empty(); });
|
||||||
}
|
}
|
||||||
|
@ -100,7 +139,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename Predicate>
|
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);
|
auto it = std::find_if(dl_harqs.begin(), dl_harqs.end(), p);
|
||||||
return (it == dl_harqs.end()) ? nullptr : &(*it);
|
return (it == dl_harqs.end()) ? nullptr : &(*it);
|
||||||
|
@ -112,9 +151,9 @@ private:
|
||||||
return (it == ul_harqs.end()) ? nullptr : &(*it);
|
return (it == ul_harqs.end()) ? nullptr : &(*it);
|
||||||
}
|
}
|
||||||
|
|
||||||
tti_point tti_rx;
|
tti_point tti_rx;
|
||||||
std::vector<harq_proc> dl_harqs;
|
std::vector<dl_harq_proc> dl_harqs;
|
||||||
std::vector<harq_proc> ul_harqs;
|
std::vector<ul_harq_proc> ul_harqs;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sched_nr_impl
|
} // 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_bitset.h"
|
||||||
#include "srsran/adt/bounded_vector.h"
|
#include "srsran/adt/bounded_vector.h"
|
||||||
|
#include "srsran/adt/optional.h"
|
||||||
#include "srsran/adt/span.h"
|
#include "srsran/adt/span.h"
|
||||||
#include "srsran/common/phy_cfg_nr.h"
|
#include "srsran/common/phy_cfg_nr.h"
|
||||||
#include "srsran/common/tti_point.h"
|
#include "srsran/common/tti_point.h"
|
||||||
|
@ -34,18 +35,15 @@ namespace srsenb {
|
||||||
|
|
||||||
const static size_t SCHED_NR_MAX_CARRIERS = 4;
|
const static size_t SCHED_NR_MAX_CARRIERS = 4;
|
||||||
const static uint16_t SCHED_NR_INVALID_RNTI = 0;
|
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 = 18;
|
||||||
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_TB = 1;
|
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_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
|
class sched_nr_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using pdcch_bitmap = srsran::bounded_bitset<SCHED_NR_MAX_NOF_RBGS, true>;
|
static const size_t MAX_GRANTS = mac_interface_phy_nr::MAX_GRANTS;
|
||||||
using rbg_bitmap = srsran::bounded_bitset<SCHED_NR_MAX_NOF_RBGS, true>;
|
|
||||||
|
|
||||||
///// Configuration /////
|
///// Configuration /////
|
||||||
|
|
||||||
|
@ -53,21 +51,25 @@ public:
|
||||||
uint8_t k0 = 0; // 0..32
|
uint8_t k0 = 0; // 0..32
|
||||||
uint8_t k1 = 4; // 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 {
|
struct pusch_td_res_alloc {
|
||||||
uint8_t k2 = 4; // 0..32
|
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 {
|
struct bwp_cfg_t {
|
||||||
uint32_t start_rb = 0;
|
uint32_t start_rb = 0;
|
||||||
uint32_t rb_width = 100;
|
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 {
|
struct cell_cfg_t {
|
||||||
uint32_t nof_prb = 100;
|
srsran_carrier_nr_t carrier = {};
|
||||||
uint32_t nof_rbg = 25;
|
srsran_tdd_config_nr_t tdd = {};
|
||||||
srsran::bounded_vector<bwp_cfg_t, SCHED_NR_MAX_BWP_PER_CELL> bwps{1};
|
srsran::bounded_vector<bwp_cfg_t, SCHED_NR_MAX_BWP_PER_CELL> bwps{1}; // idx0 for BWP-common
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sched_cfg_t {
|
struct sched_cfg_t {
|
||||||
|
@ -75,9 +77,8 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ue_cc_cfg_t {
|
struct ue_cc_cfg_t {
|
||||||
bool active = false;
|
bool active = false;
|
||||||
pdsch_td_res_alloc_list pdsch_res_list{1};
|
uint32_t cc = 0;
|
||||||
pusch_td_res_alloc_list pusch_res_list{1};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ue_cfg_t {
|
struct ue_cfg_t {
|
||||||
|
@ -86,47 +87,26 @@ public:
|
||||||
srsran::phy_cfg_nr_t phy_cfg = {};
|
srsran::phy_cfg_nr_t phy_cfg = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
////// RACH //////
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
///// Sched Result /////
|
///// Sched Result /////
|
||||||
|
|
||||||
const static int MAX_GRANTS = 64;
|
using dl_sched_t = mac_interface_phy_nr::dl_sched_t;
|
||||||
|
using ul_sched_t = mac_interface_phy_nr::ul_sched_t;
|
||||||
|
|
||||||
using pdcch_dl_t = mac_interface_phy_nr::pdcch_dl_t;
|
virtual ~sched_nr_interface() = default;
|
||||||
using pdcch_ul_t = mac_interface_phy_nr::pdcch_ul_t;
|
virtual int cell_cfg(srsran::const_span<sched_nr_interface::cell_cfg_t> ue_cfg) = 0;
|
||||||
using pdcch_dl_list_t = srsran::bounded_vector<pdcch_dl_t, MAX_GRANTS>;
|
virtual void ue_cfg(uint16_t rnti, const ue_cfg_t& ue_cfg) = 0;
|
||||||
using pdcch_ul_list_t = srsran::bounded_vector<pdcch_ul_t, MAX_GRANTS>;
|
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;
|
||||||
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>;
|
|
||||||
|
|
||||||
struct dl_tti_request_t {
|
|
||||||
tti_point pdsch_tti;
|
|
||||||
pdcch_dl_list_t pdcchs;
|
|
||||||
pdsch_list_t pdschs;
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct tti_request_t {
|
|
||||||
dl_tti_request_t dl_res;
|
|
||||||
ul_tti_request_t ul_res;
|
|
||||||
};
|
|
||||||
|
|
||||||
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 void dl_ack_info(uint16_t rnti, uint32_t cc, uint32_t pid, uint32_t tb_idx, bool ack) = 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;
|
virtual void ul_sr_info(tti_point, uint16_t rnti) = 0;
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#ifndef SRSRAN_SCHED_NR_PDCCH_H
|
#ifndef SRSRAN_SCHED_NR_PDCCH_H
|
||||||
#define 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_bitset.h"
|
||||||
#include "srsran/adt/bounded_vector.h"
|
#include "srsran/adt/bounded_vector.h"
|
||||||
#include "srsran/phy/common/phy_common_nr.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>;
|
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;
|
class slot_ue;
|
||||||
|
|
||||||
using pdcch_dl_t = sched_nr_interface::pdcch_dl_t;
|
using bwp_cfg_t = sched_nr_interface::bwp_cfg_t;
|
||||||
using pdcch_dl_list_t = sched_nr_interface::pdcch_dl_list_t;
|
using pdcch_dl_t = mac_interface_phy_nr::pdcch_dl_t;
|
||||||
using pdcch_ul_t = sched_nr_interface::pdcch_ul_t;
|
using pdcch_ul_t = mac_interface_phy_nr::pdcch_ul_t;
|
||||||
using pdcch_ul_list_t = sched_nr_interface::pdcch_ul_list_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
|
class coreset_region
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
coreset_region(uint32_t bwp_id_,
|
coreset_region(const bwp_params& bwp_cfg_,
|
||||||
uint32_t slot_idx,
|
uint32_t coreset_id_,
|
||||||
uint32_t nof_td_symbols,
|
uint32_t slot_idx,
|
||||||
uint32_t nof_freq_resources,
|
pdcch_dl_list_t& pdcch_dl_list,
|
||||||
pdcch_dl_list_t& pdcch_list);
|
pdcch_ul_list_t& pdcch_ul_list);
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,31 +61,32 @@ public:
|
||||||
* @param user UE object or null in case of broadcast/RAR/paging allocation
|
* @param user UE object or null in case of broadcast/RAR/paging allocation
|
||||||
* @return if the allocation was successful
|
* @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();
|
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 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(); }
|
size_t nof_allocs() const { return dfs_tree.size(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t bwp_id;
|
const srsran_coreset_t* coreset_cfg;
|
||||||
uint32_t slot_idx;
|
uint32_t coreset_id;
|
||||||
uint32_t nof_symbols;
|
uint32_t slot_idx;
|
||||||
uint32_t nof_freq_res;
|
uint32_t nof_freq_res = 0;
|
||||||
|
|
||||||
// List of PDCCH grants
|
// List of PDCCH grants
|
||||||
struct alloc_record {
|
struct alloc_record {
|
||||||
uint32_t coreset_id;
|
|
||||||
uint32_t aggr_idx;
|
uint32_t aggr_idx;
|
||||||
|
uint32_t ss_id;
|
||||||
uint32_t idx;
|
uint32_t idx;
|
||||||
pdcch_grant_type_t alloc_type;
|
pdcch_grant_type_t alloc_type;
|
||||||
slot_ue* ue;
|
slot_ue* ue;
|
||||||
};
|
};
|
||||||
srsran::bounded_vector<alloc_record, MAX_GRANTS> dci_list;
|
srsran::bounded_vector<alloc_record, MAX_GRANTS> dci_list;
|
||||||
pdcch_dl_list_t& pdcch_dl_list;
|
pdcch_dl_list_t& pdcch_dl_list;
|
||||||
|
pdcch_ul_list_t& pdcch_ul_list;
|
||||||
|
|
||||||
// DFS decision tree of PDCCH grants
|
// DFS decision tree of PDCCH grants
|
||||||
struct tree_node {
|
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 "../sched_common.h"
|
||||||
#include "lib/include/srsran/adt/circular_array.h"
|
#include "lib/include/srsran/adt/circular_array.h"
|
||||||
|
#include "sched_nr_helpers.h"
|
||||||
#include "sched_nr_interface.h"
|
#include "sched_nr_interface.h"
|
||||||
#include "sched_nr_pdcch.h"
|
#include "sched_nr_pdcch.h"
|
||||||
#include "sched_nr_ue.h"
|
#include "sched_nr_ue.h"
|
||||||
|
@ -31,71 +32,76 @@
|
||||||
namespace srsenb {
|
namespace srsenb {
|
||||||
namespace sched_nr_impl {
|
namespace sched_nr_impl {
|
||||||
|
|
||||||
using pdsch_bitmap = srsran::bounded_bitset<25, true>;
|
struct pending_rar_t;
|
||||||
using pusch_bitmap = srsran::bounded_bitset<25, true>;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
struct pucch_t {};
|
|
||||||
|
|
||||||
const static size_t MAX_CORESET_PER_BWP = 3;
|
const static size_t MAX_CORESET_PER_BWP = 3;
|
||||||
using slot_coreset_list = srsran::bounded_vector<coreset_region, MAX_CORESET_PER_BWP>;
|
using slot_coreset_list = std::array<srsran::optional<coreset_region>, MAX_CORESET_PER_BWP>;
|
||||||
|
|
||||||
|
using pdsch_t = mac_interface_phy_nr::pdsch_t;
|
||||||
|
using pdsch_list_t = srsran::bounded_vector<pdsch_t, MAX_GRANTS>;
|
||||||
|
|
||||||
|
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 {
|
struct bwp_slot_grid {
|
||||||
pdcch_dl_list_t pdcch_dl_list;
|
uint32_t slot_idx;
|
||||||
pdcch_ul_list_t pdcch_ul_list;
|
const bwp_params* cfg;
|
||||||
slot_coreset_list coresets;
|
|
||||||
pdsch_bitmap dl_rbgs;
|
bool is_dl, is_ul;
|
||||||
pdsch_list_t pdsch_grants;
|
bwp_rb_bitmap dl_prbs;
|
||||||
pusch_bitmap ul_rbgs;
|
bwp_rb_bitmap ul_prbs;
|
||||||
pusch_list pusch_grants;
|
pdcch_dl_list_t dl_pdcchs;
|
||||||
srsran::bounded_vector<pucch_t, SCHED_NR_MAX_PDSCH_DATA> pucch_grants;
|
pdcch_ul_list_t ul_pdcchs;
|
||||||
|
pdsch_list_t pdschs;
|
||||||
|
slot_coreset_list coresets;
|
||||||
|
pusch_list_t puschs;
|
||||||
|
harq_ack_list_t pending_acks;
|
||||||
|
|
||||||
bwp_slot_grid() = default;
|
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();
|
void reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bwp_res_grid {
|
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()]; };
|
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.sf_idx()]; };
|
const bwp_slot_grid& operator[](tti_point tti) const { return slots[tti.to_uint() % slots.capacity()]; };
|
||||||
uint32_t id() const { return bwp_id; }
|
uint32_t id() const { return cfg->bwp_id; }
|
||||||
uint32_t nof_prbs() const { return cell_cfg->cell_cfg.nof_prb; }
|
uint32_t nof_prbs() const { return cfg->cfg.rb_width; }
|
||||||
|
|
||||||
|
const bwp_params* cfg = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t bwp_id;
|
|
||||||
const sched_cell_params* cell_cfg = nullptr;
|
|
||||||
|
|
||||||
srsran::bounded_vector<bwp_slot_grid, TTIMOD_SZ> slots;
|
srsran::bounded_vector<bwp_slot_grid, TTIMOD_SZ> slots;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cell_res_grid {
|
class bwp_slot_allocator
|
||||||
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
|
|
||||||
{
|
{
|
||||||
public:
|
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);
|
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:
|
private:
|
||||||
srslog::basic_logger& logger;
|
srslog::basic_logger& logger;
|
||||||
bwp_res_grid& bwp_grid;
|
bwp_res_grid& bwp_grid;
|
||||||
|
|
||||||
tti_point tti_rx;
|
tti_point pdcch_tti;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sched_nr_impl
|
} // namespace sched_nr_impl
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#ifndef SRSRAN_SCHED_NR_UE_H
|
#ifndef SRSRAN_SCHED_NR_UE_H
|
||||||
#define 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_harq.h"
|
||||||
#include "sched_nr_interface.h"
|
#include "sched_nr_interface.h"
|
||||||
#include "srsran/adt/circular_map.h"
|
#include "srsran/adt/circular_map.h"
|
||||||
|
@ -33,35 +33,6 @@ namespace srsenb {
|
||||||
|
|
||||||
namespace sched_nr_impl {
|
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 ue_carrier;
|
||||||
|
|
||||||
class slot_ue
|
class slot_ue
|
||||||
|
@ -79,19 +50,18 @@ public:
|
||||||
uint32_t cc = SCHED_NR_MAX_CARRIERS;
|
uint32_t cc = SCHED_NR_MAX_CARRIERS;
|
||||||
|
|
||||||
// UE parameters common to all sectors
|
// UE parameters common to all sectors
|
||||||
const ue_cfg_extended* cfg = nullptr;
|
const bwp_ue_cfg* cfg = nullptr;
|
||||||
bool pending_sr;
|
bool pending_sr;
|
||||||
|
|
||||||
// UE parameters that are sector specific
|
// UE parameters that are sector specific
|
||||||
const ue_cc_cfg_t* cc_cfg = nullptr;
|
const ue_cc_cfg_t* cc_cfg = nullptr;
|
||||||
uint32_t bwp_id;
|
|
||||||
tti_point pdcch_tti;
|
tti_point pdcch_tti;
|
||||||
tti_point pdsch_tti;
|
tti_point pdsch_tti;
|
||||||
tti_point pusch_tti;
|
tti_point pusch_tti;
|
||||||
tti_point uci_tti;
|
tti_point uci_tti;
|
||||||
uint32_t dl_cqi;
|
uint32_t dl_cqi;
|
||||||
uint32_t ul_cqi;
|
uint32_t ul_cqi;
|
||||||
harq_proc* h_dl = nullptr;
|
dl_harq_proc* h_dl = nullptr;
|
||||||
harq_proc* h_ul = nullptr;
|
harq_proc* h_ul = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -101,8 +71,8 @@ private:
|
||||||
class ue_carrier
|
class ue_carrier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ue_carrier(uint16_t rnti, uint32_t cc, const ue_cfg_t& 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_extended& cfg);
|
slot_ue try_reserve(tti_point pdcch_tti, const ue_cfg_t& cfg);
|
||||||
void push_feedback(srsran::move_callback<void(ue_carrier&)> callback);
|
void push_feedback(srsran::move_callback<void(ue_carrier&)> callback);
|
||||||
|
|
||||||
const uint16_t rnti;
|
const uint16_t rnti;
|
||||||
|
@ -115,7 +85,8 @@ public:
|
||||||
harq_entity harq_ent;
|
harq_entity harq_ent;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const ue_cfg_t* cfg = nullptr;
|
bwp_ue_cfg bwp_cfg;
|
||||||
|
const sched_cell_params& cell_params;
|
||||||
|
|
||||||
resource_guard busy;
|
resource_guard busy;
|
||||||
tti_point last_tti_rx;
|
tti_point last_tti_rx;
|
||||||
|
@ -126,7 +97,7 @@ private:
|
||||||
class ue
|
class ue
|
||||||
{
|
{
|
||||||
public:
|
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);
|
slot_ue try_reserve(tti_point tti_rx, uint32_t cc);
|
||||||
|
|
||||||
|
@ -137,12 +108,13 @@ public:
|
||||||
std::array<std::unique_ptr<ue_carrier>, SCHED_NR_MAX_CARRIERS> carriers;
|
std::array<std::unique_ptr<ue_carrier>, SCHED_NR_MAX_CARRIERS> carriers;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const uint16_t rnti;
|
const uint16_t rnti;
|
||||||
|
const sched_params& sched_cfg;
|
||||||
|
|
||||||
bool pending_sr = false;
|
bool pending_sr = false;
|
||||||
|
|
||||||
int current_idx = 0;
|
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>;
|
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
|
#ifndef SRSRAN_SCHED_NR_WORKER_H
|
||||||
#define 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_rb_grid.h"
|
||||||
#include "sched_nr_ue.h"
|
#include "sched_nr_ue.h"
|
||||||
#include "srsran/adt/circular_array.h"
|
#include "srsran/adt/circular_array.h"
|
||||||
|
@ -31,19 +32,17 @@
|
||||||
#include "srsran/adt/span.h"
|
#include "srsran/adt/span.h"
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <semaphore.h>
|
|
||||||
|
|
||||||
namespace srsenb {
|
namespace srsenb {
|
||||||
namespace sched_nr_impl {
|
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
|
class slot_cc_worker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit slot_cc_worker(const sched_cell_params& cell_params, cell_res_grid& phy_grid) :
|
explicit slot_cc_worker(serv_cell_ctxt& sched);
|
||||||
cfg(cell_params), res_grid(0, phy_grid)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void start(tti_point tti_rx_, ue_map_t& ue_db_);
|
void start(tti_point tti_rx_, ue_map_t& ue_db_);
|
||||||
void run();
|
void run();
|
||||||
|
@ -53,41 +52,50 @@ public:
|
||||||
private:
|
private:
|
||||||
void alloc_dl_ues();
|
void alloc_dl_ues();
|
||||||
void alloc_ul_ues();
|
void alloc_ul_ues();
|
||||||
|
void log_result() const;
|
||||||
|
|
||||||
const sched_cell_params& cfg;
|
const sched_cell_params& cfg;
|
||||||
|
serv_cell_ctxt& cell;
|
||||||
|
srslog::basic_logger& logger;
|
||||||
|
|
||||||
tti_point tti_rx;
|
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;
|
srsran::static_circular_map<uint16_t, slot_ue, SCHED_NR_MAX_USERS> slot_ues;
|
||||||
};
|
};
|
||||||
|
|
||||||
class sched_worker_manager
|
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:
|
public:
|
||||||
explicit sched_worker_manager(ue_map_t& ue_db_, const sched_params& cfg_);
|
explicit sched_worker_manager(ue_map_t& ue_db_, const sched_params& cfg_);
|
||||||
sched_worker_manager(const sched_worker_manager&) = delete;
|
sched_worker_manager(const sched_worker_manager&) = delete;
|
||||||
sched_worker_manager(sched_worker_manager&&) = delete;
|
sched_worker_manager(sched_worker_manager&&) = delete;
|
||||||
~sched_worker_manager();
|
~sched_worker_manager();
|
||||||
|
|
||||||
void reserve_workers(tti_point tti_rx);
|
void start_slot(tti_point tti_rx, srsran::move_callback<void()> process_feedback);
|
||||||
void start_tti(tti_point tti_rx);
|
bool run_slot(tti_point tti_rx, uint32_t cc);
|
||||||
bool run_tti(tti_point tti_rx, uint32_t cc, sched_nr_interface::tti_request_t& req);
|
void release_slot(tti_point tti_rx);
|
||||||
void end_tti(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:
|
private:
|
||||||
const sched_params& cfg;
|
const sched_params& cfg;
|
||||||
ue_map_t& ue_db;
|
ue_map_t& ue_db;
|
||||||
|
srslog::basic_logger& logger;
|
||||||
|
|
||||||
struct slot_worker_ctxt {
|
std::mutex ue_db_mutex;
|
||||||
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;
|
|
||||||
|
|
||||||
srsran::bounded_vector<cell_res_grid, SCHED_NR_MAX_CARRIERS> cell_grid_list;
|
std::vector<std::unique_ptr<slot_worker_ctxt> > slot_worker_ctxts;
|
||||||
|
|
||||||
|
srsran::bounded_vector<serv_cell_ctxt, SCHED_NR_MAX_CARRIERS> cell_grid_list;
|
||||||
|
|
||||||
slot_worker_ctxt& get_sf(tti_point tti_rx);
|
slot_worker_ctxt& get_sf(tti_point tti_rx);
|
||||||
};
|
};
|
||||||
|
|
|
@ -90,6 +90,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
srslog::basic_logger* logger;
|
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;
|
srsran::static_circular_map<uint32_t, srsran::unique_byte_buffer_t, SRSRAN_FDD_NOF_HARQ * 8> pdu_map;
|
||||||
};
|
};
|
||||||
|
@ -224,7 +225,6 @@ private:
|
||||||
|
|
||||||
// Mutexes
|
// Mutexes
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
std::mutex rx_buffers_mutex;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace srsenb
|
} // namespace srsenb
|
||||||
|
|
|
@ -40,12 +40,18 @@ struct rrc_cfg_sr_t {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rrc_cfg_qci_t {
|
struct rrc_cfg_qci_t {
|
||||||
bool configured = false;
|
bool configured = false;
|
||||||
|
int enb_dl_max_retx_thres = -1;
|
||||||
asn1::rrc::lc_ch_cfg_s::ul_specific_params_s_ lc_cfg;
|
asn1::rrc::lc_ch_cfg_s::ul_specific_params_s_ lc_cfg;
|
||||||
asn1::rrc::pdcp_cfg_s pdcp_cfg;
|
asn1::rrc::pdcp_cfg_s pdcp_cfg;
|
||||||
asn1::rrc::rlc_cfg_c rlc_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 {
|
struct rrc_cfg_t {
|
||||||
uint32_t enb_id; ///< Required to pack SIB1
|
uint32_t enb_id; ///< Required to pack SIB1
|
||||||
// Per eNB SIBs
|
// Per eNB SIBs
|
||||||
|
@ -71,6 +77,8 @@ struct rrc_cfg_t {
|
||||||
uint32_t max_mac_dl_kos;
|
uint32_t max_mac_dl_kos;
|
||||||
uint32_t max_mac_ul_kos;
|
uint32_t max_mac_ul_kos;
|
||||||
uint32_t rlf_release_timer_ms;
|
uint32_t rlf_release_timer_ms;
|
||||||
|
srb_cfg_t srb1_cfg;
|
||||||
|
srb_cfg_t srb2_cfg;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr uint32_t UE_PCELL_CC_IDX = 0;
|
constexpr uint32_t UE_PCELL_CC_IDX = 0;
|
||||||
|
|
|
@ -40,6 +40,8 @@ struct rrc_cfg_cqi_t {
|
||||||
uint32_t nof_prb;
|
uint32_t nof_prb;
|
||||||
uint32_t period;
|
uint32_t period;
|
||||||
uint32_t m_ri;
|
uint32_t m_ri;
|
||||||
|
bool is_subband_enabled;
|
||||||
|
uint32_t subband_k;
|
||||||
bool simultaneousAckCQI;
|
bool simultaneousAckCQI;
|
||||||
rrc_cfg_cqi_mode_t mode;
|
rrc_cfg_cqi_mode_t mode;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,41 @@
|
||||||
|
|
||||||
// All times are in ms. Use -1 for infinity, where available
|
// 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 = (
|
qci_config = (
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -24,6 +59,9 @@ qci_config = (
|
||||||
bucket_size_duration = 100;
|
bucket_size_duration = 100;
|
||||||
log_chan_group = 2;
|
log_chan_group = 2;
|
||||||
};
|
};
|
||||||
|
enb_specific = {
|
||||||
|
dl_max_retx_thresh = 32;
|
||||||
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
qci=9;
|
qci=9;
|
||||||
|
@ -49,6 +87,9 @@ qci_config = (
|
||||||
bucket_size_duration = 100;
|
bucket_size_duration = 100;
|
||||||
log_chan_group = 3;
|
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)
|
//subframe = [0, 10, 20, 30]; // Optional vector of subframe indices every period where CQI resources will be allocated (default uses all)
|
||||||
nof_prb = 1;
|
nof_prb = 1;
|
||||||
m_ri = 8; // RI period in CQI period
|
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(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(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)
|
set(SRSRAN_SOURCES ${SRSRAN_SOURCES} rrc_nr_asn1 ngap_nr_asn1)
|
||||||
|
|
||||||
target_link_libraries(srsenb ${SRSENB_SOURCES}
|
target_link_libraries(srsenb ${SRSENB_SOURCES}
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "srsenb/hdr/enb.h"
|
#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/enb_stack_lte.h"
|
||||||
#include "srsenb/hdr/stack/gnb_stack_nr.h"
|
#include "srsenb/hdr/stack/gnb_stack_nr.h"
|
||||||
#include "srsenb/src/enb_cfg_parser.h"
|
#include "srsenb/src/enb_cfg_parser.h"
|
||||||
|
@ -104,40 +103,9 @@ int enb::init(const all_args_t& args_)
|
||||||
phy = std::move(lte_phy);
|
phy = std::move(lte_phy);
|
||||||
radio = std::move(lte_radio);
|
radio = std::move(lte_radio);
|
||||||
|
|
||||||
} else if (args.stack.type == "nr") {
|
} else {
|
||||||
std::unique_ptr<srsenb::gnb_stack_nr> nr_stack(new srsenb::gnb_stack_nr);
|
srsran::console("Stack type %s not supported.\n", args.stack.type.c_str());
|
||||||
std::unique_ptr<srsran::radio_null> nr_radio(new srsran::radio_null);
|
return SRSRAN_ERROR;
|
||||||
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");
|
|
||||||
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
|
started = true; // set to true in any case to allow stopping the eNB if an error happened
|
||||||
|
|
|
@ -82,7 +82,7 @@ int field_sched_info::parse(libconfig::Setting& root)
|
||||||
for (uint32_t i = 0; i < data->sched_info_list.size(); i++) {
|
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])) {
|
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);
|
fprintf(stderr, "Missing field si_periodicity in sched_info=%d\n", i);
|
||||||
return -1;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
if (root[i].exists("si_mapping_info")) {
|
if (root[i].exists("si_mapping_info")) {
|
||||||
data->sched_info_list[i].sib_map_info.resize((uint32_t)root[i]["si_mapping_info"].getLength());
|
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);
|
data->sched_info_list[i].sib_map_info[j].value = (sib_type_e::options)(sib_index - 3);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Invalid SIB index %d for si_mapping_info=%d in sched_info=%d\n", sib_index, j, i);
|
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 {
|
} else {
|
||||||
fprintf(stderr, "Number of si_mapping_info values exceeds maximum (%d)\n", ASN1_RRC_MAX_SIB);
|
fprintf(stderr, "Number of si_mapping_info values exceeds maximum (%d)\n", ASN1_RRC_MAX_SIB);
|
||||||
return -1;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
data->sched_info_list[i].sib_map_info.resize(0);
|
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++) {
|
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])) {
|
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);
|
fprintf(stderr, "Missing field q_offset_range in neigh_cell=%d\n", i);
|
||||||
return -1;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int phys_cell_id = 0;
|
int phys_cell_id = 0;
|
||||||
if (!root[i].lookupValue("phys_cell_id", phys_cell_id)) {
|
if (!root[i].lookupValue("phys_cell_id", phys_cell_id)) {
|
||||||
fprintf(stderr, "Missing field phys_cell_id in neigh_cell=%d\n", i);
|
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;
|
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++) {
|
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])) {
|
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);
|
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;
|
data->intra_freq_black_cell_list[i].range_present = true;
|
||||||
|
|
||||||
int start = 0;
|
int start = 0;
|
||||||
if (!root[i].lookupValue("start", start)) {
|
if (!root[i].lookupValue("start", start)) {
|
||||||
fprintf(stderr, "Missing field start in black_cell=%d\n", i);
|
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;
|
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;
|
data->carrier_freqs_info_list_present = data->carrier_freqs_info_list.size() > 0;
|
||||||
if (data->carrier_freqs_info_list.size() > ASN1_RRC_MAX_GNFG) {
|
if (data->carrier_freqs_info_list.size() > ASN1_RRC_MAX_GNFG) {
|
||||||
ERROR("CarrierFreqsInfoGERAN cannot have more than %d entries", 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++) {
|
for (uint32_t i = 0; i < data->carrier_freqs_info_list.size(); i++) {
|
||||||
int cell_resel_prio;
|
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);
|
"ncc_permitted", &data->carrier_freqs_info_list[i].common_info.ncc_permitted);
|
||||||
if (ncc_permitted.parse(root[i])) {
|
if (ncc_permitted.parse(root[i])) {
|
||||||
ERROR("Error parsing `ncc_permitted` in carrier_freqs_info_lsit=%d", i);
|
ERROR("Error parsing `ncc_permitted` in carrier_freqs_info_lsit=%d", i);
|
||||||
return -1;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int q_rx_lev_min = 0;
|
int q_rx_lev_min = 0;
|
||||||
if (!root[i].lookupValue("q_rx_lev_min", q_rx_lev_min)) {
|
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);
|
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;
|
data->carrier_freqs_info_list[i].common_info.q_rx_lev_min = q_rx_lev_min;
|
||||||
|
|
||||||
int thresh_x_high = 0;
|
int thresh_x_high = 0;
|
||||||
if (!root[i].lookupValue("thresh_x_high", thresh_x_high)) {
|
if (!root[i].lookupValue("thresh_x_high", thresh_x_high)) {
|
||||||
ERROR("Missing field `thresh_x_high` in carrier_freqs_info_list=%d", i);
|
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;
|
data->carrier_freqs_info_list[i].common_info.thresh_x_high = thresh_x_high;
|
||||||
|
|
||||||
int thresh_x_low = 0;
|
int thresh_x_low = 0;
|
||||||
if (!root[i].lookupValue("thresh_x_low", thresh_x_low)) {
|
if (!root[i].lookupValue("thresh_x_low", thresh_x_low)) {
|
||||||
ERROR("Missing field `thresh_x_low` in carrier_freqs_info_list=%d", i);
|
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;
|
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);
|
&data->carrier_freqs_info_list[i].carrier_freqs.band_ind);
|
||||||
if (band_ind.parse(root[i])) {
|
if (band_ind.parse(root[i])) {
|
||||||
ERROR("Error parsing `band_ind` in carrier_freqs_info_list=%d", 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();
|
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;
|
exp_l[j] = (short unsigned int)arfcn;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Invalid ARFCN %d in for carrier_freqs_info_list=%d explicit_list_of_arfcns\n", i, j);
|
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 {
|
} else {
|
||||||
fprintf(stderr, "Number of ARFCN in explicit_list_of_arfcns exceeds maximum (%d)\n", 31);
|
fprintf(stderr, "Number of ARFCN in explicit_list_of_arfcns exceeds maximum (%d)\n", 31);
|
||||||
return -1;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
exp_l.resize(0);
|
exp_l.resize(0);
|
||||||
|
@ -273,7 +273,7 @@ int mbsfn_sf_cfg_list_parser::parse(Setting& root)
|
||||||
}
|
}
|
||||||
if (len > 1) {
|
if (len > 1) {
|
||||||
fprintf(stderr, "Only mbsfnSubframeConfigListLengths of size 1 are supported\n");
|
fprintf(stderr, "Only mbsfnSubframeConfigListLengths of size 1 are supported\n");
|
||||||
return -1;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
*enabled = true;
|
*enabled = true;
|
||||||
mbsfn_list->resize(len);
|
mbsfn_list->resize(len);
|
||||||
|
@ -315,53 +315,53 @@ int mbsfn_area_info_list_parser::parse(Setting& root)
|
||||||
&mbsfn_item->non_mbsfn_region_len);
|
&mbsfn_item->non_mbsfn_region_len);
|
||||||
if (fieldlen.parse(root["mbsfn_area_info_list"])) {
|
if (fieldlen.parse(root["mbsfn_area_info_list"])) {
|
||||||
fprintf(stderr, "Error parsing non_mbsfn_region_length\n");
|
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(
|
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);
|
"mcch_repetition_period", &mbsfn_item->mcch_cfg_r9.mcch_repeat_period_r9);
|
||||||
if (repeat.parse(root["mbsfn_area_info_list"])) {
|
if (repeat.parse(root["mbsfn_area_info_list"])) {
|
||||||
fprintf(stderr, "Error parsing mcch_repetition_period\n");
|
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(
|
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);
|
"mcch_modification_period", &mbsfn_item->mcch_cfg_r9.mcch_mod_period_r9);
|
||||||
if (mod.parse(root["mbsfn_area_info_list"])) {
|
if (mod.parse(root["mbsfn_area_info_list"])) {
|
||||||
fprintf(stderr, "Error parsing mcch_modification_period\n");
|
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",
|
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);
|
&mbsfn_item->mcch_cfg_r9.sig_mcs_r9);
|
||||||
if (sig.parse(root["mbsfn_area_info_list"])) {
|
if (sig.parse(root["mbsfn_area_info_list"])) {
|
||||||
fprintf(stderr, "Error parsing signalling_mcs\n");
|
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);
|
parser::field<uint16_t> areaid("mbsfn_area_id", &mbsfn_item->mbsfn_area_id_r9);
|
||||||
if (areaid.parse(root["mbsfn_area_info_list"])) {
|
if (areaid.parse(root["mbsfn_area_info_list"])) {
|
||||||
fprintf(stderr, "Error parsing mbsfn_area_id\n");
|
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);
|
parser::field<uint8_t> notif_ind("notification_indicator", &mbsfn_item->notif_ind_r9);
|
||||||
if (notif_ind.parse(root["mbsfn_area_info_list"])) {
|
if (notif_ind.parse(root["mbsfn_area_info_list"])) {
|
||||||
fprintf(stderr, "Error parsing notification_indicator\n");
|
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);
|
parser::field<uint8_t> offset("mcch_offset", &mbsfn_item->mcch_cfg_r9.mcch_offset_r9);
|
||||||
if (offset.parse(root["mbsfn_area_info_list"])) {
|
if (offset.parse(root["mbsfn_area_info_list"])) {
|
||||||
fprintf(stderr, "Error parsing mcch_offset\n");
|
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",
|
field_asn1_bitstring_number<asn1::fixed_bitstring<6>, uint8_t> alloc_info("sf_alloc_info",
|
||||||
&mbsfn_item->mcch_cfg_r9.sf_alloc_info_r9);
|
&mbsfn_item->mcch_cfg_r9.sf_alloc_info_r9);
|
||||||
if (alloc_info.parse(root["mbsfn_area_info_list"])) {
|
if (alloc_info.parse(root["mbsfn_area_info_list"])) {
|
||||||
fprintf(stderr, "Error parsing mbsfn_area_info_list\n");
|
fprintf(stderr, "Error parsing mbsfn_area_info_list\n");
|
||||||
return -1;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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();
|
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"])) {
|
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"])) {
|
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"])) {
|
if (not parse_enum_by_number(s.prohibit_phr_timer, "prohibit_phr_timer", root["phr_cnfg"])) {
|
||||||
return -1;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
return 0;
|
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)
|
int field_qci::parse(libconfig::Setting& root)
|
||||||
{
|
{
|
||||||
auto nof_qci = (uint32_t)root.getLength();
|
auto nof_qci = (uint32_t)root.getLength();
|
||||||
|
@ -418,7 +484,7 @@ int field_qci::parse(libconfig::Setting& root)
|
||||||
// Parse PDCP section
|
// Parse PDCP section
|
||||||
if (!q.exists("pdcp_config")) {
|
if (!q.exists("pdcp_config")) {
|
||||||
fprintf(stderr, "Error section pdcp_config not found for qci=%d\n", qci);
|
fprintf(stderr, "Error section pdcp_config not found for qci=%d\n", qci);
|
||||||
return -1;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
rrc_cfg_qci_t qcicfg;
|
rrc_cfg_qci_t qcicfg;
|
||||||
|
@ -447,7 +513,7 @@ int field_qci::parse(libconfig::Setting& root)
|
||||||
rlc_cfg->set_um_uni_dir_dl();
|
rlc_cfg->set_um_uni_dir_dl();
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Invalid combination of UL/DL UM/AM for qci=%d\n", qci);
|
fprintf(stderr, "Invalid combination of UL/DL UM/AM for qci=%d\n", qci);
|
||||||
return -1;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse RLC-UM section
|
// 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);
|
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"])) {
|
if (sn_field_len.parse(q["rlc_config"]["ul_um"])) {
|
||||||
ERROR("Error can't find sn_field_length in section 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);
|
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"])) {
|
if (sn_field_len.parse(q["rlc_config"]["dl_um"])) {
|
||||||
ERROR("Error can't find sn_field_length in section 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);
|
field_asn1_enum_number<t_reordering_e> t_reordering("t_reordering", &um_rlc->t_reordering);
|
||||||
if (t_reordering.parse(q["rlc_config"]["dl_um"])) {
|
if (t_reordering.parse(q["rlc_config"]["dl_um"])) {
|
||||||
ERROR("Error can't find t_reordering in section 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);
|
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"])) {
|
if (t_poll_retx.parse(q["rlc_config"]["ul_am"])) {
|
||||||
ERROR("Error can't find t_poll_retx in section 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);
|
field_asn1_enum_number<poll_pdu_e> poll_pdu("poll_pdu", &am_rlc->poll_pdu);
|
||||||
if (poll_pdu.parse(q["rlc_config"]["ul_am"])) {
|
if (poll_pdu.parse(q["rlc_config"]["ul_am"])) {
|
||||||
ERROR("Error can't find poll_pdu in section 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);
|
field_asn1_enum_number<poll_byte_e> poll_byte("poll_byte", &am_rlc->poll_byte);
|
||||||
if (poll_byte.parse(q["rlc_config"]["ul_am"])) {
|
if (poll_byte.parse(q["rlc_config"]["ul_am"])) {
|
||||||
ERROR("Error can't find poll_byte in section 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",
|
field_asn1_enum_number<ul_am_rlc_s::max_retx_thres_e_> max_retx_thresh("max_retx_thresh",
|
||||||
&am_rlc->max_retx_thres);
|
&am_rlc->max_retx_thres);
|
||||||
if (max_retx_thresh.parse(q["rlc_config"]["ul_am"])) {
|
if (max_retx_thresh.parse(q["rlc_config"]["ul_am"])) {
|
||||||
ERROR("Error can't find max_retx_thresh in section 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);
|
field_asn1_enum_number<t_reordering_e> t_reordering("t_reordering", &am_rlc->t_reordering);
|
||||||
if (t_reordering.parse(q["rlc_config"]["dl_am"])) {
|
if (t_reordering.parse(q["rlc_config"]["dl_am"])) {
|
||||||
ERROR("Error can't find t_reordering in section 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);
|
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"])) {
|
if (t_status_prohibit.parse(q["rlc_config"]["dl_am"])) {
|
||||||
ERROR("Error can't find t_status_prohibit in section dl_am");
|
ERROR("Error can't find t_status_prohibit in section dl_am");
|
||||||
return -1;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse logical channel configuration section
|
// Parse logical channel configuration section
|
||||||
if (!q.exists("logical_channel_config")) {
|
if (!q.exists("logical_channel_config")) {
|
||||||
fprintf(stderr, "Error section logical_channel_config not found for qci=%d\n", qci);
|
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;
|
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);
|
parser::field<uint8> priority("priority", &lc_cfg->prio);
|
||||||
if (priority.parse(q["logical_channel_config"])) {
|
if (priority.parse(q["logical_channel_config"])) {
|
||||||
ERROR("Error can't find logical_channel_config in section priority");
|
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(
|
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);
|
"prioritized_bit_rate", &lc_cfg->prioritised_bit_rate);
|
||||||
if (prioritised_bit_rate.parse(q["logical_channel_config"])) {
|
if (prioritised_bit_rate.parse(q["logical_channel_config"])) {
|
||||||
fprintf(stderr, "Error can't find prioritized_bit_rate in section logical_channel_config\n");
|
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(
|
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);
|
"bucket_size_duration", &lc_cfg->bucket_size_dur);
|
||||||
if (bucket_size_duration.parse(q["logical_channel_config"])) {
|
if (bucket_size_duration.parse(q["logical_channel_config"])) {
|
||||||
ERROR("Error can't find bucket_size_duration in section 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);
|
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"]);
|
lc_cfg->lc_ch_group_present = not log_chan_group.parse(q["logical_channel_config"]);
|
||||||
qcicfg.configured = true;
|
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));
|
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>("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>("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>("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 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));
|
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"]));
|
HANDLEPARSERCODE(parse_meas_cell_list(&cell_cfg.meas_cfg, cellroot["meas_cell_list"]));
|
||||||
if (not cellroot.exists("meas_report_desc")) {
|
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");
|
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"]));
|
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
|
// Check RF port is not repeated
|
||||||
if (it->rf_port == it2->rf_port) {
|
if (it->rf_port == it2->rf_port) {
|
||||||
ERROR("Repeated RF port for multiple cells");
|
ERROR("Repeated RF port for multiple cells");
|
||||||
return -1;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check cell ID is not repeated
|
// Check cell ID is not repeated
|
||||||
if (it->cell_id == it2->cell_id) {
|
if (it->cell_id == it2->cell_id) {
|
||||||
ERROR("Repeated Cell identifier");
|
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;
|
return 0;
|
||||||
} else {
|
} 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;
|
std::string mnc_str;
|
||||||
if (not srsran::mnc_to_string(args_->stack.s1ap.mnc, &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);
|
ERROR("The provided mnc=%d is not valid", args_->stack.s1ap.mnc);
|
||||||
return -1;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
std::string mcc_str;
|
std::string mcc_str;
|
||||||
if (not srsran::mcc_to_string(args_->stack.s1ap.mcc, &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);
|
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;
|
sib_type1_s::cell_access_related_info_s_* cell_access = &sib1->cell_access_related_info;
|
||||||
cell_access->plmn_id_list.resize(1);
|
cell_access->plmn_id_list.resize(1);
|
||||||
srsran::plmn_id_t plmn;
|
srsran::plmn_id_t plmn;
|
||||||
if (plmn.from_string(mcc_str + mnc_str) == SRSRAN_ERROR) {
|
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());
|
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);
|
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;
|
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
|
// verify SIB13 is available
|
||||||
if (not sib_is_present(sib1->sched_info_list, sib_type_e::sib_type13_v920)) {
|
if (not sib_is_present(sib1->sched_info_list, sib_type_e::sib_type13_v920)) {
|
||||||
fprintf(stderr, "SIB13 not present in sched_info.\n");
|
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_)
|
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");
|
parser::section qci("qci_config");
|
||||||
qci.add_field(new field_qci(rrc_cfg_->qci_cfg));
|
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
|
} // namespace drb_sections
|
||||||
|
|
|
@ -155,6 +155,18 @@ private:
|
||||||
uint32_t default_offset;
|
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
|
class field_qci final : public parser::field_itf
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -54,7 +54,8 @@ namespace bpo = boost::program_options;
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* Program arguments processing
|
* Program arguments processing
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
string config_file;
|
string config_file;
|
||||||
|
static bool stdout_ts_enable = false;
|
||||||
|
|
||||||
void parse_args(all_args_t* args, int argc, char* argv[])
|
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.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.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.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")
|
("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_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.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.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 */
|
/* 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_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_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.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.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.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).")
|
("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.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_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.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
|
// eMBMS section
|
||||||
|
@ -445,8 +450,8 @@ void parse_args(all_args_t* args, int argc, char* argv[])
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config_exists(args->enb_files.drb_config, "drb.conf")) {
|
if (!config_exists(args->enb_files.rb_config, "rb.conf")) {
|
||||||
cout << "Failed to read DRB configuration file " << args->enb_files.drb_config << " - exiting" << endl;
|
cout << "Failed to read DRB configuration file " << args->enb_files.rb_config << " - exiting" << endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,7 +634,8 @@ int main(int argc, char* argv[])
|
||||||
enb->start_plot();
|
enb->start_plot();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
|
int ts_cnt = 0;
|
||||||
while (running) {
|
while (running) {
|
||||||
if (args.general.print_buffer_state) {
|
if (args.general.print_buffer_state) {
|
||||||
cnt++;
|
cnt++;
|
||||||
|
@ -638,6 +644,16 @@ int main(int argc, char* argv[])
|
||||||
enb->print_pool();
|
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));
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
}
|
}
|
||||||
input.join();
|
input.join();
|
||||||
|
|
|
@ -31,8 +31,6 @@ set(SOURCES
|
||||||
txrx.cc)
|
txrx.cc)
|
||||||
add_library(srsenb_phy STATIC ${SOURCES})
|
add_library(srsenb_phy STATIC ${SOURCES})
|
||||||
|
|
||||||
add_library(srsgnb_phy STATIC vnf_phy_nr.cc)
|
|
||||||
|
|
||||||
if (ENABLE_GUI AND SRSGUI_FOUND)
|
if (ENABLE_GUI AND SRSGUI_FOUND)
|
||||||
target_link_libraries(srsenb_phy ${SRSGUI_LIBRARIES})
|
target_link_libraries(srsenb_phy ${SRSGUI_LIBRARIES})
|
||||||
endif ()
|
endif ()
|
||||||
|
|
|
@ -35,11 +35,12 @@ slot_worker::slot_worker(srsran::phy_common_interface& common_,
|
||||||
bool slot_worker::init(const args_t& args)
|
bool slot_worker::init(const args_t& args)
|
||||||
{
|
{
|
||||||
// Calculate subframe length
|
// 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
|
// Copy common configurations
|
||||||
cell_index = args.cell_index;
|
cell_index = args.cell_index;
|
||||||
pdcch_cfg = args.pdcch_cfg;
|
// FIXME:
|
||||||
|
// pdcch_cfg = args.pdcch_cfg;
|
||||||
|
|
||||||
// Allocate Tx buffers
|
// Allocate Tx buffers
|
||||||
tx_buffer.resize(args.nof_tx_ports);
|
tx_buffer.resize(args.nof_tx_ports);
|
||||||
|
@ -64,10 +65,10 @@ bool slot_worker::init(const args_t& args)
|
||||||
// Prepare DL arguments
|
// Prepare DL arguments
|
||||||
srsran_gnb_dl_args_t dl_args = {};
|
srsran_gnb_dl_args_t dl_args = {};
|
||||||
dl_args.pdsch.measure_time = true;
|
dl_args.pdsch.measure_time = true;
|
||||||
dl_args.pdsch.max_layers = args.carrier.max_mimo_layers;
|
dl_args.pdsch.max_layers = args.nof_tx_ports;
|
||||||
dl_args.pdsch.max_prb = args.carrier.nof_prb;
|
dl_args.pdsch.max_prb = args.nof_max_prb;
|
||||||
dl_args.nof_tx_antennas = args.nof_tx_ports;
|
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
|
// Initialise DL
|
||||||
if (srsran_gnb_dl_init(&gnb_dl, tx_buffer.data(), &dl_args) < SRSRAN_SUCCESS) {
|
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;
|
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
|
// Prepare UL arguments
|
||||||
srsran_gnb_ul_args_t ul_args = {};
|
srsran_gnb_ul_args_t ul_args = {};
|
||||||
ul_args.pusch.measure_time = true;
|
ul_args.pusch.measure_time = true;
|
||||||
ul_args.pusch.max_layers = args.carrier.max_mimo_layers;
|
ul_args.pusch.max_layers = args.nof_rx_ports;
|
||||||
ul_args.pusch.max_prb = args.carrier.nof_prb;
|
ul_args.pusch.max_prb = args.nof_max_prb;
|
||||||
ul_args.nof_max_prb = args.carrier.nof_prb;
|
ul_args.nof_max_prb = args.nof_max_prb;
|
||||||
|
|
||||||
// Initialise UL
|
// Initialise UL
|
||||||
if (srsran_gnb_ul_init(&gnb_ul, rx_buffer[0], &ul_args) < SRSRAN_SUCCESS) {
|
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;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +156,7 @@ bool slot_worker::work_ul()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode PUCCH
|
// For each PUCCH...
|
||||||
for (stack_interface_phy_nr::pucch_t& pucch : ul_sched.pucch) {
|
for (stack_interface_phy_nr::pucch_t& pucch : ul_sched.pucch) {
|
||||||
stack_interface_phy_nr::pucch_info_t pucch_info = {};
|
stack_interface_phy_nr::pucch_info_t pucch_info = {};
|
||||||
pucch_info.uci_data.cfg = pucch.uci_cfg;
|
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) {
|
for (stack_interface_phy_nr::pusch_t& pusch : ul_sched.pusch) {
|
||||||
// Get payload PDU
|
// Get payload PDU
|
||||||
stack_interface_phy_nr::pusch_info_t pusch_info = {};
|
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[0].payload = pusch.data[0];
|
||||||
pusch_info.pusch_data.tb[1].payload = pusch.data[1];
|
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) <
|
if (srsran_gnb_ul_get_pusch(&gnb_ul, &ul_slot_cfg, &pusch.sch, &pusch.sch.grant, &pusch_info.pusch_data) <
|
||||||
SRSRAN_SUCCESS) {
|
SRSRAN_SUCCESS) {
|
||||||
logger.error("Error getting PUSCH");
|
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);
|
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 nr
|
||||||
} // namespace srsenb
|
} // namespace srsenb
|
||||||
|
|
|
@ -27,19 +27,27 @@ worker_pool::worker_pool(srsran::phy_common_interface& common_,
|
||||||
stack_interface_phy_nr& stack_,
|
stack_interface_phy_nr& stack_,
|
||||||
srslog::sink& log_sink_,
|
srslog::sink& log_sink_,
|
||||||
uint32_t max_workers) :
|
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
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
bool worker_pool::init(const args_t& args, const phy_cell_cfg_list_nr_t& cell_list)
|
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
|
// 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++) {
|
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_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);
|
auto w = new slot_worker(common, stack, log);
|
||||||
pool.init_worker(i, w, args.prio);
|
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 = {};
|
slot_worker::args_t w_args = {};
|
||||||
uint32_t cell_index = 0;
|
uint32_t cell_index = 0;
|
||||||
w_args.cell_index = cell_index;
|
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_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.nof_rx_ports = cell_list[cell_index].carrier.max_mimo_layers;
|
||||||
w_args.pusch_max_nof_iter = args.pusch_max_nof_iter;
|
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)) {
|
if (not w->init(w_args)) {
|
||||||
return false;
|
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)
|
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);
|
pool.start_worker(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
slot_worker* worker_pool::wait_worker(uint32_t tti)
|
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)
|
slot_worker* worker_pool::wait_worker_id(uint32_t id)
|
||||||
|
@ -80,7 +116,42 @@ slot_worker* worker_pool::wait_worker_id(uint32_t id)
|
||||||
void worker_pool::stop()
|
void worker_pool::stop()
|
||||||
{
|
{
|
||||||
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
|
} // namespace nr
|
||||||
} // namespace srsenb
|
} // namespace srsenb
|
||||||
|
|
|
@ -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);
|
return m_mac->pusch_info(slot_cfg, pusch_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gnb_stack_nr::rach_detected(const rach_info_t& rach_info) {}
|
||||||
|
|
||||||
} // namespace srsenb
|
} // 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;
|
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);
|
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/.
|
# 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})
|
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) {}
|
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)
|
int mac_nr::rx_data_indication(stack_interface_phy_nr::rx_data_ind_t& rx_data)
|
||||||
{
|
{
|
||||||
// push received PDU on queue
|
// 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;
|
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)
|
int mac_nr::get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -295,5 +192,6 @@ int mac_nr::pusch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_ph
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
void mac_nr::rach_detected(const mac_interface_phy_nr::rach_info_t& rach_info) {}
|
||||||
|
|
||||||
} // namespace srsenb
|
} // namespace srsenb
|
||||||
|
|
|
@ -20,15 +20,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "srsenb/hdr/stack/mac/nr/sched_nr.h"
|
#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 "srsenb/hdr/stack/mac/nr/sched_nr_worker.h"
|
||||||
#include "srsran/common/thread_pool.h"
|
#include "srsran/common/thread_pool.h"
|
||||||
|
|
||||||
namespace srsenb {
|
namespace srsenb {
|
||||||
|
|
||||||
using sched_nr_impl::sched_worker_manager;
|
using namespace sched_nr_impl;
|
||||||
using sched_nr_impl::ue;
|
|
||||||
using sched_nr_impl::ue_carrier;
|
|
||||||
using sched_nr_impl::ue_map_t;
|
|
||||||
|
|
||||||
static int assert_ue_cfg_valid(uint16_t rnti, const sched_nr_interface::ue_cfg_t& uecfg);
|
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().cc = cc;
|
||||||
feedback_list.back().callback = std::move(event);
|
feedback_list.back().callback = std::move(event);
|
||||||
}
|
}
|
||||||
void new_tti()
|
void new_slot()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(common_mutex);
|
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() {}
|
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);
|
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));
|
sched_workers.reset(new sched_nr_impl::sched_worker_manager(ue_db, cfg));
|
||||||
|
|
||||||
return SRSRAN_SUCCESS;
|
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)
|
void sched_nr::ue_cfg_impl(uint16_t rnti, const ue_cfg_t& uecfg)
|
||||||
{
|
{
|
||||||
if (not ue_db.contains(rnti)) {
|
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 {
|
} else {
|
||||||
ue_db[rnti]->set_cfg(uecfg);
|
ue_db[rnti]->set_cfg(uecfg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sched_nr::slot_indication(tti_point tti_rx)
|
|
||||||
{
|
|
||||||
// Lock slot workers for provided tti_rx
|
|
||||||
sched_workers->reserve_workers(tti_rx);
|
|
||||||
|
|
||||||
{
|
|
||||||
// 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();
|
|
||||||
|
|
||||||
sched_workers->start_tti(tti_rx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generate {tti,cc} scheduling decision
|
/// 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::generate_slot_result(tti_point pdcch_tti, uint32_t cc)
|
||||||
{
|
{
|
||||||
|
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
|
||||||
|
pending_events->new_slot();
|
||||||
|
});
|
||||||
|
|
||||||
// unlocked, parallel region
|
// unlocked, parallel region
|
||||||
bool all_workers_finished = sched_workers->run_tti(tti_rx, cc, req);
|
bool all_workers_finished = sched_workers->run_slot(tti_rx, cc);
|
||||||
|
|
||||||
if (all_workers_finished) {
|
if (all_workers_finished) {
|
||||||
// once all workers of the same subframe finished, synchronize sched outcome with ue_db
|
// 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->release_slot(tti_rx);
|
||||||
sched_workers->end_tti(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sched_nr::get_dl_sched(tti_point tti_tx, uint32_t cc, dl_sched_t& result)
|
||||||
|
{
|
||||||
|
if (not pending_results->has_dl_result(tti_tx, cc)) {
|
||||||
|
generate_slot_result(tti_tx, cc);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
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)
|
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");
|
VERIFY_INPUT(std::count(&uecfg.phy_cfg.pdcch.coreset_present[0],
|
||||||
if (std::count(&uecfg.phy_cfg.pdcch.coreset_present[0],
|
&uecfg.phy_cfg.pdcch.coreset_present[SRSRAN_UE_DL_NR_MAX_NOF_CORESET],
|
||||||
&uecfg.phy_cfg.pdcch.coreset_present[SRSRAN_UE_DL_NR_MAX_NOF_CORESET],
|
true) > 0,
|
||||||
true) == 0) {
|
"Provided rnti=0x%x configuration does not contain any coreset",
|
||||||
logger.warning("Provided rnti=0x%x configuration does not contain any coreset", rnti);
|
rnti);
|
||||||
return SRSRAN_ERROR;
|
|
||||||
}
|
|
||||||
return SRSRAN_SUCCESS;
|
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_,
|
bool harq_proc::new_tx(tti_point tti_tx_,
|
||||||
tti_point tti_ack_,
|
tti_point tti_ack_,
|
||||||
const rbgmask_t& rbgmask_,
|
const prb_grant& grant,
|
||||||
uint32_t mcs,
|
uint32_t mcs,
|
||||||
uint32_t tbs,
|
uint32_t tbs,
|
||||||
uint32_t max_retx_)
|
uint32_t max_retx_)
|
||||||
|
@ -66,7 +66,7 @@ bool harq_proc::new_tx(tti_point tti_tx_,
|
||||||
max_retx = max_retx_;
|
max_retx = max_retx_;
|
||||||
tti_tx = tti_tx_;
|
tti_tx = tti_tx_;
|
||||||
tti_ack = tti_ack_;
|
tti_ack = tti_ack_;
|
||||||
rbgmask = rbgmask_;
|
prbs_ = grant;
|
||||||
tb[0].ndi = !tb[0].ndi;
|
tb[0].ndi = !tb[0].ndi;
|
||||||
tb[0].mcs = mcs;
|
tb[0].mcs = mcs;
|
||||||
tb[0].tbs = tbs;
|
tb[0].tbs = tbs;
|
||||||
|
@ -74,32 +74,49 @@ bool harq_proc::new_tx(tti_point tti_tx_,
|
||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
tti_tx = tti_tx_;
|
tti_tx = tti_tx_;
|
||||||
tti_ack = tti_ack_;
|
tti_ack = tti_ack_;
|
||||||
rbgmask = rbgmask_;
|
|
||||||
tb[0].ack_state = false;
|
tb[0].ack_state = false;
|
||||||
tb[0].n_rtx++;
|
tb[0].n_rtx++;
|
||||||
if (mcs != nullptr) {
|
|
||||||
*mcs = tb[0].mcs;
|
|
||||||
}
|
|
||||||
if (tbs != nullptr) {
|
|
||||||
*tbs = tb[0].tbs;
|
|
||||||
}
|
|
||||||
return true;
|
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);
|
dl_harqs.reserve(nof_harq_procs);
|
||||||
ul_harqs.reserve(nof_harq_procs);
|
ul_harqs.reserve(nof_harq_procs);
|
||||||
for (uint32_t pid = 0; pid < nof_harq_procs; ++pid) {
|
for (uint32_t pid = 0; pid < nof_harq_procs; ++pid) {
|
||||||
dl_harqs.emplace_back(pid);
|
dl_harqs.emplace_back(pid, nprb);
|
||||||
ul_harqs.emplace_back(pid);
|
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 srsenb {
|
||||||
namespace sched_nr_impl {
|
namespace sched_nr_impl {
|
||||||
|
|
||||||
coreset_region::coreset_region(uint32_t bwp_id_,
|
coreset_region::coreset_region(const bwp_params& bwp_cfg_,
|
||||||
uint32_t slot_idx_,
|
uint32_t coreset_id_,
|
||||||
uint32_t nof_td_symbols,
|
uint32_t slot_idx_,
|
||||||
uint32_t nof_freq_resources,
|
pdcch_dl_list_t& dl_list_,
|
||||||
pdcch_dl_list_t& pdcch_list_) :
|
pdcch_ul_list_t& ul_list_) :
|
||||||
bwp_id(bwp_id_),
|
coreset_cfg(&bwp_cfg_.cfg.pdcch.coreset[coreset_id_]),
|
||||||
|
coreset_id(coreset_id_),
|
||||||
slot_idx(slot_idx_),
|
slot_idx(slot_idx_),
|
||||||
nof_symbols(nof_td_symbols),
|
pdcch_dl_list(dl_list_),
|
||||||
nof_freq_res(nof_freq_resources),
|
pdcch_ul_list(ul_list_)
|
||||||
pdcch_dl_list(pdcch_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}");
|
"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,
|
srsran_assert(nof_freq_res <= bwp_cfg_.cell_cfg.carrier.nof_prb,
|
||||||
"Provided number of CORESET freq domain resources=%d is too high",
|
"The number of frequency resources=%d of coreset_id=%d exceeds BWP bandwidth",
|
||||||
nof_freq_resources);
|
nof_freq_res,
|
||||||
|
coreset_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void coreset_region::reset()
|
void coreset_region::reset()
|
||||||
|
@ -49,9 +52,13 @@ void coreset_region::reset()
|
||||||
saved_dfs_tree.clear();
|
saved_dfs_tree.clear();
|
||||||
dci_list.clear();
|
dci_list.clear();
|
||||||
pdcch_dl_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(aggr_idx <= 4, "Invalid DCI aggregation level=%d", 1U << aggr_idx);
|
||||||
srsran_assert((user == nullptr) xor
|
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;
|
alloc_record record;
|
||||||
record.ue = user;
|
record.ue = user;
|
||||||
record.aggr_idx = aggr_idx;
|
record.aggr_idx = aggr_idx;
|
||||||
|
record.ss_id = search_space_id;
|
||||||
record.alloc_type = alloc_type;
|
record.alloc_type = alloc_type;
|
||||||
record.idx = pdcch_dl_list.size();
|
if (record.alloc_type == pdcch_grant_type_t::ul_data) {
|
||||||
record.coreset_id = coreset_id;
|
record.idx = pdcch_ul_list.size();
|
||||||
pdcch_dl_list.emplace_back();
|
pdcch_ul_list.emplace_back();
|
||||||
|
} else {
|
||||||
|
record.idx = pdcch_dl_list.size();
|
||||||
|
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
|
// Try to allocate grant. If it fails, attempt the same grant, but using a different permutation of past grant DCI
|
||||||
// positions
|
// 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
|
// Revert steps to initial state, before dci record allocation was attempted
|
||||||
dfs_tree = saved_dfs_tree;
|
dfs_tree = saved_dfs_tree;
|
||||||
pdcch_dl_list.pop_back();
|
if (record.alloc_type == pdcch_grant_type_t::ul_data) {
|
||||||
|
pdcch_ul_list.pop_back();
|
||||||
|
} else {
|
||||||
|
pdcch_dl_list.pop_back();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,8 +109,12 @@ void coreset_region::rem_last_dci()
|
||||||
|
|
||||||
// Remove DCI record
|
// Remove DCI record
|
||||||
dfs_tree.pop_back();
|
dfs_tree.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();
|
dci_list.pop_back();
|
||||||
pdcch_dl_list.pop_back();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool coreset_region::get_next_dfs()
|
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
|
// Allocation successful
|
||||||
node.total_mask |= node.current_mask;
|
node.total_mask |= node.current_mask;
|
||||||
alloc_dfs.push_back(node);
|
alloc_dfs.push_back(node);
|
||||||
pdcch_dl_t& pdcch_dl = pdcch_dl_list[record.idx];
|
if (record.alloc_type == pdcch_grant_type_t::ul_data) {
|
||||||
pdcch_dl.dci.ctx.location = node.dci_pos;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,10 +187,9 @@ srsran::span<const uint32_t> coreset_region::get_cce_loc_table(const alloc_recor
|
||||||
{
|
{
|
||||||
switch (record.alloc_type) {
|
switch (record.alloc_type) {
|
||||||
case pdcch_grant_type_t::dl_data:
|
case pdcch_grant_type_t::dl_data:
|
||||||
return record.ue->cfg->cc_params[record.ue->cc]
|
return record.ue->cfg->cce_pos_list(record.ss_id)[slot_idx][record.aggr_idx];
|
||||||
.bwps[bwp_id]
|
case pdcch_grant_type_t::ul_data:
|
||||||
.coresets[record.coreset_id]
|
return record.ue->cfg->cce_pos_list(record.ss_id)[slot_idx][record.aggr_idx];
|
||||||
.cce_positions[slot_idx][record.aggr_idx];
|
|
||||||
default:
|
default:
|
||||||
break;
|
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_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 srsenb {
|
||||||
namespace sched_nr_impl {
|
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_) :
|
bwp_slot_grid::bwp_slot_grid(const bwp_params& bwp_cfg_, uint32_t slot_idx_) :
|
||||||
dl_rbgs(cell_params.cell_cfg.nof_rbg), ul_rbgs(cell_params.cell_cfg.nof_rbg)
|
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()
|
void bwp_slot_grid::reset()
|
||||||
{
|
{
|
||||||
for (auto& coreset : coresets) {
|
for (auto& coreset : coresets) {
|
||||||
coreset.reset();
|
if (coreset.has_value()) {
|
||||||
|
coreset->reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
dl_rbgs.reset();
|
dl_prbs.reset();
|
||||||
ul_rbgs.reset();
|
ul_prbs.reset();
|
||||||
pdsch_grants.clear();
|
dl_pdcchs.clear();
|
||||||
pdcch_dl_list.clear();
|
ul_pdcchs.clear();
|
||||||
pusch_grants.clear();
|
pending_acks.clear();
|
||||||
pucch_grants.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) {
|
for (uint32_t sl = 0; sl < slots.capacity(); ++sl) {
|
||||||
slots.emplace_back(cell_cfg_, bwp_id, 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_)
|
|
||||||
{
|
|
||||||
for (uint32_t bwp_id = 0; bwp_id < cell_cfg->cell_cfg.bwps.size(); ++bwp_id) {
|
|
||||||
bwps.emplace_back(cell_cfg_, bwp_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
slot_bwp_sched::slot_bwp_sched(uint32_t bwp_id, cell_res_grid& phy_grid_) :
|
bwp_slot_allocator::bwp_slot_allocator(bwp_res_grid& bwp_grid_) :
|
||||||
logger(srslog::fetch_basic_logger("MAC")), cfg(*phy_grid_.cell_cfg), bwp_grid(phy_grid_.bwps[bwp_id])
|
logger(srslog::fetch_basic_logger("MAC")), cfg(*bwp_grid_.cfg), bwp_grid(bwp_grid_)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
alloc_result slot_bwp_sched::alloc_pdsch(slot_ue& ue, const rbgmask_t& dl_mask)
|
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)
|
||||||
{
|
{
|
||||||
if (ue.h_dl == nullptr) {
|
static const uint32_t msg3_nof_prbs = 3;
|
||||||
logger.warning("SCHED: Trying to allocate PDSCH for rnti=0x%x with no available HARQs", ue.rnti);
|
|
||||||
return alloc_result::no_rnti_opportunity;
|
bwp_slot_grid& bwp_pdcch_slot = bwp_grid[pdcch_tti];
|
||||||
}
|
bwp_slot_grid& bwp_msg3_slot = bwp_grid[pdcch_tti + 4];
|
||||||
pdsch_list_t& pdsch_grants = bwp_grid[ue.pdsch_tti].pdsch_grants;
|
|
||||||
if (pdsch_grants.full()) {
|
if (bwp_pdcch_slot.dl_pdcchs.full()) {
|
||||||
logger.warning("SCHED: Maximum number of DL allocations reached");
|
logger.warning("SCHED: Maximum number of DL allocations reached");
|
||||||
return alloc_result::no_grant_space;
|
return alloc_result::no_grant_space;
|
||||||
}
|
}
|
||||||
rbgmask_t& pdsch_mask = bwp_grid[ue.pdsch_tti].dl_rbgs;
|
|
||||||
|
// 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()) {
|
if ((pdsch_mask & dl_mask).any()) {
|
||||||
|
logger.debug("SCHED: Provided RBG mask collides with allocation previously made.");
|
||||||
return alloc_result::sch_collision;
|
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(
|
// Check Msg3 RB collision
|
||||||
pdcch_grant_type_t::dl_data, aggr_idx, coreset_id, &ue)) {
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
// Could not find space in PDCCH
|
||||||
|
logger.debug("SCHED: No space in PDCCH for DL tx.");
|
||||||
return alloc_result::no_cch_space;
|
return alloc_result::no_cch_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mcs = -1, tbs = -1;
|
// Generate DCI for RAR
|
||||||
if (ue.h_dl->empty()) {
|
pdcch_dl_t& pdcch = bwp_pdcch_slot.dl_pdcchs.back();
|
||||||
mcs = 20;
|
if (not fill_dci_rar(interv, *bwp_grid.cfg, pdcch.dci)) {
|
||||||
tbs = 100;
|
// Cancel on-going PDCCH allocation
|
||||||
bool ret = ue.h_dl->new_tx(ue.pdsch_tti, ue.uci_tti, dl_mask, mcs, tbs, 4);
|
bwp_pdcch_slot.coresets[coreset_id]->rem_last_dci();
|
||||||
srsran_assert(ret, "Failed to allocate DL HARQ");
|
return alloc_result::invalid_coderate;
|
||||||
} else {
|
|
||||||
bool ret = ue.h_dl->new_retx(ue.pdsch_tti, ue.uci_tti, dl_mask, &mcs, &tbs);
|
|
||||||
srsran_assert(ret, "Failed to allocate DL HARQ retx");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocation Successful
|
// RAR allocation successful.
|
||||||
pdcch_dl_t& pdcch = bwp_grid[ue.pdcch_tti].pdcch_dl_list.back();
|
bwp_pdcch_slot.dl_prbs.add(interv);
|
||||||
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;
|
|
||||||
|
|
||||||
return alloc_result::success;
|
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_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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (bwp_pdcch_slot.dl_prbs.collides(dl_grant)) {
|
||||||
|
return alloc_result::sch_collision;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate HARQ
|
||||||
|
if (ue.h_dl->empty()) {
|
||||||
|
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_grant);
|
||||||
|
srsran_assert(ret, "Failed to allocate DL HARQ retx");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocation Successful
|
||||||
|
|
||||||
|
// 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 bwp_slot_allocator::alloc_pusch(slot_ue& ue, const rbg_bitmap& ul_mask)
|
||||||
{
|
{
|
||||||
if (ue.h_ul == nullptr) {
|
if (ue.h_ul == nullptr) {
|
||||||
logger.warning("SCHED: Trying to allocate PUSCH for rnti=0x%x with no available HARQs", ue.rnti);
|
logger.warning("SCHED: Trying to allocate PUSCH for rnti=0x%x with no available HARQs", ue.rnti);
|
||||||
return alloc_result::no_rnti_opportunity;
|
return alloc_result::no_rnti_opportunity;
|
||||||
}
|
}
|
||||||
pusch_list& pusch_grants = bwp_grid[ue.pusch_tti].pusch_grants;
|
auto& bwp_pdcch_slot = bwp_grid[ue.pdcch_tti];
|
||||||
if (pusch_grants.full()) {
|
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");
|
logger.warning("SCHED: Maximum number of UL allocations reached");
|
||||||
return alloc_result::no_grant_space;
|
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()) {
|
if ((pusch_mask & ul_mask).any()) {
|
||||||
return alloc_result::sch_collision;
|
return alloc_result::sch_collision;
|
||||||
}
|
}
|
||||||
const uint32_t aggr_idx = 3, coreset_id = 0;
|
const uint32_t aggr_idx = 2, ss_id = 1;
|
||||||
if (not bwp_grid[ue.pdcch_tti].coresets[coreset_id].alloc_dci(
|
uint32_t coreset_id = ue.cfg->phy().pdcch.search_space[ss_id].coreset_id;
|
||||||
pdcch_grant_type_t::ul_data, aggr_idx, coreset_id, &ue)) {
|
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
|
// Could not find space in PDCCH
|
||||||
return alloc_result::no_cch_space;
|
return alloc_result::no_cch_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mcs = -1, tbs = -1;
|
|
||||||
if (ue.h_ul->empty()) {
|
if (ue.h_ul->empty()) {
|
||||||
mcs = 20;
|
int mcs = 20;
|
||||||
tbs = 100;
|
int tbs = 100;
|
||||||
bool ret = ue.h_ul->new_tx(ue.pusch_tti, ue.pusch_tti, ul_mask, mcs, tbs, ue.cfg->maxharq_tx);
|
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");
|
srsran_assert(ret, "Failed to allocate UL HARQ");
|
||||||
} else {
|
} else {
|
||||||
srsran_assert(ue.h_ul->new_retx(ue.pusch_tti, ue.pusch_tti, ul_mask, &mcs, &tbs),
|
srsran_assert(ue.h_ul->new_retx(ue.pusch_tti, ue.pusch_tti, ul_mask), "Failed to allocate UL HARQ retx");
|
||||||
"Failed to allocate UL HARQ retx");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocation Successful
|
// Allocation Successful
|
||||||
pdcch_ul_t& pdcch = bwp_grid[ue.pdcch_tti].pdcch_ul_list.back();
|
// Generate PDCCH
|
||||||
fill_dci_ue_cfg(ue, pdcch.dci);
|
pdcch_ul_t& pdcch = pdcchs.back();
|
||||||
pusch_grants.emplace_back();
|
fill_ul_dci_ue_fields(ue, *bwp_grid.cfg, ss_id, pdcch.dci.ctx.location, pdcch.dci);
|
||||||
pusch_grant& grant = pusch_grants.back();
|
// Generate PUSCH
|
||||||
grant.dci.ctx.rnti = ue.rnti;
|
bwp_pusch_slot.ul_prbs.add(ul_mask);
|
||||||
grant.bitmap = ul_mask;
|
|
||||||
pusch_mask |= ul_mask;
|
|
||||||
|
|
||||||
return alloc_result::success;
|
return alloc_result::success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,57 +25,35 @@
|
||||||
namespace srsenb {
|
namespace srsenb {
|
||||||
namespace sched_nr_impl {
|
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_) :
|
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_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)
|
void ue_carrier::push_feedback(srsran::move_callback<void(ue_carrier&)> callback)
|
||||||
{
|
{
|
||||||
pending_feedback.push_back(std::move(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);
|
slot_ue sfu(busy, rnti, tti_rx, cc);
|
||||||
if (sfu.empty()) {
|
if (sfu.empty()) {
|
||||||
return sfu;
|
return sfu;
|
||||||
}
|
}
|
||||||
// successfully acquired. Process any CC-specific pending feedback
|
// 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()) {
|
while (not pending_feedback.empty()) {
|
||||||
pending_feedback.front()(*this);
|
pending_feedback.front()(*this);
|
||||||
pending_feedback.pop_front();
|
pending_feedback.pop_front();
|
||||||
|
@ -90,23 +68,35 @@ slot_ue ue_carrier::try_reserve(tti_point tti_rx, const ue_cfg_extended& uecfg_)
|
||||||
}
|
}
|
||||||
|
|
||||||
// set UE parameters common to all carriers
|
// set UE parameters common to all carriers
|
||||||
sfu.cfg = &uecfg_;
|
sfu.cfg = &bwp_cfg;
|
||||||
|
|
||||||
// copy cc-specific parameters and find available HARQs
|
// copy cc-specific parameters and find available HARQs
|
||||||
sfu.cc_cfg = &uecfg_.carriers[cc];
|
sfu.cc_cfg = &uecfg_.carriers[cc];
|
||||||
sfu.pdcch_tti = tti_rx + TX_ENB_DELAY;
|
sfu.pdcch_tti = tti_rx + TX_ENB_DELAY;
|
||||||
sfu.pdsch_tti = sfu.pdcch_tti + sfu.cc_cfg->pdsch_res_list[0].k0;
|
const uint32_t k0 = 0;
|
||||||
sfu.pusch_tti = sfu.pdcch_tti + sfu.cc_cfg->pusch_res_list[0].k2;
|
sfu.pdsch_tti = sfu.pdcch_tti + k0;
|
||||||
sfu.uci_tti = sfu.pdsch_tti + sfu.cc_cfg->pdsch_res_list[0].k1;
|
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.dl_cqi = dl_cqi;
|
||||||
sfu.ul_cqi = ul_cqi;
|
sfu.ul_cqi = ul_cqi;
|
||||||
sfu.h_dl = harq_ent.find_pending_dl_retx();
|
|
||||||
if (sfu.h_dl == nullptr) {
|
const srsran_tdd_config_nr_t& tdd_cfg = cell_params.cell_cfg.tdd;
|
||||||
sfu.h_dl = harq_ent.find_empty_dl_harq();
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sfu.h_ul = harq_ent.find_pending_ul_retx();
|
if (srsran_tdd_nr_is_ul(&tdd_cfg, 0, sfu.pusch_tti.sf_idx())) {
|
||||||
if (sfu.h_ul == nullptr) {
|
// If UL enabled
|
||||||
sfu.h_ul = harq_ent.find_empty_ul_harq();
|
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) {
|
if (sfu.h_dl == nullptr and sfu.h_ul == nullptr) {
|
||||||
|
@ -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) {
|
for (uint32_t cc = 0; cc < cfg.carriers.size(); ++cc) {
|
||||||
if (cfg.carriers[cc].active) {
|
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 "srsenb/hdr/stack/mac/nr/sched_nr_worker.h"
|
||||||
|
#include "srsran/common/string_helpers.h"
|
||||||
|
|
||||||
namespace srsenb {
|
namespace srsenb {
|
||||||
namespace sched_nr_impl {
|
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
|
/// 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)
|
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}
|
// UE acquired successfully for scheduling in this {tti, cc}
|
||||||
}
|
}
|
||||||
|
|
||||||
tti_rx = tti_rx_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void slot_cc_worker::run()
|
void slot_cc_worker::run()
|
||||||
{
|
{
|
||||||
srsran_assert(running(), "scheduler worker::run() called for non-active worker");
|
srsran_assert(running(), "scheduler worker::run() called for non-active worker");
|
||||||
|
|
||||||
// Prioritize PDCCH scheduling for DL and UL data in a RoundRobin fashion
|
bwp_alloc.new_slot(tti_rx + TX_ENB_DELAY);
|
||||||
if ((tti_rx.to_uint() & 0x1u) == 0) {
|
|
||||||
alloc_dl_ues();
|
// Allocate pending RARs
|
||||||
alloc_ul_ues();
|
cell.bwps[0].ra.run_slot(bwp_alloc);
|
||||||
} else {
|
|
||||||
alloc_ul_ues();
|
// TODO: Prioritize PDCCH scheduling for DL and UL data in a Round-Robin fashion
|
||||||
alloc_dl_ues();
|
alloc_dl_ues();
|
||||||
}
|
alloc_ul_ues();
|
||||||
|
|
||||||
|
// Log CC scheduler result
|
||||||
|
log_result();
|
||||||
}
|
}
|
||||||
|
|
||||||
void slot_cc_worker::end_tti()
|
void slot_cc_worker::end_tti()
|
||||||
|
@ -81,10 +87,11 @@ void slot_cc_worker::alloc_dl_ues()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rbgmask_t dlmask(cfg.cell_cfg.nof_rbg);
|
rbgmask_t dlmask(cfg.bwps[0].N_rbg);
|
||||||
dlmask.fill(0, dlmask.size(), true);
|
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()
|
void slot_cc_worker::alloc_ul_ues()
|
||||||
{
|
{
|
||||||
if (slot_ues.empty()) {
|
if (slot_ues.empty()) {
|
||||||
|
@ -95,69 +102,99 @@ void slot_cc_worker::alloc_ul_ues()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rbgmask_t ulmask(cfg.cell_cfg.nof_rbg);
|
rbgmask_t ulmask(cfg.bwps[0].N_rbg);
|
||||||
ulmask.fill(0, ulmask.size(), true);
|
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) {
|
for (uint32_t cc = 0; cc < cfg.cells.size(); ++cc) {
|
||||||
cell_grid_list.emplace_back(cfg.cells[cc]);
|
cell_grid_list.emplace_back(cfg.cells[cc]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: For now, we only allow parallelism at the sector level
|
// 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) {
|
for (size_t i = 0; i < cfg.sched_cfg.nof_concurrent_subframes; ++i) {
|
||||||
slot_ctxts[i].reset(new slot_worker_ctxt());
|
slot_worker_ctxts[i].reset(new slot_worker_ctxt());
|
||||||
sem_init(&slot_ctxts[i]->sf_sem, 0, 1);
|
slot_worker_ctxts[i]->workers.reserve(cfg.cells.size());
|
||||||
slot_ctxts[i]->workers.reserve(cfg.cells.size());
|
|
||||||
for (uint32_t cc = 0; cc < cfg.cells.size(); ++cc) {
|
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()
|
sched_worker_manager::~sched_worker_manager() = default;
|
||||||
{
|
|
||||||
// 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::slot_worker_ctxt& sched_worker_manager::get_sf(tti_point tti_rx)
|
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);
|
||||||
auto& sf_worker_ctxt = get_sf(tti_rx_);
|
|
||||||
sem_wait(&sf_worker_ctxt.sf_sem);
|
|
||||||
|
|
||||||
sf_worker_ctxt.tti_rx = 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
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(tti_rx, ue_db);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
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();
|
||||||
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");
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sched_worker_manager::run_tti(tti_point tti_rx_, uint32_t cc, slot_res_t& tti_req)
|
bool sched_worker_manager::run_slot(tti_point tti_rx_, uint32_t cc)
|
||||||
{
|
{
|
||||||
auto& sf_worker_ctxt = get_sf(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.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
|
// Get {tti, cc} scheduling decision
|
||||||
sf_worker_ctxt.workers[cc].run();
|
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
|
// decrement the number of active workers
|
||||||
int rem_workers = sf_worker_ctxt.worker_count.fetch_sub(1, std::memory_order_release) - 1;
|
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)");
|
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;
|
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_);
|
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.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)");
|
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
|
{
|
||||||
for (slot_cc_worker& worker : sf_worker_ctxt.workers) {
|
std::lock_guard<std::mutex> lock(ue_db_mutex);
|
||||||
worker.end_tti();
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sem_post(&sf_worker_ctxt.sf_sem);
|
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();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sched_nr_impl
|
} // namespace sched_nr_impl
|
||||||
|
|
|
@ -288,6 +288,7 @@ uint32_t sched_ue_cell::get_aggr_level(uint32_t nof_bits) const
|
||||||
} else {
|
} else {
|
||||||
dl_cqi = dl_cqi_ctxt.get_avg_cqi();
|
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,
|
return srsenb::get_aggr_level(nof_bits,
|
||||||
dl_cqi,
|
dl_cqi,
|
||||||
cell_cfg->sched_cfg->min_aggr_level,
|
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)
|
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)) {
|
if (not has_tti(tti)) {
|
||||||
return nullptr;
|
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)
|
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())) {
|
if (not pdu_map.has_space(tti.to_uint())) {
|
||||||
logger->error("UE buffers: could not allocate buffer for tti=%d", tti.to_uint());
|
logger->error("UE buffers: could not allocate buffer for tti=%d", tti.to_uint());
|
||||||
return nullptr;
|
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)
|
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;
|
static const uint32_t old_tti_threshold = SRSRAN_FDD_NOF_HARQ + 4;
|
||||||
|
|
||||||
tti_point max_tti{current_tti - old_tti_threshold};
|
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)
|
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");
|
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);
|
return cc_buffers[enb_cc_idx].get_rx_used_buffers().request_pdu(tti_point(tti), len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ue::clear_old_buffers(uint32_t tti)
|
void ue::clear_old_buffers(uint32_t tti)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(rx_buffers_mutex);
|
|
||||||
// remove old buffers
|
// remove old buffers
|
||||||
for (auto& cc : cc_buffers) {
|
for (auto& cc : cc_buffers) {
|
||||||
cc.get_rx_used_buffers().clear_old_pdus(tti_point{tti});
|
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)
|
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));
|
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;
|
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;
|
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_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_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_to_add_mod_s meas_obj = {};
|
||||||
meas_obj.meas_obj_id = 1;
|
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.set_meas_obj_eutra();
|
||||||
meas_obj.meas_obj.meas_obj_eutra().carrier_freq = 300;
|
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().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().presence_ant_port1 = false;
|
||||||
meas_obj.meas_obj.meas_obj_eutra().neigh_cell_cfg.from_number(0b01);
|
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_obj_to_add_mod_s meas_obj2 = {};
|
||||||
meas_obj2.meas_obj_id = 2;
|
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.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().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();
|
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().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.set_present(true);
|
||||||
meas_obj2.meas_obj.meas_obj_nr_r15().band_nr_r15.get()->set_setup() = 78;
|
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
|
// report config
|
||||||
meas_cfg.report_cfg_to_add_mod_list_present = true;
|
meas_cfg.report_cfg_to_add_mod_list_present = true;
|
||||||
meas_cfg.report_cfg_to_add_mod_list.resize(1);
|
report_cfg_to_add_mod_s report_cfg = {};
|
||||||
auto& report_cfg = meas_cfg.report_cfg_to_add_mod_list[0];
|
|
||||||
|
|
||||||
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.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.set_event();
|
||||||
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.event().event_id.set_event_b1_nr_r15();
|
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_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_rsrq = true;
|
||||||
report_cfg.report_cfg.report_cfg_inter_rat().report_quant_cell_nr_r15.get()->ss_sinr = 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
|
// measIdToAddModList
|
||||||
meas_cfg.meas_id_to_add_mod_list_present = true;
|
meas_cfg.meas_id_to_add_mod_list_present = true;
|
||||||
meas_cfg.meas_id_to_add_mod_list.resize(1);
|
meas_id_to_add_mod_s meas_id = {};
|
||||||
auto& meas_id = meas_cfg.meas_id_to_add_mod_list[0];
|
meas_id.meas_id = meas_obj.meas_obj_id;
|
||||||
meas_id.meas_id = 1;
|
meas_id.meas_obj_id = meas_obj2.meas_obj_id;
|
||||||
meas_id.meas_obj_id = 2;
|
meas_id.report_cfg_id = report_cfg.report_cfg_id;
|
||||||
meas_id.report_cfg_id = 1;
|
meas_cfg.meas_id_to_add_mod_list.push_back(meas_id);
|
||||||
|
|
||||||
// quantityConfig
|
// quantityConfig
|
||||||
meas_cfg.quant_cfg_present = true;
|
meas_cfg.quant_cfg_present = true;
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "srsenb/hdr/stack/rrc/ue_rr_cfg.h"
|
#include "srsenb/hdr/stack/rrc/ue_rr_cfg.h"
|
||||||
#include "srsran/asn1/rrc_utils.h"
|
#include "srsran/asn1/rrc_utils.h"
|
||||||
#include "srsran/common/enb_events.h"
|
#include "srsran/common/enb_events.h"
|
||||||
|
#include "srsran/common/srsran_assert.h"
|
||||||
#include "srsran/common/standard_streams.h"
|
#include "srsran/common/standard_streams.h"
|
||||||
#include "srsran/interfaces/enb_pdcp_interfaces.h"
|
#include "srsran/interfaces/enb_pdcp_interfaces.h"
|
||||||
#include "srsran/interfaces/enb_rlc_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)
|
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) {
|
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) {
|
if (pending_rr_cfg.drb_to_release_list.size() > 0) {
|
||||||
for (uint8_t drb_id : pending_rr_cfg.drb_to_release_list) {
|
for (uint8_t drb_id : pending_rr_cfg.drb_to_release_list) {
|
||||||
parent->rlc->del_bearer(rnti, drb_to_lcid((lte_drb)drb_id));
|
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) {
|
if (not drb.rlc_cfg_present) {
|
||||||
parent->logger.warning("Default RLC DRB config not supported");
|
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…
Reference in New Issue