fixing conflict

master
Ismael Gomez 8 years ago
commit 2d0508ab25

@ -510,7 +510,7 @@ int main(int argc, char **argv) {
sigaddset(&sigset, SIGINT); sigaddset(&sigset, SIGINT);
sigprocmask(SIG_UNBLOCK, &sigset, NULL); sigprocmask(SIG_UNBLOCK, &sigset, NULL);
signal(SIGINT, sig_int_handler); signal(SIGINT, sig_int_handler);
if (!output_file_name) { if (!output_file_name) {
int srate = srslte_sampling_freq_hz(cell.nof_prb); int srate = srslte_sampling_freq_hz(cell.nof_prb);
@ -534,7 +534,6 @@ int main(int argc, char **argv) {
printf("Set TX freq: %.2f MHz\n", printf("Set TX freq: %.2f MHz\n",
srslte_rf_set_tx_freq(&rf, rf_freq) / 1000000); srslte_rf_set_tx_freq(&rf, rf_freq) / 1000000);
} }
srslte_rf_start_tx_stream(&rf);
#endif #endif
if (update_radl(sf_idx)) { if (update_radl(sf_idx)) {
@ -663,7 +662,7 @@ srslte_rf_start_tx_stream(&rf);
nf++; nf++;
sfn = (sfn + 1) % 1024; sfn = (sfn + 1) % 1024;
} }
srslte_rf_stop_tx_stream(&rf);
base_free(); base_free();
printf("Done\n"); printf("Done\n");

@ -83,32 +83,6 @@ static const char error_text[ERROR_N_ITEMS][20] = { "None",
"Can't start", "Can't start",
"Already started"}; "Already started"};
typedef enum{
RB_ID_SRB0 = 0,
RB_ID_SRB1,
RB_ID_SRB2,
RB_ID_DRB1,
RB_ID_DRB2,
RB_ID_DRB3,
RB_ID_DRB4,
RB_ID_DRB5,
RB_ID_DRB6,
RB_ID_DRB7,
RB_ID_DRB8,
RB_ID_N_ITEMS,
}rb_id_t;
static const char rb_id_text[RB_ID_N_ITEMS][20] = { "SRB0",
"SRB1",
"SRB2",
"DRB1",
"DRB2",
"DRB3",
"DRB4",
"DRB5",
"DRB6",
"DRB7",
"DRB8"};
/****************************************************************************** /******************************************************************************
* Byte and Bit buffers * Byte and Bit buffers
* *

@ -28,9 +28,32 @@
#define INTERFACE_COMMON_H #define INTERFACE_COMMON_H
#include "srslte/common/timers.h" #include "srslte/common/timers.h"
#include "srslte/common/security.h"
#include "srslte/asn1/liblte_rrc.h"
namespace srslte { namespace srslte {
class srslte_pdcp_config_t
{
public:
srslte_pdcp_config_t(bool is_control_ = false, bool is_data_ = false, uint8_t direction_ = SECURITY_DIRECTION_UPLINK)
:direction(direction_)
,is_control(is_control_)
,is_data(is_data_)
,do_security(false)
,sn_len(12) {}
uint8_t direction;
bool is_control;
bool is_data;
bool do_security;
uint8_t sn_len;
// TODO: Support the following configurations
// bool do_rohc;
};
class mac_interface_timers class mac_interface_timers
{ {
public: public:

@ -34,6 +34,7 @@ public:
bool init(metrics_interface<metrics_t> *m_, float report_period_secs=1.0) { bool init(metrics_interface<metrics_t> *m_, float report_period_secs=1.0) {
m = m_; m = m_;
start_periodic(report_period_secs*1e6); start_periodic(report_period_secs*1e6);
return true;
} }
void stop() { void stop() {
thread_cancel(); thread_cancel();
@ -47,7 +48,7 @@ private:
void run_period() { void run_period() {
metrics_t metric; metrics_t metric;
m->get_metrics(metric); m->get_metrics(metric);
for (int i=0;i<listeners.size();i++) { for (uint32_t i=0;i<listeners.size();i++) {
listeners[i]->set_metrics(metric); listeners[i]->set_metrics(metric);
} }
} }

@ -28,7 +28,9 @@
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/security.h" #include "srslte/common/security.h"
#include "srslte/common/interfaces_common.h"
#include "srslte/interfaces/sched_interface.h" #include "srslte/interfaces/sched_interface.h"
#include "srslte/upper/rlc_interface.h"
#include "srslte/asn1/liblte_rrc.h" #include "srslte/asn1/liblte_rrc.h"
#include "srslte/asn1/liblte_s1ap.h" #include "srslte/asn1/liblte_s1ap.h"
@ -156,7 +158,7 @@ public:
virtual void add_user(uint16_t rnti) = 0; virtual void add_user(uint16_t rnti) = 0;
virtual void rem_user(uint16_t rnti) = 0; virtual void rem_user(uint16_t rnti) = 0;
virtual void add_bearer(uint16_t rnti, uint32_t lcid) = 0; virtual void add_bearer(uint16_t rnti, uint32_t lcid) = 0;
virtual void add_bearer(uint16_t rnti, uint32_t lcid, LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) = 0; virtual void add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_rlc_config_t cnfg) = 0;
}; };
// PDCP interface for GTPU // PDCP interface for GTPU
@ -174,7 +176,7 @@ public:
virtual void add_user(uint16_t rnti) = 0; virtual void add_user(uint16_t rnti) = 0;
virtual void rem_user(uint16_t rnti) = 0; virtual void rem_user(uint16_t rnti) = 0;
virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu) = 0;
virtual void add_bearer(uint16_t rnti, uint32_t lcid, LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg=NULL) = 0; virtual void add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_pdcp_config_t cnfg) = 0;
virtual void config_security(uint16_t rnti, virtual void config_security(uint16_t rnti,
uint32_t lcid, uint32_t lcid,
uint8_t *k_rrc_enc_, uint8_t *k_rrc_enc_,

@ -39,6 +39,7 @@
#include "srslte/common/interfaces_common.h" #include "srslte/common/interfaces_common.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/security.h" #include "srslte/common/security.h"
#include "srslte/upper/rlc_interface.h"
namespace srsue { namespace srsue {
@ -104,11 +105,16 @@ public:
}; };
// RRC interface for MAC // RRC interface for MAC
class rrc_interface_mac class rrc_interface_mac_common
{
public:
virtual void ra_problem() = 0;
};
class rrc_interface_mac : public rrc_interface_mac_common
{ {
public: public:
virtual void release_pucch_srs() = 0; virtual void release_pucch_srs() = 0;
virtual void ra_problem() = 0;
}; };
// RRC interface for PHY // RRC interface for PHY
@ -127,6 +133,7 @@ public:
virtual uint16_t get_mcc() = 0; virtual uint16_t get_mcc() = 0;
virtual uint16_t get_mnc() = 0; virtual uint16_t get_mnc() = 0;
virtual void enable_capabilities() = 0; virtual void enable_capabilities() = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
}; };
// RRC interface for GW // RRC interface for GW
@ -146,6 +153,7 @@ public:
virtual void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu) = 0;
virtual void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu) = 0;
virtual void write_pdu_pcch(srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu_pcch(srslte::byte_buffer_t *pdu) = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
}; };
// RRC interface for RLC // RRC interface for RLC
@ -153,6 +161,7 @@ class rrc_interface_rlc
{ {
public: public:
virtual void max_retx_attempted() = 0; virtual void max_retx_attempted() = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
}; };
// PDCP interface for GW // PDCP interface for GW
@ -168,7 +177,7 @@ class pdcp_interface_rrc
public: public:
virtual void reset() = 0; virtual void reset() = 0;
virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0;
virtual void add_bearer(uint32_t lcid, LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg=NULL) = 0; virtual void add_bearer(uint32_t lcid, srslte::srslte_pdcp_config_t cnfg = srslte::srslte_pdcp_config_t()) = 0;
virtual void config_security(uint32_t lcid, virtual void config_security(uint32_t lcid,
uint8_t *k_rrc_enc_, uint8_t *k_rrc_enc_,
uint8_t *k_rrc_int_, uint8_t *k_rrc_int_,
@ -193,7 +202,7 @@ class rlc_interface_rrc
public: public:
virtual void reset() = 0; virtual void reset() = 0;
virtual void add_bearer(uint32_t lcid) = 0; virtual void add_bearer(uint32_t lcid) = 0;
virtual void add_bearer(uint32_t lcid, LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) = 0; virtual void add_bearer(uint32_t lcid, srslte::srslte_rlc_config_t cnfg) = 0;
}; };
// RLC interface for PDCP // RLC interface for PDCP
@ -230,6 +239,31 @@ public:
}; };
//BSR interface for MUX
class bsr_interface_mux
{
public:
typedef enum {
LONG_BSR,
SHORT_BSR,
TRUNC_BSR
} bsr_format_t;
typedef struct {
bsr_format_t format;
uint32_t buff_size[4];
} bsr_t;
/* MUX calls BSR to check if it can fit a BSR into PDU */
virtual bool need_to_send_bsr_on_ul_grant(uint32_t grant_size, bsr_t *bsr) = 0;
/* MUX calls BSR to let it generate a padding BSR if there is space in PDU */
virtual bool generate_padding_bsr(uint32_t nof_padding_bytes, bsr_t *bsr) = 0;
/* MAX calls BSR to set the Tx TTI */
virtual void set_tx_tti(uint32_t tti) = 0;
};
/** MAC interface /** MAC interface
* *
@ -275,6 +309,7 @@ public:
uint32_t rv; uint32_t rv;
uint16_t rnti; uint16_t rnti;
uint32_t current_tx_nb; uint32_t current_tx_nb;
int32_t tti_offset; // relative offset between grant and UL tx/HARQ rx
srslte_softbuffer_tx_t *softbuffer; srslte_softbuffer_tx_t *softbuffer;
srslte_phy_grant_t phy_grant; srslte_phy_grant_t phy_grant;
uint8_t *payload_ptr; uint8_t *payload_ptr;
@ -309,9 +344,27 @@ public:
}; };
/* 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 temp_rnti;
uint16_t tpc_rnti;
uint16_t sps_rnti;
uint64_t contention_id;
} ue_rnti_t;
typedef struct {
uint32_t max_harq_msg3_tx;
uint32_t max_harq_tx;
} ul_harq_params_t;
};
/* Interface RRC -> MAC */ /* Interface RRC -> MAC */
class mac_interface_rrc class mac_interface_rrc : public mac_interface_rrc_common
{ {
public: public:
@ -319,19 +372,10 @@ public:
LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT main; LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT main;
LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT rach; LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT rach;
LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT sr; LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT sr;
ul_harq_params_t ul_harq_params;
uint32_t prach_config_index; uint32_t prach_config_index;
} mac_cfg_t; } mac_cfg_t;
// Class to handle UE specific RNTIs between RRC and MAC
typedef struct {
uint16_t crnti;
uint16_t temp_rnti;
uint16_t tpc_rnti;
uint16_t sps_rnti;
uint64_t contention_id;
} ue_rnti_t;
/* Instructs the MAC to start receiving BCCH */ /* Instructs the MAC to start receiving BCCH */
virtual void bcch_start_rx() = 0; virtual void bcch_start_rx() = 0;
virtual void bcch_stop_rx() = 0; virtual void bcch_stop_rx() = 0;
@ -391,46 +435,51 @@ typedef struct {
float estimator_fil_w; float estimator_fil_w;
bool rssi_sensor_enabled; bool rssi_sensor_enabled;
} phy_args_t; } phy_args_t;
/* Interface MAC -> PHY */
class phy_interface_mac /* RAT agnostic Interface MAC -> PHY */
class phy_interface_mac_common
{ {
public: public:
/* Configure PRACH using parameters written by RRC */
virtual void configure_prach_params() = 0;
/* Start synchronization with strongest cell in the current carrier frequency */ /* Start synchronization with strongest cell in the current carrier frequency */
virtual void sync_start() = 0; virtual void sync_start() = 0;
virtual void sync_stop() = 0; virtual void sync_stop() = 0;
/* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */ /* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */
virtual void set_crnti(uint16_t rnti) = 0; 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;
/* Sets RAR grant payload */
virtual void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]) = 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 : public phy_interface_mac_common
{
public:
/* Configure PRACH using parameters written by RRC */
virtual void configure_prach_params() = 0;
virtual void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm) = 0; virtual void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm) = 0;
virtual int prach_tx_tti() = 0; virtual int prach_tx_tti() = 0;
/* Indicates the transmission of a SR signal in the next opportunity */ /* Indicates the transmission of a SR signal in the next opportunity */
virtual void sr_send() = 0; virtual void sr_send() = 0;
virtual int sr_last_tx_tti() = 0; virtual int sr_last_tx_tti() = 0;
/* Time advance commands */
virtual void set_timeadv_rar(uint32_t ta_cmd) = 0;
virtual void set_timeadv(uint32_t ta_cmd) = 0;
/* Sets RAR grant payload */
virtual void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]) = 0;
/* Instruct the PHY to decode PDCCH with the CRC scrambled with given RNTI */ /* Instruct the PHY to decode PDCCH with the CRC scrambled with given RNTI */
virtual void pdcch_ul_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1) = 0; virtual void pdcch_ul_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1) = 0;
virtual void pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1) = 0; virtual void pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1) = 0;
virtual void pdcch_ul_search_reset() = 0; virtual void pdcch_ul_search_reset() = 0;
virtual void pdcch_dl_search_reset() = 0; virtual void pdcch_dl_search_reset() = 0;
virtual uint32_t get_current_tti() = 0;
virtual float get_phr() = 0;
virtual float get_pathloss_db() = 0;
}; };
class phy_interface_rrc class phy_interface_rrc

@ -48,7 +48,8 @@
#include "srslte/phy/phch/pdsch_cfg.h" #include "srslte/phy/phch/pdsch_cfg.h"
typedef struct { typedef struct {
srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME];
bool sequence_generated;
} srslte_pdsch_user_t; } srslte_pdsch_user_t;
/* PDSCH object */ /* PDSCH object */

@ -80,7 +80,8 @@ typedef struct SRSLTE_API {
} srslte_pucch_cfg_t; } srslte_pucch_cfg_t;
typedef struct { typedef struct {
srslte_sequence_t seq_f2[SRSLTE_NSUBFRAMES_X_FRAME]; srslte_sequence_t seq_f2[SRSLTE_NSUBFRAMES_X_FRAME];
bool sequence_generated;
} srslte_pucch_user_t; } srslte_pucch_user_t;
/* PUCCH object */ /* PUCCH object */

@ -61,7 +61,8 @@ typedef struct {
} srslte_pusch_hopping_cfg_t; } srslte_pusch_hopping_cfg_t;
typedef struct { typedef struct {
srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME];
bool sequences_generated;
} srslte_pusch_user_t; } srslte_pusch_user_t;
/* PUSCH object */ /* PUSCH object */

@ -99,10 +99,6 @@ SRSLTE_API int srslte_rf_start_rx_stream(srslte_rf_t *h);
SRSLTE_API int srslte_rf_stop_rx_stream(srslte_rf_t *h); SRSLTE_API int srslte_rf_stop_rx_stream(srslte_rf_t *h);
SRSLTE_API int srslte_rf_start_tx_stream(srslte_rf_t *h);
SRSLTE_API int srslte_rf_stop_tx_stream(srslte_rf_t *h);
SRSLTE_API void srslte_rf_flush_buffer(srslte_rf_t *h); SRSLTE_API void srslte_rf_flush_buffer(srslte_rf_t *h);
SRSLTE_API bool srslte_rf_has_rssi(srslte_rf_t *h); SRSLTE_API bool srslte_rf_has_rssi(srslte_rf_t *h);

@ -46,7 +46,7 @@ class gw
{ {
public: public:
gw(); gw();
void init(srsue::pdcp_interface_gw *pdcp_, srsue::rrc_interface_gw *rrc_, srsue::ue_interface *ue_, log *gw_log_); void init(srsue::pdcp_interface_gw *pdcp_, srsue::rrc_interface_gw *rrc_, srsue::ue_interface *ue_, log *gw_log_, uint32_t lcid_);
void stop(); void stop();
void get_metrics(gw_metrics_t &m); void get_metrics(gw_metrics_t &m);
@ -56,11 +56,11 @@ public:
// NAS interface // NAS interface
error_t setup_if_addr(uint32_t ip_addr, char *err_str); error_t setup_if_addr(uint32_t ip_addr, char *err_str);
private: private:
static const int GW_THREAD_PRIO = 7; static const int GW_THREAD_PRIO = 7;
srsue::pdcp_interface_gw *pdcp; srsue::pdcp_interface_gw *pdcp;
srsue::rrc_interface_gw *rrc; srsue::rrc_interface_gw *rrc;
srsue::ue_interface *ue; srsue::ue_interface *ue;
@ -73,6 +73,7 @@ private:
struct ifreq ifr; struct ifreq ifr;
int32 sock; int32 sock;
bool if_up; bool if_up;
uint32_t lcid;
long ul_tput_bytes; long ul_tput_bytes;
long dl_tput_bytes; long dl_tput_bytes;

@ -46,13 +46,14 @@ public:
srsue::rrc_interface_pdcp *rrc_, srsue::rrc_interface_pdcp *rrc_,
srsue::gw_interface_pdcp *gw_, srsue::gw_interface_pdcp *gw_,
log *pdcp_log_, log *pdcp_log_,
uint32_t lcid_,
uint8_t direction_); uint8_t direction_);
void stop(); void stop();
// RRC interface // RRC interface
void reset(); void reset();
void write_sdu(uint32_t lcid, byte_buffer_t *sdu); void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
void add_bearer(uint32_t lcid, LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg = NULL); void add_bearer(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t());
void config_security(uint32_t lcid, void config_security(uint32_t lcid,
uint8_t *k_rrc_enc, uint8_t *k_rrc_enc,
uint8_t *k_rrc_int, uint8_t *k_rrc_int,
@ -72,6 +73,7 @@ private:
log *pdcp_log; log *pdcp_log;
pdcp_entity pdcp_array[SRSLTE_N_RADIO_BEARERS]; pdcp_entity pdcp_array[SRSLTE_N_RADIO_BEARERS];
uint32_t lcid; // default LCID that is maintained active by PDCP instance
uint8_t direction; uint8_t direction;
bool valid_lcid(uint32_t lcid); bool valid_lcid(uint32_t lcid);

@ -67,9 +67,7 @@ public:
srsue::gw_interface_pdcp *gw_, srsue::gw_interface_pdcp *gw_,
srslte::log *log_, srslte::log *log_,
uint32_t lcid_, uint32_t lcid_,
uint8_t direction_, srslte_pdcp_config_t cfg_);
LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg = NULL
);
void reset(); void reset();
bool is_active(); bool is_active();
@ -94,12 +92,7 @@ private:
bool active; bool active;
uint32_t lcid; uint32_t lcid;
bool do_security; srslte_pdcp_config_t cfg;
u_int8_t direction;
uint8_t sn_len;
// TODO: Support the following configurations
// bool do_rohc;
uint32_t rx_count; uint32_t rx_count;
uint32_t tx_count; uint32_t tx_count;

@ -34,6 +34,7 @@
#include "srslte/common/msg_queue.h" #include "srslte/common/msg_queue.h"
#include "srslte/upper/rlc_entity.h" #include "srslte/upper/rlc_entity.h"
#include "srslte/upper/rlc_metrics.h" #include "srslte/upper/rlc_metrics.h"
#include "srslte/upper/rlc_common.h"
namespace srslte { namespace srslte {
@ -55,13 +56,15 @@ public:
srsue::rrc_interface_rlc *rrc_, srsue::rrc_interface_rlc *rrc_,
srsue::ue_interface *ue_, srsue::ue_interface *ue_,
log *rlc_log_, log *rlc_log_,
mac_interface_timers *mac_timers_); mac_interface_timers *mac_timers_,
uint32_t lcid_);
void stop(); void stop();
void get_metrics(rlc_metrics_t &m); void get_metrics(rlc_metrics_t &m);
// PDCP interface // PDCP interface
void write_sdu(uint32_t lcid, byte_buffer_t *sdu); void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
std::string get_rb_name(uint32_t lcid);
// MAC interface // MAC interface
uint32_t get_buffer_state(uint32_t lcid); uint32_t get_buffer_state(uint32_t lcid);
@ -75,7 +78,7 @@ public:
// RRC interface // RRC interface
void reset(); void reset();
void add_bearer(uint32_t lcid); void add_bearer(uint32_t lcid);
void add_bearer(uint32_t lcid, LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg); void add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg);
private: private:
void reset_metrics(); void reset_metrics();
@ -87,6 +90,7 @@ private:
srslte::mac_interface_timers *mac_timers; srslte::mac_interface_timers *mac_timers;
srsue::ue_interface *ue; srsue::ue_interface *ue;
srslte::rlc_entity rlc_array[SRSLTE_N_RADIO_BEARERS]; srslte::rlc_entity rlc_array[SRSLTE_N_RADIO_BEARERS];
uint32_t default_lcid;
long ul_tput_bytes[SRSLTE_N_RADIO_BEARERS]; long ul_tput_bytes[SRSLTE_N_RADIO_BEARERS];
long dl_tput_bytes[SRSLTE_N_RADIO_BEARERS]; long dl_tput_bytes[SRSLTE_N_RADIO_BEARERS];

@ -76,7 +76,7 @@ public:
srsue::pdcp_interface_rlc *pdcp_, srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_, srsue::rrc_interface_rlc *rrc_,
mac_interface_timers *mac_timers); mac_interface_timers *mac_timers);
void configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg); void configure(srslte_rlc_config_t cnfg);
void reset(); void reset();
void empty_queue(); void empty_queue();
@ -128,15 +128,7 @@ private:
* Ref: 3GPP TS 36.322 v10.0.0 Section 7 * Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/ ***************************************************************************/
// TX configs srslte_rlc_am_config_t cfg;
int32_t t_poll_retx; // Poll retx timeout (ms)
int32_t poll_pdu; // Insert poll bit after this many PDUs
int32_t poll_byte; // Insert poll bit after this much data (KB)
uint32_t max_retx_thresh; // Max number of retx
// RX configs
int32_t t_reordering; // Timer used by rx to detect PDU loss (ms)
int32_t t_status_prohibit; // Timer used by rx to prohibit tx of status PDU (ms)
/**************************************************************************** /****************************************************************************
* State variables and counters * State variables and counters

@ -27,6 +27,8 @@
#ifndef RLC_COMMON_H #ifndef RLC_COMMON_H
#define RLC_COMMON_H #define RLC_COMMON_H
#include "srslte/upper/rlc_interface.h"
namespace srslte { namespace srslte {
/**************************************************************************** /****************************************************************************
@ -66,14 +68,6 @@ typedef enum{
static const char rlc_dc_field_text[RLC_DC_FIELD_N_ITEMS][20] = {"Control PDU", static const char rlc_dc_field_text[RLC_DC_FIELD_N_ITEMS][20] = {"Control PDU",
"Data PDU"}; "Data PDU"};
typedef enum{
RLC_UMD_SN_SIZE_5_BITS = 0,
RLC_UMD_SN_SIZE_10_BITS,
RLC_UMD_SN_SIZE_N_ITEMS,
}rlc_umd_sn_size_t;
static const char rlc_umd_sn_size_text[RLC_UMD_SN_SIZE_N_ITEMS][20] = {"5 bits", "10 bits"};
static const uint16_t rlc_umd_sn_size_num[RLC_UMD_SN_SIZE_N_ITEMS] = {5, 10};
// UMD PDU Header // UMD PDU Header
typedef struct{ typedef struct{
uint8_t fi; // Framing info uint8_t fi; // Framing info
@ -162,7 +156,7 @@ public:
srsue::pdcp_interface_rlc *pdcp_, srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_, srsue::rrc_interface_rlc *rrc_,
srslte::mac_interface_timers *mac_timers_) = 0; srslte::mac_interface_timers *mac_timers_) = 0;
virtual void configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) = 0; virtual void configure(srslte_rlc_config_t cnfg) = 0;
virtual void reset() = 0; virtual void reset() = 0;
virtual void empty_queue() = 0; virtual void empty_queue() = 0;

@ -54,7 +54,7 @@ public:
srsue::rrc_interface_rlc *rrc_, srsue::rrc_interface_rlc *rrc_,
mac_interface_timers *mac_timers_); mac_interface_timers *mac_timers_);
void configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg); void configure(srslte_rlc_config_t cnfg);
void reset(); void reset();
bool active(); bool active();

@ -0,0 +1,126 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef RLC_INTERFACE_H
#define RLC_INTERFACE_H
// for custom constructors
#include "srslte/asn1/liblte_rrc.h"
namespace srslte {
typedef enum{
RLC_UMD_SN_SIZE_5_BITS = 0,
RLC_UMD_SN_SIZE_10_BITS,
RLC_UMD_SN_SIZE_N_ITEMS,
}rlc_umd_sn_size_t;
static const char rlc_umd_sn_size_text[RLC_UMD_SN_SIZE_N_ITEMS][20] = {"5 bits", "10 bits"};
static const uint16_t rlc_umd_sn_size_num[RLC_UMD_SN_SIZE_N_ITEMS] = {5, 10};
typedef struct {
/****************************************************************************
* Configurable parameters
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
// TX configs
int32_t t_poll_retx; // Poll retx timeout (ms)
int32_t poll_pdu; // Insert poll bit after this many PDUs
int32_t poll_byte; // Insert poll bit after this much data (KB)
uint32_t max_retx_thresh; // Max number of retx
// RX configs
int32_t t_reordering; // Timer used by rx to detect PDU loss (ms)
int32_t t_status_prohibit; // Timer used by rx to prohibit tx of status PDU (ms)
} srslte_rlc_am_config_t;
typedef struct {
/****************************************************************************
* Configurable parameters
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
int32_t t_reordering; // Timer used by rx to detect PDU loss (ms)
rlc_umd_sn_size_t tx_sn_field_length; // Number of bits used for tx (UL) sequence number
rlc_umd_sn_size_t rx_sn_field_length; // Number of bits used for rx (DL) sequence number
uint32_t rx_window_size;
uint32_t rx_mod; // Rx counter modulus
uint32_t tx_mod; // Tx counter modulus
} srslte_rlc_um_config_t;
class srslte_rlc_config_t
{
public:
LIBLTE_RRC_RLC_MODE_ENUM rlc_mode;
srslte_rlc_am_config_t am;
srslte_rlc_um_config_t um;
// Constructor based on liblte's RLC config
srslte_rlc_config_t(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) : rlc_mode(cnfg->rlc_mode), am(), um()
{
switch(rlc_mode)
{
case LIBLTE_RRC_RLC_MODE_AM:
am.t_poll_retx = liblte_rrc_t_poll_retransmit_num[cnfg->ul_am_rlc.t_poll_retx];
am.poll_pdu = liblte_rrc_poll_pdu_num[cnfg->ul_am_rlc.poll_pdu];
am.poll_byte = liblte_rrc_poll_byte_num[cnfg->ul_am_rlc.poll_byte]*1000; // KB
am.max_retx_thresh = liblte_rrc_max_retx_threshold_num[cnfg->ul_am_rlc.max_retx_thresh];
am.t_reordering = liblte_rrc_t_reordering_num[cnfg->dl_am_rlc.t_reordering];
am.t_status_prohibit = liblte_rrc_t_status_prohibit_num[cnfg->dl_am_rlc.t_status_prohibit];
break;
case LIBLTE_RRC_RLC_MODE_UM_BI:
um.t_reordering = liblte_rrc_t_reordering_num[cnfg->dl_um_bi_rlc.t_reordering];
um.rx_sn_field_length = (rlc_umd_sn_size_t)cnfg->dl_um_bi_rlc.sn_field_len;
um.rx_window_size = (RLC_UMD_SN_SIZE_5_BITS == um.rx_sn_field_length) ? 16 : 512;
um.rx_mod = (RLC_UMD_SN_SIZE_5_BITS == um.rx_sn_field_length) ? 32 : 1024;
um.tx_sn_field_length = (rlc_umd_sn_size_t)cnfg->ul_um_bi_rlc.sn_field_len;
um.tx_mod = (RLC_UMD_SN_SIZE_5_BITS == um.tx_sn_field_length) ? 32 : 1024;
break;
case LIBLTE_RRC_RLC_MODE_UM_UNI_UL:
um.tx_sn_field_length = (rlc_umd_sn_size_t)cnfg->ul_um_uni_rlc.sn_field_len;
um.tx_mod = (RLC_UMD_SN_SIZE_5_BITS == um.tx_sn_field_length) ? 32 : 1024;
break;
case LIBLTE_RRC_RLC_MODE_UM_UNI_DL:
um.t_reordering = liblte_rrc_t_reordering_num[cnfg->dl_um_uni_rlc.t_reordering];
um.rx_sn_field_length = (rlc_umd_sn_size_t)cnfg->dl_um_uni_rlc.sn_field_len;
um.rx_window_size = (RLC_UMD_SN_SIZE_5_BITS == um.rx_sn_field_length) ? 16 : 512;
um.rx_mod = (RLC_UMD_SN_SIZE_5_BITS == um.rx_sn_field_length) ? 32 : 1024;
break;
default:
// Handle default case
break;
}
}
};
} // namespace srslte
#endif // RLC_INTERFACE_H

@ -46,7 +46,7 @@ public:
srsue::pdcp_interface_rlc *pdcp_, srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_, srsue::rrc_interface_rlc *rrc_,
mac_interface_timers *mac_timers); mac_interface_timers *mac_timers);
void configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg); void configure(srslte_rlc_config_t cnfg);
void reset(); void reset();
void empty_queue(); void empty_queue();

@ -56,7 +56,7 @@ public:
srsue::pdcp_interface_rlc *pdcp_, srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_, srsue::rrc_interface_rlc *rrc_,
mac_interface_timers *mac_timers_); mac_interface_timers *mac_timers_);
void configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg); void configure(srslte_rlc_config_t cnfg);
void reset(); void reset();
void empty_queue(); void empty_queue();
@ -92,9 +92,6 @@ private:
// Rx window // Rx window
std::map<uint32_t, rlc_umd_pdu_t> rx_window; std::map<uint32_t, rlc_umd_pdu_t> rx_window;
uint32_t rx_window_size;
uint32_t rx_mod; // Rx counter modulus
uint32_t tx_mod; // Tx counter modulus
// RX SDU buffers // RX SDU buffers
byte_buffer_t *rx_sdu; byte_buffer_t *rx_sdu;
@ -108,9 +105,7 @@ private:
* Ref: 3GPP TS 36.322 v10.0.0 Section 7 * Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/ ***************************************************************************/
int32_t t_reordering; // Timer used by rx to detect PDU loss (ms) srslte_rlc_um_config_t cfg;
rlc_umd_sn_size_t tx_sn_field_length; // Number of bits used for tx (UL) sequence number
rlc_umd_sn_size_t rx_sn_field_length; // Number of bits used for rx (DL) sequence number
/**************************************************************************** /****************************************************************************
* State variables and counters * State variables and counters

@ -32,6 +32,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <srslte/phy/phch/pdsch.h>
#include "prb_dl.h" #include "prb_dl.h"
#include "srslte/phy/phch/pdsch.h" #include "srslte/phy/phch/pdsch.h"
@ -362,6 +363,7 @@ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
} }
q->users[rnti]->sequence_generated = true;
} }
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
@ -467,15 +469,15 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q,
srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->e, cfg->nbits.nof_re); srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->e, cfg->nbits.nof_re);
/* descramble */ /* descramble */
if (!q->users[rnti]) { if (q->users[rnti] && q->users[rnti]->sequence_generated) {
srslte_sequence_t seq; srslte_scrambling_s_offset(&q->users[rnti]->seq[cfg->sf_idx], q->e, 0, cfg->nbits.nof_bits);
} else {
srslte_sequence_t seq;
if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
srslte_scrambling_s_offset(&seq, q->e, 0, cfg->nbits.nof_bits); srslte_scrambling_s_offset(&seq, q->e, 0, cfg->nbits.nof_bits);
srslte_sequence_free(&seq); srslte_sequence_free(&seq);
} else {
srslte_scrambling_s_offset(&q->users[rnti]->seq[cfg->sf_idx], q->e, 0, cfg->nbits.nof_bits);
} }
if (SRSLTE_VERBOSE_ISDEBUG()) { if (SRSLTE_VERBOSE_ISDEBUG()) {
@ -537,15 +539,15 @@ int srslte_pdsch_encode(srslte_pdsch_t *q,
} }
/* scramble */ /* scramble */
if (!q->users[rnti]) { if (q->users[rnti] && q->users[rnti]->sequence_generated) {
srslte_sequence_t seq; srslte_scrambling_bytes(&q->users[rnti]->seq[cfg->sf_idx], (uint8_t*) q->e, cfg->nbits.nof_bits);
} else {
srslte_sequence_t seq;
if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
srslte_scrambling_bytes(&seq, (uint8_t*) q->e, cfg->nbits.nof_bits); srslte_scrambling_bytes(&seq, (uint8_t*) q->e, cfg->nbits.nof_bits);
srslte_sequence_free(&seq); srslte_sequence_free(&seq);
} else {
srslte_scrambling_bytes(&q->users[rnti]->seq[cfg->sf_idx], (uint8_t*) q->e, cfg->nbits.nof_bits);
} }
srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs.mod], (uint8_t*) q->e, q->d, cfg->nbits.nof_bits); srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs.mod], (uint8_t*) q->e, q->d, cfg->nbits.nof_bits);

