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

master
Ismael Gomez 6 years ago
commit 243a7708d4

@ -100,109 +100,204 @@ public:
private:
byte_buffer_pool *pool;
srslte::log *log;
uint32_t lcid;
srsue::pdcp_interface_rlc *pdcp;
srsue::rrc_interface_rlc *rrc;
// Transmitter sub-class
class rlc_am_tx : public timer_callback
{
public:
rlc_am_tx(rlc_am *parent_, uint32_t queue_len);
~rlc_am_tx();
// TX SDU buffers
rlc_tx_queue tx_sdu_queue;
byte_buffer_t *tx_sdu;
// PDU being resegmented
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;
void init();
bool configure(srslte_rlc_am_config_t cfg_);
static const int poll_periodicity = 8; // After how many data PDUs a status PDU shall be requested
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
***************************************************************************/
// Timer checks
bool status_prohibited();
bool poll_retx();
void check_reordering_timeout();
// 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.
// Helpers
bool poll_required();
// Tx counters
uint32_t pdu_without_poll;
uint32_t byte_without_poll;
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);
rlc_status_pdu_t tx_status;
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);
/****************************************************************************
* Timers
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
void reassemble_rx_sdus();
srslte::timers::timer *poll_retx_timer;
uint32_t poll_retx_timer_id;
bool inside_tx_window(uint16_t sn);
bool inside_rx_window(uint16_t sn);
void debug_state();
void print_rx_segments();
srslte::timers::timer *status_prohibit_timer;
uint32_t status_prohibit_timer_id;
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);
// 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;
srslte::log *log;
srsue::pdcp_interface_rlc *pdcp;
mac_interface_timers *mac_timers;
uint32_t lcid;
srslte_rlc_am_config_t cfg;
std::string rb_name;
static const int poll_periodicity = 8; // After how many data PDUs a status PDU shall be requested
};
/****************************************************************************

@ -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,
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;
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,
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);
if (srslte_pdcch_encode(&q->pdcch, &dci_msg, location, rnti, q->sf_symbols, sf_idx, q->cfi)) {

@ -97,7 +97,8 @@ int main(int argc, char **argv) {
}
/* 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)) {
printf("error initialising CRC\n");
exit(-1);

@ -60,6 +60,8 @@ bool verbose = false;
#define TEST(X, CODE) static bool test_##X (char *func_name, double *timing, uint32_t block_size) {\
struct timeval start, end;\
bzero(&start, sizeof(start));\
bzero(&end, sizeof(end));\
float mse = 0.0f;\
bool passed;\
strncpy(func_name, #X, 32);\
@ -781,7 +783,8 @@ TEST(srslte_vec_apply_cfo,
)
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, z);
@ -807,7 +810,8 @@ TEST(srslte_cfo_correct,
)
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, z);

@ -129,7 +129,9 @@ int main(int argc, char **argv)
{
int ret = SRSLTE_ERROR;
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);

@ -440,7 +440,7 @@ void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg)
rlc_log->error("Error instantiating RLC\n");
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;
} else {
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

@ -75,13 +75,13 @@ bool rlc_um::configure(srslte_rlc_config_t cnfg_)
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
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;
}
@ -149,7 +149,6 @@ void rlc_um::write_sdu(byte_buffer_t *sdu, bool blocking)
} else {
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)
{
if(is_mrb) {
if (is_mrb) {
std::stringstream ss;
ss << "MRB" << lcid;
return ss.str();

@ -190,8 +190,8 @@ uint32_t prbset_to_bitmask() {
int main(int argc, char **argv) {
struct timeval t[3] = {};
size_t tx_nof_bits = 0, rx_nof_bits = 0;
srslte_enb_dl_t enb_dl = {};
srslte_ue_dl_t ue_dl = {};
srslte_enb_dl_t enb_dl;
srslte_ue_dl_t ue_dl;
srslte_softbuffer_tx_t *softbuffer_tx[SRSLTE_MAX_TB] = {};
srslte_softbuffer_rx_t *softbuffer_rx[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};
bzero(&enb_dl, sizeof(enb_dl));
bzero(&ue_dl, sizeof(ue_dl));
/*
* Allocate Memory
*/
@ -304,9 +307,12 @@ int main(int argc, char **argv) {
/*
* Run eNodeB
*/
srslte_ra_dl_dci_t dci = {};
srslte_ra_dl_dci_t dci;
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));
last_prbset_num = prbset_num;

