/* * Copyright 2013-2019 Software Radio Systems Limited * * This file is part of srsLTE. * * srsLTE is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * srsLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * A copy of the GNU Affero General Public License can be found in * the LICENSE file in the top-level directory of this distribution * and at http://www.gnu.org/licenses/. * */ #include "srslte/common/log_filter.h" #include "srslte/interfaces/ue_interfaces.h" #include "srsue/hdr/mac/mac.h" #include #include using namespace srsue; using namespace srslte; #define TESTASSERT(cond) \ { \ if (!(cond)) { \ std::cout << "[" << __FUNCTION__ << "][Line " << __LINE__ << "]: FAIL at " << (#cond) << std::endl; \ return SRSLTE_ERROR; \ } \ } namespace srslte { // fake classes class rlc_dummy : public srsue::rlc_interface_mac { public: rlc_dummy(srslte::log_filter* log_) : received_bytes(0), log(log_) {} bool has_data(const uint32_t lcid) { return false; } uint32_t get_buffer_state(const uint32_t lcid) { return 10; } int read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) { return 0; }; void write_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) { log->debug_hex(payload, nof_bytes, "Received %d B on LCID %d\n", nof_bytes, lcid); received_bytes += nof_bytes; }; void write_pdu_bcch_bch(uint8_t* payload, uint32_t nof_bytes){}; void write_pdu_bcch_dlsch(uint8_t* payload, uint32_t nof_bytes){}; void write_pdu_pcch(uint8_t* payload, uint32_t nof_bytes){}; void write_pdu_mch(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes){}; uint32_t get_received_bytes() { return received_bytes; } private: uint32_t received_bytes; srslte::log_filter* log; }; class phy_dummy : public phy_interface_mac { public: phy_dummy() : scell_cmd(0){}; // phy_interface_mac void configure_prach_params(){}; virtual void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm){}; prach_info_t prach_get_info() { prach_info_t info = {}; return info; }; void sr_send(){}; int sr_last_tx_tti() { return 0; }; void set_mch_period_stop(uint32_t stop){}; // phy_interface_mac_common void set_crnti(uint16_t rnti){}; void set_timeadv_rar(uint32_t ta_cmd){}; void set_timeadv(uint32_t ta_cmd){}; void set_activation_deactivation_scell(uint32_t cmd) { scell_cmd = cmd; }; void set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rnti){}; uint32_t get_current_tti() { return 0; } float get_phr() { return 0; }; float get_pathloss_db() { return 0; }; // getter for test execution uint32_t get_scell_cmd() { return scell_cmd; } private: uint32_t scell_cmd; }; class rrc_dummy : public rrc_interface_mac { public: void ho_ra_completed(bool ra_successful) { printf("%s\n", __FUNCTION__); } void release_pucch_srs() { printf("%s\n", __FUNCTION__); } void run_tti(uint32_t tti) { printf("%s\n", __FUNCTION__); } void ra_problem() { printf("%s\n", __FUNCTION__); } }; } // namespace srslte int mac_unpack_test() { // This MAC PDU contains three subheaders const uint32_t mac_header_len = 4; // Subheader 1 is SCell Activation/Deactivation CE // - 1 byte SDU payload 0x02 const uint32_t mac_pdu1_len = 1; // Subheader 2 is for LCID 1 // - 2 bytes SDU payload 0x00 0x08 const uint32_t mac_pdu2_len = 2; // Subheader 3 is for LCID 3 (RLC AM PDU with 2 B header and 54 B data) // - 56 bytes SDU payload 0x98 .. 0x89, 0x00, 0x00 const uint32_t mac_pdu3_len = 56; uint8_t dl_sch_pdu[] = {0x3b, 0x21, 0x02, 0x03, 0x02, 0x00, 0x08, 0x98, 0x1b, 0x45, 0x00, 0x05, 0xda, 0xc7, 0x23, 0x40, 0x00, 0x40, 0x11, 0xe6, 0x9b, 0xc0, 0xa8, 0x03, 0x01, 0xc0, 0xa8, 0x03, 0x02, 0xd8, 0x29, 0x13, 0x89, 0x05, 0xc6, 0x2b, 0x73, 0x00, 0x0d, 0xc3, 0xb3, 0x5c, 0xa3, 0x23, 0xad, 0x00, 0x03, 0x20, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x13, 0x89, 0x00, 0x00}; srslte::log_filter rlc_log("RLC"); srslte::log_filter mac_log("MAC"); mac_log.set_level(srslte::LOG_LEVEL_DEBUG); mac_log.set_hex_limit(100000); 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); // create dummy DL action and grant and push MAC PDU mac_interface_phy::tb_action_dl_t dl_action; mac_interface_phy::mac_grant_dl_t mac_grant; bzero(&dl_action, sizeof(dl_action)); bzero(&mac_grant, sizeof(mac_grant)); mac_grant.rnti = 0xbeaf; mac_grant.tb[0].tbs = sizeof(dl_sch_pdu); int cc_idx = 0; // Send grant to MAC and get action for this TB, then call tb_decoded to unlock MAC mac.new_grant_dl(cc_idx, mac_grant, &dl_action); // Copy PDU into provided buffer bool dl_ack[SRSLTE_MAX_CODEWORDS] = {true, false}; memcpy(dl_action.tb[0].payload, dl_sch_pdu, sizeof(dl_sch_pdu)); dl_action.tb[0].enabled = true; mac.tb_decoded(cc_idx, mac_grant, dl_ack); // make sure MAC PDU thread picks up before stopping sleep(1); mac.run_tti(0); mac.stop(); // check length of both received RLC PDUs TESTASSERT(rlc.get_received_bytes() == mac_pdu2_len + mac_pdu3_len); // check received SCell activation command TESTASSERT(phy.get_scell_cmd() == 2); return SRSLTE_SUCCESS; } int main(int argc, char** argv) { if (mac_unpack_test()) { printf("MAC PDU unpack test failed.\n"); return -1; } return 0; }