@ -33,6 +33,7 @@
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <complex.h> #include <complex.h>
#include <srslte/srslte.h>
#include "srslte/phy/ch_estimation/refsignal_ul.h" #include "srslte/phy/ch_estimation/refsignal_ul.h"
#include "srslte/phy/phch/pucch.h" #include "srslte/phy/phch/pucch.h"
@ -489,7 +490,7 @@ void srslte_pucch_clear_rnti(srslte_pucch_t *q, uint16_t rnti) {
int srslte_pucch_set_crnti(srslte_pucch_t *q, uint16_t rnti) { int srslte_pucch_set_crnti(srslte_pucch_t *q, uint16_t rnti) {
if (!q->users[rnti]) { if (!q->users[rnti]) {
q->users[rnti] = malloc(sizeof(srslte_pucch_user_t)); q->users[rnti] = calloc(1, sizeof(srslte_pucch_user_t));
if (q->users[rnti]) { if (q->users[rnti]) {
for (uint32_t sf_idx=0;sf_idx<SRSLTE_NSUBFRAMES_X_FRAME;sf_idx++) { for (uint32_t sf_idx=0;sf_idx<SRSLTE_NSUBFRAMES_X_FRAME;sf_idx++) {
// Precompute scrambling sequence for pucch format 2 // Precompute scrambling sequence for pucch format 2
@ -498,6 +499,7 @@ int srslte_pucch_set_crnti(srslte_pucch_t *q, uint16_t rnti) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
} }
q->users[rnti]->sequence_generated = true;
} }
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
@ -591,7 +593,7 @@ static int uci_mod_bits(srslte_pucch_t *q, srslte_pucch_format_t format, uint8_t
case SRSLTE_PUCCH_FORMAT_2: case SRSLTE_PUCCH_FORMAT_2:
case SRSLTE_PUCCH_FORMAT_2A: case SRSLTE_PUCCH_FORMAT_2A:
case SRSLTE_PUCCH_FORMAT_2B: case SRSLTE_PUCCH_FORMAT_2B:
if (q->users[rnti]) { if (q->users[rnti] && q->users[rnti]->sequence_generated) {
memcpy(q->bits_scram, bits, SRSLTE_PUCCH2_NOF_BITS*sizeof(uint8_t)); memcpy(q->bits_scram, bits, SRSLTE_PUCCH2_NOF_BITS*sizeof(uint8_t));
srslte_scrambling_b(&q->users[rnti]->seq_f2[sf_idx], q->bits_scram); srslte_scrambling_b(&q->users[rnti]->seq_f2[sf_idx], q->bits_scram);
srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH2_NOF_BITS); srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH2_NOF_BITS);
@ -796,7 +798,7 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format,
case SRSLTE_PUCCH_FORMAT_2: case SRSLTE_PUCCH_FORMAT_2:
case SRSLTE_PUCCH_FORMAT_2A: case SRSLTE_PUCCH_FORMAT_2A:
case SRSLTE_PUCCH_FORMAT_2B: case SRSLTE_PUCCH_FORMAT_2B:
if (q->users[rnti]) { if (q->users[rnti] && q->users[rnti]->sequence_generated) {
pucch_encode_(q, format, n_pucch, sf_idx, rnti, NULL, ref, true); pucch_encode_(q, format, n_pucch, sf_idx, rnti, NULL, ref, true);
srslte_vec_prod_conj_ccc(q->z, ref, q->z_tmp, SRSLTE_PUCCH_MAX_SYMBOLS); srslte_vec_prod_conj_ccc(q->z, ref, q->z_tmp, SRSLTE_PUCCH_MAX_SYMBOLS);
for (int i=0;i<SRSLTE_PUCCH2_NOF_BITS/2;i++) { for (int i=0;i<SRSLTE_PUCCH2_NOF_BITS/2;i++) {

@ -400,7 +400,8 @@ int srslte_pusch_set_rnti(srslte_pusch_t *q, uint16_t rnti) {
q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
} }
q->users[rnti]->sequences_generated = true;
} }
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
@ -444,15 +445,15 @@ int srslte_pusch_encode(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_softb
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (!q->users[rnti]) { if (q->users[rnti] && q->users[rnti]->sequences_generated) {
srslte_sequence_t seq; srslte_scrambling_bytes(&q->users[rnti]->seq[cfg->sf_idx], (uint8_t*) q->q, cfg->nbits.nof_bits);
} else {
srslte_sequence_t seq;
if (srslte_sequence_pusch(&seq, rnti, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { if (srslte_sequence_pusch(&seq, rnti, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
srslte_scrambling_bytes(&seq, (uint8_t*) q->q, cfg->nbits.nof_bits); srslte_scrambling_bytes(&seq, (uint8_t*) q->q, cfg->nbits.nof_bits);
srslte_sequence_free(&seq); srslte_sequence_free(&seq);
} else {
srslte_scrambling_bytes(&q->users[rnti]->seq[cfg->sf_idx], (uint8_t*) q->q, cfg->nbits.nof_bits);
} }
// Correct UCI placeholder/repetition bits // Correct UCI placeholder/repetition bits
@ -535,13 +536,13 @@ int srslte_pusch_decode(srslte_pusch_t *q,
srslte_sequence_t *seq = NULL; srslte_sequence_t *seq = NULL;
// Create sequence if does not exist // Create sequence if does not exist
if (!q->users[rnti]) { if (q->users[rnti] && q->users[rnti]->sequences_generated) {
seq = &q->tmp_seq; seq = &q->users[rnti]->seq[cfg->sf_idx];
} else {
seq = &q->tmp_seq;
if (srslte_sequence_pusch(seq, rnti, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { if (srslte_sequence_pusch(seq, rnti, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
} else {
seq = &q->users[rnti]->seq[cfg->sf_idx];
} }
// Decode RI/HARQ bits before descrambling // Decode RI/HARQ bits before descrambling
@ -553,7 +554,7 @@ int srslte_pusch_decode(srslte_pusch_t *q,
// Descrambling // Descrambling
srslte_scrambling_s_offset(seq, q->q, 0, cfg->nbits.nof_bits); srslte_scrambling_s_offset(seq, q->q, 0, cfg->nbits.nof_bits);
if (!q->users[rnti]) { if (!(q->users[rnti] && q->users[rnti]->sequences_generated)) {
srslte_sequence_free(seq); srslte_sequence_free(seq);
} }

@ -164,13 +164,6 @@ int rf_blade_stop_rx_stream(void *h)
return 0; return 0;
} }
int rf_blade_stop_tx_stream(void *h)
{
return 0;
}
void rf_blade_flush_buffer(void *h) void rf_blade_flush_buffer(void *h)
{ {
} }

@ -51,11 +51,6 @@ SRSLTE_API int rf_blade_start_rx_stream_nsamples(void *h,
SRSLTE_API int rf_blade_stop_rx_stream(void *h); SRSLTE_API int rf_blade_stop_rx_stream(void *h);
SRSLTE_API int rf_blade_start_tx_stream(void *h);
SRSLTE_API int rf_blade_stop_tx_stream(void *h);
SRSLTE_API void rf_blade_flush_buffer(void *h); SRSLTE_API void rf_blade_flush_buffer(void *h);
SRSLTE_API bool rf_blade_has_rssi(void *h); SRSLTE_API bool rf_blade_has_rssi(void *h);

@ -32,8 +32,6 @@ typedef struct {
bool (*srslte_rf_rx_wait_lo_locked) (void *h); bool (*srslte_rf_rx_wait_lo_locked) (void *h);
int (*srslte_rf_start_rx_stream)(void *h); int (*srslte_rf_start_rx_stream)(void *h);
int (*srslte_rf_stop_rx_stream)(void *h); int (*srslte_rf_stop_rx_stream)(void *h);
int (*srslte_rf_start_tx_stream)(void *h);
int (*srslte_rf_stop_tx_stream)(void *h);
void (*srslte_rf_flush_buffer)(void *h); void (*srslte_rf_flush_buffer)(void *h);
bool (*srslte_rf_has_rssi)(void *h); bool (*srslte_rf_has_rssi)(void *h);
float (*srslte_rf_get_rssi)(void *h); float (*srslte_rf_get_rssi)(void *h);
@ -77,8 +75,6 @@ static rf_dev_t dev_uhd = {
rf_uhd_rx_wait_lo_locked, rf_uhd_rx_wait_lo_locked,
rf_uhd_start_rx_stream, rf_uhd_start_rx_stream,
rf_uhd_stop_rx_stream, rf_uhd_stop_rx_stream,
rf_uhd_start_tx_stream,
rf_uhd_stop_tx_stream,
rf_uhd_flush_buffer, rf_uhd_flush_buffer,
rf_uhd_has_rssi, rf_uhd_has_rssi,
rf_uhd_get_rssi, rf_uhd_get_rssi,
@ -117,8 +113,6 @@ static rf_dev_t dev_blade = {
rf_blade_rx_wait_lo_locked, rf_blade_rx_wait_lo_locked,
rf_blade_start_rx_stream, rf_blade_start_rx_stream,
rf_blade_stop_rx_stream, rf_blade_stop_rx_stream,
rf_blade_start_tx_stream,
rf_blade_stop_tx_stream,
rf_blade_flush_buffer, rf_blade_flush_buffer,
rf_blade_has_rssi, rf_blade_has_rssi,
rf_blade_get_rssi, rf_blade_get_rssi,
@ -156,8 +150,6 @@ static rf_dev_t dev_soapy = {
rf_soapy_rx_wait_lo_locked, rf_soapy_rx_wait_lo_locked,
rf_soapy_start_rx_stream, rf_soapy_start_rx_stream,
rf_soapy_stop_rx_stream, rf_soapy_stop_rx_stream,
rf_soapy_start_tx_stream,
rf_soapy_stop_tx_stream,
rf_soapy_flush_buffer, rf_soapy_flush_buffer,
rf_soapy_has_rssi, rf_soapy_has_rssi,
rf_soapy_get_rssi, rf_soapy_get_rssi,

@ -154,21 +154,11 @@ int srslte_rf_start_rx_stream(srslte_rf_t *rf)
return ((rf_dev_t*) rf->dev)->srslte_rf_start_rx_stream(rf->handler); return ((rf_dev_t*) rf->dev)->srslte_rf_start_rx_stream(rf->handler);
} }
int srslte_rf_start_tx_stream(srslte_rf_t *rf)
{
return ((rf_dev_t*) rf->dev)->srslte_rf_start_tx_stream(rf->handler);
}
int srslte_rf_stop_rx_stream(srslte_rf_t *rf) int srslte_rf_stop_rx_stream(srslte_rf_t *rf)
{ {
return ((rf_dev_t*) rf->dev)->srslte_rf_stop_rx_stream(rf->handler); return ((rf_dev_t*) rf->dev)->srslte_rf_stop_rx_stream(rf->handler);
} }
int srslte_rf_stop_tx_stream(srslte_rf_t *rf)
{
return ((rf_dev_t*) rf->dev)->srslte_rf_stop_tx_stream(rf->handler);
}
void srslte_rf_flush_buffer(srslte_rf_t *rf) void srslte_rf_flush_buffer(srslte_rf_t *rf)
{ {
((rf_dev_t*) rf->dev)->srslte_rf_flush_buffer(rf->handler); ((rf_dev_t*) rf->dev)->srslte_rf_flush_buffer(rf->handler);

@ -49,6 +49,8 @@ typedef struct {
cf_t zero_mem[64*1024]; cf_t zero_mem[64*1024];
int soapy_error(void *h) int soapy_error(void *h)
{ {
return 0; return 0;
@ -84,11 +86,6 @@ void rf_soapy_register_error_handler(void *notused, srslte_rf_error_handler_t ne
// not supported // not supported
} }
static bool isLocked(rf_soapy_handler_t *handler, char *sensor_name, void *value_h)
{
// not supported
return true;
}
char* rf_soapy_devname(void* h) char* rf_soapy_devname(void* h)
@ -129,12 +126,24 @@ int rf_soapy_start_rx_stream(void *h)
int rf_soapy_start_tx_stream(void *h) int rf_soapy_start_tx_stream(void *h)
{ {
<<<<<<< HEAD
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if(SoapySDRDevice_activateStream(handler->device, handler->txStream, 0, 0, 0) != 0) if(SoapySDRDevice_activateStream(handler->device, handler->txStream, 0, 0, 0) != 0)
return SRSLTE_ERROR; return SRSLTE_ERROR;
handler->tx_stream_active = true; handler->tx_stream_active = true;
=======
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if (SoapySDRDevice_setupStream(handler->device, &(handler->txStream), SOAPY_SDR_TX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) {
printf("setupStream fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR;
}
if(SoapySDRDevice_activateStream(handler->device, handler->txStream, 0, 0, 0) != 0)
return SRSLTE_ERROR;
>>>>>>> 266f1b08fbf508cda5f1d2db3451776fd14c56cb
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -216,6 +225,7 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
bzero(handler, sizeof(rf_soapy_handler_t)); bzero(handler, sizeof(rf_soapy_handler_t));
*h = handler; *h = handler;
handler->device = sdr; handler->device = sdr;
<<<<<<< HEAD
handler->tx_stream_active = false; handler->tx_stream_active = false;
if (SoapySDRDevice_setupStream(handler->device, &(handler->rxStream), SOAPY_SDR_RX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) { if (SoapySDRDevice_setupStream(handler->device, &(handler->rxStream), SOAPY_SDR_RX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) {
printf("setupStream fail: %s\n", SoapySDRDevice_lastError()); printf("setupStream fail: %s\n", SoapySDRDevice_lastError());
@ -224,11 +234,18 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
if (SoapySDRDevice_setupStream(handler->device, &(handler->txStream), SOAPY_SDR_TX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) { if (SoapySDRDevice_setupStream(handler->device, &(handler->txStream), SOAPY_SDR_TX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) {
=======
if (SoapySDRDevice_setupStream(handler->device, &(handler->rxStream), SOAPY_SDR_RX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) {
>>>>>>> 266f1b08fbf508cda5f1d2db3451776fd14c56cb
printf("setupStream fail: %s\n", SoapySDRDevice_lastError()); printf("setupStream fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
<<<<<<< HEAD
=======
>>>>>>> 266f1b08fbf508cda5f1d2db3451776fd14c56cb
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -313,7 +330,11 @@ double rf_soapy_set_tx_gain(void *h, double gain)
printf("setGain fail: %s\n", SoapySDRDevice_lastError()); printf("setGain fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
<<<<<<< HEAD
return rf_soapy_get_tx_gain(h); return rf_soapy_get_tx_gain(h);
=======
return rf_soapy_get_rx_gain(h);
>>>>>>> 266f1b08fbf508cda5f1d2db3451776fd14c56cb
} }
@ -351,7 +372,11 @@ double rf_soapy_set_tx_freq(void *h, double freq)
printf("setFrequency fail: %s\n", SoapySDRDevice_lastError()); printf("setFrequency fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
<<<<<<< HEAD
return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_TX, 0); return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_TX, 0);
=======
return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0);
>>>>>>> 266f1b08fbf508cda5f1d2db3451776fd14c56cb
} }
@ -423,6 +448,7 @@ int rf_soapy_recv_with_time(void *h,
{ {
return rf_soapy_recv_with_time_multi(h, &data, nsamples, blocking, secs, frac_secs); return rf_soapy_recv_with_time_multi(h, &data, nsamples, blocking, secs, frac_secs);
} }
<<<<<<< HEAD
int rf_soapy_send_timed(void *h, int rf_soapy_send_timed(void *h,
@ -474,5 +500,28 @@ int rf_soapy_send_timed(void *h,
return ret; return ret;
=======
>>>>>>> 266f1b08fbf508cda5f1d2db3451776fd14c56cb
int rf_soapy_send_timed(void *h,
void *data,
int nsamples,
time_t secs,
double frac_secs,
bool has_time_spec,
bool blocking,
bool is_start_of_burst,
bool is_end_of_burst)
{
int flags;
long long timeNs;
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
timeNs = secs * 1000000000;
timeNs = timeNs + (frac_secs * 1000000000);
int ret = SoapySDRDevice_writeStream(handler->device, handler->txStream, data, nsamples, &flags, timeNs, 100000);
if(ret != nsamples)
return SRSLTE_ERROR;
return ret;
} }

@ -49,10 +49,6 @@ SRSLTE_API int rf_soapy_start_rx_stream(void *h);
SRSLTE_API int rf_soapy_stop_rx_stream(void *h); SRSLTE_API int rf_soapy_stop_rx_stream(void *h);
SRSLTE_API int rf_soapy_start_tx_stream(void *h);
SRSLTE_API int rf_soapy_stop_tx_stream(void *h);
SRSLTE_API void rf_soapy_flush_buffer(void *h); SRSLTE_API void rf_soapy_flush_buffer(void *h);
SRSLTE_API bool rf_soapy_has_rssi(void *h); SRSLTE_API bool rf_soapy_has_rssi(void *h);

@ -235,17 +235,6 @@ int rf_uhd_start_rx_stream(void *h)
return 0; return 0;
} }
int rf_uhd_start_tx_stream(void *h)
{
return 0;
}
int rf_uhd_stop_tx_stream(void *h)
{
return 0;
}
int rf_uhd_stop_rx_stream(void *h) int rf_uhd_stop_rx_stream(void *h)
{ {
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;

@ -51,10 +51,6 @@ SRSLTE_API void rf_uhd_set_rx_cal(void *h, srslte_rf_cal_t *cal);
SRSLTE_API int rf_uhd_start_rx_stream(void *h); SRSLTE_API int rf_uhd_start_rx_stream(void *h);
SRSLTE_API int rf_uhd_start_tx_stream(void *h);
SRSLTE_API int rf_uhd_stop_tx_stream(void *h);
SRSLTE_API int rf_uhd_start_rx_stream_nsamples(void *h, SRSLTE_API int rf_uhd_start_rx_stream_nsamples(void *h,
uint32_t nsamples); uint32_t nsamples);

@ -44,13 +44,14 @@ gw::gw()
:if_up(false) :if_up(false)
{} {}
void gw::init(srsue::pdcp_interface_gw *pdcp_, srsue::rrc_interface_gw *rrc_, srsue::ue_interface *ue_, log *gw_log_) void gw::init(srsue::pdcp_interface_gw *pdcp_, srsue::rrc_interface_gw *rrc_, srsue::ue_interface *ue_, log *gw_log_, uint32_t lcid_)
{ {
pool = byte_buffer_pool::get_instance(); pool = byte_buffer_pool::get_instance();
pdcp = pdcp_; pdcp = pdcp_;
rrc = rrc_; rrc = rrc_;
ue = ue_; ue = ue_;
gw_log = gw_log_; gw_log = gw_log_;
lcid = lcid_;
run_enable = true; run_enable = true;
gettimeofday(&metrics_time[1], NULL); gettimeofday(&metrics_time[1], NULL);
@ -261,7 +262,7 @@ void gw::run_thread()
// Send PDU directly to PDCP // Send PDU directly to PDCP
pdu->set_timestamp(); pdu->set_timestamp();
ul_tput_bytes += pdu->N_bytes; ul_tput_bytes += pdu->N_bytes;
pdcp->write_sdu(RB_ID_DRB1, pdu); pdcp->write_sdu(lcid, pdu);
do { do {
pdu = pool_allocate; pdu = pool_allocate;

@ -32,15 +32,22 @@ namespace srslte {
pdcp::pdcp() pdcp::pdcp()
{} {}
void pdcp::init(srsue::rlc_interface_pdcp *rlc_, srsue::rrc_interface_pdcp *rrc_, srsue::gw_interface_pdcp *gw_, log *pdcp_log_, uint8_t direction_) void pdcp::init(srsue::rlc_interface_pdcp *rlc_, srsue::rrc_interface_pdcp *rrc_, srsue::gw_interface_pdcp *gw_, log *pdcp_log_, uint32_t lcid_, uint8_t direction_)
{ {
rlc = rlc_; rlc = rlc_;
rrc = rrc_; rrc = rrc_;
gw = gw_; gw = gw_;
pdcp_log = pdcp_log_; pdcp_log = pdcp_log_;
lcid = lcid_;
direction = direction_; direction = direction_;
pdcp_array[0].init(rlc, rrc, gw, pdcp_log, RB_ID_SRB0, direction); // SRB0 // Default config
srslte_pdcp_config_t cnfg;
cnfg.is_control = false;
cnfg.is_data = false;
cnfg.direction = direction_;
pdcp_array[0].init(rlc, rrc, gw, pdcp_log, lcid, cnfg);
} }
void pdcp::stop() void pdcp::stop()
@ -52,7 +59,7 @@ void pdcp::reset()
pdcp_array[i].reset(); pdcp_array[i].reset();
} }
pdcp_array[0].init(rlc, rrc, gw, pdcp_log, RB_ID_SRB0, direction); // SRB0 pdcp_array[0].init(rlc, rrc, gw, pdcp_log, lcid, direction);
} }
/******************************************************************************* /*******************************************************************************
@ -64,17 +71,17 @@ void pdcp::write_sdu(uint32_t lcid, byte_buffer_t *sdu)
pdcp_array[lcid].write_sdu(sdu); pdcp_array[lcid].write_sdu(sdu);
} }
void pdcp::add_bearer(uint32_t lcid, LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg) void pdcp::add_bearer(uint32_t lcid, srslte_pdcp_config_t cfg)
{ {
if(lcid < 0 || lcid >= SRSLTE_N_RADIO_BEARERS) { if(lcid >= SRSLTE_N_RADIO_BEARERS) {
pdcp_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_RADIO_BEARERS, lcid); pdcp_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_RADIO_BEARERS, lcid);
return; return;
} }
if (!pdcp_array[lcid].is_active()) { if (!pdcp_array[lcid].is_active()) {
pdcp_array[lcid].init(rlc, rrc, gw, pdcp_log, lcid, direction, cnfg); pdcp_array[lcid].init(rlc, rrc, gw, pdcp_log, lcid, cfg);
pdcp_log->info("Added bearer %s\n", rb_id_text[lcid]); pdcp_log->info("Added bearer %s\n", rrc->get_rb_name(lcid).c_str());
} else { } else {
pdcp_log->warning("Bearer %s already configured. Reconfiguration not supported\n", rb_id_text[lcid]); pdcp_log->warning("Bearer %s already configured. Reconfiguration not supported\n", rrc->get_rb_name(lcid).c_str());
} }
} }
@ -116,7 +123,7 @@ void pdcp::write_pdu_pcch(byte_buffer_t *sdu)
*******************************************************************************/ *******************************************************************************/
bool pdcp::valid_lcid(uint32_t lcid) bool pdcp::valid_lcid(uint32_t lcid)
{ {
if(lcid < 0 || lcid >= SRSLTE_N_RADIO_BEARERS) { if(lcid >= SRSLTE_N_RADIO_BEARERS) {
pdcp_log->error("Radio bearer id must be in [0:%d] - %d", SRSLTE_N_RADIO_BEARERS, lcid); pdcp_log->error("Radio bearer id must be in [0:%d] - %d", SRSLTE_N_RADIO_BEARERS, lcid);
return false; return false;
} }

@ -34,8 +34,6 @@ pdcp_entity::pdcp_entity()
:active(false) :active(false)
,tx_count(0) ,tx_count(0)
,rx_count(0) ,rx_count(0)
,do_security(false)
,sn_len(12)
{ {
pool = byte_buffer_pool::get_instance(); pool = byte_buffer_pool::get_instance();
} }
@ -45,38 +43,27 @@ void pdcp_entity::init(srsue::rlc_interface_pdcp *rlc_,
srsue::gw_interface_pdcp *gw_, srsue::gw_interface_pdcp *gw_,
srslte::log *log_, srslte::log *log_,
uint32_t lcid_, uint32_t lcid_,
u_int8_t direction_, srslte_pdcp_config_t cfg_)
LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg)
{ {
rlc = rlc_; rlc = rlc_;
rrc = rrc_; rrc = rrc_;
gw = gw_; gw = gw_;
log = log_; log = log_;
lcid = lcid_; lcid = lcid_;
direction = direction_; cfg = cfg_;
active = true; active = true;
tx_count = 0; tx_count = 0;
rx_count = 0; rx_count = 0;
do_security = false;
if(cnfg) log->debug("Init %s\n", rrc->get_rb_name(lcid).c_str());
{
if(cnfg->rlc_um_pdcp_sn_size_present) {
if(LIBLTE_RRC_PDCP_SN_SIZE_7_BITS == cnfg->rlc_um_pdcp_sn_size) {
sn_len = 7;
}
}
// TODO: handle remainder of cnfg
}
log->debug("Init %s\n", rb_id_text[lcid]);
} }
void pdcp_entity::reset() void pdcp_entity::reset()
{ {
active = false; active = false;
if(log) if(log)
log->debug("Reset %s\n", rb_id_text[lcid]); log->debug("Reset %s\n", rrc->get_rb_name(lcid).c_str());
} }
bool pdcp_entity::is_active() bool pdcp_entity::is_active()
@ -87,44 +74,32 @@ bool pdcp_entity::is_active()
// RRC interface // RRC interface
void pdcp_entity::write_sdu(byte_buffer_t *sdu) void pdcp_entity::write_sdu(byte_buffer_t *sdu)
{ {
log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU, do_security = %s", rb_id_text[lcid], (do_security)?"true":"false"); log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU, do_security = %s", rrc->get_rb_name(lcid).c_str(), (cfg.do_security)?"true":"false");
// Handle SRB messages if (cfg.is_control) {
switch(lcid)
{
case RB_ID_SRB0:
rlc->write_sdu(lcid, sdu);
break;
case RB_ID_SRB1: // Intentional fall-through
case RB_ID_SRB2:
pdcp_pack_control_pdu(tx_count, sdu); pdcp_pack_control_pdu(tx_count, sdu);
if(do_security) if(cfg.do_security)
{ {
integrity_generate(&k_rrc_int[16], integrity_generate(&k_rrc_int[16],
tx_count, tx_count,
lcid-1, lcid-1,
direction, cfg.direction,
sdu->msg, sdu->msg,
sdu->N_bytes-4, sdu->N_bytes-4,
&sdu->msg[sdu->N_bytes-4]); &sdu->msg[sdu->N_bytes-4]);
} }
tx_count++; tx_count++;
rlc->write_sdu(lcid, sdu);
break;
} }
// Handle DRB messages if (cfg.is_data) {
if(lcid >= RB_ID_DRB1) if(12 == cfg.sn_len) {
{
if(12 == sn_len)
{
pdcp_pack_data_pdu_long_sn(tx_count++, sdu); pdcp_pack_data_pdu_long_sn(tx_count++, sdu);
} else { } else {
pdcp_pack_data_pdu_short_sn(tx_count++, sdu); pdcp_pack_data_pdu_short_sn(tx_count++, sdu);
} }
rlc->write_sdu(lcid, sdu);
} }
rlc->write_sdu(lcid, sdu);
} }
void pdcp_entity::config_security(uint8_t *k_rrc_enc_, void pdcp_entity::config_security(uint8_t *k_rrc_enc_,
@ -132,7 +107,7 @@ void pdcp_entity::config_security(uint8_t *k_rrc_enc_,
CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) INTEGRITY_ALGORITHM_ID_ENUM integ_algo_)
{ {
do_security = true; cfg.do_security = true;
for(int i=0; i<32; i++) for(int i=0; i<32; i++)
{ {
k_rrc_enc[i] = k_rrc_enc_[i]; k_rrc_enc[i] = k_rrc_enc_[i];
@ -145,37 +120,32 @@ void pdcp_entity::config_security(uint8_t *k_rrc_enc_,
// RLC interface // RLC interface
void pdcp_entity::write_pdu(byte_buffer_t *pdu) void pdcp_entity::write_pdu(byte_buffer_t *pdu)
{ {
// Handle SRB messages
switch(lcid)
{
case RB_ID_SRB0:
// Simply pass on to RRC
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", rb_id_text[lcid]);
rrc->write_pdu(RB_ID_SRB0, pdu);
break;
case RB_ID_SRB1: // Intentional fall-through
case RB_ID_SRB2:
uint32_t sn;
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", rb_id_text[lcid]);
pdcp_unpack_control_pdu(pdu, &sn);
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s SDU SN: %d",
rb_id_text[lcid], sn);
rrc->write_pdu(lcid, pdu);
break;
}
// Handle DRB messages
if(lcid >= RB_ID_DRB1)
{
if (cfg.is_data) {
uint32_t sn; uint32_t sn;
if(12 == sn_len) if(12 == cfg.sn_len)
{ {
pdcp_unpack_data_pdu_long_sn(pdu, &sn); pdcp_unpack_data_pdu_long_sn(pdu, &sn);
} else { } else {
pdcp_unpack_data_pdu_short_sn(pdu, &sn); pdcp_unpack_data_pdu_short_sn(pdu, &sn);
} }
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU: %d", rb_id_text[lcid], sn); log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU: %d", rrc->get_rb_name(lcid).c_str(), sn);
gw->write_pdu(lcid, pdu); gw->write_pdu(lcid, pdu);
} else {
if (cfg.is_control) {
uint32_t sn;
pdcp_unpack_control_pdu(pdu, &sn);
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s SDU SN: %d",
rrc->get_rb_name(lcid).c_str(), sn);
} else {
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", rrc->get_rb_name(lcid).c_str());
}
// pass to RRC
rrc->write_pdu(lcid, pdu);
} }
} }

@ -41,18 +41,20 @@ void rlc::init(srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_, srsue::rrc_interface_rlc *rrc_,
srsue::ue_interface *ue_, srsue::ue_interface *ue_,
log *rlc_log_, log *rlc_log_,
mac_interface_timers *mac_timers_) mac_interface_timers *mac_timers_,
uint32_t lcid_)
{ {
pdcp = pdcp_; pdcp = pdcp_;
rrc = rrc_; rrc = rrc_;
ue = ue_; ue = ue_;
rlc_log = rlc_log_; rlc_log = rlc_log_;
mac_timers = mac_timers_; mac_timers = mac_timers_;
default_lcid = lcid_;
gettimeofday(&metrics_time[1], NULL); gettimeofday(&metrics_time[1], NULL);
reset_metrics(); reset_metrics();
rlc_array[0].init(RLC_MODE_TM, rlc_log, RB_ID_SRB0, pdcp, rrc, mac_timers); // SRB0 rlc_array[0].init(RLC_MODE_TM, rlc_log, default_lcid, pdcp, rrc, mac_timers); // SRB0
} }
void rlc::reset_metrics() void rlc::reset_metrics()
@ -97,7 +99,7 @@ void rlc::reset()
rlc_array[i].reset(); rlc_array[i].reset();
} }
rlc_array[0].init(RLC_MODE_TM, rlc_log, RB_ID_SRB0, pdcp, rrc, mac_timers); // SRB0 rlc_array[0].init(RLC_MODE_TM, rlc_log, default_lcid, pdcp, rrc, mac_timers); // SRB0
} }
/******************************************************************************* /*******************************************************************************
@ -110,6 +112,11 @@ void rlc::write_sdu(uint32_t lcid, byte_buffer_t *sdu)
} }
} }
std::string rlc::get_rb_name(uint32_t lcid)
{
return rrc->get_rb_name(lcid);
}
/******************************************************************************* /*******************************************************************************
MAC interface MAC interface
*******************************************************************************/ *******************************************************************************/
@ -186,11 +193,10 @@ void rlc::write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes)
*******************************************************************************/ *******************************************************************************/
void rlc::add_bearer(uint32_t lcid) void rlc::add_bearer(uint32_t lcid)
{ {
// No config provided - use defaults for lcid // No config provided - use defaults for SRB1 and SRB2
LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; if(lcid < 3) {
if(RB_ID_SRB1 == lcid || RB_ID_SRB2 == lcid)
{
if (!rlc_array[lcid].active()) { if (!rlc_array[lcid].active()) {
LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg;
cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM;
cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS45; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS45;
cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_INFINITY; cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_INFINITY;
@ -198,28 +204,27 @@ void rlc::add_bearer(uint32_t lcid)
cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4;
cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS35; cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS35;
cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS0; cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS0;
add_bearer(lcid, &cnfg); add_bearer(lcid, srslte_rlc_config_t(&cnfg));
} else { } else {
rlc_log->warning("Bearer %s already configured. Reconfiguration not supported\n", rb_id_text[lcid]); rlc_log->warning("Bearer %s already configured. Reconfiguration not supported\n", get_rb_name(lcid).c_str());
} }
}else{ }else{
rlc_log->error("Radio bearer %s does not support default RLC configuration.", rlc_log->error("Radio bearer %s does not support default RLC configuration.\n",
rb_id_text[lcid]); get_rb_name(lcid).c_str());
} }
} }
void rlc::add_bearer(uint32_t lcid, LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg)
{ {
if(lcid < 0 || lcid >= SRSLTE_N_RADIO_BEARERS) { if(lcid < 0 || lcid >= SRSLTE_N_RADIO_BEARERS) {
rlc_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_RADIO_BEARERS, lcid); rlc_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_RADIO_BEARERS, lcid);
return; return;
} }
if (!rlc_array[lcid].active()) { if (!rlc_array[lcid].active()) {
rlc_log->info("Adding radio bearer %s with mode %s\n", rlc_log->info("Adding radio bearer %s with mode %s\n",
rb_id_text[lcid], liblte_rrc_rlc_mode_text[cnfg->rlc_mode]); get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg.rlc_mode]);
switch(cnfg->rlc_mode) switch(cnfg.rlc_mode)
{ {
case LIBLTE_RRC_RLC_MODE_AM: case LIBLTE_RRC_RLC_MODE_AM:
rlc_array[lcid].init(RLC_MODE_AM, rlc_log, lcid, pdcp, rrc, mac_timers); rlc_array[lcid].init(RLC_MODE_AM, rlc_log, lcid, pdcp, rrc, mac_timers);
@ -238,7 +243,7 @@ void rlc::add_bearer(uint32_t lcid, LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg)
return; return;
} }
} else { } else {
rlc_log->warning("Bearer %s already created.\n", rb_id_text[lcid]); rlc_log->warning("Bearer %s already created.\n", get_rb_name(lcid).c_str());
} }
rlc_array[lcid].configure(cnfg); rlc_array[lcid].configure(cnfg);

@ -74,20 +74,13 @@ void rlc_am::init(srslte::log *log_,
rrc = rrc_; rrc = rrc_;
} }
void rlc_am::configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) void rlc_am::configure(srslte_rlc_config_t cfg_)
{ {
t_poll_retx = liblte_rrc_t_poll_retransmit_num[cnfg->ul_am_rlc.t_poll_retx]; cfg = cfg_.am;
poll_pdu = liblte_rrc_poll_pdu_num[cnfg->ul_am_rlc.poll_pdu];
poll_byte = liblte_rrc_poll_byte_num[cnfg->ul_am_rlc.poll_byte]*1000; // KB
max_retx_thresh = liblte_rrc_max_retx_threshold_num[cnfg->ul_am_rlc.max_retx_thresh];
t_reordering = liblte_rrc_t_reordering_num[cnfg->dl_am_rlc.t_reordering];
t_status_prohibit = liblte_rrc_t_status_prohibit_num[cnfg->dl_am_rlc.t_status_prohibit];
log->info("%s configured: t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, " log->info("%s configured: t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, "
"t_reordering=%d, t_status_prohibit=%d\n", "t_reordering=%d, t_status_prohibit=%d\n",
rb_id_text[lcid], t_poll_retx, poll_pdu, poll_byte, max_retx_thresh, rrc->get_rb_name(lcid).c_str(), cfg.t_poll_retx, cfg.poll_pdu, cfg.poll_byte, cfg.max_retx_thresh,
t_reordering, t_status_prohibit); cfg.t_reordering, cfg.t_status_prohibit);
} }
@ -176,7 +169,7 @@ uint32_t rlc_am::get_bearer()
void rlc_am::write_sdu(byte_buffer_t *sdu) void rlc_am::write_sdu(byte_buffer_t *sdu)
{ {
log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rb_id_text[lcid]); log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rrc->get_rb_name(lcid).c_str());
tx_sdu_queue.write(sdu); tx_sdu_queue.write(sdu);
} }
@ -225,7 +218,7 @@ uint32_t rlc_am::get_total_buffer_state()
// Room needed for fixed header? // Room needed for fixed header?
if(n_bytes > 0) { if(n_bytes > 0) {
n_bytes += 2; n_bytes += 2;
log->debug("Buffer state - tx SDUs: %d bytes\n", n_bytes); log->debug("Total buffer state LCID=%d - tx SDUs: %d bytes\n", lcid, n_bytes);
} }
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
@ -242,7 +235,7 @@ uint32_t rlc_am::get_buffer_state()
check_reordering_timeout(); check_reordering_timeout();
if(do_status && !status_prohibited()) { if(do_status && !status_prohibited()) {
n_bytes = prepare_status(); n_bytes = prepare_status();
log->debug("Buffer state - status report: %d bytes\n", n_bytes); log->debug("Buffer state LCID=%d - status report: %d bytes\n", lcid, n_bytes);
goto unlock_and_return; goto unlock_and_return;
} }
@ -275,7 +268,7 @@ uint32_t rlc_am::get_buffer_state()
// Room needed for fixed header? // Room needed for fixed header?
if(n_bytes > 0) { if(n_bytes > 0) {
n_bytes += 2; n_bytes += 2;
log->debug("Buffer state - tx SDUs: %d bytes\n", n_bytes); log->debug("Buffer state LCID=%d - tx SDUs: %d bytes\n", lcid, n_bytes);
} }
unlock_and_return: unlock_and_return:
@ -347,7 +340,7 @@ void rlc_am::check_reordering_timeout()
if(reordering_timeout.is_running() && reordering_timeout.expired()) if(reordering_timeout.is_running() && reordering_timeout.expired())
{ {
reordering_timeout.reset(); reordering_timeout.reset();
log->debug("%s reordering timeout expiry - updating vr_ms\n", rb_id_text[lcid]); log->debug("%s reordering timeout expiry - updating vr_ms\n", rrc->get_rb_name(lcid).c_str());
// 36.322 v10 Section 5.1.3.2.4 // 36.322 v10 Section 5.1.3.2.4
vr_ms = vr_x; vr_ms = vr_x;
@ -362,7 +355,7 @@ void rlc_am::check_reordering_timeout()
if(RX_MOD_BASE(vr_h) > RX_MOD_BASE(vr_ms)) if(RX_MOD_BASE(vr_h) > RX_MOD_BASE(vr_ms))
{ {
reordering_timeout.start(t_reordering); reordering_timeout.start(cfg.t_reordering);
vr_x = vr_h; vr_x = vr_h;
} }
@ -376,9 +369,9 @@ void rlc_am::check_reordering_timeout()
bool rlc_am::poll_required() bool rlc_am::poll_required()
{ {
if(poll_pdu > 0 && pdu_without_poll > (uint32_t)poll_pdu) if(cfg.poll_pdu > 0 && pdu_without_poll > (uint32_t)cfg.poll_pdu)
return true; return true;
if(poll_byte > 0 && byte_without_poll > (uint32_t)poll_byte) if(cfg.poll_byte > 0 && byte_without_poll > (uint32_t)cfg.poll_byte)
return true; return true;
if(poll_retx()) if(poll_retx())
return true; return true;
@ -409,18 +402,18 @@ int rlc_am::build_status_pdu(uint8_t *payload, uint32_t nof_bytes)
if(pdu_len > 0 && nof_bytes >= (uint32_t)pdu_len) if(pdu_len > 0 && nof_bytes >= (uint32_t)pdu_len)
{ {
log->info("%s Tx status PDU - %s\n", log->info("%s Tx status PDU - %s\n",
rb_id_text[lcid], rlc_am_to_string(&status).c_str()); rrc->get_rb_name(lcid).c_str(), rlc_am_to_string(&status).c_str());
do_status = false; do_status = false;
poll_received = false; poll_received = false;
if(t_status_prohibit > 0) if(cfg.t_status_prohibit > 0)
status_prohibit_timeout.start(t_status_prohibit); status_prohibit_timeout.start(cfg.t_status_prohibit);
debug_state(); debug_state();
return rlc_am_write_status_pdu(&status, payload); return rlc_am_write_status_pdu(&status, payload);
}else{ }else{
log->warning("%s Cannot tx status PDU - %d bytes available, %d bytes required\n", log->warning("%s Cannot tx status PDU - %d bytes available, %d bytes required\n",
rb_id_text[lcid], nof_bytes, pdu_len); rrc->get_rb_name(lcid).c_str(), nof_bytes, pdu_len);
return 0; return 0;
} }
} }
@ -437,7 +430,7 @@ int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes)
// Is resegmentation needed? // Is resegmentation needed?
if(retx.is_segment || required_buffer_size(retx) > (int)nof_bytes) { if(retx.is_segment || required_buffer_size(retx) > (int)nof_bytes) {
log->debug("%s build_retx_pdu - resegmentation required\n", rb_id_text[lcid]); log->debug("%s build_retx_pdu - resegmentation required\n", rrc->get_rb_name(lcid).c_str());
return build_segment(payload, nof_bytes, retx); return build_segment(payload, nof_bytes, retx);
} }
@ -450,7 +443,7 @@ int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes)
poll_sn = vt_s; poll_sn = vt_s;
pdu_without_poll = 0; pdu_without_poll = 0;
byte_without_poll = 0; byte_without_poll = 0;
poll_retx_timeout.start(t_poll_retx); poll_retx_timeout.start(cfg.t_poll_retx);
} }
uint8_t *ptr = payload; uint8_t *ptr = payload;
@ -459,10 +452,10 @@ int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes)
retx_queue.pop_front(); retx_queue.pop_front();
tx_window[retx.sn].retx_count++; tx_window[retx.sn].retx_count++;
if(tx_window[retx.sn].retx_count >= max_retx_thresh) if(tx_window[retx.sn].retx_count >= cfg.max_retx_thresh)
rrc->max_retx_attempted(); rrc->max_retx_attempted();
log->info("%s Retx PDU scheduled for tx. SN: %d, retx count: %d\n", log->info("%s Retx PDU scheduled for tx. SN: %d, retx count: %d\n",
rb_id_text[lcid], retx.sn, tx_window[retx.sn].retx_count); rrc->get_rb_name(lcid).c_str(), retx.sn, tx_window[retx.sn].retx_count);
debug_state(); debug_state();
return (ptr-payload) + tx_window[retx.sn].buf->N_bytes; return (ptr-payload) + tx_window[retx.sn].buf->N_bytes;
@ -495,7 +488,7 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r
if(nof_bytes <= head_len) if(nof_bytes <= head_len)
{ {
log->warning("%s Cannot build a PDU segment - %d bytes available, %d bytes required for header\n", log->warning("%s Cannot build a PDU segment - %d bytes available, %d bytes required for header\n",
rb_id_text[lcid], nof_bytes, head_len); rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len);
return 0; return 0;
} }
pdu_space = nof_bytes-head_len; pdu_space = nof_bytes-head_len;
@ -561,15 +554,15 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r
memcpy(ptr, data, len); memcpy(ptr, data, len);
log->info("%s Retx PDU segment scheduled for tx. SN: %d, SO: %d\n", log->info("%s Retx PDU segment scheduled for tx. SN: %d, SO: %d\n",
rb_id_text[lcid], retx.sn, retx.so_start); rrc->get_rb_name(lcid).c_str(), retx.sn, retx.so_start);
debug_state(); debug_state();
int pdu_len = (ptr-payload) + len; int pdu_len = (ptr-payload) + len;
if(pdu_len > (int)nof_bytes) { if(pdu_len > (int)nof_bytes) {
log->error("%s Retx PDU segment length error. Available: %d, Used: %d\n", log->error("%s Retx PDU segment length error. Available: %d, Used: %d\n",
rb_id_text[lcid], nof_bytes, pdu_len); rrc->get_rb_name(lcid).c_str(), nof_bytes, pdu_len);
log->debug("%s Retx PDU segment length error. Header len: %d, Payload len: %d, N_li: %d\n", log->debug("%s Retx PDU segment length error. Header len: %d, Payload len: %d, N_li: %d\n",
rb_id_text[lcid], (ptr-payload), len, new_header.N_li); rrc->get_rb_name(lcid).c_str(), (ptr-payload), len, new_header.N_li);
} }
return pdu_len; return pdu_len;
@ -617,13 +610,13 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
if(pdu_space <= head_len) if(pdu_space <= head_len)
{ {
log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n", log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n",
rb_id_text[lcid], nof_bytes, head_len); rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len);
pool->deallocate(pdu); pool->deallocate(pdu);
return 0; return 0;
} }
log->debug("%s Building PDU - pdu_space: %d, head_len: %d \n", log->debug("%s Building PDU - pdu_space: %d, head_len: %d \n",
rb_id_text[lcid], pdu_space, head_len); rrc->get_rb_name(lcid).c_str(), pdu_space, head_len);
// Check for SDU segment // Check for SDU segment
if(tx_sdu) if(tx_sdu)
@ -638,7 +631,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
if(tx_sdu->N_bytes == 0) if(tx_sdu->N_bytes == 0)
{ {
log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rb_id_text[lcid], tx_sdu->get_latency_us()); rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us());
pool->deallocate(tx_sdu); pool->deallocate(tx_sdu);
tx_sdu = NULL; tx_sdu = NULL;
} }
@ -649,7 +642,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU
log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n", log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n",
rb_id_text[lcid], to_move, pdu_space, head_len); rrc->get_rb_name(lcid).c_str(), to_move, pdu_space, head_len);
} }
// Pull SDUs from queue // Pull SDUs from queue
@ -673,7 +666,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
if(tx_sdu->N_bytes == 0) if(tx_sdu->N_bytes == 0)
{ {
log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rb_id_text[lcid], tx_sdu->get_latency_us()); rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us());
pool->deallocate(tx_sdu); pool->deallocate(tx_sdu);
tx_sdu = NULL; tx_sdu = NULL;
} }
@ -683,7 +676,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
pdu_space = 0; pdu_space = 0;
log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n", log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n",
rb_id_text[lcid], to_move, pdu_space, head_len); rrc->get_rb_name(lcid).c_str(), to_move, pdu_space, head_len);
} }
if(tx_sdu) if(tx_sdu)
@ -692,22 +685,22 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
// Set Poll bit // Set Poll bit
pdu_without_poll++; pdu_without_poll++;
byte_without_poll += (pdu->N_bytes + head_len); byte_without_poll += (pdu->N_bytes + head_len);
log->debug("%s pdu_without_poll: %d\n", rb_id_text[lcid], pdu_without_poll); log->debug("%s pdu_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), pdu_without_poll);
log->debug("%s byte_without_poll: %d\n", rb_id_text[lcid], byte_without_poll); log->debug("%s byte_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), byte_without_poll);
if(poll_required()) if(poll_required())
{ {
log->debug("%s setting poll bit to request status\n", rb_id_text[lcid]); log->debug("%s setting poll bit to request status\n", rrc->get_rb_name(lcid).c_str());
header.p = 1; header.p = 1;
poll_sn = vt_s; poll_sn = vt_s;
pdu_without_poll = 0; pdu_without_poll = 0;
byte_without_poll = 0; byte_without_poll = 0;
poll_retx_timeout.start(t_poll_retx); poll_retx_timeout.start(cfg.t_poll_retx);
} }
// Set SN // Set SN
header.sn = vt_s; header.sn = vt_s;
vt_s = (vt_s + 1)%MOD; vt_s = (vt_s + 1)%MOD;
log->info("%s PDU scheduled for tx. SN: %d\n", rb_id_text[lcid], header.sn); log->info("%s PDU scheduled for tx. SN: %d\n", rrc->get_rb_name(lcid).c_str(), header.sn);
// Place PDU in tx_window, write header and TX // Place PDU in tx_window, write header and TX
tx_window[header.sn].buf = pdu; tx_window[header.sn].buf = pdu;
@ -728,26 +721,26 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h
std::map<uint32_t, rlc_amd_rx_pdu_t>::iterator it; std::map<uint32_t, rlc_amd_rx_pdu_t>::iterator it;
log->info_hex(payload, nof_bytes, "%s Rx data PDU SN: %d", log->info_hex(payload, nof_bytes, "%s Rx data PDU SN: %d",
rb_id_text[lcid], header.sn); rrc->get_rb_name(lcid).c_str(), header.sn);
if(!inside_rx_window(header.sn)) { if(!inside_rx_window(header.sn)) {
if(header.p) { if(header.p) {
log->info("%s Status packet requested through polling bit\n", rb_id_text[lcid]); log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str());
do_status = true; do_status = true;
} }
log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", log->info("%s SN: %d outside rx window [%d:%d] - discarding\n",
rb_id_text[lcid], header.sn, vr_r, vr_mr); rrc->get_rb_name(lcid).c_str(), header.sn, vr_r, vr_mr);
return; return;
} }
it = rx_window.find(header.sn); it = rx_window.find(header.sn);
if(rx_window.end() != it) { if(rx_window.end() != it) {
if(header.p) { if(header.p) {
log->info("%s Status packet requested through polling bit\n", rb_id_text[lcid]); log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str());
do_status = true; do_status = true;
} }
log->info("%s Discarding duplicate SN: %d\n", log->info("%s Discarding duplicate SN: %d\n",
rb_id_text[lcid], header.sn); rrc->get_rb_name(lcid).c_str(), header.sn);
return; return;
} }
@ -780,7 +773,7 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h
// Check poll bit // Check poll bit
if(header.p) if(header.p)
{ {
log->info("%s Status packet requested through polling bit\n", rb_id_text[lcid]); log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str());
poll_received = true; poll_received = true;
// 36.322 v10 Section 5.2.3 // 36.322 v10 Section 5.2.3
@ -812,7 +805,7 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h
{ {
if(RX_MOD_BASE(vr_h) > RX_MOD_BASE(vr_r)) if(RX_MOD_BASE(vr_h) > RX_MOD_BASE(vr_r))
{ {
reordering_timeout.start(t_reordering); reordering_timeout.start(cfg.t_reordering);
vr_x = vr_h; vr_x = vr_h;
} }
} }
@ -825,16 +818,16 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a
std::map<uint32_t, rlc_amd_rx_pdu_segments_t>::iterator it; std::map<uint32_t, rlc_amd_rx_pdu_segments_t>::iterator it;
log->info_hex(payload, nof_bytes, "%s Rx data PDU segment. SN: %d, SO: %d", log->info_hex(payload, nof_bytes, "%s Rx data PDU segment. SN: %d, SO: %d",
rb_id_text[lcid], header.sn, header.so); rrc->get_rb_name(lcid).c_str(), header.sn, header.so);
// Check inside rx window // Check inside rx window
if(!inside_rx_window(header.sn)) { if(!inside_rx_window(header.sn)) {
if(header.p) { if(header.p) {
log->info("%s Status packet requested through polling bit\n", rb_id_text[lcid]); log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str());
do_status = true; do_status = true;
} }
log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", log->info("%s SN: %d outside rx window [%d:%d] - discarding\n",
rb_id_text[lcid], header.sn, vr_r, vr_mr); rrc->get_rb_name(lcid).c_str(), header.sn, vr_r, vr_mr);
return; return;
} }
@ -853,7 +846,7 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a
if(rx_segments.end() != it) { if(rx_segments.end() != it) {
if(header.p) { if(header.p) {
log->info("%s Status packet requested through polling bit\n", rb_id_text[lcid]); log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str());
do_status = true; do_status = true;
} }
@ -883,7 +876,7 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a
// Check poll bit // Check poll bit
if(header.p) if(header.p)
{ {
log->info("%s Status packet requested through polling bit\n", rb_id_text[lcid]); log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str());
poll_received = true; poll_received = true;
// 36.322 v10 Section 5.2.3 // 36.322 v10 Section 5.2.3
@ -901,12 +894,12 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a
void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes)
{ {
log->info_hex(payload, nof_bytes, "%s Rx control PDU", rb_id_text[lcid]); log->info_hex(payload, nof_bytes, "%s Rx control PDU", rrc->get_rb_name(lcid).c_str());
rlc_status_pdu_t status; rlc_status_pdu_t status;
rlc_am_read_status_pdu(payload, nof_bytes, &status); rlc_am_read_status_pdu(payload, nof_bytes, &status);
log->info("%s Rx Status PDU: %s\n", rb_id_text[lcid], rlc_am_to_string(&status).c_str()); log->info("%s Rx Status PDU: %s\n", rrc->get_rb_name(lcid).c_str(), rlc_am_to_string(&status).c_str());
poll_retx_timeout.reset(); poll_retx_timeout.reset();
@ -944,7 +937,7 @@ void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes)
} }
} else { } else {
log->warning("%s invalid segment NACK received for SN %d. so_start: %d, so_end: %d, N_bytes: %d\n", log->warning("%s invalid segment NACK received for SN %d. so_start: %d, so_end: %d, N_bytes: %d\n",
rb_id_text[lcid], i, status.nacks[j].so_start, status.nacks[j].so_end, it->second.buf->N_bytes); rrc->get_rb_name(lcid).c_str(), i, status.nacks[j].so_start, status.nacks[j].so_end, it->second.buf->N_bytes);
} }
} }
@ -998,7 +991,7 @@ void rlc_am::reassemble_rx_sdus()
rx_sdu->N_bytes += len; rx_sdu->N_bytes += len;
rx_window[vr_r].buf->msg += len; rx_window[vr_r].buf->msg += len;
rx_window[vr_r].buf->N_bytes -= len; rx_window[vr_r].buf->N_bytes -= len;
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rb_id_text[lcid]); log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rrc->get_rb_name(lcid).c_str());
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
@ -1014,7 +1007,7 @@ void rlc_am::reassemble_rx_sdus()
rx_sdu->N_bytes += rx_window[vr_r].buf->N_bytes; rx_sdu->N_bytes += rx_window[vr_r].buf->N_bytes;
if(rlc_am_end_aligned(rx_window[vr_r].header.fi)) if(rlc_am_end_aligned(rx_window[vr_r].header.fi))
{ {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rb_id_text[lcid]); log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rrc->get_rb_name(lcid).c_str());
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
@ -1058,7 +1051,7 @@ void rlc_am::debug_state()
{ {
log->debug("%s vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d " log->debug("%s vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d "
"vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d\n", "vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d\n",
rb_id_text[lcid], vt_a, vt_ms, vt_s, poll_sn, rrc->get_rb_name(lcid).c_str(), vt_a, vt_ms, vt_s, poll_sn,
vr_r, vr_mr, vr_x, vr_ms, vr_h); vr_r, vr_mr, vr_x, vr_ms, vr_h);
} }

@ -64,7 +64,7 @@ void rlc_entity::init(rlc_mode_t mode,
rlc->init(rlc_entity_log_, lcid_, pdcp_, rrc_, mac_timers_); rlc->init(rlc_entity_log_, lcid_, pdcp_, rrc_, mac_timers_);
} }
void rlc_entity::configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) void rlc_entity::configure(srslte_rlc_config_t cnfg)
{ {
if(rlc) if(rlc)
rlc->configure(cnfg); rlc->configure(cnfg);

@ -46,7 +46,7 @@ void rlc_tm::init(srslte::log *log_,
rrc = rrc_; rrc = rrc_;
} }
void rlc_tm::configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) void rlc_tm::configure(srslte_rlc_config_t cnfg)
{ {
log->error("Attempted to configure TM RLC entity"); log->error("Attempted to configure TM RLC entity");
} }
@ -79,7 +79,7 @@ uint32_t rlc_tm::get_bearer()
// PDCP interface // PDCP interface
void rlc_tm::write_sdu(byte_buffer_t *sdu) void rlc_tm::write_sdu(byte_buffer_t *sdu)
{ {
log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rb_id_text[lcid]); log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rrc->get_rb_name(lcid).c_str());
ul_queue.write(sdu); ul_queue.write(sdu);
} }
@ -99,7 +99,7 @@ int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes)
uint32_t pdu_size = ul_queue.size_tail_bytes(); uint32_t pdu_size = ul_queue.size_tail_bytes();
if(pdu_size > nof_bytes) if(pdu_size > nof_bytes)
{ {
log->error("TX %s PDU size larger than MAC opportunity\n", rb_id_text[lcid]); log->error("TX %s PDU size larger than MAC opportunity\n", rrc->get_rb_name(lcid).c_str());
return 0; return 0;
} }
byte_buffer_t *buf; byte_buffer_t *buf;
@ -107,13 +107,13 @@ int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes)
pdu_size = buf->N_bytes; pdu_size = buf->N_bytes;
memcpy(payload, buf->msg, buf->N_bytes); memcpy(payload, buf->msg, buf->N_bytes);
log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rb_id_text[lcid], buf->get_latency_us()); rrc->get_rb_name(lcid).c_str(), buf->get_latency_us());
pool->deallocate(buf); pool->deallocate(buf);
log->info_hex(payload, pdu_size, "TX %s, %s PDU", rb_id_text[lcid], rlc_mode_text[RLC_MODE_TM]); log->info_hex(payload, pdu_size, "TX %s, %s PDU", rrc->get_rb_name(lcid).c_str(), rlc_mode_text[RLC_MODE_TM]);
return pdu_size; return pdu_size;
} }
void rlc_tm:: write_pdu(uint8_t *payload, uint32_t nof_bytes) void rlc_tm::write_pdu(uint8_t *payload, uint32_t nof_bytes)
{ {
byte_buffer_t *buf = pool_allocate; byte_buffer_t *buf = pool_allocate;
memcpy(buf->msg, payload, nof_bytes); memcpy(buf->msg, payload, nof_bytes);

@ -27,7 +27,7 @@
#include "srslte/upper/rlc_um.h" #include "srslte/upper/rlc_um.h"
#define RX_MOD_BASE(x) (x-vr_uh-rx_window_size)%rx_mod #define RX_MOD_BASE(x) (x-vr_uh-cfg.rx_window_size)%cfg.rx_mod
namespace srslte { namespace srslte {
@ -65,41 +65,28 @@ void rlc_um::init(srslte::log *log_,
reordering_timeout_id = mac_timers->get_unique_id(); reordering_timeout_id = mac_timers->get_unique_id();
} }
void rlc_um::configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) void rlc_um::configure(srslte_rlc_config_t cnfg_)
{ {
switch(cnfg->rlc_mode) cfg = cnfg_.um;
switch(cnfg_.rlc_mode)
{ {
case LIBLTE_RRC_RLC_MODE_UM_BI: case LIBLTE_RRC_RLC_MODE_UM_BI:
t_reordering = liblte_rrc_t_reordering_num[cnfg->dl_um_bi_rlc.t_reordering];
rx_sn_field_length = (rlc_umd_sn_size_t)cnfg->dl_um_bi_rlc.sn_field_len;
rx_window_size = (RLC_UMD_SN_SIZE_5_BITS == rx_sn_field_length) ? 16 : 512;
rx_mod = (RLC_UMD_SN_SIZE_5_BITS == rx_sn_field_length) ? 32 : 1024;
tx_sn_field_length = (rlc_umd_sn_size_t)cnfg->ul_um_bi_rlc.sn_field_len;
tx_mod = (RLC_UMD_SN_SIZE_5_BITS == tx_sn_field_length) ? 32 : 1024;
log->info("%s configured in %s mode: " log->info("%s configured in %s mode: "
"t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n", "t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n",
rb_id_text[lcid], liblte_rrc_rlc_mode_text[cnfg->rlc_mode], rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
t_reordering, cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length], rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
rlc_umd_sn_size_num[rx_sn_field_length],
rlc_umd_sn_size_num[tx_sn_field_length]);
break; break;
case LIBLTE_RRC_RLC_MODE_UM_UNI_UL: case LIBLTE_RRC_RLC_MODE_UM_UNI_UL:
tx_sn_field_length = (rlc_umd_sn_size_t)cnfg->ul_um_uni_rlc.sn_field_len;
tx_mod = (RLC_UMD_SN_SIZE_5_BITS == tx_sn_field_length) ? 32 : 1024;
log->info("%s configured in %s mode: tx_sn_field_length=%u bits\n", log->info("%s configured in %s mode: tx_sn_field_length=%u bits\n",
rb_id_text[lcid], liblte_rrc_rlc_mode_text[cnfg->rlc_mode], rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
rlc_umd_sn_size_num[tx_sn_field_length]); rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
break; break;
case LIBLTE_RRC_RLC_MODE_UM_UNI_DL: case LIBLTE_RRC_RLC_MODE_UM_UNI_DL:
t_reordering = liblte_rrc_t_reordering_num[cnfg->dl_um_uni_rlc.t_reordering];
rx_sn_field_length = (rlc_umd_sn_size_t)cnfg->dl_um_uni_rlc.sn_field_len;
rx_window_size = (RLC_UMD_SN_SIZE_5_BITS == rx_sn_field_length) ? 16 : 512;
rx_mod = (RLC_UMD_SN_SIZE_5_BITS == rx_sn_field_length) ? 32 : 1024;
log->info("%s configured in %s mode: " log->info("%s configured in %s mode: "
"t_reordering=%d ms, rx_sn_field_length=%u bits\n", "t_reordering=%d ms, rx_sn_field_length=%u bits\n",
rb_id_text[lcid], liblte_rrc_rlc_mode_text[cnfg->rlc_mode], rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
liblte_rrc_t_reordering_num[t_reordering], cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
rlc_umd_sn_size_num[rx_sn_field_length]);
break; break;
default: default:
log->error("RLC configuration mode not recognized\n"); log->error("RLC configuration mode not recognized\n");
@ -159,7 +146,7 @@ uint32_t rlc_um::get_bearer()
void rlc_um::write_sdu(byte_buffer_t *sdu) void rlc_um::write_sdu(byte_buffer_t *sdu)
{ {
log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rb_id_text[lcid]); log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rrc->get_rb_name(lcid).c_str());
tx_sdu_queue.write(sdu); tx_sdu_queue.write(sdu);
} }
@ -222,14 +209,14 @@ void rlc_um::timer_expired(uint32_t timeout_id)
// 36.322 v10 Section 5.1.2.2.4 // 36.322 v10 Section 5.1.2.2.4
log->info("%s reordering timeout expiry - updating vr_ur and reassembling\n", log->info("%s reordering timeout expiry - updating vr_ur and reassembling\n",
rb_id_text[lcid]); rrc->get_rb_name(lcid).c_str());
log->warning("Lost PDU SN: %d\n", vr_ur); log->warning("Lost PDU SN: %d\n", vr_ur);
pdu_lost = true; pdu_lost = true;
rx_sdu->reset(); rx_sdu->reset();
while(RX_MOD_BASE(vr_ur) < RX_MOD_BASE(vr_ux)) while(RX_MOD_BASE(vr_ur) < RX_MOD_BASE(vr_ux))
{ {
vr_ur = (vr_ur + 1)%rx_mod; vr_ur = (vr_ur + 1)%cfg.rx_mod;
log->debug("Entering Reassemble from timeout id=%d\n", timeout_id); log->debug("Entering Reassemble from timeout id=%d\n", timeout_id);
reassemble_rx_sdus(); reassemble_rx_sdus();
log->debug("Finished reassemble from timeout id=%d\n", timeout_id); log->debug("Finished reassemble from timeout id=%d\n", timeout_id);
@ -237,7 +224,7 @@ void rlc_um::timer_expired(uint32_t timeout_id)
mac_timers->get(reordering_timeout_id)->stop(); mac_timers->get(reordering_timeout_id)->stop();
if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur)) if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur))
{ {
mac_timers->get(reordering_timeout_id)->set(this, t_reordering); mac_timers->get(reordering_timeout_id)->set(this, cfg.t_reordering);
mac_timers->get(reordering_timeout_id)->run(); mac_timers->get(reordering_timeout_id)->run();
vr_ux = vr_uh; vr_ux = vr_uh;
} }
@ -274,7 +261,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
header.fi = RLC_FI_FIELD_START_AND_END_ALIGNED; header.fi = RLC_FI_FIELD_START_AND_END_ALIGNED;
header.sn = vt_us; header.sn = vt_us;
header.N_li = 0; header.N_li = 0;
header.sn_size = tx_sn_field_length; header.sn_size = cfg.tx_sn_field_length;
uint32_t to_move = 0; uint32_t to_move = 0;
uint32_t last_li = 0; uint32_t last_li = 0;
@ -286,7 +273,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
if(pdu_space <= head_len) if(pdu_space <= head_len)
{ {
log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n", log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n",
rb_id_text[lcid], nof_bytes, head_len); rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len);
return 0; return 0;
} }
@ -296,7 +283,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
uint32_t space = pdu_space-head_len; uint32_t space = pdu_space-head_len;
to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n", log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n",
rb_id_text[lcid], to_move, tx_sdu->N_bytes); rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes);
memcpy(pdu_ptr, tx_sdu->msg, to_move); memcpy(pdu_ptr, tx_sdu->msg, to_move);
last_li = to_move; last_li = to_move;
pdu_ptr += to_move; pdu_ptr += to_move;
@ -306,7 +293,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
if(tx_sdu->N_bytes == 0) if(tx_sdu->N_bytes == 0)
{ {
log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rb_id_text[lcid], tx_sdu->get_latency_us()); rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us());
pool->deallocate(tx_sdu); pool->deallocate(tx_sdu);
tx_sdu = NULL; tx_sdu = NULL;
} }
@ -325,7 +312,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
uint32_t space = pdu_space-head_len; uint32_t space = pdu_space-head_len;
to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
log->debug("%s adding new SDU segment - %d bytes of %d remaining\n", log->debug("%s adding new SDU segment - %d bytes of %d remaining\n",
rb_id_text[lcid], to_move, tx_sdu->N_bytes); rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes);
memcpy(pdu_ptr, tx_sdu->msg, to_move); memcpy(pdu_ptr, tx_sdu->msg, to_move);
last_li = to_move; last_li = to_move;
pdu_ptr += to_move; pdu_ptr += to_move;
@ -335,7 +322,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
if(tx_sdu->N_bytes == 0) if(tx_sdu->N_bytes == 0)
{ {
log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rb_id_text[lcid], tx_sdu->get_latency_us()); rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us());
pool->deallocate(tx_sdu); pool->deallocate(tx_sdu);
tx_sdu = NULL; tx_sdu = NULL;
} }
@ -347,14 +334,14 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
// Set SN // Set SN
header.sn = vt_us; header.sn = vt_us;
vt_us = (vt_us + 1)%tx_mod; vt_us = (vt_us + 1)%cfg.tx_mod;
// Add header and TX // Add header and TX
log->debug("%s packing PDU with length %d\n", rb_id_text[lcid], pdu->N_bytes); log->debug("%s packing PDU with length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes);
rlc_um_write_data_pdu_header(&header, pdu); rlc_um_write_data_pdu_header(&header, pdu);
memcpy(payload, pdu->msg, pdu->N_bytes); memcpy(payload, pdu->msg, pdu->N_bytes);
uint32_t ret = pdu->N_bytes; uint32_t ret = pdu->N_bytes;
log->debug("%sreturning length %d\n", rb_id_text[lcid], pdu->N_bytes); log->debug("%sreturning length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes);
pool->deallocate(pdu); pool->deallocate(pdu);
debug_state(); debug_state();
@ -365,23 +352,23 @@ void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes)
{ {
std::map<uint32_t, rlc_umd_pdu_t>::iterator it; std::map<uint32_t, rlc_umd_pdu_t>::iterator it;
rlc_umd_pdu_header_t header; rlc_umd_pdu_header_t header;
rlc_um_read_data_pdu_header(payload, nof_bytes, rx_sn_field_length, &header); rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.rx_sn_field_length, &header);
log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d", log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d",
rb_id_text[lcid], header.sn); rrc->get_rb_name(lcid).c_str(), header.sn);
if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh-rx_window_size) && if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) &&
RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ur)) RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ur))
{ {
log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", log->info("%s SN: %d outside rx window [%d:%d] - discarding\n",
rb_id_text[lcid], header.sn, vr_ur, vr_uh); rrc->get_rb_name(lcid).c_str(), header.sn, vr_ur, vr_uh);
return; return;
} }
it = rx_window.find(header.sn); it = rx_window.find(header.sn);
if(rx_window.end() != it) if(rx_window.end() != it)
{ {
log->info("%s Discarding duplicate SN: %d\n", log->info("%s Discarding duplicate SN: %d\n",
rb_id_text[lcid], header.sn); rrc->get_rb_name(lcid).c_str(), header.sn);
return; return;
} }
@ -403,7 +390,7 @@ void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes)
// Update vr_uh // Update vr_uh
if(!inside_reordering_window(header.sn)) if(!inside_reordering_window(header.sn))
vr_uh = (header.sn + 1)%rx_mod; vr_uh = (header.sn + 1)%cfg.rx_mod;
// Reassemble and deliver SDUs, while updating vr_ur // Reassemble and deliver SDUs, while updating vr_ur
log->debug("Entering Reassemble from received PDU\n"); log->debug("Entering Reassemble from received PDU\n");
@ -423,7 +410,7 @@ void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes)
{ {
if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur)) if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur))
{ {
mac_timers->get(reordering_timeout_id)->set(this, t_reordering); mac_timers->get(reordering_timeout_id)->set(this, cfg.t_reordering);
mac_timers->get(reordering_timeout_id)->run(); mac_timers->get(reordering_timeout_id)->run();
vr_ux = vr_uh; vr_ux = vr_uh;
} }
@ -452,11 +439,11 @@ void rlc_um::reassemble_rx_sdus()
rx_sdu->N_bytes += len; rx_sdu->N_bytes += len;
rx_window[vr_ur].buf->msg += len; rx_window[vr_ur].buf->msg += len;
rx_window[vr_ur].buf->N_bytes -= len; rx_window[vr_ur].buf->N_bytes -= len;
if((pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) || (vr_ur != ((vr_ur_in_rx_sdu+1)%rx_mod))) { if((pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) || (vr_ur != ((vr_ur_in_rx_sdu+1)%cfg.rx_mod))) {
log->warning("Dropping remainder of lost PDU (lower edge middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); log->warning("Dropping remainder of lost PDU (lower edge middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu);
rx_sdu->reset(); rx_sdu->reset();
} else { } else {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", rb_id_text[lcid], vr_ur, i); log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i);
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
@ -476,7 +463,7 @@ void rlc_um::reassemble_rx_sdus()
log->warning("Dropping remainder of lost PDU (lower edge last segments)\n"); log->warning("Dropping remainder of lost PDU (lower edge last segments)\n");
rx_sdu->reset(); rx_sdu->reset();
} else { } else {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (lower edge last segments)", rb_id_text[lcid], vr_ur); log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (lower edge last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur);
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
@ -489,7 +476,7 @@ void rlc_um::reassemble_rx_sdus()
rx_window.erase(vr_ur); rx_window.erase(vr_ur);
} }
vr_ur = (vr_ur + 1)%rx_mod; vr_ur = (vr_ur + 1)%cfg.rx_mod;
} }
@ -502,15 +489,15 @@ void rlc_um::reassemble_rx_sdus()
int len = rx_window[vr_ur].header.li[i]; int len = rx_window[vr_ur].header.li[i];
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, len); memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, len);
log->debug("Concatenating %d bytes in to current length %d. rx_window remaining bytes=%d, vr_ur_in_rx_sdu=%d, vr_ur=%d, rx_mod=%d, last_mod=%d\n", log->debug("Concatenating %d bytes in to current length %d. rx_window remaining bytes=%d, vr_ur_in_rx_sdu=%d, vr_ur=%d, rx_mod=%d, last_mod=%d\n",
len, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes, vr_ur_in_rx_sdu, vr_ur, rx_mod, (vr_ur_in_rx_sdu+1)%rx_mod); len, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes, vr_ur_in_rx_sdu, vr_ur, cfg.rx_mod, (vr_ur_in_rx_sdu+1)%cfg.rx_mod);
rx_sdu->N_bytes += len; rx_sdu->N_bytes += len;
rx_window[vr_ur].buf->msg += len; rx_window[vr_ur].buf->msg += len;
rx_window[vr_ur].buf->N_bytes -= len; rx_window[vr_ur].buf->N_bytes -= len;
if((pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) || (vr_ur != ((vr_ur_in_rx_sdu+1)%rx_mod))) { if((pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) || (vr_ur != ((vr_ur_in_rx_sdu+1)%cfg.rx_mod))) {
log->warning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); log->warning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu);
rx_sdu->reset(); rx_sdu->reset();
} else { } else {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", rb_id_text[lcid], vr_ur, i); log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i);
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
@ -530,7 +517,7 @@ void rlc_um::reassemble_rx_sdus()
log->warning("Dropping remainder of lost PDU (update vr_ur last segments)\n"); log->warning("Dropping remainder of lost PDU (update vr_ur last segments)\n");
rx_sdu->reset(); rx_sdu->reset();
} else { } else {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", rb_id_text[lcid], vr_ur); log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur);
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
@ -542,13 +529,13 @@ void rlc_um::reassemble_rx_sdus()
pool->deallocate(rx_window[vr_ur].buf); pool->deallocate(rx_window[vr_ur].buf);
rx_window.erase(vr_ur); rx_window.erase(vr_ur);
vr_ur = (vr_ur + 1)%rx_mod; vr_ur = (vr_ur + 1)%cfg.rx_mod;
} }
} }
bool rlc_um::inside_reordering_window(uint16_t sn) bool rlc_um::inside_reordering_window(uint16_t sn)
{ {
if(RX_MOD_BASE(sn) >= RX_MOD_BASE(vr_uh-rx_window_size) && if(RX_MOD_BASE(sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) &&
RX_MOD_BASE(sn) < RX_MOD_BASE(vr_uh)) RX_MOD_BASE(sn) < RX_MOD_BASE(vr_uh))
{ {
return true; return true;
@ -560,7 +547,7 @@ bool rlc_um::inside_reordering_window(uint16_t sn)
void rlc_um::debug_state() void rlc_um::debug_state()
{ {
log->debug("%s vt_us = %d, vr_ur = %d, vr_ux = %d, vr_uh = %d \n", log->debug("%s vt_us = %d, vr_ur = %d, vr_ux = %d, vr_uh = %d \n",
rb_id_text[lcid], vt_us, vr_ur, vr_ux, vr_uh); rrc->get_rb_name(lcid).c_str(), vt_us, vr_ur, vr_ux, vr_uh);
} }

@ -67,6 +67,7 @@ public:
// RRC interface // RRC interface
void max_retx_attempted(){} void max_retx_attempted(){}
std::string get_rb_name(uint32_t lcid) { return std::string(""); }
byte_buffer_t *sdus[10]; byte_buffer_t *sdus[10];
int n_sdus; int n_sdus;
@ -101,6 +102,7 @@ void basic_test()
cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4;
cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25;
cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4;
cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); rlc1.configure(&cnfg);
rlc2.configure(&cnfg); rlc2.configure(&cnfg);
@ -180,6 +182,7 @@ void concat_test()
cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4;
cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25;
cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4;
cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); rlc1.configure(&cnfg);
rlc2.configure(&cnfg); rlc2.configure(&cnfg);
@ -244,6 +247,7 @@ void segment_test()
cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4;
cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25;
cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4;
cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); rlc1.configure(&cnfg);
rlc2.configure(&cnfg); rlc2.configure(&cnfg);
@ -326,6 +330,7 @@ void retx_test()
cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4;
cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25;
cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4;
cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); rlc1.configure(&cnfg);
rlc2.configure(&cnfg); rlc2.configure(&cnfg);
@ -422,6 +427,7 @@ void resegment_test_1()
cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4;
cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25;
cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4;
cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); rlc1.configure(&cnfg);
rlc2.configure(&cnfg); rlc2.configure(&cnfg);
@ -531,6 +537,7 @@ void resegment_test_2()
cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4;
cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25;
cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4;
cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); rlc1.configure(&cnfg);
rlc2.configure(&cnfg); rlc2.configure(&cnfg);
@ -637,6 +644,7 @@ void resegment_test_3()
cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4;
cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25;
cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4;
cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); rlc1.configure(&cnfg);
rlc2.configure(&cnfg); rlc2.configure(&cnfg);
@ -739,6 +747,7 @@ void resegment_test_4()
cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4;
cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25;
cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4;
cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); rlc1.configure(&cnfg);
rlc2.configure(&cnfg); rlc2.configure(&cnfg);
@ -841,6 +850,7 @@ void resegment_test_5()
cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4;
cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25;
cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4;
cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); rlc1.configure(&cnfg);
rlc2.configure(&cnfg); rlc2.configure(&cnfg);
@ -942,6 +952,7 @@ void resegment_test_6()
cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4;
cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25;
cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4;
cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); rlc1.configure(&cnfg);
rlc2.configure(&cnfg); rlc2.configure(&cnfg);