@ -42,15 +42,21 @@ class mac_dummy_timers
:public srslte::mac_interface_timers
{
public:
srslte::timers::timer* timer_get(uint32_t timer_id)
{
return &t;
mac_dummy_timers() : timers(8) {}
srslte::timers::timer* timer_get(uint32_t timer_id) {
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:
srslte::timers::timer t;
srslte::timers timers;
};
class rlc_am_tester
@ -135,7 +141,7 @@ private:
bool running;
};
void basic_test()
bool basic_test()
{
srslte::log_filter log1("RLC_AM_1");
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.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg);
rlc2.configure(&cnfg);
if (not rlc1.configure(&cnfg)) {
return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1
byte_buffer_t sdu_bufs[NBUFS];
@ -215,11 +226,17 @@ void basic_test()
}
// Check statistics
assert(rlc1.get_num_tx_bytes() == rlc2.get_num_rx_bytes());
assert(rlc2.get_num_tx_bytes() == rlc1.get_num_rx_bytes());
if (rlc1.get_num_tx_bytes() != rlc2.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 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.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg);
rlc2.configure(&cnfg);
if (not rlc1.configure(&cnfg)) {
return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1
byte_buffer_t sdu_bufs[NBUFS];
@ -284,11 +306,17 @@ void concat_test()
}
// check statistics
assert(rlc1.get_num_tx_bytes() == rlc2.get_num_rx_bytes());
assert(rlc2.get_num_tx_bytes() == rlc1.get_num_rx_bytes());
if (rlc1.get_num_tx_bytes() != rlc2.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 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.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg);
rlc2.configure(&cnfg);
if (not rlc1.configure(&cnfg)) {
return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1
byte_buffer_t sdu_bufs[NBUFS];
@ -370,11 +403,17 @@ void segment_test()
assert(tester.sdus[i]->msg[j] == j);
}
assert(rlc1.get_num_tx_bytes() == rlc2.get_num_rx_bytes());
assert(rlc2.get_num_tx_bytes() == rlc1.get_num_rx_bytes());
if (rlc1.get_num_tx_bytes() != rlc2.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 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.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg);
rlc2.configure(&cnfg);
if (not rlc1.configure(&cnfg)) {
return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1
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);
}
// Sleep to let reordering timeout expire
usleep(10000);
// Step timers until reordering timeout expires
int cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(4 == rlc2.get_buffer_state());
@ -462,12 +509,14 @@ void retx_test()
assert(tester.n_sdus == 5);
for(int i=0; i<tester.n_sdus; i++)
{
assert(tester.sdus[i]->N_bytes == 1);
assert(*(tester.sdus[i]->msg) == i);
if (tester.sdus[i]->N_bytes != 1) return -1;
if (*(tester.sdus[i]->msg) != i) return -1;
}
return 0;
}
void resegment_test_1()
bool resegment_test_1()
{
// SDUs: | 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.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg);
rlc2.configure(&cnfg);
if (not rlc1.configure(&cnfg)) {
return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1
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);
}
// Sleep to let reordering timeout expire
usleep(10000);
// Step timers until reordering timeout expires
int cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(4 == rlc2.get_buffer_state());
@ -570,13 +627,15 @@ void resegment_test_1()
assert(tester.n_sdus == 5);
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++)
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 |
@ -612,8 +671,13 @@ void resegment_test_2()
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);
rlc2.configure(&cnfg);
if (not rlc1.configure(&cnfg)) {
return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1
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);
}
// Sleep to let reordering timeout expire
usleep(10000);
// Step timers until reordering timeout expires
int cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(4 == rlc2.get_buffer_state());
@ -677,13 +744,15 @@ void resegment_test_2()
assert(tester.n_sdus == 5);
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++)
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 |
@ -719,8 +788,13 @@ void resegment_test_3()
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);
rlc2.configure(&cnfg);
if (not rlc1.configure(&cnfg)) {
return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1
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);
}
// Sleep to let reordering timeout expire
usleep(10000);
// Step timers until reordering timeout expires
int cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(4 == rlc2.get_buffer_state());
@ -780,13 +857,15 @@ void resegment_test_3()
assert(tester.n_sdus == 5);
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++)
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 |
@ -822,8 +901,13 @@ void resegment_test_4()
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);
rlc2.configure(&cnfg);
if (not rlc1.configure(&cnfg)) {
return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1
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);
}
// Sleep to let reordering timeout expire
usleep(10000);
// Step timers until reordering timeout expires
int cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(4 == rlc2.get_buffer_state());
@ -883,13 +970,15 @@ void resegment_test_4()
assert(tester.n_sdus == 5);
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++)
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 |
@ -908,8 +997,6 @@ void resegment_test_5()
rlc_am rlc1;
rlc_am rlc2;
int len;
log1.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.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg);
rlc2.configure(&cnfg);
if (not rlc1.configure(&cnfg)) {
return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 5 SDUs into RLC1
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);
}
// Sleep to let reordering timeout expire
usleep(10000);
// Step timers until reordering timeout expires
int cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(4 == rlc2.get_buffer_state());
@ -986,13 +1081,15 @@ void resegment_test_5()
assert(tester.n_sdus == 5);
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++)
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 |
// 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.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg);
rlc2.configure(&cnfg);
if (not rlc1.configure(&cnfg)) {
return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push SDUs into RLC1
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);
}
// Sleep to let reordering timeout expire
usleep(10000);
// Step timers until reordering timeout expires
int cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(4 == rlc2.get_buffer_state());
@ -1111,14 +1216,17 @@ void resegment_test_6()
}
for(int i=3;i<9;i++)
{
assert(tester.sdus[i]->N_bytes == 54);
for(int j=0;j<54;j++)
assert(tester.sdus[i]->msg[j] == j);
if(tester.sdus[i]->N_bytes != 54) return -1;
for(int j=0;j<54;j++) {
if (tester.sdus[i]->msg[j] != j) return -1;
}
}
return 0;
}
// Retransmission of PDU segments of the same size
void resegment_test_7()
bool resegment_test_7()
{
// SDUs: | 30 | 30 |
// 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.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg);
rlc2.configure(&cnfg);
if (not rlc1.configure(&cnfg)) {
return -1;
}
if (not rlc2.configure(&cnfg)) {
return -1;
}
// Push 2 SDUs into RLC1
byte_buffer_t sdu_bufs[N_SDU_BUFS];
@ -1201,8 +1314,11 @@ void resegment_test_7()
}
}
// Sleep to let reordering timeout expire
usleep(10000);
// Step timers until reordering timeout expires
int cnt = 5;
while (cnt--) {
timers.step_all();
}
assert(12 == rlc1.get_buffer_state());
@ -1222,8 +1338,6 @@ void resegment_test_7()
}
}
usleep(10000);
// Read status PDU from RLC2
assert(rlc2.get_buffer_state());
byte_buffer_t status_buf;
@ -1237,7 +1351,6 @@ void resegment_test_7()
assert(15 == rlc1.get_buffer_state());
// second round of retx, forcing resegmentation
byte_buffer_t retx2[4];
for (uint32_t i = 0; i < 4; i++) {
@ -1253,26 +1366,35 @@ void resegment_test_7()
// check buffer states
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());
// Check number of SDUs and their content
assert(tester.n_sdus == N_SDU_BUFS);
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++) {
assert(tester.sdus[i]->msg[j] == i);
if (tester.sdus[i]->msg[j] != i) return -1;
}
}
#if HAVE_PCAP
pcap.close();
#endif
return 0;
}
// Retransmission of PDU segments with different size
void resegment_test_8()
bool resegment_test_8()
{
// SDUs: | 30 | 30 |
// 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.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg);
rlc2.configure(&cnfg);
if (not rlc1.configure(&cnfg)) {
exit(-1);
}
if (not rlc2.configure(&cnfg)) {
exit(-1);
}
// Push 2 SDUs into RLC1
byte_buffer_t sdu_bufs[N_SDU_BUFS];
@ -1354,8 +1481,11 @@ void resegment_test_8()
}
}
// Sleep to let reordering timeout expire
usleep(10000);
// Step timers until reordering timeout expires
int cnt = 5;
while (cnt--) {
timers.step_all();
}
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
assert(rlc2.get_buffer_state());
@ -1402,27 +1536,41 @@ void resegment_test_8()
#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
assert(0 == rlc1.get_buffer_state());
assert(0 == rlc2.get_buffer_state());
if (rlc1.get_buffer_state() != 0) {
return -1;
};
if (rlc2.get_buffer_state() != 0) {
return -1;
};
// Check number of SDUs and their content
assert(tester.n_sdus == N_SDU_BUFS);
for(int i=0; i<tester.n_sdus; i++)
{
assert(tester.sdus[i]->N_bytes == sdu_size);
for(int i=0; i<tester.n_sdus; i++) {
if (tester.sdus[i]->N_bytes != sdu_size) return -1;
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
pcap.close();
#endif
return 0;
}
void reset_test()
bool reset_test()
{
srslte::log_filter log1("RLC_AM_1");
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.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
byte_buffer_t sdu_buf;
@ -1473,10 +1623,14 @@ void reset_test()
len = rlc1.read_pdu(pdu_bufs.msg, 100);
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");
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.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg);
if (not rlc1.configure(&cnfg)) {
return -1;
}
// start thread reading
ul_writer writer(&rlc1);
@ -1510,48 +1666,93 @@ void stop_test()
// stop RLC1
rlc1.stop();
return 0;
}
int main(int argc, char **argv) {
basic_test();
int main(int argc, char **argv)
{
if (basic_test()) {
printf("basic_test failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup();
concat_test();
if (concat_test()) {
printf("concat_test failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup();
segment_test();
if (segment_test()) {
printf("segment_test failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup();
retx_test();
if (retx_test()) {
printf("retx_test failed\n");
exit(-1);
};
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();
resegment_test_2();
if (resegment_test_2()) {
printf("resegment_test_2 failed\n");
exit(-1);
};
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();
resegment_test_4();
if (resegment_test_4()) {
printf("resegment_test_4 failed\n");
exit(-1);
};
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();
resegment_test_6();
if (resegment_test_6()) {
printf("resegment_test_6 failed\n");
exit(-1);
};
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();
resegment_test_8();
if (resegment_test_8()) {
printf("resegment_test_8 failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup();
reset_test();
if (reset_test()) {
printf("reset_test failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup();
stop_test();
if (stop_test()) {
printf("stop_test failed\n");
exit(-1);
};
byte_buffer_pool::get_instance()->cleanup();
}

@ -28,6 +28,7 @@
#define SRSENB_PHCH_COMMON_H
#include <map>
#include <semaphore.h>
#include "srslte/interfaces/enb_interfaces.h"
#include "srslte/interfaces/enb_metrics_interface.h"
#include "srslte/common/gen_mch_tables.h"
@ -36,6 +37,7 @@
#include "srslte/common/thread_pool.h"
#include "srslte/radio/radio.h"
#include <string.h>
namespace srsenb {
typedef struct {
@ -73,29 +75,16 @@ class phch_common
{
public:
phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) {
nof_mutex = 0;
max_mutex = max_mutex_;
params.max_prach_offset_us = 20;
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));
}
phch_common(uint32_t nof_workers);
~phch_common();
void set_nof_workers(uint32_t nof_workers);
bool init(srslte_cell_t *cell, srslte::radio *radio_handler, mac_interface_phy *mac);
void reset();
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);
// Common objects
@ -148,13 +137,12 @@ public:
private:
std::vector<pthread_mutex_t> tx_mutex;
std::vector<sem_t> tx_sem;
bool is_first_tx;
bool is_first_of_burst;
uint32_t nof_workers;
uint32_t nof_mutex;
uint32_t max_mutex;
uint32_t max_workers;
pthread_mutex_t user_mutex;

@ -46,7 +46,7 @@ public:
void reset();
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);
void rem_rnti(uint16_t rnti);
@ -93,8 +93,9 @@ private:
cf_t *signal_buffer_rx[SRSLTE_MAX_PORTS];
cf_t *signal_buffer_tx[SRSLTE_MAX_PORTS];
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 tx_worker_cnt;
srslte_enb_dl_t enb_dl;
srslte_enb_ul_t enb_ul;
srslte_softbuffer_tx_t temp_mbsfn_softbuffer;

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

@ -41,9 +41,35 @@ using namespace std;
namespace srsenb {
void phch_common::set_nof_mutex(uint32_t nof_mutex_) {
nof_mutex = nof_mutex_;
assert(nof_mutex <= max_mutex);
phch_common::phch_common(uint32_t max_workers) : tx_sem(max_workers)
{
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() {
@ -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_tx = true;
for (uint32_t i=0;i<max_mutex;i++) {
pthread_mutex_init(&tx_mutex[i], NULL);
}
reset();
reset();
return true;
}
void phch_common::stop() {
for (uint32_t i=0;i<nof_mutex;i++) {
pthread_mutex_trylock(&tx_mutex[i]);
pthread_mutex_unlock(&tx_mutex[i]);
for (uint32_t i=0;i<max_workers;i++) {
sem_post(&tx_sem[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) {
is_first_tx = false;
} else {
pthread_mutex_lock(&tx_mutex[tx_mutex_cnt%nof_mutex]);
is_first_tx = false;
// Allow my own transmission if I'm the first to transmit
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);
// Trigger next transmission
pthread_mutex_unlock(&tx_mutex[(tx_mutex_cnt+1)%nof_mutex]);
// Allow next TTI to transmit
sem_post(&tx_sem[(tti+1)%nof_workers]);
// Trigger MAC clock
mac->tti_clock();

@ -206,7 +206,7 @@ cf_t* phch_worker::get_buffer_rx(uint32_t 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_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_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));
}
@ -483,7 +483,7 @@ void phch_worker::work_imp()
pthread_mutex_unlock(&mutex);
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;

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

@ -42,7 +42,7 @@ using namespace std;
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;
radio_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_;
worker_com = worker_com_;
prach = prach_;
tx_mutex_cnt = 0;
tx_worker_cnt = 0;
running = true;
nof_tx_mutex = MUTEX_X_WORKER*workers_pool->get_nof_workers();
worker_com->set_nof_mutex(nof_tx_mutex);
nof_workers = workers_pool->get_nof_workers();
worker_com->set_nof_workers(nof_workers);
start(prio_);
return true;
@ -126,12 +126,12 @@ void txrx::run_thread()
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",
tti, tx_mutex_cnt,
tti, tx_worker_cnt,
tx_time.full_secs, tx_time.frac_secs,
worker->get_id());
worker->set_time(tti, tx_mutex_cnt, tx_time);
tx_mutex_cnt = (tx_mutex_cnt+1)%nof_tx_mutex;
worker->set_time(tti, tx_worker_cnt, tx_time);
tx_worker_cnt = (tx_worker_cnt+1)%nof_workers;
// Trigger phy worker execution
workers_pool->start_worker(worker);

@ -33,6 +33,7 @@
#include <pthread.h>
#include <string.h>
#include <vector>
#include <semaphore.h>
#include "srslte/srslte.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/radio/radio.h"
@ -116,7 +117,8 @@ typedef struct {
uint8_t last_ri;
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,
phy_args_t *args,
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 set_nof_mutex(uint32_t nof_mutex);
void set_nof_workers(uint32_t nof_workers);
bool sr_enabled;
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;
srslte::radio *radio_h;
@ -208,10 +211,6 @@ typedef struct {
bool is_first_tx;
uint32_t nof_workers;
uint32_t nof_mutex;
uint32_t max_mutex;
srslte_cell_t cell;
dl_metrics_t dl_metrics;

@ -83,7 +83,6 @@ public:
void force_freq(float dl_freq, float ul_freq);
// Other functions
const static int MUTEX_X_WORKER = 4;
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 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;
uint32_t tti;
bool do_agc;
uint32_t nof_tx_mutex;
uint32_t tx_mutex_cnt;
uint32_t tx_worker_cnt;
uint32_t nof_workers;
float ul_dl_factor;
int current_earfcn;

@ -52,7 +52,7 @@ public:
/* Functions used by main PHY thread */
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_prach(cf_t *prach_ptr, float prach_power);
void set_cfo(float cfo);

@ -39,15 +39,14 @@ namespace srsue {
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;
args = NULL;
log_h = NULL;
radio_h = NULL;
mac = NULL;
max_mutex = max_mutex_;
nof_mutex = 0;
mac = NULL;
this->max_workers = max_workers;
rx_gain_offset = 0;
last_ri = 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));
// FIXME: This is an ugly fix to avoid the TX filters to empty
/*
for (int i=0;i<50000;i++) {
zeros[i] = 0.01*cexpf(((float) i/50000)*0.1*_Complex_I);
}*/
for (uint32_t i=0;i<max_workers;i++) {
sem_init(&tx_sem[i], 0, 0); // All semaphores start blocked
}
reset();
sib13_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)
{
@ -87,15 +97,6 @@ void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args,
args = _args;
is_first_tx = true;
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) {
@ -231,23 +232,30 @@ bool phch_common::is_any_pending_ack() {
return false;
}
/* The transmisison of UL subframes must be in sequence. 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 send to the radio
/* The transmission of UL subframes must be in sequence. The correct sequence is guaranteed by a chain of N semaphores,
* one per TTI%max_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, bool tx_enable,
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) {
is_first_tx = false;
} else {
pthread_mutex_lock(&tx_mutex[tti%nof_mutex]);
is_first_tx = false;
// Allow my own transmission if I'm the first to transmit
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) {
radio_h->tx_single(buffer, nof_samples, tx_time);
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]);
}

@ -81,8 +81,8 @@ void phch_recv::init(srslte::radio_multi *_radio_handler, mac_interface_phy *_ma
return;
}
nof_tx_mutex = MUTEX_X_WORKER * workers_pool->get_nof_workers();
worker_com->set_nof_mutex(nof_tx_mutex);
nof_workers = workers_pool->get_nof_workers();
worker_com->set_nof_workers(nof_workers);
// Initialize cell searcher
search_p.init(sf_buffer, log_h, nof_rx_antennas, this);
@ -128,7 +128,7 @@ void phch_recv::reset()
radio_overflow_return = false;
in_sync_cnt = 0;
out_of_sync_cnt = 0;
tx_mutex_cnt = 0;
tx_worker_cnt = 0;
time_adv_sec = 0;
next_offset = 0;
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_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);
next_offset = 0;
if (next_time_adv_sec != 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
if (prach_ptr) {

@ -193,10 +193,10 @@ cf_t* phch_worker::get_buffer(uint32_t 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_;
tx_tti = tx_tti_;
tti = tti_;
tx_tti = tx_worker_cnt;
log_h->step(tti);
if (log_phy_lib_h) {
log_phy_lib_h->step(tti);

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

@ -1176,7 +1176,8 @@ void nas::send_detach_request(bool switch_off)
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) {
detach_request.detach_type.switch_off = 1;
detach_request.detach_type.type_of_detach = LIBLTE_MME_SO_FLAG_SWITCH_OFF;

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

@ -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)
{
uint32_t tti;
uint32_t tti = 0;
uint32_t si_win_start=0, si_win_len=0;
uint16_t period;
uint32_t sched_index;
uint16_t period = 0;
uint32_t sched_index = 0;
uint32_t x, sf, offset;
uint32_t last_win_start = 0;

Loading…
Cancel
Save