Refactor in eNodeB, add channel emulator and fixes in OFDM

* Added channel emulator to srsENB. Added support for fixed delay

* Bug in OFDM when using nonguru mode

* A few changes and refactor in eNodeB
master
Ismael Gomez 5 years ago committed by GitHub
parent 8980810061
commit 3828e03f33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -46,13 +46,14 @@
#define MSG3_DELAY_MS 2 // Delay added to TX_DELAY
#define TTI_SUB(a, b) ((((a) + 10240) - (b)) % 10240)
#define TTI_ADD(a, b) (((a) + (b)) % 10240)
#define TTI_TX(tti) ((tti + TX_DELAY) % 10240)
#define TTI_TX(tti) TTI_ADD(tti, TX_DELAY)
// Use only in FDD mode!!
#define FDD_HARQ_DELAY_MS 4
#define TTI_RX(tti) (TTI_SUB(tti, FDD_HARQ_DELAY_MS))
#define TTI_RX_ACK(tti) ((tti + (2 * FDD_HARQ_DELAY_MS)) % 10240)
#define TTI_RX_ACK(tti) (TTI_ADD(tti, FDD_HARQ_DELAY_MS + TX_DELAY))
#define TTIMOD_SZ 20
#define TTIMOD(tti) (tti%TTIMOD_SZ)

@ -55,6 +55,7 @@ public:
int pusch_mcs;
int pusch_max_mcs;
int nof_ctrl_symbols;
int max_aggr_level;
} sched_args_t;
@ -72,6 +73,7 @@ public:
/* prach configuration */
uint32_t prach_config;
uint32_t prach_nof_preambles;
uint32_t prach_freq_offset;
uint32_t prach_rar_window;
uint32_t prach_contention_resolution_timer;
@ -156,7 +158,15 @@ public:
} ul_sched_data_t;
typedef struct {
uint32_t ra_id;
uint32_t preamble_idx;
uint32_t ta_cmd;
uint16_t temp_crnti;
uint32_t msg3_size;
uint32_t prach_tti;
} dl_sched_rar_info_t;
typedef struct {
dl_sched_rar_info_t data;
srslte_dci_rar_grant_t grant;
} dl_sched_rar_grant_t;
@ -229,7 +239,7 @@ public:
/* DL information */
virtual int dl_ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack) = 0;
virtual int dl_rach_info(uint32_t tti, uint32_t ra_id, uint16_t rnti, uint32_t estimated_size) = 0;
virtual int dl_rach_info(dl_sched_rar_info_t rar_info) = 0;
virtual int dl_ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value) = 0;
virtual int dl_pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value) = 0;
virtual int dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) = 0;

@ -43,7 +43,6 @@ typedef struct {
typedef struct SRSLTE_API {
bool is_from_rar;
uint32_t L_prb;
uint32_t n_prb[2]; // rb_start after frequency hopping
uint32_t n_prb_tilde[2]; // rb_start after frequency hopping per retx

@ -25,6 +25,7 @@
static inline double calculate_delay_us(srslte_channel_delay_t* q, const srslte_timestamp_t* ts)
{
if (q->period_s) {
// Convert period from seconds to samples
uint64_t period_nsamples = (uint64_t)roundf(q->period_s * q->srate_hz);
@ -39,6 +40,9 @@ static inline double calculate_delay_us(srslte_channel_delay_t* q, const srslte_
double delay_us = q->delay_min_us + (q->delay_max_us - q->delay_min_us) * (1.0 + sin(arg)) / 2.0;
return delay_us;
} else {
return q->delay_max_us;
}
}
static inline uint32_t calculate_delay_nsamples(srslte_channel_delay_t* q)

@ -459,8 +459,7 @@ void srslte_ofdm_rx_sf(srslte_ofdm_t *q) {
for (n=0;n<2;n++) {
srslte_ofdm_rx_slot(q, n);
}
}
else{
} else {
srslte_ofdm_rx_slot_mbsfn(q, &q->in_buffer[0*q->slot_sz], &q->out_buffer[0*q->nof_re*q->nof_symbols]);
srslte_ofdm_rx_slot(q, 1);
}
@ -469,14 +468,13 @@ void srslte_ofdm_rx_sf(srslte_ofdm_t *q) {
void srslte_ofdm_rx_sf_ng(srslte_ofdm_t *q, cf_t *input, cf_t *output) {
uint32_t n;
if (q->freq_shift) {
srslte_vec_prod_ccc(q->in_buffer, q->shift_buffer, q->in_buffer, 2*q->slot_sz);
srslte_vec_prod_ccc(input, q->shift_buffer, input, 2*q->slot_sz);
}
if (!q->mbsfn_subframe) {
for (n=0;n<2;n++) {
srslte_ofdm_rx_slot_ng(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]);
}
}
else{
} else {
srslte_ofdm_rx_slot_mbsfn(q, &q->in_buffer[0*q->slot_sz], &q->out_buffer[0*q->nof_re*q->nof_symbols]);
srslte_ofdm_rx_slot(q, 1);
}

@ -136,6 +136,7 @@ enable = false
#####################################################################
# Scheduler configuration options
#
# max_aggr_level: Optional maximum aggregation level index (l=log2(L) can be 0, 1, 2 or 3)
# pdsch_mcs: Optional fixed PDSCH MCS (ignores reported CQIs if specified)
# pdsch_max_mcs: Optional PDSCH MCS limit
# pusch_mcs: Optional fixed PUSCH MCS (ignores reported CQIs if specified)
@ -144,6 +145,7 @@ enable = false
#
#####################################################################
[scheduler]
#max_aggr_level = -1
#pdsch_mcs = -1
#pdsch_max_mcs = -1
#pusch_mcs = -1
@ -162,6 +164,86 @@ nof_ctrl_symbols = 3
#m1u_multiaddr = 239.255.0.1
#m1u_if_addr = 127.0.1.201
#####################################################################
# Channel emulator options:
# enable: Enable/Disable internal Downlink/Uplink channel emulator
#
# -- Fading emulator
# fading.enable: Enable/disable fading simulator
# fading.model: Fading model + maximum doppler (E.g. none, epa5, eva70, etu300, etc)
#
# -- Delay Emulator delay(t) = delay_min + (delay_max - delay_min) * (1 + sin(2pi*t/period)) / 2
# Maximum speed [m/s]: (delay_max - delay_min) * pi * 300 / period
# delay.enable: Enable/disable delay simulator
# delay.period_s: Delay period in seconds.
# delay.init_time_s: Delay initial time in seconds.
# delay.maximum_us: Maximum delay in microseconds
# delay.minumum_us: Minimum delay in microseconds
#
# -- Radio-Link Failure (RLF) Emulator
# rlf.enable: Enable/disable RLF simulator
# rlf.t_on_ms: Time for On state of the channel (ms)
# rlf.t_off_ms: Time for Off state of the channel (ms)
#
# -- High Speed Train Doppler model simulator
# hst.enable: Enable/Disable HST simulator
# hst.period_s: HST simulation period in seconds
# hst.fd_hz: Doppler frequency in Hz
# hst.init_time_s: Initial time in seconds
#####################################################################
[channel.dl]
#enable = false
[channel.dl.fading]
#enable = false
#model = none
[channel.dl.delay]
#enable = false
#period_s = 3600
#init_time_s = 0
#maximum_us = 100
#minimum_us = 10
[channel.dl.rlf]
#enable = false
#t_on_ms = 10000
#t_off_ms = 2000
[channel.dl.hst]
#enable = false
#period_s = 7.2
#fd_hz = 750.0
#init_time_s = 0.0
[channel.ul]
#enable = false
[channel.ul.fading]
#enable = false
#model = none
[channel.ul.delay]
#enable = false
#period_s = 3600
#init_time_s = 0
#maximum_us = 100
#minimum_us = 10
[channel.ul.rlf]
#enable = false
#t_on_ms = 10000
#t_off_ms = 2000
[channel.ul.hst]
#enable = false
#period_s = 7.2
#fd_hz = -750.0
#init_time_s = 0.0
#####################################################################
# Expert configuration options
#

@ -27,6 +27,7 @@
#include "srslte/common/log.h"
#include "srslte/common/thread_pool.h"
#include "srslte/common/threads.h"
#include "srslte/phy/channel/channel.h"
#include "srslte/interfaces/common_interfaces.h"
#include "srslte/interfaces/enb_interfaces.h"
#include "srslte/interfaces/enb_metrics_interface.h"
@ -51,6 +52,9 @@ typedef struct {
std::string equalizer_mode;
float estimator_fil_w;
bool pregenerate_signals;
srslte::channel::args_t dl_channel_args;
srslte::channel::args_t ul_channel_args;
} phy_args_t;
class phy_common
@ -79,6 +83,7 @@ public:
srslte::radio_interface_phy* radio = nullptr;
stack_interface_phy_lte* stack = nullptr;
srslte::channel_ptr dl_channel = nullptr;
// Common objects for schedulign grants
stack_interface_phy_lte::ul_sched_t ul_grants[TTIMOD_SZ] = {};

@ -75,6 +75,7 @@ private:
std::vector<std::unique_ptr<cc_worker> > cc_workers;
srslte_softbuffer_tx_t temp_mbsfn_softbuffer = {};
};
} // namespace srsenb

@ -28,6 +28,7 @@
#include "srslte/common/thread_pool.h"
#include "srslte/common/threads.h"
#include "srslte/radio/radio.h"
#include "srslte/phy/channel/channel.h"
namespace srsenb {
@ -53,6 +54,7 @@ private:
srslte::thread_pool* workers_pool = nullptr;
prach_worker* prach = nullptr;
phy_common* worker_com = nullptr;
srslte::channel_ptr ul_channel = nullptr;
// Main system TTI counter
uint32_t tti = 0;

@ -136,7 +136,6 @@ private:
srslte_cell_t cell;
mac_args_t args;
uint32_t tti;
bool started;
/* Scheduler unit */
@ -153,22 +152,13 @@ private:
std::map<uint16_t, ue*> ue_db;
uint16_t last_rnti;
uint8_t* assemble_rar(sched_interface::dl_sched_rar_grant_t *grants, uint32_t nof_grants, int rar_idx, uint32_t pdu_len);
uint8_t* assemble_rar(sched_interface::dl_sched_rar_grant_t *grants, uint32_t nof_grants, int rar_idx, uint32_t pdu_len, uint32_t tti);
uint8_t* assemble_si(uint32_t index);
const static int rar_payload_len = 128;
std::vector<srslte::rar_pdu> rar_pdu_msg;
srslte::byte_buffer_t rar_payload[sched_interface::MAX_RAR_LIST];
typedef struct {
uint32_t preamble_idx;
uint32_t ta_cmd;
uint16_t temp_crnti;
} pending_rar_t;
const static int MAX_PENDING_RARS = 64;
pending_rar_t pending_rars[MAX_PENDING_RARS];
const static int NOF_BCCH_DLSCH_MSG=sched_interface::MAX_SIBS;
uint8_t bcch_dlsch_payload[sched_interface::MAX_SIB_PAYLOAD_LEN];
@ -199,13 +189,14 @@ private:
/* Class to run upper-layer timers with normal priority */
class timer_thread : public thread {
public:
timer_thread(srslte::timers* t) : ttisync(10240), timers(t), running(false), thread("MAC_TIMER") { start(); }
timer_thread(mac* parent_, srslte::timers* t) : ttisync(10240), timers(t), running(false), parent(parent_), thread("MAC_TIMER") { start(); }
void tti_clock();
void stop();
private:
void run_thread();
srslte::tti_sync_cv ttisync;
srslte::timers *timers;
mac *parent;
bool running;
};
timer_thread timers_thread;

@ -30,6 +30,7 @@
#include "srslte/interfaces/sched_interface.h"
#include <map>
#include <mutex>
#include <queue>
#include <pthread.h>
namespace srsenb {
@ -108,6 +109,7 @@ public:
int ue_cfg(uint16_t rnti, ue_cfg_t *ue_cfg);
int ue_rem(uint16_t rnti);
bool ue_exists(uint16_t rnti);
void ue_needs_ta_cmd(uint16_t rnti, uint32_t nof_ta_cmd);
void phy_config_enabled(uint16_t rnti, bool enabled);
@ -122,7 +124,7 @@ public:
int dl_ant_info(uint16_t rnti, asn1::rrc::phys_cfg_ded_s::ant_info_c_* dedicated);
int dl_ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack);
int dl_rach_info(uint32_t tti, uint32_t ra_id, uint16_t rnti, uint32_t estimated_size);
int dl_rach_info(dl_sched_rar_info_t rar_info);
int dl_ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value);
int dl_pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value);
int dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value);
@ -167,13 +169,6 @@ protected:
// This is for computing DCI locations
srslte_regs_t regs;
typedef struct {
int buf_rar;
uint16_t rnti;
uint32_t ra_id;
uint32_t rar_tti;
} sched_rar_t;
typedef struct {
bool is_in_window;
uint32_t window_start;
@ -230,7 +225,7 @@ protected:
void new_tti(uint32_t tti_rx_, uint32_t start_cfi);
alloc_outcome_t alloc_bc(uint32_t aggr_lvl, uint32_t sib_idx, uint32_t sib_ntx);
alloc_outcome_t alloc_paging(uint32_t aggr_lvl, uint32_t paging_payload);
rar_code_t alloc_rar(uint32_t aggr_lvl, const dl_sched_rar_t& rar_grant, uint32_t rar_tti, uint32_t buf_rar);
rar_code_t alloc_rar(uint32_t aggr_lvl, const dl_sched_rar_t& rar_grant, uint32_t prach_tti, uint32_t buf_rar);
void generate_dcis();
// dl_tti_sched itf
alloc_outcome_t alloc_dl_user(sched_ue* user, const rbgmask_t& user_mask, uint32_t pid) final;
@ -307,9 +302,8 @@ protected:
uint32_t mcs;
} pending_msg3_t;
const static int SCHED_MAX_PENDING_RAR = 8;
sched_rar_t pending_rar[SCHED_MAX_PENDING_RAR];
pending_msg3_t pending_msg3[10];
std::queue<dl_sched_rar_info_t> pending_rars;
pending_msg3_t pending_msg3[TTIMOD_SZ];
// Allowed DCI locations for SIB and RAR per CFI
sched_ue::sched_dci_cce_t common_locations[3];