@ -71,6 +71,7 @@ public:
// RRC interface // RRC interface
void max_retx_attempted(){} void max_retx_attempted(){}
std::string get_rb_name(uint32_t lcid) { return std::string(""); }
byte_buffer_t *sdus[5]; byte_buffer_t *sdus[5];
int n_sdus; int n_sdus;

@ -43,6 +43,32 @@ namespace srsenb {
#define SRSENB_N_DRB 8 #define SRSENB_N_DRB 8
#define SRSENB_N_RADIO_BEARERS 11 #define SRSENB_N_RADIO_BEARERS 11
typedef enum{
RB_ID_SRB0 = 0,
RB_ID_SRB1,
RB_ID_SRB2,
RB_ID_DRB1,
RB_ID_DRB2,
RB_ID_DRB3,
RB_ID_DRB4,
RB_ID_DRB5,
RB_ID_DRB6,
RB_ID_DRB7,
RB_ID_DRB8,
RB_ID_N_ITEMS,
}rb_id_t;
static const char rb_id_text[RB_ID_N_ITEMS][20] = { "SRB0",
"SRB1",
"SRB2",
"DRB1",
"DRB2",
"DRB3",
"DRB4",
"DRB5",
"DRB6",
"DRB7",
"DRB8"};
// Cat 3 UE - Max number of DL-SCH transport block bits received within a TTI // Cat 3 UE - Max number of DL-SCH transport block bits received within a TTI
// 3GPP 36.306 Table 4.1.1 // 3GPP 36.306 Table 4.1.1
#define SRSENB_MAX_BUFFER_SIZE_BITS 102048 #define SRSENB_MAX_BUFFER_SIZE_BITS 102048

@ -51,7 +51,7 @@ public:
void add_user(uint16_t rnti); void add_user(uint16_t rnti);
void rem_user(uint16_t rnti); void rem_user(uint16_t rnti);
void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu); void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu);
void add_bearer(uint16_t rnti, uint32_t lcid, LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg=NULL); void add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_pdcp_config_t cnfg);
void config_security(uint16_t rnti, void config_security(uint16_t rnti,
uint32_t lcid, uint32_t lcid,
uint8_t *k_rrc_enc_, uint8_t *k_rrc_enc_,
@ -89,6 +89,7 @@ private:
void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu); void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu);
void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu); void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu);
void write_pdu_pcch(srslte::byte_buffer_t *pdu); void write_pdu_pcch(srslte::byte_buffer_t *pdu);
std::string get_rb_name(uint32_t lcid);
}; };
class user_interface class user_interface

