eNB_agent_scheduler_dlsch_ue_remote.c 4.81 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
/*******************************************************************************
    OpenAirInterface
    Copyright(c) 1999 - 2014 Eurecom

    OpenAirInterface is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.


    OpenAirInterface 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with OpenAirInterface.The full GNU General Public License is
    included in this distribution in the file called "COPYING". If not,
    see <http://www.gnu.org/licenses/>.

  Contact Information
  OpenAirInterface Admin: openair_admin@eurecom.fr
  OpenAirInterface Tech : openair_tech@eurecom.fr
  OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr

  Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE

*******************************************************************************/

/*! \file eNB_agent_scheduler_dlsch_ue_remote.c
 * \brief procedures related to remote scheduling in the DLSCH transport channel
 * \author Xenofon Foukas
 * \date 2016
 * \email: x.foukas@sms.ed.ac.uk
 * \version 0.1
 * @ingroup _mac

 */

#include "eNB_agent_scheduler_dlsch_ue_remote.h"

struct DlMacConfigHead queue_head;

int queue_initialized = 0;

void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe,
			     int *mbsfn_flag, Protocol__ProgranMessage **dl_info) {

  if (queue_initialized) {
    TAILQ_INIT(&queue_head);
    queue_initialized = 1;
  }

  dl_mac_config_element_t *dl_config_elem;

  int diff;
  
  // First we check to see if we have a scheduling decision for this sfn_sf already in our queue
  while(queue_head.tqh_first != NULL) {
    dl_config_elem = queue_head.tqh_first;
    diff = get_sf_difference(mod_id, dl_config_elem->dl_info->dl_mac_config_msg->sfn_sf);
    // Check if this decision is for now, for a later or a previous subframe
    if ( diff == 0) { // Now
      TAILQ_REMOVE(&queue_head, queue_head.tqh_first, configs);
      *dl_info = dl_config_elem->dl_info;
      free(dl_config_elem);
      return;
    } else if (diff < 0) { //previous subframe , delete message and free memory
      TAILQ_REMOVE(&queue_head, queue_head.tqh_first, configs);
      enb_agent_mac_destroy_dl_config(dl_config_elem->dl_info);
      free(dl_config_elem);
    } else { // next subframe, nothing to do now
      enb_agent_create_empty_dl_config(mod_id, dl_info);
      return;
    }
  }

  //Done with the local cache. Now we need to check if something new arrived
  enb_agent_get_pending_dl_mac_config(mod_id, dl_info);
  while (*dl_info != NULL) {

    diff = get_sf_difference(mod_id, (*dl_info)->dl_mac_config_msg->sfn_sf);
    if (diff == 0) { // Got a command for this sfn_sf
      return;
    } else if (diff < 0) {
      enb_agent_mac_destroy_dl_config(*dl_info);
    } else { // Intended for future subframe. Store it in local cache
      dl_mac_config_element_t *e = malloc(sizeof(dl_mac_config_element_t));
      TAILQ_INSERT_TAIL(&queue_head, e, configs);
      enb_agent_create_empty_dl_config(mod_id, dl_info);
      // No need to look for another. Messages arrive ordered
      return;
    }
    enb_agent_get_pending_dl_mac_config(mod_id, dl_info);
  }
  
  // We found no pending command, so we will simply pass an empty one
  enb_agent_create_empty_dl_config(mod_id, dl_info);
}

int get_sf_difference(mid_t mod_id, uint16_t sfn_sf) {
  int diff_in_subframes;
  
  uint16_t current_frame = get_current_system_frame_num(mod_id);
  uint16_t current_subframe = get_current_subframe(mod_id);
  uint16_t current_sfn_sf = get_sfn_sf(mod_id);
  
  if (sfn_sf == current_sfn_sf) {
    return 0;
  }
  
  uint16_t frame_mask = !((1<<4) - 1);
  uint16_t frame = (sfn_sf & frame_mask) >> 4;
  
  uint16_t sf_mask = !(((1<<12) - 1) << 4);
  uint16_t subframe = (sfn_sf & sf_mask);
  
  if (frame == current_frame) {
    return subframe - current_subframe;
  } else if (frame > current_frame) {
    diff_in_subframes = 9 - current_subframe;
    diff_in_subframes += subframe;
    diff_in_subframes += (frame-2) * 10;
    if (diff_in_subframes > SCHED_AHEAD_SUBFRAMES) {
      return -1;
    } else {
      return 1;
    }
  } else { //frame < current_frame
    diff_in_subframes = 9 - current_subframe;
    diff_in_subframes += subframe;
    if (frame > 0) {
      diff_in_subframes += (frame - 1) * 10;
    }
    diff_in_subframes += (1023 - current_frame) * 10;
    if (diff_in_subframes > SCHED_AHEAD_SUBFRAMES) {
      return -1;
    } else {
      return 1;
    }
  }
}