eNB_scheduler_mch.c 27.6 KB
Newer Older
1
/*! \file eNB_scheduler_mch.c
2
 * \brief procedures related to eNB for the MCH transport channel
3 4 5
 * \author  Navid Nikaein and Raymond Knopp
 * \date 2012 - 2014
 * \email: navid.nikaein@eurecom.fr
6
 * \version 1.0
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
 * @ingroup _mac

 */

#include "assertions.h"
#include "PHY/defs.h"
#include "PHY/extern.h"

#include "SCHED/defs.h"
#include "SCHED/extern.h"

#include "LAYER2/MAC/defs.h"
#include "LAYER2/MAC/proto.h"
#include "LAYER2/MAC/extern.h"
#include "UTIL/LOG/log.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h"
#include "OCG.h"
#include "OCG_extern.h"

#include "RRC/LITE/extern.h"
#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"

//#include "LAYER2/MAC/pre_processor.c"
#include "pdcp.h"

#if defined(ENABLE_ITTI)
# include "intertask_interface.h"
#endif

37 38
#include "SIMULATION/TOOLS/defs.h" // for taus

39 40 41 42 43
#define ENABLE_MAC_PAYLOAD_DEBUG
#define DEBUG_eNB_SCHEDULER 1


#ifdef Rel10
44 45
int8_t get_mbsfn_sf_alloction (module_id_t module_idP, uint8_t CC_id, uint8_t mbsfn_sync_area)
{
46
  // currently there is one-to-one mapping between sf allocation pattern and sync area
47
  if (mbsfn_sync_area > MAX_MBSFN_AREA) {
48
    LOG_W(MAC,"[eNB %d] CC_id %d MBSFN synchronization area %d out of range\n ", module_idP, CC_id, mbsfn_sync_area);
49
    return -1;
50
  } else if (eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[mbsfn_sync_area] != NULL) {
51
    return mbsfn_sync_area;
52
  } else {
53
    LOG_W(MAC,"[eNB %d] CC_id %d MBSFN Subframe Config pattern %d not found \n ", module_idP, CC_id, mbsfn_sync_area);
54
    return -1;
55 56 57
  }
}