@ -50,10 +50,11 @@ public:
void add_user(uint16_t rnti); void add_user(uint16_t rnti);
void rem_user(uint16_t rnti); void rem_user(uint16_t rnti);
void add_bearer(uint16_t rnti, uint32_t lcid); void add_bearer(uint16_t rnti, uint32_t lcid);
void add_bearer(uint16_t rnti, uint32_t lcid, LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg); void add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_rlc_config_t cnfg);
// rlc_interface_pdcp // rlc_interface_pdcp
void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu); void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu);
std::string get_rb_name(uint32_t lcid);
// rlc_interface_mac // rlc_interface_mac
int read_pdu(uint16_t rnti, uint32_t lcid, uint8_t *payload, uint32_t nof_bytes); int read_pdu(uint16_t rnti, uint32_t lcid, uint8_t *payload, uint32_t nof_bytes);
@ -73,6 +74,7 @@ private:
void write_pdu_bcch_dlsch(srslte::byte_buffer_t *sdu); void write_pdu_bcch_dlsch(srslte::byte_buffer_t *sdu);
void write_pdu_pcch(srslte::byte_buffer_t *sdu); void write_pdu_pcch(srslte::byte_buffer_t *sdu);
void max_retx_attempted(); void max_retx_attempted();
std::string get_rb_name(uint32_t lcid);
uint16_t rnti; uint16_t rnti;
srsenb::pdcp_interface_rlc *pdcp; srsenb::pdcp_interface_rlc *pdcp;

@ -384,7 +384,7 @@ int mac::rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv)
} }
// Save RA info // Save RA info
pending_rars[ra_id].preamble_idx = preamble_idx; pending_rars[ra_id].preamble_idx = preamble_idx;
pending_rars[ra_id].ta_cmd = time_adv; pending_rars[ra_id].ta_cmd = 2*time_adv;
pending_rars[ra_id].temp_crnti = last_rnti; pending_rars[ra_id].temp_crnti = last_rnti;
// Add new user to the scheduler so that it can RX/TX SRB0 // Add new user to the scheduler so that it can RX/TX SRB0

