Merge branch 'next' into agpl_next

# Conflicts:
#	srsue/src/phy/nr/state.cc
master
srsLTE codebot 4 years ago committed by Your Name
commit d290fe9714

@ -371,8 +371,6 @@ static void base_init()
exit(-1);
}
srslte_pdsch_set_rnti(&pdsch, UE_CRNTI);
if (mbsfn_area_id > -1) {
if (srslte_pmch_init(&pmch, cell.nof_prb, 1)) {
ERROR("Error creating PMCH object");

@ -633,9 +633,6 @@ int main(int argc, char** argv)
pdsch_cfg.rnti = prog_args.rnti;
/* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */
srslte_ue_dl_set_rnti(&ue_dl, prog_args.rnti);
/* Configure MBSFN area id and non-MBSFN Region */
if (prog_args.mbsfn_area_id > -1) {
srslte_ue_dl_set_mbsfn_area_id(&ue_dl, prog_args.mbsfn_area_id);

@ -23,6 +23,7 @@
#define SRSLTE_CIRCULAR_ARRAY_H
#include <array>
#include <cstddef>
/**
*

@ -141,7 +141,7 @@ public:
}
uint32_t get_headroom() { return msg - buffer; }
// Returns the remaining space from what is reported to be the length of msg
uint32_t get_tailroom() { return (sizeof(buffer) - (msg - buffer) - N_bytes); }
uint32_t get_tailroom() const { return (sizeof(buffer) - (msg - buffer) - N_bytes); }
std::chrono::microseconds get_latency_us() const { return md.tp.get_latency_us(); }
std::chrono::high_resolution_clock::time_point get_timestamp() const { return md.tp.get_timestamp(); }
@ -156,6 +156,9 @@ public:
N_bytes += size;
}
// vector-like interface
void resize(size_t size) { N_bytes = size; }
size_t capacity() const { return get_tailroom(); }
uint8_t* data() { return msg; }
const uint8_t* data() const { return msg; }
uint32_t size() const { return N_bytes; }

@ -22,91 +22,26 @@
#ifndef SRSLTE_MAC_PCAP_H
#define SRSLTE_MAC_PCAP_H
#include "srslte/common/block_queue.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/pcap.h"
#include "srslte/common/threads.h"
#include "srslte/srslog/srslog.h"
#include <mutex>
#include <stdint.h>
#include <thread>
#include "srslte/common/mac_pcap_base.h"
#include "srslte/srslte.h"
namespace srslte {
class mac_pcap : srslte::thread
class mac_pcap : public mac_pcap_base
{
public:
mac_pcap(srslte_rat_t rat);
mac_pcap();
~mac_pcap();
void enable(bool enable);
uint32_t open(std::string filename, uint32_t ue_id = 0);
uint32_t close();
void set_ue_id(uint16_t ue_id);
// EUTRA
void
write_ul_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint32_t reTX, uint32_t tti, uint8_t cc_idx);
void write_dl_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, bool crc_ok, uint32_t tti, uint8_t cc_idx);
void write_dl_ranti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t ranti, bool crc_ok, uint32_t tti, uint8_t cc_idx);
// SI and BCH only for DL
void write_dl_sirnti(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx);
void write_dl_bch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx);
void write_dl_pch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx);
void write_dl_mch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx);
void write_ul_rrc_pdu(const uint8_t* input, const int32_t input_len);
// Sidelink
void write_sl_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint32_t reTX, uint32_t tti, uint8_t cc_idx);
// NR
void write_dl_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint8_t harqid, uint32_t tti);
void write_ul_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
void write_dl_ra_rnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
void write_dl_bch_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
void write_dl_pch_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
void write_dl_si_rnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
private:
srslog::basic_logger& logger;
bool running = false;
srslte_rat_t rat = srslte_rat_t::nulltype;
void write_pdu(srslte::mac_pcap_base::pcap_pdu_t& pdu);
FILE* pcap_file = nullptr;
uint32_t dlt = 0; // The DLT used for the PCAP file
std::string filename;
FILE* pcap_file = nullptr;
uint32_t ue_id = 0;
void pack_and_queue(uint8_t* payload,
uint32_t payload_len,
uint32_t reTX,
bool crc_ok,
uint8_t cc_idx,
uint32_t tti,
uint16_t crnti_,
uint8_t direction,
uint8_t rnti_type);
void pack_and_queue_nr(uint8_t* payload,
uint32_t payload_len,
uint32_t tti,
uint16_t crnti,
uint8_t harqid,
uint8_t direction,
uint8_t rnti_type);
typedef struct {
// Different PCAP context for both RATs
MAC_Context_Info_t context;
mac_nr_context_info_t context_nr;
unique_byte_buffer_t pdu;
} pcap_pdu_t;
block_queue<pcap_pdu_t> queue;
std::mutex mutex;
void write_pdu(pcap_pdu_t& pdu);
void run_thread() final;
};
} // namespace srslte
#endif // SRSLTE_MAC_PCAP_H

@ -0,0 +1,125 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 SRSLTE_MAC_PCAP_BASE_H
#define SRSLTE_MAC_PCAP_BASE_H
#include "srslte/common/block_queue.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/pcap.h"
#include "srslte/common/threads.h"
#include "srslte/srslog/srslog.h"
#include <mutex>
#include <stdint.h>
#include <thread>
namespace srslte {
class mac_pcap_base : protected srslte::thread
{
public:
mac_pcap_base();
~mac_pcap_base();
void enable(bool enable);
virtual uint32_t close() = 0;
void set_ue_id(uint16_t ue_id);
// EUTRA
void
write_ul_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint32_t reTX, uint32_t tti, uint8_t cc_idx);
void write_dl_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, bool crc_ok, uint32_t tti, uint8_t cc_idx);
void write_dl_ranti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t ranti, bool crc_ok, uint32_t tti, uint8_t cc_idx);
void write_ul_crnti(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint16_t crnti,
uint16_t ue_id,
uint32_t reTX,
uint32_t tti,
uint8_t cc_idx);
void write_dl_crnti(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint16_t crnti,
uint16_t ue_id,
bool crc_ok,
uint32_t tti,
uint8_t cc_idx);
// SI and BCH only for DL
void write_dl_sirnti(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx);
void write_dl_bch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx);
void write_dl_pch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx);
void write_dl_mch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx);
void write_ul_rrc_pdu(const uint8_t* input, const int32_t input_len);
// Sidelink
void write_sl_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint32_t reTX, uint32_t tti, uint8_t cc_idx);
// NR
void write_dl_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint8_t harqid, uint32_t tti);
void write_ul_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
void write_dl_ra_rnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
void write_dl_bch_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
void write_dl_pch_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
void write_dl_si_rnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
// NR for enb with different ue_id
// clang-format off
void write_dl_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint16_t ue_id, uint8_t harqid, uint32_t tti);
void write_ul_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint16_t ue_id, uint8_t harqid, uint32_t tti);
// clang-format on
protected:
typedef struct {
// Different PCAP context for both RATs
srslte::srslte_rat_t rat;
MAC_Context_Info_t context;
mac_nr_context_info_t context_nr;
unique_byte_buffer_t pdu;
} pcap_pdu_t;
virtual void write_pdu(pcap_pdu_t& pdu) = 0;
void run_thread() final;
std::mutex mutex;
srslog::basic_logger& logger;
bool running = false;
block_queue<pcap_pdu_t> queue;
uint16_t ue_id = 0;
private:
void pack_and_queue(uint8_t* payload,
uint32_t payload_len,
uint16_t ue_id,
uint32_t reTX,
bool crc_ok,
uint8_t cc_idx,
uint32_t tti,
uint16_t crnti_,
uint8_t direction,
uint8_t rnti_type);
void pack_and_queue_nr(uint8_t* payload,
uint32_t payload_len,
uint32_t tti,
uint16_t crnti,
uint16_t ue_id,
uint8_t harqid,
uint8_t direction,
uint8_t rnti_type);
};
} // namespace srslte
#endif // SRSLTE_MAC_PCAP_BASE_H

@ -0,0 +1,44 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 SRSLTE_MAC_PCAP_NET_H
#define SRSLTE_MAC_PCAP_NET_H
#include "srslte/common/common.h"
#include "srslte/common/mac_pcap_base.h"
#include "srslte/common/network_utils.h"
#include "srslte/srslte.h"
namespace srslte {
class mac_pcap_net : public mac_pcap_base
{
public:
mac_pcap_net();
~mac_pcap_net();
uint32_t open(std::string client_ip_addr_,
std::string bind_addr_str = "0.0.0.0",
uint16_t client_udp_port_ = 5847,
uint16_t bind_udp_port_ = 5687,
uint32_t ue_id_ = 0);
uint32_t close();
private:
void write_pdu(srslte::mac_pcap_base::pcap_pdu_t& pdu);
void write_mac_lte_pdu_to_net(srslte::mac_pcap_base::pcap_pdu_t& pdu);
void write_mac_nr_pdu_to_net(srslte::mac_pcap_base::pcap_pdu_t& pdu);
srslte::socket_handler_t socket;
struct sockaddr_in client_addr;
};
} // namespace srslte
#endif // SRSLTE_MAC_PCAP_NET_H

@ -23,6 +23,7 @@
#define SRSLTE_NAS_PCAP_H
#include "srslte/common/pcap.h"
#include <string>
namespace srslte {
@ -36,12 +37,13 @@ public:
pcap_file = NULL;
}
void enable();
void open(const char* filename, uint32_t ue_id = 0);
uint32_t open(std::string filename_, uint32_t ue_id = 0);
void close();
void write_nas(uint8_t* pdu, uint32_t pdu_len_bytes);
private:
bool enable_write;
std::string filename;
FILE* pcap_file;
uint32_t ue_id;
void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes);

@ -26,6 +26,8 @@
#include <stdbool.h>
#include <stdio.h>
#define PCAP_CONTEXT_HEADER_MAX 256
#define MAC_LTE_DLT 147
#define NAS_LTE_DLT 148
#define UDP_DLT 149 // UDP needs to be selected as protocol
@ -198,6 +200,8 @@ void LTE_PCAP_Close(FILE* fd);
/* Write an individual MAC PDU (PCAP packet header + mac-context + mac-pdu) */
int LTE_PCAP_MAC_WritePDU(FILE* fd, MAC_Context_Info_t* context, const unsigned char* PDU, unsigned int length);
int LTE_PCAP_MAC_UDP_WritePDU(FILE* fd, MAC_Context_Info_t* context, const unsigned char* PDU, unsigned int length);
int LTE_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(MAC_Context_Info_t* context, uint8_t* PDU, unsigned int length);
/* Write an individual NAS PDU (PCAP packet header + nas-context + nas-pdu) */
int LTE_PCAP_NAS_WritePDU(FILE* fd, NAS_Context_Info_t* context, const unsigned char* PDU, unsigned int length);
@ -209,7 +213,8 @@ int LTE_PCAP_RLC_WritePDU(FILE* fd, RLC_Context_Info_t* context, const unsigned
int LTE_PCAP_S1AP_WritePDU(FILE* fd, S1AP_Context_Info_t* context, const unsigned char* PDU, unsigned int length);
/* Write an individual NR MAC PDU (PCAP packet header + UDP header + nr-mac-context + mac-pdu) */
int NR_PCAP_MAC_WritePDU(FILE* fd, mac_nr_context_info_t* context, const unsigned char* PDU, unsigned int length);
int NR_PCAP_MAC_UDP_WritePDU(FILE* fd, mac_nr_context_info_t* context, const unsigned char* PDU, unsigned int length);
int NR_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(mac_nr_context_info_t* context, uint8_t* buffer, unsigned int length);
#ifdef __cplusplus
}

@ -32,26 +32,17 @@ namespace srslte {
class task_scheduler
{
public:
explicit task_scheduler(uint32_t default_extern_tasks_size = 512,
uint32_t nof_background_threads = 0,
uint32_t nof_timers_prealloc = 100) :
external_tasks{default_extern_tasks_size},
timers{nof_timers_prealloc},
background_tasks{nof_background_threads}
explicit task_scheduler(uint32_t default_extern_tasks_size = 512, uint32_t nof_timers_prealloc = 100) :
external_tasks{default_extern_tasks_size}, timers{nof_timers_prealloc}
{
background_queue_id = external_tasks.add_queue();
// Start background thread
if (background_tasks.nof_workers() > 0) {
background_tasks.start();
}
}
task_scheduler(const task_scheduler&) = delete;
task_scheduler(task_scheduler&&) = delete;
task_scheduler& operator=(const task_scheduler&) = delete;
task_scheduler& operator=(task_scheduler&&) = delete;
void stop()
{
background_tasks.stop();
external_tasks.reset();
}
void stop() { external_tasks.reset(); }
srslte::unique_timer get_unique_timer() { return timers.get_unique_timer(); }
@ -65,17 +56,6 @@ public:
//! Enqueues internal task to be run in next tic
void defer_task(srslte::move_task_t func) { internal_tasks.push_back(std::move(func)); }
//! Delegates a task to a thread pool that runs in the background
void enqueue_background_task(std::function<void(uint32_t)> f)
{
if (background_tasks.nof_workers() > 0) {
background_tasks.push_task(std::move(f));
} else {
external_tasks.push(background_queue_id,
std::bind([](const std::function<void(uint32_t)>& task) { task(0); }, std::move(f)));
}
}
//! Defer the handling of the result of a background task to next tic
void notify_background_task_result(srslte::move_task_t task)
{
@ -126,7 +106,6 @@ private:
}
}
srslte::task_thread_pool background_tasks; ///< Thread pool used for long, low-priority tasks
int background_queue_id = -1; ///< Queue for handling the outcomes of tasks run in the background
srslte::task_multiqueue external_tasks;
srslte::timer_handler timers;
@ -140,7 +119,6 @@ public:
task_sched_handle(task_scheduler* sched_) : sched(sched_) {}
srslte::unique_timer get_unique_timer() { return sched->get_unique_timer(); }
void enqueue_background_task(std::function<void(uint32_t)> f) { sched->enqueue_background_task(std::move(f)); }
void notify_background_task_result(srslte::move_task_t task)
{
sched->notify_background_task_result(std::move(task));
@ -162,7 +140,6 @@ public:
ext_task_sched_handle(task_scheduler* sched_) : sched(sched_) {}
srslte::unique_timer get_unique_timer() { return sched->get_unique_timer(); }
void enqueue_background_task(std::function<void(uint32_t)> f) { sched->enqueue_background_task(std::move(f)); }
void notify_background_task_result(srslte::move_task_t task)
{
sched->notify_background_task_result(std::move(task));

@ -152,6 +152,51 @@ private:
std::atomic<unsigned> warning_counter;
};
/// This custom sink intercepts log messages allowing users to check if a certain log entry has been generated.
/// Calling spy.has_message("something") will return true if any log entries generated so far contain the string
/// "something".
/// The log entries history can be cleared with reset so old entries can be discarded.
class log_sink_message_spy : public srslog::sink
{
public:
explicit log_sink_message_spy(std::unique_ptr<srslog::log_formatter> f) :
srslog::sink(std::move(f)), s(srslog::get_default_sink())
{}
/// Identifier of this custom sink.
static const char* name() { return "log_sink_message_spy"; }
/// Discards all registered log entries.
void reset()
{
// Flush to make sure all entries have been processed by the backend.
srslog::flush();
entries.clear();
}
/// Returns true if the string in msg is found in the registered log entries.
bool has_message(const std::string& msg) const
{
srslog::flush();
return std::find_if(entries.cbegin(), entries.cend(), [&](const std::string& entry) {
return entry.find(msg) != std::string::npos;
}) != entries.cend();
}
srslog::detail::error_string write(srslog::detail::memory_buffer buffer) override
{
entries.emplace_back(buffer.data(), buffer.size());
return s.write(buffer);
}
srslog::detail::error_string flush() override { return s.flush(); }
private:
srslog::sink& s;
std::vector<std::string> entries;
};
// specialization of test_log_filter to store last logged message
class nullsink_log : public test_log_filter
{

@ -29,6 +29,8 @@
#ifndef SRSLTE_THREAD_POOL_H
#define SRSLTE_THREAD_POOL_H
#include "srslte/adt/move_callback.h"
#include "srslte/srslog/srslog.h"
#include <condition_variable>
#include <functional>
#include <memory>
@ -95,17 +97,22 @@ private:
class task_thread_pool
{
using task_t = std::function<void(uint32_t worker_id)>;
using task_t = srslte::move_callback<void()>;
public:
explicit task_thread_pool(uint32_t nof_workers);
task_thread_pool(uint32_t nof_workers = 1, bool start_deferred = false, int32_t prio_ = -1, uint32_t mask_ = 255);
task_thread_pool(const task_thread_pool&) = delete;
task_thread_pool(task_thread_pool&&) = delete;
task_thread_pool& operator=(const task_thread_pool&) = delete;
task_thread_pool& operator=(task_thread_pool&&) = delete;
~task_thread_pool();
void start(int32_t prio = -1, uint32_t mask = 255);
void stop();
void start(int32_t prio_ = -1, uint32_t mask_ = 255);
void set_nof_workers(uint32_t nof_workers);
void push_task(const task_t& task);
void push_task(task_t&& task);
uint32_t nof_pending_tasks();
uint32_t nof_pending_tasks() const;
size_t nof_workers() const { return workers.size(); }
private:
@ -114,7 +121,6 @@ private:
public:
explicit worker_t(task_thread_pool* parent_, uint32_t id);
void stop();
void setup(int32_t prio, uint32_t mask);
bool is_running() const { return running; }
uint32_t id() const { return id_; }
@ -128,13 +134,19 @@ private:
bool running = false;
};
int32_t prio = -1;
uint32_t mask = 255;
srslog::basic_logger& logger;
std::queue<task_t> pending_tasks;
std::vector<worker_t> workers;
std::mutex queue_mutex;
std::vector<std::unique_ptr<worker_t> > workers;
mutable std::mutex queue_mutex;
std::condition_variable cv_empty;
bool running;
bool running = false;
};
srslte::task_thread_pool& get_background_workers();
} // namespace srslte
#endif // SRSLTE_THREAD_POOL_H

@ -189,8 +189,6 @@ public:
void stop() { impl()->stop(); }
void clear() { impl()->clear(); }
void release()
{
impl()->clear();

@ -29,6 +29,7 @@
#include "srsenb/hdr/stack/rrc/rrc_metrics.h"
#include "srsenb/hdr/stack/upper/common_enb.h"
#include "srsenb/hdr/stack/upper/s1ap_metrics.h"
#include "srslte/system/sys_metrics.h"
#include "srslte/common/metrics_hub.h"
#include "srslte/radio/radio_metrics.h"
#include "srslte/upper/pdcp_metrics.h"
@ -57,6 +58,7 @@ struct enb_metrics_t {
srslte::rf_metrics_t rf;
std::vector<phy_metrics_t> phy;
stack_metrics_t stack;
srslte::sys_metrics_t sys;
bool running;
};

@ -37,14 +37,6 @@ public:
*/
virtual void rem_rnti(uint16_t rnti) = 0;
/**
* Pregenerates the scrambling sequences for a given RNTI.
* WARNING: This function make take several ms to complete.
*
* @param rnti identifier of the user
*/
virtual int pregen_sequences(uint16_t rnti) = 0;
/**
*
* @param stop

@ -22,7 +22,7 @@
#ifndef SRSLTE_PHY_INTERFACE_TYPES_H
#define SRSLTE_PHY_INTERFACE_TYPES_H
#include "srslte/phy/phch/prach.h"
#include "srslte/srslte.h"
/// Common types defined by the PHY layer.
@ -49,4 +49,31 @@ inline bool operator!=(const srslte_prach_cfg_t& a, const srslte_prach_cfg_t& b)
return !(a == b);
}
namespace srsue {
struct phy_meas_nr_t {
float rsrp;
float rsrq;
float sinr;
float cfo_hz;
uint32_t arfcn_nr;
uint32_t pci_nr;
};
struct phy_meas_t {
float rsrp;
float rsrq;
float cfo_hz;
uint32_t earfcn;
uint32_t pci;
};
struct phy_cell_t {
uint32_t pci;
uint32_t earfcn;
float cfo_hz;
};
} // namespace srsue
#endif // SRSLTE_PHY_INTERFACE_TYPES_H

@ -22,8 +22,8 @@
#ifndef SRSLTE_RRC_INTERFACE_TYPES_H
#define SRSLTE_RRC_INTERFACE_TYPES_H
#include "srslte/common/common.h"
#include "srslte/common/bcd_helpers.h"
#include "srslte/common/common.h"
#include "srslte/config.h"
#include "srslte/srslte.h"
#include <string>

@ -39,6 +39,7 @@ struct phy_cfg_nr_t {
srslte_prach_cfg_t prach = {};
srslte_ue_dl_nr_pdcch_cfg_t pdcch = {};
srslte_ue_dl_nr_harq_ack_cfg_t harq_ack = {};
srslte_csi_hl_cfg_t csi = {};
phy_cfg_nr_t()
{
@ -507,6 +508,13 @@ struct phy_cfg_nr_t {
// nrofSymbols: 14
// startingSymbolIndex: 0
// timeDomainOCC: 2
pucch.sr_resources[1].resource.format = SRSLTE_PUCCH_NR_FORMAT_1;
pucch.sr_resources[1].resource.starting_prb = 0;
pucch.sr_resources[1].resource.initial_cyclic_shift = 8;
pucch.sr_resources[1].resource.nof_symbols = 14;
pucch.sr_resources[1].resource.start_symbol_idx = 0;
pucch.sr_resources[1].resource.time_domain_occ = 2;
// Item 17
// PUCCH-Resource
// pucch-ResourceId: 17
@ -516,6 +524,13 @@ struct phy_cfg_nr_t {
// nrofPRBs: 1
// nrofSymbols: 2
// startingSymbolIndex: 2
srslte_pucch_nr_resource_t pucch_res_17 = {};
pucch_res_17.starting_prb = 1;
pucch_res_17.format = SRSLTE_PUCCH_NR_FORMAT_2;
pucch_res_17.nof_prb = 1;
pucch_res_17.nof_symbols = 2;
pucch_res_17.start_symbol_idx = 2;
// format1: setup (1)
// setup
// format2: setup (1)
@ -529,6 +544,7 @@ struct phy_cfg_nr_t {
}
}
}
pucch_res_17.max_code_rate = 2;
// schedulingRequestResourceToAddModList: 1 item
// Item 0
@ -538,6 +554,10 @@ struct phy_cfg_nr_t {
// periodicityAndOffset: sl40 (10)
// sl40: 8
// resource: 16
pucch.sr_resources[1].sr_id = 0;
pucch.sr_resources[1].period = 40;
pucch.sr_resources[1].offset = 8;
pucch.sr_resources[1].configured = true;
// dl-DataToUL-ACK: 7 items
// Item 0
@ -562,6 +582,42 @@ struct phy_cfg_nr_t {
harq_ack.dl_data_to_ul_ack[5] = 12;
harq_ack.dl_data_to_ul_ack[6] = 11;
harq_ack.nof_dl_data_to_ul_ack = 7;
// csi-ReportConfigToAddModList: 1 item
// Item 0
// CSI-ReportConfig
// reportConfigId: 0
// resourcesForChannelMeasurement: 0
// csi-IM-ResourcesForInterference: 1
// reportConfigType: periodic (0)
// periodic
// reportSlotConfig: slots80 (7)
// slots80: 9
// pucch-CSI-ResourceList: 1 item
// Item 0
// PUCCH-CSI-Resource
// uplinkBandwidthPartId: 0
// pucch-Resource: 17
// reportQuantity: cri-RI-PMI-CQI (1)
// cri-RI-PMI-CQI: NULL
// reportFreqConfiguration
// cqi-FormatIndicator: widebandCQI (0)
// timeRestrictionForChannelMeasurements: notConfigured (1)
// timeRestrictionForInterferenceMeasurements: notConfigured (1)
// groupBasedBeamReporting: disabled (1)
// disabled
// cqi-Table: table2 (1)
// subbandSize: value1 (0)
csi.reports[0].type = SRSLTE_CSI_REPORT_TYPE_PERIODIC;
csi.reports[0].channel_meas_id = 0;
csi.reports[0].interf_meas_present = true;
csi.reports[0].interf_meas_id = 1;
csi.reports[0].periodic.period = 80;
csi.reports[0].periodic.offset = 9;
csi.reports[0].periodic.resource = pucch_res_17;
csi.reports[0].quantity = SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI;
csi.reports[0].freq_cfg = SRSLTE_CSI_REPORT_FREQ_WIDEBAND;
csi.reports[0].cqi_table = SRSLTE_CSI_CQI_TABLE_2;
}
};
} // namespace srslte

@ -63,10 +63,10 @@ public:
uint32_t min_nof_ctrl_symbols = 1;
uint32_t max_nof_ctrl_symbols = 3;
int max_aggr_level = 3;
bool pucch_mux_enabled = false;
};
struct cell_cfg_t {
// Main cell configuration (used to calculate DCI locations in scheduler)
srslte_cell_t cell;

@ -0,0 +1,67 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 SRSLTE_UE_GW_INTERFACES_H
#define SRSLTE_UE_GW_INTERFACES_H
#include "srslte/asn1/liblte_mme.h"
namespace srsue {
class gw_interface_nas
{
public:
virtual int setup_if_addr(uint32_t eps_bearer_id,
uint32_t lcid,
uint8_t pdn_type,
uint32_t ip_addr,
uint8_t* ipv6_if_id,
char* err_str) = 0;
virtual int apply_traffic_flow_template(const uint8_t& eps_bearer_id,
const uint8_t& lcid,
const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft) = 0;
typedef enum {
TEST_LOOP_INACTIVE = 0,
TEST_LOOP_MODE_A_ACTIVE,
TEST_LOOP_MODE_B_ACTIVE,
TEST_LOOP_MODE_C_ACTIVE
} test_loop_mode_state_t;
/**
* Updates the test loop mode. The IP delay parameter is only valid for Mode B.
* @param mode
* @param ip_pdu_delay_ms The PDU delay in ms
*/
virtual void set_test_loop_mode(const test_loop_mode_state_t mode, const uint32_t ip_pdu_delay_ms = 0) = 0;
};
class gw_interface_rrc
{
public:
virtual void add_mch_port(uint32_t lcid, uint32_t port) = 0;
virtual int update_lcid(uint32_t eps_bearer_id, uint32_t new_lcid) = 0;
};
class gw_interface_pdcp
{
public:
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
};
class gw_interface_stack : public gw_interface_nas, public gw_interface_rrc, public gw_interface_pdcp
{};
} // namespace srsue
#endif // SRSLTE_UE_GW_INTERFACES_H

@ -28,658 +28,11 @@
#ifndef SRSLTE_UE_INTERFACES_H
#define SRSLTE_UE_INTERFACES_H
#include <set>
#include <string>
#include "mac_interface_types.h"
#include "pdcp_interface_types.h"
#include "rlc_interface_types.h"
#include "rrc_interface_types.h"
#include "srslte/asn1/asn1_utils.h"
#include "srslte/asn1/liblte_mme.h"
#include "srslte/common/common.h"
#include "srslte/common/interfaces_common.h"
#include "srslte/common/security.h"
#include "srslte/common/stack_procedure.h"
#include "srslte/common/tti_point.h"
#include "srslte/phy/channel/channel.h"
#include "srslte/phy/rf/rf.h"
#include "srslte/upper/pdcp_entity_base.h"
#include "ue_mac_interfaces.h"
#include "ue_rrc_interfaces.h"
namespace srsue {
typedef enum { AUTH_OK, AUTH_FAILED, AUTH_SYNCH_FAILURE } auth_result_t;
// USIM interface for NAS
class usim_interface_nas
{
public:
virtual std::string get_imsi_str() = 0;
virtual std::string get_imei_str() = 0;
virtual bool get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0;
virtual bool get_imei_vec(uint8_t* imei_, uint32_t n) = 0;
virtual bool get_home_plmn_id(srslte::plmn_id_t* home_plmn_id) = 0;
virtual auth_result_t generate_authentication_response(uint8_t* rand,
uint8_t* autn_enb,
uint16_t mcc,
uint16_t mnc,
uint8_t* res,
int* res_len,
uint8_t* k_asme) = 0;
virtual void generate_nas_keys(uint8_t* k_asme,
uint8_t* k_nas_enc,
uint8_t* k_nas_int,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0;
};
// USIM interface for RRC
class usim_interface_rrc
{
public:
virtual void generate_as_keys(uint8_t* k_asme, uint32_t count_ul, srslte::as_security_config_t* sec_cfg) = 0;
virtual void generate_as_keys_ho(uint32_t pci, uint32_t earfcn, int ncc, srslte::as_security_config_t* sec_cfg) = 0;
virtual void store_keys_before_ho(const srslte::as_security_config_t& as_cfg) = 0;
virtual void restore_keys_from_failed_ho(srslte::as_security_config_t* as_cfg) = 0;
};
// GW interface for NAS
class gw_interface_nas
{
public:
virtual int setup_if_addr(uint32_t eps_bearer_id,
uint32_t lcid,
uint8_t pdn_type,
uint32_t ip_addr,
uint8_t* ipv6_if_id,
char* err_str) = 0;
virtual int apply_traffic_flow_template(const uint8_t& eps_bearer_id,
const uint8_t& lcid,
const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft) = 0;
typedef enum {
TEST_LOOP_INACTIVE = 0,
TEST_LOOP_MODE_A_ACTIVE,
TEST_LOOP_MODE_B_ACTIVE,
TEST_LOOP_MODE_C_ACTIVE
} test_loop_mode_state_t;
/**
* Updates the test loop mode. The IP delay parameter is only valid for Mode B.
* @param mode
* @param ip_pdu_delay_ms The PDU delay in ms
*/
virtual void set_test_loop_mode(const test_loop_mode_state_t mode, const uint32_t ip_pdu_delay_ms = 0) = 0;
};
// GW interface for RRC
class gw_interface_rrc
{
public:
virtual void add_mch_port(uint32_t lcid, uint32_t port) = 0;
virtual int update_lcid(uint32_t eps_bearer_id, uint32_t new_lcid) = 0;
};
// GW interface for PDCP
class gw_interface_pdcp
{
public:
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
};
// RRC interface for MAC
class rrc_interface_mac_common
{
public:
virtual void ra_problem() = 0;
};
class rrc_interface_mac : public rrc_interface_mac_common
{
public:
virtual void ra_completed() = 0;
virtual void release_pucch_srs() = 0;
};
struct phy_cell_t {
uint32_t pci;
uint32_t earfcn;
float cfo_hz;
};
// Measurement object from phy
typedef struct {
float rsrp;
float rsrq;
float cfo_hz;
uint32_t earfcn;
uint32_t pci;
} phy_meas_t;
typedef struct {
float rsrp;
float rsrq;
float sinr;
float cfo_hz;
uint32_t arfcn_nr;
uint32_t pci_nr;
} phy_meas_nr_t;
// RRC interface for RRC NR
class rrc_eutra_interface_rrc_nr
{
public:
virtual void new_cell_meas_nr(const std::vector<phy_meas_nr_t>& meas) = 0;
virtual void nr_rrc_con_reconfig_complete(bool status) = 0;
};
// RRC interface for PHY
class rrc_interface_phy_lte
{
public:
virtual void in_sync() = 0;
virtual void out_of_sync() = 0;
virtual void new_cell_meas(const std::vector<phy_meas_t>& meas) = 0;
typedef struct {
enum { CELL_FOUND = 0, CELL_NOT_FOUND, ERROR } found;
enum { MORE_FREQS = 0, NO_MORE_FREQS } last_freq;
} cell_search_ret_t;
virtual void cell_search_complete(cell_search_ret_t ret, phy_cell_t found_cell) = 0;
virtual void cell_select_complete(bool status) = 0;
virtual void set_config_complete(bool status) = 0;
virtual void set_scell_complete(bool status) = 0;
};
// RRC interface for NAS
class rrc_interface_nas
{
public:
typedef struct {
srslte::plmn_id_t plmn_id;
uint16_t tac;
} found_plmn_t;
const static int MAX_FOUND_PLMNS = 16;
virtual ~rrc_interface_nas() = default;
virtual void write_sdu(srslte::unique_byte_buffer_t sdu) = 0;
virtual uint16_t get_mcc() = 0;
virtual uint16_t get_mnc() = 0;
virtual void enable_capabilities() = 0;
virtual bool plmn_search() = 0;
virtual void plmn_select(srslte::plmn_id_t plmn_id) = 0;
virtual bool connection_request(srslte::establishment_cause_t cause,
srslte::unique_byte_buffer_t dedicatedInfoNAS) = 0;
virtual void set_ue_identity(srslte::s_tmsi_t s_tmsi) = 0;
virtual bool is_connected() = 0;
virtual void paging_completed(bool outcome) = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
virtual uint32_t get_lcid_for_eps_bearer(const uint32_t& eps_bearer_id) = 0;
virtual bool has_nr_dc() = 0;
};
// RRC interface for PDCP
class rrc_interface_pdcp
{
public:
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t pdu) = 0;
virtual void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t pdu) = 0;
virtual void write_pdu_pcch(srslte::unique_byte_buffer_t pdu) = 0;
virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
};
// RRC interface for RLC
class rrc_interface_rlc
{
public:
virtual void max_retx_attempted() = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
};
// NAS interface for RRC
class nas_interface_rrc
{
public:
virtual void left_rrc_connected() = 0;
virtual void set_barring(srslte::barring_t barring) = 0;
virtual bool paging(srslte::s_tmsi_t* ue_identity) = 0;
virtual bool is_registered() = 0;
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
virtual uint32_t get_k_enb_count() = 0;
virtual bool get_k_asme(uint8_t* k_asme_, uint32_t n) = 0;
virtual uint32_t get_ipv4_addr() = 0;
virtual bool get_ipv6_addr(uint8_t* ipv6_addr) = 0;
virtual void
plmn_search_completed(const rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS],
int nof_plmns) = 0;
virtual bool connection_request_completed(bool outcome) = 0;
};
// PDCP interface for RRC
class pdcp_interface_rrc
{
public:
virtual void reestablish() = 0;
virtual void reestablish(uint32_t lcid) = 0;
virtual void reset() = 0;
virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, int sn = -1) = 0;
virtual void add_bearer(uint32_t lcid, srslte::pdcp_config_t cnfg) = 0;
virtual void change_lcid(uint32_t old_lcid, uint32_t new_lcid) = 0;
virtual void config_security(uint32_t lcid, srslte::as_security_config_t sec_cfg) = 0;
virtual void config_security_all(srslte::as_security_config_t sec_cfg) = 0;
virtual void enable_integrity(uint32_t lcid, srslte::srslte_direction_t direction) = 0;
virtual void enable_encryption(uint32_t lcid,
srslte::srslte_direction_t direction = srslte::srslte_direction_t::DIRECTION_TXRX) = 0;
virtual void send_status_report() = 0;
virtual void send_status_report(uint32_t lcid) = 0;
};
// RRC NR interface for RRC (LTE)
class rrc_nr_interface_rrc
{
public:
virtual void get_eutra_nr_capabilities(srslte::byte_buffer_t* eutra_nr_caps) = 0;
virtual void get_nr_capabilities(srslte::byte_buffer_t* nr_cap) = 0;
virtual void phy_set_cells_to_meas(uint32_t carrier_freq_r15) = 0;
virtual void phy_meas_stop() = 0;
virtual bool rrc_reconfiguration(bool endc_release_and_add_r15,
bool nr_secondary_cell_group_cfg_r15_present,
asn1::dyn_octstring nr_secondary_cell_group_cfg_r15,
bool sk_counter_r15_present,
uint32_t sk_counter_r15,
bool nr_radio_bearer_cfg1_r15_present,
asn1::dyn_octstring nr_radio_bearer_cfg1_r15) = 0;
virtual bool is_config_pending() = 0;
};
class usim_interface_rrc_nr
{
public:
virtual void generate_nr_context(uint16_t sk_counter, srslte::as_security_config_t* sec_cfg) = 0;
virtual void update_nr_context(srslte::as_security_config_t* sec_cfg) = 0;
};
// PDCP interface for RLC
class pdcp_interface_rlc
{
public:
/* RLC calls PDCP to push a PDCP PDU. */
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu) = 0;
virtual void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu) = 0;
virtual void write_pdu_pcch(srslte::unique_byte_buffer_t sdu) = 0;
virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
virtual void notify_delivery(uint32_t lcid, const std::vector<uint32_t>& pdcp_sn) = 0;
virtual void notify_failure(uint32_t lcid, const std::vector<uint32_t>& pdcp_sn) = 0;
};
class pdcp_interface_gw
{
public:
virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
virtual bool is_lcid_enabled(uint32_t lcid) = 0;
};
// RLC interface for RRC
class rlc_interface_rrc
{
public:
virtual void reset() = 0;
virtual void reestablish() = 0;
virtual void reestablish(uint32_t lcid) = 0;
virtual void add_bearer(uint32_t lcid, const srslte::rlc_config_t& cnfg) = 0;
virtual void add_bearer_mrb(uint32_t lcid) = 0;
virtual void del_bearer(uint32_t lcid) = 0;
virtual void suspend_bearer(uint32_t lcid) = 0;
virtual void resume_bearer(uint32_t lcid) = 0;
virtual void change_lcid(uint32_t old_lcid, uint32_t new_lcid) = 0;
virtual bool has_bearer(uint32_t lcid) = 0;
virtual bool has_data(const uint32_t lcid) = 0;
virtual bool is_suspended(const uint32_t lcid) = 0;
virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
};
// RLC interface for PDCP
class rlc_interface_pdcp
{
public:
///< PDCP calls RLC to push an RLC SDU. SDU gets placed into the buffer
///< MAC pulls RLC PDUs according to TB size
virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
///< Indicate RLC that a certain SN can be discarded
virtual void discard_sdu(uint32_t lcid, uint32_t discard_sn) = 0;
///< Helper to query RLC mode
virtual bool rb_is_um(uint32_t lcid) = 0;
///< Allow PDCP to query SDU queue status
virtual bool sdu_queue_is_full(uint32_t lcid) = 0;
};
// RLC interface for MAC
class rlc_interface_mac : public srslte::read_pdu_interface
{
public:
/* MAC calls has_data() to query whether a logical channel has data to transmit (without
* knowing how much. This function should return quickly. */
virtual bool has_data_locked(const uint32_t lcid) = 0;
/* MAC calls RLC to get the buffer state for a logical channel. */
virtual uint32_t get_buffer_state(const uint32_t lcid) = 0;
const static int MAX_PDU_SEGMENTS = 20;
/* MAC calls RLC to get RLC segment of nof_bytes length.
* Segmentation happens in this function. RLC PDU is stored in payload. */
virtual int read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) = 0;
/* MAC calls RLC to push an RLC PDU. This function is called from an independent MAC thread.
* PDU gets placed into the buffer and higher layer thread gets notified. */
virtual void write_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) = 0;
virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t payload) = 0;
virtual void write_pdu_bcch_dlsch(uint8_t* payload, uint32_t nof_bytes) = 0;
virtual void write_pdu_pcch(srslte::unique_byte_buffer_t payload) = 0;
virtual void write_pdu_mch(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) = 0;
};
/** MAC interface
*
*/
/* Interface PHY -> MAC */
class mac_interface_phy_lte
{
public:
typedef struct {
uint32_t nof_mbsfn_services;
} mac_phy_cfg_mbsfn_t;
typedef struct {
uint32_t tbs;
bool ndi;
bool ndi_present;
int rv;
} mac_tb_t;
typedef struct {
mac_tb_t tb[SRSLTE_MAX_TB];
uint32_t pid;
uint16_t rnti;
bool is_sps_release;
uint32_t tti;
} mac_grant_dl_t;
typedef struct {
mac_tb_t tb;
uint32_t pid;
uint16_t rnti;
bool phich_available;
bool hi_value;
bool is_rar;
uint32_t tti_tx;
} mac_grant_ul_t;
typedef struct {
bool enabled;
uint32_t rv;
uint8_t* payload;
union {
srslte_softbuffer_rx_t* rx;
srslte_softbuffer_tx_t* tx;
} softbuffer;
} tb_action_t;
typedef struct {
tb_action_t tb[SRSLTE_MAX_TB];
bool generate_ack;
} tb_action_dl_t;
typedef struct {
tb_action_t tb;
uint32_t current_tx_nb;
bool expect_ack;
bool is_rar;
} tb_action_ul_t;
/* Query the MAC for the current RNTI to look for
*/
virtual uint16_t get_dl_sched_rnti(uint32_t tti) = 0;
virtual uint16_t get_ul_sched_rnti(uint32_t tti) = 0;
/* Indicate reception of UL dci.
* payload_ptr points to memory where MAC PDU must be written by MAC layer */
virtual void new_grant_ul(uint32_t cc_idx, mac_grant_ul_t grant, tb_action_ul_t* action) = 0;
/* Indicate reception of DL dci. */
virtual void new_grant_dl(uint32_t cc_idx, mac_grant_dl_t grant, tb_action_dl_t* action) = 0;
/* Indicate successful decoding of PDSCH AND PCH TB. */
virtual void tb_decoded(uint32_t cc_idx, mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]) = 0;
/* Indicate successful decoding of BCH TB through PBCH */
virtual void bch_decoded_ok(uint32_t cc_idx, uint8_t* payload, uint32_t len) = 0;
/* Indicate successful decoding of MCH TB through PMCH */
virtual void mch_decoded(uint32_t len, bool crc) = 0;
/* Obtain action for a new MCH subframe. */
virtual void new_mch_dl(const srslte_pdsch_grant_t& phy_grant, tb_action_dl_t* action) = 0;
/* Communicate the number of mbsfn services available */
virtual void set_mbsfn_config(uint32_t nof_mbsfn_services) = 0;
};
/* Interface RRC -> MAC shared between different RATs */
class mac_interface_rrc_common
{
public:
// Class to handle UE specific RNTIs between RRC and MAC
typedef struct {
uint16_t crnti;
uint16_t rar_rnti;
uint16_t temp_rnti;
uint16_t tpc_rnti;
uint16_t sps_rnti;
uint64_t contention_id;
} ue_rnti_t;
};
/* Interface RRC -> MAC */
class mac_interface_rrc : public mac_interface_rrc_common
{
public:
/* Instructs the MAC to start receiving BCCH */
virtual void bcch_start_rx(int si_window_start, int si_window_length) = 0;
virtual void bcch_stop_rx() = 0;
/* Instructs the MAC to start receiving PCCH */
virtual void pcch_start_rx() = 0;
/* RRC configures a logical channel */
virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0;
/* Instructs the MAC to start receiving an MCH */
virtual void mch_start_rx(uint32_t lcid) = 0;
/* Set entire MAC config */
virtual void set_config(srslte::mac_cfg_t& mac_cfg) = 0;
/* Update SR config only for PUCCH release */
virtual void set_config(srslte::sr_cfg_t& sr_cfg) = 0;
virtual void set_rach_ded_cfg(uint32_t preamble_index, uint32_t prach_mask) = 0;
virtual void get_rntis(ue_rnti_t* rntis) = 0;
virtual void set_contention_id(uint64_t uecri) = 0;
virtual void set_ho_rnti(uint16_t crnti, uint16_t target_pci) = 0;
virtual void reconfiguration(const uint32_t& cc_idx, const bool& enable) = 0;
virtual void reset() = 0;
};
/** PHY interface
*
*/
typedef struct {
std::string type = "lte";
srslte::phy_log_args_t log;
std::string dl_earfcn = "3400"; // comma-separated list of DL EARFCNs
std::string ul_earfcn = ""; // comma-separated list of UL EARFCNs
std::vector<uint32_t> dl_earfcn_list = {3400}; // vectorized version of dl_earfcn that gets populated during init
std::map<uint32_t, uint32_t> ul_earfcn_map; // Map linking DL EARFCN and UL EARFCN
std::string dl_nr_arfcn = "632628"; // comma-separated list of DL NR ARFCNs
std::vector<uint32_t> dl_nr_arfcn_list = {
632628}; // vectorized version of dl_nr_arfcn that gets populated during init
float dl_freq = -1.0f;
float ul_freq = -1.0f;
bool ul_pwr_ctrl_en = false;
float prach_gain = -1;
uint32_t pdsch_max_its = 8;
bool meas_evm = false;
uint32_t nof_phy_threads = 3;
int worker_cpu_mask = -1;
int sync_cpu_affinity = -1;
uint32_t nof_lte_carriers = 1;
uint32_t nof_nr_carriers = 0;
uint32_t nr_nof_prb = 50;
double nr_freq_hz = 2630e6;
uint32_t nof_rx_ant = 1;
std::string equalizer_mode = "mmse";
int cqi_max = 15;
int cqi_fixed = -1;
float snr_ema_coeff = 0.1f;
std::string snr_estim_alg = "refs";
bool agc_enable = true;
bool correct_sync_error = false;
bool cfo_is_doppler = false;
bool cfo_integer_enabled = false;
float cfo_correct_tol_hz = 1.0f;
float cfo_pss_ema = DEFAULT_CFO_EMA_TRACK;
float cfo_loop_bw_pss = DEFAULT_CFO_BW_PSS;
float cfo_loop_bw_ref = DEFAULT_CFO_BW_REF;
float cfo_loop_ref_min = DEFAULT_CFO_REF_MIN;
float cfo_loop_pss_tol = DEFAULT_CFO_PSS_MIN;
float sfo_ema = DEFAULT_SFO_EMA_COEFF;
uint32_t sfo_correct_period = DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD;
uint32_t cfo_loop_pss_conv = DEFAULT_PSS_STABLE_TIMEOUT;
uint32_t cfo_ref_mask = 1023;
bool interpolate_subframe_enabled = false;
bool estimator_fil_auto = false;
float estimator_fil_stddev = 1.0f;
uint32_t estimator_fil_order = 4;
float snr_to_cqi_offset = 0.0f;
std::string sss_algorithm = "full";
float rx_gain_offset = 62;
bool pdsch_csi_enabled = true;
bool pdsch_8bit_decoder = false;
uint32_t intra_freq_meas_len_ms = 20;
uint32_t intra_freq_meas_period_ms = 200;
float force_ul_amplitude = 0.0f;
float in_sync_rsrp_dbm_th = -130.0f;
float in_sync_snr_db_th = 1.0f;
uint32_t nof_in_sync_events = 10;
uint32_t nof_out_of_sync_events = 20;
srslte::channel::args_t dl_channel_args;
srslte::channel::args_t ul_channel_args;
srslte::vnf_args_t vnf_args;
} phy_args_t;
/* RAT agnostic Interface MAC -> PHY */
class phy_interface_mac_common
{
public:
/* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */
virtual void set_crnti(uint16_t rnti) = 0;
/* Time advance commands */
virtual void set_timeadv_rar(uint32_t ta_cmd) = 0;
virtual void set_timeadv(uint32_t ta_cmd) = 0;
/* Activate / Disactivate SCell*/
virtual void set_activation_deactivation_scell(uint32_t cmd, uint32_t tti) = 0;
/* Sets RAR dci payload */
virtual void set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rnti) = 0;
virtual uint32_t get_current_tti() = 0;
virtual float get_phr() = 0;
virtual float get_pathloss_db() = 0;
};
/* Interface MAC -> PHY */
class phy_interface_mac_lte : public phy_interface_mac_common
{
public:
typedef struct {
bool is_transmitted;
uint32_t tti_ra;
uint32_t f_id;
uint32_t preamble_format;
} prach_info_t;
virtual void
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;
/* Indicates the transmission of a SR signal in the next opportunity */
virtual void sr_send() = 0;
virtual int sr_last_tx_tti() = 0;
virtual void set_mch_period_stop(uint32_t stop) = 0;
};
class phy_interface_rrc_lte
{
public:
virtual bool set_config(srslte::phy_cfg_t config, uint32_t cc_idx = 0) = 0;
virtual bool set_scell(srslte_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn) = 0;
virtual void set_config_tdd(srslte_tdd_config_t& tdd_config) = 0;
virtual void set_config_mbsfn_sib2(srslte::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) = 0;
virtual void set_config_mbsfn_sib13(const srslte::sib13_t& sib13) = 0;
virtual void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch) = 0;
virtual void deactivate_scells() = 0;
/* Measurements interface */
virtual void set_cells_to_meas(uint32_t earfcn, const std::set<uint32_t>& pci) = 0;
virtual void meas_stop() = 0;
/* Cell search and selection procedures */
virtual bool cell_search() = 0;
virtual bool cell_select(phy_cell_t cell) = 0;
virtual bool cell_is_camping() = 0;
virtual void enable_pregen_signals(bool enable) = 0;
};
// STACK interface for GW
class stack_interface_gw : public pdcp_interface_gw
{
public:
virtual bool is_registered() = 0;
virtual bool start_service_request() = 0;
};
class gw_interface_stack : public gw_interface_nas, public gw_interface_rrc, public gw_interface_pdcp
{};
// STACK interface for RRC
class stack_interface_rrc
{
@ -695,10 +48,6 @@ public:
virtual void run_tti(const uint32_t tti, const uint32_t tti_jump) = 0;
};
// Combined interface for stack (MAC and RRC) to access PHY
class phy_interface_stack_lte : public phy_interface_mac_lte, public phy_interface_rrc_lte
{};
} // namespace srsue
#endif // SRSLTE_UE_INTERFACES_H