58 59
int schedule_MBMS(module_id_t module_idP, uint8_t CC_id, frame_t frameP, sub_frame_t subframeP)
{
60 61 62 63

  int mcch_flag=0,mtch_flag=0, msi_flag=0;
  int mbsfn_period =0;// 1<<(eNB_mac_inst[module_idP].mbsfn_SubframeConfig[0]->radioframeAllocationPeriod);
  int mcch_period = 0;//32<<(eNB_mac_inst[module_idP].mbsfn_AreaInfo[0]->mcch_Config_r9.mcch_RepetitionPeriod_r9);
64
  int mch_scheduling_period = 8<<(eNB_mac_inst[module_idP].common_channels[CC_id].pmch_Config[0]->mch_SchedulingPeriod_r9);
65 66 67 68 69 70 71 72 73 74 75 76
  unsigned char mcch_sdu_length;
  unsigned char header_len_mcch=0,header_len_msi=0,header_len_mtch=0, header_len_mtch_temp=0, header_len_mcch_temp=0, header_len_msi_temp=0;
  int ii=0, msi_pos=0;
  int mcch_mcs = -1;
  uint16_t TBS,j,padding=0,post_padding=0;
  mac_rlc_status_resp_t rlc_status;
  int num_mtch;
  int msi_length,i,k;
  unsigned char sdu_lcids[11], num_sdus=0, offset=0;
  uint16_t sdu_lengths[11], sdu_length_total=0;
  unsigned char mch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; // check the max value, this is for dlsch only

77
  eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.Pdu_size=0;
78 79

  for (i=0;
80 81 82
       i< eNB_mac_inst[module_idP].common_channels[CC_id].num_active_mbsfn_area;
       i++ ) {
    // assume, that there is always a mapping
83
    if ((j=get_mbsfn_sf_alloction(module_idP,CC_id,i)) == -1) {
84
      return 0;
85
    }
86

87 88 89 90
    mbsfn_period = 1<<(eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[j]->radioframeAllocationPeriod);
    mcch_period = 32<<(eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_RepetitionPeriod_r9);
    msi_pos=0;
    ii=0;
91 92
    LOG_D(MAC,"[eNB %d] CC_id %d Frame %d subframeP %d : Checking MBSFN Sync Area %d/%d with SF allocation %d/%d for MCCH and MTCH (mbsfn period %d, mcch period %d)\n",
          module_idP, CC_id, frameP, subframeP,i,eNB_mac_inst[module_idP].common_channels[CC_id].num_active_mbsfn_area,
93
          j,eNB_mac_inst[module_idP].common_channels[CC_id].num_sf_allocation_pattern,mbsfn_period,mcch_period);
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
    switch (eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.signallingMCS_r9) {
    case 0:
      mcch_mcs = 2;
      break;

    case 1:
      mcch_mcs = 7;
      break;

    case 2:
      mcch_mcs = 13;
      break;

    case 3:
      mcch_mcs = 19;
      break;
    }

    // 1st: Check the MBSFN subframes from SIB2 info (SF allocation pattern i, max 8 non-overlapping patterns exist)
    if (frameP %  mbsfn_period == eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[j]->radioframeAllocationOffset) { // MBSFN frameP
      if (eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[j]->subframeAllocation.present == MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) { // one-frameP format

        //  Find the first subframeP in this MCH to transmit MSI
        if (frameP % mch_scheduling_period == eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[j]->radioframeAllocationOffset ) {
          while (ii == 0) {
            ii = eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & (0x80>>msi_pos);
            msi_pos++;
          }

125 126
          LOG_D(MAC,"[eNB %d] CC_id %d Frame %d subframeP %d : sync area %d sf allocation pattern %d sf alloc %x msi pos is %d \n",
                module_idP, CC_id, frameP, subframeP,i,j,
127 128 129 130 131 132
                eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0], msi_pos);
        }

        // Check if the subframeP is for MSI, MCCH or MTCHs and Set the correspoding flag to 1
        switch (subframeP) {
        case 1:
133
          if (mac_xface->frame_parms->frame_type == FDD) {
134
            if ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF1) == MBSFN_FDD_SF1) {
135
              if (msi_pos == 1) {
136
                msi_flag = 1;
137
              }
138 139

              if ( (frameP % mcch_period == eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
140
                   ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF1) == MBSFN_FDD_SF1) ) {
141
                mcch_flag = 1;
142
              }
143 144 145 146 147 148 149 150

              mtch_flag = 1;
            }
          }

          break;

        case 2:
151
          if (mac_xface->frame_parms->frame_type == FDD) {
152
            if ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF2) == MBSFN_FDD_SF2) {
153
              if (msi_pos == 2) {
154
                msi_flag = 1;
155
              }
156 157

              if ( (frameP % mcch_period == eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
158
                   ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF2) == MBSFN_FDD_SF2) ) {
159
                mcch_flag = 1;
160
              }
161

162 163
              mtch_flag = 1;
            }
164
          }
165 166 167 168

          break;

        case 3:
169
          if (mac_xface->frame_parms->frame_type == TDD) { // TDD
170
            if ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF3) == MBSFN_TDD_SF3) {
171
              if (msi_pos == 1) {
172
                msi_flag = 1;
173
              }
174 175

              if ( (frameP % mcch_period == eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
176
                   ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF3) == MBSFN_TDD_SF3) ) {
177
                mcch_flag = 1;
178
              }
179 180 181 182 183

              mtch_flag = 1;
            }
          } else { // FDD
            if ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF3) == MBSFN_FDD_SF3) {
184
              if (msi_pos == 3) {
185
                msi_flag = 1;
186
              }
187 188

              if ( (frameP % mcch_period == eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
189
                   ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF3) == MBSFN_FDD_SF3) ) {
190
                mcch_flag = 1;
191
              }
192 193 194 195 196 197 198 199

              mtch_flag = 1;
            }
          }

          break;

        case 4:
200
          if (mac_xface->frame_parms->frame_type == TDD) {
201
            if ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF4) == MBSFN_TDD_SF4) {
202
              if (msi_pos == 2) {
203
                msi_flag = 1;
204
              }
205 206

              if ( (frameP % mcch_period == eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
207
                   ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF4) == MBSFN_TDD_SF4) ) {
208
                mcch_flag = 1;
209
              }