@ -25,6 +25,7 @@
*/ */
#include "upper/pdcp.h" #include "upper/pdcp.h"
#include "upper/common_enb.h"
namespace srsenb { namespace srsenb {
@ -50,7 +51,7 @@ void pdcp::add_user(uint16_t rnti)
{ {
if (users.count(rnti) == 0) { if (users.count(rnti) == 0) {
srslte::pdcp *obj = new srslte::pdcp; srslte::pdcp *obj = new srslte::pdcp;
obj->init(&users[rnti].rlc_itf, &users[rnti].rrc_itf, &users[rnti].gtpu_itf, log_h, SECURITY_DIRECTION_DOWNLINK); obj->init(&users[rnti].rlc_itf, &users[rnti].rrc_itf, &users[rnti].gtpu_itf, log_h, RB_ID_SRB0, SECURITY_DIRECTION_DOWNLINK);
users[rnti].rlc_itf.rnti = rnti; users[rnti].rlc_itf.rnti = rnti;
users[rnti].gtpu_itf.rnti = rnti; users[rnti].gtpu_itf.rnti = rnti;
users[rnti].rrc_itf.rnti = rnti; users[rnti].rrc_itf.rnti = rnti;
@ -72,14 +73,13 @@ void pdcp::rem_user(uint16_t rnti)
} }
} }
void pdcp::add_bearer(uint16_t rnti, uint32_t lcid, LIBLTE_RRC_PDCP_CONFIG_STRUCT* cnfg) void pdcp::add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_pdcp_config_t cfg)
{ {
if (users.count(rnti)) { if (users.count(rnti)) {
users[rnti].pdcp->add_bearer(lcid, cnfg); users[rnti].pdcp->add_bearer(lcid, cfg);
} }
} }
void pdcp::reset(uint16_t rnti) void pdcp::reset(uint16_t rnti)
{ {
if (users.count(rnti)) { if (users.count(rnti)) {
@ -143,6 +143,10 @@ void pdcp::user_interface_rrc::write_pdu_pcch(srslte::byte_buffer_t* pdu)
{ {
fprintf(stderr, "Error: Received PCCH from ue=%d\n", rnti); fprintf(stderr, "Error: Received PCCH from ue=%d\n", rnti);
} }
std::string pdcp::user_interface_rrc::get_rb_name(uint32_t lcid)
{
return std::string(rb_id_text[lcid]);
}
} }

@ -25,6 +25,7 @@
*/ */
#include "upper/rlc.h" #include "upper/rlc.h"
#include "upper/common_enb.h"
namespace srsenb { namespace srsenb {
@ -53,7 +54,7 @@ void rlc::add_user(uint16_t rnti)
{ {
if (users.count(rnti) == 0) { if (users.count(rnti) == 0) {
srslte::rlc *obj = new srslte::rlc; srslte::rlc *obj = new srslte::rlc;
obj->init(&users[rnti], &users[rnti], &users[rnti], log_h, mac_timers); obj->init(&users[rnti], &users[rnti], &users[rnti], log_h, mac_timers, RB_ID_SRB0);
users[rnti].rnti = rnti; users[rnti].rnti = rnti;
users[rnti].pdcp = pdcp; users[rnti].pdcp = pdcp;
users[rnti].rrc = rrc; users[rnti].rrc = rrc;
@ -97,7 +98,7 @@ void rlc::add_bearer(uint16_t rnti, uint32_t lcid)
} }
} }
void rlc::add_bearer(uint16_t rnti, uint32_t lcid, LIBLTE_RRC_RLC_CONFIG_STRUCT* cnfg) void rlc::add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_rlc_config_t cnfg)
{ {
if (users.count(rnti)) { if (users.count(rnti)) {
users[rnti].rlc->add_bearer(lcid, cnfg); users[rnti].rlc->add_bearer(lcid, cnfg);
@ -184,4 +185,9 @@ void rlc::user_interface::write_pdu_pcch(srslte::byte_buffer_t* sdu)
fprintf(stderr, "Error: Received PCCH from ue=%d\n", rnti); fprintf(stderr, "Error: Received PCCH from ue=%d\n", rnti);
} }
std::string rlc::user_interface::get_rb_name(uint32_t lcid)
{
return std::string(rb_id_text[lcid]);
}
} }

@ -27,10 +27,8 @@
#include "srslte/asn1/liblte_mme.h" #include "srslte/asn1/liblte_mme.h"
#include "upper/rrc.h" #include "upper/rrc.h"
using srslte::rb_id_text;
using srslte::byte_buffer_t; using srslte::byte_buffer_t;
using srslte::bit_buffer_t; using srslte::bit_buffer_t;
using srslte::rb_id_t;
namespace srsenb { namespace srsenb {
@ -607,11 +605,11 @@ void rrc::run_thread()
} }
switch(p.lcid) switch(p.lcid)
{ {
case srslte::RB_ID_SRB0: case RB_ID_SRB0:
parse_ul_ccch(p.rnti, p.pdu); parse_ul_ccch(p.rnti, p.pdu);
break; break;
case srslte::RB_ID_SRB1: case RB_ID_SRB1:
case srslte::RB_ID_SRB2: case RB_ID_SRB2:
parse_ul_dcch(p.rnti, p.lcid, p.pdu); parse_ul_dcch(p.rnti, p.lcid, p.pdu);
break; break;
case LCID_REM_USER: case LCID_REM_USER:
@ -919,7 +917,7 @@ void rrc::ue::set_security_key(uint8_t* key, uint32_t length)
k_up_enc, k_up_enc,
k_up_int); k_up_int);
parent->configure_security(rnti, srslte::RB_ID_SRB1, parent->configure_security(rnti, RB_ID_SRB1,
k_rrc_enc, k_rrc_int, k_rrc_enc, k_rrc_int,
k_up_enc, k_up_int, k_up_enc, k_up_int,
cipher_algo, integ_algo); cipher_algo, integ_algo);
@ -1156,9 +1154,14 @@ void rrc::ue::send_connection_setup(bool is_setup)
// Configure MAC // Configure MAC
parent->mac->ue_cfg(rnti, &sched_cfg); parent->mac->ue_cfg(rnti, &sched_cfg);
// Configure SRB1 in RLC and PDCP // Configure SRB1 in RLC
parent->rlc->add_bearer(rnti, 1); parent->rlc->add_bearer(rnti, 1);
parent->pdcp->add_bearer(rnti, 1);
// Configure SRB1 in PDCP
srslte::srslte_pdcp_config_t pdcp_cnfg;
pdcp_cnfg.is_control = true;
pdcp_cnfg.direction = SECURITY_DIRECTION_DOWNLINK;
parent->pdcp->add_bearer(rnti, 1, pdcp_cnfg);
// Configure PHY layer // Configure PHY layer
parent->phy->set_config_dedicated(rnti, phy_cfg); parent->phy->set_config_dedicated(rnti, phy_cfg);
@ -1170,7 +1173,6 @@ void rrc::ue::send_connection_setup(bool is_setup)
rr_cfg->sps_cnfg_present = false; rr_cfg->sps_cnfg_present = false;
send_dl_ccch(&dl_ccch_msg); send_dl_ccch(&dl_ccch_msg);
} }
@ -1314,12 +1316,27 @@ void rrc::ue::send_connection_reconf(srslte::byte_buffer_t *pdu)
// Configure SRB2 in RLC and PDCP // Configure SRB2 in RLC and PDCP
parent->rlc->add_bearer(rnti, 2); parent->rlc->add_bearer(rnti, 2);
parent->pdcp->add_bearer(rnti, 2);
// Configure SRB2 in PDCP
srslte::srslte_pdcp_config_t pdcp_cnfg;
pdcp_cnfg.direction = SECURITY_DIRECTION_DOWNLINK;
pdcp_cnfg.is_control = true;
pdcp_cnfg.is_data = false;
parent->pdcp->add_bearer(rnti, 2, pdcp_cnfg);
// Configure DRB1 in RLC // Configure DRB1 in RLC
parent->rlc->add_bearer(rnti, 3, &conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[0].rlc_cnfg); parent->rlc->add_bearer(rnti, 3, &conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[0].rlc_cnfg);
// Configure DRB1 in PDCP // Configure DRB1 in PDCP
parent->pdcp->add_bearer(rnti, 3, &conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[0].pdcp_cnfg); pdcp_cnfg.is_control = false;
pdcp_cnfg.is_data = true;
if (conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[0].pdcp_cnfg.rlc_um_pdcp_sn_size_present) {
if(LIBLTE_RRC_PDCP_SN_SIZE_7_BITS == conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[0].pdcp_cnfg.rlc_um_pdcp_sn_size) {
pdcp_cnfg.sn_len = 7;
}
}
parent->pdcp->add_bearer(rnti, 3, pdcp_cnfg);
// DRB1 has already been configured in GTPU through bearer setup // DRB1 has already been configured in GTPU through bearer setup
// Add NAS Attach accept // Add NAS Attach accept
@ -1432,7 +1449,7 @@ void rrc::ue::send_dl_ccch(LIBLTE_RRC_DL_CCCH_MSG_STRUCT *dl_ccch_msg)
rnti, rnti,
liblte_rrc_dl_ccch_msg_type_text[dl_ccch_msg->msg_type]); liblte_rrc_dl_ccch_msg_type_text[dl_ccch_msg->msg_type]);
parent->pdcp->write_sdu(rnti, srslte::RB_ID_SRB0, pdu); parent->pdcp->write_sdu(rnti, RB_ID_SRB0, pdu);
} else { } else {
parent->rrc_log->error("Allocating pdu\n"); parent->rrc_log->error("Allocating pdu\n");
@ -1453,7 +1470,7 @@ void rrc::ue::send_dl_dcch(LIBLTE_RRC_DL_DCCH_MSG_STRUCT *dl_dcch_msg, byte_buff
rnti, rnti,
liblte_rrc_dl_dcch_msg_type_text[dl_dcch_msg->msg_type]); liblte_rrc_dl_dcch_msg_type_text[dl_dcch_msg->msg_type]);
parent->pdcp->write_sdu(rnti, srslte::RB_ID_SRB1, pdu); parent->pdcp->write_sdu(rnti, RB_ID_SRB1, pdu);
} else { } else {
parent->rrc_log->error("Allocating pdu\n"); parent->rrc_log->error("Allocating pdu\n");

@ -155,6 +155,7 @@ public:
void set_activity_user(uint16_t rnti) {} void set_activity_user(uint16_t rnti) {}
bool is_paging_opportunity(uint32_t tti, uint32_t *payload_len) {return false;} bool is_paging_opportunity(uint32_t tti, uint32_t *payload_len) {return false;}
void read_pdu_pcch(uint8_t* payload, uint32_t buffer_size) {} void read_pdu_pcch(uint8_t* payload, uint32_t buffer_size) {}
std::string get_rb_name(uint32_t lcid) { return std::string("lcid"); }
void write_pdu(uint32_t lcid, srslte::byte_buffer_t *sdu) void write_pdu(uint32_t lcid, srslte::byte_buffer_t *sdu)
{ {
@ -566,7 +567,7 @@ int main(int argc, char *argv[])
my_phy.init(&phy_args, &phy_cfg, &my_radio, &my_mac, &log_phy); my_phy.init(&phy_args, &phy_cfg, &my_radio, &my_mac, &log_phy);
my_mac.init(&mac_args, &mac_cfg.cell, &my_phy, &my_tester, &my_tester, &log_mac); my_mac.init(&mac_args, &mac_cfg.cell, &my_phy, &my_tester, &my_tester, &log_mac);
my_rlc.init(&my_tester, &my_tester, &my_tester, &log_rlc, &my_mac); my_rlc.init(&my_tester, &my_tester, &my_tester, &log_rlc, &my_mac, 0 /* SRB0 */);
my_tester.init(&my_rlc, &my_mac, &my_phy, &log_tester, prog_args.ip_address); my_tester.init(&my_rlc, &my_mac, &my_phy, &log_tester, prog_args.ip_address);
if (prog_args.enable_gui) { if (prog_args.enable_gui) {

@ -41,8 +41,8 @@ namespace srsue {
class demux : public srslte::pdu_queue::process_callback class demux : public srslte::pdu_queue::process_callback
{ {
public: public:
demux(); demux(uint8_t nof_harq_proc_);
void init(phy_interface_mac* phy_h_, rlc_interface_mac *rlc, srslte::log* log_h_, srslte::timers* timers_db_); void init(phy_interface_mac_common* phy_h_, rlc_interface_mac *rlc, srslte::log* log_h_, srslte::timers* timers_db_);
bool process_pdus(); bool process_pdus();
uint8_t* request_buffer(uint32_t pid, uint32_t len); uint8_t* request_buffer(uint32_t pid, uint32_t len);
@ -57,7 +57,6 @@ public:
void process_pdu(uint8_t *pdu, uint32_t nof_bytes, uint32_t tstamp); void process_pdu(uint8_t *pdu, uint32_t nof_bytes, uint32_t tstamp);
private: private:
const static int NOF_HARQ_PID = 8;
const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps
const static int NOF_BUFFER_PDUS = 64; // Number of PDU buffers per HARQ pid const static int NOF_BUFFER_PDUS = 64; // Number of PDU buffers per HARQ pid
uint8_t bcch_buffer[1024]; // BCCH PID has a dedicated buffer uint8_t bcch_buffer[1024]; // BCCH PID has a dedicated buffer
@ -73,10 +72,11 @@ private:
bool is_uecrid_successful; bool is_uecrid_successful;
phy_interface_mac *phy_h; phy_interface_mac_common *phy_h;
srslte::log *log_h; srslte::log *log_h;
srslte::timers *timers_db; srslte::timers *timers_db;
rlc_interface_mac *rlc; rlc_interface_mac *rlc;
uint8_t nof_harq_proc;
// Buffer of PDUs // Buffer of PDUs
srslte::pdu_queue pdus; srslte::pdu_queue pdus;

@ -27,9 +27,15 @@
#ifndef DL_HARQ_H #ifndef DL_HARQ_H
#define DL_HARQ_H #define DL_HARQ_H
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srslte/common/timers.h" #include "srslte/common/timers.h"
#include "mac/demux.h" #include "mac/demux.h"
#include "mac/mac_common.h"
#include "mac/dl_sps.h" #include "mac/dl_sps.h"
#include "srslte/common/mac_pcap.h" #include "srslte/common/mac_pcap.h"
@ -39,79 +45,314 @@
namespace srsue { namespace srsue {
template <std::size_t N, typename Tgrant, typename Taction, typename Tphygrant>
class dl_harq_entity class dl_harq_entity
{ {
public: public:
const static uint32_t NOF_HARQ_PROC = 8; const static uint32_t HARQ_BCCH_PID = N;
const static uint32_t HARQ_BCCH_PID = NOF_HARQ_PROC;
dl_harq_entity();
bool init(srslte::log *log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg, srslte::timers *timers_, demux *demux_unit);
dl_harq_entity() : proc(N+1)
{
pcap = NULL;
}
bool init(srslte::log *log_h_, srslte::timers *timers_, demux *demux_unit_)
{
timers_db = timers_;
demux_unit = demux_unit_;
si_window_start = 0;
log_h = log_h_;
for (uint32_t i=0;i<N+1;i++) {
if (!proc[i].init(i, this)) {
return false;
}
}
return true;
}
/***************** PHY->MAC interface for DL processes **************************/ /***************** PHY->MAC interface for DL processes **************************/
void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t *action); void new_grant_dl(Tgrant grant, Taction *action)
void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid); {
if (grant.rnti_type != SRSLTE_RNTI_SPS) {
uint32_t harq_pid;
void reset(); // Set BCCH PID for SI RNTI
void start_pcap(srslte::mac_pcap* pcap); if (grant.rnti_type == SRSLTE_RNTI_SI) {
int get_current_tbs(uint32_t harq_pid); harq_pid = HARQ_BCCH_PID;
} else {
harq_pid = grant.pid%N;
}
if (grant.rnti_type == SRSLTE_RNTI_TEMP && last_temporal_crnti != grant.rnti) {
grant.ndi = true;
Info("Set NDI=1 for Temp-RNTI DL grant\n");
last_temporal_crnti = grant.rnti;
}
if (grant.rnti_type == SRSLTE_RNTI_USER && proc[harq_pid].is_sps()) {
grant.ndi = true;
Info("Set NDI=1 for C-RNTI DL grant\n");
}
proc[harq_pid].new_grant_dl(grant, action);
} else {
/* This is for SPS scheduling */
uint32_t harq_pid = get_harq_sps_pid(grant.tti)%N;
if (grant.ndi) {
grant.ndi = false;
proc[harq_pid].new_grant_dl(grant, action);
} else {
if (grant.is_sps_release) {
dl_sps_assig.clear();
if (timers_db->get(TIME_ALIGNMENT)->is_running()) {
//phy_h->send_sps_ack();
Warning("PHY Send SPS ACK not implemented\n");
}
} else {
Error("SPS not implemented\n");
//dl_sps_assig.reset(grant.tti, grant);
//grant.ndi = true;
//procs[harq_pid].save_grant();
}
}
}
}
void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
{
if (rnti_type == SRSLTE_RNTI_SI) {
proc[N].tb_decoded(ack);
} else {
proc[harq_pid%N].tb_decoded(ack);
}
}
void reset()
{
for (uint32_t i=0;i<N+1;i++) {
proc[i].reset();
}
dl_sps_assig.clear();
}
void start_pcap(srslte::mac_pcap* pcap_) { pcap = pcap_; }
int get_current_tbs(uint32_t harq_pid) { return proc[harq_pid%N].get_current_tbs(); }
void set_si_window_start(int si_window_start_) { si_window_start = si_window_start_; }
float get_average_retx() { return average_retx; }
void set_si_window_start(int si_window_start);
float get_average_retx();
private: private:
class dl_harq_process { class dl_harq_process {
public: public:
dl_harq_process(); dl_harq_process()
bool init(uint32_t pid, dl_harq_entity *parent); {
void reset(); is_initiated = false;
bool is_sps(); ack = false;
void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t *action); bzero(&cur_grant, sizeof(Tgrant));
void tb_decoded(bool ack); }
int get_current_tbs();
bool init(uint32_t pid_, dl_harq_entity *parent)
{
if (srslte_softbuffer_rx_init(&softbuffer, 110)) {
Error("Error initiating soft buffer\n");
return false;
} else {
pid = pid_;
is_initiated = true;
harq_entity = parent;
log_h = harq_entity->log_h;
return true;
}
}
void reset()
{
ack = false;
payload_buffer_ptr = NULL;
bzero(&cur_grant, sizeof(Tgrant));
if (is_initiated) {
srslte_softbuffer_rx_reset(&softbuffer);
}
}
private: void new_grant_dl(Tgrant grant, Taction *action)
bool calc_is_new_transmission(mac_interface_phy::mac_grant_t grant); {
// Compute RV for BCCH when not specified in PDCCH format
if (pid == HARQ_BCCH_PID && grant.rv == -1) {
uint32_t k;
if ((grant.tti/10)%2 == 0 && grant.tti%10 == 5) { // This is SIB1, k is different
k = (grant.tti/20)%4;
grant.rv = ((uint32_t) ceilf((float)1.5*k))%4;
} else if (grant.rv == -1) {
k = (grant.tti-harq_entity->si_window_start)%4;
grant.rv = ((uint32_t) ceilf((float)1.5*k))%4;
}
}
calc_is_new_transmission(grant);
if (is_new_transmission) {
ack = false;
srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes*8);
n_retx = 0;
}
// Save grant
grant.last_ndi = cur_grant.ndi;
grant.last_tti = cur_grant.tti;
memcpy(&cur_grant, &grant, sizeof(Tgrant));
// Fill action structure
bzero(action, sizeof(Taction));
action->default_ack = ack;
action->generate_ack = true;
action->decode_enabled = false;
// If data has not yet been successfully decoded
if (ack == false) {
// Instruct the PHY To combine the received data and attempt to decode it
payload_buffer_ptr = harq_entity->demux_unit->request_buffer(pid, cur_grant.n_bytes);
action->payload_ptr = payload_buffer_ptr;
if (!action->payload_ptr) {
action->decode_enabled = false;
Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes);
return;
}
action->decode_enabled = true;
action->rv = cur_grant.rv;
action->rnti = cur_grant.rnti;
action->softbuffer = &softbuffer;
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(Tphygrant));
n_retx++;
} else {
Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid);
}
if (pid == HARQ_BCCH_PID || harq_entity->timers_db->get(TIME_ALIGNMENT)->is_expired()) {
// Do not generate ACK
Debug("Not generating ACK\n");
action->generate_ack = false;
} else {
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP && ack == false) {
// Postpone ACK after contention resolution is resolved
action->generate_ack_callback = harq_entity->generate_ack_callback;
action->generate_ack_callback_arg = harq_entity->demux_unit;
Debug("ACK pending contention resolution\n");
} else {
Debug("Generating ACK\n");
}
}
}
void tb_decoded(bool ack_)
{
ack = ack_;
if (ack == true) {
if (pid == HARQ_BCCH_PID) {
if (harq_entity->pcap) {
harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.n_bytes, ack, cur_grant.tti);
}
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes, cur_grant.tti);
} else {
if (harq_entity->pcap) {
harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.n_bytes, cur_grant.rnti, ack, cur_grant.tti);
}
if (ack) {
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP) {
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.n_bytes);
} else {
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes, cur_grant.tti);
// Compute average number of retransmissions per packet
harq_entity->average_retx = SRSLTE_VEC_CMA((float) n_retx, harq_entity->average_retx, harq_entity->nof_pkts++);
}
}
}
} else {
harq_entity->demux_unit->deallocate(payload_buffer_ptr);
}
Info("DL %d: %s tbs=%d, rv=%d, ack=%s, ndi=%d (%d), tti=%d (%d)\n",
pid, is_new_transmission?"newTX":"reTX ",
cur_grant.n_bytes, cur_grant.rv, ack?"OK":"KO",
cur_grant.ndi, cur_grant.last_ndi, cur_grant.tti, cur_grant.last_tti);
if (ack && pid == HARQ_BCCH_PID) {
reset();
}
}
bool is_sps() { return false; }
int get_current_tbs() { return cur_grant.n_bytes*8; }
private:
bool calc_is_new_transmission(Tgrant grant)
{
bool is_new_tb = true;
if ((srslte_tti_interval(grant.tti, cur_grant.tti) <= 8 && (grant.n_bytes == cur_grant.n_bytes)) ||
pid == HARQ_BCCH_PID)
{
is_new_tb = false;
}
if ((grant.ndi != cur_grant.ndi && !is_new_tb) || // NDI toggled for same TB
is_new_tb || // is new TB
(pid == HARQ_BCCH_PID && grant.rv == 0)) // Broadcast PID and 1st TX (RV=0)
{
is_new_transmission = true;
Debug("Set HARQ for new transmission\n");
} else {
is_new_transmission = false;
Debug("Set HARQ for retransmission\n");
}
return is_new_transmission;
}
bool is_initiated; bool is_initiated;
dl_harq_entity *harq_entity; dl_harq_entity *harq_entity;
srslte::log *log_h; srslte::log *log_h;
bool is_new_transmission; bool is_new_transmission;
uint32_t pid; uint32_t pid;
uint8_t *payload_buffer_ptr; uint8_t *payload_buffer_ptr;
bool ack; bool ack;
uint32_t n_retx; uint32_t n_retx;
mac_interface_phy::mac_grant_t cur_grant; Tgrant cur_grant;
srslte_softbuffer_rx_t softbuffer; srslte_softbuffer_rx_t softbuffer;
}; };
static bool generate_ack_callback(void *arg);
// Private members of dl_harq_entity
static bool generate_ack_callback(void *arg)
{
demux *demux_unit = (demux*) arg;
return demux_unit->get_uecrid_successful();
}
uint32_t get_harq_sps_pid(uint32_t tti); uint32_t get_harq_sps_pid(uint32_t tti) { return 0; }
dl_sps dl_sps_assig; dl_sps dl_sps_assig;
dl_harq_process proc[NOF_HARQ_PROC+1];
std::vector<dl_harq_process> proc;
srslte::timers *timers_db; srslte::timers *timers_db;
mac_interface_rrc::mac_cfg_t *mac_cfg;
demux *demux_unit; demux *demux_unit;
srslte::log *log_h; srslte::log *log_h;
srslte::mac_pcap *pcap; srslte::mac_pcap *pcap;
uint16_t last_temporal_crnti; uint16_t last_temporal_crnti;
int si_window_start; int si_window_start;
float average_retx; float average_retx;
uint64_t nof_pkts; uint64_t nof_pkts;
}; };

@ -98,17 +98,6 @@ public:
u_int32_t get_unique_id(); u_int32_t get_unique_id();
uint32_t get_current_tti(); uint32_t get_current_tti();
enum {
HARQ_RTT,
TIME_ALIGNMENT,
CONTENTION_TIMER,
BSR_TIMER_PERIODIC,
BSR_TIMER_RETX,
PHR_TIMER_PERIODIC,
PHR_TIMER_PROHIBIT,
NOF_MAC_TIMERS
} mac_timers_t;
static const int MAC_NOF_UPPER_TIMERS = 20; static const int MAC_NOF_UPPER_TIMERS = 20;
@ -117,6 +106,7 @@ private:
static const int MAC_MAIN_THREAD_PRIO = 5; static const int MAC_MAIN_THREAD_PRIO = 5;
static const int MAC_PDU_THREAD_PRIO = 6; static const int MAC_PDU_THREAD_PRIO = 6;
static const int MAC_NOF_HARQ_PROC = 8;
// Interaction with PHY // Interaction with PHY
srslte::tti_sync_cv ttisync; srslte::tti_sync_cv ttisync;
@ -141,9 +131,9 @@ private:
mux mux_unit; mux mux_unit;
demux demux_unit; demux demux_unit;
/* DL/UL HARQ */ /* DL/UL HARQ */
dl_harq_entity dl_harq; dl_harq_entity<MAC_NOF_HARQ_PROC, mac_grant_t, tb_action_dl_t, srslte_phy_grant_t> dl_harq;
ul_harq_entity ul_harq; ul_harq_entity<MAC_NOF_HARQ_PROC, mac_grant_t, tb_action_ul_t, srslte_phy_grant_t> ul_harq;
/* MAC Uplink-related Procedures */ /* MAC Uplink-related Procedures */
ra_proc ra_procedure; ra_proc ra_procedure;

@ -0,0 +1,45 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef MAC_COMMON_H
#define MAC_COMMON_H
namespace srsue {
typedef enum {
HARQ_RTT,
TIME_ALIGNMENT,
CONTENTION_TIMER,
BSR_TIMER_PERIODIC,
BSR_TIMER_RETX,
PHR_TIMER_PERIODIC,
PHR_TIMER_PROHIBIT,
NOF_MAC_TIMERS
} mac_timers_t;
} // namespace srsue
#endif // MAC_COMMON_H

@ -55,9 +55,9 @@ namespace srsue {
class mux class mux
{ {
public: public:
mux(); mux(uint8_t nof_harq_proc_);
void reset(); void reset();
void init(rlc_interface_mac *rlc, srslte::log *log_h, bsr_proc *bsr_procedure, phr_proc *phr_procedure_); void init(rlc_interface_mac *rlc, srslte::log *log_h, bsr_interface_mux *bsr_procedure, phr_proc *phr_procedure_);
bool is_pending_any_sdu(); bool is_pending_any_sdu();
bool is_pending_sdu(uint32_t lcid); bool is_pending_sdu(uint32_t lcid);
@ -87,16 +87,17 @@ private:
std::vector<lchid_t> lch; std::vector<lchid_t> lch;
// Keep track of the PIDs that transmitted BSR reports // Keep track of the PIDs that transmitted BSR reports
bool pid_has_bsr[MAX_HARQ_PROC]; std::vector<bool> pid_has_bsr;
// Mutex for exclusive access // Mutex for exclusive access
pthread_mutex_t mutex; pthread_mutex_t mutex;
srslte::log *log_h; srslte::log *log_h;
rlc_interface_mac *rlc; rlc_interface_mac *rlc;
bsr_proc *bsr_procedure; bsr_interface_mux *bsr_procedure;
phr_proc *phr_procedure; phr_proc *phr_procedure;
uint16_t pending_crnti_ce; uint16_t pending_crnti_ce;
uint8_t nof_harq_proc;
/* Msg3 Buffer */ /* Msg3 Buffer */
static const uint32_t MSG3_BUFF_SZ = 128; static const uint32_t MSG3_BUFF_SZ = 128;
@ -105,9 +106,6 @@ private:
/* PDU Buffer */ /* PDU Buffer */
srslte::sch_pdu pdu_msg; srslte::sch_pdu pdu_msg;
bool msg3_has_been_transmitted; bool msg3_has_been_transmitted;
}; };
} // namespace srsue } // namespace srsue