@ -0,0 +1,151 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 SRSLTE_UE_MAC_INTERFACES_H
#define SRSLTE_UE_MAC_INTERFACES_H
#include "mac_interface_types.h"
namespace srsue {
class mac_interface_phy_lte
{
public:
typedef struct {
uint32_t nof_mbsfn_services;
} mac_phy_cfg_mbsfn_t;
typedef struct {
uint32_t tbs;
bool ndi;
bool ndi_present;
int rv;
} mac_tb_t;
typedef struct {
mac_tb_t tb[SRSLTE_MAX_TB];
uint32_t pid;
uint16_t rnti;
bool is_sps_release;
uint32_t tti;
} mac_grant_dl_t;
typedef struct {
mac_tb_t tb;
uint32_t pid;
uint16_t rnti;
bool phich_available;
bool hi_value;
bool is_rar;
uint32_t tti_tx;
} mac_grant_ul_t;
typedef struct {
bool enabled;
uint32_t rv;
uint8_t* payload;
union {
srslte_softbuffer_rx_t* rx;
srslte_softbuffer_tx_t* tx;
} softbuffer;
} tb_action_t;
typedef struct {
tb_action_t tb[SRSLTE_MAX_TB];
bool generate_ack;
} tb_action_dl_t;
typedef struct {
tb_action_t tb;
uint32_t current_tx_nb;
bool expect_ack;
bool is_rar;
} tb_action_ul_t;
/* Query the MAC for the current RNTI to look for
*/
virtual uint16_t get_dl_sched_rnti(uint32_t tti) = 0;
virtual uint16_t get_ul_sched_rnti(uint32_t tti) = 0;
/* Indicate reception of UL dci.
* payload_ptr points to memory where MAC PDU must be written by MAC layer */
virtual void new_grant_ul(uint32_t cc_idx, mac_grant_ul_t grant, tb_action_ul_t* action) = 0;
/* Indicate reception of DL dci. */
virtual void new_grant_dl(uint32_t cc_idx, mac_grant_dl_t grant, tb_action_dl_t* action) = 0;
/* Indicate successful decoding of PDSCH AND PCH TB. */
virtual void tb_decoded(uint32_t cc_idx, mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]) = 0;
/* Indicate successful decoding of BCH TB through PBCH */
virtual void bch_decoded_ok(uint32_t cc_idx, uint8_t* payload, uint32_t len) = 0;
/* Indicate successful decoding of MCH TB through PMCH */
virtual void mch_decoded(uint32_t len, bool crc) = 0;
/* Obtain action for a new MCH subframe. */
virtual void new_mch_dl(const srslte_pdsch_grant_t& phy_grant, tb_action_dl_t* action) = 0;
/* Communicate the number of mbsfn services available */
virtual void set_mbsfn_config(uint32_t nof_mbsfn_services) = 0;
};
class mac_interface_rrc_common
{
public:
// Class to handle UE specific RNTIs between RRC and MAC
typedef struct {
uint16_t crnti;
uint16_t rar_rnti;
uint16_t temp_rnti;
uint16_t tpc_rnti;
uint16_t sps_rnti;
uint64_t contention_id;
} ue_rnti_t;
};
class mac_interface_rrc : public mac_interface_rrc_common
{
public:
/* Instructs the MAC to start receiving BCCH */
virtual void bcch_start_rx(int si_window_start, int si_window_length) = 0;
virtual void bcch_stop_rx() = 0;
/* Instructs the MAC to start receiving PCCH */
virtual void pcch_start_rx() = 0;
/* RRC configures a logical channel */
virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0;
/* Instructs the MAC to start receiving an MCH */
virtual void mch_start_rx(uint32_t lcid) = 0;
/* Set entire MAC config */
virtual void set_config(srslte::mac_cfg_t& mac_cfg) = 0;
/* Update SR config only for PUCCH release */
virtual void set_config(srslte::sr_cfg_t& sr_cfg) = 0;
virtual void set_rach_ded_cfg(uint32_t preamble_index, uint32_t prach_mask) = 0;
virtual void get_rntis(ue_rnti_t* rntis) = 0;
virtual void set_contention_id(uint64_t uecri) = 0;
virtual void set_ho_rnti(uint16_t crnti, uint16_t target_pci) = 0;
virtual void reconfiguration(const uint32_t& cc_idx, const bool& enable) = 0;
virtual void reset() = 0;
};
} // namespace srsue
#endif // SRSLTE_UE_MAC_INTERFACES_H

@ -0,0 +1,44 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 SRSLTE_UE_NAS_INTERFACES_H
#define SRSLTE_UE_NAS_INTERFACES_H
#include "srslte/interfaces/rrc_interface_types.h"
namespace srsue {
class nas_interface_rrc
{
public:
const static int MAX_FOUND_PLMNS = 16;
struct found_plmn_t {
srslte::plmn_id_t plmn_id;
uint16_t tac;
};
virtual void left_rrc_connected() = 0;
virtual void set_barring(srslte::barring_t barring) = 0;
virtual bool paging(srslte::s_tmsi_t* ue_identity) = 0;
virtual bool is_registered() = 0;
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
virtual uint32_t get_k_enb_count() = 0;
virtual bool get_k_asme(uint8_t* k_asme_, uint32_t n) = 0;
virtual uint32_t get_ipv4_addr() = 0;
virtual bool get_ipv6_addr(uint8_t* ipv6_addr) = 0;
virtual void plmn_search_completed(const found_plmn_t found_plmns[MAX_FOUND_PLMNS], int nof_plmns) = 0;
virtual bool connection_request_completed(bool outcome) = 0;
};
} // namespace srsue
#endif // SRSLTE_UE_NAS_INTERFACES_H

@ -26,6 +26,7 @@
#include "srslte/interfaces/mac_interface_types.h"
#include "srslte/interfaces/rrc_nr_interface_types.h"
#include <array>
#include <set>
#include <string>
namespace srsue {
@ -55,6 +56,19 @@ public:
uint32_t tbs;
} mac_nr_grant_ul_t;
/// For UL, payload buffer remains in MAC
typedef struct {
bool enabled;
uint32_t rv;
srslte::byte_buffer_t* payload;
srslte_softbuffer_tx_t* softbuffer;
} tb_ul_t;
/// Struct provided by MAC with all necessary information for PHY
typedef struct {
tb_ul_t tb; // only single TB in UL
} tb_action_ul_t;
virtual int sf_indication(const uint32_t tti) = 0; ///< FIXME: rename to slot indication
// Query the MAC for the current RNTI to look for
@ -68,10 +82,16 @@ public:
/// Indicate succussfully received TB to MAC. The TB buffer is allocated in the PHY and handed as unique_ptr to MAC
virtual void tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant) = 0;
/// Indicate reception of UL grant (only TBS is provided). Buffer for resulting MAC PDU is provided by MAC and is
/// passed as pointer to PHY during tx_reuqest
virtual void
new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, srslte::byte_buffer_t* phy_tx_pdu) = 0;
/**
* @brief Indicate reception of UL grant to MAC
*
* Buffer for resulting MAC PDU is provided and managed (owned) by MAC and is passed as pointer in ul_action
*
* @param cc_idx The carrier index on which the grant has been received
* @param grant Reference to the grant
* @param action Pointer to the TB action to be filled by MAC
*/
virtual void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action) = 0;
/**
* @brief Indicate the successful transmission of a PRACH.
@ -110,6 +130,8 @@ struct phy_args_nr_t {
srslte::phy_log_args_t log;
srslte_ue_dl_nr_args_t dl;
srslte_ue_ul_nr_args_t ul;
std::set<uint32_t> fixed_sr = {1};
uint32_t fix_wideband_cqi = 15; // Set to a non-zero value for fixing the wide-band CQI report
phy_args_nr_t()
{
@ -121,6 +143,8 @@ struct phy_args_nr_t {
ul.nof_max_prb = 100;
ul.pusch.measure_time = true;
ul.pusch.sch.disable_simd = false;
// fixed_sr.insert(0); // Enable SR_id = 0 by default for testing purposes
}
};
@ -146,6 +170,9 @@ public:
const int preamble_index,
const float preamble_received_target_power,
const float ta_base_sec = 0.0f) = 0;
/// Instruct PHY to transmit SR for a given identifier
virtual void sr_send(uint32_t sr_id) = 0;
};
class phy_interface_rrc_nr

@ -0,0 +1,68 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 SRSLTE_UE_PDCP_INTERFACES_H
#define SRSLTE_UE_PDCP_INTERFACES_H
#include "pdcp_interface_types.h"
namespace srsue {
class pdcp_interface_rrc
{
public:
virtual void reestablish() = 0;
virtual void reestablish(uint32_t lcid) = 0;
virtual void reset() = 0;
virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, int sn = -1) = 0;
virtual void add_bearer(uint32_t lcid, srslte::pdcp_config_t cnfg) = 0;
virtual void change_lcid(uint32_t old_lcid, uint32_t new_lcid) = 0;
virtual void config_security(uint32_t lcid, srslte::as_security_config_t sec_cfg) = 0;
virtual void config_security_all(srslte::as_security_config_t sec_cfg) = 0;
virtual void enable_integrity(uint32_t lcid, srslte::srslte_direction_t direction) = 0;
virtual void enable_encryption(uint32_t lcid,
srslte::srslte_direction_t direction = srslte::srslte_direction_t::DIRECTION_TXRX) = 0;
virtual void send_status_report() = 0;
virtual void send_status_report(uint32_t lcid) = 0;
};
class pdcp_interface_rlc
{
public:
/* RLC calls PDCP to push a PDCP PDU. */
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu) = 0;
virtual void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu) = 0;
virtual void write_pdu_pcch(srslte::unique_byte_buffer_t sdu) = 0;
virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
virtual void notify_delivery(uint32_t lcid, const std::vector<uint32_t>& pdcp_sn) = 0;
virtual void notify_failure(uint32_t lcid, const std::vector<uint32_t>& pdcp_sn) = 0;
};
class pdcp_interface_gw
{
public:
virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
virtual bool is_lcid_enabled(uint32_t lcid) = 0;
};
// STACK interface for GW
class stack_interface_gw : public pdcp_interface_gw
{
public:
virtual bool is_registered() = 0;
virtual bool start_service_request() = 0;
};
} // namespace srsue
#endif // SRSLTE_UE_PDCP_INTERFACES_H

@ -0,0 +1,174 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 SRSLTE_UE_PHY_INTERFACES_H
#define SRSLTE_UE_PHY_INTERFACES_H
#include "srslte/srslte.h"
#include "phy_interface_types.h"
#include "rrc_interface_types.h"
#include "srslte/common/interfaces_common.h"
#include "srslte/phy/channel/channel.h"
#include <map>
#include <set>
#include <string>
namespace srsue {
struct phy_args_t {
std::string type = "lte";
srslte::phy_log_args_t log;
std::string dl_earfcn = "3400"; // comma-separated list of DL EARFCNs
std::string ul_earfcn = ""; // comma-separated list of UL EARFCNs
std::vector<uint32_t> dl_earfcn_list = {3400}; // vectorized version of dl_earfcn that gets populated during init
std::map<uint32_t, uint32_t> ul_earfcn_map; // Map linking DL EARFCN and UL EARFCN
std::string dl_nr_arfcn = "632628"; // comma-separated list of DL NR ARFCNs
std::vector<uint32_t> dl_nr_arfcn_list = {
632628}; // vectorized version of dl_nr_arfcn that gets populated during init
float dl_freq = -1.0f;
float ul_freq = -1.0f;
bool ul_pwr_ctrl_en = false;
float prach_gain = -1;
uint32_t pdsch_max_its = 8;
bool meas_evm = false;
uint32_t nof_phy_threads = 3;
int worker_cpu_mask = -1;
int sync_cpu_affinity = -1;
uint32_t nof_lte_carriers = 1;
uint32_t nof_nr_carriers = 0;
uint32_t nr_nof_prb = 50;
double nr_freq_hz = 2630e6;
uint32_t nof_rx_ant = 1;
std::string equalizer_mode = "mmse";
int cqi_max = 15;
int cqi_fixed = -1;
float snr_ema_coeff = 0.1f;
std::string snr_estim_alg = "refs";
bool agc_enable = true;
bool correct_sync_error = false;
bool cfo_is_doppler = false;
bool cfo_integer_enabled = false;
float cfo_correct_tol_hz = 1.0f;
float cfo_pss_ema = DEFAULT_CFO_EMA_TRACK;
float cfo_loop_bw_pss = DEFAULT_CFO_BW_PSS;
float cfo_loop_bw_ref = DEFAULT_CFO_BW_REF;
float cfo_loop_ref_min = DEFAULT_CFO_REF_MIN;
float cfo_loop_pss_tol = DEFAULT_CFO_PSS_MIN;
float sfo_ema = DEFAULT_SFO_EMA_COEFF;
uint32_t sfo_correct_period = DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD;
uint32_t cfo_loop_pss_conv = DEFAULT_PSS_STABLE_TIMEOUT;
uint32_t cfo_ref_mask = 1023;
bool interpolate_subframe_enabled = false;
bool estimator_fil_auto = false;
float estimator_fil_stddev = 1.0f;
uint32_t estimator_fil_order = 4;
float snr_to_cqi_offset = 0.0f;
std::string sss_algorithm = "full";
float rx_gain_offset = 62;
bool pdsch_csi_enabled = true;
bool pdsch_8bit_decoder = false;
uint32_t intra_freq_meas_len_ms = 20;
uint32_t intra_freq_meas_period_ms = 200;
float force_ul_amplitude = 0.0f;
float in_sync_rsrp_dbm_th = -130.0f;
float in_sync_snr_db_th = 1.0f;
uint32_t nof_in_sync_events = 10;
uint32_t nof_out_of_sync_events = 20;
srslte::channel::args_t dl_channel_args;
srslte::channel::args_t ul_channel_args;
srslte::vnf_args_t vnf_args;
};
/* RAT agnostic Interface MAC -> PHY */
class phy_interface_mac_common
{
public:
/* Time advance commands */
virtual void set_timeadv_rar(uint32_t ta_cmd) = 0;
virtual void set_timeadv(uint32_t ta_cmd) = 0;
/* Activate / Disactivate SCell*/
virtual void set_activation_deactivation_scell(uint32_t cmd, uint32_t tti) = 0;
/* Sets RAR dci payload */
virtual void set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rnti) = 0;
virtual uint32_t get_current_tti() = 0;
virtual float get_phr() = 0;
virtual float get_pathloss_db() = 0;
};
/* Interface MAC -> PHY */
class phy_interface_mac_lte : public phy_interface_mac_common
{
public:
typedef struct {
bool is_transmitted;
uint32_t tti_ra;
uint32_t f_id;
uint32_t preamble_format;
} prach_info_t;
virtual void
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;
/* Indicates the transmission of a SR signal in the next opportunity */
virtual void sr_send() = 0;
virtual int sr_last_tx_tti() = 0;
virtual void set_mch_period_stop(uint32_t stop) = 0;
};
class phy_interface_rrc_lte
{
public:
virtual bool set_config(srslte::phy_cfg_t config, uint32_t cc_idx = 0) = 0;
virtual bool set_scell(srslte_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn) = 0;
virtual void set_config_tdd(srslte_tdd_config_t& tdd_config) = 0;
virtual void set_config_mbsfn_sib2(srslte::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) = 0;
virtual void set_config_mbsfn_sib13(const srslte::sib13_t& sib13) = 0;
virtual void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch) = 0;
virtual void deactivate_scells() = 0;
/* Measurements interface */
virtual void set_cells_to_meas(uint32_t earfcn, const std::set<uint32_t>& pci) = 0;
virtual void meas_stop() = 0;
/* Cell search and selection procedures */
virtual bool cell_search() = 0;
virtual bool cell_select(phy_cell_t cell) = 0;
virtual bool cell_is_camping() = 0;
virtual void enable_pregen_signals(bool enable) = 0;
};
// Combined interface for stack (MAC and RRC) to access PHY
class phy_interface_stack_lte : public phy_interface_mac_lte, public phy_interface_rrc_lte
{};
} // namespace srsue
#endif // SRSLTE_UE_PHY_INTERFACES_H

@ -0,0 +1,83 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 SRSLTE_UE_RLC_INTERFACES_H
#define SRSLTE_UE_RLC_INTERFACES_H
#include "srslte/common/interfaces_common.h"
#include "srslte/interfaces/rlc_interface_types.h"
namespace srsue {
class rlc_interface_rrc
{
public:
virtual void reset() = 0;
virtual void reestablish() = 0;
virtual void reestablish(uint32_t lcid) = 0;
virtual void add_bearer(uint32_t lcid, const srslte::rlc_config_t& cnfg) = 0;
virtual void add_bearer_mrb(uint32_t lcid) = 0;
virtual void del_bearer(uint32_t lcid) = 0;
virtual void suspend_bearer(uint32_t lcid) = 0;
virtual void resume_bearer(uint32_t lcid) = 0;
virtual void change_lcid(uint32_t old_lcid, uint32_t new_lcid) = 0;
virtual bool has_bearer(uint32_t lcid) = 0;
virtual bool has_data(const uint32_t lcid) = 0;
virtual bool is_suspended(const uint32_t lcid) = 0;
virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
};
class rlc_interface_pdcp
{
public:
///< PDCP calls RLC to push an RLC SDU. SDU gets placed into the buffer
///< MAC pulls RLC PDUs according to TB size
virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
///< Indicate RLC that a certain SN can be discarded
virtual void discard_sdu(uint32_t lcid, uint32_t discard_sn) = 0;
///< Helper to query RLC mode
virtual bool rb_is_um(uint32_t lcid) = 0;
///< Allow PDCP to query SDU queue status
virtual bool sdu_queue_is_full(uint32_t lcid) = 0;
};
class rlc_interface_mac : public srslte::read_pdu_interface
{
public:
/* MAC calls has_data() to query whether a logical channel has data to transmit (without
* knowing how much. This function should return quickly. */
virtual bool has_data_locked(const uint32_t lcid) = 0;
/* MAC calls RLC to get the buffer state for a logical channel. */
virtual uint32_t get_buffer_state(const uint32_t lcid) = 0;
const static int MAX_PDU_SEGMENTS = 20;
/* MAC calls RLC to get RLC segment of nof_bytes length.
* Segmentation happens in this function. RLC PDU is stored in payload. */
virtual int read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) = 0;
/* MAC calls RLC to push an RLC PDU. This function is called from an independent MAC thread.
* PDU gets placed into the buffer and higher layer thread gets notified. */
virtual void write_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) = 0;
virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t payload) = 0;
virtual void write_pdu_bcch_dlsch(uint8_t* payload, uint32_t nof_bytes) = 0;
virtual void write_pdu_pcch(srslte::unique_byte_buffer_t payload) = 0;
virtual void write_pdu_mch(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) = 0;
};
} // namespace srsue
#endif // SRSLTE_UE_RLC_INTERFACES_H