210 211 212 213 214 215 216 217

              mtch_flag = 1;
            }
          }

          break;

        case 6:
218
          if (mac_xface->frame_parms->frame_type == FDD) {
219
            if ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF6) == MBSFN_FDD_SF6) {
220
              if (msi_pos == 4) {
221
                msi_flag = 1;
222
              }
223 224

              if ( (frameP % mcch_period == eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
225
                   ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF6) == MBSFN_FDD_SF6) ) {
226
                mcch_flag = 1;
227
              }
228 229 230 231 232 233 234 235

              mtch_flag = 1;
            }
          }

          break;

        case 7:
236
          if (mac_xface->frame_parms->frame_type == TDD) { // TDD
237
            if ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF7) == MBSFN_TDD_SF7) {
238
              if (msi_pos == 3) {
239
                msi_flag = 1;
240
              }
241 242

              if ( (frameP % mcch_period == eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
243
                   ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF7) == MBSFN_TDD_SF7) ) {
244
                mcch_flag = 1;
245
              }
246 247 248 249 250

              mtch_flag = 1;
            }
          } else { // FDD
            if ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF7) == MBSFN_FDD_SF7) {
251
              if (msi_pos == 5) {
252
                msi_flag = 1;
253
              }
254 255

              if ( (frameP % mcch_period == eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
256
                   ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF7) == MBSFN_FDD_SF7) ) {
257
                mcch_flag = 1;
258
              }
259 260 261 262 263 264 265 266

              mtch_flag = 1;
            }
          }

          break;

        case 8:
267
          if (mac_xface->frame_parms->frame_type == TDD) { //TDD
268
            if ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF8) == MBSFN_TDD_SF8) {
269
              if (msi_pos == 4) {
270
                msi_flag = 1;
271
              }
272 273

              if ( (frameP % mcch_period == eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
274
                   ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF8) == MBSFN_TDD_SF8) ) {
275
                mcch_flag = 1;
276
              }
277 278 279 280 281

              mtch_flag = 1;
            }
          } else { // FDD
            if ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF8) == MBSFN_FDD_SF8) {
282
              if (msi_pos == 6) {
283
                msi_flag = 1;
284
              }
285 286

              if ( (frameP % mcch_period == eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
287
                   ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF8) == MBSFN_FDD_SF8) ) {
288
                mcch_flag = 1;
289
              }
290 291 292 293 294 295 296 297

              mtch_flag = 1;
            }
          }

          break;

        case 9:
298
          if (mac_xface->frame_parms->frame_type == TDD) {
299
            if ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF9) == MBSFN_TDD_SF9) {
300
              if (msi_pos == 5) {
301
                msi_flag = 1;
302
              }
303 304

              if ( (frameP % mcch_period == eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
305
                   ((eNB_mac_inst[module_idP].common_channels[CC_id].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF9) == MBSFN_TDD_SF9) ) {
306
                mcch_flag = 1;
307
              }
308 309 310

              mtch_flag = 1;
            }
311
          }
312 313 314 315 316 317

          break;
        }// end switch

        // sf allocation is non-overlapping
        if ((msi_flag==1) || (mcch_flag==1) || (mtch_flag==1)) {
318 319
          LOG_D(MAC,"[eNB %d] CC_id %d Frame %d Subframe %d: sync area %d SF alloc %d: msi flag %d, mcch flag %d, mtch flag %d\n",
                module_idP, CC_id, frameP, subframeP,i,j,msi_flag,mcch_flag,mtch_flag);
320 321 322
          break;
        }
      } else { // four-frameP format
323
      }
324
    }
325
  } // end of for loop
326

327 328 329
  eNB_mac_inst[module_idP].common_channels[CC_id].msi_active=0;
  eNB_mac_inst[module_idP].common_channels[CC_id].mcch_active=0;
  eNB_mac_inst[module_idP].common_channels[CC_id].mtch_active=0;
330