@ -37,7 +37,7 @@
namespace srsue { namespace srsue {
class bsr_proc : public srslte::timer_callback class bsr_proc : public srslte::timer_callback, public bsr_interface_mux
{ {
public: public:
bsr_proc(); bsr_proc();
@ -48,18 +48,6 @@ public:
void set_priority(uint32_t lcid, uint32_t priority); void set_priority(uint32_t lcid, uint32_t priority);
void timer_expired(uint32_t timer_id); void timer_expired(uint32_t timer_id);
uint32_t get_buffer_state(); uint32_t get_buffer_state();
typedef enum {
LONG_BSR,
SHORT_BSR,
TRUNC_BSR
} bsr_format_t;
typedef struct {
bsr_format_t format;
uint32_t buff_size[4];
} bsr_t;
bool need_to_send_bsr_on_ul_grant(uint32_t grant_size, bsr_t *bsr); bool need_to_send_bsr_on_ul_grant(uint32_t grant_size, bsr_t *bsr);
bool generate_padding_bsr(uint32_t nof_padding_bytes, bsr_t *bsr); bool generate_padding_bsr(uint32_t nof_padding_bytes, bsr_t *bsr);
bool need_to_send_sr(uint32_t tti); bool need_to_send_sr(uint32_t tti);

@ -27,78 +27,268 @@
#ifndef ULHARQ_H #ifndef ULHARQ_H
#define ULHARQ_H #define ULHARQ_H
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "mac/mux.h" #include "mac/mux.h"
#include "mac/mac_common.h"
#include "mac/ul_sps.h" #include "mac/ul_sps.h"
#include "srslte/common/mac_pcap.h" #include "srslte/common/mac_pcap.h"
#include "srslte/common/timers.h" #include "srslte/common/timers.h"
#include "srslte/common/interfaces_common.h"
/* Uplink HARQ entity as defined in 5.4.2 of 36.321 */ /* Uplink HARQ entity as defined in 5.4.2 of 36.321 */
namespace srsue { namespace srsue {
template <std::size_t N, typename Tgrant, typename Taction, typename Tphygrant>
class ul_harq_entity class ul_harq_entity
{ {
public: public:
static uint32_t pidof(uint32_t tti)
const static uint32_t NOF_HARQ_PROC = 8; {
static uint32_t pidof(uint32_t tti); return (uint32_t) tti%N;
}
ul_harq_entity() { ul_harq_entity() : proc(N)
{
pcap = NULL; pcap = NULL;
timers_db = NULL; timers_db = NULL;
mux_unit = NULL; mux_unit = NULL;
log_h = NULL; log_h = NULL;
mac_cfg = NULL; params = NULL;
rntis = NULL; rntis = NULL;
average_retx = 0; average_retx = 0;
nof_pkts = 0; nof_pkts = 0;
}
bool init(srslte::log *log_h_,
mac_interface_rrc_common::ue_rnti_t *rntis_,
mac_interface_rrc_common::ul_harq_params_t *params_,
srslte::timers* timers_db_,
mux *mux_unit_)
{
log_h = log_h_;
mux_unit = mux_unit_;
params = params_;
rntis = rntis_;
timers_db = timers_db_;
for (uint32_t i=0;i<N;i++) {
if (!proc[i].init(i, this)) {
return false;
}
}
return true;
}
void reset()
{
for (uint32_t i=0;i<N;i++) {
proc[i].reset();
}
ul_sps_assig.clear();
} }
bool init(srslte::log *log_h,
mac_interface_rrc::ue_rnti_t *rntis,
mac_interface_rrc::mac_cfg_t *mac_cfg,
srslte::timers* timers_,
mux *mux_unit);
void reset();
void reset_ndi();
void start_pcap(srslte::mac_pcap* pcap); void reset_ndi()
{
for (uint32_t i=0;i<N;i++) {
proc[i].reset_ndi();
}
}
void start_pcap(srslte::mac_pcap* pcap_)
{
pcap = pcap_;
}
/***************** PHY->MAC interface for UL processes **************************/ /***************** PHY->MAC interface for UL processes **************************/
void new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_ul_t *action); void new_grant_ul(Tgrant grant, Taction *action)
void new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t *action); {
void harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t *action); if (grant.rnti_type == SRSLTE_RNTI_USER ||
grant.rnti_type == SRSLTE_RNTI_TEMP ||
grant.rnti_type == SRSLTE_RNTI_RAR)
{
if (grant.rnti_type == SRSLTE_RNTI_USER && proc[pidof(grant.tti)].is_sps()) {
grant.ndi = true;
}
run_tti(grant.tti, &grant, action);
} else if (grant.rnti_type == SRSLTE_RNTI_SPS) {
if (grant.ndi) {
grant.ndi = proc[pidof(grant.tti)].get_ndi();
run_tti(grant.tti, &grant, action);
} else {
Info("Not implemented\n");
}
}
}
int get_current_tbs(uint32_t tti); void new_grant_ul_ack(Tgrant grant, bool ack, Taction *action)
{
set_ack(grant.tti, ack, action);
new_grant_ul(grant, action);
}
void harq_recv(uint32_t tti, bool ack, Taction *action)
{
set_ack(tti, ack, action);
run_tti(tti, NULL, action);
}
int get_current_tbs(uint32_t tti)
{
int tti_harq = (int) tti-4;
if (tti_harq < 0) {
tti_harq += 10240;
}
uint32_t pid_harq = pidof(tti_harq);
return proc[pid_harq].get_current_tbs();
}
float get_average_retx(); float get_average_retx()
{
return average_retx;
}
private: private:
class ul_harq_process { class ul_harq_process {
public: public:
ul_harq_process(); ul_harq_process()
bool init(uint32_t pid, ul_harq_entity *parent); {
void reset(); current_tx_nb = 0;
void reset_ndi(); current_irv = 0;
is_initiated = false;
is_grant_configured = false;
tti_last_tx = 0;
bzero(&cur_grant, sizeof(Tgrant));
}
bool init(uint32_t pid_, ul_harq_entity *parent)
{
if (srslte_softbuffer_tx_init(&softbuffer, 110)) {
fprintf(stderr, "Error initiating soft buffer\n");
return false;
} else {
is_initiated = true;
harq_entity = parent;
log_h = harq_entity->log_h;
pid = pid_;
payload_buffer = (uint8_t*) srslte_vec_malloc(payload_buffer_len*sizeof(uint8_t));
if (!payload_buffer) {
Error("Allocating memory\n");
return false;
}
pdu_ptr = payload_buffer;
return true;
}
}
void reset()
{
current_tx_nb = 0;
current_irv = 0;
tti_last_tx = 0;
is_grant_configured = false;
bzero(&cur_grant, sizeof(Tgrant));
}
void reset_ndi() { ndi = false; }
void run_tti(uint32_t tti, mac_interface_phy::mac_grant_t *grant, mac_interface_phy::tb_action_ul_t* action); void run_tti(uint32_t tti_tx, Tgrant *grant, Taction* action)
{
uint32_t max_retx;
if (is_msg3) {
max_retx = harq_entity->params->max_harq_msg3_tx;
} else {
max_retx = harq_entity->params->max_harq_tx;
}
uint32_t get_rv(); // Receive and route HARQ feedbacks
bool has_grant(); if (grant) {
if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi != get_ndi()) ||
(grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) ||
grant->is_from_rar)
{
// New transmission
void set_harq_feedback(bool ack); // Uplink grant in a RAR
bool get_ndi(); if (grant->is_from_rar) {
bool is_sps(); Debug("Getting Msg3 buffer payload, grant size=%d bytes\n", grant->n_bytes);
uint32_t last_tx_tti(); pdu_ptr = harq_entity->mux_unit->msg3_get(payload_buffer, grant->n_bytes);
uint32_t get_nof_retx(); if (pdu_ptr) {
int get_current_tbs(); generate_new_tx(tti_tx, true, grant, action);
} else {
Warning("UL RAR grant available but no Msg3 on buffer\n");
}
// Normal UL grant
} else {
// Request a MAC PDU from the Multiplexing & Assemble Unit
pdu_ptr = harq_entity->mux_unit->pdu_get(payload_buffer, grant->n_bytes, tti_tx, pid);
if (pdu_ptr) {
generate_new_tx(tti_tx, false, grant, action);
} else {
Warning("Uplink grant but no MAC PDU in Multiplex Unit buffer\n");
}
}
} else {
// Adaptive Re-TX
if (current_tx_nb >= max_retx) {
Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx);
reset();
action->expect_ack = false;
} else {
generate_retx(tti_tx, grant, action);
}
}
} else if (has_grant()) {
// Non-Adaptive Re-Tx
if (current_tx_nb >= max_retx) {
Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx);
reset();
action->expect_ack = false;
} else {
generate_retx(tti_tx, action);
}
}
if (harq_entity->pcap && grant) {
if (grant->is_from_rar) {
grant->rnti = harq_entity->rntis->temp_rnti;
}
harq_entity->pcap->write_ul_crnti(pdu_ptr, grant->n_bytes, grant->rnti, get_nof_retx(), tti_tx);
}
}
void set_harq_feedback(bool ack)
{
harq_feedback = ack;
// UL packet successfully delivered
if (ack) {
Info("UL %d: HARQ = ACK for UL transmission. Discarting TB.\n", pid);
reset();
} else {
Info("UL %d: HARQ = NACK for UL transmission\n", pid);
}
}
uint32_t get_rv()
{
int rv_of_irv[4] = {0, 2, 3, 1};
return rv_of_irv[current_irv%4];
}
bool has_grant() { return is_grant_configured; }
bool get_ndi() { return ndi; }
bool is_sps() { return false; }
uint32_t last_tx_tti() { return tti_last_tx; }
uint32_t get_nof_retx() { return current_tx_nb; }
int get_current_tbs() { return cur_grant.n_bytes*8; }
private: private:
mac_interface_phy::mac_grant_t cur_grant; Tgrant cur_grant;
uint32_t pid; uint32_t pid;
uint32_t current_tx_nb; uint32_t current_tx_nb;
@ -118,28 +308,109 @@ private:
uint8_t *payload_buffer; uint8_t *payload_buffer;
uint8_t *pdu_ptr; uint8_t *pdu_ptr;
void generate_retx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action); void generate_retx(uint32_t tti_tx, Taction *action)
void generate_retx(uint32_t tti_tx, mac_interface_phy::mac_grant_t *grant, {
mac_interface_phy::tb_action_ul_t *action); generate_retx(tti_tx, NULL, action);
void generate_new_tx(uint32_t tti_tx, bool is_msg3, mac_interface_phy::mac_grant_t *grant, }
mac_interface_phy::tb_action_ul_t *action);
void generate_tx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action); // Retransmission with or w/o grant (Section 5.4.2.2)
void generate_retx(uint32_t tti_tx, Tgrant *grant,
Taction *action)
{
int irv_of_rv[4] = {0, 3, 1, 2};
if (grant) {
// HARQ entity requests an adaptive transmission
if (grant->rv) {
current_irv = irv_of_rv[grant->rv%4];
}
memcpy(&cur_grant, grant, sizeof(Tgrant));
harq_feedback = false;
Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d\n",
pid, current_tx_nb, get_rv(), grant->n_bytes);
generate_tx(tti_tx, action);
} else {
Info("UL %d: Non-Adaptive retx=%d, RV=%d, TBS=%d\n",
pid, current_tx_nb, get_rv(), cur_grant.n_bytes);
// HARQ entity requests a non-adaptive transmission
if (!harq_feedback) {
generate_tx(tti_tx, action);
}
}
// On every Msg3 retransmission, restart mac-ContentionResolutionTimer as defined in Section 5.1.5
if (is_msg3) {
harq_entity->timers_db->get(CONTENTION_TIMER)->reset();
}
harq_entity->mux_unit->pusch_retx(tti_tx, pid);
}
// New transmission (Section 5.4.2.2)
void generate_new_tx(uint32_t tti_tx, bool is_msg3_, Tgrant *grant, Taction *action)
{
if (grant) {
// Compute average number of retransmissions per packet considering previous packet
harq_entity->average_retx = SRSLTE_VEC_CMA((float) current_tx_nb, harq_entity->average_retx, harq_entity->nof_pkts++);
memcpy(&cur_grant, grant, sizeof(Tgrant));
harq_feedback = false;
is_grant_configured = true;
current_tx_nb = 0;
current_irv = 0;
is_msg3 = is_msg3_;
Info("UL %d: New TX%s, RV=%d, TBS=%d, RNTI=%d\n",
pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes, cur_grant.rnti);
generate_tx(tti_tx, action);
}
}
// Transmission of pending frame (Section 5.4.2.2)
void generate_tx(uint32_t tti_tx, Taction *action)
{
action->current_tx_nb = current_tx_nb;
current_tx_nb++;
action->expect_ack = true;
action->rnti = is_msg3?harq_entity->rntis->temp_rnti:cur_grant.rnti;
action->rv = cur_grant.rv>0?cur_grant.rv:get_rv();
action->softbuffer = &softbuffer;
action->tx_enabled = true;
action->payload_ptr = pdu_ptr;
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(Tphygrant));
current_irv = (current_irv+1)%4;
tti_last_tx = tti_tx;
}
}; };
// Implements Section 5.4.2.1
void run_tti(uint32_t tti, mac_interface_phy::mac_grant_t *grant, mac_interface_phy::tb_action_ul_t* action); // Called with UL grant
void set_ack(uint32_t tti, bool ack); void run_tti(uint32_t tti, Tgrant *grant, Taction* action)
{
uint32_t tti_tx = (tti+action->tti_offset)%10240;
proc[pidof(tti_tx)].run_tti(tti_tx, grant, action);
}
void set_ack(uint32_t tti, bool ack, Taction *action)
{
int tti_harq = (int) tti - action->tti_offset;
if (tti_harq < 0) {
tti_harq += 10240;
}
uint32_t pid_harq = pidof(tti_harq);
if (proc[pid_harq].has_grant() && (proc[pid_harq].last_tx_tti() <= (uint32_t)tti_harq)) {
proc[pid_harq].set_harq_feedback(ack);
}
}
ul_sps ul_sps_assig; ul_sps ul_sps_assig;
srslte::timers *timers_db; srslte::timers *timers_db;
mux *mux_unit; mux *mux_unit;
ul_harq_process proc[NOF_HARQ_PROC]; std::vector<ul_harq_process> proc;
srslte::log *log_h; srslte::log *log_h;
srslte::mac_pcap *pcap; srslte::mac_pcap *pcap;
mac_interface_rrc::ue_rnti_t *rntis; mac_interface_rrc_common::ue_rnti_t *rntis;
mac_interface_rrc::mac_cfg_t *mac_cfg; mac_interface_rrc_common::ul_harq_params_t *params;
float average_retx; float average_retx;
uint64_t nof_pkts; uint64_t nof_pkts;

@ -37,6 +37,7 @@
#include <string> #include <string>
#include <pthread.h> #include <pthread.h>
#include "ue_base.h"
#include "srslte/radio/radio_multi.h" #include "srslte/radio/radio_multi.h"
#include "phy/phy.h" #include "phy/phy.h"
#include "mac/mac.h" #include "mac/mac.h"
@ -56,89 +57,15 @@
namespace srsue { namespace srsue {
/*******************************************************************************
UE Parameters
*******************************************************************************/
typedef struct {
float dl_freq;
float ul_freq;
float rx_gain;
float tx_gain;
uint32_t nof_rx_ant;
std::string device_name;
std::string device_args;
std::string time_adv_nsamples;
std::string burst_preamble;
}rf_args_t;
typedef struct {
bool enable;
std::string filename;
}pcap_args_t;
typedef struct {
bool enable;
std::string phy_filename;
std::string radio_filename;
}trace_args_t;
typedef struct {
std::string phy_level;
std::string mac_level;
std::string rlc_level;
std::string pdcp_level;
std::string rrc_level;
std::string gw_level;
std::string nas_level;
std::string usim_level;
std::string all_level;
int phy_hex_limit;
int mac_hex_limit;
int rlc_hex_limit;
int pdcp_hex_limit;
int rrc_hex_limit;
int gw_hex_limit;
int nas_hex_limit;
int usim_hex_limit;
int all_hex_limit;
std::string filename;
}log_args_t;
typedef struct {
bool enable;
}gui_args_t;
typedef struct {
phy_args_t phy;
float metrics_period_secs;
bool pregenerate_signals;
int ue_cateogry;
}expert_args_t;
typedef struct {
rf_args_t rf;
rf_cal_t rf_cal;
pcap_args_t pcap;
trace_args_t trace;
log_args_t log;
gui_args_t gui;
usim_args_t usim;
expert_args_t expert;
}all_args_t;
/******************************************************************************* /*******************************************************************************
Main UE class Main UE class
*******************************************************************************/ *******************************************************************************/
class ue class ue
:public ue_interface :public ue_base
,public ue_metrics_interface
{ {
public: public:
static ue* get_instance(void); ue();
static void cleanup(void);
bool init(all_args_t *args_); bool init(all_args_t *args_);
void stop(); void stop();
@ -158,8 +85,6 @@ public:
private: private:
static ue *instance;
ue();
virtual ~ue(); virtual ~ue();
srslte::radio_multi radio; srslte::radio_multi radio;
@ -189,8 +114,6 @@ private:
all_args_t *args; all_args_t *args;
bool started; bool started;
rf_metrics_t rf_metrics; rf_metrics_t rf_metrics;
srslte::LOG_LEVEL_ENUM level(std::string l);
bool check_srslte_version(); bool check_srslte_version();
}; };

@ -0,0 +1,164 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/******************************************************************************
* File: ue_base.h
* Description: Base class for UEs.
*****************************************************************************/
#ifndef UE_BASE_H
#define UE_BASE_H
#include <stdarg.h>
#include <string>
#include <pthread.h>
#include "srslte/radio/radio_multi.h"
#include "phy/phy.h"
#include "upper/usim.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/logger.h"
#include "srslte/common/log_filter.h"
#include "ue_metrics_interface.h"
namespace srsue {
/*******************************************************************************
UE Parameters
*******************************************************************************/
typedef struct {
float dl_freq;
float ul_freq;
float rx_gain;
float tx_gain;
uint32_t nof_rx_ant;
std::string device_name;
std::string device_args;
std::string time_adv_nsamples;
std::string burst_preamble;
}rf_args_t;
typedef struct {
bool enable;
std::string filename;
}pcap_args_t;
typedef struct {
bool enable;
std::string phy_filename;
std::string radio_filename;
}trace_args_t;
typedef struct {
std::string phy_level;
std::string mac_level;
std::string rlc_level;
std::string pdcp_level;
std::string rrc_level;
std::string gw_level;
std::string nas_level;
std::string usim_level;
std::string all_level;
int phy_hex_limit;
int mac_hex_limit;
int rlc_hex_limit;
int pdcp_hex_limit;
int rrc_hex_limit;
int gw_hex_limit;
int nas_hex_limit;
int usim_hex_limit;
int all_hex_limit;
std::string filename;
}log_args_t;
typedef struct {
bool enable;
}gui_args_t;
typedef struct {
phy_args_t phy;
float metrics_period_secs;
bool pregenerate_signals;
std::string ue_cateogry;
}expert_args_t;
typedef struct {
rf_args_t rf;
rf_cal_t rf_cal;
pcap_args_t pcap;
trace_args_t trace;
log_args_t log;
gui_args_t gui;
usim_args_t usim;
expert_args_t expert;
}all_args_t;
typedef enum {
LTE = 0,
SRSUE_INSTANCE_TYPE_NITEMS
} srsue_instance_type_t;
static const char srsue_instance_type_text[SRSUE_INSTANCE_TYPE_NITEMS][10] = { "LTE" };
/*******************************************************************************
Main UE class
*******************************************************************************/
class ue_base
:public ue_interface
,public ue_metrics_interface
{
public:
ue_base() {}
virtual ~ue_base() {}
static ue_base* get_instance(srsue_instance_type_t type);
void cleanup(void);
virtual bool init(all_args_t *args_) = 0;
virtual void stop() = 0;
virtual bool is_attached() = 0;
virtual void start_plot() = 0;
void handle_rf_msg(srslte_rf_error_t error);
// UE metrics interface
virtual bool get_metrics(ue_metrics_t &m) = 0;
virtual void pregenerate_signals(bool enable) = 0;
srslte::log_filter rf_log;
rf_metrics_t rf_metrics;
srslte::LOG_LEVEL_ENUM level(std::string l);
};
} // namespace srsue
#endif // UE_BASE_H

@ -65,7 +65,8 @@ public:
void init(usim_interface_nas *usim_, void init(usim_interface_nas *usim_,
rrc_interface_nas *rrc_, rrc_interface_nas *rrc_,
gw_interface_nas *gw_, gw_interface_nas *gw_,
srslte::log *nas_log_); srslte::log *nas_log_,
uint32_t lcid_);
void stop(); void stop();
emm_state_t get_state(); emm_state_t get_state();
@ -83,6 +84,7 @@ private:
rrc_interface_nas *rrc; rrc_interface_nas *rrc;
usim_interface_nas *usim; usim_interface_nas *usim;
gw_interface_nas *gw; gw_interface_nas *gw;
uint32_t default_lcid;
emm_state_t state; emm_state_t state;

@ -29,6 +29,7 @@
#include "pthread.h" #include "pthread.h"
#include "rrc_common.h"
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
@ -41,24 +42,6 @@ using srslte::byte_buffer_t;
namespace srsue { namespace srsue {
// RRC states (3GPP 36.331 v10.0.0)
typedef enum{
RRC_STATE_IDLE = 0,
RRC_STATE_SIB1_SEARCH,
RRC_STATE_SIB2_SEARCH,
RRC_STATE_WAIT_FOR_CON_SETUP,
RRC_STATE_COMPLETING_SETUP,
RRC_STATE_RRC_CONNECTED,
RRC_STATE_N_ITEMS,
}rrc_state_t;
static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE",
"SIB1_SEARCH",
"SIB2_SEARCH",
"WAIT FOR CON SETUP",
"COMPLETING SETUP",
"RRC CONNECTED"};
class rrc class rrc
:public rrc_interface_nas :public rrc_interface_nas
,public rrc_interface_phy ,public rrc_interface_phy
@ -161,6 +144,23 @@ private:
void write_pdu_bcch_dlsch(byte_buffer_t *pdu); void write_pdu_bcch_dlsch(byte_buffer_t *pdu);
void write_pdu_pcch(byte_buffer_t *pdu); void write_pdu_pcch(byte_buffer_t *pdu);
// Radio bearers
typedef enum{
RB_ID_SRB0 = 0,
RB_ID_SRB1,
RB_ID_SRB2,
RB_ID_DRB1,
RB_ID_DRB2,
RB_ID_DRB3,
RB_ID_DRB4,
RB_ID_DRB5,
RB_ID_DRB6,
RB_ID_DRB7,
RB_ID_DRB8
} rb_id_t;
std::map<uint8_t, std::string> bearers;
std::string get_rb_name(uint32_t lcid) { return bearers.at(lcid); }
// RLC interface // RLC interface
void max_retx_attempted(); void max_retx_attempted();
@ -202,6 +202,7 @@ private:
void set_phy_default(); void set_phy_default();
void set_mac_default(); void set_mac_default();
void set_rrc_default(); void set_rrc_default();
void set_bearers();
}; };

@ -0,0 +1,52 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef RRC_COMMON_H
#define RRC_COMMON_H
namespace srsue {
// RRC states (3GPP 36.331 v10.0.0)
typedef enum{
RRC_STATE_IDLE = 0,
RRC_STATE_SIB1_SEARCH,
RRC_STATE_SIB2_SEARCH,
RRC_STATE_WAIT_FOR_CON_SETUP,
RRC_STATE_COMPLETING_SETUP,
RRC_STATE_RRC_CONNECTED,
RRC_STATE_N_ITEMS,
}rrc_state_t;
static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE",
"SIB1_SEARCH",
"SIB2_SEARCH",
"WAIT FOR CON SETUP",
"COMPLETING SETUP",
"RRC CONNECTED"};
} // namespace srsue
#endif // RRC_COMMON_H

@ -31,7 +31,7 @@ if (RPATH)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
endif (RPATH) endif (RPATH)
add_executable(srsue main.cc ue.cc metrics_stdout.cc) add_executable(srsue main.cc ue_base.cc ue.cc metrics_stdout.cc)
target_link_libraries(srsue srsue_mac target_link_libraries(srsue srsue_mac
srsue_phy srsue_phy
srsue_upper srsue_upper

@ -36,11 +36,11 @@
namespace srsue { namespace srsue {
demux::demux() : mac_msg(20), pending_mac_msg(20) demux::demux(uint8_t nof_harq_proc_) : mac_msg(20), pending_mac_msg(20), nof_harq_proc(nof_harq_proc_)
{ {
} }
void demux::init(phy_interface_mac* phy_h_, rlc_interface_mac *rlc_, srslte::log* log_h_, srslte::timers* timers_db_) void demux::init(phy_interface_mac_common* phy_h_, rlc_interface_mac *rlc_, srslte::log* log_h_, srslte::timers* timers_db_)
{ {
phy_h = phy_h_; phy_h = phy_h_;
log_h = log_h_; log_h = log_h_;
@ -68,9 +68,9 @@ void demux::deallocate(uint8_t* payload_buffer_ptr)
uint8_t* demux::request_buffer(uint32_t pid, uint32_t len) uint8_t* demux::request_buffer(uint32_t pid, uint32_t len)
{ {
uint8_t *buff = NULL; uint8_t *buff = NULL;
if (pid < NOF_HARQ_PID) { if (pid < nof_harq_proc) {
return pdus.request(len); return pdus.request(len);
} else if (pid == NOF_HARQ_PID) { } else if (pid == nof_harq_proc) {
buff = bcch_buffer; buff = bcch_buffer;
} else { } else {
Error("Requested buffer for invalid PID=%d\n", pid); Error("Requested buffer for invalid PID=%d\n", pid);
@ -119,9 +119,9 @@ void demux::push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes)
*/ */
void demux::push_pdu(uint32_t pid, uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) void demux::push_pdu(uint32_t pid, uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp)
{ {
if (pid < NOF_HARQ_PID) { if (pid < nof_harq_proc) {
return pdus.push(buff, nof_bytes, tstamp); return pdus.push(buff, nof_bytes, tstamp);
} else if (pid == NOF_HARQ_PID) { } else if (pid == nof_harq_proc) {
/* Demultiplexing of MAC PDU associated with SI-RNTI. The PDU passes through /* Demultiplexing of MAC PDU associated with SI-RNTI. The PDU passes through
* the MAC in transparent mode. * the MAC in transparent mode.
* Warning: In this case function sends the message to RLC now, since SI blocks do not * Warning: In this case function sends the message to RLC now, since SI blocks do not
@ -190,8 +190,8 @@ bool demux::process_ce(srslte::sch_subh *subh) {
Info("Received TA=%d\n", subh->get_ta_cmd()); Info("Received TA=%d\n", subh->get_ta_cmd());
// Start or restart timeAlignmentTimer // Start or restart timeAlignmentTimer
timers_db->get(mac::TIME_ALIGNMENT)->reset(); timers_db->get(TIME_ALIGNMENT)->reset();
timers_db->get(mac::TIME_ALIGNMENT)->run(); timers_db->get(TIME_ALIGNMENT)->run();
break; break;
case srslte::sch_subh::PADDING: case srslte::sch_subh::PADDING:
break; break;

@ -1,337 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#include "mac/mac.h"
#include "mac/dl_harq.h"
namespace srsue {
/***********************************************************
*
* HARQ ENTITY
*
*********************************************************/
dl_harq_entity::dl_harq_entity()
{
pcap = NULL;
}
bool dl_harq_entity::init(srslte::log* log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg_, srslte::timers* timers_, demux *demux_unit_)
{
timers_db = timers_;
demux_unit = demux_unit_;
mac_cfg = mac_cfg_;
si_window_start = 0;
log_h = log_h_;
for (uint32_t i=0;i<NOF_HARQ_PROC+1;i++) {
if (!proc[i].init(i, this)) {
return false;
}
}
return true;
}
void dl_harq_entity::start_pcap(srslte::mac_pcap* pcap_)
{
pcap = pcap_;
}
void dl_harq_entity::reset()
{
for (uint32_t i=0;i<NOF_HARQ_PROC+1;i++) {
proc[i].reset();
}
dl_sps_assig.clear();
}
uint32_t dl_harq_entity::get_harq_sps_pid(uint32_t tti) {
return 0;
}
void dl_harq_entity::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action)
{
if (grant.rnti_type != SRSLTE_RNTI_SPS) {
uint32_t harq_pid;
// Set BCCH PID for SI RNTI
if (grant.rnti_type == SRSLTE_RNTI_SI) {
harq_pid = HARQ_BCCH_PID;
} else {
harq_pid = grant.pid%NOF_HARQ_PROC;
}
if (grant.rnti_type == SRSLTE_RNTI_TEMP && last_temporal_crnti != grant.rnti) {
grant.ndi = true;
Info("Set NDI=1 for Temp-RNTI DL grant\n");
last_temporal_crnti = grant.rnti;
}
if (grant.rnti_type == SRSLTE_RNTI_USER && proc[harq_pid].is_sps()) {
grant.ndi = true;
Info("Set NDI=1 for C-RNTI DL grant\n");
}
proc[harq_pid].new_grant_dl(grant, action);
} else {
/* This is for SPS scheduling */
uint32_t harq_pid = get_harq_sps_pid(grant.tti)%NOF_HARQ_PROC;
if (grant.ndi) {
grant.ndi = false;
proc[harq_pid].new_grant_dl(grant, action);
} else {
if (grant.is_sps_release) {
dl_sps_assig.clear();
if (timers_db->get(mac::TIME_ALIGNMENT)->is_running()) {
//phy_h->send_sps_ack();
Warning("PHY Send SPS ACK not implemented\n");
}
} else {
Error("SPS not implemented\n");
//dl_sps_assig.reset(grant.tti, grant);
//grant.ndi = true;
//procs[harq_pid].save_grant();
}
}
}
}
void dl_harq_entity::tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
{
if (rnti_type == SRSLTE_RNTI_SI) {
proc[NOF_HARQ_PROC].tb_decoded(ack);
} else {
proc[harq_pid%NOF_HARQ_PROC].tb_decoded(ack);
}
}
int dl_harq_entity::get_current_tbs(uint32_t harq_pid)
{
return proc[harq_pid%NOF_HARQ_PROC].get_current_tbs();
}
bool dl_harq_entity::generate_ack_callback(void *arg)
{
demux *demux_unit = (demux*) arg;
return demux_unit->get_uecrid_successful();
}
void dl_harq_entity::set_si_window_start(int si_window_start_)
{
si_window_start = si_window_start_;
}
float dl_harq_entity::get_average_retx()
{
return average_retx;
}
/***********************************************************
*
* HARQ PROCESS
*
*********************************************************/
dl_harq_entity::dl_harq_process::dl_harq_process() {
is_initiated = false;
ack = false;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
}
void dl_harq_entity::dl_harq_process::reset() {
ack = false;
payload_buffer_ptr = NULL;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
if (is_initiated) {
srslte_softbuffer_rx_reset(&softbuffer);
}
}
bool dl_harq_entity::dl_harq_process::init(uint32_t pid_, dl_harq_entity *parent) {
if (srslte_softbuffer_rx_init(&softbuffer, 110)) {
Error("Error initiating soft buffer\n");
return false;
} else {
pid = pid_;
is_initiated = true;
harq_entity = parent;
log_h = harq_entity->log_h;
return true;
}
}
bool dl_harq_entity::dl_harq_process::is_sps()
{
return false;
}
bool dl_harq_entity::dl_harq_process::calc_is_new_transmission(mac_interface_phy::mac_grant_t grant) {
bool is_new_tb = true;
if ((srslte_tti_interval(grant.tti, cur_grant.tti) <= 8 && (grant.n_bytes == cur_grant.n_bytes)) ||
pid == HARQ_BCCH_PID)
{
is_new_tb = false;
}
if ((grant.ndi != cur_grant.ndi && !is_new_tb) || // NDI toggled for same TB
is_new_tb || // is new TB
(pid == HARQ_BCCH_PID && grant.rv == 0)) // Broadcast PID and 1st TX (RV=0)
{
is_new_transmission = true;
Debug("Set HARQ for new transmission\n");
} else {
is_new_transmission = false;
Debug("Set HARQ for retransmission\n");
}
return is_new_transmission;
}
void dl_harq_entity::dl_harq_process::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action)
{
// Compute RV for BCCH when not specified in PDCCH format
if (pid == HARQ_BCCH_PID && grant.rv == -1) {
uint32_t k;
if ((grant.tti/10)%2 == 0 && grant.tti%10 == 5) { // This is SIB1, k is different
k = (grant.tti/20)%4;
grant.rv = ((uint32_t) ceilf((float)1.5*k))%4;
} else if (grant.rv == -1) {
k = (grant.tti-harq_entity->si_window_start)%4;
grant.rv = ((uint32_t) ceilf((float)1.5*k))%4;
}
}
calc_is_new_transmission(grant);
if (is_new_transmission) {
ack = false;
srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes*8);
n_retx = 0;
}
// Save grant
grant.last_ndi = cur_grant.ndi;
grant.last_tti = cur_grant.tti;
memcpy(&cur_grant, &grant, sizeof(mac_interface_phy::mac_grant_t));
// Fill action structure
bzero(action, sizeof(mac_interface_phy::tb_action_dl_t));
action->default_ack = ack;
action->generate_ack = true;
action->decode_enabled = false;
// If data has not yet been successfully decoded
if (ack == false) {
// Instruct the PHY To combine the received data and attempt to decode it
payload_buffer_ptr = harq_entity->demux_unit->request_buffer(pid, cur_grant.n_bytes);
action->payload_ptr = payload_buffer_ptr;
if (!action->payload_ptr) {
action->decode_enabled = false;
Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes);
return;
}
action->decode_enabled = true;
action->rv = cur_grant.rv;
action->rnti = cur_grant.rnti;
action->softbuffer = &softbuffer;
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(srslte_phy_grant_t));
n_retx++;
} else {
Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid);
}
if (pid == HARQ_BCCH_PID || harq_entity->timers_db->get(mac::TIME_ALIGNMENT)->is_expired()) {
// Do not generate ACK
Debug("Not generating ACK\n");
action->generate_ack = false;
} else {
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP && ack == false) {
// Postpone ACK after contention resolution is resolved
action->generate_ack_callback = harq_entity->generate_ack_callback;
action->generate_ack_callback_arg = harq_entity->demux_unit;
Debug("ACK pending contention resolution\n");
} else {
Debug("Generating ACK\n");
}
}
}
int dl_harq_entity::dl_harq_process::get_current_tbs()
{
return cur_grant.n_bytes*8;
}
void dl_harq_entity::dl_harq_process::tb_decoded(bool ack_)
{
ack = ack_;
if (ack == true) {
if (pid == HARQ_BCCH_PID) {
if (harq_entity->pcap) {
harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.n_bytes, ack, cur_grant.tti);
}
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes, cur_grant.tti);
} else {
if (harq_entity->pcap) {
harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.n_bytes, cur_grant.rnti, ack, cur_grant.tti);
}
if (ack) {
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP) {
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.n_bytes);
} else {
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes, cur_grant.tti);
// Compute average number of retransmissions per packet
harq_entity->average_retx = SRSLTE_VEC_CMA((float) n_retx, harq_entity->average_retx, harq_entity->nof_pkts++);
}
}
}
} else {
harq_entity->demux_unit->deallocate(payload_buffer_ptr);
}
Info("DL %d: %s tbs=%d, rv=%d, ack=%s, ndi=%d (%d), tti=%d (%d)\n",
pid, is_new_transmission?"newTX":"reTX ",
cur_grant.n_bytes, cur_grant.rv, ack?"OK":"KO",
cur_grant.ndi, cur_grant.last_ndi, cur_grant.tti, cur_grant.last_tti);
if (ack && pid == HARQ_BCCH_PID) {
reset();
}
}
}