@ -0,0 +1,120 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 SRSLTE_UE_RRC_INTERFACES_H
#define SRSLTE_UE_RRC_INTERFACES_H
#include "phy_interface_types.h"
#include "rrc_interface_types.h"
#include "srslte/asn1/asn1_utils.h"
#include "srslte/common/byte_buffer.h"
#include "srslte/common/tti_point.h"
namespace srsue {
class rrc_interface_mac_common
{
public:
virtual void ra_problem() = 0;
};
class rrc_interface_mac : public rrc_interface_mac_common
{
public:
virtual void ra_completed() = 0;
virtual void release_pucch_srs() = 0;
};
class rrc_eutra_interface_rrc_nr
{
public:
virtual void new_cell_meas_nr(const std::vector<phy_meas_nr_t>& meas) = 0;
virtual void nr_rrc_con_reconfig_complete(bool status) = 0;
};
class rrc_interface_phy_lte
{
public:
virtual void in_sync() = 0;
virtual void out_of_sync() = 0;
virtual void new_cell_meas(const std::vector<phy_meas_t>& meas) = 0;
typedef struct {
enum { CELL_FOUND = 0, CELL_NOT_FOUND, ERROR } found;
enum { MORE_FREQS = 0, NO_MORE_FREQS } last_freq;
} cell_search_ret_t;
virtual void cell_search_complete(cell_search_ret_t ret, phy_cell_t found_cell) = 0;
virtual void cell_select_complete(bool status) = 0;
virtual void set_config_complete(bool status) = 0;
virtual void set_scell_complete(bool status) = 0;
};
class rrc_interface_nas
{
public:
virtual ~rrc_interface_nas() = default;
virtual void write_sdu(srslte::unique_byte_buffer_t sdu) = 0;
virtual uint16_t get_mcc() = 0;
virtual uint16_t get_mnc() = 0;
virtual void enable_capabilities() = 0;
virtual bool plmn_search() = 0;
virtual void plmn_select(srslte::plmn_id_t plmn_id) = 0;
virtual bool connection_request(srslte::establishment_cause_t cause,
srslte::unique_byte_buffer_t dedicatedInfoNAS) = 0;
virtual void set_ue_identity(srslte::s_tmsi_t s_tmsi) = 0;
virtual bool is_connected() = 0;
virtual void paging_completed(bool outcome) = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
virtual uint32_t get_lcid_for_eps_bearer(const uint32_t& eps_bearer_id) = 0;
virtual bool has_nr_dc() = 0;
};
class rrc_interface_pdcp
{
public:
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t pdu) = 0;
virtual void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t pdu) = 0;
virtual void write_pdu_pcch(srslte::unique_byte_buffer_t pdu) = 0;
virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
};
class rrc_interface_rlc
{
public:
virtual void max_retx_attempted() = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
};
class rrc_nr_interface_rrc
{
public:
virtual void get_eutra_nr_capabilities(srslte::byte_buffer_t* eutra_nr_caps) = 0;
virtual void get_nr_capabilities(srslte::byte_buffer_t* nr_cap) = 0;
virtual void phy_set_cells_to_meas(uint32_t carrier_freq_r15) = 0;
virtual void phy_meas_stop() = 0;
virtual bool rrc_reconfiguration(bool endc_release_and_add_r15,
bool nr_secondary_cell_group_cfg_r15_present,
asn1::dyn_octstring nr_secondary_cell_group_cfg_r15,
bool sk_counter_r15_present,
uint32_t sk_counter_r15,
bool nr_radio_bearer_cfg1_r15_present,
asn1::dyn_octstring nr_radio_bearer_cfg1_r15) = 0;
virtual bool is_config_pending() = 0;
};
} // namespace srsue
#endif // SRSLTE_UE_RRC_INTERFACES_H