331 332
  // Calculate the mcs
  if ((msi_flag==1) || (mcch_flag==1)) {
333 334 335
    eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.mcs = mcch_mcs;
  } else if (mtch_flag == 1) { // only MTCH in this subframeP
    eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.mcs = eNB_mac_inst[module_idP].common_channels[CC_id].pmch_Config[0]->dataMCS_r9;
336 337 338 339 340 341 342
  }


  // 2nd: Create MSI, get MCCH from RRC and MTCHs from RLC

  // there is MSI (MCH Scheduling Info)
  if (msi_flag == 1) {
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
    // Create MSI here
    uint16_t msi_control_element[29], *msi_ptr;

    msi_ptr = &msi_control_element[0];
    ((MSI_ELEMENT *) msi_ptr)->lcid = MCCH_LCHANID; //MCCH

    if (mcch_flag==1) {
      ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0;
      ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0;
    } else {                  // no mcch for this MSP
      ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0x7;// stop value is 2047
      ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0xff;
    }

    msi_ptr+= sizeof(MSI_ELEMENT);

    //Header for MTCHs
    num_mtch = eNB_mac_inst[module_idP].common_channels[CC_id].mbms_SessionList[0]->list.count;

    for (k=0; k<num_mtch; k++) { // loop for all session in this MCH (MCH[0]) at this moment
      ((MSI_ELEMENT *) msi_ptr)->lcid = eNB_mac_inst[module_idP].common_channels[CC_id].mbms_SessionList[0]->list.array[k]->logicalChannelIdentity_r9;//mtch_lcid;
      ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0; // last subframeP of this mtch (only one mtch now)
      ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0xB;
      msi_ptr+=sizeof(MSI_ELEMENT);
    }

    msi_length = msi_ptr-msi_control_element;

371
    if (msi_length<128) {
372
      header_len_msi = 2;
373
    } else {
374
      header_len_msi = 3;
375
    }
376

377 378
    LOG_D(MAC,"[eNB %d] CC_id %d Frame %d : MSI->MCH, length of MSI is %d bytes \n",
          module_idP,CC_id,frameP,msi_length);
379 380 381 382 383 384 385 386 387 388 389
    //LOG_D(MAC,"Scheduler: MSI is transmitted in this subframeP \n" );

    //   LOG_D(MAC,"Scheduler: MSI length is %d bytes\n",msi_length);
    // Store MSI data to mch_buffer[0]
    memcpy((char *)&mch_buffer[sdu_length_total],
           msi_control_element,
           msi_length);

    sdu_lcids[num_sdus] = MCH_SCHDL_INFO;
    sdu_lengths[num_sdus] = msi_length;
    sdu_length_total += sdu_lengths[num_sdus];
390
    LOG_I(MAC,"[eNB %d] CC_id %d Create %d bytes for MSI\n", module_idP, CC_id, sdu_lengths[num_sdus]);
391 392
    num_sdus++;
    eNB_mac_inst[module_idP].common_channels[CC_id].msi_active=1;
393 394 395 396
  }

  // there is MCCH
  if (mcch_flag == 1) {
397 398
    LOG_D(MAC,"[eNB %d] CC_id %d Frame %d Subframe %d: Schedule MCCH MESSAGE (area %d, sfAlloc %d)\n",
          module_idP, CC_id, frameP, subframeP, i, j);
399

400
    mcch_sdu_length = mac_rrc_data_req(module_idP,
401
                                       CC_id,
402 403 404 405 406 407
                                       frameP,
                                       MCCH,1,
                                       &eNB_mac_inst[module_idP].common_channels[CC_id].MCCH_pdu.payload[0],
                                       1,// this is eNB
                                       module_idP, // index
                                       i); // this is the mbsfn sync area index
408

409
    if (mcch_sdu_length > 0) {
410 411
      LOG_D(MAC,"[eNB %d] CC_id %d Frame %d subframeP %d : MCCH->MCH, Received %d bytes from RRC \n",
            module_idP,CC_id,frameP,subframeP,mcch_sdu_length);
412

413 414
      header_len_mcch = 2;

415
      if (mac_xface->frame_parms->frame_type == TDD) {
416 417
        LOG_D(MAC,"[eNB %d] CC_id %d Frame %d subframeP %d: Scheduling MCCH->MCH (TDD) for MCCH message %d bytes (mcs %d )\n",
              module_idP, CC_id,
418 419 420 421
              frameP,subframeP,
              mcch_sdu_length,
              mcch_mcs);
      } else {
422 423
        LOG_I(MAC,"[eNB %d] CC_id %d Frame %d subframeP %d: Scheduling MCCH->MCH (FDD) for MCCH message %d bytes (mcs %d)\n",
              module_idP, CC_id,
424 425 426
              frameP, subframeP,
              mcch_sdu_length,
              mcch_mcs);
427
      }
428 429 430 431 432 433 434 435 436

      eNB_mac_inst[module_idP].common_channels[CC_id].mcch_active=1;

      memcpy((char *)&mch_buffer[sdu_length_total],
             &eNB_mac_inst[module_idP].common_channels[CC_id].MCCH_pdu.payload[0],
             mcch_sdu_length);
      sdu_lcids[num_sdus] = MCCH_LCHANID;
      sdu_lengths[num_sdus] = mcch_sdu_length;

437
      if (sdu_lengths[num_sdus]>128) {
438
        header_len_mcch = 3;
439
      }
440 441

      sdu_length_total += sdu_lengths[num_sdus];
442
      LOG_D(MAC,"[eNB %d] CC_id %d Got %d bytes for MCCH from RRC \n",module_idP,CC_id,sdu_lengths[num_sdus]);
443 444
      num_sdus++;
    }
445
  }