@ -42,7 +42,9 @@
namespace srsue { namespace srsue {
mac::mac() : ttisync(10240), mac::mac() : ttisync(10240),
timers_db((uint32_t) NOF_MAC_TIMERS), timers_db((uint32_t) NOF_MAC_TIMERS),
mux_unit(MAC_NOF_HARQ_PROC),
demux_unit(MAC_NOF_HARQ_PROC),
pdu_process_thread(&demux_unit) pdu_process_thread(&demux_unit)
{ {
started = false; started = false;
@ -66,13 +68,13 @@ bool mac::init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac
srslte_softbuffer_rx_init(&pch_softbuffer, 100); srslte_softbuffer_rx_init(&pch_softbuffer, 100);
bsr_procedure.init( rlc_h, log_h, &config, &timers_db); bsr_procedure.init( rlc_h, log_h, &config, &timers_db);
phr_procedure.init(phy_h, log_h, &config, &timers_db); phr_procedure.init(phy_h, log_h, &config, &timers_db);
mux_unit.init ( rlc_h, log_h, &bsr_procedure, &phr_procedure); mux_unit.init ( rlc_h, log_h, &bsr_procedure, &phr_procedure);
demux_unit.init (phy_h, rlc_h, log_h, &timers_db); demux_unit.init (phy_h, rlc_h, log_h, &timers_db);
ra_procedure.init (phy_h, rrc, log_h, &uernti, &config, &timers_db, &mux_unit, &demux_unit); ra_procedure.init (phy_h, rrc, log_h, &uernti, &config, &timers_db, &mux_unit, &demux_unit);
sr_procedure.init (phy_h, rrc, log_h, &config); sr_procedure.init (phy_h, rrc, log_h, &config);
ul_harq.init ( log_h, &uernti, &config, &timers_db, &mux_unit); ul_harq.init ( log_h, &uernti, &config.ul_harq_params, &timers_db, &mux_unit);
dl_harq.init ( log_h, &config, &timers_db, &demux_unit); dl_harq.init ( log_h, &timers_db, &demux_unit);
reset(); reset();
@ -308,7 +310,7 @@ void mac::new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy::
/* Start PHR Periodic timer on first UL grant */ /* Start PHR Periodic timer on first UL grant */
if (is_first_ul_grant) { if (is_first_ul_grant) {
is_first_ul_grant = false; is_first_ul_grant = false;
timers_db.get(mac::PHR_TIMER_PERIODIC)->run(); timers_db.get(PHR_TIMER_PERIODIC)->run();
} }
if (grant.rnti_type == SRSLTE_RNTI_USER && ra_procedure.is_contention_resolution()) { if (grant.rnti_type == SRSLTE_RNTI_USER && ra_procedure.is_contention_resolution()) {
ra_procedure.pdcch_to_crnti(true); ra_procedure.pdcch_to_crnti(true);

@ -37,7 +37,7 @@
namespace srsue { namespace srsue {
mux::mux() : pdu_msg(MAX_NOF_SUBHEADERS) mux::mux(uint8_t nof_harq_proc_) : pdu_msg(MAX_NOF_SUBHEADERS), pid_has_bsr(nof_harq_proc_), nof_harq_proc(nof_harq_proc_)
{ {
pthread_mutex_init(&mutex, NULL); pthread_mutex_init(&mutex, NULL);
@ -51,7 +51,7 @@ mux::mux() : pdu_msg(MAX_NOF_SUBHEADERS)
msg3_flush(); msg3_flush();
} }
void mux::init(rlc_interface_mac *rlc_, srslte::log *log_h_, bsr_proc *bsr_procedure_, phr_proc *phr_procedure_) void mux::init(rlc_interface_mac *rlc_, srslte::log *log_h_, bsr_interface_mux *bsr_procedure_, phr_proc *phr_procedure_)
{ {
log_h = log_h_; log_h = log_h_;
rlc = rlc_; rlc = rlc_;
@ -141,7 +141,7 @@ srslte::sch_subh::cetype bsr_format_convert(bsr_proc::bsr_format_t format) {
void mux::pusch_retx(uint32_t tx_tti, uint32_t pid) void mux::pusch_retx(uint32_t tx_tti, uint32_t pid)
{ {
if (pid_has_bsr[pid%MAX_HARQ_PROC]) { if (pid_has_bsr[pid%nof_harq_proc]) {
bsr_procedure->set_tx_tti(tx_tti); bsr_procedure->set_tx_tti(tx_tti);
} }
} }
@ -189,13 +189,17 @@ uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32
bsr_is_inserted = true; bsr_is_inserted = true;
} }
} }
// MAC control element for PHR // MAC control element for PHR
float phr_value; if (phr_procedure) {
if (phr_procedure->generate_phr_on_ul_grant(&phr_value)) { float phr_value;
if (pdu_msg.new_subh()) { if (phr_procedure->generate_phr_on_ul_grant(&phr_value)) {
pdu_msg.get()->set_phr(phr_value); if (pdu_msg.new_subh()) {
pdu_msg.get()->set_phr(phr_value);
}
} }
} }
// Update buffer states for all logical channels // Update buffer states for all logical channels
int sdu_space = pdu_msg.get_sdu_space(); int sdu_space = pdu_msg.get_sdu_space();
for (uint32_t i=0;i<lch.size();i++) { for (uint32_t i=0;i<lch.size();i++) {
@ -252,7 +256,7 @@ uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32
/* Generate MAC PDU and save to buffer */ /* Generate MAC PDU and save to buffer */
uint8_t *ret = pdu_msg.write_packet(log_h); uint8_t *ret = pdu_msg.write_packet(log_h);
pid_has_bsr[pid%MAX_HARQ_PROC] = bsr_is_inserted; pid_has_bsr[pid%nof_harq_proc] = bsr_is_inserted;
if (bsr_is_inserted) { if (bsr_is_inserted) {
bsr_procedure->set_tx_tti(tx_tti); bsr_procedure->set_tx_tti(tx_tti);
} }

@ -57,10 +57,10 @@ void bsr_proc::init(rlc_interface_mac *rlc_, srslte::log* log_h_, mac_interface_
void bsr_proc::reset() void bsr_proc::reset()
{ {
timers_db->get(mac::BSR_TIMER_PERIODIC)->stop(); timers_db->get(BSR_TIMER_PERIODIC)->stop();
timers_db->get(mac::BSR_TIMER_PERIODIC)->reset(); timers_db->get(BSR_TIMER_PERIODIC)->reset();
timers_db->get(mac::BSR_TIMER_RETX)->stop(); timers_db->get(BSR_TIMER_RETX)->stop();
timers_db->get(mac::BSR_TIMER_RETX)->reset(); timers_db->get(BSR_TIMER_RETX)->reset();
reset_sr = false; reset_sr = false;
sr_is_sent = false; sr_is_sent = false;
@ -78,14 +78,14 @@ void bsr_proc::reset()
/* Process Periodic BSR */ /* Process Periodic BSR */
void bsr_proc::timer_expired(uint32_t timer_id) { void bsr_proc::timer_expired(uint32_t timer_id) {
switch(timer_id) { switch(timer_id) {
case mac::BSR_TIMER_PERIODIC: case BSR_TIMER_PERIODIC:
if (triggered_bsr_type == NONE) { if (triggered_bsr_type == NONE) {
// Check condition 4 in Sec 5.4.5 // Check condition 4 in Sec 5.4.5
triggered_bsr_type = PERIODIC; triggered_bsr_type = PERIODIC;
Debug("BSR: Triggering Periodic BSR\n"); Debug("BSR: Triggering Periodic BSR\n");
} }
break; break;
case mac::BSR_TIMER_RETX: case BSR_TIMER_RETX:
// Enable reTx of SR only if periodic timer is not infinity // Enable reTx of SR only if periodic timer is not infinity
int periodic = liblte_rrc_periodic_bsr_timer_num[mac_cfg->main.ulsch_cnfg.periodic_bsr_timer]; int periodic = liblte_rrc_periodic_bsr_timer_num[mac_cfg->main.ulsch_cnfg.periodic_bsr_timer];
if (periodic >= 0) { if (periodic >= 0) {
@ -222,17 +222,17 @@ void bsr_proc::step(uint32_t tti)
} }
int periodic = liblte_rrc_periodic_bsr_timer_num[mac_cfg->main.ulsch_cnfg.periodic_bsr_timer]; int periodic = liblte_rrc_periodic_bsr_timer_num[mac_cfg->main.ulsch_cnfg.periodic_bsr_timer];
if (periodic > 0 && (uint32_t)periodic != timers_db->get(mac::BSR_TIMER_PERIODIC)->get_timeout()) if (periodic > 0 && (uint32_t)periodic != timers_db->get(BSR_TIMER_PERIODIC)->get_timeout())
{ {
timers_db->get(mac::BSR_TIMER_PERIODIC)->set(this, periodic); timers_db->get(BSR_TIMER_PERIODIC)->set(this, periodic);
timers_db->get(mac::BSR_TIMER_PERIODIC)->run(); timers_db->get(BSR_TIMER_PERIODIC)->run();
Info("BSR: Configured timer periodic %d ms\n", periodic); Info("BSR: Configured timer periodic %d ms\n", periodic);
} }
int retx = liblte_rrc_retransmission_bsr_timer_num[mac_cfg->main.ulsch_cnfg.retx_bsr_timer]; int retx = liblte_rrc_retransmission_bsr_timer_num[mac_cfg->main.ulsch_cnfg.retx_bsr_timer];
if (retx > 0 && (uint32_t)retx != timers_db->get(mac::BSR_TIMER_RETX)->get_timeout()) if (retx > 0 && (uint32_t)retx != timers_db->get(BSR_TIMER_RETX)->get_timeout())
{ {
timers_db->get(mac::BSR_TIMER_RETX)->set(this, retx); timers_db->get(BSR_TIMER_RETX)->set(this, retx);
timers_db->get(mac::BSR_TIMER_RETX)->run(); timers_db->get(BSR_TIMER_RETX)->run();
Info("BSR: Configured timer reTX %d ms\n", retx); Info("BSR: Configured timer reTX %d ms\n", retx);
} }
@ -309,18 +309,18 @@ bool bsr_proc::need_to_send_bsr_on_ul_grant(uint32_t grant_size, bsr_t *bsr)
grant_size, total_data, bsr_sz); grant_size, total_data, bsr_sz);
ret = true; ret = true;
} }
if (timers_db->get(mac::BSR_TIMER_PERIODIC)->get_timeout() && bsr->format != TRUNC_BSR) { if (timers_db->get(BSR_TIMER_PERIODIC)->get_timeout() && bsr->format != TRUNC_BSR) {
timers_db->get(mac::BSR_TIMER_PERIODIC)->reset(); timers_db->get(BSR_TIMER_PERIODIC)->reset();
timers_db->get(mac::BSR_TIMER_PERIODIC)->run(); timers_db->get(BSR_TIMER_PERIODIC)->run();
} }
} }
// Cancel all triggered BSR and SR // Cancel all triggered BSR and SR
triggered_bsr_type = NONE; triggered_bsr_type = NONE;
reset_sr = true; reset_sr = true;
// Restart or Start ReTX timer // Restart or Start ReTX timer
if (timers_db->get(mac::BSR_TIMER_RETX)->get_timeout()) { if (timers_db->get(BSR_TIMER_RETX)->get_timeout()) {
timers_db->get(mac::BSR_TIMER_RETX)->reset(); timers_db->get(BSR_TIMER_RETX)->reset();
timers_db->get(mac::BSR_TIMER_RETX)->run(); timers_db->get(BSR_TIMER_RETX)->run();
} }
return ret; return ret;
} }
@ -340,9 +340,9 @@ bool bsr_proc::generate_padding_bsr(uint32_t nof_padding_bytes, bsr_t *bsr)
bsr_type_tostring(triggered_bsr_type), bsr_format_tostring(bsr->format), bsr_type_tostring(triggered_bsr_type), bsr_format_tostring(bsr->format),
bsr->buff_size[0], bsr->buff_size[1], bsr->buff_size[2], bsr->buff_size[3]); bsr->buff_size[0], bsr->buff_size[1], bsr->buff_size[2], bsr->buff_size[3]);
if (timers_db->get(mac::BSR_TIMER_PERIODIC)->get_timeout() && bsr->format != TRUNC_BSR) { if (timers_db->get(BSR_TIMER_PERIODIC)->get_timeout() && bsr->format != TRUNC_BSR) {
timers_db->get(mac::BSR_TIMER_PERIODIC)->reset(); timers_db->get(BSR_TIMER_PERIODIC)->reset();
timers_db->get(mac::BSR_TIMER_PERIODIC)->run(); timers_db->get(BSR_TIMER_PERIODIC)->run();
} }
} }

@ -76,13 +76,13 @@ bool phr_proc::pathloss_changed() {
/* Trigger PHR when timers exire */ /* Trigger PHR when timers exire */
void phr_proc::timer_expired(uint32_t timer_id) { void phr_proc::timer_expired(uint32_t timer_id) {
switch(timer_id) { switch(timer_id) {
case mac::PHR_TIMER_PERIODIC: case PHR_TIMER_PERIODIC:
timers_db->get(mac::PHR_TIMER_PERIODIC)->reset(); timers_db->get(PHR_TIMER_PERIODIC)->reset();
timers_db->get(mac::PHR_TIMER_PERIODIC)->run(); timers_db->get(PHR_TIMER_PERIODIC)->run();
Debug("PHR: Triggered by timer periodic (timer expired).\n"); Debug("PHR: Triggered by timer periodic (timer expired).\n");
phr_is_triggered = true; phr_is_triggered = true;
break; break;
case mac::PHR_TIMER_PROHIBIT: case PHR_TIMER_PROHIBIT:
int pathloss_db = liblte_rrc_dl_pathloss_change_num[mac_cfg->main.phr_cnfg.dl_pathloss_change]; int pathloss_db = liblte_rrc_dl_pathloss_change_num[mac_cfg->main.phr_cnfg.dl_pathloss_change];
if (pathloss_changed()) { if (pathloss_changed()) {
Info("PHR: Triggered by pathloss difference. cur_pathloss_db=%f (timer expired)\n", last_pathloss_db); Info("PHR: Triggered by pathloss difference. cur_pathloss_db=%f (timer expired)\n", last_pathloss_db);
@ -105,8 +105,8 @@ void phr_proc::step(uint32_t tti)
if (timer_periodic != cfg_timer_periodic && cfg_timer_periodic > 0) if (timer_periodic != cfg_timer_periodic && cfg_timer_periodic > 0)
{ {
timer_periodic = cfg_timer_periodic; timer_periodic = cfg_timer_periodic;
timers_db->get(mac::PHR_TIMER_PERIODIC)->set(this, timer_periodic); timers_db->get(PHR_TIMER_PERIODIC)->set(this, timer_periodic);
timers_db->get(mac::PHR_TIMER_PERIODIC)->run(); timers_db->get(PHR_TIMER_PERIODIC)->run();
phr_is_triggered = true; phr_is_triggered = true;
Info("PHR: Configured timer periodic %d ms\n", timer_periodic); Info("PHR: Configured timer periodic %d ms\n", timer_periodic);
} }
@ -118,12 +118,12 @@ void phr_proc::step(uint32_t tti)
if (timer_prohibit != cfg_timer_prohibit && cfg_timer_prohibit > 0) if (timer_prohibit != cfg_timer_prohibit && cfg_timer_prohibit > 0)
{ {
timer_prohibit = cfg_timer_prohibit; timer_prohibit = cfg_timer_prohibit;
timers_db->get(mac::PHR_TIMER_PROHIBIT)->set(this, timer_prohibit); timers_db->get(PHR_TIMER_PROHIBIT)->set(this, timer_prohibit);
timers_db->get(mac::PHR_TIMER_PROHIBIT)->run(); timers_db->get(PHR_TIMER_PROHIBIT)->run();
Info("PHR: Configured timer prohibit %d ms\n", timer_prohibit); Info("PHR: Configured timer prohibit %d ms\n", timer_prohibit);
phr_is_triggered = true; phr_is_triggered = true;
} }
if (pathloss_changed() && timers_db->get(mac::PHR_TIMER_PROHIBIT)->is_expired()) if (pathloss_changed() && timers_db->get(PHR_TIMER_PROHIBIT)->is_expired())
{ {
Info("PHR: Triggered by pathloss difference. cur_pathloss_db=%f\n", last_pathloss_db); Info("PHR: Triggered by pathloss difference. cur_pathloss_db=%f\n", last_pathloss_db);
phr_is_triggered = true; phr_is_triggered = true;
@ -140,10 +140,10 @@ bool phr_proc::generate_phr_on_ul_grant(float *phr)
Debug("PHR: Generating PHR=%f\n", phr?*phr:0.0); Debug("PHR: Generating PHR=%f\n", phr?*phr:0.0);
timers_db->get(mac::PHR_TIMER_PERIODIC)->reset(); timers_db->get(PHR_TIMER_PERIODIC)->reset();
timers_db->get(mac::PHR_TIMER_PROHIBIT)->reset(); timers_db->get(PHR_TIMER_PROHIBIT)->reset();
timers_db->get(mac::PHR_TIMER_PERIODIC)->run(); timers_db->get(PHR_TIMER_PERIODIC)->run();
timers_db->get(mac::PHR_TIMER_PROHIBIT)->run(); timers_db->get(PHR_TIMER_PROHIBIT)->run();
phr_is_triggered = false; phr_is_triggered = false;

@ -115,7 +115,7 @@ void ra_proc::read_params() {
delta_preamble_db = delta_preamble_db_table[configIndex%5]; delta_preamble_db = delta_preamble_db_table[configIndex%5];
if (contentionResolutionTimer > 0) { if (contentionResolutionTimer > 0) {
timers_db->get(mac::CONTENTION_TIMER)->set(this, contentionResolutionTimer); timers_db->get(CONTENTION_TIMER)->set(this, contentionResolutionTimer);
} }
} }
@ -165,14 +165,14 @@ void ra_proc::process_timeadv_cmd(uint32_t ta) {
if (preambleIndex == 0) { if (preambleIndex == 0) {
// Preamble not selected by UE MAC // Preamble not selected by UE MAC
phy_h->set_timeadv_rar(ta); phy_h->set_timeadv_rar(ta);
timers_db->get(mac::TIME_ALIGNMENT)->reset(); timers_db->get(TIME_ALIGNMENT)->reset();
timers_db->get(mac::TIME_ALIGNMENT)->run(); timers_db->get(TIME_ALIGNMENT)->run();
Debug("Applying RAR TA CMD %d\n", ta); Debug("Applying RAR TA CMD %d\n", ta);
} else { } else {
// Preamble selected by UE MAC // Preamble selected by UE MAC
if (!timers_db->get(mac::TIME_ALIGNMENT)->is_running()) { if (!timers_db->get(TIME_ALIGNMENT)->is_running()) {
phy_h->set_timeadv_rar(ta); phy_h->set_timeadv_rar(ta);
timers_db->get(mac::TIME_ALIGNMENT)->run(); timers_db->get(TIME_ALIGNMENT)->run();
Debug("Applying RAR TA CMD %d\n", ta); Debug("Applying RAR TA CMD %d\n", ta);
} else { } else {
// Ignore TA CMD // Ignore TA CMD
@ -355,8 +355,8 @@ void ra_proc::tb_decoded_ok() {
state = CONTENTION_RESOLUTION; state = CONTENTION_RESOLUTION;
// Start contention resolution timer // Start contention resolution timer
timers_db->get(mac::CONTENTION_TIMER)->reset(); timers_db->get(CONTENTION_TIMER)->reset();
timers_db->get(mac::CONTENTION_TIMER)->run(); timers_db->get(CONTENTION_TIMER)->run();
} }
} else { } else {
rDebug("Found RAR for preamble %d\n", rar_pdu_msg.get()->get_rapid()); rDebug("Found RAR for preamble %d\n", rar_pdu_msg.get()->get_rapid());
@ -417,7 +417,7 @@ bool ra_proc::contention_resolution_id_received(uint64_t rx_contention_id) {
rDebug("MAC PDU Contains Contention Resolution ID CE\n"); rDebug("MAC PDU Contains Contention Resolution ID CE\n");
// MAC PDU successfully decoded and contains MAC CE contention Id // MAC PDU successfully decoded and contains MAC CE contention Id
timers_db->get(mac::CONTENTION_TIMER)->stop(); timers_db->get(CONTENTION_TIMER)->stop();
if (transmitted_contention_id == rx_contention_id) if (transmitted_contention_id == rx_contention_id)
{ {
@ -453,7 +453,7 @@ void ra_proc::step_contention_resolution() {
(started_by_pdcch && pdcch_to_crnti_received != PDCCH_CRNTI_NOT_RECEIVED)) (started_by_pdcch && pdcch_to_crnti_received != PDCCH_CRNTI_NOT_RECEIVED))
{ {
rDebug("PDCCH for C-RNTI received\n"); rDebug("PDCCH for C-RNTI received\n");
timers_db->get(mac::CONTENTION_TIMER)->stop(); timers_db->get(CONTENTION_TIMER)->stop();
rntis->temp_rnti = 0; rntis->temp_rnti = 0;
state = COMPLETION; state = COMPLETION;
} }
@ -559,7 +559,7 @@ void ra_proc::pdcch_to_crnti(bool contains_uplink_grant) {
void ra_proc::harq_retx() void ra_proc::harq_retx()
{ {
timers_db->get(mac::CONTENTION_TIMER)->reset(); timers_db->get(CONTENTION_TIMER)->reset();
} }
} }

@ -1,394 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#include "srslte/common/log.h"
#include "mac/mac.h"
#include "mac/ul_harq.h"
namespace srsue {
/***********************************************************
*
* HARQ ENTITY
*
*********************************************************/
bool ul_harq_entity::init(srslte::log *log_h_,
mac_interface_rrc::ue_rnti_t *rntis_,
mac_interface_rrc::mac_cfg_t *mac_cfg_,
srslte::timers *timers_db_,
mux *mux_unit_) {
log_h = log_h_;
mux_unit = mux_unit_;
mac_cfg = mac_cfg_;
rntis = rntis_;
timers_db = timers_db_;
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
if (!proc[i].init(i, this)) {
return false;
}
}
return true;
}
uint32_t ul_harq_entity::pidof(uint32_t tti) {
return (uint32_t) tti%NOF_HARQ_PROC;
}
void ul_harq_entity::start_pcap(srslte::mac_pcap* pcap_)
{
pcap = pcap_;
}
void ul_harq_entity::reset() {
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
proc[i].reset();
}
ul_sps_assig.clear();
}
void ul_harq_entity::reset_ndi() {
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
proc[i].reset_ndi();
}
}
int ul_harq_entity::get_current_tbs(uint32_t tti) {
int tti_harq = (int) tti-4;
if (tti_harq < 0) {
tti_harq += 10240;
}
uint32_t pid_harq = pidof(tti_harq);
return proc[pid_harq].get_current_tbs();
}
void ul_harq_entity::set_ack(uint32_t tti, bool ack) {
int tti_harq = (int) tti - 4;
if (tti_harq < 0) {
tti_harq += 10240;
}
uint32_t pid_harq = pidof(tti_harq);
if (proc[pid_harq].has_grant() && (proc[pid_harq].last_tx_tti() <= (uint32_t)tti_harq)) {
proc[pid_harq].set_harq_feedback(ack);
}
}
void ul_harq_entity::harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t* action)
{
set_ack(tti, ack);
run_tti(tti, NULL, action);
}
// Implements Section 5.4.1
void ul_harq_entity::new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_ul_t* action)
{
if (grant.rnti_type == SRSLTE_RNTI_USER ||
grant.rnti_type == SRSLTE_RNTI_TEMP ||
grant.rnti_type == SRSLTE_RNTI_RAR)
{
if (grant.rnti_type == SRSLTE_RNTI_USER && proc[pidof(grant.tti)].is_sps()) {
grant.ndi = true;
}
run_tti(grant.tti, &grant, action);
} else if (grant.rnti_type == SRSLTE_RNTI_SPS) {
if (grant.ndi) {
grant.ndi = proc[pidof(grant.tti)].get_ndi();
run_tti(grant.tti, &grant, action);
} else {
Info("Not implemented\n");
}
}
}
void ul_harq_entity::new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t* action)
{
set_ack(grant.tti, ack);
new_grant_ul(grant, action);
}
// Implements Section 5.4.2.1
// Called with UL grant
void ul_harq_entity::run_tti(uint32_t tti, mac_interface_phy::mac_grant_t *grant, mac_interface_phy::tb_action_ul_t* action)
{
uint32_t tti_tx = (tti+4)%10240;
proc[pidof(tti_tx)].run_tti(tti_tx, grant, action);
}
float ul_harq_entity::get_average_retx()
{
return average_retx;
}
/***********************************************************
*
* HARQ PROCESS
*
*********************************************************/
static int rv_of_irv[4] = {0, 2, 3, 1};
static int irv_of_rv[4] = {0, 3, 1, 2};
ul_harq_entity::ul_harq_process::ul_harq_process() {
current_tx_nb = 0;
current_irv = 0;
is_initiated = false;
is_grant_configured = false;
tti_last_tx = 0;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
}
void ul_harq_entity::ul_harq_process::reset() {
current_tx_nb = 0;
current_irv = 0;
tti_last_tx = 0;
is_grant_configured = false;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
}
bool ul_harq_entity::ul_harq_process::has_grant() {
return is_grant_configured;
}
void ul_harq_entity::ul_harq_process::reset_ndi() {
ndi = false;
}
bool ul_harq_entity::ul_harq_process::get_ndi()
{
return ndi;
}
uint32_t ul_harq_entity::ul_harq_process::get_rv()
{
return rv_of_irv[current_irv%4];
}
void ul_harq_entity::ul_harq_process::set_harq_feedback(bool ack) {
harq_feedback = ack;
// UL packet successfully delivered
if (ack) {
Info("UL %d: HARQ = ACK for UL transmission. Discarting TB.\n", pid);
reset();
} else {
Info("UL %d: HARQ = NACK for UL transmission\n", pid);
}
}
bool ul_harq_entity::ul_harq_process::init(uint32_t pid_, ul_harq_entity* parent) {
if (srslte_softbuffer_tx_init(&softbuffer, 110)) {
fprintf(stderr, "Error initiating soft buffer\n");
return false;
} else {
is_initiated = true;
harq_entity = parent;
log_h = harq_entity->log_h;
pid = pid_;
payload_buffer = (uint8_t*) srslte_vec_malloc(payload_buffer_len*sizeof(uint8_t));
if (!payload_buffer) {
Error("Allocating memory\n");
return false;
}
pdu_ptr = payload_buffer;
return true;
}
}
void ul_harq_entity::ul_harq_process::run_tti(uint32_t tti_tx, mac_interface_phy::mac_grant_t* grant, mac_interface_phy::tb_action_ul_t* action)
{
uint32_t max_retx;
if (is_msg3) {
max_retx = harq_entity->mac_cfg->rach.max_harq_msg3_tx;
} else {
max_retx = liblte_rrc_max_harq_tx_num[harq_entity->mac_cfg->main.ulsch_cnfg.max_harq_tx];
}
// Receive and route HARQ feedbacks
if (grant) {
if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi != get_ndi()) ||
(grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) ||
grant->is_from_rar)
{
// New transmission
// Uplink grant in a RAR
if (grant->is_from_rar) {
Debug("Getting Msg3 buffer payload, grant size=%d bytes\n", grant->n_bytes);
pdu_ptr = harq_entity->mux_unit->msg3_get(payload_buffer, grant->n_bytes);
if (pdu_ptr) {
generate_new_tx(tti_tx, true, grant, action);
} else {
Warning("UL RAR grant available but no Msg3 on buffer\n");
}
// Normal UL grant
} else {
// Request a MAC PDU from the Multiplexing & Assemble Unit
pdu_ptr = harq_entity->mux_unit->pdu_get(payload_buffer, grant->n_bytes, tti_tx, pid);
if (pdu_ptr) {
generate_new_tx(tti_tx, false, grant, action);
} else {
Warning("Uplink grant but no MAC PDU in Multiplex Unit buffer\n");
}
}
} else {
// Adaptive Re-TX
if (current_tx_nb >= max_retx) {
Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx);
reset();
action->expect_ack = false;
} else {
generate_retx(tti_tx, grant, action);
}
}
} else if (has_grant()) {
// Non-Adaptive Re-Tx
if (current_tx_nb >= max_retx) {
Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx);
reset();
action->expect_ack = false;
} else {
generate_retx(tti_tx, action);
}
}
if (harq_entity->pcap && grant) {
if (grant->is_from_rar) {
grant->rnti = harq_entity->rntis->temp_rnti;
}
harq_entity->pcap->write_ul_crnti(pdu_ptr, grant->n_bytes, grant->rnti, get_nof_retx(), tti_tx);
}
}
int ul_harq_entity::ul_harq_process::get_current_tbs()
{
return cur_grant.n_bytes*8;
}
void ul_harq_entity::ul_harq_process::generate_retx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action)
{
generate_retx(tti_tx, NULL, action);
}
// Retransmission with or w/o grant (Section 5.4.2.2)
void ul_harq_entity::ul_harq_process::generate_retx(uint32_t tti_tx, mac_interface_phy::mac_grant_t *grant,
mac_interface_phy::tb_action_ul_t *action)
{
if (grant) {
// HARQ entity requests an adaptive transmission
if (grant->rv) {
current_irv = irv_of_rv[grant->rv%4];
}
memcpy(&cur_grant, grant, sizeof(mac_interface_phy::mac_grant_t));
harq_feedback = false;
Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d\n",
pid, current_tx_nb, get_rv(), grant->n_bytes);
generate_tx(tti_tx, action);
} else {
Info("UL %d: Non-Adaptive retx=%d, RV=%d, TBS=%d\n",
pid, current_tx_nb, get_rv(), cur_grant.n_bytes);
// HARQ entity requests a non-adaptive transmission
if (!harq_feedback) {
generate_tx(tti_tx, action);
}
}
// On every Msg3 retransmission, restart mac-ContentionResolutionTimer as defined in Section 5.1.5
if (is_msg3) {
harq_entity->timers_db->get(mac::CONTENTION_TIMER)->reset();
}
harq_entity->mux_unit->pusch_retx(tti_tx, pid);
}
// New transmission (Section 5.4.2.2)
void ul_harq_entity::ul_harq_process::generate_new_tx(uint32_t tti_tx, bool is_msg3_,
mac_interface_phy::mac_grant_t *grant,
mac_interface_phy::tb_action_ul_t *action)
{
if (grant) {
// Compute average number of retransmissions per packet considering previous packet
harq_entity->average_retx = SRSLTE_VEC_CMA((float) current_tx_nb, harq_entity->average_retx, harq_entity->nof_pkts++);
memcpy(&cur_grant, grant, sizeof(mac_interface_phy::mac_grant_t));
harq_feedback = false;
is_grant_configured = true;
current_tx_nb = 0;
current_irv = 0;
is_msg3 = is_msg3_;
Info("UL %d: New TX%s, RV=%d, TBS=%d, RNTI=%d\n",
pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes, cur_grant.rnti);
generate_tx(tti_tx, action);
}
}
// Transmission of pending frame (Section 5.4.2.2)
void ul_harq_entity::ul_harq_process::generate_tx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action)
{
action->current_tx_nb = current_tx_nb;
current_tx_nb++;
action->expect_ack = true;
action->rnti = is_msg3?harq_entity->rntis->temp_rnti:cur_grant.rnti;
action->rv = cur_grant.rv>0?cur_grant.rv:get_rv();
action->softbuffer = &softbuffer;
action->tx_enabled = true;
action->payload_ptr = pdu_ptr;
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(srslte_phy_grant_t));
current_irv = (current_irv+1)%4;
tti_last_tx = tti_tx;
}
bool ul_harq_entity::ul_harq_process::is_sps()
{
return false;
}
uint32_t ul_harq_entity::ul_harq_process::last_tx_tti()
{
return tti_last_tx;
}
uint32_t ul_harq_entity::ul_harq_process::get_nof_retx()
{
return current_tx_nb;
}
}

@ -126,7 +126,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
"index of the core used by the sync thread") "index of the core used by the sync thread")
("expert.ue_category", ("expert.ue_category",
bpo::value<int>(&args->expert.ue_cateogry)->default_value(4), bpo::value<string>(&args->expert.ue_cateogry)->default_value("4"),
"UE Category (1 to 5)") "UE Category (1 to 5)")
("expert.metrics_period_secs", ("expert.metrics_period_secs",
@ -342,18 +342,26 @@ void *input_loop(void *m) {
return NULL; return NULL;
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[])
{
signal(SIGINT, sig_int_handler); signal(SIGINT, sig_int_handler);
all_args_t args; all_args_t args;
metrics_stdout metrics; parse_args(&args, argc, argv);
ue *ue = ue::get_instance();
cout << "--- Software Radio Systems LTE UE ---" << endl << endl;
parse_args(&args, argc, argv); srsue_instance_type_t type = LTE;
ue_base *ue = ue_base::get_instance(type);
if (!ue) {
cout << "Error creating UE instance." << endl << endl;
exit(1);
}
cout << "--- Software Radio Systems " << srsue_instance_type_text[type] << " UE ---" << endl << endl;
if (!ue->init(&args)) { if (!ue->init(&args)) {
exit(1); exit(1);
} }
metrics_stdout metrics;
metrics.init(ue, args.expert.metrics_period_secs); metrics.init(ue, args.expert.metrics_period_secs);
pthread_t input; pthread_t input;

@ -240,6 +240,9 @@ void phch_worker::work_imp()
set_uci_periodic_cqi(); set_uci_periodic_cqi();
} }
/* TTI offset for UL is always 4 for LTE */
ul_action.tti_offset = 4;
/* Send UL grant or HARQ information (from PHICH) to MAC */ /* Send UL grant or HARQ information (from PHICH) to MAC */
if (ul_grant_available && ul_ack_available) { if (ul_grant_available && ul_ack_available) {
phy->mac->new_grant_ul_ack(ul_mac_grant, ul_ack, &ul_action); phy->mac->new_grant_ul_ack(ul_mac_grant, ul_ack, &ul_action);

@ -26,7 +26,6 @@
#include "ue.h" #include "ue.h"
//#include "srslte_version_check.h"
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include <pthread.h> #include <pthread.h>
#include <iostream> #include <iostream>
@ -38,28 +37,6 @@ using namespace srslte;
namespace srsue{ namespace srsue{
ue* ue::instance = NULL;
pthread_mutex_t ue_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
ue* ue::get_instance(void)
{
pthread_mutex_lock(&ue_instance_mutex);
if(NULL == instance) {
instance = new ue();
}
pthread_mutex_unlock(&ue_instance_mutex);
return(instance);
}
void ue::cleanup(void)
{
pthread_mutex_lock(&ue_instance_mutex);
if(NULL != instance) {
delete instance;
instance = NULL;
}
pthread_mutex_unlock(&ue_instance_mutex);
}
ue::ue() ue::ue()
:started(false) :started(false)
{ {
@ -184,14 +161,15 @@ bool ue::init(all_args_t *args_)
phy_log.console("Setting frequency: DL=%.1f Mhz, UL=%.1f MHz\n", args->rf.dl_freq/1e6, args->rf.ul_freq/1e6); phy_log.console("Setting frequency: DL=%.1f Mhz, UL=%.1f MHz\n", args->rf.dl_freq/1e6, args->rf.ul_freq/1e6);
mac.init(&phy, &rlc, &rrc, &mac_log); mac.init(&phy, &rlc, &rrc, &mac_log);
rlc.init(&pdcp, &rrc, this, &rlc_log, &mac); rlc.init(&pdcp, &rrc, this, &rlc_log, &mac, 0 /* RB_ID_SRB0 */);
pdcp.init(&rlc, &rrc, &gw, &pdcp_log, SECURITY_DIRECTION_UPLINK);
pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK);
rrc.init(&phy, &mac, &rlc, &pdcp, &nas, &usim, &mac, &rrc_log); rrc.init(&phy, &mac, &rlc, &pdcp, &nas, &usim, &mac, &rrc_log);
rrc.set_ue_category(atoi(args->expert.ue_cateogry.c_str()));
rrc.set_ue_category(args->expert.ue_cateogry); nas.init(&usim, &rrc, &gw, &nas_log, 1 /* RB_ID_SRB1 */);
gw.init(&pdcp, &rrc, this, &gw_log, 3 /* RB_ID_DRB1 */);
nas.init(&usim, &rrc, &gw, &nas_log);
gw.init(&pdcp, &rrc, this, &gw_log);
usim.init(&args->usim, &usim_log); usim.init(&args->usim, &usim_log);
started = true; started = true;
@ -271,49 +249,8 @@ bool ue::get_metrics(ue_metrics_t &m)
void ue::rf_msg(srslte_rf_error_t error) void ue::rf_msg(srslte_rf_error_t error)
{ {
ue *u = ue::get_instance(); ue_base *ue = ue_base::get_instance(LTE);
u->handle_rf_msg(error); ue->handle_rf_msg(error);
}
void ue::handle_rf_msg(srslte_rf_error_t error)
{
if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OVERFLOW) {
rf_metrics.rf_o++;
rf_metrics.rf_error = true;
rf_log.warning("Overflow\n");
}else if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_UNDERFLOW) {
rf_metrics.rf_u++;
rf_metrics.rf_error = true;
rf_log.warning("Underflow\n");
} else if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_LATE) {
rf_metrics.rf_l++;
rf_metrics.rf_error = true;
rf_log.warning("Late\n");
} else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OTHER) {
std::string str(error.msg);
str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());
str.erase(std::remove(str.begin(), str.end(), '\r'), str.end());
str.push_back('\n');
rf_log.info(str);
}
}
srslte::LOG_LEVEL_ENUM ue::level(std::string l)
{
std::transform(l.begin(), l.end(), l.begin(), ::toupper);
if("NONE" == l){
return srslte::LOG_LEVEL_NONE;
}else if("ERROR" == l){
return srslte::LOG_LEVEL_ERROR;
}else if("WARNING" == l){
return srslte::LOG_LEVEL_WARNING;
}else if("INFO" == l){
return srslte::LOG_LEVEL_INFO;
}else if("DEBUG" == l){
return srslte::LOG_LEVEL_DEBUG;
}else{
return srslte::LOG_LEVEL_NONE;
}
} }
} // namespace srsue } // namespace srsue

@ -0,0 +1,111 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "ue_base.h"
#include "ue.h"
#include "srslte/srslte.h"
#include <pthread.h>
#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
using namespace srslte;
namespace srsue{
static ue_base* instance = NULL;
pthread_mutex_t ue_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
ue_base* ue_base::get_instance(srsue_instance_type_t type)
{
pthread_mutex_lock(&ue_instance_mutex);
if(NULL == instance) {
switch (type) {
case LTE:
instance = new ue();
break;
default:
perror("Unknown UE type.\n");
}
}
pthread_mutex_unlock(&ue_instance_mutex);
return(instance);
}
void ue_base::cleanup(void)
{
pthread_mutex_lock(&ue_instance_mutex);
if(NULL != instance) {
delete instance;
instance = NULL;
}
pthread_mutex_unlock(&ue_instance_mutex);
}
void ue_base::handle_rf_msg(srslte_rf_error_t error)
{
if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OVERFLOW) {
rf_metrics.rf_o++;
rf_metrics.rf_error = true;
rf_log.warning("Overflow\n");
}else if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_UNDERFLOW) {
rf_metrics.rf_u++;
rf_metrics.rf_error = true;
rf_log.warning("Underflow\n");
} else if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_LATE) {
rf_metrics.rf_l++;
rf_metrics.rf_error = true;
rf_log.warning("Late\n");
} else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OTHER) {
std::string str(error.msg);
str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());
str.erase(std::remove(str.begin(), str.end(), '\r'), str.end());
str.push_back('\n');
rf_log.info(str);
}
}
srslte::LOG_LEVEL_ENUM ue_base::level(std::string l)
{
std::transform(l.begin(), l.end(), l.begin(), ::toupper);
if("NONE" == l){
return srslte::LOG_LEVEL_NONE;
}else if("ERROR" == l){
return srslte::LOG_LEVEL_ERROR;
}else if("WARNING" == l){
return srslte::LOG_LEVEL_WARNING;
}else if("INFO" == l){
return srslte::LOG_LEVEL_INFO;
}else if("DEBUG" == l){
return srslte::LOG_LEVEL_DEBUG;
}else{
return srslte::LOG_LEVEL_NONE;
}
}
} // namespace srsue