@ -0,0 +1,65 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 SRSLTE_UE_USIM_INTERFACES_H
#define SRSLTE_UE_USIM_INTERFACES_H
#include "rrc_interface_types.h"
#include <string>
namespace srsue {
enum auth_result_t { AUTH_OK, AUTH_FAILED, AUTH_SYNCH_FAILURE };
// USIM interface for NAS
class usim_interface_nas
{
public:
virtual std::string get_imsi_str() = 0;
virtual std::string get_imei_str() = 0;
virtual bool get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0;
virtual bool get_imei_vec(uint8_t* imei_, uint32_t n) = 0;
virtual bool get_home_plmn_id(srslte::plmn_id_t* home_plmn_id) = 0;
virtual auth_result_t generate_authentication_response(uint8_t* rand,
uint8_t* autn_enb,
uint16_t mcc,
uint16_t mnc,
uint8_t* res,
int* res_len,
uint8_t* k_asme) = 0;
virtual void generate_nas_keys(uint8_t* k_asme,
uint8_t* k_nas_enc,
uint8_t* k_nas_int,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0;
};
// USIM interface for RRC
class usim_interface_rrc
{
public:
virtual void generate_as_keys(uint8_t* k_asme, uint32_t count_ul, srslte::as_security_config_t* sec_cfg) = 0;
virtual void generate_as_keys_ho(uint32_t pci, uint32_t earfcn, int ncc, srslte::as_security_config_t* sec_cfg) = 0;
virtual void store_keys_before_ho(const srslte::as_security_config_t& as_cfg) = 0;
virtual void restore_keys_from_failed_ho(srslte::as_security_config_t* as_cfg) = 0;
};
class usim_interface_rrc_nr
{
public:
virtual void generate_nr_context(uint16_t sk_counter, srslte::as_security_config_t* sec_cfg) = 0;
virtual void update_nr_context(srslte::as_security_config_t* sec_cfg) = 0;
};
} // namespace srsue
#endif // SRSLTE_UE_USIM_INTERFACES_H

@ -71,9 +71,9 @@ SRSLTE_API void srslte_sequence_apply_s(const int16_t* in, int16_t* out, uint32_
SRSLTE_API void srslte_sequence_apply_c(const int8_t* in, int8_t* out, uint32_t length, uint32_t seed);
SRSLTE_API void srslte_sequence_apply_bit(const uint8_t* in, uint8_t* out, uint32_t length, uint32_t seed);
SRSLTE_API void srslte_sequence_apply_packed(const uint8_t* in, uint8_t* out, uint32_t length, uint32_t seed);
SRSLTE_API void srslte_sequence_apply_bit_packed(const uint8_t* in, uint8_t* out, uint32_t length, uint32_t seed);
SRSLTE_API void srslte_sequence_apply_bit(const uint8_t* in, uint8_t* out, uint32_t length, uint32_t seed);
SRSLTE_API int srslte_sequence_pbch(srslte_sequence_t* seq, srslte_cp_t cp, uint32_t cell_id);
@ -86,9 +86,65 @@ SRSLTE_API int srslte_sequence_pdcch(srslte_sequence_t* seq, uint32_t nslot, uin
SRSLTE_API int
srslte_sequence_pdsch(srslte_sequence_t* seq, uint16_t rnti, int q, uint32_t nslot, uint32_t cell_id, uint32_t len);
SRSLTE_API void srslte_sequence_pdsch_apply_pack(const uint8_t* in,
uint8_t* out,
uint16_t rnti,
int q,
uint32_t nslot,
uint32_t cell_id,
uint32_t len);
SRSLTE_API void srslte_sequence_pdsch_apply_f(const float* in,
float* out,
uint16_t rnti,
int q,
uint32_t nslot,
uint32_t cell_id,
uint32_t len);
SRSLTE_API void srslte_sequence_pdsch_apply_s(const int16_t* in,
int16_t* out,
uint16_t rnti,
int q,
uint32_t nslot,
uint32_t cell_id,
uint32_t len);
SRSLTE_API void srslte_sequence_pdsch_apply_c(const int8_t* in,
int8_t* out,
uint16_t rnti,
int q,
uint32_t nslot,
uint32_t cell_id,
uint32_t len);
SRSLTE_API int
srslte_sequence_pusch(srslte_sequence_t* seq, uint16_t rnti, uint32_t nslot, uint32_t cell_id, uint32_t len);
SRSLTE_API void srslte_sequence_pusch_apply_pack(const uint8_t* in,
uint8_t* out,
uint16_t rnti,
uint32_t nslot,
uint32_t cell_id,
uint32_t len);
SRSLTE_API void srslte_sequence_pusch_apply_c(const int8_t* in,
int8_t* out,
uint16_t rnti,
uint32_t nslot,
uint32_t cell_id,
uint32_t len);
SRSLTE_API void srslte_sequence_pusch_apply_s(const int16_t* in,
int16_t* out,
uint16_t rnti,
uint32_t nslot,
uint32_t cell_id,
uint32_t len);
SRSLTE_API void
srslte_sequence_pusch_gen_unpack(uint8_t* out, uint16_t rnti, uint32_t nslot, uint32_t cell_id, uint32_t len);
SRSLTE_API int srslte_sequence_pucch(srslte_sequence_t* seq, uint16_t rnti, uint32_t nslot, uint32_t cell_id);
SRSLTE_API int srslte_sequence_pmch(srslte_sequence_t* seq, uint32_t nslot, uint32_t mbsfn_id, uint32_t len);

@ -102,10 +102,6 @@ SRSLTE_API void srslte_enb_dl_free(srslte_enb_dl_t* q);
SRSLTE_API int srslte_enb_dl_set_cell(srslte_enb_dl_t* q, srslte_cell_t cell);
SRSLTE_API int srslte_enb_dl_add_rnti(srslte_enb_dl_t* q, uint16_t rnti);
SRSLTE_API void srslte_enb_dl_rem_rnti(srslte_enb_dl_t* q, uint16_t rnti);
SRSLTE_API bool srslte_enb_dl_location_is_common_ncce(srslte_enb_dl_t* q, uint32_t ncce);
SRSLTE_API void srslte_enb_dl_put_base(srslte_enb_dl_t* q, srslte_dl_sf_cfg_t* dl_sf);

@ -72,10 +72,6 @@ SRSLTE_API int srslte_enb_ul_set_cell(srslte_enb_ul_t* q,
srslte_refsignal_dmrs_pusch_cfg_t* pusch_cfg,
srslte_refsignal_srs_cfg_t* srs_cfg);
SRSLTE_API int srslte_enb_ul_add_rnti(srslte_enb_ul_t* q, uint16_t rnti);
SRSLTE_API void srslte_enb_ul_rem_rnti(srslte_enb_ul_t* q, uint16_t rnti);
SRSLTE_API void srslte_enb_ul_fft(srslte_enb_ul_t* q);
SRSLTE_API int srslte_enb_ul_get_pucch(srslte_enb_ul_t* q,

@ -0,0 +1,69 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 SRSLTE_CSI_NR_H
#define SRSLTE_CSI_NR_H
#include "uci_cfg_nr.h"
/**
* @brief Fills Uplink Control Information data with triggered reports for the given slot
* @param cfg CSI report configuration
* @param slot_idx Slot index within the radio frame
* @param measurements CSI measurements
* @param[out] uci_data Uplink Control Information data
* @return The number CSI reports for transmission if the provided data is valid, SRSLTE_ERROR code otherwise
*/
SRSLTE_API int srslte_csi_generate_reports(const srslte_csi_hl_cfg_t* cfg,
uint32_t slot_idx,
const srslte_csi_measurements_t measurements[SRSLTE_CSI_MAX_NOF_RESOURCES],
srslte_csi_report_cfg_t report_cfg[SRSLTE_CSI_MAX_NOF_REPORT],
srslte_csi_report_value_t report_value[SRSLTE_CSI_MAX_NOF_REPORT]);
/**
* @brief Compute number of CSI bits necessary to transmit all the CSI reports for a PUCCH transmission
* @param report_list Provides the CSI report list
* @param nof_reports Number of CSI reports in the list
* @return The number of bits if the provided list is valid, SRSLTE_ERROR code otherwise
*/
SRSLTE_API int srslte_csi_nof_bits(const srslte_csi_report_cfg_t* report_list, uint32_t nof_reports);
/**
* @brief Pack CSI part 1 bits for a PUCCH transmission
* @param report_list Provides the CSI report list
* @param nof_reports Number of CSI reports in the list
* @param o_csi1 CSI bits
* @param max_o_csi1 Maximum number of CSI bits
* @return number of packed bits if provided data is valid, SRSLTE_ERROR code otherwise
*/
SRSLTE_API int srslte_csi_part1_pack(const srslte_csi_report_cfg_t* report_cfg,
const srslte_csi_report_value_t* report_value,
uint32_t nof_reports,
uint8_t* o_csi1,
uint32_t max_o_csi1);
/**
* @brief Converts to string a given list of CSI reports
* @param report_cfg Report configuration list
* @param report_value Report value list
* @param nof_reports Number of reports
* @param str String pointer
* @param str_len Maximum string length
* @return Number of used characters
*/
SRSLTE_API uint32_t srslte_csi_str(const srslte_csi_report_cfg_t* report_cfg,
const srslte_csi_report_value_t* report_value,
uint32_t nof_reports,
char* str,
uint32_t str_len);
#endif // SRSLTE_CSI_NR_H

@ -0,0 +1,165 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 SRSLTE_CSI_CFG_H
#define SRSLTE_CSI_CFG_H
#include "pucch_cfg_nr.h"
#include "srslte/config.h"
#include <stdint.h>
/**
* @brief Maximum number of CSI report configurations defined in TS 38.331 maxNrofCSI-ReportConfigurations
*/
#define SRSLTE_CSI_MAX_NOF_REPORT 48
/**
* @brief Maximum number of CSI-RS resources defined in TS 38.331 maxNrofCSI-ResourceConfigurations
*/
#define SRSLTE_CSI_MAX_NOF_RESOURCES 112
/**
* @brief CSI report types defined in TS 38.331 CSI-ReportConfig
*/
typedef enum SRSLTE_API {
SRSLTE_CSI_REPORT_TYPE_NONE = 0,
SRSLTE_CSI_REPORT_TYPE_PERIODIC,
SRSLTE_CSI_REPORT_TYPE_SEMI_PERSISTENT_ON_PUCCH,
SRSLTE_CSI_REPORT_TYPE_SEMI_PERSISTENT_ON_PUSCH,
SRSLTE_CSI_REPORT_TYPE_APERIODIC,
} srslte_csi_report_type_t;
/**
* @brief CSI report quantities defined in TS 38.331 CSI-ReportConfig
*/
typedef enum SRSLTE_API {
SRSLTE_CSI_REPORT_QUANTITY_NONE = 0,
SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI,
SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_I1,
SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_I1_CQI,
SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_CQI,
SRSLTE_CSI_REPORT_QUANTITY_CRI_RSRP,
SRSLTE_CSI_REPORT_QUANTITY_SSB_INDEX_RSRP,
SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_LI_PMI_CQI
} srslte_csi_report_quantity_t;
/**
* @brief CSI report frequency configuration defined in TS 38.331 CSI-ReportConfig
*/
typedef enum SRSLTE_API {
SRSLTE_CSI_REPORT_FREQ_WIDEBAND = 0,
SRSLTE_CSI_REPORT_FREQ_SUBBAND
} srslte_csi_report_freq_t;
/**
* @brief CQI table selection
*/
typedef enum SRSLTE_API {
SRSLTE_CSI_CQI_TABLE_1 = 0,
SRSLTE_CSI_CQI_TABLE_2,
SRSLTE_CSI_CQI_TABLE_3,
} srslte_csi_cqi_table_t;
/**
* @brief CSI periodic report configuration from upper layers
* @remark Described in TS 38.331 CSI-ReportConfig
*/
typedef struct SRSLTE_API {
uint32_t period; ///< Period in slots
uint32_t offset; ///< Offset from beginning of the period in slots
srslte_pucch_nr_resource_t resource; ///< PUCCH resource to use for reporting
} srslte_csi_periodic_report_cfg_t;
/**
* @brief CSI report configuration from higher layers
*/
typedef struct SRSLTE_API {
uint32_t channel_meas_id; ///< Channel measurement resource identifier
uint32_t interf_meas_id; ///< Interference measurement resource identifier
bool interf_meas_present; ///< Indicates if interference measurement identifier is present
srslte_csi_report_type_t type; ///< CSI report type (none, periodic, semiPersistentOnPUCCH, ...)
union {
void* none; ///< Reserved, no configured
srslte_csi_periodic_report_cfg_t periodic; ///< Used for periodic reporting
// ... add here other types
};
srslte_csi_report_quantity_t quantity; ///< Report quantity
srslte_csi_cqi_table_t cqi_table; ///< CQI table selection
srslte_csi_report_freq_t freq_cfg; ///< Determine whether it is wideband or subband
} srslte_csi_hl_report_cfg_t;
/**
* @brief General CSI configuration provided by higher layers
*/
typedef struct SRSLTE_API {
srslte_csi_hl_report_cfg_t reports[SRSLTE_CSI_MAX_NOF_REPORT]; ///< CSI report configuration
// ... add here physical CSI measurement sets
} srslte_csi_hl_cfg_t;
/**
* @brief Generic measurement structure
*/
typedef struct SRSLTE_API {
uint32_t cri; ///< CSI-RS Resource Indicator
float wideband_rsrp_dBm; ///< Measured NZP-CSI-RS RSRP (Ignore for IM-CSI-RS)
float wideband_epre_dBm; ///< Measured EPRE
float wideband_snr_db; ///< SNR calculated from NZP-CSI-RS RSRP and EPRE (Ignore for IM-CSI-RS)
// Resource set context
uint32_t nof_ports; ///< Number of antenna ports
uint32_t K_csi_rs; ///< Number of CSI-RS in the corresponding resource set
} srslte_csi_measurements_t;
/**
* @brief CSI report configuration
*/
typedef struct SRSLTE_API {
srslte_csi_report_type_t type; ///< CSI report type (none, periodic, semiPersistentOnPUCCH, ...)
srslte_csi_report_quantity_t quantity; ///< Report quantity
srslte_pucch_nr_resource_t pucch_resource; ///< PUCCH resource to use for periodic reporting
srslte_csi_report_freq_t freq_cfg; ///< Determine whether it is wideband or subband
// Resource set context
uint32_t nof_ports; ///< Number of antenna ports
uint32_t K_csi_rs; ///< Number of CSI-RS in the corresponding resource set
} srslte_csi_report_cfg_t;
/**
* @brief Wideband CSI report values
*/
typedef struct SRSLTE_API {
uint32_t ri;
uint32_t pmi;
uint32_t cqi;
} srslte_csi_report_wideband_cri_ri_pmi_cqi_t;
/**
* @brief Unified CSI report values
*/
typedef struct SRSLTE_API {
uint32_t cri; ///< CSI-RS Resource Indicator
union {
void* none;
srslte_csi_report_wideband_cri_ri_pmi_cqi_t wideband_cri_ri_pmi_cqi;
};
bool valid; ///< Used by receiver only
} srslte_csi_report_value_t;
/**
* @brief Complete report configuration and value
*/
typedef struct SRSLTE_API {
srslte_csi_report_cfg_t cfg[SRSLTE_CSI_MAX_NOF_REPORT]; ///< Configuration ready for encoding
srslte_csi_report_value_t value[SRSLTE_CSI_MAX_NOF_REPORT]; ///< Quantified values
uint32_t nof_reports; ///< Total number of reports to transmit
} srslte_csi_reports_t;
#endif // SRSLTE_CSI_CFG_H

@ -44,12 +44,6 @@
#include "srslte/phy/phch/sch.h"
#include "srslte/phy/scrambling/scrambling.h"
typedef struct {
srslte_sequence_t seq[SRSLTE_MAX_CODEWORDS][SRSLTE_NOF_SF_X_FRAME];
uint32_t cell_id;
bool sequence_generated;
} srslte_pdsch_user_t;
/* PDSCH object */
typedef struct SRSLTE_API {
srslte_cell_t cell;
@ -57,7 +51,6 @@ typedef struct SRSLTE_API {
uint32_t nof_rx_antennas;
uint32_t max_re;
uint16_t ue_rnti;
bool is_ue;
bool llr_is_8bit;
@ -79,11 +72,6 @@ typedef struct SRSLTE_API {
srslte_evm_buffer_t* evm_buffer[SRSLTE_MAX_CODEWORDS];
float avg_evm;
// This is to generate the scrambling seq for multiple CRNTIs
srslte_pdsch_user_t** users;
srslte_sequence_t tmp_seq;
srslte_sch_t dl_sch;
void* coworker_ptr;
@ -108,10 +96,6 @@ SRSLTE_API int srslte_pdsch_enable_coworker(srslte_pdsch_t* q);
SRSLTE_API int srslte_pdsch_set_cell(srslte_pdsch_t* q, srslte_cell_t cell);
SRSLTE_API int srslte_pdsch_set_rnti(srslte_pdsch_t* q, uint16_t rnti);
SRSLTE_API void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti);
/* These functions do not modify the state and run in real-time */
SRSLTE_API int srslte_pdsch_encode(srslte_pdsch_t* q,
srslte_dl_sf_cfg_t* sf,

@ -58,12 +58,6 @@
#define SRSLTE_PUCCH_DEFAULT_THRESHOLD_FORMAT3 (0.5f)
#define SRSLTE_PUCCH_DEFAULT_THRESHOLD_DMRS (0.4f)
typedef struct {
srslte_sequence_t seq_f2[SRSLTE_NOF_SF_X_FRAME];
uint32_t cell_id;
bool sequence_generated;
} srslte_pucch_user_t;
/* PUCCH object */
typedef struct SRSLTE_API {
srslte_cell_t cell;
@ -71,9 +65,7 @@ typedef struct SRSLTE_API {
srslte_uci_cqi_pucch_t cqi;
srslte_pucch_user_t** users;
srslte_sequence_t tmp_seq;
uint16_t ue_rnti;
srslte_sequence_t seq_f2;
bool is_ue;
int16_t llr[SRSLTE_PUCCH3_NOF_BITS];
@ -109,10 +101,6 @@ SRSLTE_API void srslte_pucch_free(srslte_pucch_t* q);
/* These functions modify the state of the object and may take some time */
SRSLTE_API int srslte_pucch_set_cell(srslte_pucch_t* q, srslte_cell_t cell);
SRSLTE_API int srslte_pucch_set_rnti(srslte_pucch_t* q, uint16_t rnti);
SRSLTE_API void srslte_pucch_free_rnti(srslte_pucch_t* q, uint16_t rnti);
/* These functions do not modify the state and run in real-time */
SRSLTE_API void srslte_pucch_uci_gen_cfg(srslte_pucch_t* q, srslte_pucch_cfg_t* cfg, srslte_uci_data_t* uci_data);
@ -148,7 +136,7 @@ SRSLTE_API int srslte_pucch_format2ab_mod_bits(srslte_pucch_format_t format, uin
SRSLTE_API uint32_t srslte_pucch_m(const srslte_pucch_cfg_t* cfg, srslte_cp_t cp);
SRSLTE_API uint32_t srslte_pucch_n_prb(srslte_cell_t* cell, srslte_pucch_cfg_t* cfg, uint32_t ns);
SRSLTE_API uint32_t srslte_pucch_n_prb(const srslte_cell_t* cell, const srslte_pucch_cfg_t* cfg, uint32_t ns);
SRSLTE_API int srslte_pucch_n_cs_cell(srslte_cell_t cell,
uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB]);

@ -86,6 +86,11 @@
*/
#define SRSLTE_PUCCH_NR_MAX_NOF_SETS 4
/**
* Maximum number of SR resources (TS 38.331 maxNrofSR-Resources)
*/
#define SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES 8
typedef enum SRSLTE_API {
SRSLTE_PUCCH_NR_FORMAT_0 = 0,
SRSLTE_PUCCH_NR_FORMAT_1,
@ -151,10 +156,24 @@ typedef struct SRSLTE_API {
uint32_t max_payload_size; ///< Maximum payload size, set to 0 if not present
} srslte_pucch_nr_resource_set_t;
/**
* @brief Scheduling Request resource described in TS 38.331 SchedulingRequestResourceConfig
* @note Every SR configuration corresponds to one or more logical channels (resources)
*/
typedef struct SRSLTE_API {
uint32_t sr_id; ///< Scheduling Request identifier
uint32_t period; ///< Period in slots
uint32_t offset; ///< Offset from beginning of the period in slots
srslte_pucch_nr_resource_t resource; ///< PUCCH resource
bool configured; ///< Set to true if higher layers added this value, otherwise set to false
} srslte_pucch_nr_sr_resource_t;
typedef struct SRSLTE_API {
srslte_pucch_nr_common_cfg_t common; ///< NR-PUCCH configuration common for all formats and resources
srslte_pucch_nr_resource_set_t sets[SRSLTE_PUCCH_NR_MAX_NOF_SETS]; ///< Resource sets, indexed by pucch-ResourceSetId
bool enabled; ///< Set to true if any set is enabled
srslte_pucch_nr_sr_resource_t
sr_resources[SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES]; ///< SR resources, indexed by identifier
} srslte_pucch_nr_hl_cfg_t;
/**

@ -45,12 +45,6 @@
#include "srslte/phy/phch/sch.h"
#include "srslte/phy/scrambling/scrambling.h"
typedef struct {
srslte_sequence_t seq[SRSLTE_NOF_SF_X_FRAME];
uint32_t cell_id;
bool sequence_generated;
} srslte_pusch_user_t;
/* PUSCH object */
typedef struct SRSLTE_API {
srslte_cell_t cell;
@ -76,10 +70,6 @@ typedef struct SRSLTE_API {
srslte_modem_table_t mod[SRSLTE_MOD_NITEMS];
srslte_sch_t ul_sch;
// This is to generate the scrambling seq for multiple CRNTIs
srslte_pusch_user_t** users;
srslte_sequence_t tmp_seq;
// EVM buffer
srslte_evm_buffer_t* evm_buffer;
@ -108,10 +98,6 @@ SRSLTE_API void srslte_pusch_free(srslte_pusch_t* q);
/* These functions modify the state of the object and may take some time */
SRSLTE_API int srslte_pusch_set_cell(srslte_pusch_t* q, srslte_cell_t cell);
SRSLTE_API int srslte_pusch_set_rnti(srslte_pusch_t* q, uint16_t rnti);
SRSLTE_API void srslte_pusch_free_rnti(srslte_pusch_t* q, uint16_t rnti);
/**
* Asserts PUSCH grant attributes are in range
* @param grant Pointer to PUSCH grant

@ -102,6 +102,6 @@ SRSLTE_API int srslte_ra_mcs_from_tbs_idx(uint32_t tbs_idx, bool use_tbs_index_a
SRSLTE_API int srslte_ra_tbs_from_idx(uint32_t tbs_idx, uint32_t n_prb);
SRSLTE_API int srslte_ra_tbs_to_table_idx(uint32_t tbs, uint32_t n_prb);
SRSLTE_API int srslte_ra_tbs_to_table_idx(uint32_t tbs, uint32_t n_prb, uint32_t max_tbs_idx);
#endif // SRSLTE_RA_H

@ -119,4 +119,11 @@ SRSLTE_API int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pu
const srslte_uci_cfg_nr_t* uci_cfg,
srslte_pucch_nr_resource_t* resource);
/**
* @brief Computes the number of SR bits
* @param K Number of SR transmission opportunities, including negative
* @return The number of bits according to the number of SRs
*/
SRSLTE_API uint32_t srslte_ra_ul_nr_nof_sr_bits(uint32_t K);
#endif // SRSLTE_RA_UL_NR_H

@ -22,6 +22,7 @@
#ifndef SRSLTE_UCI_CFG_NR_H
#define SRSLTE_UCI_CFG_NR_H
#include "csi_cfg.h"
#include "srslte/phy/common/phy_common.h"
#include <stdbool.h>
#include <stdint.h>
@ -61,8 +62,8 @@ typedef struct SRSLTE_API {
/// Common Parameters
uint32_t o_ack; ///< Number of HARQ-ACK bits
uint32_t o_sr; ///< Number of SR bits
uint32_t o_csi1; ///< Number of CSI1 report number of bits
uint32_t o_csi2; ///< Number of CSI2 report number of bits
srslte_csi_report_cfg_t csi[SRSLTE_CSI_MAX_NOF_REPORT]; ///< CSI report configuration
uint32_t nof_csi; ///< Number of CSI reports
/// PUSCH only parameters
srslte_mod_t modulation; ///< Modulation
@ -71,7 +72,9 @@ typedef struct SRSLTE_API {
uint16_t rnti; ///< RNTI
uint32_t pucch_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; ///< number of CCEs in a CORESET of a PDCCH reception with DCI format 1_0 or DCI format 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
bool sr_positive_present; ///< Set to true if there is at least one positive SR
} srslte_uci_cfg_nr_t;
/**
@ -79,9 +82,8 @@ typedef struct SRSLTE_API {
*/
typedef struct SRSLTE_API {
uint8_t ack[SRSLTE_UCI_NR_MAX_ACK_BITS]; ///< HARQ ACK feedback bits
uint8_t sr[SRSLTE_UCI_NR_MAX_SR_BITS]; ///< Scheduling Request bits
uint8_t csi1[SRSLTE_UCI_NR_MAX_CSI1_BITS]; ///< Channel State Information part 1
uint8_t csi2[SRSLTE_UCI_NR_MAX_CSI2_BITS]; ///< Channel State Information part 2
uint32_t sr; ///< Number of positive SR
srslte_csi_report_value_t csi[SRSLTE_CSI_MAX_NOF_REPORT]; ///< Packed CSI report values
bool valid; ///< Indicates whether the message has been decoded successfully, ignored in the transmitter
} srslte_uci_value_nr_t;

@ -79,7 +79,6 @@ typedef struct SRSLTE_API {
srslte_cell_t cell;
uint32_t nof_rx_antennas;
uint16_t current_mbsfn_area_id;
uint16_t pregen_rnti;
// Objects for all DL Physical Channels
srslte_pcfich_t pcfich;
@ -101,10 +100,8 @@ typedef struct SRSLTE_API {
// Buffers to store channel symbols after demodulation
cf_t* sf_symbols[SRSLTE_MAX_PORTS];
dci_blind_search_t current_ss_common;
// Variables for blind DCI search
dci_blind_search_t current_ss_ue[SRSLTE_MI_MAX_REGS][SRSLTE_NOF_CFI][SRSLTE_NOF_SF_X_FRAME];
dci_blind_search_t current_ss_common[SRSLTE_MI_MAX_REGS][SRSLTE_NOF_CFI];
srslte_dci_msg_t pending_ul_dci_msg[SRSLTE_MAX_DCI_MSG];
uint32_t pending_ul_dci_count;
@ -167,8 +164,6 @@ SRSLTE_API void srslte_ue_dl_free(srslte_ue_dl_t* q);
SRSLTE_API int srslte_ue_dl_set_cell(srslte_ue_dl_t* q, srslte_cell_t cell);
SRSLTE_API void srslte_ue_dl_set_rnti(srslte_ue_dl_t* q, uint16_t rnti);
SRSLTE_API int srslte_ue_dl_set_mbsfn_area_id(srslte_ue_dl_t* q, uint16_t mbsfn_area_id);
SRSLTE_API void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t* q, uint8_t non_mbsfn_region_length);

@ -79,7 +79,6 @@ typedef enum {
} srslte_ue_ul_normalize_mode_t;
typedef struct SRSLTE_API {
srslte_ul_cfg_t ul_cfg;
bool grant_available;
uint32_t cc_idx;
@ -95,7 +94,6 @@ typedef struct SRSLTE_API {
typedef struct SRSLTE_API {
srslte_cell_t cell;
uint16_t current_rnti;
bool signals_pregenerated;
srslte_ofdm_t fft;
@ -123,8 +121,6 @@ SRSLTE_API void srslte_ue_ul_free(srslte_ue_ul_t* q);
SRSLTE_API int srslte_ue_ul_set_cell(srslte_ue_ul_t* q, srslte_cell_t cell);
SRSLTE_API void srslte_ue_ul_set_rnti(srslte_ue_ul_t* q, uint16_t rnti);
SRSLTE_API int srslte_ue_ul_pregen_signals(srslte_ue_ul_t* q, srslte_ue_ul_cfg_t* cfg);
SRSLTE_API int srslte_ue_ul_dci_to_pusch_grant(srslte_ue_ul_t* q,

@ -84,4 +84,21 @@ SRSLTE_API int srslte_ue_ul_nr_pucch_info(const srslte_pucch_nr_resource_t* reso
char* str,
uint32_t str_len);
/**
* @brief Decides whether the provided slot index within the radio frame is a SR transmission opportunity
*
* @remark Implemented according to TS 38.213 9.2.4 UE procedure for reporting SR
*
* @param sr_resources Provides the SR configuration from the upper layers
* @param slot_idx Slot index in the radio frame
* @param[out] sr_resource_id Optional SR resource index (or identifier)
*
* @return the number of SR opportunities if the provided slot index is a SR transmission opportunity, SRSLTE_ERROR code
* if provided parameters are invalid
*/
SRSLTE_API int
srslte_ue_ul_nr_sr_send_slot(const srslte_pucch_nr_sr_resource_t sr_resources[SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES],
uint32_t slot_idx,
uint32_t sr_resource_id[SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES]);
#endif // SRSLTE_UE_UL_DATA_H

@ -36,6 +36,7 @@ extern "C" {
#include "srslte/config.h"
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
@ -108,6 +109,7 @@ SRSLTE_API void* srslte_vec_realloc(void* ptr, uint32_t old_size, uint32_t new_s
SRSLTE_API void srslte_vec_zero(void* ptr, uint32_t nsamples);
SRSLTE_API void srslte_vec_cf_zero(cf_t* ptr, uint32_t nsamples);
SRSLTE_API void srslte_vec_f_zero(float* ptr, uint32_t nsamples);
SRSLTE_API void srslte_vec_i8_zero(int8_t* ptr, uint32_t nsamples);
SRSLTE_API void srslte_vec_u8_zero(uint8_t* ptr, uint32_t nsamples);
SRSLTE_API void srslte_vec_i16_zero(int16_t* ptr, uint32_t nsamples);
SRSLTE_API void srslte_vec_u32_zero(uint32_t* ptr, uint32_t nsamples);

@ -90,6 +90,7 @@ extern "C" {
#include "srslte/phy/fec/softbuffer.h"
#include "srslte/phy/phch/cqi.h"
#include "srslte/phy/phch/csi.h"
#include "srslte/phy/phch/dci.h"
#include "srslte/phy/phch/dci_nr.h"
#include "srslte/phy/phch/pbch.h"

@ -0,0 +1,33 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 SRSLTE_SYS_METRICS_H
#define SRSLTE_SYS_METRICS_H
#include <cstdint>
namespace srslte {
/// Metrics of cpu usage, memory consumption and number of thread used by the process.
struct sys_metrics_t {
uint32_t process_realmem_kB = 0;
uint32_t process_virtualmem_kB = 0;
float process_realmem = -1.f;
float process_virtualmem = -1.f;
uint32_t thread_count = 0;
float process_cpu_usage = -1.f;
float system_mem = -1.f;
};
} // namespace srslte
#endif // SRSLTE_SYS_METRICS_H

@ -0,0 +1,66 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 SRSLTE_SYS_METRICS_PROCESSOR_H
#define SRSLTE_SYS_METRICS_PROCESSOR_H
#include "srslte/system/sys_metrics.h"
#include <chrono>
#include <string>
namespace srslte {
/// Process information from the system to create sys_metrics_t. The information is processed from the /proc/ system.
class sys_metrics_processor
{
/// Helper class used to parse the information from the /proc/[pid]/stats.
struct proc_stats_info {
proc_stats_info();
// Initialize the variables that will be used.
int32_t num_threads = 0;
uint32_t utime = 0;
uint32_t stime = 0;
// Rest of the information of the stats file.
int32_t pid, ppid, pgrp, session, tty_nr, tpgid, exit_signal, processor, exit_code, cutime, cstime, priority, nice,
itrealvalue, rss, cguest_time;
uint32_t minflt, cminflt, majflt, cmajflt, vsize, rsslim, startcode, endcode, startstack, kstkesp, kstkeip, signal,
blocked, sigignore, sigcatch, wchan, nswap, cnswap, guest_time, start_data, end_data, start_brk, arg_start,
arg_end, env_start, env_end, flags, rt_priority, policy;
uint64_t starttime, delaycct_blkio_ticks;
uint8_t state;
std::string comm;
};
public:
/// Measures and returns the system metrics.
sys_metrics_t get_metrics();
private:
/// Calculates and returns the cpu usage in %. current_query is the most recent proc_stats_info, and
/// delta_time_in_seconds is the elapsed time between the last measure and current in seconds. NOTE: Returns -1.0f on
/// error.
float calculate_cpu_usage(const proc_stats_info& current_query, float delta_time_in_seconds) const;
/// Calculate the memory parameters and writes them in metrics.
/// NOTE: on error, metrics memory parameters are set to 0.
void calculate_mem_usage(sys_metrics_t& metrics) const;
private:
proc_stats_info last_query = {};
std::chrono::time_point<std::chrono::steady_clock> last_query_time = std::chrono::steady_clock::now();
};
} // namespace srslte
#endif // SRSLTE_SYS_METRICS_PROCESSOR_H

@ -23,7 +23,10 @@
#define SRSUE_DUMMY_CLASSES_H
#include "srslte/common/task_scheduler.h"
#include "srslte/interfaces/phy_interface_types.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/interfaces/ue_phy_interfaces.h"
#include "srslte/interfaces/ue_rlc_interfaces.h"
namespace srsue {
@ -49,7 +52,7 @@ public:
// run pending tasks without updating timers
void run_pending_tasks() { task_sched.run_pending_tasks(); }
srslte::task_scheduler task_sched{512, 0, 100};
srslte::task_scheduler task_sched{512, 100};
};
class rlc_dummy_interface : public rlc_interface_mac

@ -25,8 +25,9 @@
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/task_scheduler.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/interfaces/ue_pdcp_interfaces.h"
#include "srslte/upper/pdcp_entity_lte.h"
#include <set>
namespace srslte {

@ -22,16 +22,82 @@
#ifndef SRSLTE_PDCP_ENTITY_LTE_H
#define SRSLTE_PDCP_ENTITY_LTE_H
#include "srslte/adt/circular_array.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/security.h"
#include "srslte/common/threads.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/interfaces/ue_rrc_interfaces.h"
#include "srslte/upper/pdcp_entity_base.h"
namespace srsue {
class gw_interface_pdcp;
class rlc_interface_pdcp;
} // namespace srsue
namespace srslte {
class undelivered_sdus_queue
{
public:
explicit undelivered_sdus_queue(srslte::task_sched_handle task_sched);
bool empty() const { return count == 0; }
bool is_full() const { return count >= capacity; }
uint32_t size() const { return count; }
static uint32_t get_capacity() { return capacity; }
bool has_sdu(uint32_t sn) const
{
assert(sn != invalid_sn && "provided PDCP SN is invalid");
return sdus[sn].sdu != nullptr and sdus[sn].sdu->md.pdcp_sn == sn;
}
// Getter for the number of discard timers. Used for debugging.
size_t nof_discard_timers() const;
bool add_sdu(uint32_t sn,
const srslte::unique_byte_buffer_t& sdu,
uint32_t discard_timeout,
const std::function<void(uint32_t)>& callback);
unique_byte_buffer_t& operator[](uint32_t sn)
{
assert(has_sdu(sn));
return sdus[sn].sdu;
}
bool clear_sdu(uint32_t sn);
void clear();
uint32_t get_bytes() const { return bytes; }
uint32_t get_fms() const { return fms; }
void set_fms(uint32_t fms_) { fms = fms_; }
void update_fms();
void update_lms(uint32_t sn);
uint32_t get_lms() const { return lms; }
std::map<uint32_t, srslte::unique_byte_buffer_t> get_buffered_sdus();
private:
const static uint32_t capacity = 4096;
const static uint32_t invalid_sn = -1;
static uint32_t increment_sn(uint32_t sn) { return (sn + 1) % capacity; }
struct sdu_data {
srslte::unique_byte_buffer_t sdu;
srslte::unique_timer discard_timer;
};
uint32_t count = 0;
uint32_t bytes = 0;
uint32_t fms = 0;
uint32_t lms = 0;
srslte::circular_array<sdu_data, capacity> sdus;
};
/****************************************************************************
* Structs and Defines
* Ref: 3GPP TS 36.323 v10.1.0
@ -43,6 +109,7 @@ namespace srslte {
* LTE PDCP Entity
* Class for LTE PDCP entities
***************************************************************************/
class pdcp_entity_lte final : public pdcp_entity_base
{
public:
@ -82,13 +149,12 @@ public:
void get_bearer_state(pdcp_lte_state_t* state) override;
void set_bearer_state(const pdcp_lte_state_t& state) override;
// Getter for the number of discard timers. Used for debugging.
uint32_t nof_discard_timers() const;
// Metrics helpers
pdcp_bearer_metrics_t get_metrics() override;
void reset_metrics() override;
size_t nof_discard_timers() const { return undelivered_sdus != nullptr ? undelivered_sdus->nof_discard_timers() : 0; }
private:
srsue::rlc_interface_pdcp* rlc = nullptr;
srsue::rrc_interface_pdcp* rrc = nullptr;
@ -100,20 +166,18 @@ private:
uint32_t reordering_window = 0;
uint32_t maximum_pdcp_sn = 0;
// PDU handlers
void handle_control_pdu(srslte::unique_byte_buffer_t pdu);
void handle_srb_pdu(srslte::unique_byte_buffer_t pdu);
void handle_um_drb_pdu(srslte::unique_byte_buffer_t pdu);
void handle_am_drb_pdu(srslte::unique_byte_buffer_t pdu);
// Discard callback (discardTimer)
class discard_callback;
std::vector<unique_timer> discard_timers;
unique_timer* get_discard_timer(uint32_t sn);
void stop_discard_timer(uint32_t sn);
// TX Queue
uint32_t maximum_allocated_sns_window = 2048;
std::map<uint32_t, unique_byte_buffer_t> undelivered_sdus_queue;
void handle_control_pdu(srslte::unique_byte_buffer_t pdu);
void handle_srb_pdu(srslte::unique_byte_buffer_t pdu);
void handle_um_drb_pdu(srslte::unique_byte_buffer_t pdu);
void handle_am_drb_pdu(srslte::unique_byte_buffer_t pdu);
std::unique_ptr<undelivered_sdus_queue> undelivered_sdus;
};
// Discard callback (discardTimer)

@ -30,7 +30,9 @@
#include "srslte/common/security.h"
#include "srslte/common/task_scheduler.h"
#include "srslte/common/threads.h"
#include "srslte/interfaces/ue_gw_interfaces.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/interfaces/ue_rlc_interfaces.h"
#include <map>
namespace srslte {

@ -25,7 +25,10 @@
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/task_scheduler.h"
#include "srslte/interfaces/ue_pdcp_interfaces.h"
#include "srslte/interfaces/ue_rlc_interfaces.h"
#include "srslte/interfaces/ue_rrc_interfaces.h"
#include "srslte/upper/rlc_common.h"
#include "srslte/upper/rlc_metrics.h"

@ -25,7 +25,6 @@
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/upper/byte_buffer_queue.h"
#include "srslte/upper/rlc_common.h"
#include <map>
@ -42,4 +41,11 @@ bool rlc_am_is_control_pdu(byte_buffer_t* pdu);
} // namespace srslte
namespace srsue {
class pdcp_interface_rlc;
class rrc_interface_rlc;
} // namespace srsue
#endif // SRSLTE_RLC_AM_BASE_H

@ -27,8 +27,8 @@
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/task_scheduler.h"
#include "srslte/common/timeout.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/upper/byte_buffer_queue.h"
#include "srslte/upper/rlc_am_base.h"
#include "srslte/upper/rlc_common.h"
@ -43,6 +43,7 @@ namespace srslte {
struct rlc_amd_rx_pdu_t {
rlc_amd_pdu_header_t header;
unique_byte_buffer_t buf;
uint32_t rlc_sn;
};
struct rlc_amd_rx_pdu_segments_t {
@ -78,14 +79,16 @@ struct pdcp_sdu_info_t {
std::vector<rlc_sn_info_t> rlc_sn_info_list; // List of RLC PDUs in transit and whether they have been acked or not.
};
struct tx_window_t {
tx_window_t() { clear(); }
void add_pdu(size_t sn)
template <class T>
struct rlc_ringbuffer_t {
rlc_ringbuffer_t() { clear(); }
T& add_pdu(size_t sn)
{
assert(not active_flag[sn]);
assert(not has_sn(sn));
window[sn].rlc_sn = sn;
active_flag[sn] = true;
count++;
return window[sn];
}
void remove_pdu(size_t sn)
{
@ -94,7 +97,7 @@ struct tx_window_t {
active_flag[sn] = false;
count--;
}
rlc_amd_tx_pdu_t& operator[](size_t sn)
T& operator[](size_t sn)
{
assert(has_sn(sn));
return window[sn];
@ -104,30 +107,27 @@ struct tx_window_t {
void clear()
{
std::fill(active_flag.begin(), active_flag.end(), false);
for (size_t i = 0; i < window.size(); ++i) {
window[i].pdcp_sns.clear();
}
count = 0;
}
bool has_sn(uint32_t sn) const { return active_flag[sn] and window[sn].rlc_sn == sn; }
rlc_amd_tx_pdu_t& front()
bool has_sn(uint32_t sn) const { return active_flag[sn] and (window[sn].rlc_sn == sn); }
// Return the sum data bytes of all active PDUs (check PDU is non-null)
uint32_t get_buffered_bytes()
{
assert(not empty());
uint32_t min_rlc_sn = std::numeric_limits<uint32_t>::max(), min_idx = std::numeric_limits<uint32_t>::max();
for (uint32_t i = 0; i < window.size(); ++i) {
if (active_flag[i] and window[i].rlc_sn < min_rlc_sn) {
min_idx = i;
min_rlc_sn = window[i].rlc_sn;
uint32_t buff_size = 0;
for (const auto& pdu : window) {
if (pdu.buf != nullptr) {
buff_size += pdu.buf->N_bytes;
}
}
assert(has_sn(min_rlc_sn));
return window[min_idx];
return buff_size;
}
private:
size_t count = 0;
srslte::circular_array<bool, RLC_AM_WINDOW_SIZE> active_flag = {};
srslte::circular_array<rlc_amd_tx_pdu_t, RLC_AM_WINDOW_SIZE> window;
srslte::circular_array<T, RLC_AM_WINDOW_SIZE> window;
};
struct buffered_pdcp_pdu_list {
@ -179,6 +179,51 @@ private:
uint32_t count = 0;
};
class pdu_retx_queue
{
public:
rlc_amd_retx_t& push()
{
assert(not full());
rlc_amd_retx_t& p = buffer[wpos];
wpos = (wpos + 1) % RLC_AM_WINDOW_SIZE;
return p;
}
void pop() { rpos = (rpos + 1) % RLC_AM_WINDOW_SIZE; }
rlc_amd_retx_t& front()
{
assert(not empty());
return buffer[rpos];
}
void clear()
{
wpos = 0;
rpos = 0;
}
bool has_sn(uint32_t sn) const
{
for (size_t i = rpos; i != wpos; i = (i + 1) % RLC_AM_WINDOW_SIZE) {
if (buffer[i].sn == sn) {
return true;
}
}
return false;
}
size_t size() const { return (wpos >= rpos) ? wpos - rpos : RLC_AM_WINDOW_SIZE + wpos - rpos; }
bool empty() const { return wpos == rpos; }
bool full() const { return size() == RLC_AM_WINDOW_SIZE - 1; }
private:
std::array<rlc_amd_retx_t, RLC_AM_WINDOW_SIZE> buffer;
size_t wpos = 0;
size_t rpos = 0;
};
class rlc_am_lte : public rlc_common
{
public:
@ -247,17 +292,17 @@ private:
int build_retx_pdu(uint8_t* payload, uint32_t nof_bytes);
int build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_t retx);
int build_data_pdu(uint8_t* payload, uint32_t nof_bytes);
void update_notification_ack_info(const rlc_amd_tx_pdu_t& tx_pdu, std::vector<uint32_t>& notify_info_vec);
void update_notification_ack_info(const rlc_amd_tx_pdu_t& tx_pdu);
void debug_state();
bool retx_queue_has_sn(uint32_t sn);
int required_buffer_size(rlc_amd_retx_t retx);
void retransmit_pdu();
// Helpers
bool poll_required();
bool do_status();
void check_sn_reached_max_retx(uint32_t sn);
rlc_am_lte* parent = nullptr;
byte_buffer_pool* pool = nullptr;
@ -308,8 +353,9 @@ private:
bsr_callback_t bsr_callback;
// Tx windows
tx_window_t tx_window;
std::deque<rlc_amd_retx_t> retx_queue;
rlc_ringbuffer_t<rlc_amd_tx_pdu_t> tx_window;
pdu_retx_queue retx_queue;
std::vector<uint32_t> notify_info_vec;
// Mutexes
pthread_mutex_t mutex;
@ -378,7 +424,7 @@ private:
pthread_mutex_t mutex;
// Rx windows
std::map<uint32_t, rlc_amd_rx_pdu_t> rx_window;
rlc_ringbuffer_t<rlc_amd_rx_pdu_t> rx_window;
std::map<uint32_t, rlc_amd_rx_pdu_segments_t> rx_segments;
bool poll_received = false;

@ -25,7 +25,6 @@
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/upper/byte_buffer_queue.h"
#include "srslte/upper/rlc_am_base.h"
#include <map>

@ -24,6 +24,7 @@
#include "srslte/common/block_queue.h"
#include "srslte/common/logmap.h"
#include "srslte/interfaces/rlc_interface_types.h"
#include "srslte/upper/rlc_metrics.h"
#include <stdlib.h>

@ -25,10 +25,16 @@
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/upper/byte_buffer_queue.h"
#include "srslte/upper/rlc_common.h"
namespace srsue {
class pdcp_interface_rlc;
class rrc_interface_rlc;
} // namespace srsue
namespace srslte {
class rlc_tm final : public rlc_common

@ -26,7 +26,7 @@
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/task_scheduler.h"
#include "srslte/upper/byte_buffer_queue.h"
#include "srslte/upper/rlc_common.h"
#include <map>
@ -34,6 +34,13 @@
#include <pthread.h>
#include <queue>
namespace srsue {
class pdcp_interface_rlc;
class rrc_interface_rlc;
} // namespace srsue
namespace srslte {
class rlc_um_base : public rlc_common

@ -25,7 +25,6 @@
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/upper/byte_buffer_queue.h"
#include "srslte/upper/rlc_um_base.h"
#include <map>

@ -24,4 +24,5 @@ add_subdirectory(mac)
add_subdirectory(phy)
add_subdirectory(radio)
add_subdirectory(srslog)
add_subdirectory(system)
add_subdirectory(upper)

@ -5911,6 +5911,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_information_msg(LIBLTE_BYTE_MSG_STRUCT*
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8* msg_ptr = msg->msg;
uint8* msg_end = msg->msg + msg->N_bytes;
uint8 sec_hdr_type;
if (msg != NULL && emm_info != NULL) {
@ -5935,7 +5936,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_information_msg(LIBLTE_BYTE_MSG_STRUCT*
}
// Short Name For Network
if (LIBLTE_MME_SHORT_NAME_FOR_NETWORK_IEI == *msg_ptr) {
if (msg_ptr < msg_end && LIBLTE_MME_SHORT_NAME_FOR_NETWORK_IEI == *msg_ptr) {
msg_ptr++;
liblte_mme_unpack_network_name_ie(&msg_ptr, &emm_info->short_net_name);
emm_info->short_net_name_present = true;
@ -5944,7 +5945,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_information_msg(LIBLTE_BYTE_MSG_STRUCT*
}
// Local Time Zone
if (LIBLTE_MME_LOCAL_TIME_ZONE_IEI == *msg_ptr) {
if (msg_ptr < msg_end && LIBLTE_MME_LOCAL_TIME_ZONE_IEI == *msg_ptr) {
msg_ptr++;
liblte_mme_unpack_time_zone_ie(&msg_ptr, &emm_info->local_time_zone);
emm_info->local_time_zone_present = true;
@ -5953,7 +5954,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_information_msg(LIBLTE_BYTE_MSG_STRUCT*
}
// Universal Time And Local Time Zone
if (LIBLTE_MME_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_IEI == *msg_ptr) {
if (msg_ptr < msg_end && LIBLTE_MME_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_IEI == *msg_ptr) {
msg_ptr++;
liblte_mme_unpack_time_zone_and_time_ie(&msg_ptr, &emm_info->utc_and_local_time_zone);
emm_info->utc_and_local_time_zone_present = true;
@ -5962,7 +5963,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_information_msg(LIBLTE_BYTE_MSG_STRUCT*
}
// Network Daylight Saving Time
if (LIBLTE_MME_NETWORK_DAYLIGHT_SAVING_TIME_IEI == *msg_ptr) {
if (msg_ptr < msg_end && LIBLTE_MME_NETWORK_DAYLIGHT_SAVING_TIME_IEI == *msg_ptr) {
msg_ptr++;
liblte_mme_unpack_daylight_saving_time_ie(&msg_ptr, &emm_info->net_dst);
emm_info->net_dst_present = true;

@ -120,9 +120,48 @@ srslte::pdcp_config_t make_drb_pdcp_config_t(const uint8_t bearer_id, bool is_ue
case 10:
discard_timer = pdcp_discard_timer_t::ms10;
break;
case 20:
discard_timer = pdcp_discard_timer_t::ms20;
break;
case 30:
discard_timer = pdcp_discard_timer_t::ms30;
break;
case 40:
discard_timer = pdcp_discard_timer_t::ms40;
break;
case 50:
discard_timer = pdcp_discard_timer_t::ms50;
break;
case 60:
discard_timer = pdcp_discard_timer_t::ms60;
break;
case 75:
discard_timer = pdcp_discard_timer_t::ms75;
break;
case 100:
discard_timer = pdcp_discard_timer_t::ms100;
break;
case 150:
discard_timer = pdcp_discard_timer_t::ms150;
break;
case 200:
discard_timer = pdcp_discard_timer_t::ms200;
break;
case 250:
discard_timer = pdcp_discard_timer_t::ms250;
break;
case 300:
discard_timer = pdcp_discard_timer_t::ms300;
break;
case 500:
discard_timer = pdcp_discard_timer_t::ms500;
break;
case 750:
discard_timer = pdcp_discard_timer_t::ms750;
break;
case 1500:
discard_timer = pdcp_discard_timer_t::ms1500;
break;
default:
discard_timer = pdcp_discard_timer_t::infinity;
break;

@ -32,8 +32,10 @@ set(SOURCES arch_select.cc
logmap.cc
logger_srslog_wrapper.cc
mac_pcap.cc
mac_pcap_base.cc
nas_pcap.cc
network_utils.cc
mac_pcap_net.cc
pcap.c
rlc_pcap.cc
s1ap_pcap.cc
@ -58,7 +60,7 @@ add_dependencies(srslte_common gen_build_info)
add_executable(arch_select arch_select.cc)
target_include_directories(srslte_common PUBLIC ${SEC_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR} ${BACKWARD_INCLUDE_DIRS})
target_link_libraries(srslte_common srslte_phy srslog ${SEC_LIBRARIES} ${BACKWARD_LIBRARIES})
target_link_libraries(srslte_common srslte_phy srslog ${SEC_LIBRARIES} ${BACKWARD_LIBRARIES} ${SCTP_LIBRARIES})
target_compile_definitions(srslte_common PRIVATE ${BACKWARD_DEFINITIONS})
INSTALL(TARGETS srslte_common DESTINATION ${LIBRARY_DIR})

@ -226,8 +226,9 @@ int srslte_basic_vnf::handle_ul_ind(basic_vnf_api::ul_ind_msg_t* msg)
ul_grant.tti = msg->tti;
ul_grant.tbs = msg->pdus.length;
ul_grant.rnti = msg->rnti;
srslte::unique_byte_buffer_t tx_pdu = srslte::make_byte_buffer();
m_ue_stack->new_grant_ul(cc_idx, ul_grant, tx_pdu.get());
srsue::stack_interface_phy_nr::tb_action_ul_t ul_action = {};
m_ue_stack->new_grant_ul(cc_idx, ul_grant, &ul_action);
return SRSLTE_SUCCESS;
}

@ -20,27 +20,16 @@
*/
#include "srslte/common/mac_pcap.h"
#include "srslte/config.h"
#include "srslte/phy/common/phy_common.h"
#include <stdint.h>
#include "srslte/common/threads.h"
namespace srslte {
mac_pcap::mac_pcap(srslte_rat_t rat_) :
logger(srslog::fetch_basic_logger("MAC")), thread("PCAP_WRITER_" + to_string(rat_)), rat(rat_)
{}
mac_pcap::mac_pcap() : mac_pcap_base() {}
mac_pcap::~mac_pcap()
{
close();
}
void mac_pcap::enable(bool enable_)
{
std::lock_guard<std::mutex> lock(mutex);
running = enable_;
}
uint32_t mac_pcap::open(std::string filename_, uint32_t ue_id_)
{
std::lock_guard<std::mutex> lock(mutex);
@ -50,18 +39,7 @@ uint32_t mac_pcap::open(std::string filename_, uint32_t ue_id_)
}
// set DLT for selected RAT
switch (rat) {
case srslte_rat_t::lte:
dlt = MAC_LTE_DLT;
break;
case srslte_rat_t::nr:
dlt = UDP_DLT;
break;
default:
logger.error("Error opening PCAP. Unsupported RAT selected.");
return SRSLTE_ERROR;
}
pcap_file = LTE_PCAP_Open(dlt, filename_.c_str());
if (pcap_file == nullptr) {
logger.error("Couldn't open %s to write PCAP", filename_.c_str());
@ -97,7 +75,7 @@ uint32_t mac_pcap::close()
// close file handle
{
std::lock_guard<std::mutex> lock(mutex);
srslte::console("Saving %s MAC PCAP (DLT=%d) to %s\n", to_string(rat).c_str(), dlt, filename.c_str());
srslte::console("Saving MAC PCAP (DLT=%d) to %s\n", dlt, filename.c_str());
LTE_PCAP_Close(pcap_file);
pcap_file = nullptr;
}
@ -105,15 +83,15 @@ uint32_t mac_pcap::close()
return SRSLTE_SUCCESS;
}
void mac_pcap::write_pdu(pcap_pdu_t& pdu)
void mac_pcap::write_pdu(srslte::mac_pcap_base::pcap_pdu_t& pdu)
{
if (pdu.pdu != nullptr) {
switch (rat) {
switch (pdu.rat) {
case srslte_rat_t::lte:
LTE_PCAP_MAC_WritePDU(pcap_file, &pdu.context, pdu.pdu->msg, pdu.pdu->N_bytes);
LTE_PCAP_MAC_UDP_WritePDU(pcap_file, &pdu.context, pdu.pdu->msg, pdu.pdu->N_bytes);
break;
case srslte_rat_t::nr:
NR_PCAP_MAC_WritePDU(pcap_file, &pdu.context_nr, pdu.pdu->msg, pdu.pdu->N_bytes);
NR_PCAP_MAC_UDP_WritePDU(pcap_file, &pdu.context_nr, pdu.pdu->msg, pdu.pdu->N_bytes);
break;
default:
logger.error("Error writing PDU to PCAP. Unsupported RAT selected.");
@ -121,256 +99,4 @@ void mac_pcap::write_pdu(pcap_pdu_t& pdu)
}
}
void mac_pcap::run_thread()
{
// blocking write until stopped
while (running) {
pcap_pdu_t pdu = queue.wait_pop();
{
std::lock_guard<std::mutex> lock(mutex);
write_pdu(pdu);
}
}
// write remainder of queue
std::lock_guard<std::mutex> lock(mutex);
pcap_pdu_t pdu = {};
while (queue.try_pop(&pdu)) {
write_pdu(pdu);
}
}
void mac_pcap::set_ue_id(uint16_t ue_id_)
{
std::lock_guard<std::mutex> lock(mutex);
ue_id = ue_id_;
}
// Function called from PHY worker context, locking not needed as PDU queue is thread-safe
void mac_pcap::pack_and_queue(uint8_t* payload,
uint32_t payload_len,
uint32_t reTX,
bool crc_ok,
uint8_t cc_idx,
uint32_t tti,
uint16_t crnti,
uint8_t direction,
uint8_t rnti_type)
{
if (running && payload != nullptr) {
pcap_pdu_t pdu = {};
pdu.context.radioType = FDD_RADIO;
pdu.context.direction = direction;
pdu.context.rntiType = rnti_type;
pdu.context.rnti = crnti;
pdu.context.ueid = (uint16_t)ue_id;
pdu.context.isRetx = (uint8_t)reTX;
pdu.context.crcStatusOK = crc_ok;
pdu.context.cc_idx = cc_idx;
pdu.context.sysFrameNumber = (uint16_t)(tti / 10);
pdu.context.subFrameNumber = (uint16_t)(tti % 10);
// try to allocate PDU buffer
pdu.pdu = srslte::make_byte_buffer();
if (pdu.pdu != nullptr && pdu.pdu->get_tailroom() >= payload_len) {
// copy payload into PDU buffer
memcpy(pdu.pdu->msg, payload, payload_len);
pdu.pdu->N_bytes = payload_len;
queue.push(std::move(pdu));
} else {
logger.info("Dropping PDU in PCAP. No buffer available or not enough space (pdu_len=%d).", payload_len);
}
}
}
// Function called from PHY worker context, locking not needed as PDU queue is thread-safe
void mac_pcap::pack_and_queue_nr(uint8_t* payload,
uint32_t payload_len,
uint32_t tti,
uint16_t crnti,
uint8_t harqid,
uint8_t direction,
uint8_t rnti_type)
{
if (running && payload != nullptr) {
pcap_pdu_t pdu = {};
pdu.context_nr.radioType = FDD_RADIO;
pdu.context_nr.direction = direction;
pdu.context_nr.rntiType = rnti_type;
pdu.context_nr.rnti = crnti;
pdu.context_nr.ueid = ue_id;
pdu.context_nr.harqid = harqid;
pdu.context_nr.system_frame_number = tti / 10;
pdu.context_nr.sub_frame_number = tti % 10;
// try to allocate PDU buffer
pdu.pdu = srslte::make_byte_buffer();
if (pdu.pdu != nullptr && pdu.pdu->get_tailroom() >= payload_len) {
// copy payload into PDU buffer
memcpy(pdu.pdu->msg, payload, payload_len);
pdu.pdu->N_bytes = payload_len;
queue.push(std::move(pdu));
} else {
logger.info("Dropping PDU in NR PCAP. No buffer available or not enough space (pdu_len=%d).", payload_len);
}
}
}
void mac_pcap::write_dl_crnti(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint16_t rnti,
bool crc_ok,
uint32_t tti,
uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, 0, crc_ok, cc_idx, tti, rnti, DIRECTION_DOWNLINK, C_RNTI);
}
void mac_pcap::write_dl_ranti(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint16_t rnti,
bool crc_ok,
uint32_t tti,
uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, 0, crc_ok, cc_idx, tti, rnti, DIRECTION_DOWNLINK, RA_RNTI);
}
void mac_pcap::write_ul_crnti(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint16_t rnti,
uint32_t reTX,
uint32_t tti,
uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, reTX, true, cc_idx, tti, rnti, DIRECTION_UPLINK, C_RNTI);
}
void mac_pcap::write_sl_crnti(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint16_t rnti,
uint32_t reTX,
uint32_t tti,
uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, reTX, true, cc_idx, tti, rnti, DIRECTION_UPLINK, SL_RNTI);
}
void mac_pcap::write_dl_bch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, 0, crc_ok, cc_idx, tti, 0, DIRECTION_DOWNLINK, NO_RNTI);
}
void mac_pcap::write_dl_pch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, 0, crc_ok, cc_idx, tti, SRSLTE_PRNTI, DIRECTION_DOWNLINK, P_RNTI);
}
void mac_pcap::write_dl_mch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, 0, crc_ok, cc_idx, tti, SRSLTE_MRNTI, DIRECTION_DOWNLINK, M_RNTI);
}
void mac_pcap::write_dl_sirnti(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, 0, crc_ok, cc_idx, tti, SRSLTE_SIRNTI, DIRECTION_DOWNLINK, SI_RNTI);
}
void mac_pcap::write_dl_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, C_RNTI);
}
void mac_pcap::write_ul_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_UPLINK, C_RNTI);
}
void mac_pcap::write_dl_ra_rnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, RA_RNTI);
}
void mac_pcap::write_dl_bch_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, NO_RNTI);
}
void mac_pcap::write_dl_pch_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, P_RNTI);
}
void mac_pcap::write_dl_si_rnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, SI_RNTI);
}
void mac_pcap::write_ul_rrc_pdu(const uint8_t* input, const int32_t input_len)
{
uint8_t pdu[1024];
bzero(pdu, sizeof(pdu));
// Size is limited by PDU buffer and MAC subheader (format 1 < 128 B)
if (input_len > 128 - 7) {
logger.error("PDU too large.");
return;
}
// MAC PDU Header (Short BSR) (1:54) (Padding:remainder) [3 subheaders]
// Sub-header (lcid=Short BSR)
// 0... .... = SCH reserved bit: 0x0
// .0.. .... = Format2: Data length is < 32768 bytes
// ..1. .... = Extension: 0x1
// ...1 1101 = LCID: Short BSR (0x1d)
// Sub-header (lcid=1, length=54)
// 0... .... = SCH reserved bit: 0x0
// .0.. .... = Format2: Data length is < 32768 bytes
// ..1. .... = Extension: 0x1
// ...0 0001 = LCID: 1 (0x01)
// 0... .... = Format: Data length is < 128 bytes
// .011 0110 = Length: 54 (Will be dynamically updated)
// Sub-header (lcid=Padding, length is remainder)
// 0... .... = SCH reserved bit: 0x0
// .0.. .... = Format2: Data length is < 32768 bytes
// ..0. .... = Extension: 0x0
// ...1 1111 = LCID: Padding (0x1f)
uint8_t mac_hdr[] = {0x3D, 0x21, 0x36, 0x1F, 0x0C};
// Update MAC length
mac_hdr[2] = input_len + 7; // rlc_hdr (2) + pdcp_hdr (1) + MAC (4)
// AM Header (P) sn=4
// 1... .... = Frame type: Data PDU (0x1)
// .0.. .... = Re-segmentation Flag: AMD PDU (0x0)
// ..1. .... = Polling Bit: Status report is requested (0x1)
// ...0 0... = Framing Info: First byte begins a RLC SDU and last byte ends a RLC SDU (0x0)
// .... .0.. = Extension: Data field follows from the octet following the fixed part of the header (0x0)
// .... ..00 0000 0100 = Sequence Number: 4
uint8_t rlc_hdr[] = {0xA0, 0x04};
// PDCP-LTE sn=3
// 000. .... = Reserved: 0
// ...0 0011 = Seq Num: 3
uint8_t pdcp_hdr[] = {0x03};
uint8_t* pdu_ptr = pdu;
memcpy(pdu_ptr, mac_hdr, sizeof(mac_hdr));
pdu_ptr += sizeof(mac_hdr);
memcpy(pdu_ptr, rlc_hdr, sizeof(rlc_hdr));
pdu_ptr += sizeof(rlc_hdr);
memcpy(pdu_ptr, pdcp_hdr, sizeof(pdcp_hdr));
pdu_ptr += sizeof(pdcp_hdr);
memcpy(pdu_ptr, input, input_len);
pdu_ptr += input_len;
// MAC
uint8_t pad = 0x00;
for (uint32_t i = 0; i < 4; i++) {
memcpy(pdu_ptr, &pad, 1);
pdu_ptr += 1;
}
// Pad
memcpy(pdu_ptr, &pad, 1);
pdu_ptr += 1;
write_ul_crnti(pdu, pdu_ptr - pdu, 14931, true, 0, 0);
}
} // namespace srslte

@ -0,0 +1,336 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 "srslte/common/mac_pcap_base.h"
#include "srslte/config.h"
#include "srslte/phy/common/phy_common.h"
#include <stdint.h>
namespace srslte {
mac_pcap_base::mac_pcap_base() : logger(srslog::fetch_basic_logger("MAC")), thread("PCAP_WRITER_MAC") {}
mac_pcap_base::~mac_pcap_base() {}
void mac_pcap_base::enable(bool enable_)
{
std::lock_guard<std::mutex> lock(mutex);
running = enable_;
}
void mac_pcap_base::set_ue_id(uint16_t ue_id_)
{
std::lock_guard<std::mutex> lock(mutex);
ue_id = ue_id_;
}
void mac_pcap_base::run_thread()
{
// blocking write until stopped
while (running) {
pcap_pdu_t pdu = queue.wait_pop();
{
std::lock_guard<std::mutex> lock(mutex);
write_pdu(pdu);
}
}
// write remainder of queue
std::lock_guard<std::mutex> lock(mutex);
pcap_pdu_t pdu = {};
while (queue.try_pop(&pdu)) {
write_pdu(pdu);
}
}
// Function called from PHY worker context, locking not needed as PDU queue is thread-safe
void mac_pcap_base::pack_and_queue(uint8_t* payload,
uint32_t payload_len,
uint16_t ue_id,
uint32_t reTX,
bool crc_ok,
uint8_t cc_idx,
uint32_t tti,
uint16_t crnti,
uint8_t direction,
uint8_t rnti_type)
{
if (running && payload != nullptr) {
pcap_pdu_t pdu = {};
pdu.rat = srslte::srslte_rat_t::lte;
pdu.context.radioType = FDD_RADIO;
pdu.context.direction = direction;
pdu.context.rntiType = rnti_type;
pdu.context.rnti = crnti;
pdu.context.ueid = ue_id;
pdu.context.isRetx = (uint8_t)reTX;
pdu.context.crcStatusOK = crc_ok;
pdu.context.cc_idx = cc_idx;
pdu.context.sysFrameNumber = (uint16_t)(tti / 10);
pdu.context.subFrameNumber = (uint16_t)(tti % 10);
// try to allocate PDU buffer
pdu.pdu = srslte::make_byte_buffer();
if (pdu.pdu != nullptr && pdu.pdu->get_tailroom() >= payload_len) {
// copy payload into PDU buffer
memcpy(pdu.pdu->msg, payload, payload_len);
pdu.pdu->N_bytes = payload_len;
queue.push(std::move(pdu));
} else {
logger.info("Dropping PDU in PCAP. No buffer available or not enough space (pdu_len=%d).", payload_len);
}
}
}
// Function called from PHY worker context, locking not needed as PDU queue is thread-safe
void mac_pcap_base::pack_and_queue_nr(uint8_t* payload,
uint32_t payload_len,
uint32_t tti,
uint16_t crnti,
uint16_t ue_id,
uint8_t harqid,
uint8_t direction,
uint8_t rnti_type)
{
if (running && payload != nullptr) {
pcap_pdu_t pdu = {};
pdu.rat = srslte_rat_t::nr;
pdu.context_nr.radioType = FDD_RADIO;
pdu.context_nr.direction = direction;
pdu.context_nr.rntiType = rnti_type;
pdu.context_nr.rnti = crnti;
pdu.context_nr.ueid = ue_id;
pdu.context_nr.harqid = harqid;
pdu.context_nr.system_frame_number = tti / 10;
pdu.context_nr.sub_frame_number = tti % 10;
// try to allocate PDU buffer
pdu.pdu = srslte::make_byte_buffer();
if (pdu.pdu != nullptr && pdu.pdu->get_tailroom() >= payload_len) {
// copy payload into PDU buffer
memcpy(pdu.pdu->msg, payload, payload_len);
pdu.pdu->N_bytes = payload_len;
queue.push(std::move(pdu));
} else {
logger.info("Dropping PDU in NR PCAP. No buffer available or not enough space (pdu_len=%d).", payload_len);
}
}
}
void mac_pcap_base::write_dl_crnti(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint16_t rnti,
bool crc_ok,
uint32_t tti,
uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, ue_id, 0, crc_ok, cc_idx, tti, rnti, DIRECTION_DOWNLINK, C_RNTI);
}
void mac_pcap_base::write_dl_ranti(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint16_t rnti,
bool crc_ok,
uint32_t tti,
uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, ue_id, 0, crc_ok, cc_idx, tti, rnti, DIRECTION_DOWNLINK, RA_RNTI);
}
void mac_pcap_base::write_ul_crnti(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint16_t rnti,
uint32_t reTX,
uint32_t tti,
uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, ue_id, reTX, true, cc_idx, tti, rnti, DIRECTION_UPLINK, C_RNTI);
}
void mac_pcap_base::write_ul_crnti(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint16_t rnti,
uint16_t ue_id,
uint32_t reTX,
uint32_t tti,
uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, ue_id, reTX, true, cc_idx, tti, rnti, DIRECTION_UPLINK, C_RNTI);
}
void mac_pcap_base::write_dl_crnti(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint16_t rnti,
uint16_t ue_id,
bool crc_ok,
uint32_t tti,
uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, ue_id, 0, crc_ok, cc_idx, tti, rnti, DIRECTION_DOWNLINK, C_RNTI);
}
void mac_pcap_base::write_sl_crnti(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint16_t rnti,
uint32_t reTX,
uint32_t tti,
uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, ue_id, reTX, true, cc_idx, tti, rnti, DIRECTION_UPLINK, SL_RNTI);
}
void mac_pcap_base::write_dl_bch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, ue_id, 0, crc_ok, cc_idx, tti, 0, DIRECTION_DOWNLINK, NO_RNTI);
}
void mac_pcap_base::write_dl_pch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, ue_id, 0, crc_ok, cc_idx, tti, SRSLTE_PRNTI, DIRECTION_DOWNLINK, P_RNTI);
}
void mac_pcap_base::write_dl_mch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, ue_id, 0, crc_ok, cc_idx, tti, SRSLTE_MRNTI, DIRECTION_DOWNLINK, M_RNTI);
}
void mac_pcap_base::write_dl_sirnti(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx)
{
pack_and_queue(pdu, pdu_len_bytes, ue_id, 0, crc_ok, cc_idx, tti, SRSLTE_SIRNTI, DIRECTION_DOWNLINK, SI_RNTI);
}
void mac_pcap_base::write_dl_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, ue_id, harqid, DIRECTION_DOWNLINK, C_RNTI);
}
void mac_pcap_base::write_dl_crnti_nr(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint16_t crnti,
uint16_t ue_id,
uint8_t harqid,
uint32_t tti)
{
pack_and_queue_nr(pdu, pdu_len_bytes, tti, crnti, ue_id, harqid, DIRECTION_DOWNLINK, C_RNTI);
}
void mac_pcap_base::write_ul_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, ue_id, harqid, DIRECTION_UPLINK, C_RNTI);
}
void mac_pcap_base::write_ul_crnti_nr(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint16_t rnti,
uint16_t ue_id,
uint8_t harqid,
uint32_t tti)
{
pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, ue_id, harqid, DIRECTION_UPLINK, C_RNTI);
}
void mac_pcap_base::write_dl_ra_rnti_nr(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint16_t rnti,
uint8_t harqid,
uint32_t tti)
{
pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, ue_id, harqid, DIRECTION_DOWNLINK, RA_RNTI);
}
void mac_pcap_base::write_dl_bch_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, ue_id, harqid, DIRECTION_DOWNLINK, NO_RNTI);
}
void mac_pcap_base::write_dl_pch_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, ue_id, harqid, DIRECTION_DOWNLINK, P_RNTI);
}
void mac_pcap_base::write_dl_si_rnti_nr(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint16_t rnti,
uint8_t harqid,
uint32_t tti)
{
pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, ue_id, harqid, DIRECTION_DOWNLINK, SI_RNTI);
}
void mac_pcap_base::write_ul_rrc_pdu(const uint8_t* input, const int32_t input_len)
{
uint8_t pdu[1024];
bzero(pdu, sizeof(pdu));
// Size is limited by PDU buffer and MAC subheader (format 1 < 128 B)
if (input_len > 128 - 7) {
logger.error("PDU too large.");
return;
}
// MAC PDU Header (Short BSR) (1:54) (Padding:remainder) [3 subheaders]
// Sub-header (lcid=Short BSR)
// 0... .... = SCH reserved bit: 0x0
// .0.. .... = Format2: Data length is < 32768 bytes
// ..1. .... = Extension: 0x1
// ...1 1101 = LCID: Short BSR (0x1d)
// Sub-header (lcid=1, length=54)
// 0... .... = SCH reserved bit: 0x0
// .0.. .... = Format2: Data length is < 32768 bytes
// ..1. .... = Extension: 0x1
// ...0 0001 = LCID: 1 (0x01)
// 0... .... = Format: Data length is < 128 bytes
// .011 0110 = Length: 54 (Will be dynamically updated)
// Sub-header (lcid=Padding, length is remainder)
// 0... .... = SCH reserved bit: 0x0
// .0.. .... = Format2: Data length is < 32768 bytes
// ..0. .... = Extension: 0x0
// ...1 1111 = LCID: Padding (0x1f)
uint8_t mac_hdr[] = {0x3D, 0x21, 0x36, 0x1F, 0x0C};
// Update MAC length
mac_hdr[2] = input_len + 7; // rlc_hdr (2) + pdcp_hdr (1) + MAC (4)
// AM Header (P) sn=4
// 1... .... = Frame type: Data PDU (0x1)
// .0.. .... = Re-segmentation Flag: AMD PDU (0x0)
// ..1. .... = Polling Bit: Status report is requested (0x1)
// ...0 0... = Framing Info: First byte begins a RLC SDU and last byte ends a RLC SDU (0x0)
// .... .0.. = Extension: Data field follows from the octet following the fixed part of the header (0x0)
// .... ..00 0000 0100 = Sequence Number: 4
uint8_t rlc_hdr[] = {0xA0, 0x04};
// PDCP-LTE sn=3
// 000. .... = Reserved: 0
// ...0 0011 = Seq Num: 3
uint8_t pdcp_hdr[] = {0x03};
uint8_t* pdu_ptr = pdu;
memcpy(pdu_ptr, mac_hdr, sizeof(mac_hdr));
pdu_ptr += sizeof(mac_hdr);
memcpy(pdu_ptr, rlc_hdr, sizeof(rlc_hdr));
pdu_ptr += sizeof(rlc_hdr);
memcpy(pdu_ptr, pdcp_hdr, sizeof(pdcp_hdr));
pdu_ptr += sizeof(pdcp_hdr);
memcpy(pdu_ptr, input, input_len);
pdu_ptr += input_len;
// MAC
uint8_t pad = 0x00;
for (uint32_t i = 0; i < 4; i++) {
memcpy(pdu_ptr, &pad, 1);
pdu_ptr += 1;
}
// Pad
memcpy(pdu_ptr, &pad, 1);
pdu_ptr += 1;
write_ul_crnti(pdu, pdu_ptr - pdu, 14931, true, 0, 0);
}
} // namespace srslte