446

447
  TBS = mac_xface->get_TBS_DL(eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.mcs, mac_xface->frame_parms->N_RB_DL);
448 449 450 451 452
#ifdef Rel10
  // do not let mcch and mtch multiplexing when relaying is active
  // for sync area 1, so not transmit data
  //if ((i == 0) && ((eNB_mac_inst[module_idP].MBMS_flag != multicast_relay) || (eNB_mac_inst[module_idP].mcch_active==0))) {
#endif
453

454 455
  // there is MTCHs, loop if there are more than 1
  if (mtch_flag == 1) {
456 457
    // Calculate TBS
    /* if ((msi_flag==1) || (mcch_flag==1)) {
458
     TBS = mac_xface->get_TBS(mcch_mcs, mac_xface->frame_parms->N_RB_DL);
459 460
     }
     else { // only MTCH in this subframeP
461
     TBS = mac_xface->get_TBS(eNB_mac_inst[module_idP].pmch_Config[0]->dataMCS_r9, mac_xface->frame_parms->N_RB_DL);
462
     }
463 464

    // get MTCH data from RLC (like for DTCH)
465
    LOG_D(MAC,"[eNB %d] CC_id %d Frame %d subframe %d: Schedule MTCH (area %d, sfAlloc %d)\n",Mod_id,CC_id,frame,subframe,i,j);
466 467

    header_len_mtch = 3;
468 469
    LOG_D(MAC,"[eNB %d], CC_id %d, Frame %d, MTCH->MCH, Checking RLC status (rab %d, tbs %d, len %d)\n",
    Mod_id,CC_id,frame,MTCH,TBS,
470
    TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch);
471 472

    rlc_status = mac_rlc_status_ind(Mod_id,frame,1,RLC_MBMS_YES,MTCH+ (maxDRB + 3) * MAX_MOBILES_PER_RG,
473
          TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch);
474 475
    printf("frame %d, subframe %d,  rlc_status.bytes_in_buffer is %d\n",frame,subframe, rlc_status.bytes_in_buffer);

476
     */
477

478
    // get MTCH data from RLC (like for DTCH)
479
    LOG_D(MAC,"[eNB %d] CC_id %d Frame %d subframeP %d: Schedule MTCH (area %d, sfAlloc %d)\n",module_idP,CC_id,frameP,subframeP,i,j);
480

481
    header_len_mtch = 3;
482 483
    LOG_D(MAC,"[eNB %d], CC_id %d, Frame %d, MTCH->MCH, Checking RLC status (rab %d, tbs %d, len %d)\n",
          module_idP,CC_id,frameP,MTCH,TBS,
484 485
          TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch);

486
    rlc_status = mac_rlc_status_ind(module_idP,0,frameP,module_idP,ENB_FLAG_YES,MBMS_FLAG_YES,MTCH,
487 488 489 490 491
                                    TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch);
    LOG_D(MAC,"e-MBMS log channel %u frameP %d, subframeP %d,  rlc_status.bytes_in_buffer is %d\n",
          MTCH,frameP,subframeP, rlc_status.bytes_in_buffer);

    if (rlc_status.bytes_in_buffer >0) {
492 493
      LOG_I(MAC,"[eNB %d][MBMS USER-PLANE], CC_id %d, Frame %d, MTCH->MCH, Requesting %d bytes from RLC (header len mtch %d)\n",
            module_idP,CC_id,frameP,TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch,header_len_mtch);
494 495 496 497

      sdu_lengths[num_sdus] = mac_rlc_data_req(
                                module_idP,
                                0,
498
				module_idP,
499 500 501 502 503 504
                                frameP,
                                ENB_FLAG_YES,
                                MBMS_FLAG_YES,
                                MTCH,
                                (char*)&mch_buffer[sdu_length_total]);
      //sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,frameP, MBMS_FLAG_NO,  MTCH+(MAX_NUM_RB*(NUMBER_OF_UE_MAX+1)), (char*)&mch_buffer[sdu_length_total]);
505
      LOG_I(MAC,"[eNB %d][MBMS USER-PLANE] CC_id %d Got %d bytes for MTCH %d\n",module_idP,CC_id,sdu_lengths[num_sdus],MTCH);
506 507 508
      eNB_mac_inst[module_idP].common_channels[CC_id].mtch_active=1;
      sdu_lcids[num_sdus] = MTCH;
      sdu_length_total += sdu_lengths[num_sdus];
509

510
      if (sdu_lengths[num_sdus] < 128) {
511
        header_len_mtch = 2;
512
      }
513

514 515 516 517
      num_sdus++;
    } else {
      header_len_mtch = 0;
    }
518
  }
