* Add VCD timing for PDCP, RLC, and MAC * Update MAC-PHY interface * update eNB MAC DLSCH scheduler and preprocessor with component carrier * Add test case for dlsim performance git-svn-id: http://svn.eurecom.fr/openair4G/trunk@5708 818b1a75-f10b-46b9-bf7c-635c3b92a50f
593 lines
15 KiB
C
Executable File
593 lines
15 KiB
C
Executable File
/*******************************************************************************
|
|
|
|
Eurecom OpenAirInterface
|
|
Copyright(c) 1999 - 2011 Eurecom
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
under the terms and conditions of the GNU General Public License,
|
|
version 2, as published by the Free Software Foundation.
|
|
|
|
This program is distributed in the hope 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
|
|
this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
The full GNU General Public License is included in this distribution in
|
|
the file called "COPYING".
|
|
|
|
Contact Information
|
|
Openair Admin: openair_admin@eurecom.fr
|
|
Openair Tech : openair_tech@eurecom.fr
|
|
Forums : http://forums.eurecom.fsr/openairinterface
|
|
Address : Eurecom, 2229, route des crêtes, 06560 Valbonne Sophia Antipolis, France
|
|
|
|
*******************************************************************************/
|
|
|
|
/*! \file phy_procedures_lte_eNB.c
|
|
* \brief Implementation of common utilities for eNB/UE procedures from 36.213 LTE specifications
|
|
* \author R. Knopp, F. Kaltenberger
|
|
* \date 2011
|
|
* \version 0.1
|
|
* \company Eurecom
|
|
* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr
|
|
* \note
|
|
* \warning
|
|
*/
|
|
#include "PHY/defs.h"
|
|
#include "PHY/extern.h"
|
|
#include "MAC_INTERFACE/defs.h"
|
|
#include "MAC_INTERFACE/extern.h"
|
|
#include "SCHED/defs.h"
|
|
#include "SCHED/extern.h"
|
|
|
|
|
|
void get_Msg3_alloc(LTE_DL_FRAME_PARMS *frame_parms,
|
|
unsigned char current_subframe,
|
|
unsigned int current_frame,
|
|
unsigned int *frame,
|
|
unsigned char *subframe) {
|
|
|
|
// Fill in other TDD Configuration!!!!
|
|
|
|
if (frame_parms->frame_type == FDD) {
|
|
*subframe = current_subframe+6;
|
|
if (*subframe>9) {
|
|
*subframe = *subframe-10;
|
|
*frame = current_frame+1;
|
|
}
|
|
else {
|
|
*frame=current_frame;
|
|
}
|
|
}
|
|
else { // TDD
|
|
if (frame_parms->tdd_config == 1) {
|
|
switch (current_subframe) {
|
|
|
|
case 0:
|
|
*subframe = 7;
|
|
*frame = current_frame;
|
|
break;
|
|
case 4:
|
|
*subframe = 2;
|
|
*frame = current_frame+1;
|
|
break;
|
|
case 5:
|
|
*subframe = 2;
|
|
*frame = current_frame+1;
|
|
break;
|
|
case 9:
|
|
*subframe = 7;
|
|
*frame = current_frame+1;
|
|
break;
|
|
}
|
|
}
|
|
else if (frame_parms->tdd_config == 3) {
|
|
switch (current_subframe) {
|
|
|
|
case 0:
|
|
case 5:
|
|
case 6:
|
|
*subframe = 2;
|
|
*frame = current_frame+1;
|
|
break;
|
|
case 7:
|
|
*subframe = 3;
|
|
*frame = current_frame+1;
|
|
break;
|
|
case 8:
|
|
*subframe = 4;
|
|
*frame = current_frame+1;
|
|
break;
|
|
case 9:
|
|
*subframe = 2;
|
|
*frame = current_frame+2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void get_Msg3_alloc_ret(LTE_DL_FRAME_PARMS *frame_parms,
|
|
unsigned char current_subframe,
|
|
unsigned int current_frame,
|
|
unsigned int *frame,
|
|
unsigned char *subframe) {
|
|
if (frame_parms->frame_type == FDD) {
|
|
// always retransmit in n+8
|
|
*subframe = current_subframe+8;
|
|
if (*subframe>9) {
|
|
*subframe = *subframe-10;
|
|
*frame = current_frame+1;
|
|
}
|
|
else {
|
|
*frame=current_frame;
|
|
}
|
|
}
|
|
else {
|
|
if (frame_parms->tdd_config == 1) {
|
|
// original PUSCH in 2, PHICH in 6 (S), ret in 2
|
|
// original PUSCH in 3, PHICH in 9, ret in 3
|
|
// original PUSCH in 7, PHICH in 1 (S), ret in 7
|
|
// original PUSCH in 8, PHICH in 4, ret in 8
|
|
*frame = current_frame+1;
|
|
}
|
|
else if (frame_parms->tdd_config == 3) {
|
|
// original PUSCH in 2, PHICH in 8, ret in 2 next frame
|
|
// original PUSCH in 3, PHICH in 9, ret in 3 next frame
|
|
// original PUSCH in 4, PHICH in 0, ret in 4 next frame
|
|
*frame=current_frame+1;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t get_Msg3_harq_pid(LTE_DL_FRAME_PARMS *frame_parms,
|
|
uint32_t frame,
|
|
unsigned char current_subframe) {
|
|
|
|
uint8_t ul_subframe=0;
|
|
uint32_t ul_frame;
|
|
|
|
if (frame_parms->frame_type ==FDD) {
|
|
ul_subframe = (current_subframe>3) ? (current_subframe-4) : (current_subframe+6);
|
|
ul_frame = (current_subframe>3) ? (frame+1) : frame;
|
|
}
|
|
else {
|
|
switch (frame_parms->tdd_config) {
|
|
case 1:
|
|
switch (current_subframe) {
|
|
|
|
case 9:
|
|
case 0:
|
|
ul_subframe = 7;
|
|
break;
|
|
case 5:
|
|
case 7:
|
|
ul_subframe = 2;
|
|
break;
|
|
|
|
}
|
|
break;
|
|
case 3:
|
|
switch (current_subframe) {
|
|
|
|
case 0:
|
|
case 5:
|
|
case 6:
|
|
ul_subframe = 2;
|
|
break;
|
|
case 7:
|
|
ul_subframe = 3;
|
|
break;
|
|
case 8:
|
|
ul_subframe = 4;
|
|
break;
|
|
case 9:
|
|
ul_subframe = 2;
|
|
break;
|
|
}
|
|
break;
|
|
case 4:
|
|
switch (current_subframe) {
|
|
|
|
case 0:
|
|
case 5:
|
|
case 6:
|
|
case 8:
|
|
case 9:
|
|
ul_subframe = 2;
|
|
break;
|
|
case 7:
|
|
ul_subframe = 3;
|
|
break;
|
|
}
|
|
break;
|
|
case 5:
|
|
ul_subframe =2;
|
|
break;
|
|
default:
|
|
LOG_E(PHY,"get_Msg3_harq_pid: Unsupported TDD configuration %d\n",frame_parms->tdd_config);
|
|
mac_xface->macphy_exit("get_Msg3_harq_pid: Unsupported TDD configuration");
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(subframe2harq_pid(frame_parms,ul_frame,ul_subframe));
|
|
|
|
}
|
|
|
|
unsigned char ul_ACK_subframe2_dl_subframe(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe,unsigned char ACK_index) {
|
|
|
|
if (frame_parms->frame_type == FDD) {
|
|
return((subframe<4) ? subframe+6 : subframe-4);
|
|
}
|
|
else {
|
|
switch (frame_parms->tdd_config) {
|
|
case 3:
|
|
if (subframe == 2) { // ACK subframes 5 and 6
|
|
if (ACK_index==2)
|
|
return(1);
|
|
return(5+ACK_index);
|
|
}
|
|
else if (subframe == 3) { // ACK subframes 7 and 8
|
|
return(7+ACK_index); // To be updated
|
|
}
|
|
else if (subframe == 4) { // ACK subframes 9 and 0
|
|
return((9+ACK_index)%10);
|
|
}
|
|
else {
|
|
LOG_E(PHY,"phy_procedures_lte_common.c/subframe2_dl_harq_pid: illegal subframe %d for tdd_config %d\n",
|
|
subframe,frame_parms->tdd_config);
|
|
return(0);
|
|
}
|
|
break;
|
|
case 1:
|
|
if (subframe == 2) { // ACK subframes 5 and 6
|
|
return(5+ACK_index);
|
|
}
|
|
else if (subframe == 3) { // ACK subframe 9
|
|
return(9); // To be updated
|
|
}
|
|
else if (subframe == 7) { // ACK subframes 0 and 1
|
|
return(ACK_index); // To be updated
|
|
}
|
|
else if (subframe == 8) { // ACK subframe 4
|
|
return(4); // To be updated
|
|
}
|
|
else {
|
|
LOG_E(PHY,"phy_procedures_lte_common.c/ul_ACK_subframe2_dl_subframe: illegal subframe %d for tdd_config %d\n",
|
|
subframe,frame_parms->tdd_config);
|
|
return(0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
unsigned char ul_ACK_subframe2_M(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe) {
|
|
|
|
if (frame_parms->frame_type == FDD) {
|
|
return(1);
|
|
}
|
|
else {
|
|
switch (frame_parms->tdd_config) {
|
|
case 3:
|
|
if (subframe == 2) { // ACK subframes 5 and 6
|
|
return(2); // should be 3
|
|
}
|
|
else if (subframe == 3) { // ACK subframes 7 and 8
|
|
return(2); // To be updated
|
|
}
|
|
else if (subframe == 4) { // ACK subframes 9 and 0
|
|
return(2);
|
|
}
|
|
else {
|
|
LOG_E(PHY,"phy_procedures_lte_common.c/subframe2_dl_harq_pid: illegal subframe %d for tdd_config %d\n",
|
|
subframe,frame_parms->tdd_config);
|
|
return(0);
|
|
}
|
|
break;
|
|
case 1:
|
|
if (subframe == 2) { // ACK subframes 5 and 6
|
|
return(2);
|
|
}
|
|
else if (subframe == 3) { // ACK subframe 9
|
|
return(1); // To be updated
|
|
}
|
|
else if (subframe == 7) { // ACK subframes 0 and 1
|
|
return(2); // To be updated
|
|
}
|
|
else if (subframe == 8) { // ACK subframe 4
|
|
return(1); // To be updated
|
|
}
|
|
else {
|
|
LOG_E(PHY,"phy_procedures_lte_common.c/subframe2_dl_harq_pid: illegal subframe %d for tdd_config %d\n",
|
|
subframe,frame_parms->tdd_config);
|
|
return(0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
// This function implements table 10.1-1 of 36-213, p. 69
|
|
uint8_t get_ack(LTE_DL_FRAME_PARMS *frame_parms,
|
|
harq_status_t *harq_ack,
|
|
unsigned char subframe,
|
|
unsigned char *o_ACK) {
|
|
|
|
//printf("get_ack: SF %d\n",subframe);
|
|
uint8_t status=0;
|
|
uint8_t subframe_dl;
|
|
|
|
if (frame_parms->frame_type == FDD) {
|
|
if (subframe < 4)
|
|
subframe_dl = subframe + 6;
|
|
else
|
|
subframe_dl = subframe - 4;
|
|
o_ACK[0] = harq_ack[subframe_dl].ack;
|
|
status = harq_ack[subframe_dl].send_harq_status;
|
|
//printf("get_ack: Getting ACK/NAK for PDSCH (subframe %d) => %d\n",subframe_dl,o_ACK[0]);
|
|
}
|
|
else {
|
|
switch (frame_parms->tdd_config) {
|
|
case 1:
|
|
if (subframe == 2) { // ACK subframes 5 (forget 6)
|
|
o_ACK[0] = harq_ack[5].ack;
|
|
status = harq_ack[5].send_harq_status;
|
|
}
|
|
else if (subframe == 3) { // ACK subframe 9
|
|
o_ACK[0] = harq_ack[9].ack;
|
|
status = harq_ack[9].send_harq_status;
|
|
}
|
|
else if (subframe == 4) { // nothing
|
|
status = 0;
|
|
}
|
|
else if (subframe == 7) { // ACK subframes 0 (forget 1)
|
|
o_ACK[0] = harq_ack[0].ack;
|
|
status = harq_ack[0].send_harq_status;
|
|
}
|
|
else if (subframe == 8) { // ACK subframes 4
|
|
o_ACK[0] = harq_ack[4].ack;
|
|
status = harq_ack[4].send_harq_status;
|
|
}
|
|
else {
|
|
LOG_E(PHY,"phy_procedures_lte.c: get_ack, illegal subframe %d for tdd_config %d\n",
|
|
subframe,frame_parms->tdd_config);
|
|
return(0);
|
|
}
|
|
break;
|
|
case 3:
|
|
if (subframe == 2) { // ACK subframes 5 and 6
|
|
if (harq_ack[5].send_harq_status == 1) {
|
|
o_ACK[0] = harq_ack[5].ack;
|
|
if (harq_ack[6].send_harq_status == 1)
|
|
o_ACK[1] = harq_ack[6].ack;
|
|
}
|
|
else if (harq_ack[6].send_harq_status == 1)
|
|
o_ACK[0] = harq_ack[6].ack;
|
|
status = harq_ack[5].send_harq_status + (harq_ack[6].send_harq_status<<1);
|
|
}
|
|
else if (subframe == 3) { // ACK subframes 7 and 8
|
|
if (harq_ack[7].send_harq_status == 1) {
|
|
o_ACK[0] = harq_ack[7].ack;
|
|
if (harq_ack[8].send_harq_status == 1)
|
|
o_ACK[1] = harq_ack[8].ack;
|
|
}
|
|
else if (harq_ack[8].send_harq_status == 1)
|
|
o_ACK[0] = harq_ack[8].ack;
|
|
|
|
status = harq_ack[7].send_harq_status + (harq_ack[8].send_harq_status<<1);
|
|
//printf("status %d : o_ACK (%d,%d)\n", status,o_ACK[0],o_ACK[1]);
|
|
}
|
|
else if (subframe == 4) { // ACK subframes 9 and 0
|
|
if (harq_ack[9].send_harq_status == 1) {
|
|
o_ACK[0] = harq_ack[9].ack;
|
|
if (harq_ack[0].send_harq_status == 1)
|
|
o_ACK[1] = harq_ack[0].ack;
|
|
}
|
|
else if (harq_ack[8].send_harq_status == 1)
|
|
o_ACK[0] = harq_ack[8].ack;
|
|
|
|
status = harq_ack[9].send_harq_status + (harq_ack[0].send_harq_status<<1);
|
|
}
|
|
else {
|
|
LOG_E(PHY,"phy_procedures_lte.c: get_ack, illegal subframe %d for tdd_config %d\n",
|
|
subframe,frame_parms->tdd_config);
|
|
return(0);
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
//printf("status %d\n",status);
|
|
|
|
return(status);
|
|
}
|
|
|
|
uint8_t Np6[4]={0,1,3,5};
|
|
uint8_t Np15[4]={0,3,8,13};
|
|
uint8_t Np25[4]={0,5,13,22};
|
|
uint8_t Np50[4]={0,11,27,44};
|
|
uint8_t Np75[4]={0,16,41,66};
|
|
uint8_t Np100[4]={0,22,55,88};
|
|
// This is part of the PUCCH allocation procedure (see Section 10.1 36.213)
|
|
uint16_t get_Np(uint8_t N_RB_DL,uint8_t nCCE,uint8_t plus1) {
|
|
uint8_t *Np;
|
|
switch (N_RB_DL) {
|
|
case 6:
|
|
Np=Np6;
|
|
break;
|
|
case 15:
|
|
Np=Np15;
|
|
break;
|
|
case 25:
|
|
Np=Np25;
|
|
break;
|
|
case 50:
|
|
Np=Np50;
|
|
break;
|
|
case 75:
|
|
Np=Np75;
|
|
break;
|
|
case 100:
|
|
Np=Np100;
|
|
break;
|
|
default:
|
|
LOG_E(PHY,"get_Np() FATAL: unsupported N_RB_DL %d\n",N_RB_DL);
|
|
return(0);
|
|
break;
|
|
}
|
|
|
|
if (nCCE>=Np[2])
|
|
return(Np[2+plus1]);
|
|
else if (nCCE>=Np[1])
|
|
return(Np[1+plus1]);
|
|
else
|
|
return(Np[0+plus1]);
|
|
}
|
|
|
|
lte_subframe_t subframe_select(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe) {
|
|
|
|
// if FDD return dummy value
|
|
if (frame_parms->frame_type == FDD)
|
|
return(SF_DL);
|
|
|
|
switch (frame_parms->tdd_config) {
|
|
|
|
case 1:
|
|
switch (subframe) {
|
|
case 0:
|
|
case 4:
|
|
case 5:
|
|
case 9:
|
|
return(SF_DL);
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
case 7:
|
|
case 8:
|
|
return(SF_UL);
|
|
break;
|
|
default:
|
|
return(SF_S);
|
|
break;
|
|
}
|
|
case 3:
|
|
if ((subframe<1) || (subframe>=5))
|
|
return(SF_DL);
|
|
else if ((subframe>1) && (subframe < 5))
|
|
return(SF_UL);
|
|
else if (subframe==1)
|
|
return (SF_S);
|
|
else {
|
|
LOG_E(PHY,"[PHY_PROCEDURES_LTE] Unknown subframe number\n");
|
|
return(255);
|
|
}
|
|
break;
|
|
default:
|
|
LOG_E(PHY,"subframe %d Unsupported TDD configuration %d\n",subframe,frame_parms->tdd_config);
|
|
mac_xface->macphy_exit("subframe x Unsupported TDD configuration");
|
|
return(255);
|
|
|
|
}
|
|
}
|
|
|
|
lte_subframe_t get_subframe_direction(uint8_t Mod_id,uint8_t CC_id,uint8_t subframe) {
|
|
|
|
return(subframe_select(&PHY_vars_eNB_g[Mod_id][CC_id]->lte_frame_parms,subframe));
|
|
|
|
}
|
|
|
|
uint8_t phich_subframe_to_harq_pid(LTE_DL_FRAME_PARMS *frame_parms,uint32_t frame,uint8_t subframe) {
|
|
|
|
//LOG_D(PHY,"phich_subframe_to_harq_pid.c: frame %d, subframe %d\n",frame,subframe);
|
|
return(subframe2harq_pid(frame_parms,
|
|
phich_frame2_pusch_frame(frame_parms,frame,subframe),
|
|
phich_subframe2_pusch_subframe(frame_parms,subframe)));
|
|
}
|
|
|
|
unsigned int is_phich_subframe(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe) {
|
|
|
|
if (frame_parms->frame_type == FDD) {
|
|
return(1);
|
|
}
|
|
else {
|
|
switch (frame_parms->tdd_config) {
|
|
case 1:
|
|
if ((subframe == 1) || (subframe == 4) || (subframe == 6) || (subframe == 9))
|
|
return(1);
|
|
break;
|
|
case 3:
|
|
if ((subframe == 0) || (subframe == 8) || (subframe == 9))
|
|
return(1);
|
|
break;
|
|
case 4:
|
|
if ((subframe == 0) || (subframe == 8) )
|
|
return(1);
|
|
break;
|
|
case 5:
|
|
if (subframe == 0)
|
|
return(1);
|
|
break;
|
|
default:
|
|
return(0);
|
|
break;
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
LTE_eNB_UE_stats* get_eNB_UE_stats(uint8_t Mod_id, uint8_t CC_id,uint16_t rnti) {
|
|
int8_t UE_id;
|
|
if ((PHY_vars_eNB_g == NULL) || (PHY_vars_eNB_g[Mod_id] == NULL) || (PHY_vars_eNB_g[Mod_id][CC_id]==NULL)) {
|
|
LOG_E(PHY,"get_eNB_UE_stats: No phy_vars_eNB found (or not allocated) for Mod_id %d,CC_id %d\n",Mod_id,CC_id);
|
|
return NULL;
|
|
}
|
|
UE_id = find_ue(rnti, PHY_vars_eNB_g[Mod_id][CC_id]);
|
|
if (UE_id == -1) {
|
|
LOG_E(PHY,"get_eNB_UE_stats: UE with rnti %x not found\n",rnti);
|
|
return NULL;
|
|
}
|
|
return(&PHY_vars_eNB_g[Mod_id][CC_id]->eNB_UE_stats[(uint32_t)UE_id]);
|
|
}
|
|
|
|
int8_t find_ue(uint16_t rnti, PHY_VARS_eNB *phy_vars_eNB) {
|
|
uint8_t i;
|
|
|
|
for (i=0;i<NUMBER_OF_UE_MAX;i++) {
|
|
if ((phy_vars_eNB->dlsch_eNB[i]) &&
|
|
(phy_vars_eNB->dlsch_eNB[i][0]) &&
|
|
(phy_vars_eNB->dlsch_eNB[i][0]->rnti==rnti)) {
|
|
return(i);
|
|
}
|
|
}
|
|
#ifdef CBA
|
|
for (i=0; i<NUM_MAX_CBA_GROUP; i++){
|
|
if ((phy_vars_eNB->ulsch_eNB[i]) && // ue J is the representative of group j
|
|
(phy_vars_eNB->ulsch_eNB[i]->num_active_cba_groups) &&
|
|
(phy_vars_eNB->ulsch_eNB[i]->cba_rnti[i]== rnti))
|
|
return(i);
|
|
}
|
|
#endif
|
|
|
|
return(-1);
|
|
}
|
|
|
|
LTE_DL_FRAME_PARMS* get_lte_frame_parms(module_id_t Mod_id, uint8_t CC_id){
|
|
|
|
return(&PHY_vars_eNB_g[Mod_id][CC_id]->lte_frame_parms);
|
|
|
|
}
|
|
|
|
MU_MIMO_mode *get_mu_mimo_mode (module_id_t Mod_id, uint8_t CC_id){
|
|
|
|
return(&PHY_vars_eNB_g[Mod_id][CC_id]->mu_mimo_mode);
|
|
}
|