@ -0,0 +1,170 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 "srslte/common/mac_pcap_net.h"
namespace srslte {
mac_pcap_net::mac_pcap_net() : mac_pcap_base() {}
mac_pcap_net::~mac_pcap_net()
{
close();
}
uint32_t mac_pcap_net::open(std::string client_ip_addr_,
std::string bind_addr_str,
uint16_t client_udp_port_,
uint16_t bind_udp_port_,
uint32_t ue_id_)
{
std::lock_guard<std::mutex> lock(mutex);
if (socket.is_init()) {
logger.error("PCAP socket writer for %s already running. Close first.", bind_addr_str.c_str());
return SRSLTE_ERROR;
}
if (not socket.open_socket(
net_utils::addr_family::ipv4, net_utils::socket_type::datagram, net_utils::protocol_type::UDP)) {
logger.error("Couldn't open socket %s to write PCAP", bind_addr_str.c_str());
return SRSLTE_ERROR;
}
if (not socket.bind_addr(bind_addr_str.c_str(), bind_udp_port_)) {
socket.reset();
logger.error("Couldn't bind socket %s to write PCAP", bind_addr_str.c_str());
return SRSLTE_ERROR;
}
logger.info("Sending MAC PCAP frames to %s:%d (from %s:%d)",
client_ip_addr_.c_str(),
client_udp_port_,
bind_addr_str.c_str(),
bind_udp_port_);
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = inet_addr(client_ip_addr_.c_str());
client_addr.sin_port = htons(client_udp_port_);
running = true;
ue_id = ue_id_;
// start writer thread
start();
return SRSLTE_SUCCESS;
}
uint32_t mac_pcap_net::close()
{
{
std::lock_guard<std::mutex> lock(mutex);
if (running == false || socket.is_init() == false) {
return SRSLTE_ERROR;
}
// tell writer thread to stop
running = false;
pcap_pdu_t pdu = {};
queue.push(std::move(pdu));
}
wait_thread_finish();
// close socket handle
if (socket.is_init()) {
std::lock_guard<std::mutex> lock(mutex);
socket.close();
}
return SRSLTE_SUCCESS;
}
void mac_pcap_net::write_pdu(pcap_pdu_t& pdu)
{
if (pdu.pdu != nullptr && socket.is_init()) {
switch (pdu.rat) {
case srslte_rat_t::lte:
write_mac_lte_pdu_to_net(pdu);
break;
case srslte_rat_t::nr:
write_mac_nr_pdu_to_net(pdu);
break;
default:
logger.error("Error writing PDU to PCAP socket. Unsupported RAT selected.");
}
}
}
void mac_pcap_net::write_mac_lte_pdu_to_net(pcap_pdu_t& pdu)
{
int bytes_sent;
uint32_t offset = 0;
uint8_t buffer[PCAP_CONTEXT_HEADER_MAX];
// MAC_LTE_START_STRING for UDP heuristics
memcpy(buffer + offset, MAC_LTE_START_STRING, strlen(MAC_LTE_START_STRING));
offset += strlen(MAC_LTE_START_STRING);
offset += LTE_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(&pdu.context, buffer + offset, PCAP_CONTEXT_HEADER_MAX);
if (pdu.pdu.get()->get_headroom() < offset) {
logger.error("PDU headroom is to small for adding context buffer");
return;
}
pdu.pdu.get()->msg -= offset;
memcpy(pdu.pdu.get()->msg, buffer, offset);
pdu.pdu.get()->N_bytes += offset;
bytes_sent = sendto(socket.get_socket(),
pdu.pdu.get()->msg,
pdu.pdu.get()->N_bytes,
0,
(const struct sockaddr*)&client_addr,
sizeof(client_addr));
if ((int)pdu.pdu.get()->N_bytes != bytes_sent || bytes_sent < 0) {
logger.error(
"Sending UDP packet mismatches %d != %d (err %s)", pdu.pdu.get()->N_bytes, bytes_sent, strerror(errno));
}
}
void mac_pcap_net::write_mac_nr_pdu_to_net(pcap_pdu_t& pdu)
{
int bytes_sent;
uint32_t offset = 0;
uint8_t buffer[PCAP_CONTEXT_HEADER_MAX];
// MAC_LTE_START_STRING for UDP heuristics
memcpy(buffer + offset, MAC_LTE_START_STRING, strlen(MAC_LTE_START_STRING));
offset += strlen(MAC_LTE_START_STRING);
offset += NR_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(&pdu.context_nr, buffer + offset, PCAP_CONTEXT_HEADER_MAX);
if (pdu.pdu.get()->get_headroom() < offset) {
logger.error("PDU headroom is to small for adding context buffer");
return;
}
pdu.pdu.get()->msg -= offset;
memcpy(pdu.pdu.get()->msg, buffer, offset);
pdu.pdu.get()->N_bytes += offset;
bytes_sent = sendto(socket.get_socket(),
pdu.pdu.get()->msg,
pdu.pdu.get()->N_bytes,
0,
(const struct sockaddr*)&client_addr,
sizeof(client_addr));
if ((int)pdu.pdu.get()->N_bytes != bytes_sent || bytes_sent < 0) {
logger.error(
"Sending UDP packet mismatches %d != %d (err %s)", pdu.pdu.get()->N_bytes, bytes_sent, strerror(errno));
}
}
} // namespace srslte

@ -30,15 +30,22 @@ void nas_pcap::enable()
{
enable_write = true;
}
void nas_pcap::open(const char* filename, uint32_t ue_id_)
uint32_t nas_pcap::open(std::string filename_, uint32_t ue_id_)
{
pcap_file = LTE_PCAP_Open(NAS_LTE_DLT, filename);
filename = filename_;
pcap_file = LTE_PCAP_Open(NAS_LTE_DLT, filename.c_str());
if (pcap_file == nullptr) {
return SRSLTE_ERROR;
}
ue_id = ue_id_;
enable_write = true;
return SRSLTE_SUCCESS;
}
void nas_pcap::close()
{
fprintf(stdout, "Saving NAS PCAP file (DLT=%d)\n", NAS_LTE_DLT);
fprintf(stdout, "Saving NAS PCAP file (DLT=%d) to %s \n", NAS_LTE_DLT, filename.c_str());
LTE_PCAP_Close(pcap_file);
}