@ -43,13 +43,15 @@ nas::nas()
void nas::init(usim_interface_nas *usim_, void nas::init(usim_interface_nas *usim_,
rrc_interface_nas *rrc_, rrc_interface_nas *rrc_,
gw_interface_nas *gw_, gw_interface_nas *gw_,
srslte::log *nas_log_) srslte::log *nas_log_,
uint32_t lcid_)
{ {
pool = byte_buffer_pool::get_instance(); pool = byte_buffer_pool::get_instance();
usim = usim_; usim = usim_;
rrc = rrc_; rrc = rrc_;
gw = gw_; gw = gw_;
nas_log = nas_log_; nas_log = nas_log_;
default_lcid = lcid_;
} }
void nas::stop() void nas::stop()
@ -85,7 +87,7 @@ void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu)
uint8 pd; uint8 pd;
uint8 msg_type; uint8 msg_type;
nas_log->info_hex(pdu->msg, pdu->N_bytes, "DL %s PDU", rb_id_text[lcid]); nas_log->info_hex(pdu->msg, pdu->N_bytes, "DL %s PDU", rrc->get_rb_name(lcid).c_str());
// Parse the message // Parse the message
liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT*)pdu, &pd, &msg_type); liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT*)pdu, &pd, &msg_type);
@ -492,8 +494,8 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu)
pdu->N_bytes-5, pdu->N_bytes-5,
&pdu->msg[1]); &pdu->msg[1]);
nas_log->info("Sending Security Mode Complete nas_count_ul=%d, RB=%s\n", nas_log->info("Sending Security Mode Complete nas_count_ul=%d, RB=%s\n",
count_ul, count_ul,
rb_id_text[lcid]); rrc->get_rb_name(lcid).c_str());
success = true; success = true;
} }
} }
@ -572,7 +574,7 @@ void nas::send_attach_request()
liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT*)msg); liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT*)msg);
nas_log->info("Sending attach request\n"); nas_log->info("Sending attach request\n");
rrc->write_sdu(RB_ID_SRB1, msg); rrc->write_sdu(default_lcid, msg);
} }
void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg)
@ -614,7 +616,7 @@ void nas::send_service_request()
uint8_t mac[4]; uint8_t mac[4];
integrity_generate(&k_nas_int[16], integrity_generate(&k_nas_int[16],
count_ul, count_ul,
RB_ID_SRB1-1, default_lcid-1,
SECURITY_DIRECTION_UPLINK, SECURITY_DIRECTION_UPLINK,
&msg->msg[0], &msg->msg[0],
2, 2,
@ -625,7 +627,7 @@ void nas::send_service_request()
msg->msg[3] = mac[3]; msg->msg[3] = mac[3];
msg->N_bytes++; msg->N_bytes++;
nas_log->info("Sending service request\n"); nas_log->info("Sending service request\n");
rrc->write_sdu(RB_ID_SRB1, msg); rrc->write_sdu(default_lcid, msg);
} }
void nas::send_esm_information_response(){} void nas::send_esm_information_response(){}

@ -32,6 +32,7 @@
#include "srslte/phy/utils/bit.h" #include "srslte/phy/utils/bit.h"
#include "srslte/common/security.h" #include "srslte/common/security.h"
#include "srslte/common/bcd_helpers.h" #include "srslte/common/bcd_helpers.h"
#include "boost/assign.hpp"
#define TIMEOUT_RESYNC_REESTABLISH 100 #define TIMEOUT_RESYNC_REESTABLISH 100
@ -42,7 +43,9 @@ namespace srsue{
rrc::rrc() rrc::rrc()
:state(RRC_STATE_IDLE) :state(RRC_STATE_IDLE)
,drb_up(false) ,drb_up(false)
{} {
set_bearers();
}
static void liblte_rrc_handler(void *ctx, char *str) { static void liblte_rrc_handler(void *ctx, char *str) {
rrc *r = (rrc*) ctx; rrc *r = (rrc*) ctx;
@ -116,7 +119,7 @@ void rrc::set_ue_category(int category)
void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu)
{ {
rrc_log->info_hex(sdu->msg, sdu->N_bytes, "RX %s SDU", rb_id_text[lcid]); rrc_log->info_hex(sdu->msg, sdu->N_bytes, "RX %s SDU", bearers.at(lcid).c_str());
switch(state) switch(state)
{ {
@ -227,7 +230,7 @@ bool rrc::have_drb()
void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu)
{ {
rrc_log->info_hex(pdu->msg, pdu->N_bytes, "TX %s PDU", rb_id_text[lcid]); rrc_log->info_hex(pdu->msg, pdu->N_bytes, "TX %s PDU", bearers.at(lcid).c_str());
rrc_log->info("TX PDU Stack latency: %ld us\n", pdu->get_latency_us()); rrc_log->info("TX PDU Stack latency: %ld us\n", pdu->get_latency_us());
switch(lcid) switch(lcid)
@ -793,7 +796,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu)
liblte_rrc_unpack_dl_dcch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dl_dcch_msg); liblte_rrc_unpack_dl_dcch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dl_dcch_msg);
rrc_log->info("%s - Received %s\n", rrc_log->info("%s - Received %s\n",
rb_id_text[lcid], bearers.at(lcid).c_str(),
liblte_rrc_dl_dcch_msg_type_text[dl_dcch_msg.msg_type]); liblte_rrc_dl_dcch_msg_type_text[dl_dcch_msg.msg_type]);
// Reset and reuse pdu buffer if possible // Reset and reuse pdu buffer if possible
@ -989,7 +992,8 @@ void rrc::apply_sib2_configs()
mac->get_config(&cfg); mac->get_config(&cfg);
cfg.main.time_alignment_timer = sib2.time_alignment_timer; cfg.main.time_alignment_timer = sib2.time_alignment_timer;
memcpy(&cfg.rach, &sib2.rr_config_common_sib.rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT)); memcpy(&cfg.rach, &sib2.rr_config_common_sib.rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT));
cfg.prach_config_index = sib2.rr_config_common_sib.prach_cnfg.root_sequence_index; cfg.prach_config_index = sib2.rr_config_common_sib.prach_cnfg.root_sequence_index;
cfg.ul_harq_params.max_harq_msg3_tx = cfg.rach.max_harq_msg3_tx;
mac->set_config(&cfg); mac->set_config(&cfg);
rrc_log->info("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms\n", rrc_log->info("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms\n",
@ -1218,7 +1222,13 @@ void rrc::apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cnfg
} }
// Setup MAC configuration // Setup MAC configuration
mac->set_config_main(&default_cfg); mac->set_config_main(&default_cfg);
// Update UL HARQ config
mac_interface_rrc::mac_cfg_t cfg;
mac->get_config(&cfg);
cfg.ul_harq_params.max_harq_tx = liblte_rrc_max_harq_tx_num[default_cfg.ulsch_cnfg.max_harq_tx];
mac->set_config(&cfg);
rrc_log->info("Set MAC main config: harq-MaxReTX=%d, bsr-TimerReTX=%d, bsr-TimerPeriodic=%d\n", rrc_log->info("Set MAC main config: harq-MaxReTX=%d, bsr-TimerReTX=%d, bsr-TimerPeriodic=%d\n",
liblte_rrc_max_harq_tx_num[default_cfg.ulsch_cnfg.max_harq_tx], liblte_rrc_max_harq_tx_num[default_cfg.ulsch_cnfg.max_harq_tx],
@ -1319,9 +1329,10 @@ void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGU
void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg) void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg)
{ {
// Setup PDCP // Setup PDCP
pdcp->add_bearer(srb_cnfg->srb_id); pdcp->add_bearer(srb_cnfg->srb_id, srslte_pdcp_config_t(true)); // Set PDCP config control flag
if(RB_ID_SRB2 == srb_cnfg->srb_id) if(RB_ID_SRB2 == srb_cnfg->srb_id) {
pdcp->config_security(srb_cnfg->srb_id, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); pdcp->config_security(srb_cnfg->srb_id, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo);
}
// Setup RLC // Setup RLC
if(srb_cnfg->rlc_cnfg_present) if(srb_cnfg->rlc_cnfg_present)
@ -1330,7 +1341,7 @@ void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg)
{ {
rlc->add_bearer(srb_cnfg->srb_id); rlc->add_bearer(srb_cnfg->srb_id);
}else{ }else{
rlc->add_bearer(srb_cnfg->srb_id, &srb_cnfg->rlc_explicit_cnfg); rlc->add_bearer(srb_cnfg->srb_id, srslte_rlc_config_t(&srb_cnfg->rlc_explicit_cnfg));
} }
} }
@ -1365,7 +1376,7 @@ void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg)
} }
srbs[srb_cnfg->srb_id] = *srb_cnfg; srbs[srb_cnfg->srb_id] = *srb_cnfg;
rrc_log->info("Added radio bearer %s\n", rb_id_text[srb_cnfg->srb_id]); rrc_log->info("Added radio bearer %s\n", bearers.at(srb_cnfg->srb_id).c_str());
} }
void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg)
@ -1387,11 +1398,18 @@ void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg)
} }
// Setup PDCP // Setup PDCP
pdcp->add_bearer(lcid, &drb_cnfg->pdcp_cnfg); srslte_pdcp_config_t pdcp_cfg;
pdcp_cfg.is_data = true;
if (drb_cnfg->pdcp_cnfg.rlc_um_pdcp_sn_size_present) {
if (LIBLTE_RRC_PDCP_SN_SIZE_7_BITS == drb_cnfg->pdcp_cnfg.rlc_um_pdcp_sn_size) {
pdcp_cfg.sn_len = 7;
}
}
pdcp->add_bearer(lcid, pdcp_cfg);
// TODO: setup PDCP security (using k_up_enc) // TODO: setup PDCP security (using k_up_enc)
// Setup RLC // Setup RLC
rlc->add_bearer(lcid, &drb_cnfg->rlc_cnfg); rlc->add_bearer(lcid, srslte_rlc_config_t(&drb_cnfg->rlc_cnfg));
// Setup MAC // Setup MAC
uint8_t log_chan_group = 0; uint8_t log_chan_group = 0;
@ -1419,7 +1437,7 @@ void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg)
drbs[lcid] = *drb_cnfg; drbs[lcid] = *drb_cnfg;
drb_up = true; drb_up = true;
rrc_log->info("Added radio bearer %s\n", rb_id_text[lcid]); rrc_log->info("Added radio bearer %s\n", bearers.at(lcid).c_str());
} }
void rrc::release_drb(uint8_t lcid) void rrc::release_drb(uint8_t lcid)
@ -1479,4 +1497,19 @@ void rrc::set_rrc_default() {
mac_timers->get(safe_reset_timer)->set(this, 10); mac_timers->get(safe_reset_timer)->set(this, 10);
} }
void rrc::set_bearers()
{
boost::assign::insert(bearers) (RB_ID_SRB0, "SRB0")
(RB_ID_SRB1, "SRB1")
(RB_ID_SRB2, "SRB2")
(RB_ID_DRB1, "DRB1")
(RB_ID_DRB2, "DRB2")
(RB_ID_DRB3, "DRB3")
(RB_ID_DRB4, "DRB4")
(RB_ID_DRB5, "DRB5")
(RB_ID_DRB6, "DRB6")
(RB_ID_DRB7, "DRB7")
(RB_ID_DRB8, "DRB8");
}
} // namespace srsue } // namespace srsue

@ -269,6 +269,7 @@ public:
} }
void write_pdu_pcch(srslte::byte_buffer_t *sdu) {} void write_pdu_pcch(srslte::byte_buffer_t *sdu) {}
void max_retx_attempted(){} void max_retx_attempted(){}
std::string get_rb_name(uint32_t lcid) { return std::string("rb"); }
void in_sync() {}; void in_sync() {};
void out_of_sync() {}; void out_of_sync() {};
@ -543,7 +544,7 @@ int main(int argc, char *argv[])
my_phy.init(&my_radio, &my_mac, &my_tester, &log_phy, NULL); my_phy.init(&my_radio, &my_mac, &my_tester, &log_phy, NULL);
my_mac.init(&my_phy, &rlc, &my_tester, &log_mac); my_mac.init(&my_phy, &rlc, &my_tester, &log_mac);
rlc.init(&my_tester, &my_tester, &my_tester, &log_rlc, &my_mac); rlc.init(&my_tester, &my_tester, &my_tester, &log_rlc, &my_mac, 0 /* SRB0 */);
my_tester.init(&my_phy, &my_mac, &rlc, &log_tester, prog_args.ip_address); my_tester.init(&my_phy, &my_mac, &rlc, &log_tester, prog_args.ip_address);

Loading…
Cancel
Save