@ -83,7 +83,7 @@ public:
void tpc_inc();
void tpc_dec();
void set_max_mcs(int mcs_ul, int mcs_dl);
void set_max_mcs(int mcs_ul, int mcs_dl, int max_aggr_level = -1);
void set_fixed_mcs(int mcs_ul, int mcs_dl);
dl_harq_proc* find_dl_harq(uint32_t tti);
@ -117,6 +117,8 @@ public:
void set_sr();
void unset_sr();
void set_needs_ta_cmd(uint32_t nof_ta_cmd);
int generate_format1(
dl_harq_proc* h, sched_interface::dl_sched_data_t* data, uint32_t tti, uint32_t cfi, const rbgmask_t& user_mask);
int generate_format2a(
@ -198,12 +200,15 @@ private:
uint32_t ul_cqi_tti;
uint16_t rnti;
uint32_t max_mcs_dl;
uint32_t max_aggr_level;
uint32_t max_mcs_ul;
uint32_t max_msg3retx;
int fixed_mcs_ul;
int fixed_mcs_dl;
uint32_t P;
uint32_t nof_ta_cmd;
int next_tpc_pusch;
int next_tpc_pucch;

@ -26,9 +26,11 @@
#include "srslte/common/pdu.h"
#include "srslte/common/mac_pcap.h"
#include "srslte/common/pdu_queue.h"
#include "srslte/common/block_queue.h"
#include "srslte/interfaces/enb_interfaces.h"
#include "srslte/interfaces/sched_interface.h"
#include <pthread.h>
#include <vector>
#include "mac_metrics.h"
namespace srsenb {
@ -42,7 +44,9 @@ public:
sched_interface* sched,
rrc_interface_mac* rrc_,
rlc_interface_mac* rlc,
srslte::log* log_);
srslte::log* log_,
uint32_t nof_rx_harq_proc = SRSLTE_FDD_NOF_HARQ,
uint32_t nof_tx_harq_proc = SRSLTE_FDD_NOF_HARQ * SRSLTE_MAX_TB);
virtual ~ue();
void reset();
@ -51,6 +55,8 @@ public:
void set_tti(uint32_t tti);
uint32_t set_ta(int ta);
void config(uint16_t rnti, uint32_t nof_prb, sched_interface *sched, rrc_interface_mac *rrc_, rlc_interface_mac *rlc, srslte::log *log_h);
uint8_t* generate_pdu(uint32_t harq_pid,
uint32_t tb_idx,
@ -108,12 +114,13 @@ private:
uint32_t nof_failures = 0;
const static int NOF_RX_HARQ_PROCESSES = SRSLTE_FDD_NOF_HARQ;
const static int NOF_TX_HARQ_PROCESSES = SRSLTE_FDD_NOF_HARQ * SRSLTE_MAX_TB;
srslte_softbuffer_tx_t softbuffer_tx[NOF_TX_HARQ_PROCESSES];
srslte_softbuffer_rx_t softbuffer_rx[NOF_RX_HARQ_PROCESSES];
srslte::block_queue<uint32_t> pending_ta_commands;
uint8_t* pending_buffers[NOF_RX_HARQ_PROCESSES] = {nullptr};
int nof_rx_harq_proc = 0;
int nof_tx_harq_proc = 0;
std::vector<srslte_softbuffer_tx_t> softbuffer_tx;
std::vector<srslte_softbuffer_rx_t> softbuffer_rx;
std::vector<uint8_t*> pending_buffers;
// For DL there are two buffers, one for each Transport block
srslte::byte_buffer_t tx_payload_buffer[SRSLTE_FDD_NOF_HARQ][SRSLTE_MAX_TB];

@ -130,8 +130,44 @@ void parse_args(all_args_t *args, int argc, char* argv[]) {
("scheduler.pdsch_max_mcs", bpo::value<int>(&args->stack.mac.sched.pdsch_max_mcs)->default_value(-1), "Optional PDSCH MCS limit")
("scheduler.pusch_mcs", bpo::value<int>(&args->stack.mac.sched.pusch_mcs)->default_value(-1), "Optional fixed PUSCH MCS (ignores reported CQIs if specified)")
("scheduler.pusch_max_mcs", bpo::value<int>(&args->stack.mac.sched.pusch_max_mcs)->default_value(-1), "Optional PUSCH MCS limit")
("scheduler.max_aggr_level", bpo::value<int>(&args->stack.mac.sched.max_aggr_level)->default_value(-1), "Optional maximum aggregation level index (l=log2(L)) ")
("scheduler.nof_ctrl_symbols", bpo::value<int>(&args->stack.mac.sched.nof_ctrl_symbols)->default_value(3), "Number of control symbols")
/* Downlink Channel emulator section */
("channel.dl.enable", bpo::value<bool>(&args->phy.dl_channel_args.enable)->default_value(false), "Enable/Disable internal Downlink channel emulator")
("channel.dl.fading.enable", bpo::value<bool>(&args->phy.dl_channel_args.fading_enable)->default_value(false), "Enable/Disable Fading model")
("channel.dl.fading.model", bpo::value<std::string>(&args->phy.dl_channel_args.fading_model)->default_value("none"), "Fading model + maximum doppler (E.g. none, epa5, eva70, etu300, etc)")
("channel.dl.delay.enable", bpo::value<bool>(&args->phy.dl_channel_args.delay_enable)->default_value(false), "Enable/Disable Delay simulator")
("channel.dl.delay.period_s", bpo::value<float>(&args->phy.dl_channel_args.delay_period_s)->default_value(3600), "Delay period in seconds (integer)")
("channel.dl.delay.init_time_s", bpo::value<float>(&args->phy.dl_channel_args.delay_init_time_s)->default_value(0), "Initial time in seconds")
("channel.dl.delay.maximum_us", bpo::value<float>(&args->phy.dl_channel_args.delay_max_us)->default_value(100.0f), "Maximum delay in microseconds")
("channel.dl.delay.minimum_us", bpo::value<float>(&args->phy.dl_channel_args.delay_min_us)->default_value(10.0f), "Minimum delay in microseconds")
("channel.dl.rlf.enable", bpo::value<bool>(&args->phy.dl_channel_args.rlf_enable)->default_value(false), "Enable/Disable Radio-Link Failure simulator")
("channel.dl.rlf.t_on_ms", bpo::value<uint32_t >(&args->phy.dl_channel_args.rlf_t_on_ms)->default_value(10000), "Time for On state of the channel (ms)")
("channel.dl.rlf.t_off_ms", bpo::value<uint32_t >(&args->phy.dl_channel_args.rlf_t_off_ms)->default_value(2000), "Time for Off state of the channel (ms)")
("channel.dl.hst.enable", bpo::value<bool>(&args->phy.dl_channel_args.hst_enable)->default_value(false), "Enable/Disable HST simulator")
("channel.dl.hst.period_s", bpo::value<float>(&args->phy.dl_channel_args.hst_period_s)->default_value(7.2f), "HST simulation period in seconds")
("channel.dl.hst.fd_hz", bpo::value<float>(&args->phy.dl_channel_args.hst_fd_hz)->default_value(+750.0f), "Doppler frequency in Hz")
("channel.dl.hst.init_time_s", bpo::value<float>(&args->phy.dl_channel_args.hst_init_time_s)->default_value(0), "Initial time in seconds")
/* Uplink Channel emulator section */
("channel.ul.enable", bpo::value<bool>(&args->phy.ul_channel_args.enable)->default_value(false), "Enable/Disable internal Uplink channel emulator")
("channel.ul.fading.enable", bpo::value<bool>(&args->phy.ul_channel_args.fading_enable)->default_value(false), "Enable/Disable Fading model")
("channel.ul.fading.model", bpo::value<std::string>(&args->phy.ul_channel_args.fading_model)->default_value("none"), "Fading model + maximum doppler (E.g. none, epa5, eva70, etu300, etc)")
("channel.ul.delay.enable", bpo::value<bool>(&args->phy.ul_channel_args.delay_enable)->default_value(false), "Enable/Disable Delay simulator")
("channel.ul.delay.period_s", bpo::value<float>(&args->phy.ul_channel_args.delay_period_s)->default_value(3600), "Delay period in seconds (integer)")
("channel.ul.delay.init_time_s", bpo::value<float>(&args->phy.ul_channel_args.delay_init_time_s)->default_value(0), "Initial time in seconds")
("channel.ul.delay.maximum_us", bpo::value<float>(&args->phy.ul_channel_args.delay_max_us)->default_value(100.0f), "Maximum delay in microseconds")
("channel.ul.delay.minimum_us", bpo::value<float>(&args->phy.ul_channel_args.delay_min_us)->default_value(10.0f), "Minimum delay in microseconds")
("channel.ul.rlf.enable", bpo::value<bool>(&args->phy.ul_channel_args.rlf_enable)->default_value(false), "Enable/Disable Radio-Link Failure simulator")
("channel.ul.rlf.t_on_ms", bpo::value<uint32_t >(&args->phy.ul_channel_args.rlf_t_on_ms)->default_value(10000), "Time for On state of the channel (ms)")
("channel.ul.rlf.t_off_ms", bpo::value<uint32_t >(&args->phy.ul_channel_args.rlf_t_off_ms)->default_value(2000), "Time for Off state of the channel (ms)")
("channel.ul.hst.enable", bpo::value<bool>(&args->phy.ul_channel_args.hst_enable)->default_value(false), "Enable/Disable HST simulator")
("channel.ul.hst.period_s", bpo::value<float>(&args->phy.ul_channel_args.hst_period_s)->default_value(7.2f), "HST simulation period in seconds")
("channel.ul.hst.fd_hz", bpo::value<float>(&args->phy.ul_channel_args.hst_fd_hz)->default_value(-750.0f), "Doppler frequency in Hz")
("channel.ul.hst.init_time_s", bpo::value<float>(&args->phy.ul_channel_args.hst_init_time_s)->default_value(0), "Initial time in seconds")
/* Expert section */
("expert.metrics_period_secs", bpo::value<float>(&args->general.metrics_period_secs)->default_value(1.0), "Periodicity for metrics in seconds")
("expert.metrics_csv_enable", bpo::value<bool>(&args->general.metrics_csv_enable)->default_value(false), "Write metrics to CSV file")

@ -481,7 +481,7 @@ int cc_worker::decode_pusch(stack_interface_phy_lte::ul_sched_grant_t* grants, u
return SRSLTE_ERROR;
}
uint32_t ul_pid = TTI_RX(tti_rx) % SRSLTE_FDD_NOF_HARQ;
uint32_t ul_pid = TTI_RX(ul_sf.tti) % SRSLTE_FDD_NOF_HARQ;
// Handle Format0 adaptive retx
// Use last TBS for this TB in case of mcs>28
@ -492,12 +492,15 @@ int cc_worker::decode_pusch(stack_interface_phy_lte::ul_sched_grant_t* grants, u
phy->ue_db_set_last_ul_tb(rnti, ul_pid, grant->tb);
// Run PUSCH decoder
pusch_res = {};
ue_db[rnti]->ul_cfg.pusch.softbuffers.rx = grants[i].softbuffer_rx;
pusch_res.data = grants[i].data;
if (pusch_res.data) {
if (srslte_enb_ul_get_pusch(&enb_ul, &ul_sf, &ue_db[rnti]->ul_cfg.pusch, &pusch_res)) {
Error("Decoding PUSCH\n");
return SRSLTE_ERROR;
}
}
// Save PHICH scheduling for this user. Each user can have just 1 PUSCH dci per TTI
ue_db[rnti]->phich_grant.n_prb_lowest = grant->n_prb_tilde[0];
@ -507,7 +510,7 @@ int cc_worker::decode_pusch(stack_interface_phy_lte::ul_sched_grant_t* grants, u
// Notify MAC of RL status
if (snr_db >= PUSCH_RL_SNR_DB_TH) {
phy->stack->snr_info(tti_rx, rnti, snr_db);
phy->stack->snr_info(ul_sf.tti, rnti, snr_db);
if (grants[i].dci.tb.rv == 0) {
if (!pusch_res.crc) {
@ -519,12 +522,13 @@ int cc_worker::decode_pusch(stack_interface_phy_lte::ul_sched_grant_t* grants, u
}
}
// Notify MAC new received data and HARQ Indication value
phy->stack->crc_info(tti_rx, rnti, grant->tb.tbs / 8, pusch_res.crc);
// Send UCI data to MAC
send_uci_data(rnti, &ue_db[rnti]->ul_cfg.pusch.uci_cfg, &pusch_res.uci);
// Notify MAC new received data and HARQ Indication value
if (pusch_res.data) {
phy->stack->crc_info(tti_rx, rnti, grant->tb.tbs / 8, pusch_res.crc);
// Save metrics stats
ue_db[rnti]->metrics_ul(grants[i].dci.tb.mcs_idx, 0, snr_db, pusch_res.avg_iterations_block);
@ -534,6 +538,7 @@ int cc_worker::decode_pusch(stack_interface_phy_lte::ul_sched_grant_t* grants, u
Info("PUSCH: %s, snr=%.1f dB\n", str, snr_db);
}
}
}
return SRSLTE_SUCCESS;
}

@ -23,6 +23,7 @@
#include "srslte/asn1/rrc_asn1.h"
#include "srslte/common/log.h"
#include "srslte/common/threads.h"
#include "srslte/phy/channel/channel.h"
#include <sstream>
#include <assert.h>
@ -39,7 +40,7 @@ namespace srsenb {
phy_common::phy_common(uint32_t max_workers_) : tx_sem(max_workers_)
{
nof_workers = max_workers_;
nof_workers = 0;
params.max_prach_offset_us = 20;
have_mtch_stop = false;
max_workers = max_workers_;
@ -79,6 +80,24 @@ bool phy_common::init(const srslte_cell_t& cell_,
pthread_mutex_init(&mtch_mutex, nullptr);
pthread_cond_init(&mtch_cvar, nullptr);
// Instantiate UL channel emulator
if (params.ul_channel_args.enable) {
dl_channel =
srslte::channel_ptr(new srslte::channel(params.dl_channel_args, 1));
dl_channel->set_srate((uint32_t)srslte_sampling_freq_hz(cell.nof_prb));
}
is_first_tx = true;
// Instantiate UL channel emulator
if (params.ul_channel_args.enable) {
dl_channel =
srslte::channel_ptr(new srslte::channel(params.dl_channel_args, 1));
dl_channel->set_srate((uint32_t)srslte_sampling_freq_hz(cell.nof_prb));
}
is_first_tx = true;
reset();
return true;
@ -115,6 +134,10 @@ void phy_common::worker_end(uint32_t tti,
// Wait for the green light to transmit in the current TTI
sem_wait(&tx_sem[tti%nof_workers]);
if (dl_channel) {
dl_channel->run(buffer, buffer, nof_samples, tx_time);
}
// always transmit on single radio
radio->tx(0, buffer, nof_samples, tx_time);

@ -61,6 +61,10 @@ bool txrx::init(srslte::radio_interface_phy* radio_h_,
nof_workers = workers_pool->get_nof_workers();
worker_com->set_nof_workers(nof_workers);
if (worker_com->params.dl_channel_args.enable) {
ul_channel = srslte::channel_ptr(new srslte::channel(worker_com->params.ul_channel_args, 1));
}
start(prio_);
return true;
}
@ -86,6 +90,10 @@ void txrx::run_thread()
radio_h->set_rx_srate(0, samp_rate);
radio_h->set_tx_srate(0, samp_rate);
if (ul_channel) {
ul_channel->set_srate(samp_rate);
}
log_h->info("Starting RX/TX thread nof_prb=%d, sf_len=%d\n", worker_com->cell.nof_prb, sf_len);
// Set TTI so that first TX is at tti=0
@ -104,6 +112,10 @@ void txrx::run_thread()
radio_h->rx_now(0, buffer, sf_len, &rx_time);
if (ul_channel) {
ul_channel->run(buffer, buffer, sf_len, rx_time);
}
/* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */
srslte_timestamp_copy(&tx_time, &rx_time);
srslte_timestamp_add(&tx_time, 0, TX_DELAY * 1e-3);

@ -38,7 +38,7 @@ using namespace asn1::rrc;
namespace srsenb {
mac::mac() : timers_db(128), timers_thread(&timers_db), tti(0), last_rnti(0),
mac::mac() : timers_db(128), timers_thread(this, &timers_db), last_rnti(0),
rar_pdu_msg(sched_interface::MAX_RAR_LIST), rar_payload(),
pdu_process_thread(this)
{
@ -52,7 +52,6 @@ mac::mac() : timers_db(128), timers_thread(&timers_db), tti(0), last_rnti(0),
bzero(&locations, sizeof(locations));
bzero(&cell, sizeof(cell));
bzero(&args, sizeof(args));
bzero(&pending_rars, sizeof(pending_rars));
bzero(&bcch_dlsch_payload, sizeof(bcch_dlsch_payload));
bzero(&pcch_payload_buffer, sizeof(pcch_payload_buffer));
bzero(&bcch_softbuffer_tx, sizeof(bcch_softbuffer_tx));
@ -136,7 +135,6 @@ void mac::reset()
timers_db.stop_all();
tti = 0;
last_rnti = 70;
/* Setup scheduler */
@ -147,9 +145,8 @@ void mac::start_pcap(srslte::mac_pcap* pcap_)
{
pcap = pcap_;
// Set pcap in all UEs for UL messages
for(std::map<uint16_t, ue*>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
ue *u = iter->second;
u->start_pcap(pcap);
for (auto& u : ue_db) {
u.second->start_pcap(pcap);
}
}
@ -282,10 +279,9 @@ void mac::get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS])
{
pthread_rwlock_rdlock(&rwlock);
int cnt=0;
for(std::map<uint16_t, ue*>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
ue *u = iter->second;
if(iter->first != SRSLTE_MRNTI) {
u->metrics_read(&metrics[cnt]);
for (auto& u : ue_db) {
if(u.first != SRSLTE_MRNTI) {
u.second->metrics_read(&metrics[cnt]);
cnt++;
}
}
@ -372,8 +368,6 @@ int mac::crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc)
int mac::set_dl_ant_info(uint16_t rnti, phys_cfg_ded_s::ant_info_c_* dl_ant_info)
{
log_h->step(tti);
int ret = -1;
pthread_rwlock_rdlock(&rwlock);
if (ue_db.count(rnti)) {
@ -470,60 +464,55 @@ int mac::rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv)
{
log_h->step(tti);
// Find empty slot for pending rars
uint32_t ra_id=0;
while(pending_rars[ra_id].temp_crnti && ra_id<MAX_PENDING_RARS-1) {
ra_id++;
}
if (ra_id == MAX_PENDING_RARS) {
Error("Maximum number of pending RARs exceeded (%d)\n", MAX_PENDING_RARS);
return -1;
}
pthread_rwlock_rdlock(&rwlock);
uint32_t rnti = last_rnti;
// Create new UE
ue_db[last_rnti] = new ue(last_rnti, cell.nof_prb, &scheduler, rrc_h, rlc_h, log_h);
if (!ue_db.count(rnti)) {
ue_db[rnti] = new ue(rnti, cell.nof_prb, &scheduler, rrc_h, rlc_h, log_h,
SRSLTE_FDD_NOF_HARQ);
}
// Set PCAP if available
if (pcap) {
ue_db[last_rnti]->start_pcap(pcap);
ue_db[rnti]->start_pcap(pcap);
}
pthread_rwlock_unlock(&rwlock);
// Save RA info
pending_rars[ra_id].preamble_idx = preamble_idx;
pending_rars[ra_id].ta_cmd = time_adv;
pending_rars[ra_id].temp_crnti = last_rnti;
// Generate RAR data
sched_interface::dl_sched_rar_info_t rar_info = {};
rar_info.preamble_idx = preamble_idx;
rar_info.ta_cmd = time_adv;
rar_info.temp_crnti = rnti;
rar_info.msg3_size = 7;
rar_info.prach_tti = tti;
// Add new user to the scheduler so that it can RX/TX SRB0
sched_interface::ue_cfg_t uecfg;
bzero(&uecfg, sizeof(sched_interface::ue_cfg_t));
uecfg.ue_bearers[0].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH;
if (scheduler.ue_cfg(last_rnti, &uecfg)) {
// Release pending RAR
bzero(&pending_rars[ra_id], sizeof(pending_rar_t));
Error("Registering new user rnti=0x%x to SCHED\n", last_rnti);
if (scheduler.ue_cfg(rnti, &uecfg)) {
Error("Registering new user rnti=0x%x to SCHED\n", rnti);
return -1;
}
// Register new user in RRC
rrc_h->add_user(last_rnti);
rrc_h->add_user(rnti);
// Add temporal rnti to the PHY
if (phy_h->add_rnti(last_rnti, true)) {
Error("Registering temporal-rnti=0x%x to PHY\n", last_rnti);
if (phy_h->add_rnti(rnti, true)) {
Error("Registering temporal-rnti=0x%x to PHY\n", rnti);
}
// Trigger scheduler RACH
scheduler.dl_rach_info(tti, ra_id, last_rnti, 7);
scheduler.dl_rach_info(rar_info);
log_h->info("RACH: tti=%d, preamble=%d, offset=%d, temp_crnti=0x%x\n",
tti, preamble_idx, time_adv, last_rnti);
tti, preamble_idx, time_adv, rnti);
log_h->console("RACH: tti=%d, preamble=%d, offset=%d, temp_crnti=0x%x\n",
tti, preamble_idx, time_adv, last_rnti);
tti, preamble_idx, time_adv, rnti);
// Increase RNTI counter
last_rnti++;
if (last_rnti >= 60000) {
@ -609,7 +598,7 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
// Assemble PDU
dl_sched_res->pdsch[n].data[0] =
assemble_rar(sched_result.rar[i].msg3_grant, sched_result.rar[i].nof_grants, i, sched_result.rar[i].tbs);
assemble_rar(sched_result.rar[i].msg3_grant, sched_result.rar[i].nof_grants, i, sched_result.rar[i].tbs, tti);
if (pcap) {
pcap->write_dl_ranti(
@ -751,7 +740,7 @@ int mac::get_mch_sched(uint32_t tti, bool is_mcch, dl_sched_t* dl_sched_res)
return SRSLTE_SUCCESS;
}
uint8_t* mac::assemble_rar(sched_interface::dl_sched_rar_grant_t* grants, uint32_t nof_grants, int rar_idx, uint32_t pdu_len)
uint8_t* mac::assemble_rar(sched_interface::dl_sched_rar_grant_t* grants, uint32_t nof_grants, int rar_idx, uint32_t pdu_len, uint32_t tti)
{
uint8_t grant_buffer[64] = {};
if (pdu_len < rar_payload_len) {
@ -761,13 +750,10 @@ uint8_t* mac::assemble_rar(sched_interface::dl_sched_rar_grant_t* grants, uint32
for (uint32_t i = 0; i < nof_grants; i++) {
srslte_dci_rar_pack(&grants[i].grant, grant_buffer);
if (pdu->new_subh()) {
/* Search pending RAR */
int idx = grants[i].ra_id;
pdu->get()->set_rapid(pending_rars[idx].preamble_idx);
pdu->get()->set_ta_cmd(pending_rars[idx].ta_cmd);
pdu->get()->set_temp_crnti(pending_rars[idx].temp_crnti);
pdu->get()->set_rapid(grants[i].data.preamble_idx);
pdu->get()->set_ta_cmd(grants[i].data.ta_cmd);
pdu->get()->set_temp_crnti(grants[i].data.temp_crnti);
pdu->get()->set_sched_grant(grant_buffer);
bzero(&pending_rars[idx], sizeof(pending_rar_t));
}
}
pdu->write_packet(rar_payload[rar_idx].msg);
@ -830,7 +816,7 @@ int mac::get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res)
ul_sched_res->nof_grants++;
n++;
} else {
Warning("Invalid DL scheduling result. User 0x%x does not exist\n", rnti);
Warning("Invalid UL scheduling result. User 0x%x does not exist\n", rnti);
}
} else {
@ -959,29 +945,27 @@ bool mac::process_pdus()
{
pthread_rwlock_rdlock(&rwlock);
bool ret = false;
for(std::map<uint16_t, ue*>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
ue *u = iter->second;
uint16_t rnti = iter->first;
ret = ret | u->process_pdus();
for (auto& u : ue_db) {
ret = ret | u.second->process_pdus();
}
pthread_rwlock_unlock(&rwlock);
return ret;
}
void mac::write_mcch(sib_type2_s* sib2, sib_type13_r9_s* sib13, mcch_msg_s* mcch)
void mac::write_mcch(sib_type2_s* sib2_, sib_type13_r9_s* sib13_, mcch_msg_s* mcch_)
{
this->mcch = *mcch;
mcch = *mcch_;
mch.num_mtch_sched = this->mcch.msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9[0].mbms_session_info_list_r9.size();
for (uint32_t i = 0; i < mch.num_mtch_sched; ++i) {
mch.mtch_sched[i].lcid =
this->mcch.msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9[0].mbms_session_info_list_r9[i].lc_ch_id_r9;
}
this->sib2 = *sib2;
this->sib13 = *sib13;
sib2 = *sib2_;
sib13 = *sib13_;
const int rlc_header_len = 1;
asn1::bit_ref bref(&mcch_payload_buffer[rlc_header_len], sizeof(mcch_payload_buffer) - rlc_header_len);
mcch->pack(bref);
mcch.pack(bref);
current_mcch_length = bref.distance_bytes(&mcch_payload_buffer[1]);
current_mcch_length = current_mcch_length + rlc_header_len;
ue_db[SRSLTE_MRNTI] = new ue(SRSLTE_MRNTI, cell.nof_prb, &scheduler, rrc_h, rlc_h, log_h);

@ -154,11 +154,14 @@ alloc_outcome_t sched::tti_sched_t::alloc_paging(uint32_t aggr_lvl, uint32_t pag
}
sched::tti_sched_t::rar_code_t
sched::tti_sched_t::alloc_rar(uint32_t aggr_lvl, const dl_sched_rar_t& rar_grant, uint32_t rar_tti, uint32_t buf_rar)
sched::tti_sched_t::alloc_rar(uint32_t aggr_lvl, const dl_sched_rar_t& rar_grant, uint32_t prach_tti, uint32_t buf_rar)
{
uint16_t rar_sfidx = (uint16_t)((rar_tti + 1) % 10);
// RA-RNTI = 1 + t_id + f_id
// t_id = index of first subframe specified by PRACH (0<=t_id<10)
// f_id = index of the PRACH within subframe, in ascending order of freq domain (0<=f_id<6) (for FDD, f_id=0)
uint16_t ra_rnti = 1 + (uint16_t)(prach_tti % 10);
ctrl_code_t ret = alloc_dl_ctrl(aggr_lvl, buf_rar, rar_sfidx);
ctrl_code_t ret = alloc_dl_ctrl(aggr_lvl, buf_rar, ra_rnti);
if (not ret.first) {
Warning("SCHED: Could not allocate RAR for L=%d, cause=%s\n", aggr_lvl, ret.first.to_string());
return {ret.first, NULL};
@ -332,7 +335,7 @@ void sched::tti_sched_t::set_rar_sched_result(const pdcch_grid_t::alloc_result_t
int tbs =
generate_format1a(prb_range.prb_start, prb_range.length(), rar_alloc.req_bytes, 0, rar_alloc.rnti, &rar->dci);
if (tbs <= 0) {
log_h->warning("SCHED: Error RAR, ra_rnti_idx=%d, rbgs=(%d,%d), dci=(%d,%d)\n",
log_h->warning("SCHED: Error RAR, ra-rnti=%d, rbgs=(%d,%d), dci=(%d,%d)\n",
rar_alloc.rnti,
rar_alloc.rbg_range.rbg_start,
rar_alloc.rbg_range.rbg_end,
@ -349,11 +352,10 @@ void sched::tti_sched_t::set_rar_sched_result(const pdcch_grid_t::alloc_result_t
// Print RAR allocation result
for (uint32_t i = 0; i < rar->nof_grants; ++i) {
const auto& msg3_grant = rar->msg3_grant[i];
uint32_t pending_tti = (get_tti_tx_dl() + MSG3_DELAY_MS + TX_DELAY) % 10;
uint32_t pending_tti = (get_tti_tx_dl() + MSG3_DELAY_MS + TX_DELAY) % TTIMOD_SZ;
uint16_t expected_rnti = parent->pending_msg3[pending_tti].rnti; // FIXME
log_h->info("SCHED: RAR, ra_id=%d, rnti=0x%x, rarnti_idx=%d, rbgs=(%d,%d), dci=(%d,%d), rar_grant_rba=%d, "
log_h->info("SCHED: RAR, temp_crnti=0x%x, ra-rnti=%d, rbgs=(%d,%d), dci=(%d,%d), rar_grant_rba=%d, "
"rar_grant_mcs=%d\n",
msg3_grant.ra_id,
expected_rnti,
rar_alloc.rnti,
rar_alloc.rbg_range.rbg_start,
@ -511,7 +513,7 @@ void sched::tti_sched_t::generate_dcis()
uint32_t sched::tti_sched_t::get_nof_ctrl_symbols() const
{
return tti_alloc.get_cfi() + (parent->cfg.cell.nof_prb <= 10) ? 1 : 0;
return tti_alloc.get_cfi() + ((parent->cfg.cell.nof_prb <= 10) ? 1 : 0);
}
int sched::tti_sched_t::generate_format1a(
@ -602,6 +604,7 @@ void sched::init(rrc_interface_mac* rrc_, srslte::log* log)
sched_cfg.pusch_max_mcs = 28;
sched_cfg.pusch_mcs = -1;
sched_cfg.nof_ctrl_symbols = 3;
sched_cfg.max_aggr_level = 3;
log_h = log;
rrc = rrc_;
reset();
@ -609,9 +612,12 @@ void sched::init(rrc_interface_mac* rrc_, srslte::log* log)
int sched::reset()
{
bzero(pending_msg3, sizeof(pending_msg3_t) * 10);
bzero(pending_rar, sizeof(sched_rar_t) * SCHED_MAX_PENDING_RAR);
bzero(pending_msg3, sizeof(pending_msg3_t) * TTIMOD_SZ);
bzero(pending_sibs, sizeof(sched_sib_t) * MAX_SIBS);
while (not pending_rars.empty()) {
pending_rars.pop();
}
configured = false;
pthread_rwlock_wrlock(&rwlock);
ue_db.clear();
@ -716,7 +722,7 @@ int sched::ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* ue_cfg)
// Add or config user
pthread_rwlock_rdlock(&rwlock);
ue_db[rnti].set_cfg(rnti, ue_cfg, &cfg, &regs, log_h);
ue_db[rnti].set_max_mcs(sched_cfg.pusch_max_mcs, sched_cfg.pdsch_max_mcs);
ue_db[rnti].set_max_mcs(sched_cfg.pusch_max_mcs, sched_cfg.pdsch_max_mcs, sched_cfg.max_aggr_level);
ue_db[rnti].set_fixed_mcs(sched_cfg.pusch_mcs, sched_cfg.pdsch_mcs);
pthread_rwlock_unlock(&rwlock);
@ -745,6 +751,16 @@ bool sched::ue_exists(uint16_t rnti)
return ret;
}
void sched::ue_needs_ta_cmd(uint16_t rnti, uint32_t nof_ta_cmd) {
pthread_rwlock_rdlock(&rwlock);
if (ue_db.count(rnti)) {
ue_db[rnti].set_needs_ta_cmd(nof_ta_cmd);
} else {
Error("User rnti=0x%x not found\n", rnti);
}
pthread_rwlock_unlock(&rwlock);
}
void sched::phy_config_enabled(uint16_t rnti, bool enabled)
{
pthread_rwlock_rdlock(&rwlock);
@ -756,12 +772,12 @@ void sched::phy_config_enabled(uint16_t rnti, bool enabled)
pthread_rwlock_unlock(&rwlock);
}
int sched::bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, sched_interface::ue_bearer_cfg_t* cfg)
int sched::bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, sched_interface::ue_bearer_cfg_t* cfg_)
{
int ret = 0;
pthread_rwlock_rdlock(&rwlock);
if (ue_db.count(rnti)) {
ue_db[rnti].set_bearer_cfg(lc_id, cfg);
ue_db[rnti].set_bearer_cfg(lc_id, cfg_);
} else {
Error("User rnti=0x%x not found\n", rnti);
ret = -1;
@ -922,20 +938,13 @@ int sched::dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value)
return ret;
}
int sched::dl_rach_info(uint32_t tti, uint32_t ra_id, uint16_t rnti, uint32_t estimated_size)
int sched::dl_rach_info(dl_sched_rar_info_t rar_info)
{
for (int i = 0; i < SCHED_MAX_PENDING_RAR; i++) {
if (!pending_rar[i].buf_rar) {
pending_rar[i].ra_id = ra_id;
pending_rar[i].rnti = rnti;
pending_rar[i].rar_tti = tti;
pending_rar[i].buf_rar = estimated_size;
Info("SCHED: New RAR tti=%d, preamble=%d, temp_crnti=0x%x, ta_cmd=%d, msg3_size=%d\n",
rar_info.prach_tti, rar_info.preamble_idx, rar_info.temp_crnti, rar_info.ta_cmd, rar_info.msg3_size);
pending_rars.push(rar_info);
return 0;
}
}
Warning("SCHED: New RACH discarted because maximum number of pending RAR exceeded (%d)\n", SCHED_MAX_PENDING_RAR);
return -1;
}
int sched::ul_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi, uint32_t ul_ch_code)
{
@ -1046,7 +1055,7 @@ sched::tti_sched_t* sched::new_tti(uint32_t tti_rx)
// if it is the first time tti is run, reset vars
if (tti_rx != tti_sched->get_tti_rx()) {
uint32_t start_cfi = sched_cfg.nof_ctrl_symbols - ((cfg.cell.nof_prb >= 10) ? 0 : 1);
uint32_t start_cfi = sched_cfg.nof_ctrl_symbols;
tti_sched->new_tti(tti_rx, start_cfi);
// Protects access to pending_rar[], pending_msg3[], pending_sibs[], rlc buffers
@ -1157,78 +1166,74 @@ bool is_in_tti_interval(uint32_t tti, uint32_t tti1, uint32_t tti2)
}
// Schedules RAR
// On every call to this function, we schedule the oldest RAR which is still within the window. If outside the window we discard it.
void sched::dl_sched_rar(tti_sched_t* tti_sched)
{
for (uint32_t i = 0; i < SCHED_MAX_PENDING_RAR; i++) {
// check if the RAR is inactive or was already scheduled
if (pending_rar[i].buf_rar == 0) {
continue;
}
// Check if we are still within the RAR window, otherwise discard it
// Discard all RARs out of the window. The first one inside the window is scheduled, if we can't we exit
while (!pending_rars.empty()) {
dl_sched_rar_info_t rar = pending_rars.front();
if (not is_in_tti_interval(tti_sched->get_tti_tx_dl(),
pending_rar[i].rar_tti + 3,
pending_rar[i].rar_tti + 3 + cfg.prach_rar_window)) {
rar.prach_tti + 3,
rar.prach_tti + 3 + cfg.prach_rar_window))
{
if (tti_sched->get_tti_tx_dl() >= rar.prach_tti + 3 + cfg.prach_rar_window) {
log_h->console("SCHED: Could not transmit RAR within the window (RA TTI=%d, Window=%d, Now=%d)\n",
pending_rar[i].rar_tti,
rar.prach_tti,
cfg.prach_rar_window,
current_tti);
log_h->error("SCHED: Could not transmit RAR within the window (RA TTI=%d, Window=%d, Now=%d)\n",
pending_rar[i].rar_tti,
rar.prach_tti,
cfg.prach_rar_window,
current_tti);
pending_rar[i].buf_rar = 0;
pending_rar[i].rar_tti = 0;
// Remove from pending queue and get next one if window has passed already
pending_rars.pop();
continue;
}
// If window not yet started do not look for more pending RARs
return;
}
/* Group pending RARs with same transmission TTI */
uint32_t tti = pending_rar[i].rar_tti;
uint32_t buf_rar = 0;
/* Since we do a fixed Msg3 scheduling for all RAR, we can only allocate 1 RAR per TTI.
* If we have enough space in the window, every call to this function we'll allocate 1 pending RAR and associate a
* Msg3 transmission
*/
dl_sched_rar_t rar_grant;
uint32_t L_prb = 3;
uint32_t n_prb = 2;
uint32_t n_prb = cfg.nrb_pucch>0?cfg.nrb_pucch:2;
bzero(&rar_grant, sizeof(rar_grant));
uint32_t rba = srslte_ra_type2_to_riv(L_prb, n_prb, cfg.cell.nof_prb);
for (uint32_t j = i; j < SCHED_MAX_PENDING_RAR; ++j) {
if (pending_rar[j].rar_tti != pending_rar[i].rar_tti) {
continue;
}
if (rar_grant.nof_grants > 0) {
log_h->warning("Only 1 RA is responded at a time. Found %d for TTI=%d\n", rar_grant.nof_grants + 1, tti);
continue;
}
dl_sched_rar_grant_t* grant = &rar_grant.msg3_grant[rar_grant.nof_grants];
dl_sched_rar_grant_t *grant = &rar_grant.msg3_grant[0];
grant->grant.tpc_pusch = 3;
grant->grant.trunc_mcs = 0;
grant->grant.rba = rba;
grant->ra_id = pending_rar[j].ra_id;
buf_rar += pending_rar[j].buf_rar;
grant->data = rar;
rar_grant.nof_grants++;
}
// Try to schedule DCI + RBGs for RAR Grant
tti_sched_t::rar_code_t ret = tti_sched->alloc_rar(rar_aggr_level, rar_grant, pending_rar[i].rar_tti, buf_rar);
if (not ret.first) {
continue;
tti_sched_t::rar_code_t ret = tti_sched->alloc_rar(rar_aggr_level,
rar_grant,
rar.prach_tti,
7 * rar_grant.nof_grants); //fixme: check RAR size
// If we can allocate, schedule Msg3 and remove from pending
if (!ret.first) {
return;
}
// Schedule Msg3
uint32_t pending_tti = (tti_sched->get_tti_tx_dl() + MSG3_DELAY_MS + TX_DELAY) % 10;
// Schedule Msg3 only if there is a requirement for Msg3 data
uint32_t pending_tti = (tti_sched->get_tti_tx_dl() + MSG3_DELAY_MS + TX_DELAY) % TTIMOD_SZ;
pending_msg3[pending_tti].enabled = true;
pending_msg3[pending_tti].rnti = pending_rar[i].rnti; // FIXME
pending_msg3[pending_tti].rnti = rar.temp_crnti; // FIXME
pending_msg3[pending_tti].L = L_prb;
pending_msg3[pending_tti].n_prb = n_prb;
dl_sched_rar_grant_t *last_msg3 = &rar_grant.msg3_grant[rar_grant.nof_grants - 1];
pending_msg3[pending_tti].mcs = last_msg3->grant.trunc_mcs;
Info("SCHED: Allocating Msg3 for rnti=%d at tti=%d\n", rar.temp_crnti, tti_sched->get_tti_tx_dl() + MSG3_DELAY_MS + TX_DELAY);
// Reset allocated RARs
for (uint32_t j = i; j < SCHED_MAX_PENDING_RAR; ++j) {
if (pending_rar[j].rar_tti == pending_rar[i].rar_tti) {
pending_rar[j].buf_rar = 0;
pending_rar[j].rar_tti = 0;
}
}
// Remove pending RAR and exit
pending_rars.pop();
return;
}
}
@ -1236,7 +1241,7 @@ void sched::dl_sched_data(tti_sched_t* tti_sched)
{
// NOTE: In case of 6 PRBs, do not transmit if there is going to be a PRACH in the UL to avoid collisions
uint32_t tti_rx_ack = TTI_RX_ACK(tti_sched->get_tti_rx());
uint32_t pending_tti = tti_rx_ack % 10;
uint32_t pending_tti = tti_rx_ack % TTIMOD_SZ;
if (cfg.cell.nof_prb == 6 and (srslte_prach_tti_opportunity_config_fdd(cfg.prach_config, tti_rx_ack, -1) or
pending_msg3[pending_tti].enabled)) {
tti_sched->get_dl_mask().fill(0, tti_sched->get_dl_mask().size());
@ -1285,7 +1290,7 @@ void sched::generate_phich(tti_sched_t* tti_sched)
tti_sched->ul_sched_result.phich[nof_phich_elems].rnti = rnti;
log_h->debug("SCHED: Allocated PHICH for rnti=0x%x, value=%d\n",
rnti,
tti_sched->ul_sched_result.phich[nof_phich_elems].phich);
tti_sched->ul_sched_result.phich[nof_phich_elems].phich == ul_sched_phich_t::ACK);
nof_phich_elems++;
}
}
@ -1294,7 +1299,7 @@ void sched::generate_phich(tti_sched_t* tti_sched)
void sched::ul_sched_msg3(tti_sched_t* tti_sched)
{
uint32_t pending_tti = tti_sched->get_tti_tx_ul() % 10;
uint32_t pending_tti = tti_sched->get_tti_tx_ul() % TTIMOD_SZ;
if (not pending_msg3[pending_tti].enabled) {
return;
}

@ -55,7 +55,8 @@ sched_ue::sched_ue() :
max_mcs_ul(0),
fixed_mcs_ul(0),
fixed_mcs_dl(0),
phy_config_dedicated_enabled(false)
phy_config_dedicated_enabled(false),
nof_ta_cmd(0)
{
log_h = NULL;
@ -86,6 +87,7 @@ void sched_ue::set_cfg(uint16_t rnti_,
max_mcs_dl = 28;
max_mcs_ul = 28;
max_aggr_level = 3;
max_msg3retx = cell_cfg->maxharq_msg3tx;
cfg = *cfg_;
@ -153,7 +155,7 @@ void sched_ue::set_fixed_mcs(int mcs_ul, int mcs_dl) {
fixed_mcs_dl = mcs_dl;
}
void sched_ue::set_max_mcs(int mcs_ul, int mcs_dl) {
void sched_ue::set_max_mcs(int mcs_ul, int mcs_dl, int max_aggr_level_) {
std::lock_guard<std::mutex> lock(mutex);
if (mcs_ul < 0) {
max_mcs_ul = 28;
@ -165,6 +167,11 @@ void sched_ue::set_max_mcs(int mcs_ul, int mcs_dl) {
} else {
max_mcs_dl = mcs_dl;
}
if (max_aggr_level_ < 0) {
max_aggr_level = 3;
} else {
max_aggr_level = max_aggr_level_;
}
}
@ -246,6 +253,11 @@ void sched_ue::unset_sr()
sr = false;
}
void sched_ue::set_needs_ta_cmd(uint32_t nof_ta_cmd_) {
nof_ta_cmd = nof_ta_cmd_;
Info("SCHED: rnti=0x%x needs %d TA CMD\n", rnti, nof_ta_cmd);
}
bool sched_ue::pucch_sr_collision(uint32_t current_tti, uint32_t n_cce)
{
if (!phy_config_dedicated_enabled) {
@ -463,15 +475,26 @@ int sched_ue::generate_format1(
h->new_tx(user_mask, 0, tti, mcs, tbs, data->dci.location.ncce);
int rem_tbs = tbs;
int x = 0;
// Allocate MAC ConRes CE
if (need_conres_ce) {
data->pdu[0][0].lcid = srslte::sch_subh::CON_RES_ID;
data->pdu[0][data->nof_pdu_elems[0]].lcid = srslte::sch_subh::CON_RES_ID;
data->nof_pdu_elems[0]++;
Info("SCHED: Added MAC Contention Resolution CE for rnti=0x%x\n", rnti);
} else {
// Add TA CE. TODO: Common interface to add MAC CE
// FIXME: Can't put it in Msg4 because current srsUE doesn't read it
while(nof_ta_cmd > 0 && rem_tbs > 2) {
data->pdu[0][data->nof_pdu_elems[0]].lcid = srslte::sch_subh::TA_CMD;
data->nof_pdu_elems[0]++;
Info("SCHED: Added MAC TA CMD CE for rnti=0x%x\n", rnti);
nof_ta_cmd--;
rem_tbs -= 2;
}
}
int rem_tbs = tbs;
int x = 0;
do {
x = alloc_pdu(rem_tbs, &data->pdu[0][data->nof_pdu_elems[0]]);
if (x) {
@ -801,6 +824,9 @@ uint32_t sched_ue::get_pending_dl_new_data_unlocked(uint32_t tti)
pending_data += lch[i].buf_retx + lch[i].buf_tx;
}
}
if (!is_first_dl_tx() && nof_ta_cmd) {
pending_data += nof_ta_cmd*2;
}
return pending_data;
}
@ -1060,6 +1086,7 @@ uint32_t sched_ue::get_aggr_level(uint32_t nof_bits)
factor = 1.0;
l_max = 2;
}
l_max = SRSLTE_MIN(max_aggr_level, l_max);
do {
coderate = srslte_pdcch_coderate(nof_bits, l);
l++;

@ -38,29 +38,35 @@ ue::ue(uint16_t rnti_,
sched_interface* sched_,
rrc_interface_mac* rrc_,
rlc_interface_mac* rlc_,
srslte::log* log_) :
srslte::log* log_,
uint32_t nof_rx_harq_proc_,
uint32_t nof_tx_harq_proc_) :
rnti(rnti_),
sched(sched_),
rrc(rrc_),
rlc(rlc_),
log_h(log_),
mac_msg_dl(20, log_h),
mch_mac_msg_dl(10, log_h),
mac_msg_ul(20, log_h),
pdus(128)
mac_msg_dl(20, log_),
mch_mac_msg_dl(10, log_), mac_msg_ul(20, log_),
pdus(128),
nof_rx_harq_proc(nof_rx_harq_proc_),
nof_tx_harq_proc(nof_tx_harq_proc_)
{
bzero(&metrics, sizeof(mac_metrics_t));
bzero(&mutex, sizeof(pthread_mutex_t));
bzero(softbuffer_tx, sizeof(softbuffer_tx));
bzero(softbuffer_rx, sizeof(softbuffer_rx));
pthread_mutex_init(&mutex, NULL);
pdus.init(this, log_h);
for (int i = 0; i < NOF_RX_HARQ_PROCESSES; i++) {
softbuffer_tx.reserve(nof_tx_harq_proc);
softbuffer_rx.reserve(nof_rx_harq_proc);
pending_buffers.reserve(nof_rx_harq_proc);
for (int i = 0; i < nof_rx_harq_proc; i++) {
srslte_softbuffer_rx_init(&softbuffer_rx[i], nof_prb);
pending_buffers[i] = nullptr;
}
for (int i = 0; i < NOF_TX_HARQ_PROCESSES; i++) {
for (int i = 0; i < nof_tx_harq_proc; i++) {
srslte_softbuffer_tx_init(&softbuffer_tx[i], nof_prb);
}
// don't need to reset because just initiated the buffers
@ -72,10 +78,10 @@ ue::ue(uint16_t rnti_,
ue::~ue()
{
for (int i = 0; i < NOF_RX_HARQ_PROCESSES; i++) {
for (int i = 0; i < nof_rx_harq_proc; i++) {
srslte_softbuffer_rx_free(&softbuffer_rx[i]);
}
for (int i = 0; i < NOF_TX_HARQ_PROCESSES; i++) {
for (int i = 0; i < nof_tx_harq_proc; i++) {
srslte_softbuffer_tx_free(&softbuffer_tx[i]);
}
pthread_mutex_destroy(&mutex);
@ -86,10 +92,10 @@ void ue::reset()
bzero(&metrics, sizeof(mac_metrics_t));
nof_failures = 0;
for (int i = 0; i < NOF_RX_HARQ_PROCESSES; i++) {
for (int i = 0; i < nof_rx_harq_proc; i++) {
srslte_softbuffer_rx_reset(&softbuffer_rx[i]);
}
for (int i = 0; i < NOF_TX_HARQ_PROCESSES; i++) {
for (int i = 0; i < nof_tx_harq_proc; i++) {
srslte_softbuffer_tx_reset(&softbuffer_tx[i]);
}
}
@ -121,24 +127,24 @@ void ue::set_lcg(uint32_t lcid, uint32_t lcg)
srslte_softbuffer_rx_t* ue::get_rx_softbuffer(uint32_t tti)
{
return &softbuffer_rx[tti % NOF_RX_HARQ_PROCESSES];
return &softbuffer_rx[tti % nof_rx_harq_proc];
}
srslte_softbuffer_tx_t* ue::get_tx_softbuffer(uint32_t harq_process, uint32_t tb_idx)
{
return &softbuffer_tx[(harq_process * SRSLTE_MAX_TB + tb_idx) % NOF_TX_HARQ_PROCESSES];
return &softbuffer_tx[(harq_process * SRSLTE_MAX_TB + tb_idx) % nof_tx_harq_proc];
}
uint8_t* ue::request_buffer(uint32_t tti, uint32_t len)
{
uint8_t* ret = NULL;
if (len > 0) {
if (!pending_buffers[tti % NOF_RX_HARQ_PROCESSES]) {
if (!pending_buffers[tti % nof_rx_harq_proc]) {
ret = pdus.request(len);
pending_buffers[tti % NOF_RX_HARQ_PROCESSES] = ret;
pending_buffers[tti % nof_rx_harq_proc] = ret;
} else {
log_h->console("Error requesting buffer for pid %d, not pushed yet\n", tti % NOF_RX_HARQ_PROCESSES);
log_h->error("Requesting buffer for pid %d, not pushed yet\n", tti % NOF_RX_HARQ_PROCESSES);
log_h->console("Error requesting buffer for pid %d, not pushed yet\n", tti % nof_rx_harq_proc);
log_h->error("Requesting buffer for pid %d, not pushed yet\n", tti % nof_rx_harq_proc);
}
} else {
log_h->warning("Requesting buffer for zero bytes\n");
@ -155,6 +161,21 @@ void ue::set_tti(uint32_t tti) {
last_tti = tti;
}
uint32_t ue::set_ta(int ta_) {
int ta = ta_;
uint32_t nof_cmd = 0;
int ta_value = 0;
do {
ta_value = SRSLTE_MAX(-31, SRSLTE_MIN(32, ta));
ta -= ta_value;
uint32_t ta_cmd = (uint32_t) (ta_value + 31);
pending_ta_commands.try_push(ta_cmd);
nof_cmd++;
Info("Added TA CMD: rnti=0x%x, ta=%d, ta_value=%d, ta_cmd=%d\n", rnti, ta_, ta_value, ta_cmd);
} while (ta_value <= -31 || ta_value >= 32);
return nof_cmd;
}
#include <assert.h>
void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel)
@ -258,21 +279,21 @@ void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srslte::pdu_queue::channe
void ue::deallocate_pdu(uint32_t tti)
{
if (pending_buffers[tti % NOF_RX_HARQ_PROCESSES]) {
pdus.deallocate(pending_buffers[tti % NOF_RX_HARQ_PROCESSES]);
pending_buffers[tti % NOF_RX_HARQ_PROCESSES] = NULL;
if (pending_buffers[tti % nof_rx_harq_proc]) {
pdus.deallocate(pending_buffers[tti % nof_rx_harq_proc]);
pending_buffers[tti % nof_rx_harq_proc] = NULL;
} else {
log_h->console("Error deallocating buffer for pid=%d. Not requested\n", tti % NOF_RX_HARQ_PROCESSES);
log_h->console("Error deallocating buffer for pid=%d. Not requested\n", tti % nof_rx_harq_proc);
}
}
void ue::push_pdu(uint32_t tti, uint32_t len)
{
if (pending_buffers[tti % NOF_RX_HARQ_PROCESSES]) {
pdus.push(pending_buffers[tti % NOF_RX_HARQ_PROCESSES], len);
pending_buffers[tti % NOF_RX_HARQ_PROCESSES] = NULL;
if (pending_buffers[tti % nof_rx_harq_proc]) {
pdus.push(pending_buffers[tti % nof_rx_harq_proc], len);
pending_buffers[tti % nof_rx_harq_proc] = NULL;
} else {
log_h->console("Error pushing buffer for pid=%d. Not requested\n", tti % NOF_RX_HARQ_PROCESSES);
log_h->console("Error pushing buffer for pid=%d. Not requested\n", tti % nof_rx_harq_proc);
}
}
@ -369,6 +390,19 @@ void ue::allocate_sdu(srslte::sch_pdu *pdu, uint32_t lcid, uint32_t total_sdu_le
void ue::allocate_ce(srslte::sch_pdu *pdu, uint32_t lcid)
{
switch((srslte::sch_subh::cetype) lcid) {
case srslte::sch_subh::TA_CMD:
if (pdu->new_subh()) {
uint32_t ta_cmd = 31;
pending_ta_commands.try_pop(&ta_cmd);
if (pdu->get()->set_ta_cmd(ta_cmd)) {
Info("CE: Added TA CMD=%d\n", ta_cmd);
} else {
Error("CE: Setting TA CMD CE\n");
}
} else {
Error("CE: Setting TA CMD CE. No space for a subheader\n");
}
break;
case srslte::sch_subh::CON_RES_ID:
if (pdu->new_subh()) {
if (pdu->get()->set_con_res_id(conres_id)) {

@ -754,6 +754,8 @@ void rrc::config_mac()
sched_cfg.sibs[i].period_rf = cfg.sib1.sched_info_list[i - 1].si_periodicity.to_number();
}
}
sched_cfg.prach_config = cfg.sibs[1].sib2().rr_cfg_common.prach_cfg.prach_cfg_info.prach_cfg_idx;
sched_cfg.prach_nof_preambles = cfg.sibs[1].sib2().rr_cfg_common.rach_cfg_common.preamb_info.nof_ra_preambs.to_number();
sched_cfg.si_window_ms = cfg.sib1.si_win_len.to_number();
sched_cfg.prach_rar_window =
cfg.sibs[1].sib2().rr_cfg_common.rach_cfg_common.ra_supervision_info.ra_resp_win_size.to_number();

@ -173,7 +173,6 @@ struct sched_tester : public srsenb::sched {
};
struct ue_info {
int prach_tti, rar_tti, msg3_tti;
uint32_t ra_id;
srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg;
srsenb::sched_interface::ue_cfg_t user_cfg;
uint32_t dl_data;
@ -229,10 +228,8 @@ void sched_tester::add_user(uint16_t rnti,
srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg,
srsenb::sched_interface::ue_cfg_t ue_cfg_)
{
uint32_t ra_id = rand() % 5;
ue_info info;
info.prach_tti = tti_data.tti_rx;
info.ra_id = ra_id;
info.bearer_cfg = bearer_cfg;
info.user_cfg = ue_cfg_;
tester_ues.insert(std::make_pair(rnti, info));
@ -240,7 +237,11 @@ void sched_tester::add_user(uint16_t rnti,
if (ue_cfg(rnti, &ue_cfg_)) {
TestError("[TESTER] Registering new user rnti=0x%x to SCHED\n", rnti);
}
dl_rach_info(tti_data.tti_rx, ra_id, rnti, 7);
dl_sched_rar_info_t rar_info = {};
rar_info.prach_tti = tti_data.tti_rx;
rar_info.temp_crnti = rnti;
rar_info.msg3_size = 7;
dl_rach_info(rar_info);
// setup bearers
bearer_ue_cfg(rnti, 0, &bearer_cfg);
@ -266,7 +267,7 @@ void sched_tester::new_test_tti(uint32_t tti_)
} else {
tti_data.ul_sf_idx = (tti_data.tti_tx_ul + 10240 - FDD_HARQ_DELAY_MS) % 10;
}
tti_data.ul_pending_msg3 = pending_msg3[tti_data.tti_tx_ul % 10];
tti_data.ul_pending_msg3 = pending_msg3[tti_data.tti_tx_ul % TTIMOD_SZ];
tti_data.current_cfi = sched_cfg.nof_ctrl_symbols;
tti_data.used_cce.resize(srslte_regs_pdcch_ncce(&regs, tti_data.current_cfi));
tti_data.used_cce.reset();
@ -413,7 +414,7 @@ void sched_tester::test_ra()
if (tti_data.tti_tx_dl >= window[0]) {
for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_rar_elems; ++i) {
for (uint32_t j = 0; j < tti_data.sched_result_dl.rar[i].nof_grants; ++j) {
if (tti_data.sched_result_dl.rar[i].msg3_grant[j].ra_id == userinfo.ra_id) {
if (tti_data.sched_result_dl.rar[i].msg3_grant[j].data.prach_tti == tti_data.tti_tx_dl) {
userinfo.rar_tti = tti_data.tti_tx_dl;
}
}
@ -532,7 +533,7 @@ void sched_tester::test_tti_result()
CondError(rar.tbs == 0, "Allocated RAR process with invalid TBS=%d\n", rar.tbs);
for (uint32_t j = 0; j < rar.nof_grants; ++j) {
const auto& msg3_grant = rar.msg3_grant[j];
uint32_t pending_tti = (tti_sched->get_tti_tx_dl() + MSG3_DELAY_MS + TX_DELAY) % 10;
uint32_t pending_tti = (tti_sched->get_tti_tx_dl() + MSG3_DELAY_MS + TX_DELAY) % TTIMOD_SZ;
CondError(not pending_msg3[pending_tti].enabled, "Pending Msg3 should have been set\n");
uint32_t rba =
srslte_ra_type2_to_riv(pending_msg3[pending_tti].L, pending_msg3[pending_tti].n_prb, cfg.cell.nof_prb);
@ -687,16 +688,17 @@ void sched_tester::test_harqs()
to_ul_ack.insert(std::make_pair(ack_data.tti_tx_ul, ack_data));
}
// Check whether some pids got old
for (auto& user : ue_db) {
for (int i = 0; i < 2 * FDD_HARQ_DELAY_MS; i++) {
if (not(user.second.get_dl_harq(i)->is_empty(0) and user.second.get_dl_harq(1))) {
if (srslte_tti_interval(tti_data.tti_tx_dl, user.second.get_dl_harq(i)->get_tti()) > 49) {
TestError("[TESTER] The pid=%d for rnti=0x%x got old.\n", user.second.get_dl_harq(i)->get_id(), user.first);
}
}
}
}
// // Check whether some pids got old
// for (auto& user : ue_db) {
// for (int i = 0; i < 2 * FDD_HARQ_DELAY_MS; i++) {
// if (not(user.second.get_dl_harq(i)->is_empty(0) and user.second.get_dl_harq(1))) {
// if (srslte_tti_interval(tti_data.tti_tx_dl, user.second.get_dl_harq(i)->get_tti()) > 49) {
// TestError("[TESTER] The pid=%d for rnti=0x%x got old.\n", user.second.get_dl_harq(i)->get_id(),
// user.first);
// }
// }
// }
// }
}
void sched_tester::test_collisions()

Loading…
Cancel
Save