519

520 521 522
#ifdef Rel10
  //  }
#endif
523

524 525
  // FINAL STEP: Prepare and multiplexe MSI, MCCH and MTCHs
  if ((sdu_length_total + header_len_msi + header_len_mcch + header_len_mtch) >0) {
526 527 528 529 530 531 532 533 534 535 536 537
    // Adjust the last subheader
    /*                                 if ((msi_flag==1) || (mcch_flag==1)) {
                                       eNB_mac_inst[module_idP].MCH_pdu.mcs = mcch_mcs;
                                        }
                                      else if (mtch_flag == 1) { // only MTCH in this subframeP
                                     eNB_mac_inst[module_idP].MCH_pdu.mcs = eNB_mac_inst[module_idP].pmch_Config[0]->dataMCS_r9;
                                        }
     */
    header_len_mtch_temp = header_len_mtch;
    header_len_mcch_temp = header_len_mcch;
    header_len_msi_temp = header_len_msi;

538
    if (header_len_mtch>0) {
539
      header_len_mtch=1;         // remove Length field in the  subheader for the last PDU
540
    } else if (header_len_mcch>0) {
541
      header_len_mcch=1;
542 543 544
    } else {
      header_len_msi=1;
    }
545 546 547 548 549

    // Calculate the padding
    if ((TBS - header_len_mtch - header_len_mcch - header_len_msi - sdu_length_total) < 0) {
      LOG_E(MAC,"Error in building MAC PDU, TBS %d < PDU %d \n",
            TBS, header_len_mtch + header_len_mcch + header_len_msi + sdu_length_total);
550
      return 0;
551 552 553 554 555 556
    } else if ((TBS - header_len_mtch - header_len_mcch - header_len_msi - sdu_length_total) <= 2) {
      padding = (TBS - header_len_mtch - header_len_mcch - header_len_msi - sdu_length_total);
      post_padding = 0;
    } else { // using post_padding, give back the Length field of subheader  for the last PDU
      padding = 0;

557
      if (header_len_mtch>0) {
558
        header_len_mtch = header_len_mtch_temp;
559
      } else if (header_len_mcch>0) {
560
        header_len_mcch = header_len_mcch_temp;
561 562 563
      } else {
        header_len_msi = header_len_msi_temp;
      }
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585

      post_padding = TBS - sdu_length_total - header_len_msi - header_len_mcch - header_len_mtch;
    }

    // Generate the MAC Header for MCH
    // here we use the function for DLSCH because DLSCH & MCH have the same Header structure
    offset = generate_dlsch_header((unsigned char*)eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.payload,
                                   num_sdus,
                                   sdu_lengths,
                                   sdu_lcids,
                                   255,    // no drx
                                   0,  // no timing advance
                                   NULL,  // no contention res id
                                   padding,
                                   post_padding);

    eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.Pdu_size=TBS;
    eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.sync_area=i;
    eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.msi_active= eNB_mac_inst[module_idP].common_channels[CC_id].msi_active;
    eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.mcch_active= eNB_mac_inst[module_idP].common_channels[CC_id].mcch_active;
    eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.mtch_active= eNB_mac_inst[module_idP].common_channels[CC_id].mtch_active;
    LOG_D(MAC," MCS for this sf is %d (mcch active %d, mtch active %d)\n", eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.mcs,
586
          eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.mcch_active,eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.mtch_active );
587
    LOG_I(MAC,
588 589
          "[eNB %d][MBMS USER-PLANE ] CC_id %d Generate header : sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,padding %d,post_padding %d (mcs %d, TBS %d), header MTCH %d, header MCCH %d, header MSI %d\n",
          module_idP,CC_id,sdu_length_total,num_sdus,sdu_lengths[0],sdu_lcids[0],offset,padding,post_padding,eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.mcs,TBS,
590
          header_len_mtch, header_len_mcch, header_len_msi);
591 592 593 594
    // copy SDU to mch_pdu after the MAC Header
    memcpy(&eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.payload[offset],mch_buffer,sdu_length_total);

    // filling remainder of MCH with random data if necessery
595
    for (j=0; j<(TBS-sdu_length_total-offset); j++) {
596
      eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.payload[offset+sdu_length_total+j] = (char)(taus()&0xff);
597
    }
598

599
    /* Tracing of PDU is done on UE side */
600
    if (opt_enabled ==1 ) {
601
      trace_pdu(1, (uint8_t *)eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.payload,
602 603
                TBS, module_idP, 6, 0xffff,  // M_RNTI = 6 in wirehsark
                eNB_mac_inst[module_idP].subframe,0,0);
604 605
      LOG_D(OPT,"[eNB %d][MCH] CC_id %d Frame %d : MAC PDU with size %d\n",
            module_idP, CC_id, frameP, TBS);
606
    }
607

608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
    /*
    for (j=0;j<sdu_length_total;j++)
    printf("%2x.",eNB_mac_inst[module_idP].MCH_pdu.payload[j+offset]);
    printf(" \n");*/
    return 1;
  } else {
    eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.Pdu_size=0;
    eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.sync_area=0;
    eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.msi_active=0;
    eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.mcch_active=0;
    eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.mtch_active=0;
    // for testing purpose, fill with random data
    //for (j=0;j<(TBS-sdu_length_total-offset);j++)
    //  eNB_mac_inst[module_idP].MCH_pdu.payload[offset+sdu_length_total+j] = (char)(taus()&0xff);
    return 0;
623
  }
624

625 626 627 628 629 630 631 632 633 634
  //this is for testing
  /*
  if (mtch_flag == 1) {
  //  LOG_D(MAC,"DUY: mch_buffer length so far is : %ld\n", &mch_buffer[sdu_length_total]-&mch_buffer[0]);
  return 1;
  }
  else
  return 0;
   */
}
635 636

MCH_PDU *get_mch_sdu(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t subframeP)
637
{
638 639
  //  eNB_mac_inst[module_idP].MCH_pdu.mcs=0;
  //LOG_D(MAC," MCH_pdu.mcs is %d\n", eNB_mac_inst[module_idP].MCH_pdu.mcs);
640
//#warning "MCH pdu should take the CC_id index"
641
  return(&eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu);
642 643 644
}

#endif