|
|
@ -96,96 +96,112 @@ bool mac::init(mac_args_t *args_, srslte_cell_t *cell_, phy_interface_mac *phy,
|
|
|
|
|
|
|
|
|
|
|
|
reset();
|
|
|
|
reset();
|
|
|
|
|
|
|
|
|
|
|
|
started = true;
|
|
|
|
pthread_rwlock_init(&rwlock, NULL);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
started = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return started;
|
|
|
|
return started;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void mac::stop()
|
|
|
|
void mac::stop()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
pthread_rwlock_wrlock(&rwlock);
|
|
|
|
|
|
|
|
|
|
|
|
for (uint32_t i=0;i<ue_db.size();i++) {
|
|
|
|
for (uint32_t i=0;i<ue_db.size();i++) {
|
|
|
|
delete ue_db[i];
|
|
|
|
delete ue_db[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int i=0;i<NOF_BCCH_DLSCH_MSG;i++) {
|
|
|
|
for (int i=0;i<NOF_BCCH_DLSCH_MSG;i++) {
|
|
|
|
srslte_softbuffer_tx_free(&bcch_softbuffer_tx[i]);
|
|
|
|
srslte_softbuffer_tx_free(&bcch_softbuffer_tx[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
srslte_softbuffer_tx_free(&pcch_softbuffer_tx);
|
|
|
|
srslte_softbuffer_tx_free(&pcch_softbuffer_tx);
|
|
|
|
srslte_softbuffer_tx_free(&rar_softbuffer_tx);
|
|
|
|
srslte_softbuffer_tx_free(&rar_softbuffer_tx);
|
|
|
|
started = false;
|
|
|
|
started = false;
|
|
|
|
timers_thread.stop();
|
|
|
|
timers_thread.stop();
|
|
|
|
pdu_process_thread.stop();
|
|
|
|
pdu_process_thread.stop();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
pthread_rwlock_destroy(&rwlock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Implement Section 5.9
|
|
|
|
// Implement Section 5.9
|
|
|
|
void mac::reset()
|
|
|
|
void mac::reset()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Info("Resetting MAC\n");
|
|
|
|
Info("Resetting MAC\n");
|
|
|
|
|
|
|
|
|
|
|
|
timers_db.stop_all();
|
|
|
|
timers_db.stop_all();
|
|
|
|
|
|
|
|
|
|
|
|
tti = 0;
|
|
|
|
tti = 0;
|
|
|
|
last_rnti = 70;
|
|
|
|
last_rnti = 70;
|
|
|
|
|
|
|
|
|
|
|
|
/* Setup scheduler */
|
|
|
|
/* Setup scheduler */
|
|
|
|
scheduler.reset();
|
|
|
|
scheduler.reset();
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void mac::start_pcap(srslte::mac_pcap* pcap_)
|
|
|
|
void mac::start_pcap(srslte::mac_pcap* pcap_)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
pcap = pcap_;
|
|
|
|
pcap = pcap_;
|
|
|
|
// Set pcap in all UEs for UL messages
|
|
|
|
// Set pcap in all UEs for UL messages
|
|
|
|
for(std::map<uint16_t, ue*>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
|
|
|
|
for(std::map<uint16_t, ue*>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
|
|
|
|
ue *u = iter->second;
|
|
|
|
ue *u = iter->second;
|
|
|
|
u->start_pcap(pcap);
|
|
|
|
u->start_pcap(pcap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/********************************************************
|
|
|
|
/********************************************************
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* RLC interface
|
|
|
|
* RLC interface
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*******************************************************/
|
|
|
|
*******************************************************/
|
|
|
|
int mac::rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue)
|
|
|
|
int mac::rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
|
|
|
|
int ret = -1;
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
if(rnti != SRSLTE_MRNTI){
|
|
|
|
if(rnti != SRSLTE_MRNTI){
|
|
|
|
return scheduler.dl_rlc_buffer_state(rnti, lc_id, tx_queue, retx_queue);
|
|
|
|
ret = scheduler.dl_rlc_buffer_state(rnti, lc_id, tx_queue, retx_queue);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
for(uint32_t i = 0; i < mch.num_mtch_sched; i++){
|
|
|
|
for(uint32_t i = 0; i < mch.num_mtch_sched; i++){
|
|
|
|
if(lc_id == mch.mtch_sched[i].lcid){
|
|
|
|
if(lc_id == mch.mtch_sched[i].lcid){
|
|
|
|
mch.mtch_sched[i].lcid_buffer_size = tx_queue;
|
|
|
|
mch.mtch_sched[i].lcid_buffer_size = tx_queue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int mac::bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, sched_interface::ue_bearer_cfg_t* cfg)
|
|
|
|
int mac::bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, sched_interface::ue_bearer_cfg_t* cfg)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
// configure BSR group in UE
|
|
|
|
// configure BSR group in UE
|
|
|
|
ue_db[rnti]->set_lcg(lc_id, (uint32_t) cfg->group);
|
|
|
|
ue_db[rnti]->set_lcg(lc_id, (uint32_t) cfg->group);
|
|
|
|
return scheduler.bearer_ue_cfg(rnti, lc_id, cfg);
|
|
|
|
ret = scheduler.bearer_ue_cfg(rnti, lc_id, cfg);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int mac::bearer_ue_rem(uint16_t rnti, uint32_t lc_id)
|
|
|
|
int mac::bearer_ue_rem(uint16_t rnti, uint32_t lc_id)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
return scheduler.bearer_ue_rem(rnti, lc_id);
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
|
|
|
|
ret = scheduler.bearer_ue_rem(rnti, lc_id);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void mac::phy_config_enabled(uint16_t rnti, bool enabled)
|
|
|
|
void mac::phy_config_enabled(uint16_t rnti, bool enabled)
|
|
|
@ -193,58 +209,74 @@ void mac::phy_config_enabled(uint16_t rnti, bool enabled)
|
|
|
|
scheduler.phy_config_enabled(rnti, enabled);
|
|
|
|
scheduler.phy_config_enabled(rnti, enabled);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Update UE configuration
|
|
|
|
// Update UE configuration
|
|
|
|
int mac::ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg)
|
|
|
|
int mac::ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
|
|
|
|
|
|
|
|
// Add RNTI to the PHY (pregerate signals) now instead of after PRACH
|
|
|
|
// Add RNTI to the PHY (pregerate signals) now instead of after PRACH
|
|
|
|
if (!ue_db[rnti]->is_phy_added) {
|
|
|
|
if (!ue_db[rnti]->is_phy_added) {
|
|
|
|
ue_db[rnti]->is_phy_added = true;
|
|
|
|
ue_db[rnti]->is_phy_added = true;
|
|
|
|
Info("Registering rnti=0x%x to PHY...\n", rnti);
|
|
|
|
Info("Registering rnti=0x%x to PHY...\n", rnti);
|
|
|
|
// Register new user in PHY
|
|
|
|
// Register new user in PHY
|
|
|
|
if (phy_h->add_rnti(rnti)) {
|
|
|
|
if (phy_h->add_rnti(rnti)) {
|
|
|
|
Error("Registering new ue rnti=0x%x to PHY\n", rnti);
|
|
|
|
Error("Registering new ue rnti=0x%x to PHY\n", rnti);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Info("Done registering rnti=0x%x to PHY...\n", rnti);
|
|
|
|
Info("Done registering rnti=0x%x to PHY...\n", rnti);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Update Scheduler configuration
|
|
|
|
// Update Scheduler configuration
|
|
|
|
if (scheduler.ue_cfg(rnti, cfg)) {
|
|
|
|
if (scheduler.ue_cfg(rnti, cfg)) {
|
|
|
|
Error("Registering new UE rnti=0x%x to SCHED\n", rnti);
|
|
|
|
Error("Registering new UE rnti=0x%x to SCHED\n", rnti);
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Removes UE from DB
|
|
|
|
// Removes UE from DB
|
|
|
|
int mac::ue_rem(uint16_t rnti)
|
|
|
|
int mac::ue_rem(uint16_t rnti)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
scheduler.ue_rem(rnti);
|
|
|
|
scheduler.ue_rem(rnti);
|
|
|
|
phy_h->rem_rnti(rnti);
|
|
|
|
phy_h->rem_rnti(rnti);
|
|
|
|
delete ue_db[rnti];
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_rwlock_wrlock(&rwlock);
|
|
|
|
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
|
|
|
|
delete ue_db[rnti];
|
|
|
|
ue_db.erase(rnti);
|
|
|
|
ue_db.erase(rnti);
|
|
|
|
Info("User rnti=0x%x removed from MAC/PHY\n", rnti);
|
|
|
|
Info("User rnti=0x%x removed from MAC/PHY\n", rnti);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
Error("User rnti=0x%x already removed\n", rnti);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int mac::cell_cfg(sched_interface::cell_cfg_t* cell_cfg)
|
|
|
|
int mac::cell_cfg(sched_interface::cell_cfg_t* cell_cfg)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
memcpy(&this->cell_config, cell_cfg, sizeof(sched_interface::cell_cfg_t));
|
|
|
|
memcpy(&this->cell_config, cell_cfg, sizeof(sched_interface::cell_cfg_t));
|
|
|
|
return scheduler.cell_cfg(cell_cfg);
|
|
|
|
return scheduler.cell_cfg(cell_cfg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void mac::get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS])
|
|
|
|
void mac::get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS])
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
int cnt=0;
|
|
|
|
int cnt=0;
|
|
|
|
for(std::map<uint16_t, ue*>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
|
|
|
|
for(std::map<uint16_t, ue*>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
|
|
|
|
ue *u = iter->second;
|
|
|
|
ue *u = iter->second;
|
|
|
@ -252,21 +284,23 @@ void mac::get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS])
|
|
|
|
u->metrics_read(&metrics[cnt]);
|
|
|
|
u->metrics_read(&metrics[cnt]);
|
|
|
|
cnt++;
|
|
|
|
cnt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/********************************************************
|
|
|
|
/********************************************************
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* PHY interface
|
|
|
|
* PHY interface
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*******************************************************/
|
|
|
|
*******************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
void mac::rl_failure(uint16_t rnti)
|
|
|
|
void mac::rl_failure(uint16_t rnti)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
uint32_t nof_fails = ue_db[rnti]->rl_failure();
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
if (nof_fails >= (uint32_t) args.link_failure_nof_err && args.link_failure_nof_err > 0) {
|
|
|
|
uint32_t nof_fails = ue_db[rnti]->rl_failure();
|
|
|
|
|
|
|
|
if (nof_fails >= (uint32_t) args.link_failure_nof_err && args.link_failure_nof_err > 0) {
|
|
|
|
Info("Detected Uplink failure for rnti=0x%x\n", rnti);
|
|
|
|
Info("Detected Uplink failure for rnti=0x%x\n", rnti);
|
|
|
|
rrc_h->rl_failure(rnti);
|
|
|
|
rrc_h->rl_failure(rnti);
|
|
|
|
ue_db[rnti]->rl_failure_reset();
|
|
|
|
ue_db[rnti]->rl_failure_reset();
|
|
|
@ -274,141 +308,166 @@ void mac::rl_failure(uint16_t rnti)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void mac::rl_ok(uint16_t rnti)
|
|
|
|
void mac::rl_ok(uint16_t rnti)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
ue_db[rnti]->rl_failure_reset();
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
|
|
|
|
ue_db[rnti]->rl_failure_reset();
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int mac::ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack)
|
|
|
|
int mac::ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
log_h->step(tti);
|
|
|
|
log_h->step(tti);
|
|
|
|
uint32_t nof_bytes = scheduler.dl_ack_info(tti, rnti, tb_idx, ack);
|
|
|
|
uint32_t nof_bytes = scheduler.dl_ack_info(tti, rnti, tb_idx, ack);
|
|
|
|
ue_db[rnti]->metrics_tx(ack, nof_bytes);
|
|
|
|
ue_db[rnti]->metrics_tx(ack, nof_bytes);
|
|
|
|
|
|
|
|
|
|
|
|
if (ack) {
|
|
|
|
if (ack) {
|
|
|
|
if (nof_bytes > 64) { // do not count RLC status messages only
|
|
|
|
if (nof_bytes > 64) { // do not count RLC status messages only
|
|
|
|
rrc_h->set_activity_user(rnti);
|
|
|
|
rrc_h->set_activity_user(rnti);
|
|
|
|
log_h->info("DL activity rnti=0x%x, n_bytes=%d\n", rnti, nof_bytes);
|
|
|
|
log_h->debug("DL activity rnti=0x%x, n_bytes=%d\n", rnti, nof_bytes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int mac::crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc)
|
|
|
|
int mac::crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
log_h->step(tti);
|
|
|
|
log_h->step(tti);
|
|
|
|
|
|
|
|
int ret = -1;
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
ue_db[rnti]->set_tti(tti);
|
|
|
|
ue_db[rnti]->set_tti(tti);
|
|
|
|
|
|
|
|
|
|
|
|
ue_db[rnti]->metrics_rx(crc, nof_bytes);
|
|
|
|
ue_db[rnti]->metrics_rx(crc, nof_bytes);
|
|
|
|
|
|
|
|
|
|
|
|
// push the pdu through the queue if received correctly
|
|
|
|
// push the pdu through the queue if received correctly
|
|
|
|
if (crc) {
|
|
|
|
if (crc) {
|
|
|
|
ue_db[rnti]->push_pdu(tti, nof_bytes);
|
|
|
|
ue_db[rnti]->push_pdu(tti, nof_bytes);
|
|
|
|
pdu_process_thread.notify();
|
|
|
|
pdu_process_thread.notify();
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
ue_db[rnti]->deallocate_pdu(tti);
|
|
|
|
ue_db[rnti]->deallocate_pdu(tti);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return scheduler.ul_crc_info(tti, rnti, crc);
|
|
|
|
ret = scheduler.ul_crc_info(tti, rnti, crc);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int mac::set_dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dl_ant_info) {
|
|
|
|
int mac::set_dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dl_ant_info) {
|
|
|
|
log_h->step(tti);
|
|
|
|
log_h->step(tti);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
scheduler.dl_ant_info(rnti, dl_ant_info);
|
|
|
|
scheduler.dl_ant_info(rnti, dl_ant_info);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int mac::ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value)
|
|
|
|
int mac::ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
log_h->step(tti);
|
|
|
|
log_h->step(tti);
|
|
|
|
|
|
|
|
int ret = -1;
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
scheduler.dl_ri_info(tti, rnti, ri_value);
|
|
|
|
scheduler.dl_ri_info(tti, rnti, ri_value);
|
|
|
|
ue_db[rnti]->metrics_dl_ri(ri_value);
|
|
|
|
ue_db[rnti]->metrics_dl_ri(ri_value);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int mac::pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value)
|
|
|
|
int mac::pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
log_h->step(tti);
|
|
|
|
log_h->step(tti);
|
|
|
|
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
|
|
|
|
int ret = -1;
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
scheduler.dl_pmi_info(tti, rnti, pmi_value);
|
|
|
|
scheduler.dl_pmi_info(tti, rnti, pmi_value);
|
|
|
|
ue_db[rnti]->metrics_dl_pmi(pmi_value);
|
|
|
|
ue_db[rnti]->metrics_dl_pmi(pmi_value);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int mac::cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value)
|
|
|
|
int mac::cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
log_h->step(tti);
|
|
|
|
log_h->step(tti);
|
|
|
|
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
scheduler.dl_cqi_info(tti, rnti, cqi_value);
|
|
|
|
scheduler.dl_cqi_info(tti, rnti, cqi_value);
|
|
|
|
ue_db[rnti]->metrics_dl_cqi(cqi_value);
|
|
|
|
ue_db[rnti]->metrics_dl_cqi(cqi_value);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int mac::snr_info(uint32_t tti, uint16_t rnti, float snr)
|
|
|
|
int mac::snr_info(uint32_t tti, uint16_t rnti, float snr)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
log_h->step(tti);
|
|
|
|
log_h->step(tti);
|
|
|
|
|
|
|
|
int ret = -1;
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
uint32_t cqi = srslte_cqi_from_snr(snr);
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
|
|
|
|
uint32_t cqi = srslte_cqi_from_snr(snr);
|
|
|
|
scheduler.ul_cqi_info(tti, rnti, cqi, 0);
|
|
|
|
scheduler.ul_cqi_info(tti, rnti, cqi, 0);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int mac::sr_detected(uint32_t tti, uint16_t rnti)
|
|
|
|
int mac::sr_detected(uint32_t tti, uint16_t rnti)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
log_h->step(tti);
|
|
|
|
log_h->step(tti);
|
|
|
|
|
|
|
|
int ret = -1;
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
scheduler.ul_sr_info(tti, rnti);
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
|
|
|
|
scheduler.ul_sr_info(tti, rnti);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
Error("User rnti=0x%x not found\n", rnti);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int mac::rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv)
|
|
|
|
int mac::rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
log_h->step(tti);
|
|
|
|
log_h->step(tti);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
|
|
|
|
|
|
|
|
// Find empty slot for pending rars
|
|
|
|
// Find empty slot for pending rars
|
|
|
|
uint32_t ra_id=0;
|
|
|
|
uint32_t ra_id=0;
|
|
|
|
while(pending_rars[ra_id].temp_crnti && ra_id<MAX_PENDING_RARS-1) {
|
|
|
|
while(pending_rars[ra_id].temp_crnti && ra_id<MAX_PENDING_RARS-1) {
|
|
|
@ -416,49 +475,53 @@ int mac::rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ra_id == MAX_PENDING_RARS) {
|
|
|
|
if (ra_id == MAX_PENDING_RARS) {
|
|
|
|
Error("Maximum number of pending RARs exceeded (%d)\n", MAX_PENDING_RARS);
|
|
|
|
Error("Maximum number of pending RARs exceeded (%d)\n", MAX_PENDING_RARS);
|
|
|
|
return -1;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Create new UE
|
|
|
|
// Create new UE
|
|
|
|
ue_db[last_rnti] = new ue;
|
|
|
|
ue_db[last_rnti] = new ue;
|
|
|
|
ue_db[last_rnti]->config(last_rnti, cell.nof_prb, &scheduler, rrc_h, rlc_h, log_h);
|
|
|
|
ue_db[last_rnti]->config(last_rnti, cell.nof_prb, &scheduler, rrc_h, rlc_h, log_h);
|
|
|
|
|
|
|
|
|
|
|
|
// Set PCAP if available
|
|
|
|
// Set PCAP if available
|
|
|
|
if (pcap) {
|
|
|
|
if (pcap) {
|
|
|
|
ue_db[last_rnti]->start_pcap(pcap);
|
|
|
|
ue_db[last_rnti]->start_pcap(pcap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Save RA info
|
|
|
|
// Save RA info
|
|
|
|
pending_rars[ra_id].preamble_idx = preamble_idx;
|
|
|
|
pending_rars[ra_id].preamble_idx = preamble_idx;
|
|
|
|
pending_rars[ra_id].ta_cmd = 2*time_adv;
|
|
|
|
pending_rars[ra_id].ta_cmd = 2*time_adv;
|
|
|
|
pending_rars[ra_id].temp_crnti = last_rnti;
|
|
|
|
pending_rars[ra_id].temp_crnti = last_rnti;
|
|
|
|
|
|
|
|
|
|
|
|
// Add new user to the scheduler so that it can RX/TX SRB0
|
|
|
|
// Add new user to the scheduler so that it can RX/TX SRB0
|
|
|
|
sched_interface::ue_cfg_t uecfg;
|
|
|
|
sched_interface::ue_cfg_t uecfg;
|
|
|
|
bzero(&uecfg, sizeof(sched_interface::ue_cfg_t));
|
|
|
|
bzero(&uecfg, sizeof(sched_interface::ue_cfg_t));
|
|
|
|
uecfg.ue_bearers[0].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH;
|
|
|
|
uecfg.ue_bearers[0].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH;
|
|
|
|
if (scheduler.ue_cfg(last_rnti, &uecfg)) {
|
|
|
|
if (scheduler.ue_cfg(last_rnti, &uecfg)) {
|
|
|
|
// Release pending RAR
|
|
|
|
// Release pending RAR
|
|
|
|
bzero(&pending_rars[ra_id], sizeof(pending_rar_t));
|
|
|
|
bzero(&pending_rars[ra_id], sizeof(pending_rar_t));
|
|
|
|
Error("Registering new user rnti=0x%x to SCHED\n", last_rnti);
|
|
|
|
Error("Registering new user rnti=0x%x to SCHED\n", last_rnti);
|
|
|
|
return -1;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Register new user in RRC
|
|
|
|
// Register new user in RRC
|
|
|
|
rrc_h->add_user(last_rnti);
|
|
|
|
rrc_h->add_user(last_rnti);
|
|
|
|
// Trigger scheduler RACH
|
|
|
|
// Trigger scheduler RACH
|
|
|
|
scheduler.dl_rach_info(tti, ra_id, last_rnti, 7);
|
|
|
|
scheduler.dl_rach_info(tti, ra_id, last_rnti, 7);
|
|
|
|
|
|
|
|
|
|
|
|
log_h->info("RACH: tti=%d, preamble=%d, offset=%d, temp_crnti=0x%x\n",
|
|
|
|
log_h->info("RACH: tti=%d, preamble=%d, offset=%d, temp_crnti=0x%x\n",
|
|
|
|
tti, preamble_idx, time_adv, last_rnti);
|
|
|
|
tti, preamble_idx, time_adv, last_rnti);
|
|
|
|
log_h->console("RACH: tti=%d, preamble=%d, offset=%d, temp_crnti=0x%x\n",
|
|
|
|
log_h->console("RACH: tti=%d, preamble=%d, offset=%d, temp_crnti=0x%x\n",
|
|
|
|
tti, preamble_idx, time_adv, last_rnti);
|
|
|
|
tti, preamble_idx, time_adv, last_rnti);
|
|
|
|
|
|
|
|
|
|
|
|
// Increae RNTI counter
|
|
|
|
// Increae RNTI counter
|
|
|
|
last_rnti++;
|
|
|
|
last_rnti++;
|
|
|
|
if (last_rnti >= 60000) {
|
|
|
|
if (last_rnti >= 60000) {
|
|
|
|
last_rnti = 70;
|
|
|
|
last_rnti = 70;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unlock:
|
|
|
|
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
|
|
|
|
int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
|
|
|
@ -468,76 +531,85 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
|
|
|
|
if (!started) {
|
|
|
|
if (!started) {
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!dl_sched_res) {
|
|
|
|
if (!dl_sched_res) {
|
|
|
|
return SRSLTE_ERROR_INVALID_INPUTS;
|
|
|
|
return SRSLTE_ERROR_INVALID_INPUTS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Run scheduler with current info
|
|
|
|
// Run scheduler with current info
|
|
|
|
sched_interface::dl_sched_res_t sched_result;
|
|
|
|
sched_interface::dl_sched_res_t sched_result;
|
|
|
|
bzero(&sched_result, sizeof(sched_interface::dl_sched_res_t));
|
|
|
|
bzero(&sched_result, sizeof(sched_interface::dl_sched_res_t));
|
|
|
|
if (scheduler.dl_sched(tti, &sched_result) < 0) {
|
|
|
|
if (scheduler.dl_sched(tti, &sched_result) < 0) {
|
|
|
|
Error("Running scheduler\n");
|
|
|
|
Error("Running scheduler\n");
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int n = 0;
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// Copy data grants
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Copy data grants
|
|
|
|
for (uint32_t i=0;i<sched_result.nof_data_elems;i++) {
|
|
|
|
for (uint32_t i=0;i<sched_result.nof_data_elems;i++) {
|
|
|
|
|
|
|
|
|
|
|
|
// Get UE
|
|
|
|
// Get UE
|
|
|
|
uint16_t rnti = sched_result.data[i].rnti;
|
|
|
|
uint16_t rnti = sched_result.data[i].rnti;
|
|
|
|
|
|
|
|
|
|
|
|
// Copy grant info
|
|
|
|
|
|
|
|
dl_sched_res->sched_grants[n].rnti = rnti;
|
|
|
|
|
|
|
|
dl_sched_res->sched_grants[n].dci_format = sched_result.data[i].dci_format;
|
|
|
|
|
|
|
|
memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.data[i].dci, sizeof(srslte_ra_dl_dci_t));
|
|
|
|
|
|
|
|
memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.data[i].dci_location, sizeof(srslte_dci_location_t));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
|
|
|
|
|
|
|
|
dl_sched_res->sched_grants[n].softbuffers[tb] =
|
|
|
|
|
|
|
|
ue_db[rnti]->get_tx_softbuffer(sched_result.data[i].dci.harq_process, tb);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (sched_result.data[i].nof_pdu_elems[tb] > 0) {
|
|
|
|
|
|
|
|
/* Get PDU if it's a new transmission */
|
|
|
|
|
|
|
|
dl_sched_res->sched_grants[n].data[tb] = ue_db[rnti]->generate_pdu(tb,
|
|
|
|
|
|
|
|
sched_result.data[i].pdu[tb],
|
|
|
|
|
|
|
|
sched_result.data[i].nof_pdu_elems[tb],
|
|
|
|
|
|
|
|
sched_result.data[i].tbs[tb]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!dl_sched_res->sched_grants[n].data[tb]) {
|
|
|
|
|
|
|
|
Error("Error! PDU was not generated (rnti=0x%04x, tb=%d)\n", rnti, tb);
|
|
|
|
|
|
|
|
sched_result.data[i].dci.tb_en[tb] = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (pcap) {
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data[tb], sched_result.data[i].tbs[tb], rnti, true, tti);
|
|
|
|
// Copy grant info
|
|
|
|
|
|
|
|
dl_sched_res->sched_grants[n].rnti = rnti;
|
|
|
|
|
|
|
|
dl_sched_res->sched_grants[n].dci_format = sched_result.data[i].dci_format;
|
|
|
|
|
|
|
|
memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.data[i].dci, sizeof(srslte_ra_dl_dci_t));
|
|
|
|
|
|
|
|
memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.data[i].dci_location, sizeof(srslte_dci_location_t));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
|
|
|
|
|
|
|
|
dl_sched_res->sched_grants[n].softbuffers[tb] =
|
|
|
|
|
|
|
|
ue_db[rnti]->get_tx_softbuffer(sched_result.data[i].dci.harq_process, tb);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (sched_result.data[i].nof_pdu_elems[tb] > 0) {
|
|
|
|
|
|
|
|
/* Get PDU if it's a new transmission */
|
|
|
|
|
|
|
|
dl_sched_res->sched_grants[n].data[tb] = ue_db[rnti]->generate_pdu(tb,
|
|
|
|
|
|
|
|
sched_result.data[i].pdu[tb],
|
|
|
|
|
|
|
|
sched_result.data[i].nof_pdu_elems[tb],
|
|
|
|
|
|
|
|
sched_result.data[i].tbs[tb]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!dl_sched_res->sched_grants[n].data[tb]) {
|
|
|
|
|
|
|
|
Error("Error! PDU was not generated (rnti=0x%04x, tb=%d)\n", rnti, tb);
|
|
|
|
|
|
|
|
sched_result.data[i].dci.tb_en[tb] = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (pcap) {
|
|
|
|
|
|
|
|
pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data[tb], sched_result.data[i].tbs[tb], rnti, true, tti);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* TB not enabled OR no data to send: set pointers to NULL */
|
|
|
|
|
|
|
|
dl_sched_res->sched_grants[n].data[tb] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* TB not enabled OR no data to send: set pointers to NULL */
|
|
|
|
|
|
|
|
dl_sched_res->sched_grants[n].data[tb] = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
n++;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
Warning("Invalid DL scheduling result. User 0x%x does not exist\n", rnti);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
n++;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Copy RAR grants
|
|
|
|
// No more uses of shared ue_db beyond here
|
|
|
|
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Copy RAR grants
|
|
|
|
for (uint32_t i=0;i<sched_result.nof_rar_elems;i++) {
|
|
|
|
for (uint32_t i=0;i<sched_result.nof_rar_elems;i++) {
|
|
|
|
// Copy grant info
|
|
|
|
// Copy grant info
|
|
|
|
dl_sched_res->sched_grants[n].rnti = sched_result.rar[i].rarnti;
|
|
|
|
dl_sched_res->sched_grants[n].rnti = sched_result.rar[i].rarnti;
|
|
|
|
dl_sched_res->sched_grants[n].dci_format = SRSLTE_DCI_FORMAT1A; // Force Format 1A
|
|
|
|
dl_sched_res->sched_grants[n].dci_format = SRSLTE_DCI_FORMAT1A; // Force Format 1A
|
|
|
|
memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.rar[i].dci, sizeof(srslte_ra_dl_dci_t));
|
|
|
|
memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.rar[i].dci, sizeof(srslte_ra_dl_dci_t));
|
|
|
|
memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.rar[i].dci_location, sizeof(srslte_dci_location_t));
|
|
|
|
memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.rar[i].dci_location, sizeof(srslte_dci_location_t));
|
|
|
|
|
|
|
|
|
|
|
|
// Set softbuffer (there are no retx in RAR but a softbuffer is required)
|
|
|
|
// Set softbuffer (there are no retx in RAR but a softbuffer is required)
|
|
|
|
dl_sched_res->sched_grants[n].softbuffers[0] = &rar_softbuffer_tx;
|
|
|
|
dl_sched_res->sched_grants[n].softbuffers[0] = &rar_softbuffer_tx;
|
|
|
|
|
|
|
|
|
|
|
|
// Assemble PDU
|
|
|
|
// Assemble PDU
|
|
|
|
dl_sched_res->sched_grants[n].data[0] = assemble_rar(sched_result.rar[i].grants, sched_result.rar[i].nof_grants, i, sched_result.rar[i].tbs);
|
|
|
|
dl_sched_res->sched_grants[n].data[0] = assemble_rar(sched_result.rar[i].grants, sched_result.rar[i].nof_grants, i, sched_result.rar[i].tbs);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (pcap) {
|
|
|
|
if (pcap) {
|
|
|
|
pcap->write_dl_ranti(dl_sched_res->sched_grants[n].data[0], sched_result.rar[i].tbs, dl_sched_res->sched_grants[n].rnti, true, tti);
|
|
|
|
pcap->write_dl_ranti(dl_sched_res->sched_grants[n].data[0], sched_result.rar[i].tbs, dl_sched_res->sched_grants[n].rnti, true, tti);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -545,15 +617,15 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
|
|
|
|
n++;
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Copy SI and Paging grants
|
|
|
|
// Copy SI and Paging grants
|
|
|
|
for (uint32_t i=0;i<sched_result.nof_bc_elems;i++) {
|
|
|
|
for (uint32_t i=0;i<sched_result.nof_bc_elems;i++) {
|
|
|
|
// Copy grant info
|
|
|
|
// Copy grant info
|
|
|
|
dl_sched_res->sched_grants[n].rnti = (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH ) ? SRSLTE_SIRNTI : SRSLTE_PRNTI;
|
|
|
|
dl_sched_res->sched_grants[n].rnti = (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH ) ? SRSLTE_SIRNTI : SRSLTE_PRNTI;
|
|
|
|
dl_sched_res->sched_grants[n].dci_format = SRSLTE_DCI_FORMAT1A; // Force Format 1A
|
|
|
|
dl_sched_res->sched_grants[n].dci_format = SRSLTE_DCI_FORMAT1A; // Force Format 1A
|
|
|
|
memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.bc[i].dci, sizeof(srslte_ra_dl_dci_t));
|
|
|
|
memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.bc[i].dci, sizeof(srslte_ra_dl_dci_t));
|
|
|
|
memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.bc[i].dci_location, sizeof(srslte_dci_location_t));
|
|
|
|
memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.bc[i].dci_location, sizeof(srslte_dci_location_t));
|
|
|
|
|
|
|
|
|
|
|
|
// Set softbuffer
|
|
|
|
// Set softbuffer
|
|
|
|
if (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH) {
|
|
|
|
if (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH) {
|
|
|
|
dl_sched_res->sched_grants[n].softbuffers[0] = &bcch_softbuffer_tx[sched_result.bc[i].index];
|
|
|
|
dl_sched_res->sched_grants[n].softbuffers[0] = &bcch_softbuffer_tx[sched_result.bc[i].index];
|
|
|
|
dl_sched_res->sched_grants[n].data[0] = assemble_si(sched_result.bc[i].index);
|
|
|
|
dl_sched_res->sched_grants[n].data[0] = assemble_si(sched_result.bc[i].index);
|
|
|
@ -566,20 +638,20 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
|
|
|
|
dl_sched_res->sched_grants[n].softbuffers[0] = &pcch_softbuffer_tx;
|
|
|
|
dl_sched_res->sched_grants[n].softbuffers[0] = &pcch_softbuffer_tx;
|
|
|
|
dl_sched_res->sched_grants[n].data[0] = pcch_payload_buffer;
|
|
|
|
dl_sched_res->sched_grants[n].data[0] = pcch_payload_buffer;
|
|
|
|
rlc_h->read_pdu_pcch(pcch_payload_buffer, pcch_payload_buffer_len);
|
|
|
|
rlc_h->read_pdu_pcch(pcch_payload_buffer, pcch_payload_buffer_len);
|
|
|
|
|
|
|
|
|
|
|
|
if (pcap) {
|
|
|
|
if (pcap) {
|
|
|
|
pcap->write_dl_pch(dl_sched_res->sched_grants[n].data[0], sched_result.bc[i].tbs, true, tti);
|
|
|
|
pcap->write_dl_pch(dl_sched_res->sched_grants[n].data[0], sched_result.bc[i].tbs, true, tti);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
n++;
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
dl_sched_res->nof_grants = n;
|
|
|
|
dl_sched_res->nof_grants = n;
|
|
|
|
|
|
|
|
|
|
|
|
// Number of CCH symbols
|
|
|
|
// Number of CCH symbols
|
|
|
|
dl_sched_res->cfi = sched_result.cfi;
|
|
|
|
dl_sched_res->cfi = sched_result.cfi;
|
|
|
|
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -587,12 +659,12 @@ void mac::build_mch_sched(uint32_t tbs)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
int sfs_per_sched_period = mcch.pmch_infolist_r9[0].pmch_config_r9.sf_alloc_end_r9;
|
|
|
|
int sfs_per_sched_period = mcch.pmch_infolist_r9[0].pmch_config_r9.sf_alloc_end_r9;
|
|
|
|
int bytes_per_sf = tbs/8 - 6;// leave 6 bytes for header
|
|
|
|
int bytes_per_sf = tbs/8 - 6;// leave 6 bytes for header
|
|
|
|
|
|
|
|
|
|
|
|
int total_space_avail_bytes = sfs_per_sched_period*bytes_per_sf;
|
|
|
|
int total_space_avail_bytes = sfs_per_sched_period*bytes_per_sf;
|
|
|
|
|
|
|
|
|
|
|
|
int total_bytes_to_tx = 0;
|
|
|
|
int total_bytes_to_tx = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// calculate total bytes to be scheduled
|
|
|
|
// calculate total bytes to be scheduled
|
|
|
|
for (uint32_t i = 0; i < mch.num_mtch_sched; i++) {
|
|
|
|
for (uint32_t i = 0; i < mch.num_mtch_sched; i++) {
|
|
|
|
total_bytes_to_tx += mch.mtch_sched[i].lcid_buffer_size;
|
|
|
|
total_bytes_to_tx += mch.mtch_sched[i].lcid_buffer_size;
|
|
|
@ -600,34 +672,34 @@ void mac::build_mch_sched(uint32_t tbs)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int last_mtch_stop = 0;
|
|
|
|
int last_mtch_stop = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if(total_bytes_to_tx >= total_space_avail_bytes){
|
|
|
|
if(total_bytes_to_tx >= total_space_avail_bytes){
|
|
|
|
for(uint32_t i = 0; i < mch.num_mtch_sched;i++){
|
|
|
|
for(uint32_t i = 0; i < mch.num_mtch_sched;i++){
|
|
|
|
double ratio = mch.mtch_sched[i].lcid_buffer_size/total_bytes_to_tx;
|
|
|
|
double ratio = mch.mtch_sched[i].lcid_buffer_size/total_bytes_to_tx;
|
|
|
|
float assigned_sfs = floor(sfs_per_sched_period*ratio);
|
|
|
|
float assigned_sfs = floor(sfs_per_sched_period*ratio);
|
|
|
|
mch.mtch_sched[i].stop = last_mtch_stop + (uint32_t)assigned_sfs;
|
|
|
|
mch.mtch_sched[i].stop = last_mtch_stop + (uint32_t)assigned_sfs;
|
|
|
|
last_mtch_stop = mch.mtch_sched[i].stop;
|
|
|
|
last_mtch_stop = mch.mtch_sched[i].stop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}else {
|
|
|
|
}else {
|
|
|
|
for(uint32_t i = 0; i < mch.num_mtch_sched;i++){
|
|
|
|
for(uint32_t i = 0; i < mch.num_mtch_sched;i++){
|
|
|
|
float assigned_sfs = ceil(((float)mch.mtch_sched[i].lcid_buffer_size)/((float)bytes_per_sf));
|
|
|
|
float assigned_sfs = ceil(((float)mch.mtch_sched[i].lcid_buffer_size)/((float)bytes_per_sf));
|
|
|
|
mch.mtch_sched[i].stop = last_mtch_stop + (uint32_t)assigned_sfs;
|
|
|
|
mch.mtch_sched[i].stop = last_mtch_stop + (uint32_t)assigned_sfs;
|
|
|
|
last_mtch_stop = mch.mtch_sched[i].stop;
|
|
|
|
last_mtch_stop = mch.mtch_sched[i].stop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int mac::get_mch_sched(bool is_mcch, dl_sched_t *dl_sched_res)
|
|
|
|
int mac::get_mch_sched(bool is_mcch, dl_sched_t *dl_sched_res)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
srslte_ra_mcs_t mcs;
|
|
|
|
srslte_ra_mcs_t mcs;
|
|
|
|
srslte_ra_mcs_t mcs_data;
|
|
|
|
srslte_ra_mcs_t mcs_data;
|
|
|
|
mcs.idx = this->sib13.mbsfn_area_info_list_r9[0].signalling_mcs_r9;
|
|
|
|
mcs.idx = this->sib13.mbsfn_area_info_list_r9[0].signalling_mcs_r9;
|
|
|
|
mcs_data.idx = this->mcch.pmch_infolist_r9[0].pmch_config_r9.datamcs_r9;
|
|
|
|
mcs_data.idx = this->mcch.pmch_infolist_r9[0].pmch_config_r9.datamcs_r9;
|
|
|
|
srslte_dl_fill_ra_mcs(&mcs, this->cell_config.cell.nof_prb);
|
|
|
|
srslte_dl_fill_ra_mcs(&mcs, this->cell_config.cell.nof_prb);
|
|
|
|
srslte_dl_fill_ra_mcs(&mcs_data, this->cell_config.cell.nof_prb);
|
|
|
|
srslte_dl_fill_ra_mcs(&mcs_data, this->cell_config.cell.nof_prb);
|
|
|
|
if(is_mcch){
|
|
|
|
if(is_mcch){
|
|
|
|
|
|
|
|
|
|
|
|
build_mch_sched(mcs_data.tbs);
|
|
|
|
build_mch_sched(mcs_data.tbs);
|
|
|
|
mch.mcch_payload = mcch_payload_buffer;
|
|
|
|
mch.mcch_payload = mcch_payload_buffer;
|
|
|
|
mch.current_sf_allocation_num = 1;
|
|
|
|
mch.current_sf_allocation_num = 1;
|
|
|
@ -636,17 +708,17 @@ int mac::get_mch_sched(bool is_mcch, dl_sched_t *dl_sched_res)
|
|
|
|
mch.pdu[i].lcid = srslte::sch_subh::MCH_SCHED_INFO;
|
|
|
|
mch.pdu[i].lcid = srslte::sch_subh::MCH_SCHED_INFO;
|
|
|
|
// mch.mtch_sched[i].lcid = 1+i;
|
|
|
|
// mch.mtch_sched[i].lcid = 1+i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
mch.pdu[mch.num_mtch_sched].lcid = 0;
|
|
|
|
mch.pdu[mch.num_mtch_sched].lcid = 0;
|
|
|
|
mch.pdu[mch.num_mtch_sched].nbytes = current_mcch_length;
|
|
|
|
mch.pdu[mch.num_mtch_sched].nbytes = current_mcch_length;
|
|
|
|
dl_sched_res->sched_grants[0].rnti = SRSLTE_MRNTI;
|
|
|
|
dl_sched_res->sched_grants[0].rnti = SRSLTE_MRNTI;
|
|
|
|
dl_sched_res->sched_grants[0].data[0] = ue_db[SRSLTE_MRNTI]->generate_mch_pdu(mch, mch.num_mtch_sched + 1, mcs.tbs/8);
|
|
|
|
dl_sched_res->sched_grants[0].data[0] = ue_db[SRSLTE_MRNTI]->generate_mch_pdu(mch, mch.num_mtch_sched + 1, mcs.tbs/8);
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
uint32_t current_lcid = 1;
|
|
|
|
uint32_t current_lcid = 1;
|
|
|
|
uint32_t mtch_index = 0;
|
|
|
|
uint32_t mtch_index = 0;
|
|
|
|
uint32_t mtch_stop = mch.mtch_sched[mch.num_mtch_sched -1].stop;
|
|
|
|
uint32_t mtch_stop = mch.mtch_sched[mch.num_mtch_sched -1].stop;
|
|
|
|
|
|
|
|
|
|
|
|
for(uint32_t i = 0;i < mch.num_mtch_sched;i++) {
|
|
|
|
for(uint32_t i = 0;i < mch.num_mtch_sched;i++) {
|
|
|
|
if(mch.current_sf_allocation_num <= mch.mtch_sched[i].stop){
|
|
|
|
if(mch.current_sf_allocation_num <= mch.mtch_sched[i].stop){
|
|
|
|
current_lcid = mch.mtch_sched[i].lcid;
|
|
|
|
current_lcid = mch.mtch_sched[i].lcid;
|
|
|
@ -669,9 +741,9 @@ int mac::get_mch_sched(bool is_mcch, dl_sched_t *dl_sched_res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mch.current_sf_allocation_num++;
|
|
|
|
mch.current_sf_allocation_num++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t* mac::assemble_rar(sched_interface::dl_sched_rar_grant_t* grants, uint32_t nof_grants, int rar_idx, uint32_t pdu_len)
|
|
|
|
uint8_t* mac::assemble_rar(sched_interface::dl_sched_rar_grant_t* grants, uint32_t nof_grants, int rar_idx, uint32_t pdu_len)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -684,10 +756,10 @@ uint8_t* mac::assemble_rar(sched_interface::dl_sched_rar_grant_t* grants, uint32
|
|
|
|
if (pdu->new_subh()) {
|
|
|
|
if (pdu->new_subh()) {
|
|
|
|
/* Search pending RAR */
|
|
|
|
/* Search pending RAR */
|
|
|
|
int idx = grants[i].ra_id;
|
|
|
|
int idx = grants[i].ra_id;
|
|
|
|
pdu->get()->set_rapid(pending_rars[idx].preamble_idx);
|
|
|
|
pdu->get()->set_rapid(pending_rars[idx].preamble_idx);
|
|
|
|
pdu->get()->set_ta_cmd(pending_rars[idx].ta_cmd);
|
|
|
|
pdu->get()->set_ta_cmd(pending_rars[idx].ta_cmd);
|
|
|
|
pdu->get()->set_temp_crnti(pending_rars[idx].temp_crnti);
|
|
|
|
pdu->get()->set_temp_crnti(pending_rars[idx].temp_crnti);
|
|
|
|
pdu->get()->set_sched_grant(grant_buffer);
|
|
|
|
pdu->get()->set_sched_grant(grant_buffer);
|
|
|
|
bzero(&pending_rars[idx], sizeof(pending_rar_t));
|
|
|
|
bzero(&pending_rars[idx], sizeof(pending_rar_t));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -695,76 +767,85 @@ uint8_t* mac::assemble_rar(sched_interface::dl_sched_rar_grant_t* grants, uint32
|
|
|
|
return rar_payload[rar_idx];
|
|
|
|
return rar_payload[rar_idx];
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Error("Assembling RAR: pdu_len > rar_payload_len (%d>%d)\n", pdu_len, rar_payload_len);
|
|
|
|
Error("Assembling RAR: pdu_len > rar_payload_len (%d>%d)\n", pdu_len, rar_payload_len);
|
|
|
|
return NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t* mac::assemble_si(uint32_t index)
|
|
|
|
uint8_t* mac::assemble_si(uint32_t index)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
rlc_h->read_pdu_bcch_dlsch(index, bcch_dlsch_payload);
|
|
|
|
rlc_h->read_pdu_bcch_dlsch(index, bcch_dlsch_payload);
|
|
|
|
return bcch_dlsch_payload;
|
|
|
|
return bcch_dlsch_payload;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int mac::get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res)
|
|
|
|
int mac::get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
log_h->step(tti);
|
|
|
|
log_h->step(tti);
|
|
|
|
|
|
|
|
|
|
|
|
if (!started) {
|
|
|
|
if (!started) {
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!ul_sched_res) {
|
|
|
|
if (!ul_sched_res) {
|
|
|
|
return SRSLTE_ERROR_INVALID_INPUTS;
|
|
|
|
return SRSLTE_ERROR_INVALID_INPUTS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Run scheduler with current info
|
|
|
|
// Run scheduler with current info
|
|
|
|
sched_interface::ul_sched_res_t sched_result;
|
|
|
|
sched_interface::ul_sched_res_t sched_result;
|
|
|
|
bzero(&sched_result, sizeof(sched_interface::ul_sched_res_t));
|
|
|
|
bzero(&sched_result, sizeof(sched_interface::ul_sched_res_t));
|
|
|
|
if (scheduler.ul_sched(tti, &sched_result)<0) {
|
|
|
|
if (scheduler.ul_sched(tti, &sched_result)<0) {
|
|
|
|
Error("Running scheduler\n");
|
|
|
|
Error("Running scheduler\n");
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Copy DCI grants
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
ul_sched_res->nof_grants = 0;
|
|
|
|
|
|
|
|
int n = 0;
|
|
|
|
// Copy DCI grants
|
|
|
|
|
|
|
|
ul_sched_res->nof_grants = 0;
|
|
|
|
|
|
|
|
int n = 0;
|
|
|
|
for (uint32_t i=0;i<sched_result.nof_dci_elems;i++) {
|
|
|
|
for (uint32_t i=0;i<sched_result.nof_dci_elems;i++) {
|
|
|
|
|
|
|
|
|
|
|
|
if (sched_result.pusch[i].tbs > 0) {
|
|
|
|
if (sched_result.pusch[i].tbs > 0) {
|
|
|
|
// Get UE
|
|
|
|
// Get UE
|
|
|
|
uint16_t rnti = sched_result.pusch[i].rnti;
|
|
|
|
uint16_t rnti = sched_result.pusch[i].rnti;
|
|
|
|
|
|
|
|
|
|
|
|
// Copy grant info
|
|
|
|
if (ue_db.count(rnti)) {
|
|
|
|
ul_sched_res->sched_grants[n].rnti = rnti;
|
|
|
|
// Copy grant info
|
|
|
|
ul_sched_res->sched_grants[n].current_tx_nb = sched_result.pusch[i].current_tx_nb;
|
|
|
|
ul_sched_res->sched_grants[n].rnti = rnti;
|
|
|
|
ul_sched_res->sched_grants[n].needs_pdcch = sched_result.pusch[i].needs_pdcch;
|
|
|
|
ul_sched_res->sched_grants[n].current_tx_nb = sched_result.pusch[i].current_tx_nb;
|
|
|
|
memcpy(&ul_sched_res->sched_grants[n].grant, &sched_result.pusch[i].dci, sizeof(srslte_ra_ul_dci_t));
|
|
|
|
ul_sched_res->sched_grants[n].needs_pdcch = sched_result.pusch[i].needs_pdcch;
|
|
|
|
memcpy(&ul_sched_res->sched_grants[n].location, &sched_result.pusch[i].dci_location, sizeof(srslte_dci_location_t));
|
|
|
|
memcpy(&ul_sched_res->sched_grants[n].grant, &sched_result.pusch[i].dci, sizeof(srslte_ra_ul_dci_t));
|
|
|
|
|
|
|
|
memcpy(&ul_sched_res->sched_grants[n].location, &sched_result.pusch[i].dci_location, sizeof(srslte_dci_location_t));
|
|
|
|
ul_sched_res->sched_grants[n].softbuffer = ue_db[rnti]->get_rx_softbuffer(tti);
|
|
|
|
|
|
|
|
|
|
|
|
ul_sched_res->sched_grants[n].softbuffer = ue_db[rnti]->get_rx_softbuffer(tti);
|
|
|
|
if (sched_result.pusch[n].current_tx_nb == 0) {
|
|
|
|
|
|
|
|
srslte_softbuffer_rx_reset_tbs(ul_sched_res->sched_grants[n].softbuffer, sched_result.pusch[i].tbs*8);
|
|
|
|
if (sched_result.pusch[n].current_tx_nb == 0) {
|
|
|
|
|
|
|
|
srslte_softbuffer_rx_reset_tbs(ul_sched_res->sched_grants[n].softbuffer, sched_result.pusch[i].tbs*8);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ul_sched_res->sched_grants[n].data = ue_db[rnti]->request_buffer(tti, sched_result.pusch[i].tbs);
|
|
|
|
|
|
|
|
ul_sched_res->nof_grants++;
|
|
|
|
|
|
|
|
n++;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
Warning("Invalid DL scheduling result. User 0x%x does not exist\n", rnti);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ul_sched_res->sched_grants[n].data = ue_db[rnti]->request_buffer(tti, sched_result.pusch[i].tbs);
|
|
|
|
|
|
|
|
ul_sched_res->nof_grants++;
|
|
|
|
|
|
|
|
n++;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Warning("Grant %d for rnti=0x%x has zero TBS\n", i, sched_result.pusch[i].rnti);
|
|
|
|
Warning("Grant %d for rnti=0x%x has zero TBS\n", i, sched_result.pusch[i].rnti);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// No more uses of ue_db beyond here
|
|
|
|
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
|
|
|
|
// Copy PHICH actions
|
|
|
|
// Copy PHICH actions
|
|
|
|
for (uint32_t i=0;i<sched_result.nof_phich_elems;i++) {
|
|
|
|
for (uint32_t i=0;i<sched_result.nof_phich_elems;i++) {
|
|
|
|
ul_sched_res->phich[i].ack = sched_result.phich[i].phich == sched_interface::ul_sched_phich_t::ACK;
|
|
|
|
ul_sched_res->phich[i].ack = sched_result.phich[i].phich == sched_interface::ul_sched_phich_t::ACK;
|
|
|
|
ul_sched_res->phich[i].rnti = sched_result.phich[i].rnti;
|
|
|
|
ul_sched_res->phich[i].rnti = sched_result.phich[i].rnti;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ul_sched_res->nof_phich = sched_result.nof_phich_elems;
|
|
|
|
ul_sched_res->nof_phich = sched_result.nof_phich_elems;
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void mac::tti_clock()
|
|
|
|
void mac::tti_clock()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
timers_thread.tti_clock();
|
|
|
|
timers_thread.tti_clock();
|
|
|
@ -799,7 +880,7 @@ srslte::timers::timer* mac::timer_get(uint32_t timer_id)
|
|
|
|
*******************************************************/
|
|
|
|
*******************************************************/
|
|
|
|
void mac::timer_thread::run_thread()
|
|
|
|
void mac::timer_thread::run_thread()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
running=true;
|
|
|
|
running=true;
|
|
|
|
ttisync.set_producer_cntr(0);
|
|
|
|
ttisync.set_producer_cntr(0);
|
|
|
|
ttisync.resync();
|
|
|
|
ttisync.resync();
|
|
|
|
while(running) {
|
|
|
|
while(running) {
|
|
|
@ -829,34 +910,34 @@ void mac::timer_thread::tti_clock()
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*******************************************************/
|
|
|
|
*******************************************************/
|
|
|
|
mac::pdu_process::pdu_process(pdu_process_handler *h) : running(false) {
|
|
|
|
mac::pdu_process::pdu_process(pdu_process_handler *h) : running(false) {
|
|
|
|
handler = h;
|
|
|
|
handler = h;
|
|
|
|
pthread_mutex_init(&mutex, NULL);
|
|
|
|
pthread_mutex_init(&mutex, NULL);
|
|
|
|
pthread_cond_init(&cvar, NULL);
|
|
|
|
pthread_cond_init(&cvar, NULL);
|
|
|
|
have_data = false;
|
|
|
|
have_data = false;
|
|
|
|
start(MAC_PDU_THREAD_PRIO);
|
|
|
|
start(MAC_PDU_THREAD_PRIO);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void mac::pdu_process::stop()
|
|
|
|
void mac::pdu_process::stop()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
pthread_mutex_lock(&mutex);
|
|
|
|
pthread_mutex_lock(&mutex);
|
|
|
|
running = false;
|
|
|
|
running = false;
|
|
|
|
pthread_cond_signal(&cvar);
|
|
|
|
pthread_cond_signal(&cvar);
|
|
|
|
pthread_mutex_unlock(&mutex);
|
|
|
|
pthread_mutex_unlock(&mutex);
|
|
|
|
|
|
|
|
|
|
|
|
wait_thread_finish();
|
|
|
|
wait_thread_finish();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void mac::pdu_process::notify()
|
|
|
|
void mac::pdu_process::notify()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
pthread_mutex_lock(&mutex);
|
|
|
|
pthread_mutex_lock(&mutex);
|
|
|
|
have_data = true;
|
|
|
|
have_data = true;
|
|
|
|
pthread_cond_signal(&cvar);
|
|
|
|
pthread_cond_signal(&cvar);
|
|
|
|
pthread_mutex_unlock(&mutex);
|
|
|
|
pthread_mutex_unlock(&mutex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void mac::pdu_process::run_thread()
|
|
|
|
void mac::pdu_process::run_thread()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
running = true;
|
|
|
|
running = true;
|
|
|
|
while(running) {
|
|
|
|
while(running) {
|
|
|
|
have_data = handler->process_pdus();
|
|
|
|
have_data = handler->process_pdus();
|
|
|
|
if (!have_data) {
|
|
|
|
if (!have_data) {
|
|
|
@ -871,13 +952,15 @@ void mac::pdu_process::run_thread()
|
|
|
|
|
|
|
|
|
|
|
|
bool mac::process_pdus()
|
|
|
|
bool mac::process_pdus()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
bool ret = false;
|
|
|
|
pthread_rwlock_rdlock(&rwlock);
|
|
|
|
|
|
|
|
bool ret = false;
|
|
|
|
for(std::map<uint16_t, ue*>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
|
|
|
|
for(std::map<uint16_t, ue*>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
|
|
|
|
ue *u = iter->second;
|
|
|
|
ue *u = iter->second;
|
|
|
|
uint16_t rnti = iter->first;
|
|
|
|
uint16_t rnti = iter->first;
|
|
|
|
ret = ret | u->process_pdus();
|
|
|
|
ret = ret | u->process_pdus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
pthread_rwlock_unlock(&rwlock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|