@ -422,7 +422,11 @@ public:
bool operator()(int fd) override
{
srslte::unique_byte_buffer_t pdu(new byte_buffer_t());
srslte::unique_byte_buffer_t pdu = srslte::make_byte_buffer();
if (pdu == nullptr) {
logger.error("Unable to allocate byte buffer");
return true;
}
sockaddr_in from = {};
socklen_t fromlen = sizeof(from);
@ -459,6 +463,10 @@ public:
{
// inside rx_sockets thread. Read socket
srslte::unique_byte_buffer_t pdu = srslte::make_byte_buffer();
if (pdu == nullptr) {
logger.error("Unable to allocate byte buffer");
return true;
}
sockaddr_in from = {};
socklen_t fromlen = sizeof(from);
sctp_sndrcvinfo sri = {};

@ -21,6 +21,7 @@
#include "srslte/common/pcap.h"
#include <arpa/inet.h>
#include <linux/udp.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
@ -58,60 +59,123 @@ void LTE_PCAP_Close(FILE* fd)
}
}
/* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */
int LTE_PCAP_MAC_WritePDU(FILE* fd, MAC_Context_Info_t* context, const unsigned char* PDU, unsigned int length)
/* Packs MAC Contect to a buffer */
inline int LTE_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(MAC_Context_Info_t* context, uint8_t* buffer, unsigned int length)
{
pcaprec_hdr_t packet_header;
char context_header[256];
int offset = 0;
uint16_t tmp16;
/* Can't write if file wasn't successfully opened */
if (fd == NULL) {
if (buffer == NULL || length < PCAP_CONTEXT_HEADER_MAX) {
printf("Error: Can't write to empty file handle\n");
return 0;
return -1;
}
/*****************************************************************/
/* Context information (same as written by UDP heuristic clients */
context_header[offset++] = context->radioType;
context_header[offset++] = context->direction;
context_header[offset++] = context->rntiType;
buffer[offset++] = context->radioType;
buffer[offset++] = context->direction;
buffer[offset++] = context->rntiType;
/* RNTI */
context_header[offset++] = MAC_LTE_RNTI_TAG;
buffer[offset++] = MAC_LTE_RNTI_TAG;
tmp16 = htons(context->rnti);
memcpy(context_header + offset, &tmp16, 2);
memcpy(buffer + offset, &tmp16, 2);
offset += 2;
/* UEId */
context_header[offset++] = MAC_LTE_UEID_TAG;
buffer[offset++] = MAC_LTE_UEID_TAG;
tmp16 = htons(context->ueid);
memcpy(context_header + offset, &tmp16, 2);
memcpy(buffer + offset, &tmp16, 2);
offset += 2;
/* Subframe Number and System Frame Number */
/* SFN is stored in 12 MSB and SF in 4 LSB */
context_header[offset++] = MAC_LTE_FRAME_SUBFRAME_TAG;
buffer[offset++] = MAC_LTE_FRAME_SUBFRAME_TAG;
tmp16 = (context->sysFrameNumber << 4) | context->subFrameNumber;
tmp16 = htons(tmp16);
memcpy(context_header + offset, &tmp16, 2);
memcpy(buffer + offset, &tmp16, 2);
offset += 2;
/* CRC Status */
context_header[offset++] = MAC_LTE_CRC_STATUS_TAG;
context_header[offset++] = context->crcStatusOK;
/* CC index */
context_header[offset++] = MAC_LTE_CARRIER_ID_TAG;
context_header[offset++] = context->cc_idx;
buffer[offset++] = MAC_LTE_CRC_STATUS_TAG;
buffer[offset++] = context->crcStatusOK;
/* NB-IoT mode tag */
context_header[offset++] = MAC_LTE_NB_MODE_TAG;
context_header[offset++] = context->nbiotMode;
buffer[offset++] = MAC_LTE_NB_MODE_TAG;
buffer[offset++] = context->nbiotMode;
/* Data tag immediately preceding PDU */
context_header[offset++] = MAC_LTE_PAYLOAD_TAG;
buffer[offset++] = MAC_LTE_PAYLOAD_TAG;
return offset;
}
/* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */
inline int LTE_PCAP_MAC_WritePDU(FILE* fd, MAC_Context_Info_t* context, const unsigned char* PDU, unsigned int length)
{
pcaprec_hdr_t packet_header;
uint8_t context_header[PCAP_CONTEXT_HEADER_MAX];
int offset = 0;
/* Can't write if file wasn't successfully opened */
if (fd == NULL) {
printf("Error: Can't write to empty file handle\n");
return 0;
}
offset += LTE_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(context, &context_header[offset], PCAP_CONTEXT_HEADER_MAX);
/****************************************************************/
/* PCAP Header */
struct timeval t;
gettimeofday(&t, NULL);
packet_header.ts_sec = t.tv_sec;
packet_header.ts_usec = t.tv_usec;
packet_header.incl_len = offset + length;
packet_header.orig_len = offset + length;
/***************************************************************/
/* Now write everything to the file */
fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, fd);
fwrite(context_header, 1, offset, fd);
fwrite(PDU, 1, length, fd);
return 1;
}
/* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */
inline int
LTE_PCAP_MAC_UDP_WritePDU(FILE* fd, MAC_Context_Info_t* context, const unsigned char* PDU, unsigned int length)
{
pcaprec_hdr_t packet_header;
uint8_t context_header[PCAP_CONTEXT_HEADER_MAX] = {};
int offset = 0;
struct udphdr* udp_header;
// uint16_t tmp16;
/* Can't write if file wasn't successfully opened */
if (fd == NULL) {
printf("Error: Can't write to empty file handle\n");
return 0;
}
// Add dummy UDP header, start with src and dest port
udp_header = (struct udphdr*)context_header;
udp_header->dest = htons(0xdead);
offset += 2;
udp_header->source = htons(0xbeef);
offset += 2;
// length to be filled later
udp_header->len = 0x0000;
offset += 2;
// dummy CRC
udp_header->check = 0x0000;
offset += 2;
// Start magic string
memcpy(&context_header[offset], MAC_LTE_START_STRING, strlen(MAC_LTE_START_STRING));
offset += strlen(MAC_LTE_START_STRING);
offset += LTE_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(context, &context_header[offset], PCAP_CONTEXT_HEADER_MAX);
udp_header->len = htons(length + offset);
/****************************************************************/
/* PCAP Header */
@ -167,7 +231,7 @@ int LTE_PCAP_NAS_WritePDU(FILE* fd, NAS_Context_Info_t* context, const unsigned
int LTE_PCAP_RLC_WritePDU(FILE* fd, RLC_Context_Info_t* context, const unsigned char* PDU, unsigned int length)
{
pcaprec_hdr_t packet_header;
char context_header[256] = {};
char context_header[PCAP_CONTEXT_HEADER_MAX] = {};
int offset = 0;
uint16_t tmp16;
@ -280,72 +344,92 @@ int LTE_PCAP_S1AP_WritePDU(FILE* fd, S1AP_Context_Info_t* context, const unsigne
/**************************************************************************
* API functions for writing MAC-NR PCAP files *
**************************************************************************/
/* Write an individual NR MAC PDU (PCAP packet header + UDP header + nr-mac-context + mac-pdu) */
int NR_PCAP_MAC_WritePDU(FILE* fd, mac_nr_context_info_t* context, const unsigned char* PDU, unsigned int length)
inline int NR_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(mac_nr_context_info_t* context, uint8_t* buffer, unsigned int length)
{
char context_header[256] = {};
int offset = 0;
uint16_t tmp16;
/* Can't write if file wasn't successfully opened */
if (fd == NULL) {
printf("Error: Can't write to empty file handle\n");
return 0;
if (buffer == NULL || length < PCAP_CONTEXT_HEADER_MAX) {
printf("Error: Writing buffer null or length to small \n");
return -1;
}
// Add dummy UDP header, start with src and dest port
context_header[offset++] = 0xde;
context_header[offset++] = 0xad;
context_header[offset++] = 0xbe;
context_header[offset++] = 0xef;
// length
uint16_t tmp16 = htons(length + 31);
memcpy(context_header + offset, &tmp16, 2);
offset += 2;
// dummy CRC
context_header[offset++] = 0x00;
context_header[offset++] = 0x00;
// Start magic string
memcpy(&context_header[offset], MAC_NR_START_STRING, strlen(MAC_NR_START_STRING));
offset += strlen(MAC_NR_START_STRING);
/*****************************************************************/
/* Context information (same as written by UDP heuristic clients */
context_header[offset++] = context->radioType;
context_header[offset++] = context->direction;
context_header[offset++] = context->rntiType;
buffer[offset++] = context->radioType;
buffer[offset++] = context->direction;
buffer[offset++] = context->rntiType;
/* RNTI */
context_header[offset++] = MAC_LTE_RNTI_TAG;
buffer[offset++] = MAC_LTE_RNTI_TAG;
tmp16 = htons(context->rnti);
memcpy(context_header + offset, &tmp16, 2);
memcpy(buffer + offset, &tmp16, 2);
offset += 2;
/* UEId */
context_header[offset++] = MAC_LTE_UEID_TAG;
buffer[offset++] = MAC_LTE_UEID_TAG;
tmp16 = htons(context->ueid);
memcpy(context_header + offset, &tmp16, 2);
memcpy(buffer + offset, &tmp16, 2);
offset += 2;
/* HARQID */
context_header[offset++] = MAC_NR_HARQID;
context_header[offset++] = context->harqid;
buffer[offset++] = MAC_NR_HARQID;
buffer[offset++] = context->harqid;
/* PHR Type2 other cell */
context_header[offset++] = MAC_NR_PHR_TYPE2_OTHERCELL_TAG;
context_header[offset++] = context->phr_type2_othercell;
buffer[offset++] = MAC_NR_PHR_TYPE2_OTHERCELL_TAG;
buffer[offset++] = context->phr_type2_othercell;
/* Subframe Number and System Frame Number */
/* SFN is stored in 12 MSB and SF in 4 LSB */
context_header[offset++] = MAC_LTE_FRAME_SUBFRAME_TAG;
buffer[offset++] = MAC_LTE_FRAME_SUBFRAME_TAG;
tmp16 = (context->system_frame_number << 4) | context->sub_frame_number;
tmp16 = htons(tmp16);
memcpy(context_header + offset, &tmp16, 2);
memcpy(buffer + offset, &tmp16, 2);
offset += 2;
/* Data tag immediately preceding PDU */
context_header[offset++] = MAC_LTE_PAYLOAD_TAG;
buffer[offset++] = MAC_LTE_PAYLOAD_TAG;
return offset;
}
/* Write an individual NR MAC PDU (PCAP packet header + UDP header + nr-mac-context + mac-pdu) */
int NR_PCAP_MAC_UDP_WritePDU(FILE* fd, mac_nr_context_info_t* context, const unsigned char* PDU, unsigned int length)
{
uint8_t context_header[PCAP_CONTEXT_HEADER_MAX] = {};
struct udphdr* udp_header;
int offset = 0;
/* Can't write if file wasn't successfully opened */
if (fd == NULL) {
printf("Error: Can't write to empty file handle\n");
return -1;
}
// Add dummy UDP header, start with src and dest port
udp_header = (struct udphdr*)context_header;
udp_header->dest = htons(0xdead);
offset += 2;
udp_header->source = htons(0xbeef);
offset += 2;
// length to be filled later
udp_header->len = 0x0000;
offset += 2;
// dummy CRC
udp_header->check = 0x0000;
offset += 2;
// Start magic string
memcpy(&context_header[offset], MAC_NR_START_STRING, strlen(MAC_NR_START_STRING));
offset += strlen(MAC_NR_START_STRING);
offset += NR_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(context, &context_header[offset], PCAP_CONTEXT_HEADER_MAX);
udp_header->len = htons(offset + length);
if (offset != 31) {
printf("ERROR Does not match offset %d != 31\n", offset);
}
/****************************************************************/
/* PCAP Header */

@ -20,6 +20,7 @@
*/
#include "srslte/common/thread_pool.h"
#include "srslte/srslog/srslog.h"
#include <assert.h>
#include <chrono>
#include <stdio.h>
@ -253,11 +254,11 @@ uint32_t thread_pool::get_nof_workers()
* once a worker is available
*************************************************************************/
task_thread_pool::task_thread_pool(uint32_t nof_workers) : running(false)
task_thread_pool::task_thread_pool(uint32_t nof_workers, bool start_deferred, int32_t prio_, uint32_t mask_) :
logger(srslog::fetch_basic_logger("POOL")), workers(std::max(1u, nof_workers))
{
workers.reserve(nof_workers);
for (uint32_t i = 0; i < nof_workers; ++i) {
workers.emplace_back(this, i);
if (not start_deferred) {
start(prio_, mask_);
}
}
@ -266,12 +267,34 @@ task_thread_pool::~task_thread_pool()
stop();
}
void task_thread_pool::start(int32_t prio, uint32_t mask)
void task_thread_pool::set_nof_workers(uint32_t nof_workers)
{
std::lock_guard<std::mutex> lock(queue_mutex);
if (workers.size() > nof_workers) {
logger.error("Reducing the number of workers dynamically not supported");
return;
}
uint32_t old_size = workers.size();
workers.resize(nof_workers);
if (running) {
for (uint32_t i = old_size; i < nof_workers; ++i) {
workers[i].reset(new worker_t(this, i));
}
}
}
void task_thread_pool::start(int32_t prio_, uint32_t mask_)
{
std::lock_guard<std::mutex> lock(queue_mutex);
if (running) {
logger.error("Starting thread pool that has already started");
return;
}
prio = prio_;
mask = mask_;
running = true;
for (worker_t& w : workers) {
w.setup(prio, mask);
for (uint32_t i = 0; i < workers.size(); ++i) {
workers[i].reset(new worker_t(this, i));
}
}
@ -281,8 +304,8 @@ void task_thread_pool::stop()
if (running) {
running = false;
bool workers_running = false;
for (worker_t& w : workers) {
if (w.is_running()) {
for (std::unique_ptr<worker_t>& w : workers) {
if (w->is_running()) {
workers_running = true;
break;
}
@ -291,21 +314,12 @@ void task_thread_pool::stop()
if (workers_running) {
cv_empty.notify_all();
}
for (worker_t& w : workers) {
w.stop();
for (std::unique_ptr<worker_t>& w : workers) {
w->stop();
}
}
}
void task_thread_pool::push_task(const task_t& task)
{
{
std::lock_guard<std::mutex> lock(queue_mutex);
pending_tasks.push(task);
}
cv_empty.notify_one();
}
void task_thread_pool::push_task(task_t&& task)
{
{
@ -315,17 +329,20 @@ void task_thread_pool::push_task(task_t&& task)
cv_empty.notify_one();
}
uint32_t task_thread_pool::nof_pending_tasks()
uint32_t task_thread_pool::nof_pending_tasks() const
{
std::lock_guard<std::mutex> lock(queue_mutex);
return pending_tasks.size();
}
task_thread_pool::worker_t::worker_t(srslte::task_thread_pool* parent_, uint32_t my_id) :
parent(parent_),
thread(std::string("TASKWORKER") + std::to_string(my_id)),
id_(my_id)
parent(parent_), thread(std::string("TASKWORKER") + std::to_string(my_id)), id_(my_id), running(true)
{
if (parent->mask == 255) {
start(parent->prio);
} else {
start_cpu_mask(parent->prio, parent->mask);
}
}
void task_thread_pool::worker_t::stop()
@ -333,16 +350,6 @@ void task_thread_pool::worker_t::stop()
wait_thread_finish();
}
void task_thread_pool::worker_t::setup(int32_t prio, uint32_t mask)
{
running = true;
if (mask == 255) {
start(prio);
} else {
start_cpu_mask(prio, mask);
}
}
bool task_thread_pool::worker_t::wait_task(task_t* task)
{
std::unique_lock<std::mutex> lock(parent->queue_mutex);
@ -364,7 +371,7 @@ void task_thread_pool::worker_t::run_thread()
// main loop
task_t task;
while (wait_task(&task)) {
task(id());
task();
}
// on exit, notify pool class
@ -372,4 +379,11 @@ void task_thread_pool::worker_t::run_thread()
running = false;
}
// Global thread pool for long, low-priority tasks
task_thread_pool& get_background_workers()
{
static task_thread_pool background_workers;
return background_workers;
}
} // namespace srslte

@ -25,7 +25,11 @@
#include <strings.h>
#include "srslte/mac/pdu.h"
#include "srslte/srslte.h"
extern "C" {
#include "srslte/phy/utils/bit.h"
#include "srslte/phy/utils/vector.h"
}
// Table 6.1.3.1-1 Buffer size levels for BSR
static uint32_t btable[64] = {
@ -475,7 +479,7 @@ int sch_pdu::get_sdu_space()
} else {
ret = rem_len - (size_header_sdu(subheaders[last_sdu_idx].get_payload_size()) - 1) - 1;
}
ret = SRSLTE_MIN(ret >= 0 ? ret : 0, buffer_tx->get_tailroom());
ret = std::min(ret >= 0 ? ret : 0u, buffer_tx->get_tailroom());
return ret;
}

@ -298,8 +298,8 @@ static uint32_t dmrs_pucch_format2_cinit(const srslte_carrier_nr_t* car
const srslte_slot_cfg_t* slot,
uint32_t l)
{
uint32_t n = SRSLTE_SLOT_NR_MOD(slot->idx, carrier->numerology);
uint32_t n_id = (cfg->scrambling_id_present) ? cfg->scambling_id : carrier->id;
uint64_t n = slot->idx;
uint64_t n_id = (cfg->scrambling_id_present) ? cfg->scambling_id : carrier->id;
return SRSLTE_SEQUENCE_MOD((((SRSLTE_NSYMB_PER_SLOT_NR * n + l + 1UL) * (2UL * n_id + 1UL)) << 17UL) + 2UL * n_id);
}

@ -46,9 +46,9 @@
/**
* Parallel bit generation for x1/x2 sequences parameters. Exploits the fact that the sequence generation is 31 chips
* ahead and the maximum register shift is 3 (for x2).
* ahead and the maximum register shift is 3 (for x2). The maximum number of parallel bits is 28, 16 is optimal for SSE.
*/
#define SEQUENCE_PAR_BITS (28U)
#define SEQUENCE_PAR_BITS (24U)
#define SEQUENCE_MASK ((1U << SEQUENCE_PAR_BITS) - 1U)
/**
@ -151,7 +151,6 @@ static uint32_t sequence_x2_init[SEQUENCE_SEED_LEN] = {};
*/
__attribute__((constructor)) __attribute__((unused)) static void srslte_lte_pr_pregen()
{
// Compute transition step
sequence_x1_init = 1;
for (uint32_t n = 0; n < SEQUENCE_NC; n++) {
@ -308,7 +307,6 @@ int srslte_sequence_set_LTE_pr(srslte_sequence_t* q, uint32_t len, uint32_t seed
static inline void
sequence_generate_signed(const uint8_t* c_unpacked, int8_t* c_char, int16_t* c_short, float* c_float, uint32_t len)
{
int i = 0;
#ifdef LV_HAVE_SSE
@ -485,7 +483,6 @@ void srslte_sequence_apply_f(const float* in, float* out, uint32_t length, uint3
}
for (; i < length; i++) {
((uint32_t*)out)[i] = ((uint32_t*)in)[i] ^ (((x1 ^ x2) & 1U) << 31U);
// Step sequences
@ -496,6 +493,7 @@ void srslte_sequence_apply_f(const float* in, float* out, uint32_t length, uint3
void srslte_sequence_apply_s(const int16_t* in, int16_t* out, uint32_t length, uint32_t seed)
{
const int16_t s[2] = {+1, -1};
uint32_t x1 = sequence_x1_init; // X1 initial state is fix
uint32_t x2 = sequence_get_x2_init(seed); // loads x2 initial state
@ -529,9 +527,9 @@ void srslte_sequence_apply_s(const int16_t* in, int16_t* out, uint32_t length, u
_mm_storeu_si128((__m128i*)(out + i + j), v);
}
#endif
#endif // LV_HAVE_SSE
for (; j < SEQUENCE_PAR_BITS; j++) {
out[i + j] = in[i + j] * (((c >> j) & 1U) ? -1 : +1);
out[i + j] = in[i + j] * s[(c >> j) & 1U];
}
// Step sequences
@ -541,7 +539,7 @@ void srslte_sequence_apply_s(const int16_t* in, int16_t* out, uint32_t length, u
}
for (; i < length; i++) {
out[i] = in[i] * (((x1 ^ x2) & 1U) ? -1 : +1);
out[i] = in[i] * s[(x1 ^ x2) & 1U];
// Step sequences
x1 = sequence_gen_LTE_pr_memless_step_x1(x1);
@ -668,14 +666,11 @@ void srslte_sequence_apply_bit(const uint8_t* in, uint8_t* out, uint32_t length,
}
}
void srslte_sequence_apply_bit_packed(const uint8_t* in, uint8_t* out, uint32_t length, uint32_t seed)
void srslte_sequence_apply_packed(const uint8_t* in, uint8_t* out, uint32_t length, uint32_t seed)
{
uint32_t x1 = sequence_x1_init; // X1 initial state is fix
uint32_t x2 = sequence_get_x2_init(seed); // loads x2 initial state
uint64_t buffer = 0;
uint32_t count = 0;
const uint8_t reverse_lut[256] = {
0b00000000, 0b10000000, 0b01000000, 0b11000000, 0b00100000, 0b10100000, 0b01100000, 0b11100000, 0b00010000,
0b10010000, 0b01010000, 0b11010000, 0b00110000, 0b10110000, 0b01110000, 0b11110000, 0b00001000, 0b10001000,
@ -708,7 +703,12 @@ void srslte_sequence_apply_bit_packed(const uint8_t* in, uint8_t* out, uint32_t
0b00111111, 0b10111111, 0b01111111, 0b11111111,
};
for (uint32_t i = 0; i < length / 8; i++) {
uint32_t i = 0;
#if SEQUENCE_PAR_BITS % 8 != 0
uint64_t buffer = 0;
uint32_t count = 0;
for (; i < length / 8; i++) {
// Generate sequence bits
while (count < 8) {
uint32_t c = (uint32_t)(x1 ^ x2);
@ -727,4 +727,52 @@ void srslte_sequence_apply_bit_packed(const uint8_t* in, uint8_t* out, uint32_t
buffer = buffer >> 8UL;
count -= 8;
}
// Process spare bits
uint32_t rem8 = length % 8;
if (rem8 != 0) {
// Generate sequence bits
while (count < rem8) {
uint32_t c = (uint32_t)(x1 ^ x2);
buffer = buffer | ((SEQUENCE_MASK & c) << count);
// Step sequences
x1 = sequence_gen_LTE_pr_memless_step_par_x1(x1);
x2 = sequence_gen_LTE_pr_memless_step_par_x2(x2);
// Increase count
count += SEQUENCE_PAR_BITS;
}
out[i] = in[i] ^ reverse_lut[buffer & ((1U << rem8) - 1U) & 255U];
}
#else // SEQUENCE_PAR_BITS % 8 == 0
while (i < (length / 8 - (SEQUENCE_PAR_BITS - 1) / 8)) {
uint32_t c = (uint32_t)(x1 ^ x2);
for (uint32_t j = 0; j < SEQUENCE_PAR_BITS / 8; j++) {
out[i] = in[i] ^ reverse_lut[c & 255U];
c = c >> 8U;
i++;
}
// Step sequences
x1 = sequence_gen_LTE_pr_memless_step_par_x1(x1);
x2 = sequence_gen_LTE_pr_memless_step_par_x2(x2);
}
// Process spare bytes
uint32_t c = (uint32_t)(x1 ^ x2);
while (i < length / 8) {
out[i] = in[i] ^ reverse_lut[c & 255U];
c = c >> 8U;
i++;
}
// Process spare bits
uint32_t rem8 = length % 8;
if (rem8 != 0) {
out[i] = in[i] ^ reverse_lut[c & ((1U << rem8) - 1U) & 255U];
}
#endif // SEQUENCE_PAR_BITS % 8 == 0
}

@ -40,7 +40,7 @@ static uint8_t c_unpacked[MAX_SEQ_LEN];
static float ones_float[Nc + MAX_SEQ_LEN + 31];
static int16_t ones_short[Nc + MAX_SEQ_LEN + 31];
static int8_t ones_char[Nc + MAX_SEQ_LEN + 31];
static uint8_t ones_packed[MAX_SEQ_LEN / 8];
static uint8_t ones_packed[(MAX_SEQ_LEN * 7) / 8];
static uint8_t ones_unpacked[MAX_SEQ_LEN];
static int test_sequence(srslte_sequence_t* sequence, uint32_t seed, uint32_t length, uint32_t repetitions)
@ -152,7 +152,7 @@ static int test_sequence(srslte_sequence_t* sequence, uint32_t seed, uint32_t le
// Test in-place packed XOR
gettimeofday(&t[1], NULL);
for (uint32_t r = 0; r < repetitions; r++) {
srslte_sequence_apply_bit_packed(ones_packed, c_packed, length, seed);
srslte_sequence_apply_packed(ones_packed, c_packed, length, seed);
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
@ -163,12 +163,12 @@ static int test_sequence(srslte_sequence_t* sequence, uint32_t seed, uint32_t le
ret = SRSLTE_ERROR;
}
if (memcmp(c_packed_gold, sequence->c_bytes, length / 8) != 0) {
if (memcmp(c_packed_gold, sequence->c_bytes, (length + 7) / 8) != 0) {
ERROR("Unmatched c_packed");
ret = SRSLTE_ERROR;
}
if (memcmp(c_packed_gold, c_packed, length / 8) != 0) {
if (memcmp(c_packed_gold, c_packed, (length + 7) / 8) != 0) {
ERROR("Unmatched c_packed");
ret = SRSLTE_ERROR;
}
@ -207,7 +207,7 @@ int main(int argc, char** argv)
ones_short[i] = 1;
ones_char[i] = 1;
ones_unpacked[i] = 0;
if (i < MAX_SEQ_LEN / 8) {
if (i < (MAX_SEQ_LEN * 7) / 8) {
ones_packed[i] = 0;
}
}

@ -232,16 +232,6 @@ int srslte_enb_dl_set_cell(srslte_enb_dl_t* q, srslte_cell_t cell)
return ret;
}
int srslte_enb_dl_add_rnti(srslte_enb_dl_t* q, uint16_t rnti)
{
return srslte_pdsch_set_rnti(&q->pdsch, rnti);
}
void srslte_enb_dl_rem_rnti(srslte_enb_dl_t* q, uint16_t rnti)
{
srslte_pdsch_free_rnti(&q->pdsch, rnti);
}
#ifdef resolve
void srslte_enb_dl_apply_power_allocation(srslte_enb_dl_t* q)
{

@ -148,25 +148,6 @@ int srslte_enb_ul_set_cell(srslte_enb_ul_t* q,
return ret;
}
int srslte_enb_ul_add_rnti(srslte_enb_ul_t* q, uint16_t rnti)
{
if (srslte_pucch_set_rnti(&q->pucch, rnti)) {
ERROR("Error setting PUCCH rnti");
return -1;
}
if (srslte_pusch_set_rnti(&q->pusch, rnti)) {
ERROR("Error setting PUSCH rnti");
return -1;
}
return 0;
}
void srslte_enb_ul_rem_rnti(srslte_enb_ul_t* q, uint16_t rnti)
{
srslte_pucch_free_rnti(&q->pucch, rnti);
srslte_pusch_free_rnti(&q->pusch, rnti);
}
void srslte_enb_ul_fft(srslte_enb_ul_t* q)
{
srslte_ofdm_rx_sf(&q->fft);

@ -63,8 +63,8 @@ static const int8_t infinity7 = (1U << 6U) - 1;
* \brief Represents a node of the base factor graph.
*/
typedef union bg_node_avx512_t {
int8_t c[SRSLTE_AVX512_B_SIZE]; /*!< Each base node may contain up to \ref SRSLTE_AVX512_B_SIZE lifted nodes. */
__m512i v; /*!< All the lifted nodes of the current base node as a 512-bit line. */
int8_t* c; /*!< Each base node may contain up to \ref SRSLTE_AVX512_B_SIZE lifted nodes. */
__m512i* v; /*!< All the lifted nodes of the current base node as a 512-bit line. */
} bg_node_avx512_t;
/*!
@ -73,7 +73,7 @@ typedef union bg_node_avx512_t {
struct ldpc_regs_c_avx512 {
__m512i scaling_fctr; /*!< \brief Scaling factor for the normalized min-sum decoding algorithm. */
bg_node_avx512_t* soft_bits; /*!< \brief A-posteriori log-likelihood ratios. */
bg_node_avx512_t soft_bits; /*!< \brief A-posteriori log-likelihood ratios. */
__m512i* check_to_var; /*!< \brief Check-to-variable messages. */
__m512i* var_to_check; /*!< \brief Variable-to-check messages. */
__m512i* var_to_check_to_free; /*!< \brief the Variable-to-check messages with one extra _mm512 allocated space. */
@ -132,43 +132,34 @@ void* create_ldpc_dec_c_avx512(uint8_t bgN, uint8_t bgM, uint16_t ls, float scal
uint8_t bgK = bgN - bgM;
uint16_t hrr = bgK + 4;
if ((vp = srslte_vec_malloc(sizeof(struct ldpc_regs_c_avx512))) == NULL) {
if ((vp = SRSLTE_MEM_ALLOC(struct ldpc_regs_c_avx512, 1)) == NULL) {
return NULL;
}
SRSLTE_MEM_ZERO(vp, struct ldpc_regs_c_avx512, 1);
if ((vp->soft_bits = srslte_vec_malloc(bgN * sizeof(bg_node_avx512_t))) == NULL) {
free(vp);
if ((vp->soft_bits.v = SRSLTE_MEM_ALLOC(__m512i, bgN)) == NULL) {
delete_ldpc_dec_c_avx512(vp);
return NULL;
}
if ((vp->check_to_var = srslte_vec_malloc((hrr + 1) * bgM * sizeof(__m512i))) == NULL) {
free(vp->soft_bits);
free(vp);
if ((vp->check_to_var = SRSLTE_MEM_ALLOC(__m512i, (hrr + 1) * bgM)) == NULL) {
delete_ldpc_dec_c_avx512(vp);
return NULL;
}
if ((vp->var_to_check_to_free = srslte_vec_malloc(((hrr + 1) + 2) * sizeof(__m512i))) == NULL) {
free(vp->check_to_var);
free(vp->soft_bits);
free(vp);
if ((vp->var_to_check_to_free = SRSLTE_MEM_ALLOC(__m512i, (hrr + 1) + 2)) == NULL) {
delete_ldpc_dec_c_avx512(vp);
return NULL;
}
vp->var_to_check = &vp->var_to_check_to_free[1];
if ((vp->rotated_v2c = srslte_vec_malloc((hrr + 1) * sizeof(__m512i))) == NULL) {
free(vp->var_to_check_to_free);
free(vp->check_to_var);
free(vp->soft_bits);
free(vp);
if ((vp->rotated_v2c = SRSLTE_MEM_ALLOC(__m512i, hrr + 1)) == NULL) {
delete_ldpc_dec_c_avx512(vp);
return NULL;
}
if ((vp->this_c2v_epi8_to_free = srslte_vec_malloc((1 + 2) * sizeof(__m512i))) == NULL) {
free(vp->rotated_v2c);
free(vp->var_to_check_to_free);
free(vp->check_to_var);
free(vp->soft_bits);
free(vp);
if ((vp->this_c2v_epi8_to_free = SRSLTE_MEM_ALLOC(__m512i, 1 + 2)) == NULL) {
delete_ldpc_dec_c_avx512(vp);
return NULL;
}
vp->this_c2v_epi8 =
@ -190,14 +181,25 @@ void delete_ldpc_dec_c_avx512(void* p)
{
struct ldpc_regs_c_avx512* vp = p;
if (vp != NULL) {
if (vp == NULL) {
return;
}
if (vp->this_c2v_epi8_to_free) {
free(vp->this_c2v_epi8_to_free);
}
if (vp->rotated_v2c) {
free(vp->rotated_v2c);
}
if (vp->var_to_check_to_free) {
free(vp->var_to_check_to_free);
}
if (vp->check_to_var) {
free(vp->check_to_var);
free(vp->soft_bits);
free(vp);
}
if (vp->soft_bits.v) {
free(vp->soft_bits.v);
}
free(vp);
}
int init_ldpc_dec_c_avx512(void* p, const int8_t* llrs, uint16_t ls)
@ -213,19 +215,19 @@ int init_ldpc_dec_c_avx512(void* p, const int8_t* llrs, uint16_t ls)
// First 2 punctured bits
int ini = SRSLTE_AVX512_B_SIZE + SRSLTE_AVX512_B_SIZE;
bzero(vp->soft_bits->c, ini);
srslte_vec_i8_zero(vp->soft_bits.c, ini);
for (i = 0; i < vp->finalN; i = i + ls) {
for (k = 0; k < ls; k++) {
vp->soft_bits->c[ini + k] = llrs[i + k];
vp->soft_bits.c[ini + k] = llrs[i + k];
}
// this might be removed
bzero(&vp->soft_bits->c[ini + ls], (SRSLTE_AVX512_B_SIZE - ls) * sizeof(int8_t));
srslte_vec_i8_zero(&vp->soft_bits.c[ini + ls], SRSLTE_AVX512_B_SIZE - ls);
ini = ini + SRSLTE_AVX512_B_SIZE;
}
bzero(vp->check_to_var, (vp->hrr + 1) * vp->bgM * sizeof(__m512i));
bzero(vp->var_to_check, (vp->hrr + 1) * sizeof(__m512i));
SRSLTE_MEM_ZERO(vp->check_to_var, __m512i, (vp->hrr + 1) * vp->bgM);
SRSLTE_MEM_ZERO(vp->var_to_check, __m512i, vp->hrr + 1);
return 0;
}
@ -240,7 +242,7 @@ int extract_ldpc_message_c_avx512(void* p, uint8_t* message, uint16_t liftK)
int ini = 0;
for (int i = 0; i < liftK; i = i + vp->ls) {
for (int k = 0; k < vp->ls; k++) {
message[i + k] = (vp->soft_bits->c[ini + k] < 0);
message[i + k] = (vp->soft_bits.c[ini + k] < 0);
}
ini = ini + SRSLTE_AVX512_B_SIZE;
}
@ -259,15 +261,12 @@ int update_ldpc_var_to_check_c_avx512(void* p, int i_layer)
__m512i* this_check_to_var = vp->check_to_var + i_layer * (vp->hrr + 1);
// Update the high-rate region.
inner_var_to_check_c_avx512(&(vp->soft_bits[0].v), this_check_to_var, vp->var_to_check, infinity7, vp->hrr);
inner_var_to_check_c_avx512(vp->soft_bits.v, this_check_to_var, vp->var_to_check, infinity7, vp->hrr);
if (i_layer >= 4) {
// Update the extension region.
inner_var_to_check_c_avx512(&(vp->soft_bits[0].v) + vp->hrr + i_layer - 4,
this_check_to_var + vp->hrr,
vp->var_to_check + vp->hrr,
infinity7,
1);
inner_var_to_check_c_avx512(
vp->soft_bits.v + vp->hrr + i_layer - 4, this_check_to_var + vp->hrr, vp->var_to_check + vp->hrr, infinity7, 1);
}
return 0;
@ -391,7 +390,7 @@ int update_ldpc_soft_bits_c_avx512(void* p, int i_layer, const int8_t (*these_va
mask_epi8 = _mm512_cmpgt_epi8_mask(_mm512_neg_infty7_epi8, tmp_epi8);
vp->soft_bits[current_var_index].v = _mm512_mask_blend_epi8(mask_epi8, tmp_epi8, _mm512_neg_infty8_epi8);
vp->soft_bits.v[current_var_index] = _mm512_mask_blend_epi8(mask_epi8, tmp_epi8, _mm512_neg_infty8_epi8);
current_var_index = (*these_var_indices)[i + 1];
}

@ -48,15 +48,15 @@
* \brief Represents a node of the base factor graph.
*/
typedef union bg_node_t {
uint8_t c[SRSLTE_AVX2_B_SIZE]; /*!< Each base node may contain up to \ref SRSLTE_AVX2_B_SIZE lifted nodes. */
__m256i v; /*!< All the lifted nodes of the current base node as a 256-bit line. */
uint8_t* c; /*!< Each base node may contain up to \ref SRSLTE_AVX2_B_SIZE lifted nodes. */
__m256i* v; /*!< All the lifted nodes of the current base node as a 256-bit line. */
} bg_node_t;
/*!
* \brief Inner registers for the optimized LDPC encoder.
*/
struct ldpc_enc_avx2 {
bg_node_t* codeword; /*!< \brief Contains the entire codeword, before puncturing. */
bg_node_t codeword; /*!< \brief Contains the entire codeword, before puncturing. */
__m256i* aux; /*!< \brief Auxiliary register. */
};
@ -104,18 +104,17 @@ void* create_ldpc_enc_avx2(srslte_ldpc_encoder_t* q)
{
struct ldpc_enc_avx2* vp = NULL;
if ((vp = malloc(sizeof(struct ldpc_enc_avx2))) == NULL) {
if ((vp = SRSLTE_MEM_ALLOC(struct ldpc_enc_avx2, 1)) == NULL) {
return NULL;
}
if ((vp->codeword = srslte_vec_malloc(q->bgN * sizeof(bg_node_t))) == NULL) {
free(vp);
if ((vp->codeword.v = SRSLTE_MEM_ALLOC(__m256i, q->bgN)) == NULL) {
delete_ldpc_enc_avx2(vp);
return NULL;
}
if ((vp->aux = srslte_vec_malloc(q->bgM * sizeof(__m256i))) == NULL) {
free(vp->codeword);
free(vp);
if ((vp->aux = SRSLTE_MEM_ALLOC(__m256i, q->bgM)) == NULL) {
delete_ldpc_enc_avx2(vp);
return NULL;
}
@ -126,11 +125,16 @@ void delete_ldpc_enc_avx2(void* p)
{
struct ldpc_enc_avx2* vp = p;
if (vp != NULL) {
if (vp == NULL) {
return;
}
if (vp->aux) {
free(vp->aux);
free(vp->codeword);
free(vp);
}
if (vp->codeword.v) {
free(vp->codeword.v);
}
free(vp);
}
int load_avx2(void* p, const uint8_t* input, const uint8_t msg_len, const uint8_t cdwd_len, const uint16_t ls)
@ -145,14 +149,14 @@ int load_avx2(void* p, const uint8_t* input, const uint8_t msg_len, const uint8_
int node_size = SRSLTE_AVX2_B_SIZE;
for (int i = 0; i < msg_len * ls; i = i + ls) {
for (int k = 0; k < ls; k++) {
vp->codeword->c[ini + k] = input[i + k];
vp->codeword.c[ini + k] = input[i + k];
}
// this zero padding can be removed
bzero(&(vp->codeword->c[ini + ls]), (node_size - ls) * sizeof(uint8_t));
srslte_vec_u8_zero(&vp->codeword.c[ini + ls], node_size - ls);
ini = ini + node_size;
}
bzero(vp->codeword + msg_len, (cdwd_len - msg_len) * sizeof(__m256i));
SRSLTE_MEM_ZERO(vp->codeword.v + msg_len, __m256i, cdwd_len - msg_len);
return 0;
}
@ -168,7 +172,7 @@ int return_codeword_avx2(void* p, uint8_t* output, const uint8_t cdwd_len, const
int ini = SRSLTE_AVX2_B_SIZE + SRSLTE_AVX2_B_SIZE;
for (int i = 0; i < (cdwd_len - 2) * ls; i = i + ls) {
for (int k = 0; k < ls; k++) {
output[i + k] = vp->codeword->c[ini + k];
output[i + k] = vp->codeword.c[ini + k];
}
ini = ini + SRSLTE_AVX2_B_SIZE;
}
@ -193,14 +197,14 @@ void encode_ext_region_avx2(srslte_ldpc_encoder_t* q, uint8_t n_layers)
skip = q->bgK + m;
// the systematic part has already been computed
vp->codeword[skip].v = vp->aux[m];
vp->codeword.v[skip] = vp->aux[m];
// sum the contribution due to the high-rate region, with the proper circular shifts
for (k = 0; k < 4; k++) {
this_shift = q->pcm + q->bgK + k + m * q->bgN;
if (*this_shift != NO_CNCT) {
tmp_epi8 = rotate_node_right(vp->codeword[q->bgK + k].v, *this_shift, q->ls);
vp->codeword[skip].v = _mm256_xor_si256(vp->codeword[skip].v, tmp_epi8);
tmp_epi8 = rotate_node_right(vp->codeword.v[q->bgK + k], *this_shift, q->ls);
vp->codeword.v[skip] = _mm256_xor_si256(vp->codeword.v[skip], tmp_epi8);
}
}
}
@ -237,7 +241,7 @@ void preprocess_systematic_bits_avx2(srslte_ldpc_encoder_t* q)
// xor array aux[m] with a circularly shifted version of the current input chunk, unless
// the current check node and variable node are not connected.
if (*this_shift != NO_CNCT) {
tmp_epi8 = rotate_node_right(vp->codeword[k].v, *this_shift, ls);
tmp_epi8 = rotate_node_right(vp->codeword.v[k], *this_shift, ls);
tmp_epi8 = _mm256_and_si256(tmp_epi8, one_epi8);
vp->aux[m] = _mm256_xor_si256(vp->aux[m], tmp_epi8);
}
@ -258,17 +262,17 @@ void encode_high_rate_case1_avx2(void* o)
int skip3 = q->bgK + 3;
// first chunk of parity bits
vp->codeword[skip0].v = _mm256_xor_si256(vp->aux[0], vp->aux[1]);
vp->codeword[skip0].v = _mm256_xor_si256(vp->codeword[skip0].v, vp->aux[2]);
vp->codeword[skip0].v = _mm256_xor_si256(vp->codeword[skip0].v, vp->aux[3]);
vp->codeword.v[skip0] = _mm256_xor_si256(vp->aux[0], vp->aux[1]);
vp->codeword.v[skip0] = _mm256_xor_si256(vp->codeword.v[skip0], vp->aux[2]);
vp->codeword.v[skip0] = _mm256_xor_si256(vp->codeword.v[skip0], vp->aux[3]);
__m256i tmp_epi8 = rotate_node_right(vp->codeword[skip0].v, 1, ls);
__m256i tmp_epi8 = rotate_node_right(vp->codeword.v[skip0], 1, ls);
// second chunk of parity bits
vp->codeword[skip1].v = _mm256_xor_si256(vp->aux[0], tmp_epi8);
vp->codeword.v[skip1] = _mm256_xor_si256(vp->aux[0], tmp_epi8);
// fourth chunk of parity bits
vp->codeword[skip3].v = _mm256_xor_si256(vp->aux[3], tmp_epi8);
vp->codeword.v[skip3] = _mm256_xor_si256(vp->aux[3], tmp_epi8);
// third chunk of parity bits
vp->codeword[skip2].v = _mm256_xor_si256(vp->aux[2], vp->codeword[skip3].v);
vp->codeword.v[skip2] = _mm256_xor_si256(vp->aux[2], vp->codeword.v[skip3]);
}
void encode_high_rate_case2_avx2(void* o)
@ -287,14 +291,14 @@ void encode_high_rate_case2_avx2(void* o)
__m256i tmp_epi8 = _mm256_xor_si256(vp->aux[0], vp->aux[1]);
tmp_epi8 = _mm256_xor_si256(tmp_epi8, vp->aux[2]);
tmp_epi8 = _mm256_xor_si256(tmp_epi8, vp->aux[3]);
vp->codeword[skip0].v = rotate_node_left(tmp_epi8, 105 % ls, ls);
vp->codeword.v[skip0] = rotate_node_left(tmp_epi8, 105 % ls, ls);
// second chunk of parity bits
vp->codeword[skip1].v = _mm256_xor_si256(vp->aux[0], vp->codeword[skip0].v);
vp->codeword.v[skip1] = _mm256_xor_si256(vp->aux[0], vp->codeword.v[skip0]);
// fourth chunk of parity bits
vp->codeword[skip3].v = _mm256_xor_si256(vp->aux[3], vp->codeword[skip0].v);
vp->codeword.v[skip3] = _mm256_xor_si256(vp->aux[3], vp->codeword.v[skip0]);
// third chunk of parity bits
vp->codeword[skip2].v = _mm256_xor_si256(vp->aux[2], vp->codeword[skip3].v);
vp->codeword.v[skip2] = _mm256_xor_si256(vp->aux[2], vp->codeword.v[skip3]);
}
void encode_high_rate_case3_avx2(void* o)
@ -313,14 +317,14 @@ void encode_high_rate_case3_avx2(void* o)
__m256i tmp_epi8 = _mm256_xor_si256(vp->aux[0], vp->aux[1]);
tmp_epi8 = _mm256_xor_si256(tmp_epi8, vp->aux[2]);
tmp_epi8 = _mm256_xor_si256(tmp_epi8, vp->aux[3]);
vp->codeword[skip0].v = rotate_node_left(tmp_epi8, 1, ls);
vp->codeword.v[skip0] = rotate_node_left(tmp_epi8, 1, ls);
// second chunk of parity bits
vp->codeword[skip1].v = _mm256_xor_si256(vp->aux[0], vp->codeword[skip0].v);
vp->codeword.v[skip1] = _mm256_xor_si256(vp->aux[0], vp->codeword.v[skip0]);
// third chunk of parity bits
vp->codeword[skip2].v = _mm256_xor_si256(vp->aux[1], vp->codeword[skip1].v);
vp->codeword.v[skip2] = _mm256_xor_si256(vp->aux[1], vp->codeword.v[skip1]);
// fourth chunk of parity bits
vp->codeword[skip3].v = _mm256_xor_si256(vp->aux[3], vp->codeword[skip0].v);
vp->codeword.v[skip3] = _mm256_xor_si256(vp->aux[3], vp->codeword.v[skip0]);
}
void encode_high_rate_case4_avx2(void* o)
@ -336,17 +340,17 @@ void encode_high_rate_case4_avx2(void* o)
int skip3 = q->bgK + 3;
// first chunk of parity bits
vp->codeword[skip0].v = _mm256_xor_si256(vp->aux[0], vp->aux[1]);
vp->codeword[skip0].v = _mm256_xor_si256(vp->codeword[skip0].v, vp->aux[2]);
vp->codeword[skip0].v = _mm256_xor_si256(vp->codeword[skip0].v, vp->aux[3]);
vp->codeword.v[skip0] = _mm256_xor_si256(vp->aux[0], vp->aux[1]);
vp->codeword.v[skip0] = _mm256_xor_si256(vp->codeword.v[skip0], vp->aux[2]);
vp->codeword.v[skip0] = _mm256_xor_si256(vp->codeword.v[skip0], vp->aux[3]);
__m256i tmp_epi8 = rotate_node_right(vp->codeword[skip0].v, 1, ls);
__m256i tmp_epi8 = rotate_node_right(vp->codeword.v[skip0], 1, ls);
// second chunk of parity bits
vp->codeword[skip1].v = _mm256_xor_si256(vp->aux[0], tmp_epi8);
vp->codeword.v[skip1] = _mm256_xor_si256(vp->aux[0], tmp_epi8);
// third chunk of parity bits
vp->codeword[skip2].v = _mm256_xor_si256(vp->aux[1], vp->codeword[skip1].v);
vp->codeword.v[skip2] = _mm256_xor_si256(vp->aux[1], vp->codeword.v[skip1]);
// fourth chunk of parity bits
vp->codeword[skip3].v = _mm256_xor_si256(vp->aux[3], tmp_epi8);
vp->codeword.v[skip3] = _mm256_xor_si256(vp->aux[3], tmp_epi8);
}
static __m256i _mm256_rotatelli_si256(__m256i a, int imm)

@ -0,0 +1,221 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 "srslte/phy/phch/csi.h"
#include "srslte/phy/utils/bit.h"
#include "srslte/phy/utils/debug.h"
#include <math.h>
#define CSI_WIDEBAND_CSI_NOF_BITS 4
/// Implements SNRI to CQI conversion
uint32_t csi_snri_db_to_cqi(srslte_csi_cqi_table_t table, float snri_db)
{
return 6;
}
// Implements CSI report triggers
static bool csi_report_trigger(const srslte_csi_hl_report_cfg_t* cfg, uint32_t slot_idx)
{
switch (cfg->type) {
case SRSLTE_CSI_REPORT_TYPE_PERIODIC:
return (slot_idx + cfg->periodic.period - cfg->periodic.offset) % cfg->periodic.period == 0;
default:; // Do nothing
}
return false;
}
static void csi_wideband_cri_ri_pmi_cqi_quantify(const srslte_csi_hl_report_cfg_t* cfg,
const srslte_csi_measurements_t* channel_meas,
const srslte_csi_measurements_t* interf_meas,
srslte_csi_report_cfg_t* report_cfg,
srslte_csi_report_value_t* report_value)
{
// Take SNR by default
float wideband_sinr_db = channel_meas->wideband_snr_db;
// If interference is provided, use the channel RSRP and interference EPRE to calculate the SINR
if (interf_meas != NULL) {
wideband_sinr_db = channel_meas->wideband_rsrp_dBm - interf_meas->wideband_epre_dBm;
}
// Fill report configuration
report_cfg->type = cfg->type;
report_cfg->quantity = SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI;
report_cfg->freq_cfg = SRSLTE_CSI_REPORT_FREQ_WIDEBAND;
report_cfg->nof_ports = channel_meas->nof_ports;
report_cfg->K_csi_rs = channel_meas->K_csi_rs;
// Save PUCCH resource only if periodic type
if (cfg->type == SRSLTE_CSI_REPORT_TYPE_PERIODIC) {
report_cfg->pucch_resource = cfg->periodic.resource;
}
// Fill quantified values
report_value->wideband_cri_ri_pmi_cqi.cqi = csi_snri_db_to_cqi(cfg->cqi_table, wideband_sinr_db);
report_value->wideband_cri_ri_pmi_cqi.ri = 0;
report_value->wideband_cri_ri_pmi_cqi.pmi = 0;
}
static uint32_t csi_wideband_cri_ri_pmi_cqi_nof_bits(const srslte_csi_report_cfg_t* cfg)
{
// Compute number of bits for CRI
uint32_t nof_bits_cri = 0;
if (cfg->K_csi_rs > 0) {
nof_bits_cri = (uint32_t)ceilf(log2f((float)cfg->K_csi_rs));
}
switch (cfg->nof_ports) {
case 1:
return CSI_WIDEBAND_CSI_NOF_BITS + nof_bits_cri;
default:
ERROR("Invalid or not implemented number of ports (%d)", cfg->nof_ports);
}
return 0;
}
static int csi_wideband_cri_ri_pmi_cqi_pack(const srslte_csi_report_cfg_t* cfg,
const srslte_csi_report_value_t* value,
uint8_t* o_csi1)
{
// Compute number of bits for CRI
uint32_t nof_bits_cri = 0;
if (cfg->K_csi_rs > 0) {
nof_bits_cri = (uint32_t)ceilf(log2f((float)cfg->K_csi_rs));
}
// Write wideband CQI
srslte_bit_unpack(value->wideband_cri_ri_pmi_cqi.cqi, &o_csi1, CSI_WIDEBAND_CSI_NOF_BITS);
// Compute number of bits for CRI and write
srslte_bit_unpack(value->cri, &o_csi1, nof_bits_cri);
return nof_bits_cri + CSI_WIDEBAND_CSI_NOF_BITS;
}
int srslte_csi_generate_reports(const srslte_csi_hl_cfg_t* cfg,
uint32_t slot_idx,
const srslte_csi_measurements_t measurements[SRSLTE_CSI_MAX_NOF_RESOURCES],
srslte_csi_report_cfg_t report_cfg[SRSLTE_CSI_MAX_NOF_REPORT],
srslte_csi_report_value_t report_value[SRSLTE_CSI_MAX_NOF_REPORT])
{
uint32_t count = 0;
// Check inputs
if (cfg == NULL || measurements == NULL || report_cfg == NULL || report_value == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Iterate every possible configured CSI report
for (uint32_t i = 0; i < SRSLTE_CSI_MAX_NOF_REPORT; i++) {
// Skip if report is not configured or triggered
if (!csi_report_trigger(&cfg->reports[i], slot_idx)) {
continue;
}
// Select channel measurement
if (cfg->reports->channel_meas_id >= SRSLTE_CSI_MAX_NOF_RESOURCES) {
ERROR("Channel measurement ID (%d) is out of range", cfg->reports->channel_meas_id);
return SRSLTE_ERROR;
}
const srslte_csi_measurements_t* channel_meas = &measurements[cfg->reports->channel_meas_id];
// Select interference measurement
const srslte_csi_measurements_t* interf_meas = NULL;
if (cfg->reports->interf_meas_present) {
if (cfg->reports->interf_meas_id >= SRSLTE_CSI_MAX_NOF_RESOURCES) {
ERROR("Interference measurement ID (%d) is out of range", cfg->reports->interf_meas_id);
return SRSLTE_ERROR;
}
interf_meas = &measurements[cfg->reports->interf_meas_id];
}
// Quantify measurements according to frequency and quantity configuration
if (cfg->reports->freq_cfg == SRSLTE_CSI_REPORT_FREQ_WIDEBAND &&
cfg->reports->quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
csi_wideband_cri_ri_pmi_cqi_quantify(
&cfg->reports[i], channel_meas, interf_meas, &report_cfg[count], &report_value[count]);
count++;
} else {
; // Ignore other types
}
}
return (int)count;
}
int srslte_csi_nof_bits(const srslte_csi_report_cfg_t* report_list, uint32_t nof_reports)
{
uint32_t count = 0;
// Check input pointer
if (report_list == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Iterate all report configurations
for (uint32_t i = 0; i < nof_reports; i++) {
const srslte_csi_report_cfg_t* report = &report_list[i];
if (report->quantity && report->quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
count += csi_wideband_cri_ri_pmi_cqi_nof_bits(report);
}
}
return (int)count;
}
int srslte_csi_part1_pack(const srslte_csi_report_cfg_t* report_cfg,
const srslte_csi_report_value_t* report_value,
uint32_t nof_reports,
uint8_t* o_csi1,
uint32_t max_o_csi1)
{
uint32_t count = 0;
if (report_cfg == NULL || report_value == NULL || o_csi1 == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
int n = srslte_csi_nof_bits(report_cfg, nof_reports);
if (n > (int)max_o_csi1) {
ERROR("The maximum number of CSI bits (%d) is not enough to accommodate %d bits", max_o_csi1, n);
return SRSLTE_ERROR;
}
for (uint32_t i = 0; i < nof_reports && count < max_o_csi1; i++) {
if (report_cfg[i].freq_cfg == SRSLTE_CSI_REPORT_FREQ_WIDEBAND &&
report_cfg[i].quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
count += csi_wideband_cri_ri_pmi_cqi_pack(&report_cfg[i], &report_value[i], &o_csi1[count]);
} else {
ERROR("CSI frequency (%d) and quantity (%d) combination is not implemented",
report_cfg[i].freq_cfg,
report_cfg[i].quantity);
}
}
return (int)count;
}
uint32_t srslte_csi_str(const srslte_csi_report_cfg_t* report_cfg,
const srslte_csi_report_value_t* report_value,
uint32_t nof_reports,
char* str,
uint32_t str_len)
{
uint32_t len = 0;
for (uint32_t i = 0; i < nof_reports; i++) {
if (report_cfg[i].freq_cfg == SRSLTE_CSI_REPORT_FREQ_WIDEBAND &&
report_cfg[i].quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
len = srslte_print_check(str, str_len, len, ", cqi=%d", report_value[i].wideband_cri_ri_pmi_cqi.cqi);
}
}
return len;
}

@ -321,16 +321,6 @@ static int pdsch_init(srslte_pdsch_t* q, uint32_t max_prb, bool is_ue, uint32_t
}
}
q->users = calloc(sizeof(srslte_pdsch_user_t*), q->is_ue ? 1 : (1 + SRSLTE_SIRNTI));
if (!q->users) {
ERROR("malloc");
goto clean;
}
if (srslte_sequence_init(&q->tmp_seq, q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_256QAM))) {
goto clean;
}
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (!q->csi[i]) {
q->csi[i] = srslte_vec_f_malloc(q->max_re * 2);
@ -459,20 +449,6 @@ void srslte_pdsch_free(srslte_pdsch_t* q)
}
}
}
if (q->users) {
if (q->is_ue) {
srslte_pdsch_free_rnti(q, 0);
} else {
for (int u = 0; u <= SRSLTE_SIRNTI; u++) {
if (q->users[u]) {
srslte_pdsch_free_rnti(q, u);
}
}
}
free(q->users);
}
srslte_sequence_free(&q->tmp_seq);
for (int i = 0; i < SRSLTE_MOD_NITEMS; i++) {
srslte_modem_table_free(&q->mod[i]);
@ -507,68 +483,6 @@ int srslte_pdsch_set_cell(srslte_pdsch_t* q, srslte_cell_t cell)
return ret;
}
/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while
* to execute, so shall be called once the final C-RNTI has been allocated for the session.
*/
int srslte_pdsch_set_rnti(srslte_pdsch_t* q, uint16_t rnti)
{
uint32_t rnti_idx = q->is_ue ? 0 : rnti;
// Decide whether re-generating the sequence
if (!q->users[rnti_idx]) {
// If the sequence is not allocated generate
q->users[rnti_idx] = calloc(1, sizeof(srslte_pdsch_user_t));
if (!q->users[rnti_idx]) {
ERROR("Alocating PDSCH user");
return SRSLTE_ERROR;
}
} else if (q->users[rnti_idx]->sequence_generated && q->users[rnti_idx]->cell_id == q->cell.id && !q->is_ue) {
// The sequence was generated, cell has not changed and it is eNb, save any efforts
return SRSLTE_SUCCESS;
}
// Set sequence as not generated
q->users[rnti_idx]->sequence_generated = false;
// For each subframe
for (int sf_idx = 0; sf_idx < SRSLTE_NOF_SF_X_FRAME; sf_idx++) {
// For each codeword
for (int j = 0; j < SRSLTE_MAX_CODEWORDS; j++) {
if (srslte_sequence_pdsch(&q->users[rnti_idx]->seq[j][sf_idx],
rnti,
j,
SRSLTE_NOF_SLOTS_PER_SF * sf_idx,
q->cell.id,
q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_256QAM))) {
ERROR("Error initializing PDSCH scrambling sequence");
srslte_pdsch_free_rnti(q, rnti);
return SRSLTE_ERROR;
}
}
}
// Save generation states
q->ue_rnti = rnti;
q->users[rnti_idx]->cell_id = q->cell.id;
q->users[rnti_idx]->sequence_generated = true;
return SRSLTE_SUCCESS;
}
void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti)
{
uint32_t rnti_idx = q->is_ue ? 0 : rnti;
if (q->users[rnti_idx]) {
for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) {
for (int j = 0; j < SRSLTE_MAX_CODEWORDS; j++) {
srslte_sequence_free(&q->users[rnti_idx]->seq[j][i]);
}
}
free(q->users[rnti_idx]);
q->users[rnti_idx] = NULL;
q->ue_rnti = 0;
}
}
static float apply_power_allocation(srslte_pdsch_t* q, srslte_pdsch_cfg_t* cfg, cf_t* sf_symbols_m[SRSLTE_MAX_PORTS])
{
uint32_t nof_symbols_slot = cfg->grant.nof_symb_slot[0];
@ -606,21 +520,6 @@ static float apply_power_allocation(srslte_pdsch_t* q, srslte_pdsch_cfg_t* cfg,
return rho_a;
}
static srslte_sequence_t*
get_user_sequence(srslte_pdsch_t* q, uint16_t rnti, uint32_t codeword_idx, uint32_t sf_idx, uint32_t len)
{
uint32_t rnti_idx = q->is_ue ? 0 : rnti;
// The scrambling sequence is pregenerated for all RNTIs in the eNodeB but only for C-RNTI in the UE
if (q->users[rnti_idx] && q->users[rnti_idx]->sequence_generated && q->users[rnti_idx]->cell_id == q->cell.id &&
(!q->is_ue || q->ue_rnti == rnti)) {
return &q->users[rnti_idx]->seq[codeword_idx][sf_idx];
} else {
srslte_sequence_pdsch(&q->tmp_seq, rnti, codeword_idx, 2 * sf_idx, q->cell.id, len);
return &q->tmp_seq;
}
}
static void csi_correction(srslte_pdsch_t* q, srslte_pdsch_cfg_t* cfg, uint32_t codeword_idx, uint32_t tb_idx, void* e)
{
uint32_t qm = 0;
@ -830,19 +729,23 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t* q,
data[tb_idx].evm = NAN;
}
/* Select scrambling sequence */
srslte_sequence_t* seq =
get_user_sequence(q, cfg->rnti, codeword_idx, sf->tti % 10, cfg->grant.tb[tb_idx].nof_bits);
if (!seq) {
ERROR("Error getting user sequence for rnti=0x%x", cfg->rnti);
return -1;
}
/* Bit scrambling */
if (q->llr_is_8bit) {
srslte_scrambling_sb_offset(seq, q->e[codeword_idx], 0, cfg->grant.tb[tb_idx].nof_bits);
srslte_sequence_pdsch_apply_c(q->e[codeword_idx],
q->e[codeword_idx],
cfg->rnti,
codeword_idx,
2 * (sf->tti % SRSLTE_NOF_SF_X_FRAME),
q->cell.id,
cfg->grant.tb[tb_idx].nof_bits);
} else {
srslte_scrambling_s_offset(seq, q->e[codeword_idx], 0, cfg->grant.tb[tb_idx].nof_bits);
srslte_sequence_pdsch_apply_s(q->e[codeword_idx],
q->e[codeword_idx],
cfg->rnti,
codeword_idx,
2 * (sf->tti % SRSLTE_NOF_SF_X_FRAME),
q->cell.id,
cfg->grant.tb[tb_idx].nof_bits);
}
if (cfg->csi_enable) {
@ -1107,16 +1010,14 @@ static int srslte_pdsch_codeword_encode(srslte_pdsch_t* q,
return SRSLTE_ERROR;
}
/* Select scrambling sequence */
srslte_sequence_t* seq =
get_user_sequence(q, cfg->rnti, codeword_idx, sf->tti % 10, cfg->grant.tb[tb_idx].nof_bits);
if (!seq) {
ERROR("Error getting user sequence for rnti=0x%x", cfg->rnti);
return -1;
}
/* Bit scrambling */
srslte_scrambling_bytes(seq, (uint8_t*)q->e[codeword_idx], cfg->grant.tb[tb_idx].nof_bits);
srslte_sequence_pdsch_apply_pack((uint8_t*)q->e[codeword_idx],
(uint8_t*)q->e[codeword_idx],
cfg->rnti,
codeword_idx,
2 * (sf->tti % SRSLTE_NOF_SF_X_FRAME),
q->cell.id,
cfg->grant.tb[tb_idx].nof_bits);
/* Bit mapping */
srslte_mod_modulate_bytes(

@ -58,13 +58,7 @@ int srslte_pucch_init_(srslte_pucch_t* q, bool is_ue)
q->is_ue = is_ue;
q->users = calloc(sizeof(srslte_pucch_user_t*), q->is_ue ? 1 : (1 + SRSLTE_SIRNTI));
if (!q->users) {
perror("malloc");
goto clean_exit;
}
if (srslte_sequence_init(&q->tmp_seq, 20)) {
if (srslte_sequence_init(&q->seq_f2, 20)) {
goto clean_exit;
}
@ -98,18 +92,7 @@ int srslte_pucch_init_enb(srslte_pucch_t* q)
void srslte_pucch_free(srslte_pucch_t* q)
{
if (q->users) {
if (q->is_ue) {
srslte_pucch_free_rnti(q, 0);
} else {
for (int rnti = 0; rnti <= SRSLTE_SIRNTI; rnti++) {
srslte_pucch_free_rnti(q, rnti);
}
}
free(q->users);
}
srslte_sequence_free(&q->tmp_seq);
srslte_sequence_free(&q->seq_f2);
srslte_uci_cqi_pucch_free(&q->cqi);
if (q->z) {
@ -148,58 +131,6 @@ int srslte_pucch_set_cell(srslte_pucch_t* q, srslte_cell_t cell)
return ret;
}
void srslte_pucch_free_rnti(srslte_pucch_t* q, uint16_t rnti)
{
uint32_t rnti_idx = q->is_ue ? 0 : rnti;
if (q->users[rnti_idx]) {
for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) {
srslte_sequence_free(&q->users[rnti_idx]->seq_f2[i]);
}
free(q->users[rnti_idx]);
q->users[rnti_idx] = NULL;
q->ue_rnti = 0;
}
}
int srslte_pucch_set_rnti(srslte_pucch_t* q, uint16_t rnti)
{
uint32_t rnti_idx = q->is_ue ? 0 : rnti;
// Decide whether re-generating the sequence
if (!q->users[rnti_idx]) {
// If the sequence is not allocated generate
q->users[rnti_idx] = calloc(1, sizeof(srslte_pdsch_user_t));
if (!q->users[rnti_idx]) {
ERROR("Alocating PDSCH user");
return SRSLTE_ERROR;
}
} else if (q->users[rnti_idx]->sequence_generated && q->users[rnti_idx]->cell_id == q->cell.id && !q->is_ue) {
// The sequence was generated, cell has not changed and it is eNb, save any efforts
return SRSLTE_SUCCESS;
}
// Set sequence as not generated
q->users[rnti_idx]->sequence_generated = false;
// For each subframe
for (int sf_idx = 0; sf_idx < SRSLTE_NOF_SF_X_FRAME; sf_idx++) {
if (srslte_sequence_pucch(
&q->users[rnti_idx]->seq_f2[sf_idx], rnti, SRSLTE_NOF_SLOTS_PER_SF * sf_idx, q->cell.id)) {
ERROR("Error initializing PUCCH scrambling sequence");
srslte_pucch_free_rnti(q, rnti);
return SRSLTE_ERROR;
}
}
// Save generation states
q->ue_rnti = rnti;
q->users[rnti_idx]->cell_id = q->cell.id;
q->users[rnti_idx]->sequence_generated = true;
return SRSLTE_SUCCESS;
}
static cf_t uci_encode_format1()
{
return 1.0;
@ -227,34 +158,11 @@ static cf_t uci_encode_format1b(uint8_t bits[2])
}
}
static srslte_sequence_t* get_user_sequence(srslte_pucch_t* q, uint16_t rnti, uint32_t sf_idx)
{
uint32_t rnti_idx = q->is_ue ? 0 : rnti;
// The scrambling sequence is pregenerated for all RNTIs in the eNodeB but only for C-RNTI in the UE
if (rnti >= SRSLTE_CRNTI_START && rnti < SRSLTE_CRNTI_END) {
if (q->users[rnti_idx] && q->users[rnti_idx]->sequence_generated && q->users[rnti_idx]->cell_id == q->cell.id &&
(!q->is_ue || q->ue_rnti == rnti)) {
return &q->users[rnti_idx]->seq_f2[sf_idx];
} else {
if (srslte_sequence_pucch(&q->tmp_seq, rnti, 2 * sf_idx, q->cell.id)) {
ERROR("Error computing PUCCH Format 2 scrambling sequence");
return NULL;
}
return &q->tmp_seq;
}
} else {
ERROR("Invalid RNTI=0x%x", rnti);
return NULL;
}
}
/* Encode PUCCH bits according to Table 5.4.1-1 in Section 5.4.1 of 36.211 */
static int
uci_mod_bits(srslte_pucch_t* q, srslte_ul_sf_cfg_t* sf, srslte_pucch_cfg_t* cfg, uint8_t bits[SRSLTE_PUCCH_MAX_BITS])
{
uint8_t tmp[2];
srslte_sequence_t* seq;
switch (cfg->format) {
case SRSLTE_PUCCH_FORMAT_1:
q->d[0] = uci_encode_format1();
@ -270,26 +178,22 @@ uci_mod_bits(srslte_pucch_t* q, srslte_ul_sf_cfg_t* sf, srslte_pucch_cfg_t* cfg,
case SRSLTE_PUCCH_FORMAT_2:
case SRSLTE_PUCCH_FORMAT_2A:
case SRSLTE_PUCCH_FORMAT_2B:
seq = get_user_sequence(q, cfg->rnti, sf->tti % 10);
if (seq) {
memcpy(q->bits_scram, bits, SRSLTE_PUCCH2_NOF_BITS * sizeof(uint8_t));
srslte_scrambling_b_offset(seq, q->bits_scram, 0, SRSLTE_PUCCH2_NOF_BITS);
srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH2_NOF_BITS);
} else {
ERROR("Error modulating PUCCH2 bits: could not generate sequence");
return -1;
if (srslte_sequence_pucch(&q->seq_f2, cfg->rnti, 2 * (sf->tti % 10), q->cell.id)) {
ERROR("Error computing PUCCH Format 2 scrambling sequence\n");
return SRSLTE_ERROR;
}
srslte_vec_u8_copy(q->bits_scram, bits, SRSLTE_PUCCH2_NOF_BITS);
srslte_scrambling_b_offset(&q->seq_f2, q->bits_scram, 0, SRSLTE_PUCCH2_NOF_BITS);
srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH2_NOF_BITS);
break;
case SRSLTE_PUCCH_FORMAT_3:
seq = get_user_sequence(q, cfg->rnti, sf->tti % 10);
if (seq) {
memcpy(q->bits_scram, bits, SRSLTE_PUCCH3_NOF_BITS * sizeof(uint8_t));
srslte_scrambling_b_offset(seq, q->bits_scram, 0, SRSLTE_PUCCH3_NOF_BITS);
srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH3_NOF_BITS);
} else {
ERROR("Error modulating PUCCH3 bits: rnti not set");
if (srslte_sequence_pucch(&q->seq_f2, cfg->rnti, 2 * (sf->tti % 10), q->cell.id)) {
ERROR("Error computing PUCCH Format 2 scrambling sequence\n");
return SRSLTE_ERROR;
}
srslte_vec_u8_copy(q->bits_scram, bits, SRSLTE_PUCCH3_NOF_BITS);
srslte_scrambling_b_offset(&q->seq_f2, q->bits_scram, 0, SRSLTE_PUCCH3_NOF_BITS);
srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH3_NOF_BITS);
break;
default:
ERROR("PUCCH format %s not supported", srslte_pucch_format_text(cfg->format));
@ -641,19 +545,15 @@ static int decode_signal_format3(srslte_pucch_t* q,
srslte_vec_sc_prod_cfc(q->d, 2.0f / (N_sf_0 + N_sf_1), q->d, SRSLTE_NRE * 2);
srslte_sequence_t* seq = get_user_sequence(q, cfg->rnti, sf->tti % 10);
if (seq) {
srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->d, q->llr, SRSLTE_PUCCH3_NOF_BITS);
srslte_scrambling_s_offset(seq, q->llr, 0, SRSLTE_PUCCH3_NOF_BITS);
return (int)srslte_block_decode_i16(q->llr, SRSLTE_PUCCH3_NOF_BITS, bits, SRSLTE_UCI_MAX_ACK_SR_BITS);
} else {
ERROR("Error modulating PUCCH3 bits: rnti not set");
if (srslte_sequence_pucch(&q->seq_f2, cfg->rnti, 2 * (sf->tti % 10), q->cell.id)) {
ERROR("Error computing PUCCH Format 2 scrambling sequence\n");
return SRSLTE_ERROR;
}
srslte_scrambling_s_offset(&q->seq_f2, q->llr, 0, SRSLTE_PUCCH3_NOF_BITS);
return SRSLTE_SUCCESS;
return (int)srslte_block_decode_i16(q->llr, SRSLTE_PUCCH3_NOF_BITS, bits, SRSLTE_UCI_MAX_ACK_SR_BITS);
}
static int encode_signal(srslte_pucch_t* q,
@ -725,7 +625,6 @@ static bool decode_signal(srslte_pucch_t* q,
float corr = 0, corr_max = -1e9;
uint8_t b_max = 0, b2_max = 0; // default bit value, eg. HI is NACK
srslte_sequence_t* seq;
cf_t ref[SRSLTE_PUCCH_MAX_SYMBOLS];
switch (cfg->format) {
@ -781,15 +680,17 @@ static bool decode_signal(srslte_pucch_t* q,
case SRSLTE_PUCCH_FORMAT_2:
case SRSLTE_PUCCH_FORMAT_2A:
case SRSLTE_PUCCH_FORMAT_2B:
seq = get_user_sequence(q, cfg->rnti, sf->tti % SRSLTE_NOF_SF_X_FRAME);
if (seq) {
if (srslte_sequence_pucch(&q->seq_f2, cfg->rnti, 2 * (sf->tti % 10), q->cell.id)) {
ERROR("Error computing PUCCH Format 2 scrambling sequence\n");
return SRSLTE_ERROR;
}
encode_signal_format12(q, sf, cfg, NULL, ref, true);
srslte_vec_prod_conj_ccc(q->z, ref, q->z_tmp, SRSLTE_PUCCH_MAX_SYMBOLS);
for (int i = 0; i < (SRSLTE_PUCCH2_N_SF * SRSLTE_NOF_SLOTS_PER_SF); i++) {
q->z[i] = srslte_vec_acc_cc(&q->z_tmp[i * SRSLTE_NRE], SRSLTE_NRE) / SRSLTE_NRE;
}
srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->z, llr_pucch2, SRSLTE_PUCCH2_NOF_BITS / 2);
srslte_scrambling_s_offset(seq, llr_pucch2, 0, SRSLTE_PUCCH2_NOF_BITS);
srslte_scrambling_s_offset(&q->seq_f2, llr_pucch2, 0, SRSLTE_PUCCH2_NOF_BITS);
// Calculate the LLR RMS for normalising
float llr_pow = srslte_vec_avg_power_sf(llr_pucch2, SRSLTE_PUCCH2_NOF_BITS);
@ -801,10 +702,6 @@ static bool decode_signal(srslte_pucch_t* q,
corr = 0;
}
detected = true;
} else {
ERROR("Decoding PUCCH2: could not generate sequence");
return -1;
}
break;
case SRSLTE_PUCCH_FORMAT_3:
corr = (float)decode_signal_format3(q, sf, cfg, pucch_bits, q->z) / 4800.0f;
@ -1065,7 +962,7 @@ bool srslte_pucch_cfg_isvalid(srslte_pucch_cfg_t* cfg, uint32_t nof_prb)
}
}
uint32_t srslte_pucch_n_prb(srslte_cell_t* cell, srslte_pucch_cfg_t* cfg, uint32_t ns)
uint32_t srslte_pucch_n_prb(const srslte_cell_t* cell, const srslte_pucch_cfg_t* cfg, uint32_t ns)
{
uint32_t m = srslte_pucch_m(cfg, cell->cp);
// Determine n_prb

@ -125,16 +125,6 @@ static int pusch_init(srslte_pusch_t* q, uint32_t max_prb, bool is_ue)
q->is_ue = is_ue;
q->users = calloc(sizeof(srslte_pusch_user_t*), q->is_ue ? 1 : (1 + SRSLTE_SIRNTI));
if (!q->users) {
perror("malloc");
goto clean;
}
if (srslte_sequence_init(&q->tmp_seq, q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) {
goto clean;
}
srslte_sch_init(&q->ul_sch);
if (srslte_dft_precoding_init(&q->dft_precoding, max_prb, is_ue)) {
@ -219,19 +209,6 @@ void srslte_pusch_free(srslte_pusch_t* q)
}
srslte_dft_precoding_free(&q->dft_precoding);
if (q->users) {
if (q->is_ue) {
srslte_pusch_free_rnti(q, 0);
} else {
for (int rnti = 0; rnti <= SRSLTE_SIRNTI; rnti++) {
srslte_pusch_free_rnti(q, rnti);
}
}
free(q->users);
}
srslte_sequence_free(&q->tmp_seq);
for (i = 0; i < SRSLTE_MOD_NITEMS; i++) {
srslte_modem_table_free(&q->mod[i]);
}
@ -257,86 +234,6 @@ int srslte_pusch_set_cell(srslte_pusch_t* q, srslte_cell_t cell)
return ret;
}
/* Precalculate the PUSCH scramble sequences for a given RNTI. This function takes a while
* to execute, so shall be called once the final C-RNTI has been allocated for the session.
* For the connection procedure, use srslte_pusch_encode() functions */
int srslte_pusch_set_rnti(srslte_pusch_t* q, uint16_t rnti)
{
uint32_t rnti_idx = q->is_ue ? 0 : rnti;
// Decide whether re-generating the sequence
if (!q->users[rnti_idx]) {
// If the sequence is not allocated generate
q->users[rnti_idx] = calloc(1, sizeof(srslte_pdsch_user_t));
if (!q->users[rnti_idx]) {
ERROR("Alocating PDSCH user");
return SRSLTE_ERROR;
}
} else if (q->users[rnti_idx]->sequence_generated && q->users[rnti_idx]->cell_id == q->cell.id && !q->is_ue) {
// The sequence was generated, cell has not changed and it is eNb, save any efforts
return SRSLTE_SUCCESS;
}
// Set sequence as not generated
q->users[rnti_idx]->sequence_generated = false;
// For each subframe
for (int sf_idx = 0; sf_idx < SRSLTE_NOF_SF_X_FRAME; sf_idx++) {
if (srslte_sequence_pusch(&q->users[rnti_idx]->seq[sf_idx],
rnti,
SRSLTE_NOF_SLOTS_PER_SF * sf_idx,
q->cell.id,
q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) {
ERROR("Error initializing PUSCH scrambling sequence");
srslte_pusch_free_rnti(q, rnti);
return SRSLTE_ERROR;
}
}
// Save generation states
q->ue_rnti = rnti;
q->users[rnti_idx]->cell_id = q->cell.id;
q->users[rnti_idx]->sequence_generated = true;
return SRSLTE_SUCCESS;
}
void srslte_pusch_free_rnti(srslte_pusch_t* q, uint16_t rnti)
{
uint32_t rnti_idx = q->is_ue ? 0 : rnti;
if (q->users[rnti_idx]) {
for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) {
srslte_sequence_free(&q->users[rnti_idx]->seq[i]);
}
free(q->users[rnti_idx]);
q->users[rnti_idx] = NULL;
q->ue_rnti = 0;
}
}
static srslte_sequence_t* get_user_sequence(srslte_pusch_t* q, uint16_t rnti, uint32_t sf_idx, uint32_t len)
{
uint32_t rnti_idx = q->is_ue ? 0 : rnti;
if (SRSLTE_RNTI_ISUSER(rnti)) {
// The scrambling sequence is pregenerated for all RNTIs in the eNodeB but only for C-RNTI in the UE
if (q->users[rnti_idx] && q->users[rnti_idx]->sequence_generated && q->users[rnti_idx]->cell_id == q->cell.id &&
(!q->is_ue || q->ue_rnti == rnti)) {
return &q->users[rnti_idx]->seq[sf_idx];
} else {
if (srslte_sequence_pusch(&q->tmp_seq, rnti, 2 * sf_idx, q->cell.id, len)) {
ERROR("Error generating temporal scrambling sequence");
return NULL;
}
return &q->tmp_seq;
}
} else {
ERROR("Invalid RNTI=0x%x", rnti);
return NULL;
}
}
int srslte_pusch_assert_grant(const srslte_pusch_grant_t* grant)
{
// Check for valid number of PRB
@ -407,15 +304,13 @@ int srslte_pusch_encode(srslte_pusch_t* q,
uint32_t nof_ri_ack_bits = (uint32_t)ret;
// Generate scrambling sequence if not pre-generated
srslte_sequence_t* seq = get_user_sequence(q, cfg->rnti, sf->tti % 10, cfg->grant.tb.nof_bits);
if (!seq) {
ERROR("Error getting user sequence for rnti=0x%x", cfg->rnti);
return -1;
}
// Run scrambling
srslte_scrambling_bytes(seq, (uint8_t*)q->q, cfg->grant.tb.nof_bits);
srslte_sequence_pusch_apply_pack((uint8_t*)q->q,
(uint8_t*)q->q,
cfg->rnti,
2 * (sf->tti % SRSLTE_NOF_SF_X_FRAME),
q->cell.id,
cfg->grant.tb.nof_bits);
// Correct UCI placeholder/repetition bits
uint8_t* d = q->q;
@ -537,25 +432,25 @@ int srslte_pusch_decode(srslte_pusch_t* q,
out->evm = NAN;
}
// Generate scrambling sequence if not pre-generated
srslte_sequence_t* seq = get_user_sequence(q, cfg->rnti, sf->tti % 10, cfg->grant.tb.nof_bits);
if (!seq) {
ERROR("Error getting user sequence for rnti=0x%x", cfg->rnti);
return -1;
}
// Descrambling
if (q->llr_is_8bit) {
srslte_scrambling_sb_offset(seq, q->q, 0, cfg->grant.tb.nof_bits);
srslte_sequence_pusch_apply_c(
q->q, q->q, cfg->rnti, 2 * (sf->tti % SRSLTE_NOF_SF_X_FRAME), q->cell.id, cfg->grant.tb.nof_bits);
} else {
srslte_scrambling_s_offset(seq, q->q, 0, cfg->grant.tb.nof_bits);
srslte_sequence_pusch_apply_s(
q->q, q->q, cfg->rnti, 2 * (sf->tti % SRSLTE_NOF_SF_X_FRAME), q->cell.id, cfg->grant.tb.nof_bits);
}
// Generate packed sequence for UCI decoder
uint8_t* c = (uint8_t*)q->z; // Reuse Z
srslte_sequence_pusch_gen_unpack(
c, cfg->rnti, 2 * (sf->tti % SRSLTE_NOF_SF_X_FRAME), q->cell.id, cfg->grant.tb.nof_bits);
// Set max number of iterations
srslte_sch_set_max_noi(&q->ul_sch, cfg->max_nof_iterations);
// Decode
ret = srslte_ulsch_decode(&q->ul_sch, cfg, q->q, q->g, seq->c, out->data, &out->uci);
ret = srslte_ulsch_decode(&q->ul_sch, cfg, q->q, q->g, c, out->data, &out->uci);
out->crc = (ret == 0);
// Save number of iterations

@ -190,15 +190,15 @@ srslte_mod_t srslte_ra_ul_mod_from_mcs(uint32_t mcs)
static int srslte_ra_dl_mcs_from_tbs_idx(uint32_t tbs_idx, bool use_tbs_index_alt)
{
if (use_tbs_index_alt) {
for (int i = 0; i < 28; i++) {
if (tbs_idx == dl_mcs_tbs_idx_table2[i]) {
return i;
for (int mcs = 27; mcs >= 0; mcs--) {
if (tbs_idx == dl_mcs_tbs_idx_table2[mcs]) {
return mcs;
}
}
} else {
for (int i = 0; i < 29; i++) {
if (tbs_idx == dl_mcs_tbs_idx_table[i]) {
return i;
for (int mcs = 28; mcs >= 0; mcs--) {
if (tbs_idx == dl_mcs_tbs_idx_table[mcs]) {
return mcs;
}
}
}
@ -207,9 +207,10 @@ static int srslte_ra_dl_mcs_from_tbs_idx(uint32_t tbs_idx, bool use_tbs_index_al
static int srslte_ra_ul_mcs_from_tbs_idx(uint32_t tbs_idx)
{
for (int i = 0; i < 29; i++) {
if (tbs_idx == ul_mcs_tbs_idx_table[i]) {
return i;
// Note: go in descent order to find max mcs possible
for (int mcs = 28; mcs >= 0; mcs--) {
if (tbs_idx == ul_mcs_tbs_idx_table[mcs]) {
return mcs;
}
}
return SRSLTE_ERROR;
@ -233,21 +234,22 @@ int srslte_ra_tbs_from_idx(uint32_t tbs_idx, uint32_t n_prb)
/* Returns lowest nearest index of TBS value in table 7.1.7.2 on 36.213
* or -1 if the TBS value is not within the valid TBS values
*/
int srslte_ra_tbs_to_table_idx(uint32_t tbs, uint32_t n_prb)
/*
* Returns upper bound (exclusive) of TBS index interval whose TBS value encompasses the provided TBS
* \remark taken from table 7.1.7.2 on 36.213
* @return upper bound of TBS index (0..27), -2 if bad arguments
*/
int srslte_ra_tbs_to_table_idx(uint32_t tbs, uint32_t n_prb, uint32_t max_tbs_idx)
{
uint32_t idx;
if (n_prb > 0 && n_prb <= SRSLTE_MAX_PRB) {
if (tbs <= tbs_table[0][n_prb - 1]) {
return 0;
if (n_prb == 0 || n_prb > SRSLTE_MAX_PRB) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (tbs >= tbs_table[26][n_prb - 1]) {
return 27;
}
for (idx = 0; idx < 26; idx++) {
if (tbs_table[idx][n_prb - 1] <= tbs && tbs_table[idx + 1][n_prb - 1] >= tbs) {
return idx + 1;
if (tbs < tbs_table[0][n_prb - 1]) {
return 0;
}
for (int tbs_idx = max_tbs_idx; tbs_idx >= 0; tbs_idx--) {
if (tbs_table[tbs_idx][n_prb - 1] <= tbs) {
return tbs_idx + 1;
}
}
return SRSLTE_ERROR;

@ -362,6 +362,15 @@ static int dl_dci_compute_tb(bool pdsch_use_tbs_index_alt, const srslte_dci_dl_t
}
}
// 256QAM table is allowed if:
// - if the higher layer parameter altCQI-Table-r12 is configured, and
// - if the PDSCH is assigned by a PDCCH/EPDCCH with DCI format 1/1B/1D/2/2A/2B/2C/2D with
// - CRC scrambled by C-RNTI,
// Otherwise, use 64QAM table (default table for R8).
if (dci->format == SRSLTE_DCI_FORMAT1A || !SRSLTE_RNTI_ISUSER(dci->rnti)) {
pdsch_use_tbs_index_alt = false;
}
if (!SRSLTE_RNTI_ISUSER(dci->rnti) && !SRSLTE_RNTI_ISMBSFN(dci->rnti)) {
if (dci->format == SRSLTE_DCI_FORMAT1A) {
n_prb = dci->type2_alloc.n_prb1a == SRSLTE_RA_TYPE2_NPRB1A_2 ? 2 : 3;

@ -23,6 +23,7 @@
#include "ra_helper.h"
#include "srslte/phy/ch_estimation/dmrs_pucch.h"
#include "srslte/phy/common/phy_common.h"
#include "srslte/phy/phch/csi.h"
#include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.h"
@ -381,7 +382,7 @@ int srslte_ra_ul_nr_pucch_format_2_3_min_prb(const srslte_pucch_nr_resource_t* r
}
// Compute total number of UCI bits
uint32_t O_total = uci_cfg->o_ack + uci_cfg->o_sr + uci_cfg->o_csi1 + uci_cfg->o_csi2;
uint32_t O_total = uci_cfg->o_ack + uci_cfg->o_sr + srslte_csi_nof_bits(uci_cfg->csi, uci_cfg->nof_csi);
// Add CRC bits if any
O_total += srslte_uci_nr_crc_len(O_total);
@ -459,12 +460,53 @@ int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pucch_cfg,
const srslte_uci_cfg_nr_t* uci_cfg,
srslte_pucch_nr_resource_t* resource)
{
if (pucch_cfg == NULL || uci_cfg == NULL) {
if (pucch_cfg == NULL || uci_cfg == NULL || resource == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
uint32_t O_uci = srslte_uci_nr_total_bits(uci_cfg);
// Use SR PUCCH resource
// - At least one positive SR
// - up to 2 HARQ-ACK
// - No CSI report
if (uci_cfg->sr_positive_present > 0 && uci_cfg->o_ack <= SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS &&
uci_cfg->nof_csi == 0) {
uint32_t sr_resource_id = uci_cfg->sr_resource_id;
if (sr_resource_id >= SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES) {
ERROR("SR resource ID (%d) exceeds the maximum ID (%d)", sr_resource_id, SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES);
return SRSLTE_ERROR;
}
if (!pucch_cfg->sr_resources[sr_resource_id].configured) {
ERROR("SR resource ID (%d) is not configured", sr_resource_id);
return SRSLTE_ERROR;
}
// Set PUCCH resource
*resource = pucch_cfg->sr_resources[sr_resource_id].resource;
// No more logic is required in this case
return SRSLTE_SUCCESS;
}
// Use format 2, 3 or 4 resource from higher layers
// - Irrelevant SR opportunities
// - More than 2 HARQ-ACK
// - No CSI report
if (uci_cfg->o_sr > 0 && uci_cfg->o_ack > SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS && uci_cfg->nof_csi == 0) {
return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch_resource_id, resource);
}
// Use format 2, 3 or 4 CSI report resource from higher layers
// - Irrelevant SR opportunities
// - No HARQ-ACK
// - Single periodic CSI report
if (uci_cfg->o_ack == 0 && uci_cfg->nof_csi == 1 && uci_cfg->csi[0].type == SRSLTE_CSI_REPORT_TYPE_PERIODIC) {
*resource = uci_cfg->csi[0].pucch_resource;
return SRSLTE_SUCCESS;
}
// If a UE does not have dedicated PUCCH resource configuration, provided by PUCCH-ResourceSet in PUCCH-Config,
// a PUCCH resource set is provided by pucch-ResourceCommon through an index to a row of Table 9.2.1-1 for size
// transmission of HARQ-ACK information on PUCCH in an initial UL BWP of N BWP PRBs.
@ -474,3 +516,11 @@ int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pucch_cfg,
}
return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch_resource_id, resource);
}
uint32_t srslte_ra_ul_nr_nof_sr_bits(uint32_t K)
{
if (K > 0) {
return (uint32_t)ceilf(log2f((float)K + 1.0f));
}
return 0;
}

@ -1127,10 +1127,6 @@ int srslte_ulsch_decode(srslte_sch_t* q,
uint32_t Q_prime_ri = (uint32_t)ret;
/*
if (cfg->uci_cfg.cqi.data_enable) {
printf("deinter_input: Qm=%d, nb_q=%d, nof_symb=%d, Q_prime_ri=%d\n", Qm, nb_q, cfg->grant.nof_symb, Q_prime_ri);
}*/
// Deinterleave data and CQI in ULSCH
ulsch_deinterleave(q_bits,
Qm,
@ -1257,13 +1253,8 @@ int srslte_ulsch_encode(srslte_sch_t* q,
}
Q_prime_cqi = (uint32_t)ret;
/*
if (Q_prime_cqi) {
printf("Encoding cqi Q=%d: ", Q_prime_cqi*Qm);
srslte_vec_fprint_b(stdout, q->temp_g_bits, Q_prime_cqi*Qm);
}*/
srslte_bit_pack_vector(q->temp_g_bits, g_bits, Q_prime_cqi * Qm);
// Reset the buffer because will be reused in ulsch_interleave
srslte_vec_u8_zero(q->temp_g_bits, Q_prime_cqi * Qm);
}

@ -21,6 +21,7 @@
#include "srslte/phy/common/phy_common.h"
#include "srslte/phy/common/sequence.h"
#include "srslte/phy/utils/vector.h"
#include <strings.h>
/**
@ -58,17 +59,108 @@ int srslte_sequence_pdcch(srslte_sequence_t* seq, uint32_t nslot, uint32_t cell_
/**
* 36.211 6.3.1
*/
static inline uint32_t sequence_pdsch_seed(uint16_t rnti, int q, uint32_t nslot, uint32_t cell_id)
{
return (rnti << 14) + (q << 13) + ((nslot / 2) << 9) + cell_id;
}
int srslte_sequence_pdsch(srslte_sequence_t* seq, uint16_t rnti, int q, uint32_t nslot, uint32_t cell_id, uint32_t len)
{
return srslte_sequence_LTE_pr(seq, len, (rnti << 14) + (q << 13) + ((nslot / 2) << 9) + cell_id);
return srslte_sequence_LTE_pr(seq, len, sequence_pdsch_seed(rnti, q, nslot, cell_id));
}
void srslte_sequence_pdsch_apply_pack(const uint8_t* in,
uint8_t* out,
uint16_t rnti,
int q,
uint32_t nslot,
uint32_t cell_id,
uint32_t len)
{
srslte_sequence_apply_packed(in, out, len, sequence_pdsch_seed(rnti, q, nslot, cell_id));
}
void srslte_sequence_pdsch_apply_f(const float* in,
float* out,
uint16_t rnti,
int q,
uint32_t nslot,
uint32_t cell_id,
uint32_t len)
{
srslte_sequence_apply_f(in, out, len, sequence_pdsch_seed(rnti, q, nslot, cell_id));
}
void srslte_sequence_pdsch_apply_s(const int16_t* in,
int16_t* out,
uint16_t rnti,
int q,
uint32_t nslot,
uint32_t cell_id,
uint32_t len)
{
srslte_sequence_apply_s(in, out, len, sequence_pdsch_seed(rnti, q, nslot, cell_id));
}
void srslte_sequence_pdsch_apply_c(const int8_t* in,
int8_t* out,
uint16_t rnti,
int q,
uint32_t nslot,
uint32_t cell_id,
uint32_t len)
{
srslte_sequence_apply_c(in, out, len, sequence_pdsch_seed(rnti, q, nslot, cell_id));
}
/**
* 36.211 5.3.1
*/
static inline uint32_t sequence_pusch_seed(uint16_t rnti, uint32_t nslot, uint32_t cell_id)
{
return (rnti << 14) + ((nslot / 2) << 9) + cell_id;
}
int srslte_sequence_pusch(srslte_sequence_t* seq, uint16_t rnti, uint32_t nslot, uint32_t cell_id, uint32_t len)
{
return srslte_sequence_LTE_pr(seq, len, (rnti << 14) + ((nslot / 2) << 9) + cell_id);
return srslte_sequence_LTE_pr(seq, len, sequence_pusch_seed(rnti, nslot, cell_id));
}
void srslte_sequence_pusch_apply_pack(const uint8_t* in,
uint8_t* out,
uint16_t rnti,
uint32_t nslot,
uint32_t cell_id,
uint32_t len)
{
srslte_sequence_apply_packed(in, out, len, sequence_pusch_seed(rnti, nslot, cell_id));
}
void srslte_sequence_pusch_apply_s(const int16_t* in,
int16_t* out,
uint16_t rnti,
uint32_t nslot,
uint32_t cell_id,
uint32_t len)
{
srslte_sequence_apply_s(in, out, len, sequence_pusch_seed(rnti, nslot, cell_id));
}
void srslte_sequence_pusch_gen_unpack(uint8_t* out, uint16_t rnti, uint32_t nslot, uint32_t cell_id, uint32_t len)
{
srslte_vec_u8_zero(out, len);
srslte_sequence_apply_bit(out, out, len, sequence_pusch_seed(rnti, nslot, cell_id));
}
void srslte_sequence_pusch_apply_c(const int8_t* in,
int8_t* out,
uint16_t rnti,
uint32_t nslot,
uint32_t cell_id,
uint32_t len)
{
srslte_sequence_apply_c(in, out, len, sequence_pusch_seed(rnti, nslot, cell_id));
}
/**

@ -145,8 +145,6 @@ int base_init()
return -1;
}
srslte_ue_dl_set_rnti(&ue_dl, rnti);
DEBUG("Memory init OK");
return 0;
}

@ -158,17 +158,15 @@ static int check_softbits(srslte_pdsch_t* pdsch_enb,
int ret = SRSLTE_SUCCESS;
if (!pdsch_ue->llr_is_8bit && !tb_cw_swap) {
// Generate sequence
srslte_sequence_pdsch(&pdsch_ue->tmp_seq,
// Scramble
srslte_sequence_pdsch_apply_c(pdsch_ue->e[tb],
pdsch_ue->e[tb],
rnti,
pdsch_cfg->grant.tb[tb].cw_idx,
2 * (sf_idx % 10),
cell.id,
pdsch_cfg->grant.tb[tb].nof_bits);
// Scramble
srslte_scrambling_s_offset(&pdsch_ue->tmp_seq, pdsch_ue->e[tb], 0, pdsch_cfg->grant.tb[tb].nof_bits);
int16_t* rx = pdsch_ue->e[tb];
uint8_t* rx_bytes = pdsch_ue->e[tb];
for (int i = 0, k = 0; i < pdsch_cfg->grant.tb[tb].nof_bits / 8; i++) {
@ -337,8 +335,6 @@ int main(int argc, char** argv)
pdsch_rx.llr_is_8bit = use_8_bit;
pdsch_rx.dl_sch.llr_is_8bit = use_8_bit;
srslte_pdsch_set_rnti(&pdsch_rx, rnti);
for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
softbuffers_rx[i] = calloc(sizeof(srslte_softbuffer_rx_t), 1);
if (!softbuffers_rx[i]) {
@ -384,8 +380,6 @@ int main(int argc, char** argv)
goto quit;
}
srslte_pdsch_set_rnti(&pdsch_tx, rnti);
for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
softbuffers_tx[i] = calloc(sizeof(srslte_softbuffer_tx_t), 1);
if (!softbuffers_tx[i]) {

@ -165,10 +165,6 @@ int main(int argc, char** argv)
ERROR("Error creating PDSCH object");
exit(-1);
}
if (srslte_pucch_set_rnti(&pucch_ue, 11)) {
ERROR("Error setting C-RNTI");
goto quit;
}
if (srslte_pucch_init_enb(&pucch_enb)) {
ERROR("Error creating PDSCH object");
exit(-1);
@ -177,10 +173,6 @@ int main(int argc, char** argv)
ERROR("Error creating PDSCH object");
exit(-1);
}
if (srslte_pucch_set_rnti(&pucch_enb, 11)) {
ERROR("Error setting C-RNTI");
goto quit;
}
if (srslte_refsignal_ul_set_cell(&dmrs, cell)) {
ERROR("Error creating PDSCH object");
exit(-1);

@ -245,8 +245,6 @@ int main(int argc, char** argv)
uint16_t rnti = 62;
dci.rnti = rnti;
cfg.rnti = rnti;
srslte_pusch_set_rnti(&pusch_tx, rnti);
srslte_pusch_set_rnti(&pusch_rx, rnti);
uint32_t nof_re = SRSLTE_NRE * cell.nof_prb * 2 * SRSLTE_CP_NSYMB(cell.cp);
sf_symbols = srslte_vec_cf_malloc(nof_re);

@ -22,6 +22,7 @@
#include "srslte/phy/phch/uci_nr.h"
#include "srslte/phy/fec/block/block.h"
#include "srslte/phy/fec/polar/polar_chanalloc.h"
#include "srslte/phy/phch/csi.h"
#include "srslte/phy/phch/uci_cfg.h"
#include "srslte/phy/utils/bit.h"
#include "srslte/phy/utils/vector.h"
@ -163,7 +164,8 @@ static int uci_nr_pack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_v
A += cfg->o_ack;
// Append SR bits
srslte_vec_u8_copy(&sequence[A], value->sr, cfg->o_sr);
uint8_t* bits = &sequence[A];
srslte_bit_unpack(value->sr, &bits, cfg->o_sr);
A += cfg->o_sr;
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
@ -174,7 +176,7 @@ static int uci_nr_pack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_v
return A;
}
static int uci_nr_unpack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const uint8_t* sequence, srslte_uci_value_nr_t* value)
static int uci_nr_unpack_ack_sr(const srslte_uci_cfg_nr_t* cfg, uint8_t* sequence, srslte_uci_value_nr_t* value)
{
int A = 0;
@ -183,7 +185,8 @@ static int uci_nr_unpack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const uint8_t* s
A += cfg->o_ack;
// Append SR bits
srslte_vec_u8_copy(value->sr, &sequence[A], cfg->o_sr);
uint8_t* bits = &sequence[A];
value->sr = srslte_bit_pack(&bits, cfg->o_sr);
A += cfg->o_sr;
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
@ -196,15 +199,16 @@ static int uci_nr_unpack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const uint8_t* s
static int uci_nr_A(const srslte_uci_cfg_nr_t* cfg)
{
int o_csi = srslte_csi_nof_bits(cfg->csi, cfg->nof_csi);
// 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation
if (cfg->o_csi1 == 0 && cfg->o_csi2 == 0) {
if (o_csi == 0) {
return cfg->o_ack + cfg->o_sr;
}
// 6.3.1.1.2 CSI only
if (cfg->o_ack == 0 && cfg->o_sr == 0) {
ERROR("CSI only are not implemented");
return SRSLTE_ERROR;
return o_csi;
}
// 6.3.1.1.3 HARQ-ACK/SR and CSI
@ -214,15 +218,16 @@ static int uci_nr_A(const srslte_uci_cfg_nr_t* cfg)
static int uci_nr_packing(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_value_nr_t* value, uint8_t* sequence)
{
int o_csi = srslte_csi_nof_bits(cfg->csi, cfg->nof_csi);
// 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation
if (cfg->o_csi1 == 0 && cfg->o_csi2 == 0) {
if (o_csi == 0) {
return uci_nr_pack_ack_sr(cfg, value, sequence);
}
// 6.3.1.1.2 CSI only
if (cfg->o_ack == 0 && cfg->o_sr == 0) {
ERROR("CSI only are not implemented");
return SRSLTE_ERROR;
return srslte_csi_part1_pack(cfg->csi, value->csi, cfg->nof_csi, sequence, SRSLTE_UCI_NR_MAX_NOF_BITS);
}
// 6.3.1.1.3 HARQ-ACK/SR and CSI
@ -230,10 +235,12 @@ static int uci_nr_packing(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_value
return SRSLTE_ERROR;
}
static int uci_nr_unpacking(const srslte_uci_cfg_nr_t* cfg, const uint8_t* sequence, srslte_uci_value_nr_t* value)
static int uci_nr_unpacking(const srslte_uci_cfg_nr_t* cfg, uint8_t* sequence, srslte_uci_value_nr_t* value)
{
int o_csi = srslte_csi_nof_bits(cfg->csi, cfg->nof_csi);
// 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation
if (cfg->o_csi1 == 0 && cfg->o_csi2 == 0) {
if (o_csi == 0) {
return uci_nr_unpack_ack_sr(cfg, sequence, value);
}
@ -746,10 +753,10 @@ int srslte_uci_nr_pucch_format_2_3_4_E(const srslte_pucch_nr_resource_t* resourc
static int
uci_nr_pucch_E_uci(const srslte_pucch_nr_resource_t* pucch_cfg, const srslte_uci_cfg_nr_t* uci_cfg, uint32_t E_tot)
{
if (uci_cfg->o_csi1 != 0 && uci_cfg->o_csi2) {
ERROR("Simultaneous CSI part 1 and CSI part 2 is not implemented");
return SRSLTE_ERROR;
}
// if (uci_cfg->o_csi1 != 0 && uci_cfg->o_csi2) {
// ERROR("Simultaneous CSI part 1 and CSI part 2 is not implemented");
// return SRSLTE_ERROR;
// }
return E_tot;
}
@ -800,7 +807,7 @@ uint32_t srslte_uci_nr_total_bits(const srslte_uci_cfg_nr_t* uci_cfg)
return 0;
}
return uci_cfg->o_ack + uci_cfg->o_csi1 + uci_cfg->o_csi2 + uci_cfg->o_sr;
return uci_cfg->o_ack + uci_cfg->o_sr + srslte_csi_nof_bits(uci_cfg->csi, uci_cfg->nof_csi);
}
uint32_t srslte_uci_nr_info(const srslte_uci_data_nr_t* uci_data, char* str, uint32_t str_len)
@ -815,22 +822,12 @@ uint32_t srslte_uci_nr_info(const srslte_uci_data_nr_t* uci_data, char* str, uin
len = srslte_print_check(str, str_len, len, ", ack=%s", str2);
}
if (uci_data->cfg.o_csi1 > 0) {
char str2[10];
srslte_vec_sprint_bin(str2, 10, uci_data->value.csi1, uci_data->cfg.o_csi1);
len = srslte_print_check(str, str_len, len, ", csi1=%s", str2);
}
if (uci_data->cfg.o_csi2 > 0) {
char str2[10];
srslte_vec_sprint_bin(str2, 10, uci_data->value.csi2, uci_data->cfg.o_csi2);
len = srslte_print_check(str, str_len, len, ", csi2=%s", str2);
if (uci_data->cfg.nof_csi > 0) {
len += srslte_csi_str(uci_data->cfg.csi, uci_data->value.csi, uci_data->cfg.nof_csi, &str[len], str_len - len);
}
if (uci_data->cfg.o_sr > 0) {
char str2[10];
srslte_vec_sprint_bin(str2, 10, uci_data->value.sr, uci_data->cfg.o_sr);
len = srslte_print_check(str, str_len, len, ", sr=%s", str2);
len = srslte_print_check(str, str_len, len, ", sr=%d", uci_data->value.sr);
}
return len;

@ -54,7 +54,7 @@ int rf_zmq_tx_open(rf_zmq_tx_t* q, rf_zmq_opts_t opts, void* zmq_ctx, char* sock
ret = zmq_bind(q->sock, sock_args);
if (ret) {
fprintf(stderr, "Error: connecting transmitter socket: %s\n", zmq_strerror(zmq_errno()));
fprintf(stderr, "Error: binding transmitter socket (%s): %s\n", sock_args, zmq_strerror(zmq_errno()));
goto clean_exit;
}

@ -76,7 +76,6 @@ int srslte_ue_dl_init(srslte_ue_dl_t* q, cf_t* in_buffer[SRSLTE_MAX_PORTS], uint
q->nof_rx_antennas = nof_rx_antennas;
q->mi_auto = true;
q->mi_manual_index = 0;
q->pregen_rnti = 0;
for (int j = 0; j < SRSLTE_MAX_PORTS; j++) {
q->sf_symbols[j] = srslte_vec_cf_malloc(MAX_SFLEN_RE);
@ -249,9 +248,6 @@ int srslte_ue_dl_set_cell(srslte_ue_dl_t* q, srslte_cell_t cell)
return SRSLTE_ERROR;
}
}
if (q->pregen_rnti) {
srslte_ue_dl_set_rnti(q, q->pregen_rnti);
}
ret = SRSLTE_SUCCESS;
} else {
ERROR("Invalid cell properties ue_dl: Id=%d, Ports=%d, PRBs=%d", cell.id, cell.nof_ports, cell.nof_prb);
@ -275,34 +271,6 @@ void srslte_ue_dl_set_mi_manual(srslte_ue_dl_t* q, uint32_t mi_idx)
q->mi_manual_index = mi_idx;
}
/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while
* to execute, so shall be called once the final C-RNTI has been allocated for the session.
* For the connection procedure, use srslte_pusch_encode_rnti() or srslte_pusch_decode_rnti() functions
*/
void srslte_ue_dl_set_rnti(srslte_ue_dl_t* q, uint16_t rnti)
{
srslte_pdsch_set_rnti(&q->pdsch, rnti);
srslte_dl_sf_cfg_t sf_cfg;
ZERO_OBJECT(sf_cfg);
// Compute UE-specific and Common search space for this RNTI
for (int i = 0; i < SRSLTE_MI_NOF_REGS; i++) {
srslte_pdcch_set_regs(&q->pdcch, &q->regs[i]);
for (int cfi = 1; cfi <= SRSLTE_NOF_CFI; cfi++) {
sf_cfg.cfi = cfi;
for (int sf_idx = 0; sf_idx < SRSLTE_NOF_SF_X_FRAME; sf_idx++) {
sf_cfg.tti = sf_idx;
q->current_ss_ue[i][SRSLTE_CFI_IDX(cfi)][sf_idx].nof_locations = srslte_pdcch_ue_locations(
&q->pdcch, &sf_cfg, q->current_ss_ue[i][SRSLTE_CFI_IDX(cfi)][sf_idx].loc, SRSLTE_MAX_CANDIDATES_UE, rnti);
}
q->current_ss_common[i][SRSLTE_CFI_IDX(cfi)].nof_locations = srslte_pdcch_common_locations(
&q->pdcch, q->current_ss_common[i][SRSLTE_CFI_IDX(cfi)].loc, SRSLTE_MAX_CANDIDATES_COM, cfi);
}
}
q->pregen_rnti = rnti;
}
/* Set the area ID on pmch and chest_dl to generate scrambling sequence and reference
* signals.
*/
@ -486,9 +454,6 @@ static int dci_blind_search(srslte_ue_dl_t* q,
// Look for the messages found and apply the new format if the location is common
if (search_in_common && (dci_cfg->multiple_csi_request_enabled || dci_cfg->srs_request_enabled)) {
uint32_t sf_idx = sf->tti % 10;
uint32_t cfi = sf->cfi;
/*
* A UE configured to monitor PDCCH candidates whose CRCs are scrambled with C-RNTI or SPS C-RNTI,
* with a common payload size and with the same first CCE index ncce, but with different sets of DCI
@ -496,9 +461,8 @@ static int dci_blind_search(srslte_ue_dl_t* q,
* that only the PDCCH in the common search space is transmitted by the primary cell.
*/
// Find a matching ncce in the common SS
if (srslte_location_find_ncce(q->current_ss_common[MI_IDX(sf_idx)][cfi - 1].loc,
q->current_ss_common[MI_IDX(sf_idx)][cfi - 1].nof_locations,
dci_msg[nof_dci].location.ncce)) {
if (srslte_location_find_ncce(
q->current_ss_common.loc, q->current_ss_common.nof_locations, dci_msg[nof_dci].location.ncce)) {
srslte_dci_cfg_t cfg = *dci_cfg;
srslte_dci_cfg_set_common_ss(&cfg);
// if the payload size is the same that it would have in the common SS (only Format0/1A is allowed there)
@ -557,9 +521,7 @@ static int find_dci_ss(srslte_ue_dl_t* q,
bool is_ue)
{
dci_blind_search_t search_space = {};
dci_blind_search_t* current_ss = &search_space;
uint32_t sf_idx = sf->tti % SRSLTE_NOF_SF_X_FRAME;
uint32_t cfi = sf->cfi;
srslte_dci_cfg_t dci_cfg = cfg->cfg.dci;
@ -568,39 +530,31 @@ static int find_dci_ss(srslte_ue_dl_t* q,
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Generate Common Search space
q->current_ss_common.nof_locations =
srslte_pdcch_common_locations(&q->pdcch, q->current_ss_common.loc, SRSLTE_MAX_CANDIDATES_COM, cfi);
// Generate Search Space
if (is_ue) {
if (q->pregen_rnti == rnti) {
current_ss = &q->current_ss_ue[MI_IDX(sf_idx)][SRSLTE_CFI_IDX(cfi)][sf_idx];
} else {
// If locations are not pre-generated, generate them now
current_ss->nof_locations =
srslte_pdcch_ue_locations(&q->pdcch, sf, current_ss->loc, SRSLTE_MAX_CANDIDATES_UE, rnti);
}
search_space.nof_locations =
srslte_pdcch_ue_locations(&q->pdcch, sf, search_space.loc, SRSLTE_MAX_CANDIDATES_UE, rnti);
} else {
// Disable extended CSI request and SRS request in common SS
srslte_dci_cfg_set_common_ss(&dci_cfg);
if (q->pregen_rnti == rnti) {
current_ss = &q->current_ss_common[MI_IDX(sf_idx)][SRSLTE_CFI_IDX(cfi)];
} else {
// If locations are not pre-generated, generate them now
current_ss->nof_locations =
srslte_pdcch_common_locations(&q->pdcch, current_ss->loc, SRSLTE_MAX_CANDIDATES_COM, cfi);
}
search_space = q->current_ss_common;
}
// Search for DCI in the SS
current_ss->nof_formats = nof_formats;
memcpy(current_ss->formats, formats, nof_formats * sizeof(srslte_dci_format_t));
search_space.nof_formats = nof_formats;
memcpy(search_space.formats, formats, nof_formats * sizeof(srslte_dci_format_t));
INFO("Searching %d formats in %d locations in %s SS, csi=%d",
nof_formats,
current_ss->nof_locations,
search_space.nof_locations,
is_ue ? "ue" : "common",
dci_cfg.multiple_csi_request_enabled);
return dci_blind_search(q, sf, rnti, current_ss, &dci_cfg, dci_msg, cfg->cfg.dci_common_ss);
return dci_blind_search(q, sf, rnti, &search_space, &dci_cfg, dci_msg, cfg->cfg.dci_common_ss);
}
/*

@ -174,17 +174,6 @@ int srslte_ue_ul_set_cell(srslte_ue_ul_t* q, srslte_cell_t cell)
return ret;
}
/* Precalculate the PUSCH scramble sequences for a given RNTI. This function takes a while
* to execute, so shall be called once the final C-RNTI has been allocated for the session.
* For the connection procedure, use srslte_pusch_encode_rnti() or srslte_pusch_decode_rnti() functions
*/
void srslte_ue_ul_set_rnti(srslte_ue_ul_t* q, uint16_t rnti)
{
srslte_pusch_set_rnti(&q->pusch, rnti);
srslte_pucch_set_rnti(&q->pucch, rnti);
q->current_rnti = rnti;
}
int srslte_ue_ul_pregen_signals(srslte_ue_ul_t* q, srslte_ue_ul_cfg_t* cfg)
{
if (q->signals_pregenerated) {
@ -634,7 +623,8 @@ int srslte_ue_ul_encode(srslte_ue_ul_t* q, srslte_ul_sf_cfg_t* sf, srslte_ue_ul_
} else if ((uci_pending(cfg->ul_cfg.pucch.uci_cfg) || data->uci.scheduling_request) &&
cfg->cc_idx == 0) { // Send PUCCH over PCell only
if (!cfg->ul_cfg.pucch.rnti) {
cfg->ul_cfg.pucch.rnti = q->current_rnti;
ERROR("Encoding PUCCH: rnti not set in ul_cfg\n");
return SRSLTE_ERROR;
}
ret = pucch_encode(q, sf, cfg, &data->uci) ? -1 : 1;
} else if (srs_tx_enabled(&cfg->ul_cfg.srs, sf->tti)) {

@ -148,8 +148,20 @@ static int ue_ul_nr_encode_pucch_format1(srslte_ue_ul_nr_t* q,
const srslte_uci_data_nr_t* uci_data)
{
uint8_t b[SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS] = {};
b[0] = uci_data->value.ack[0];
uint32_t nof_bits = 1;
// Set ACK bits
uint32_t nof_bits = SRSLTE_MIN(SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS, uci_data->cfg.o_ack);
for (uint32_t i = 0; i < nof_bits; i++) {
b[i] = uci_data->value.ack[i];
}
// Set SR bits
// For a positive SR transmission using PUCCH format 1, the UE transmits the PUCCH as described in [4, TS
// 38.211] by setting b ( 0 ) = 0 .
if (nof_bits == 0 && uci_data->cfg.o_sr > 0 && uci_data->value.sr > 0) {
b[0] = 0;
nof_bits = 1;
}
if (srslte_dmrs_pucch_format1_put(&q->pucch, &q->carrier, cfg, slot, resource, q->sf_symbols[0])) {
return SRSLTE_ERROR;
@ -247,3 +259,36 @@ int srslte_ue_ul_nr_pucch_info(const srslte_pucch_nr_resource_t* resource,
return len;
}
int srslte_ue_ul_nr_sr_send_slot(const srslte_pucch_nr_sr_resource_t sr_resources[SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES],
uint32_t slot_idx,
uint32_t sr_resource_id[SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES])
{
int count = 0;
// Check inputs
if (sr_resources == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Iterate over all SR resources
for (uint32_t i = 0; i < SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES; i++) {
const srslte_pucch_nr_sr_resource_t* res = &sr_resources[i];
// Skip if resource is not provided
if (!res->configured) {
continue;
}
// Check periodicity and offset condition
if ((slot_idx + res->period - res->offset) % res->period == 0) {
if (sr_resource_id != NULL) {
sr_resource_id[count] = i;
}
count++;
}
}
// If the program reached this point is because there is no SR transmission opportunity
return count;
}

@ -205,6 +205,11 @@ void srslte_vec_u8_zero(uint8_t* ptr, uint32_t nsamples)
SRSLTE_MEM_ZERO(ptr, uint8_t, nsamples);
}
void srslte_vec_i8_zero(int8_t* ptr, uint32_t nsamples)
{
SRSLTE_MEM_ZERO(ptr, int8_t, nsamples);
}
void srslte_vec_i16_zero(int16_t* ptr, uint32_t nsamples)
{
SRSLTE_MEM_ZERO(ptr, int16_t, nsamples);

@ -0,0 +1,15 @@
#
# 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.
#
set(SOURCES
sys_metrics_processor.cc)
find_package(Threads REQUIRED)
add_library(system STATIC ${SOURCES})
target_link_libraries(system "${CMAKE_THREAD_LIBS_INIT}")

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

Loading…
Cancel
Save