diff --git a/srsue/hdr/stack/mac/mux.h b/srsue/hdr/stack/mac/mux.h index eca2c7dd6..2488bf691 100644 --- a/srsue/hdr/stack/mac/mux.h +++ b/srsue/hdr/stack/mac/mux.h @@ -32,6 +32,7 @@ #include "srslte/common/log.h" #include "srslte/common/pdu.h" #include "srslte/interfaces/ue_interfaces.h" +#include /* Logical Channel Multiplexing and Prioritization + Msg3 Buffer */ @@ -39,8 +40,9 @@ typedef struct { uint8_t lcid; uint8_t lcg; - int Bj; - int PBR; // -1 sets to infinity + int32_t Bj; + int32_t PBR; // in kByte/s, -1 sets to infinity + uint32_t bucket_size; uint32_t BSD; uint32_t priority; int sched_len; @@ -53,9 +55,12 @@ class mux { public: mux(); + ~mux(){}; void reset(); void init(rlc_interface_mac *rlc, srslte::log *log_h, bsr_interface_mux *bsr_procedure, phr_proc *phr_procedure_); + void step(const uint32_t tti); + bool is_pending_any_sdu(); bool is_pending_sdu(uint32_t lcid); @@ -86,21 +91,21 @@ private: std::vector logical_channels; // Mutex for exclusive access - pthread_mutex_t mutex; + std::mutex mutex; - srslte::log *log_h; - rlc_interface_mac *rlc; - bsr_interface_mux *bsr_procedure; - phr_proc *phr_procedure; - uint16_t pending_crnti_ce; + srslte::log* log_h = nullptr; + rlc_interface_mac* rlc = nullptr; + bsr_interface_mux* bsr_procedure = nullptr; + phr_proc* phr_procedure = nullptr; + uint16_t pending_crnti_ce = 0; /* Msg3 Buffer */ srslte::byte_buffer_t msg_buff; /* PDU Buffer */ - srslte::sch_pdu pdu_msg; - bool msg3_has_been_transmitted; - bool msg3_pending; + srslte::sch_pdu pdu_msg; + bool msg3_has_been_transmitted = false; + bool msg3_pending = false; }; } // namespace srsue diff --git a/srsue/src/stack/mac/mac.cc b/srsue/src/stack/mac/mac.cc index 8f7df36d9..65db717f9 100644 --- a/srsue/src/stack/mac/mac.cc +++ b/srsue/src/stack/mac/mac.cc @@ -198,6 +198,7 @@ void mac::run_tti(const uint32_t tti) // Step all procedures Debug("Running MAC tti=%d\n", tti); + mux_unit.step(tti); bsr_procedure.step(tti); phr_procedure.step(tti); @@ -570,17 +571,19 @@ void mac::setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_t config.priority = priority; config.PBR = PBR_x_tti; config.BSD = BSD; + config.bucket_size = config.PBR * config.BSD; setup_lcid(config); } void mac::setup_lcid(const logical_channel_config_t& config) { - Info("Logical Channel Setup: LCID=%d, LCG=%d, priority=%d, PBR=%d, BSd=%d\n", + Info("Logical Channel Setup: LCID=%d, LCG=%d, priority=%d, PBR=%d, BSD=%dms, bucket_size=%d\n", config.lcid, config.lcg, config.priority, config.PBR, - config.BSD); + config.BSD, + config.bucket_size); mux_unit.setup_lcid(config); bsr_procedure.setup_lcid(config.lcid, config.lcg, config.priority); } diff --git a/srsue/src/stack/mac/mux.cc b/srsue/src/stack/mac/mux.cc index 40f4fc040..cb2ad28df 100644 --- a/srsue/src/stack/mac/mux.cc +++ b/srsue/src/stack/mac/mux.cc @@ -34,16 +34,6 @@ namespace srsue { mux::mux() : pdu_msg(MAX_NOF_SUBHEADERS) { - pthread_mutex_init(&mutex, NULL); - - pending_crnti_ce = 0; - - log_h = NULL; - rlc = NULL; - bsr_procedure = NULL; - phr_procedure = NULL; - // msg3_buff_start_pdu = NULL; - msg3_flush(); } @@ -65,6 +55,21 @@ void mux::reset() pending_crnti_ce = 0; } +void mux::step(const uint32_t tti) +{ + std::lock_guard lock(mutex); + + // update Bj according to 36.321 Sec 5.4.3.1 + for (auto& channel : logical_channels) { + // Add PRB unless it's infinity + if (channel.PBR >= 0) { + channel.Bj += channel.PBR; // PBR is in kByte/s, conversion in Byte and ms not needed + } + channel.Bj = SRSLTE_MIN((uint32_t)channel.Bj, channel.bucket_size); + Debug("Update Bj: lcid=%d, Bj=%d\n", channel.lcid, channel.Bj); + } +} + bool mux::is_pending_any_sdu() { for (uint32_t i = 0; i < logical_channels.size(); i++) { @@ -156,17 +161,10 @@ srslte::sch_subh::cetype bsr_format_convert(bsr_proc::bsr_format_t format) { // Multiplexing and logical channel priorization as defined in Section 5.4.3 uint8_t* mux::pdu_get(srslte::byte_buffer_t* payload, uint32_t pdu_sz) { - pthread_mutex_lock(&mutex); + std::lock_guard lock(mutex); // Reset sched_len and update Bj for (auto& channel : logical_channels) { - // Add PRB unless it's infinity - if (channel.PBR >= 0) { - channel.Bj += channel.PBR; - } - if (channel.Bj >= (int)channel.BSD) { - channel.Bj = channel.BSD * channel.PBR; - } channel.sched_len = 0; } @@ -272,8 +270,6 @@ uint8_t* mux::pdu_get(srslte::byte_buffer_t* payload, uint32_t pdu_sz) /* Generate MAC PDU and save to buffer */ uint8_t *ret = pdu_msg.write_packet(log_h); - pthread_mutex_unlock(&mutex); - return ret; } diff --git a/srsue/test/mac_test.cc b/srsue/test/mac_test.cc index cd9f33971..ed9b37e81 100644 --- a/srsue/test/mac_test.cc +++ b/srsue/test/mac_test.cc @@ -314,6 +314,10 @@ int mac_ul_logical_channel_prioritization_test1() mac.setup_lcid(channel.lcid, channel.lcg, channel.priority, channel.PBR, channel.BSD); } + // run TTI to setup Bj, no UL data available yet, so no BSR should be triggered + mac.run_tti(0); + usleep(200); + // write dummy data for each LCID (except CCCH) rlc.write_sdu(1, 50); rlc.write_sdu(2, 40); @@ -366,7 +370,7 @@ int mac_ul_logical_channel_prioritization_test2() // - 20 B MAC SDU for LCID=3 // - 1 B Padding // =120 N - const uint8_t tv[] = {0x3d, 0x21, 0x32, 0x22, 0x28, 0x23, 0x14, 0x1f, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + const uint8_t tv[] = {0x3d, 0x21, 0x32, 0x22, 0x28, 0x23, 0x14, 0x1f, 0x51, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, @@ -426,6 +430,10 @@ int mac_ul_logical_channel_prioritization_test2() rlc.write_sdu(2, 40); rlc.write_sdu(3, 20); + // run TTI to setup Bj, BSR should be generated + mac.run_tti(0); + usleep(100); + // create UL action and grant and push MAC PDU { mac_interface_phy_lte::tb_action_ul_t ul_action = {}; @@ -494,16 +502,16 @@ int mac_ul_logical_channel_prioritization_test3() // The config of DRB1 config.lcid = 3; config.lcg = 3; - config.PBR = 8; - config.BSD = 100; // 1000ms - config.priority = 15; // highest prio + config.PBR = 8; // 8 kByte/s + config.BSD = 100; // 100ms + config.priority = 15; lcids.push_back(config); // DRB2 config.lcid = 4; config.lcg = 1; - config.PBR = 0; - config.priority = 7; + config.PBR = 0; // no PBR + config.priority = 7; // higher prio lcids.push_back(config); // setup LCIDs in MAC @@ -511,6 +519,10 @@ int mac_ul_logical_channel_prioritization_test3() mac.setup_lcid(channel.lcid, channel.lcg, channel.priority, channel.PBR, channel.BSD); } + // run TTI to setup Bj + mac.run_tti(0); + sleep(1); + // write dummy data for each LCID rlc.write_sdu(3, 50); rlc.write_sdu(4, 50); @@ -546,6 +558,92 @@ int mac_ul_logical_channel_prioritization_test3() return SRSLTE_SUCCESS; } +// PDU with single SDU and short BSR +int mac_ul_sch_pdu_with_short_bsr_test() +{ + const uint8_t tv[] = {0x3f, 0x3d, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + + srslte::log_filter mac_log("MAC"); + mac_log.set_level(srslte::LOG_LEVEL_DEBUG); + mac_log.set_hex_limit(100000); + + srslte::log_filter rlc_log("RLC"); + rlc_log.set_level(srslte::LOG_LEVEL_DEBUG); + rlc_log.set_hex_limit(100000); + + // dummy layers + phy_dummy phy; + rlc_dummy rlc(&rlc_log); + rrc_dummy rrc; + + // the actual MAC + mac mac; + mac.init(&phy, &rlc, &rrc, &mac_log); + const uint16_t crnti = 0x1001; + mac.set_ho_rnti(crnti, 0); + + // generate configs for two LCIDs with different priority and PBR + std::vector lcids; + logical_channel_config_t config = {}; + // The config of DRB1 + config.lcid = 3; + config.lcg = 3; + config.PBR = 8; + config.BSD = 100; // 100ms + config.priority = 15; + lcids.push_back(config); + + // DRB2 + config.lcid = 4; + config.lcg = 1; + config.PBR = 0; + config.priority = 7; + lcids.push_back(config); + + // setup LCIDs in MAC + for (auto& channel : lcids) { + mac.setup_lcid(channel.lcid, channel.lcg, channel.priority, channel.PBR, channel.BSD); + } + + // write dummy data + rlc.write_sdu(1, 10); + + // generate TTI + uint32 tti = 0; + mac.run_tti(tti++); + usleep(100); + + // create UL action and grant and push MAC PDU + { + mac_interface_phy_lte::tb_action_ul_t ul_action = {}; + mac_interface_phy_lte::mac_grant_ul_t mac_grant = {}; + + mac_grant.rnti = crnti; // make sure MAC picks it up as valid UL grant + mac_grant.tb.ndi_present = true; + mac_grant.tb.ndi = true; + mac_grant.tb.tbs = 14; // give room for MAC subheader, SDU and short BSR + int cc_idx = 0; + + // Send grant to MAC and get action for this TB, then call tb_decoded to unlock MAC + mac.new_grant_ul(cc_idx, mac_grant, &ul_action); + + // print generated PDU + mac_log.info_hex(ul_action.tb.payload, mac_grant.tb.tbs, "Generated PDU (%d B)\n", mac_grant.tb.tbs); +#if HAVE_PCAP + pcap_handle->write_ul_crnti(ul_action.tb.payload, mac_grant.tb.tbs, 0x1001, true, 1); +#endif + + TESTASSERT(memcmp(ul_action.tb.payload, tv, sizeof(tv)) == 0); + } + + // make sure MAC PDU thread picks up before stopping + sleep(1); + mac.run_tti(tti); + mac.stop(); + + return SRSLTE_SUCCESS; +} + int main(int argc, char** argv) { #if HAVE_PCAP @@ -578,5 +676,10 @@ int main(int argc, char** argv) return -1; } + if (mac_ul_sch_pdu_with_short_bsr_test()) { + printf("mac_ul_sch_pdu_with_long_bsr_test() test failed.\n"); + return -1; + } + return 0; }