Merge branch 'next' of github.com:softwareradiosystems/srsLTE into next

This commit is contained in:
Ismael Gomez 2018-09-07 14:06:27 +02:00
commit 243a7708d4
27 changed files with 1568 additions and 984 deletions

View File

@ -100,109 +100,204 @@ public:
private: private:
byte_buffer_pool *pool; // Transmitter sub-class
srslte::log *log; class rlc_am_tx : public timer_callback
uint32_t lcid; {
srsue::pdcp_interface_rlc *pdcp; public:
rlc_am_tx(rlc_am *parent_, uint32_t queue_len);
~rlc_am_tx();
void init();
bool configure(srslte_rlc_am_config_t cfg_);
void empty_queue();
void reestablish();
void stop();
void write_sdu(byte_buffer_t *sdu, bool blocking);
int read_pdu(uint8_t *payload, uint32_t nof_bytes);
uint32_t get_buffer_state();
uint32_t get_total_buffer_state();
uint32_t get_num_tx_bytes();
void reset_metrics();
// Timeout callback interface
void timer_expired(uint32_t timeout_id);
// Interface for Rx subclass
void handle_control_pdu(uint8_t *payload, uint32_t nof_bytes);
private:
int build_status_pdu(uint8_t *payload, uint32_t nof_bytes);
int build_retx_pdu(uint8_t *payload, uint32_t nof_bytes);
int build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t retx);
int build_data_pdu(uint8_t *payload, uint32_t nof_bytes);
void debug_state();
bool retx_queue_has_sn(uint32_t sn);
int required_buffer_size(rlc_amd_retx_t retx);
// Timer checks
bool status_prohibited;
// Helpers
bool poll_required();
bool do_status();
rlc_am *parent;
byte_buffer_pool *pool;
srslte::log *log;
/****************************************************************************
* Configurable parameters
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
srslte_rlc_am_config_t cfg;
// TX SDU buffers
rlc_tx_queue tx_sdu_queue;
byte_buffer_t *tx_sdu;;
bool tx_enabled;
/****************************************************************************
* State variables and counters
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
// Tx state variables
uint32_t vt_a; // ACK state. SN of next PDU in sequence to be ACKed. Low edge of tx window.
uint32_t vt_ms; // Max send state. High edge of tx window. vt_a + window_size.
uint32_t vt_s; // Send state. SN to be assigned for next PDU.
uint32_t poll_sn; // Poll send state. SN of most recent PDU txed with poll bit set.
// Tx counters
uint32_t pdu_without_poll;
uint32_t byte_without_poll;
rlc_status_pdu_t tx_status;
/****************************************************************************
* Timers
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
srslte::timers::timer *poll_retx_timer;
uint32_t poll_retx_timer_id;
srslte::timers::timer *status_prohibit_timer;
uint32_t status_prohibit_timer_id;
// Tx windows
std::map<uint32_t, rlc_amd_tx_pdu_t> tx_window;
std::deque<rlc_amd_retx_t> retx_queue;
// Mutexes
pthread_mutex_t mutex;
// Metrics
uint32_t num_tx_bytes;
};
// Receiver sub-class
class rlc_am_rx : public timer_callback
{
public:
rlc_am_rx(rlc_am* parent_);
~rlc_am_rx();
void init();
bool configure(srslte_rlc_am_config_t cfg_);
void reestablish();
void stop();
void write_pdu(uint8_t *payload, uint32_t nof_bytes);
uint32_t get_num_rx_bytes();
void reset_metrics();
// Timeout callback interface
void timer_expired(uint32_t timeout_id);
// Functions needed by Tx subclass to query rx state
int get_status(rlc_status_pdu_t* status);
bool get_do_status();
void reset_status(); // called when status PDU has been sent
private:
void handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header);
void handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header);
void reassemble_rx_sdus();
bool inside_rx_window(uint16_t sn);
void debug_state();
void print_rx_segments();
bool add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment);
rlc_am *parent;
byte_buffer_pool *pool;
srslte::log *log;
/****************************************************************************
* Configurable parameters
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
srslte_rlc_am_config_t cfg;
// RX SDU buffers
byte_buffer_t *rx_sdu;
/****************************************************************************
* State variables and counters
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
// Rx state variables
uint32_t vr_r; // Receive state. SN following last in-sequence received PDU. Low edge of rx window
uint32_t vr_mr; // Max acceptable receive state. High edge of rx window. vr_r + window size.
uint32_t vr_x; // t_reordering state. SN following PDU which triggered t_reordering.
uint32_t vr_ms; // Max status tx state. Highest possible value of SN for ACK_SN in status PDU.
uint32_t vr_h; // Highest rx state. SN following PDU with highest SN among rxed PDUs.
// Mutexes
pthread_mutex_t mutex;
// Rx windows
std::map<uint32_t, rlc_amd_rx_pdu_t> rx_window;
std::map<uint32_t, rlc_amd_rx_pdu_segments_t> rx_segments;
// Metrics
uint32_t num_rx_bytes;
bool poll_received;
bool do_status;
/****************************************************************************
* Timers
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
srslte::timers::timer *reordering_timer;
uint32_t reordering_timer_id;
};
// Rx and Tx objects
rlc_am_tx tx;
rlc_am_rx rx;
// Common variables needed/provided by parent class
srsue::rrc_interface_rlc *rrc; srsue::rrc_interface_rlc *rrc;
srslte::log *log;
// TX SDU buffers srsue::pdcp_interface_rlc *pdcp;
rlc_tx_queue tx_sdu_queue; mac_interface_timers *mac_timers;
byte_buffer_t *tx_sdu; uint32_t lcid;
srslte_rlc_am_config_t cfg;
// PDU being resegmented std::string rb_name;
rlc_amd_tx_pdu_t tx_pdu_segments;
// Tx and Rx windows
std::map<uint32_t, rlc_amd_tx_pdu_t> tx_window;
std::deque<rlc_amd_retx_t> retx_queue;
std::map<uint32_t, rlc_amd_rx_pdu_t> rx_window;
std::map<uint32_t, rlc_amd_rx_pdu_segments_t> rx_segments;
// RX SDU buffers
byte_buffer_t *rx_sdu;
// Mutexes
pthread_mutex_t mutex;
bool tx_enabled;
bool poll_received;
bool do_status;
rlc_status_pdu_t status;
// Metrics
uint32_t num_tx_bytes;
uint32_t num_rx_bytes;
/****************************************************************************
* Configurable parameters
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
srslte_rlc_am_config_t cfg;
/****************************************************************************
* State variables and counters
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
// Tx state variables
uint32_t vt_a; // ACK state. SN of next PDU in sequence to be ACKed. Low edge of tx window.
uint32_t vt_ms; // Max send state. High edge of tx window. vt_a + window_size.
uint32_t vt_s; // Send state. SN to be assigned for next PDU.
uint32_t poll_sn; // Poll send state. SN of most recent PDU txed with poll bit set.
// Tx counters
uint32_t pdu_without_poll;
uint32_t byte_without_poll;
// Rx state variables
uint32_t vr_r; // Receive state. SN following last in-sequence received PDU. Low edge of rx window
uint32_t vr_mr; // Max acceptable receive state. High edge of rx window. vr_r + window size.
uint32_t vr_x; // t_reordering state. SN following PDU which triggered t_reordering.
uint32_t vr_ms; // Max status tx state. Highest possible value of SN for ACK_SN in status PDU.
uint32_t vr_h; // Highest rx state. SN following PDU with highest SN among rxed PDUs.
/****************************************************************************
* Timers
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
timeout poll_retx_timeout;
timeout reordering_timeout;
timeout status_prohibit_timeout;
static const int reordering_timeout_id = 1;
static const int poll_periodicity = 8; // After how many data PDUs a status PDU shall be requested static const int poll_periodicity = 8; // After how many data PDUs a status PDU shall be requested
// Timer checks
bool status_prohibited();
bool poll_retx();
void check_reordering_timeout();
// Helpers
bool poll_required();
int prepare_status();
int build_status_pdu(uint8_t *payload, uint32_t nof_bytes);
int build_retx_pdu(uint8_t *payload, uint32_t nof_bytes);
int build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t retx);
int build_data_pdu(uint8_t *payload, uint32_t nof_bytes);
void handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header);
void handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header);
void handle_control_pdu(uint8_t *payload, uint32_t nof_bytes);
void reassemble_rx_sdus();
bool inside_tx_window(uint16_t sn);
bool inside_rx_window(uint16_t sn);
void debug_state();
void print_rx_segments();
bool add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment);
int required_buffer_size(rlc_amd_retx_t retx);
bool retx_queue_has_sn(uint32_t sn);
}; };
/**************************************************************************** /****************************************************************************

View File

@ -417,7 +417,8 @@ int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q, srslte_ra_dl_dci_t *grant,
srslte_dci_format_t format, srslte_dci_location_t location, srslte_dci_format_t format, srslte_dci_location_t location,
uint16_t rnti, uint32_t sf_idx) uint16_t rnti, uint32_t sf_idx)
{ {
srslte_dci_msg_t dci_msg = {}; srslte_dci_msg_t dci_msg;
bzero(&dci_msg, sizeof(dci_msg));
bool rnti_is_user = true; bool rnti_is_user = true;
if (rnti == SRSLTE_SIRNTI || rnti == SRSLTE_PRNTI || (rnti >= SRSLTE_RARNTI_START && rnti <= SRSLTE_RARNTI_END)) { if (rnti == SRSLTE_SIRNTI || rnti == SRSLTE_PRNTI || (rnti >= SRSLTE_RARNTI_START && rnti <= SRSLTE_RARNTI_END)) {
@ -439,7 +440,8 @@ int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q, srslte_ra_ul_dci_t *grant,
srslte_dci_location_t location, srslte_dci_location_t location,
uint16_t rnti, uint32_t sf_idx) uint16_t rnti, uint32_t sf_idx)
{ {
srslte_dci_msg_t dci_msg = {}; srslte_dci_msg_t dci_msg;
bzero(&dci_msg, sizeof(dci_msg));
srslte_dci_msg_pack_pusch(grant, &dci_msg, q->cell.nof_prb); srslte_dci_msg_pack_pusch(grant, &dci_msg, q->cell.nof_prb);
if (srslte_pdcch_encode(&q->pdcch, &dci_msg, location, rnti, q->sf_symbols, sf_idx, q->cfi)) { if (srslte_pdcch_encode(&q->pdcch, &dci_msg, location, rnti, q->sf_symbols, sf_idx, q->cfi)) {

View File

@ -97,7 +97,8 @@ int main(int argc, char **argv) {
} }
/* Create CRC for Transport Block, it is not currently used but it is required */ /* Create CRC for Transport Block, it is not currently used but it is required */
srslte_crc_t crc_tb = {}; srslte_crc_t crc_tb;
bzero(&crc_tb, sizeof(crc_tb));
if (srslte_crc_init(&crc_tb, SRSLTE_LTE_CRC24A, 24)) { if (srslte_crc_init(&crc_tb, SRSLTE_LTE_CRC24A, 24)) {
printf("error initialising CRC\n"); printf("error initialising CRC\n");
exit(-1); exit(-1);

View File

@ -60,6 +60,8 @@ bool verbose = false;
#define TEST(X, CODE) static bool test_##X (char *func_name, double *timing, uint32_t block_size) {\ #define TEST(X, CODE) static bool test_##X (char *func_name, double *timing, uint32_t block_size) {\
struct timeval start, end;\ struct timeval start, end;\
bzero(&start, sizeof(start));\
bzero(&end, sizeof(end));\
float mse = 0.0f;\ float mse = 0.0f;\
bool passed;\ bool passed;\
strncpy(func_name, #X, 32);\ strncpy(func_name, #X, 32);\
@ -781,7 +783,8 @@ TEST(srslte_vec_apply_cfo,
) )
TEST(srslte_cfo_correct, TEST(srslte_cfo_correct,
srslte_cfo_t srslte_cfo = {0}; srslte_cfo_t srslte_cfo;
bzero(&srslte_cfo, sizeof(srslte_cfo));
MALLOC(cf_t, x); MALLOC(cf_t, x);
MALLOC(cf_t, z); MALLOC(cf_t, z);
@ -807,7 +810,8 @@ TEST(srslte_cfo_correct,
) )
TEST(srslte_cfo_correct_change, TEST(srslte_cfo_correct_change,
srslte_cfo_t srslte_cfo = {0}; srslte_cfo_t srslte_cfo;
bzero(&srslte_cfo, sizeof(srslte_cfo));
MALLOC(cf_t, x); MALLOC(cf_t, x);
MALLOC(cf_t, z); MALLOC(cf_t, z);

View File

@ -129,7 +129,9 @@ int main(int argc, char **argv)
{ {
int ret = SRSLTE_ERROR; int ret = SRSLTE_ERROR;
srslte::radio_multi *radio_h = NULL; srslte::radio_multi *radio_h = NULL;
srslte_timestamp_t ts_rx = {}, ts_tx = {}; srslte_timestamp_t ts_rx, ts_tx;
bzero(&ts_rx, sizeof(ts_rx));
bzero(&ts_tx, sizeof(ts_tx));
signal(SIGINT, sig_int_handler); signal(SIGINT, sig_int_handler);

View File

@ -440,7 +440,7 @@ void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg)
rlc_log->error("Error instantiating RLC\n"); rlc_log->error("Error instantiating RLC\n");
goto delete_and_exit; goto delete_and_exit;
} }
rlc_log->warning("Added radio bearer %s with mode %s\n", rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg.rlc_mode]); rlc_log->warning("Added radio bearer %s in %s\n", rrc->get_rb_name(lcid).c_str(), rlc_mode_text[cnfg.rlc_mode]);
goto unlock_and_exit; goto unlock_and_exit;
} else { } else {
rlc_log->warning("Bearer %s already created.\n", rrc->get_rb_name(lcid).c_str()); rlc_log->warning("Bearer %s already created.\n", rrc->get_rb_name(lcid).c_str());

File diff suppressed because it is too large Load Diff

View File

@ -75,13 +75,13 @@ bool rlc_um::configure(srslte_rlc_config_t cnfg_)
return false; return false;
} }
log->warning("%s configured in %s mode: t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n",
rb_name.c_str(), rlc_mode_text[cnfg_.rlc_mode],
cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length], rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
// store config // store config
cfg = cnfg_.um; cfg = cnfg_.um;
log->warning("%s configured in %s mode: ft_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n",
rb_name.c_str(), rlc_mode_text[cnfg_.rlc_mode],
cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length], rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
return true; return true;
} }
@ -149,7 +149,6 @@ void rlc_um::write_sdu(byte_buffer_t *sdu, bool blocking)
} else { } else {
tx.try_write_sdu(sdu); tx.try_write_sdu(sdu);
} }
} }
/**************************************************************************** /****************************************************************************
@ -199,7 +198,7 @@ void rlc_um::reset_metrics()
std::string rlc_um::get_rb_name(srsue::rrc_interface_rlc *rrc, uint32_t lcid, bool is_mrb) std::string rlc_um::get_rb_name(srsue::rrc_interface_rlc *rrc, uint32_t lcid, bool is_mrb)
{ {
if(is_mrb) { if (is_mrb) {
std::stringstream ss; std::stringstream ss;
ss << "MRB" << lcid; ss << "MRB" << lcid;
return ss.str(); return ss.str();

View File

@ -190,8 +190,8 @@ uint32_t prbset_to_bitmask() {
int main(int argc, char **argv) { int main(int argc, char **argv) {
struct timeval t[3] = {}; struct timeval t[3] = {};
size_t tx_nof_bits = 0, rx_nof_bits = 0; size_t tx_nof_bits = 0, rx_nof_bits = 0;
srslte_enb_dl_t enb_dl = {}; srslte_enb_dl_t enb_dl;
srslte_ue_dl_t ue_dl = {}; srslte_ue_dl_t ue_dl;
srslte_softbuffer_tx_t *softbuffer_tx[SRSLTE_MAX_TB] = {}; srslte_softbuffer_tx_t *softbuffer_tx[SRSLTE_MAX_TB] = {};
srslte_softbuffer_rx_t *softbuffer_rx[SRSLTE_MAX_TB] = {}; srslte_softbuffer_rx_t *softbuffer_rx[SRSLTE_MAX_TB] = {};
uint8_t *data_tx[SRSLTE_MAX_TB] = {}; uint8_t *data_tx[SRSLTE_MAX_TB] = {};
@ -206,6 +206,9 @@ int main(int argc, char **argv) {
cf_t *signal_buffer[SRSLTE_MAX_PORTS] = {NULL}; cf_t *signal_buffer[SRSLTE_MAX_PORTS] = {NULL};
bzero(&enb_dl, sizeof(enb_dl));
bzero(&ue_dl, sizeof(ue_dl));
/* /*
* Allocate Memory * Allocate Memory
*/ */
@ -304,9 +307,12 @@ int main(int argc, char **argv) {
/* /*
* Run eNodeB * Run eNodeB
*/ */
srslte_ra_dl_dci_t dci = {}; srslte_ra_dl_dci_t dci;
srslte_dci_format_t dci_format = SRSLTE_DCI_FORMAT1A; srslte_dci_format_t dci_format = SRSLTE_DCI_FORMAT1A;
srslte_ra_dl_grant_t grant = {}; srslte_ra_dl_grant_t grant;
bzero(&dci, sizeof(dci));
bzero(&grant, sizeof(grant));
prbset_num = (int) ceilf((float) cell.nof_prb / srslte_ra_type0_P(cell.nof_prb)); prbset_num = (int) ceilf((float) cell.nof_prb / srslte_ra_type0_P(cell.nof_prb));
last_prbset_num = prbset_num; last_prbset_num = prbset_num;

View File

@ -42,15 +42,21 @@ class mac_dummy_timers
:public srslte::mac_interface_timers :public srslte::mac_interface_timers
{ {
public: public:
srslte::timers::timer* timer_get(uint32_t timer_id) mac_dummy_timers() : timers(8) {}
{ srslte::timers::timer* timer_get(uint32_t timer_id) {
return &t; return timers.get(timer_id);
}
void timer_release_id(uint32_t timer_id) {
timers.release_id(timer_id);
}
uint32_t timer_get_unique_id() {
return timers.get_unique_id();
}
void step_all() {
timers.step_all();
} }
uint32_t timer_get_unique_id(){return 0;}
void timer_release_id(uint32_t id){}
private: private:
srslte::timers::timer t; srslte::timers timers;
}; };
class rlc_am_tester class rlc_am_tester
@ -135,7 +141,7 @@ private:
bool running; bool running;
}; };
void basic_test() bool basic_test()
{ {
srslte::log_filter log1("RLC_AM_1"); srslte::log_filter log1("RLC_AM_1");
srslte::log_filter log2("RLC_AM_2"); srslte::log_filter log2("RLC_AM_2");
@ -166,8 +172,13 @@ void basic_test()
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; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); if (not rlc1.configure(&cnfg)) {
rlc2.configure(&cnfg); return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1 // Push 5 SDUs into RLC1
byte_buffer_t sdu_bufs[NBUFS]; byte_buffer_t sdu_bufs[NBUFS];
@ -215,11 +226,17 @@ void basic_test()
} }
// Check statistics // Check statistics
assert(rlc1.get_num_tx_bytes() == rlc2.get_num_rx_bytes()); if (rlc1.get_num_tx_bytes() != rlc2.get_num_rx_bytes()) {
assert(rlc2.get_num_tx_bytes() == rlc1.get_num_rx_bytes()); return -1;
}
if (rlc2.get_num_tx_bytes() != rlc1.get_num_rx_bytes()) {
return -1;
}
return 0;
} }
void concat_test() bool concat_test()
{ {
srslte::log_filter log1("RLC_AM_1"); srslte::log_filter log1("RLC_AM_1");
srslte::log_filter log2("RLC_AM_2"); srslte::log_filter log2("RLC_AM_2");
@ -250,8 +267,13 @@ void concat_test()
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; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); if (not rlc1.configure(&cnfg)) {
rlc2.configure(&cnfg); return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1 // Push 5 SDUs into RLC1
byte_buffer_t sdu_bufs[NBUFS]; byte_buffer_t sdu_bufs[NBUFS];
@ -284,11 +306,17 @@ void concat_test()
} }
// check statistics // check statistics
assert(rlc1.get_num_tx_bytes() == rlc2.get_num_rx_bytes()); if (rlc1.get_num_tx_bytes() != rlc2.get_num_rx_bytes()) {
assert(rlc2.get_num_tx_bytes() == rlc1.get_num_rx_bytes()); return -1;
}
if (rlc2.get_num_tx_bytes() != rlc1.get_num_rx_bytes()) {
return -1;
}
return 0;
} }
void segment_test() bool segment_test()
{ {
srslte::log_filter log1("RLC_AM_1"); srslte::log_filter log1("RLC_AM_1");
srslte::log_filter log2("RLC_AM_2"); srslte::log_filter log2("RLC_AM_2");
@ -319,8 +347,13 @@ void segment_test()
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; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); if (not rlc1.configure(&cnfg)) {
rlc2.configure(&cnfg); return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1 // Push 5 SDUs into RLC1
byte_buffer_t sdu_bufs[NBUFS]; byte_buffer_t sdu_bufs[NBUFS];
@ -370,11 +403,17 @@ void segment_test()
assert(tester.sdus[i]->msg[j] == j); assert(tester.sdus[i]->msg[j] == j);
} }
assert(rlc1.get_num_tx_bytes() == rlc2.get_num_rx_bytes()); if (rlc1.get_num_tx_bytes() != rlc2.get_num_rx_bytes()) {
assert(rlc2.get_num_tx_bytes() == rlc1.get_num_rx_bytes()); return -1;
}
if (rlc2.get_num_tx_bytes() != rlc1.get_num_rx_bytes()) {
return -1;
}
return 0;
} }
void retx_test() bool retx_test()
{ {
srslte::log_filter log1("RLC_AM_1"); srslte::log_filter log1("RLC_AM_1");
srslte::log_filter log2("RLC_AM_2"); srslte::log_filter log2("RLC_AM_2");
@ -405,8 +444,13 @@ void retx_test()
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; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); if (not rlc1.configure(&cnfg)) {
rlc2.configure(&cnfg); return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1 // Push 5 SDUs into RLC1
byte_buffer_t sdu_bufs[NBUFS]; byte_buffer_t sdu_bufs[NBUFS];
@ -436,8 +480,11 @@ void retx_test()
rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes);
} }
// Sleep to let reordering timeout expire // Step timers until reordering timeout expires
usleep(10000); int cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(4 == rlc2.get_buffer_state()); assert(4 == rlc2.get_buffer_state());
@ -462,12 +509,14 @@ void retx_test()
assert(tester.n_sdus == 5); assert(tester.n_sdus == 5);
for(int i=0; i<tester.n_sdus; i++) for(int i=0; i<tester.n_sdus; i++)
{ {
assert(tester.sdus[i]->N_bytes == 1); if (tester.sdus[i]->N_bytes != 1) return -1;
assert(*(tester.sdus[i]->msg) == i); if (*(tester.sdus[i]->msg) != i) return -1;
} }
return 0;
} }
void resegment_test_1() bool resegment_test_1()
{ {
// SDUs: | 10 | 10 | 10 | 10 | 10 | // SDUs: | 10 | 10 | 10 | 10 | 10 |
// PDUs: | 10 | 10 | 10 | 10 | 10 | // PDUs: | 10 | 10 | 10 | 10 | 10 |
@ -502,8 +551,13 @@ void resegment_test_1()
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; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); if (not rlc1.configure(&cnfg)) {
rlc2.configure(&cnfg); return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1 // Push 5 SDUs into RLC1
byte_buffer_t sdu_bufs[NBUFS]; byte_buffer_t sdu_bufs[NBUFS];
@ -534,8 +588,11 @@ void resegment_test_1()
rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes);
} }
// Sleep to let reordering timeout expire // Step timers until reordering timeout expires
usleep(10000); int cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(4 == rlc2.get_buffer_state()); assert(4 == rlc2.get_buffer_state());
@ -570,13 +627,15 @@ void resegment_test_1()
assert(tester.n_sdus == 5); assert(tester.n_sdus == 5);
for(int i=0; i<tester.n_sdus; i++) for(int i=0; i<tester.n_sdus; i++)
{ {
assert(tester.sdus[i]->N_bytes == 10); if (tester.sdus[i]->N_bytes != 10) return -1;
for(int j=0;j<10;j++) for(int j=0;j<10;j++)
assert(tester.sdus[i]->msg[j] == j); if (tester.sdus[i]->msg[j] != j) return -1;
} }
return 0;
} }
void resegment_test_2() bool resegment_test_2()
{ {
// SDUs: | 10 | 10 | 10 | 10 | 10 | // SDUs: | 10 | 10 | 10 | 10 | 10 |
@ -612,8 +671,13 @@ void resegment_test_2()
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; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); if (not rlc1.configure(&cnfg)) {
rlc2.configure(&cnfg); return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1 // Push 5 SDUs into RLC1
byte_buffer_t sdu_bufs[NBUFS]; byte_buffer_t sdu_bufs[NBUFS];
@ -644,8 +708,11 @@ void resegment_test_2()
rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes);
} }
// Sleep to let reordering timeout expire // Step timers until reordering timeout expires
usleep(10000); int cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(4 == rlc2.get_buffer_state()); assert(4 == rlc2.get_buffer_state());
@ -677,13 +744,15 @@ void resegment_test_2()
assert(tester.n_sdus == 5); assert(tester.n_sdus == 5);
for(int i=0; i<tester.n_sdus; i++) for(int i=0; i<tester.n_sdus; i++)
{ {
assert(tester.sdus[i]->N_bytes == 10); if (tester.sdus[i]->N_bytes != 10) return -1;
for(int j=0;j<10;j++) for(int j=0;j<10;j++)
assert(tester.sdus[i]->msg[j] == j); if (tester.sdus[i]->msg[j] != j) return -1;
} }
return 0;
} }
void resegment_test_3() bool resegment_test_3()
{ {
// SDUs: | 10 | 10 | 10 | 10 | 10 | // SDUs: | 10 | 10 | 10 | 10 | 10 |
@ -719,8 +788,13 @@ void resegment_test_3()
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; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); if (not rlc1.configure(&cnfg)) {
rlc2.configure(&cnfg); return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1 // Push 5 SDUs into RLC1
byte_buffer_t sdu_bufs[NBUFS]; byte_buffer_t sdu_bufs[NBUFS];
@ -751,8 +825,11 @@ void resegment_test_3()
rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes);
} }
// Sleep to let reordering timeout expire // Step timers until reordering timeout expires
usleep(10000); int cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(4 == rlc2.get_buffer_state()); assert(4 == rlc2.get_buffer_state());
@ -780,13 +857,15 @@ void resegment_test_3()
assert(tester.n_sdus == 5); assert(tester.n_sdus == 5);
for(int i=0; i<tester.n_sdus; i++) for(int i=0; i<tester.n_sdus; i++)
{ {
assert(tester.sdus[i]->N_bytes == 10); if (tester.sdus[i]->N_bytes != 10) return -1;
for(int j=0;j<10;j++) for(int j=0;j<10;j++)
assert(tester.sdus[i]->msg[j] == j); if (tester.sdus[i]->msg[j] != j) return -1;
} }
return 0;
} }
void resegment_test_4() bool resegment_test_4()
{ {
// SDUs: | 10 | 10 | 10 | 10 | 10 | // SDUs: | 10 | 10 | 10 | 10 | 10 |
@ -822,8 +901,13 @@ void resegment_test_4()
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; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); if (not rlc1.configure(&cnfg)) {
rlc2.configure(&cnfg); return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1 // Push 5 SDUs into RLC1
byte_buffer_t sdu_bufs[NBUFS]; byte_buffer_t sdu_bufs[NBUFS];
@ -854,8 +938,11 @@ void resegment_test_4()
rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes);
} }
// Sleep to let reordering timeout expire // Step timers until reordering timeout expires
usleep(10000); int cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(4 == rlc2.get_buffer_state()); assert(4 == rlc2.get_buffer_state());
@ -883,13 +970,15 @@ void resegment_test_4()
assert(tester.n_sdus == 5); assert(tester.n_sdus == 5);
for(int i=0; i<tester.n_sdus; i++) for(int i=0; i<tester.n_sdus; i++)
{ {
assert(tester.sdus[i]->N_bytes == 10); if (tester.sdus[i]->N_bytes != 10) return -1;
for(int j=0;j<10;j++) for(int j=0;j<10;j++)
assert(tester.sdus[i]->msg[j] == j); if (tester.sdus[i]->msg[j] != j) return -1;
} }
return 0;
} }
void resegment_test_5() bool resegment_test_5()
{ {
// SDUs: | 10 | 10 | 10 | 10 | 10 | // SDUs: | 10 | 10 | 10 | 10 | 10 |
@ -908,8 +997,6 @@ void resegment_test_5()
rlc_am rlc1; rlc_am rlc1;
rlc_am rlc2; rlc_am rlc2;
int len;
log1.set_level(srslte::LOG_LEVEL_DEBUG); log1.set_level(srslte::LOG_LEVEL_DEBUG);
log2.set_level(srslte::LOG_LEVEL_DEBUG); log2.set_level(srslte::LOG_LEVEL_DEBUG);
@ -925,8 +1012,13 @@ void resegment_test_5()
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; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); if (not rlc1.configure(&cnfg)) {
rlc2.configure(&cnfg); return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1 // Push 5 SDUs into RLC1
byte_buffer_t sdu_bufs[NBUFS]; byte_buffer_t sdu_bufs[NBUFS];
@ -957,8 +1049,11 @@ void resegment_test_5()
rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes);
} }
// Sleep to let reordering timeout expire // Step timers until reordering timeout expires
usleep(10000); int cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(4 == rlc2.get_buffer_state()); assert(4 == rlc2.get_buffer_state());
@ -986,13 +1081,15 @@ void resegment_test_5()
assert(tester.n_sdus == 5); assert(tester.n_sdus == 5);
for(int i=0; i<tester.n_sdus; i++) for(int i=0; i<tester.n_sdus; i++)
{ {
assert(tester.sdus[i]->N_bytes == 10); if (tester.sdus[i]->N_bytes != 10) return -1;
for(int j=0;j<10;j++) for(int j=0;j<10;j++)
assert(tester.sdus[i]->msg[j] == j); if (tester.sdus[i]->msg[j] != j) return -1;
} }
return 0;
} }
void resegment_test_6() bool resegment_test_6()
{ {
// SDUs: |10|10|10| 54 | 54 | 54 | 54 | 54 | 54 | // SDUs: |10|10|10| 54 | 54 | 54 | 54 | 54 | 54 |
// PDUs: |10|10|10| 270 | 54 | // PDUs: |10|10|10| 270 | 54 |
@ -1027,8 +1124,13 @@ void resegment_test_6()
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; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); if (not rlc1.configure(&cnfg)) {
rlc2.configure(&cnfg); return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push SDUs into RLC1 // Push SDUs into RLC1
byte_buffer_t sdu_bufs[9]; byte_buffer_t sdu_bufs[9];
@ -1069,8 +1171,11 @@ void resegment_test_6()
rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes);
} }
// Sleep to let reordering timeout expire // Step timers until reordering timeout expires
usleep(10000); int cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(4 == rlc2.get_buffer_state()); assert(4 == rlc2.get_buffer_state());
@ -1111,14 +1216,17 @@ void resegment_test_6()
} }
for(int i=3;i<9;i++) for(int i=3;i<9;i++)
{ {
assert(tester.sdus[i]->N_bytes == 54); if(tester.sdus[i]->N_bytes != 54) return -1;
for(int j=0;j<54;j++) for(int j=0;j<54;j++) {
assert(tester.sdus[i]->msg[j] == j); if (tester.sdus[i]->msg[j] != j) return -1;
}
} }
return 0;
} }
// Retransmission of PDU segments of the same size // Retransmission of PDU segments of the same size
void resegment_test_7() bool resegment_test_7()
{ {
// SDUs: | 30 | 30 | // SDUs: | 30 | 30 |
// PDUs: | 13 | 13 | 11 | 13 | 10 | // PDUs: | 13 | 13 | 11 | 13 | 10 |
@ -1165,8 +1273,13 @@ void resegment_test_7()
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; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); if (not rlc1.configure(&cnfg)) {
rlc2.configure(&cnfg); return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 2 SDUs into RLC1 // Push 2 SDUs into RLC1
byte_buffer_t sdu_bufs[N_SDU_BUFS]; byte_buffer_t sdu_bufs[N_SDU_BUFS];
@ -1201,8 +1314,11 @@ void resegment_test_7()
} }
} }
// Sleep to let reordering timeout expire // Step timers until reordering timeout expires
usleep(10000); int cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(12 == rlc1.get_buffer_state()); assert(12 == rlc1.get_buffer_state());
@ -1222,8 +1338,6 @@ void resegment_test_7()
} }
} }
usleep(10000);
// Read status PDU from RLC2 // Read status PDU from RLC2
assert(rlc2.get_buffer_state()); assert(rlc2.get_buffer_state());
byte_buffer_t status_buf; byte_buffer_t status_buf;
@ -1237,7 +1351,6 @@ void resegment_test_7()
assert(15 == rlc1.get_buffer_state()); assert(15 == rlc1.get_buffer_state());
// second round of retx, forcing resegmentation // second round of retx, forcing resegmentation
byte_buffer_t retx2[4]; byte_buffer_t retx2[4];
for (uint32_t i = 0; i < 4; i++) { for (uint32_t i = 0; i < 4; i++) {
@ -1253,26 +1366,35 @@ void resegment_test_7()
// check buffer states // check buffer states
assert(0 == rlc1.get_buffer_state()); assert(0 == rlc1.get_buffer_state());
// Step timers until poll_retx timeout expires
cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(0 == rlc2.get_buffer_state()); assert(0 == rlc2.get_buffer_state());
// Check number of SDUs and their content // Check number of SDUs and their content
assert(tester.n_sdus == N_SDU_BUFS); assert(tester.n_sdus == N_SDU_BUFS);
for(int i=0; i<tester.n_sdus; i++) for(int i=0; i<tester.n_sdus; i++)
{ {
assert(tester.sdus[i]->N_bytes == sdu_size); if (tester.sdus[i]->N_bytes != sdu_size) return -1;
for(uint32_t j=0;j<N_SDU_BUFS;j++) { for(uint32_t j=0;j<N_SDU_BUFS;j++) {
assert(tester.sdus[i]->msg[j] == i); if (tester.sdus[i]->msg[j] != i) return -1;
} }
} }
#if HAVE_PCAP #if HAVE_PCAP
pcap.close(); pcap.close();
#endif #endif
return 0;
} }
// Retransmission of PDU segments with different size // Retransmission of PDU segments with different size
void resegment_test_8() bool resegment_test_8()
{ {
// SDUs: | 30 | 30 | // SDUs: | 30 | 30 |
// PDUs: | 15 | 15 | 15 | 15 | 15 | // PDUs: | 15 | 15 | 15 | 15 | 15 |
@ -1318,8 +1440,13 @@ void resegment_test_8()
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; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); if (not rlc1.configure(&cnfg)) {
rlc2.configure(&cnfg); exit(-1);
}
if (not rlc2.configure(&cnfg)) {
exit(-1);
}
// Push 2 SDUs into RLC1 // Push 2 SDUs into RLC1
byte_buffer_t sdu_bufs[N_SDU_BUFS]; byte_buffer_t sdu_bufs[N_SDU_BUFS];
@ -1354,8 +1481,11 @@ void resegment_test_8()
} }
} }
// Sleep to let reordering timeout expire // Step timers until reordering timeout expires
usleep(10000); int cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(12 == rlc1.get_buffer_state()); assert(12 == rlc1.get_buffer_state());
@ -1375,7 +1505,11 @@ void resegment_test_8()
} }
} }
usleep(20000); // Step timers until reordering timeout expires
cnt = 7;
while (cnt--) {
timers.step_all();
}
// Read status PDU from RLC2 // Read status PDU from RLC2
assert(rlc2.get_buffer_state()); assert(rlc2.get_buffer_state());
@ -1402,27 +1536,41 @@ void resegment_test_8()
#endif #endif
} }
// get BSR from RLC2
status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status
// Write status PDU to RLC1
rlc1.write_pdu(status_buf.msg, status_buf.N_bytes);
#if HAVE_PCAP
pcap.write_ul_am_ccch(status_buf.msg, status_buf.N_bytes);
#endif
// check buffer states // check buffer states
assert(0 == rlc1.get_buffer_state()); if (rlc1.get_buffer_state() != 0) {
assert(0 == rlc2.get_buffer_state()); return -1;
};
if (rlc2.get_buffer_state() != 0) {
return -1;
};
// Check number of SDUs and their content // Check number of SDUs and their content
assert(tester.n_sdus == N_SDU_BUFS); assert(tester.n_sdus == N_SDU_BUFS);
for(int i=0; i<tester.n_sdus; i++) for(int i=0; i<tester.n_sdus; i++) {
{ if (tester.sdus[i]->N_bytes != sdu_size) return -1;
assert(tester.sdus[i]->N_bytes == sdu_size);
for(uint32_t j=0;j<N_SDU_BUFS;j++) { for(uint32_t j=0;j<N_SDU_BUFS;j++) {
assert(tester.sdus[i]->msg[j] == i); if (tester.sdus[i]->msg[j] != i) return -1;
} }
} }
#if HAVE_PCAP #if HAVE_PCAP
pcap.close(); pcap.close();
#endif #endif
return 0;
} }
void reset_test() bool reset_test()
{ {
srslte::log_filter log1("RLC_AM_1"); srslte::log_filter log1("RLC_AM_1");
srslte::log_filter log2("RLC_AM_2"); srslte::log_filter log2("RLC_AM_2");
@ -1449,7 +1597,9 @@ void reset_test()
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; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); if (not rlc1.configure(&cnfg)) {
return -1;
}
// Push 1 SDU of size 10 into RLC1 // Push 1 SDU of size 10 into RLC1
byte_buffer_t sdu_buf; byte_buffer_t sdu_buf;
@ -1473,10 +1623,14 @@ void reset_test()
len = rlc1.read_pdu(pdu_bufs.msg, 100); len = rlc1.read_pdu(pdu_bufs.msg, 100);
pdu_bufs.N_bytes = len; pdu_bufs.N_bytes = len;
assert(0 == rlc1.get_buffer_state()); if (0 != rlc1.get_buffer_state()) {
return -1;
}
return 0;
} }
void stop_test() bool stop_test()
{ {
srslte::log_filter log1("RLC_AM_1"); srslte::log_filter log1("RLC_AM_1");
log1.set_level(srslte::LOG_LEVEL_DEBUG); log1.set_level(srslte::LOG_LEVEL_DEBUG);
@ -1499,7 +1653,9 @@ void stop_test()
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; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg); if (not rlc1.configure(&cnfg)) {
return -1;
}
// start thread reading // start thread reading
ul_writer writer(&rlc1); ul_writer writer(&rlc1);
@ -1510,48 +1666,93 @@ void stop_test()
// stop RLC1 // stop RLC1
rlc1.stop(); rlc1.stop();
return 0;
} }
int main(int argc, char **argv) { int main(int argc, char **argv)
basic_test(); {
if (basic_test()) {
printf("basic_test failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup(); byte_buffer_pool::get_instance()->cleanup();
concat_test(); if (concat_test()) {
printf("concat_test failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup(); byte_buffer_pool::get_instance()->cleanup();
segment_test(); if (segment_test()) {
printf("segment_test failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup(); byte_buffer_pool::get_instance()->cleanup();
retx_test(); if (retx_test()) {
printf("retx_test failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup(); byte_buffer_pool::get_instance()->cleanup();
resegment_test_1(); if (resegment_test_1()) {
printf("resegment_test_1 failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup(); byte_buffer_pool::get_instance()->cleanup();
resegment_test_2(); if (resegment_test_2()) {
printf("resegment_test_2 failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup(); byte_buffer_pool::get_instance()->cleanup();
resegment_test_3(); if (resegment_test_3()) {
printf("resegment_test_3 failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup(); byte_buffer_pool::get_instance()->cleanup();
resegment_test_4(); if (resegment_test_4()) {
printf("resegment_test_4 failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup(); byte_buffer_pool::get_instance()->cleanup();
resegment_test_5(); if (resegment_test_5()) {
printf("resegment_test_5 failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup(); byte_buffer_pool::get_instance()->cleanup();
resegment_test_6(); if (resegment_test_6()) {
printf("resegment_test_6 failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup(); byte_buffer_pool::get_instance()->cleanup();
resegment_test_7(); if (resegment_test_7()) {
printf("resegment_test_7 failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup(); byte_buffer_pool::get_instance()->cleanup();
resegment_test_8(); if (resegment_test_8()) {
printf("resegment_test_8 failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup(); byte_buffer_pool::get_instance()->cleanup();
reset_test(); if (reset_test()) {
printf("reset_test failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup(); byte_buffer_pool::get_instance()->cleanup();
stop_test(); if (stop_test()) {
printf("stop_test failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup(); byte_buffer_pool::get_instance()->cleanup();
} }

View File

@ -28,6 +28,7 @@
#define SRSENB_PHCH_COMMON_H #define SRSENB_PHCH_COMMON_H
#include <map> #include <map>
#include <semaphore.h>
#include "srslte/interfaces/enb_interfaces.h" #include "srslte/interfaces/enb_interfaces.h"
#include "srslte/interfaces/enb_metrics_interface.h" #include "srslte/interfaces/enb_metrics_interface.h"
#include "srslte/common/gen_mch_tables.h" #include "srslte/common/gen_mch_tables.h"
@ -36,6 +37,7 @@
#include "srslte/common/thread_pool.h" #include "srslte/common/thread_pool.h"
#include "srslte/radio/radio.h" #include "srslte/radio/radio.h"
#include <string.h> #include <string.h>
namespace srsenb { namespace srsenb {
typedef struct { typedef struct {
@ -73,29 +75,16 @@ class phch_common
{ {
public: public:
phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) { phch_common(uint32_t nof_workers);
nof_mutex = 0; ~phch_common();
max_mutex = max_mutex_;
params.max_prach_offset_us = 20; void set_nof_workers(uint32_t nof_workers);
radio = NULL;
mac = NULL;
is_first_tx = false;
is_first_of_burst = false;
pdsch_p_b = 0;
nof_workers = 0;
bzero(&pusch_cfg, sizeof(pusch_cfg));
bzero(&hopping_cfg, sizeof(hopping_cfg));
bzero(&pucch_cfg, sizeof(pucch_cfg));
bzero(&ul_grants, sizeof(ul_grants));
}
bool init(srslte_cell_t *cell, srslte::radio *radio_handler, mac_interface_phy *mac); bool init(srslte_cell_t *cell, srslte::radio *radio_handler, mac_interface_phy *mac);
void reset(); void reset();
void stop(); void stop();
void set_nof_mutex(uint32_t nof_mutex);
void worker_end(uint32_t tx_mutex_cnt, cf_t *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time); void worker_end(uint32_t tx_mutex_cnt, cf_t *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time);
// Common objects // Common objects
@ -148,13 +137,12 @@ public:
private: private:
std::vector<pthread_mutex_t> tx_mutex; std::vector<sem_t> tx_sem;
bool is_first_tx; bool is_first_tx;
bool is_first_of_burst; bool is_first_of_burst;
uint32_t nof_workers; uint32_t nof_workers;
uint32_t nof_mutex; uint32_t max_workers;
uint32_t max_mutex;
pthread_mutex_t user_mutex; pthread_mutex_t user_mutex;

View File

@ -46,7 +46,7 @@ public:
void reset(); void reset();
cf_t *get_buffer_rx(uint32_t antenna_idx); cf_t *get_buffer_rx(uint32_t antenna_idx);
void set_time(uint32_t tti, uint32_t tx_mutex_cnt, srslte_timestamp_t tx_time); void set_time(uint32_t tti, uint32_t tx_worker_cnt, srslte_timestamp_t tx_time);
int add_rnti(uint16_t rnti); int add_rnti(uint16_t rnti);
void rem_rnti(uint16_t rnti); void rem_rnti(uint16_t rnti);
@ -93,8 +93,9 @@ private:
cf_t *signal_buffer_rx[SRSLTE_MAX_PORTS]; cf_t *signal_buffer_rx[SRSLTE_MAX_PORTS];
cf_t *signal_buffer_tx[SRSLTE_MAX_PORTS]; cf_t *signal_buffer_tx[SRSLTE_MAX_PORTS];
uint32_t tti_rx, tti_tx_dl, tti_tx_ul; uint32_t tti_rx, tti_tx_dl, tti_tx_ul;
uint32_t sf_rx, sf_tx, tx_mutex_cnt; uint32_t sf_rx, sf_tx;
uint32_t t_rx, t_tx_dl, t_tx_ul; uint32_t t_rx, t_tx_dl, t_tx_ul;
uint32_t tx_worker_cnt;
srslte_enb_dl_t enb_dl; srslte_enb_dl_t enb_dl;
srslte_enb_ul_t enb_ul; srslte_enb_ul_t enb_ul;
srslte_softbuffer_tx_t temp_mbsfn_softbuffer; srslte_softbuffer_tx_t temp_mbsfn_softbuffer;

View File

@ -50,8 +50,6 @@ public:
uint32_t prio); uint32_t prio);
void stop(); void stop();
const static int MUTEX_X_WORKER = 4;
private: private:
void run_thread(); void run_thread();
@ -61,12 +59,12 @@ private:
srslte::thread_pool *workers_pool; srslte::thread_pool *workers_pool;
prach_worker *prach; prach_worker *prach;
phch_common *worker_com; phch_common *worker_com;
uint32_t tx_mutex_cnt;
uint32_t nof_tx_mutex;
// Main system TTI counter // Main system TTI counter
uint32_t tti; uint32_t tti;
uint32_t tx_worker_cnt;
uint32_t nof_workers;
bool running; bool running;
}; };

View File

@ -41,9 +41,35 @@ using namespace std;
namespace srsenb { namespace srsenb {
void phch_common::set_nof_mutex(uint32_t nof_mutex_) { phch_common::phch_common(uint32_t max_workers) : tx_sem(max_workers)
nof_mutex = nof_mutex_; {
assert(nof_mutex <= max_mutex); this->nof_workers = nof_workers;
params.max_prach_offset_us = 20;
radio = NULL;
mac = NULL;
is_first_tx = false;
is_first_of_burst = false;
pdsch_p_b = 0;
this->max_workers = max_workers;
bzero(&pusch_cfg, sizeof(pusch_cfg));
bzero(&hopping_cfg, sizeof(hopping_cfg));
bzero(&pucch_cfg, sizeof(pucch_cfg));
bzero(&ul_grants, sizeof(ul_grants));
for (uint32_t i=0;i<max_workers;i++) {
sem_init(&tx_sem[i], 0, 0); // All semaphores start blocked
}
}
phch_common::~phch_common() {
for (uint32_t i=0;i<max_workers;i++) {
sem_destroy(&tx_sem[i]);
}
}
void phch_common::set_nof_workers(uint32_t nof_workers)
{
this->nof_workers = nof_workers;
} }
void phch_common::reset() { void phch_common::reset() {
@ -61,35 +87,42 @@ bool phch_common::init(srslte_cell_t *cell_, srslte::radio* radio_h_, mac_interf
is_first_of_burst = true; is_first_of_burst = true;
is_first_tx = true; is_first_tx = true;
for (uint32_t i=0;i<max_mutex;i++) { reset();
pthread_mutex_init(&tx_mutex[i], NULL);
}
reset();
return true; return true;
} }
void phch_common::stop() { void phch_common::stop() {
for (uint32_t i=0;i<nof_mutex;i++) { for (uint32_t i=0;i<max_workers;i++) {
pthread_mutex_trylock(&tx_mutex[i]); sem_post(&tx_sem[i]);
pthread_mutex_unlock(&tx_mutex[i]);
} }
} }
void phch_common::worker_end(uint32_t tx_mutex_cnt, cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time) /* The transmission of UL subframes must be in sequence. The correct sequence is guaranteed by a chain of N semaphores,
* one per TTI%nof_workers. Each threads waits for the semaphore for the current thread and after transmission allows
* next TTI to be transmitted
*
* Each worker uses this function to indicate that all processing is done and data is ready for transmission or
* there is no transmission at all (tx_enable). In that case, the end of burst message will be sent to the radio
*/
void phch_common::worker_end(uint32_t tti, cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time)
{ {
// Wait previous TTIs to be transmitted // This variable is not protected but it is very unlikely that 2 threads arrive here simultaneously since at the beginning
// there is no workload and threads are separated by 1 ms
if (is_first_tx) { if (is_first_tx) {
is_first_tx = false; is_first_tx = false;
} else { // Allow my own transmission if I'm the first to transmit
pthread_mutex_lock(&tx_mutex[tx_mutex_cnt%nof_mutex]); sem_post(&tx_sem[tti%nof_workers]);
} }
radio->set_tti(tx_mutex_cnt); // Wait for the green light to transmit in the current TTI
sem_wait(&tx_sem[tti%nof_workers]);
radio->set_tti(tti);
radio->tx((void **) buffer, nof_samples, tx_time); radio->tx((void **) buffer, nof_samples, tx_time);
// Trigger next transmission // Allow next TTI to transmit
pthread_mutex_unlock(&tx_mutex[(tx_mutex_cnt+1)%nof_mutex]); sem_post(&tx_sem[(tti+1)%nof_workers]);
// Trigger MAC clock // Trigger MAC clock
mac->tti_clock(); mac->tti_clock();

View File

@ -206,7 +206,7 @@ cf_t* phch_worker::get_buffer_rx(uint32_t antenna_idx)
return signal_buffer_rx[antenna_idx]; return signal_buffer_rx[antenna_idx];
} }
void phch_worker::set_time(uint32_t tti_, uint32_t tx_mutex_cnt_, srslte_timestamp_t tx_time_) void phch_worker::set_time(uint32_t tti_, uint32_t tx_worker_cnt_, srslte_timestamp_t tx_time_)
{ {
tti_rx = tti_; tti_rx = tti_;
tti_tx_dl = TTI_TX(tti_rx); tti_tx_dl = TTI_TX(tti_rx);
@ -219,7 +219,7 @@ void phch_worker::set_time(uint32_t tti_, uint32_t tx_mutex_cnt_, srslte_timesta
t_rx = TTIMOD(tti_rx); t_rx = TTIMOD(tti_rx);
t_tx_ul = TTIMOD(tti_tx_ul); t_tx_ul = TTIMOD(tti_tx_ul);
tx_mutex_cnt = tx_mutex_cnt_; tx_worker_cnt = tx_worker_cnt_;
memcpy(&tx_time, &tx_time_, sizeof(srslte_timestamp_t)); memcpy(&tx_time, &tx_time_, sizeof(srslte_timestamp_t));
} }
@ -483,7 +483,7 @@ void phch_worker::work_imp()
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
Debug("Sending to radio\n"); Debug("Sending to radio\n");
phy->worker_end(tx_mutex_cnt, signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time); phy->worker_end(tx_worker_cnt, signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time);
is_worker_running = false; is_worker_running = false;

View File

@ -48,7 +48,7 @@ namespace srsenb {
phy::phy() : workers_pool(MAX_WORKERS), phy::phy() : workers_pool(MAX_WORKERS),
workers(MAX_WORKERS), workers(MAX_WORKERS),
workers_common(txrx::MUTEX_X_WORKER*MAX_WORKERS), workers_common(MAX_WORKERS),
nof_workers(0) nof_workers(0)
{ {
radio_handler = NULL; radio_handler = NULL;
@ -141,10 +141,10 @@ bool phy::init(phy_args_t *args,
void phy::stop() void phy::stop()
{ {
tx_rx.stop(); tx_rx.stop();
workers_common.stop();
for (uint32_t i=0;i<nof_workers;i++) { for (uint32_t i=0;i<nof_workers;i++) {
workers[i].stop(); workers[i].stop();
} }
workers_common.stop();
workers_pool.stop(); workers_pool.stop();
prach.stop(); prach.stop();
} }

View File

@ -42,7 +42,7 @@ using namespace std;
namespace srsenb { namespace srsenb {
txrx::txrx() : tx_mutex_cnt(0), nof_tx_mutex(0), tti(0) { txrx::txrx() : tx_worker_cnt(0), nof_workers(0), tti(0) {
running = false; running = false;
radio_h = NULL; radio_h = NULL;
log_h = NULL; log_h = NULL;
@ -58,11 +58,11 @@ bool txrx::init(srslte::radio* radio_h_, srslte::thread_pool* workers_pool_, phc
workers_pool = workers_pool_; workers_pool = workers_pool_;
worker_com = worker_com_; worker_com = worker_com_;
prach = prach_; prach = prach_;
tx_mutex_cnt = 0; tx_worker_cnt = 0;
running = true; running = true;
nof_tx_mutex = MUTEX_X_WORKER*workers_pool->get_nof_workers(); nof_workers = workers_pool->get_nof_workers();
worker_com->set_nof_mutex(nof_tx_mutex); worker_com->set_nof_workers(nof_workers);
start(prio_); start(prio_);
return true; return true;
@ -126,12 +126,12 @@ void txrx::run_thread()
srslte_timestamp_add(&tx_time, 0, HARQ_DELAY_MS*1e-3); srslte_timestamp_add(&tx_time, 0, HARQ_DELAY_MS*1e-3);
Debug("Settting TTI=%d, tx_mutex=%d, tx_time=%ld:%f to worker %d\n", Debug("Settting TTI=%d, tx_mutex=%d, tx_time=%ld:%f to worker %d\n",
tti, tx_mutex_cnt, tti, tx_worker_cnt,
tx_time.full_secs, tx_time.frac_secs, tx_time.full_secs, tx_time.frac_secs,
worker->get_id()); worker->get_id());
worker->set_time(tti, tx_mutex_cnt, tx_time); worker->set_time(tti, tx_worker_cnt, tx_time);
tx_mutex_cnt = (tx_mutex_cnt+1)%nof_tx_mutex; tx_worker_cnt = (tx_worker_cnt+1)%nof_workers;
// Trigger phy worker execution // Trigger phy worker execution
workers_pool->start_worker(worker); workers_pool->start_worker(worker);

View File

@ -33,6 +33,7 @@
#include <pthread.h> #include <pthread.h>
#include <string.h> #include <string.h>
#include <vector> #include <vector>
#include <semaphore.h>
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/radio/radio.h" #include "srslte/radio/radio.h"
@ -116,7 +117,8 @@ typedef struct {
uint8_t last_ri; uint8_t last_ri;
uint8_t last_pmi; uint8_t last_pmi;
phch_common(uint32_t max_mutex = 3); phch_common(uint32_t max_workers);
~phch_common();
void init(phy_interface_rrc::phy_cfg_t *config, void init(phy_interface_rrc::phy_cfg_t *config,
phy_args_t *args, phy_args_t *args,
srslte::log *_log, srslte::log *_log,
@ -144,8 +146,7 @@ typedef struct {
void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
void set_nof_mutex(uint32_t nof_mutex); void set_nof_workers(uint32_t nof_workers);
bool sr_enabled; bool sr_enabled;
int sr_last_tx_tti; int sr_last_tx_tti;
@ -179,7 +180,9 @@ typedef struct {
std::vector<pthread_mutex_t> tx_mutex; std::vector<sem_t> tx_sem;
uint32_t nof_workers;
uint32_t max_workers;
bool is_first_of_burst; bool is_first_of_burst;
srslte::radio *radio_h; srslte::radio *radio_h;
@ -208,10 +211,6 @@ typedef struct {
bool is_first_tx; bool is_first_tx;
uint32_t nof_workers;
uint32_t nof_mutex;
uint32_t max_mutex;
srslte_cell_t cell; srslte_cell_t cell;
dl_metrics_t dl_metrics; dl_metrics_t dl_metrics;

View File

@ -83,7 +83,6 @@ public:
void force_freq(float dl_freq, float ul_freq); void force_freq(float dl_freq, float ul_freq);
// Other functions // Other functions
const static int MUTEX_X_WORKER = 4;
double set_rx_gain(double gain); double set_rx_gain(double gain);
int radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); int radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time);
int scell_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); int scell_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time);
@ -438,9 +437,9 @@ private:
float time_adv_sec, next_time_adv_sec; float time_adv_sec, next_time_adv_sec;
uint32_t tti; uint32_t tti;
bool do_agc; bool do_agc;
uint32_t nof_tx_mutex; uint32_t tx_worker_cnt;
uint32_t tx_mutex_cnt; uint32_t nof_workers;
float ul_dl_factor; float ul_dl_factor;
int current_earfcn; int current_earfcn;

View File

@ -52,7 +52,7 @@ public:
/* Functions used by main PHY thread */ /* Functions used by main PHY thread */
cf_t* get_buffer(uint32_t antenna_idx); cf_t* get_buffer(uint32_t antenna_idx);
void set_tti(uint32_t tti, uint32_t tx_tti); void set_tti(uint32_t tti, uint32_t tx_worker_cnt);
void set_tx_time(srslte_timestamp_t tx_time, uint32_t next_offset); void set_tx_time(srslte_timestamp_t tx_time, uint32_t next_offset);
void set_prach(cf_t *prach_ptr, float prach_power); void set_prach(cf_t *prach_ptr, float prach_power);
void set_cfo(float cfo); void set_cfo(float cfo);

View File

@ -39,15 +39,14 @@ namespace srsue {
cf_t zeros[50000]; cf_t zeros[50000];
phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) phch_common::phch_common(uint32_t max_workers) : tx_sem(max_workers)
{ {
config = NULL; config = NULL;
args = NULL; args = NULL;
log_h = NULL; log_h = NULL;
radio_h = NULL; radio_h = NULL;
mac = NULL; mac = NULL;
max_mutex = max_mutex_; this->max_workers = max_workers;
nof_mutex = 0;
rx_gain_offset = 0; rx_gain_offset = 0;
last_ri = 0; last_ri = 0;
last_pmi = 0; last_pmi = 0;
@ -65,17 +64,28 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_)
bzero(zeros, 50000*sizeof(cf_t)); bzero(zeros, 50000*sizeof(cf_t));
// FIXME: This is an ugly fix to avoid the TX filters to empty for (uint32_t i=0;i<max_workers;i++) {
/* sem_init(&tx_sem[i], 0, 0); // All semaphores start blocked
for (int i=0;i<50000;i++) { }
zeros[i] = 0.01*cexpf(((float) i/50000)*0.1*_Complex_I);
}*/
reset(); reset();
sib13_configured = false; sib13_configured = false;
mcch_configured = false; mcch_configured = false;
} }
phch_common::~phch_common() {
for (uint32_t i=0;i<max_workers;i++) {
sem_post(&tx_sem[i]);
}
for (uint32_t i=0;i<max_workers;i++) {
sem_destroy(&tx_sem[i]);
}
}
void phch_common::set_nof_workers(uint32_t nof_workers) {
this->nof_workers = nof_workers;
}
void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args, srslte::log *_log, srslte::radio *_radio, rrc_interface_phy *_rrc, mac_interface_phy *_mac) void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args, srslte::log *_log, srslte::radio *_radio, rrc_interface_phy *_rrc, mac_interface_phy *_mac)
{ {
@ -87,15 +97,6 @@ void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args,
args = _args; args = _args;
is_first_tx = true; is_first_tx = true;
sr_last_tx_tti = -1; sr_last_tx_tti = -1;
for (uint32_t i=0;i<nof_mutex;i++) {
pthread_mutex_init(&tx_mutex[i], NULL);
}
}
void phch_common::set_nof_mutex(uint32_t nof_mutex_) {
nof_mutex = nof_mutex_;
assert(nof_mutex <= max_mutex);
} }
bool phch_common::ul_rnti_active(uint32_t tti) { bool phch_common::ul_rnti_active(uint32_t tti) {
@ -231,23 +232,30 @@ bool phch_common::is_any_pending_ack() {
return false; return false;
} }
/* The transmisison of UL subframes must be in sequence. Each worker uses this function to indicate /* The transmission of UL subframes must be in sequence. The correct sequence is guaranteed by a chain of N semaphores,
* that all processing is done and data is ready for transmission or there is no transmission at all (tx_enable). * one per TTI%max_workers. Each threads waits for the semaphore for the current thread and after transmission allows
* In that case, the end of burst message will be send to the radio * next TTI to be transmitted
*
* Each worker uses this function to indicate that all processing is done and data is ready for transmission or
* there is no transmission at all (tx_enable). In that case, the end of burst message will be sent to the radio
*/ */
void phch_common::worker_end(uint32_t tti, bool tx_enable, void phch_common::worker_end(uint32_t tti, bool tx_enable,
cf_t *buffer, uint32_t nof_samples, cf_t *buffer, uint32_t nof_samples,
srslte_timestamp_t tx_time) srslte_timestamp_t tx_time)
{ {
// Wait previous TTIs to be transmitted // This variable is not protected but it is very unlikely that 2 threads arrive here simultaneously since at the beginning
// there is no workload and threads are separated by 1 ms
if (is_first_tx) { if (is_first_tx) {
is_first_tx = false; is_first_tx = false;
} else { // Allow my own transmission if I'm the first to transmit
pthread_mutex_lock(&tx_mutex[tti%nof_mutex]); sem_post(&tx_sem[tti%nof_workers]);
} }
radio_h->set_tti(tti); // Wait for the green light to transmit in the current TTI
sem_wait(&tx_sem[tti%nof_workers]);
radio_h->set_tti(tti);
if (tx_enable) { if (tx_enable) {
radio_h->tx_single(buffer, nof_samples, tx_time); radio_h->tx_single(buffer, nof_samples, tx_time);
is_first_of_burst = false; is_first_of_burst = false;
@ -263,8 +271,9 @@ void phch_common::worker_end(uint32_t tti, bool tx_enable,
} }
} }
} }
// Trigger next transmission
pthread_mutex_unlock(&tx_mutex[(tti+1)%nof_mutex]); // Allow next TTI to transmit
sem_post(&tx_sem[(tti+1)%nof_workers]);
} }

View File

@ -81,8 +81,8 @@ void phch_recv::init(srslte::radio_multi *_radio_handler, mac_interface_phy *_ma
return; return;
} }
nof_tx_mutex = MUTEX_X_WORKER * workers_pool->get_nof_workers(); nof_workers = workers_pool->get_nof_workers();
worker_com->set_nof_mutex(nof_tx_mutex); worker_com->set_nof_workers(nof_workers);
// Initialize cell searcher // Initialize cell searcher
search_p.init(sf_buffer, log_h, nof_rx_antennas, this); search_p.init(sf_buffer, log_h, nof_rx_antennas, this);
@ -128,7 +128,7 @@ void phch_recv::reset()
radio_overflow_return = false; radio_overflow_return = false;
in_sync_cnt = 0; in_sync_cnt = 0;
out_of_sync_cnt = 0; out_of_sync_cnt = 0;
tx_mutex_cnt = 0; tx_worker_cnt = 0;
time_adv_sec = 0; time_adv_sec = 0;
next_offset = 0; next_offset = 0;
srate_mode = SRATE_NONE; srate_mode = SRATE_NONE;
@ -454,13 +454,13 @@ void phch_recv::run_thread()
worker->set_prach(prach_ptr?&prach_ptr[prach_sf_cnt*SRSLTE_SF_LEN_PRB(cell.nof_prb)]:NULL, prach_power); worker->set_prach(prach_ptr?&prach_ptr[prach_sf_cnt*SRSLTE_SF_LEN_PRB(cell.nof_prb)]:NULL, prach_power);
worker->set_cfo(get_tx_cfo()); worker->set_cfo(get_tx_cfo());
worker->set_tti(tti, tx_mutex_cnt); worker->set_tti(tti, tx_worker_cnt);
worker->set_tx_time(tx_time, next_offset); worker->set_tx_time(tx_time, next_offset);
next_offset = 0; next_offset = 0;
if (next_time_adv_sec != time_adv_sec) { if (next_time_adv_sec != time_adv_sec) {
time_adv_sec = next_time_adv_sec; time_adv_sec = next_time_adv_sec;
} }
tx_mutex_cnt = (tx_mutex_cnt+1) % nof_tx_mutex; tx_worker_cnt = (tx_worker_cnt+1) % nof_workers;
// Advance/reset prach subframe pointer // Advance/reset prach subframe pointer
if (prach_ptr) { if (prach_ptr) {

View File

@ -193,10 +193,10 @@ cf_t* phch_worker::get_buffer(uint32_t antenna_idx)
return signal_buffer[antenna_idx]; return signal_buffer[antenna_idx];
} }
void phch_worker::set_tti(uint32_t tti_, uint32_t tx_tti_) void phch_worker::set_tti(uint32_t tti_, uint32_t tx_worker_cnt)
{ {
tti = tti_; tti = tti_;
tx_tti = tx_tti_; tx_tti = tx_worker_cnt;
log_h->step(tti); log_h->step(tti);
if (log_phy_lib_h) { if (log_phy_lib_h) {
log_phy_lib_h->step(tti); log_phy_lib_h->step(tti);

View File

@ -52,7 +52,7 @@ namespace srsue {
phy::phy() : workers_pool(MAX_WORKERS), phy::phy() : workers_pool(MAX_WORKERS),
workers(MAX_WORKERS), workers(MAX_WORKERS),
workers_common(phch_recv::MUTEX_X_WORKER*MAX_WORKERS),nof_coworkers(0) workers_common(MAX_WORKERS),nof_coworkers(0)
{ {
} }

View File

@ -1176,7 +1176,8 @@ void nas::send_detach_request(bool switch_off)
return; return;
} }
LIBLTE_MME_DETACH_REQUEST_MSG_STRUCT detach_request = {}; LIBLTE_MME_DETACH_REQUEST_MSG_STRUCT detach_request;
bzero(&detach_request, sizeof(detach_request));
if (switch_off) { if (switch_off) {
detach_request.detach_type.switch_off = 1; detach_request.detach_type.switch_off = 1;
detach_request.detach_type.type_of_detach = LIBLTE_MME_SO_FLAG_SWITCH_OFF; detach_request.detach_type.type_of_detach = LIBLTE_MME_SO_FLAG_SWITCH_OFF;

View File

@ -64,7 +64,7 @@ int pcsc_usim::init(usim_args_t *args, srslte::log *log_)
log->error("Error reading IMSI from SIM.\n"); log->error("Error reading IMSI from SIM.\n");
return ret; return ret;
} }
imsi_str = tmp; imsi_str.assign(tmp, tmp_len);
// Check extracted IMSI and convert // Check extracted IMSI and convert
if(15 == imsi_str.length()) { if(15 == imsi_str.length()) {

View File

@ -729,10 +729,10 @@ uint32_t rrc::sib_start_tti(uint32_t tti, uint32_t period, uint32_t offset, uint
*/ */
bool rrc::si_acquire(uint32_t sib_index) bool rrc::si_acquire(uint32_t sib_index)
{ {
uint32_t tti; uint32_t tti = 0;
uint32_t si_win_start=0, si_win_len=0; uint32_t si_win_start=0, si_win_len=0;
uint16_t period; uint16_t period = 0;
uint32_t sched_index; uint32_t sched_index = 0;
uint32_t x, sf, offset; uint32_t x, sf, offset;
uint32_t last_win_start = 0; uint32_t last_win_start = 0;