Commit 6c519f5b authored by David Price's avatar David Price

Merge from RU-RAU-split and fix of frame/subframe handling. Was very confused...

Merge from RU-RAU-split and fix of frame/subframe handling.  Was very confused with the counter in the main loop, the incrementing from the USRP read library and the nFAPI frame handling.  RACH seen on wireshark and something happens on VNF
parent 6559fc19
......@@ -37,6 +37,8 @@ extern int nfapi_sync_var;
extern int sync_var;
extern void init_eNB_afterRU(void);
extern void handle_nfapi_dci_dl_pdu(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, nfapi_dl_config_request_pdu_t *dl_config_pdu);
uint16_t phy_antenna_capability_values[] = { 1, 2, 4, 8, 16 };
......@@ -947,7 +949,6 @@ void nfapi_procedures(PHY_VARS_eNB *eNB, int sfn, int sf)
common_signal_procedures(eNB, sfn, sf);
LOG_E(PHY,"SFN/SF:%d/%d pdcch_vars[num_dci:%d num_pdcch_symbols:%d dci_alloc:dci_length:%d]\n", sfn, sf, pdcch_vars->num_dci, pdcch_vars->num_pdcch_symbols, pdcch_vars->dci_alloc[0].dci_length);
if (pdcch_vars->num_dci > 0)
{
LOG_D(PHY,"SFN/SF:%d/%d pdcch_vars[num_dci:%d num_pdcch_symbols:%d dci_alloc:dci_length:%d]\n", sfn, sf, pdcch_vars->num_dci, pdcch_vars->num_pdcch_symbols, pdcch_vars->dci_alloc[0].dci_length);
......@@ -1013,8 +1014,8 @@ void nfapi_procedures(PHY_VARS_eNB *eNB, int sfn, int sf)
int pnf_phy_dl_config_req(nfapi_pnf_p7_config_t* pnf_p7, nfapi_dl_config_request_t* req)
{
#if 1
//if (1)//NFAPI_SFNSF2SF(req->sfn_sf)==5)
LOG_E(PHY,"[PNF] dl config request sfn_sf:%d pdcch:%u dci:%u pdu:%d pdsch_rnti:%d pcfich:%u RC.ru:%p RC.eNB:%p sync_var:%d\n",
if (0)//NFAPI_SFNSF2SF(req->sfn_sf)==5)
LOG_D(PHY,"[PNF] dl config request sfn_sf:%d pdcch:%u dci:%u pdu:%d pdsch_rnti:%d pcfich:%u RC.ru:%p RC.eNB:%p sync_var:%d\n",
NFAPI_SFNSF2DEC(req->sfn_sf),
req->dl_config_request_body.number_pdcch_ofdm_symbols,
req->dl_config_request_body.number_dci,
......@@ -1086,8 +1087,8 @@ int pnf_phy_dl_config_req(nfapi_pnf_p7_config_t* pnf_p7, nfapi_dl_config_request
if (dl_config_pdu_list[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)
{
nfapi_dl_config_dci_dl_pdu *dci_pdu = &dl_config_pdu_list[i].dci_dl_pdu;
nfapi_dl_config_dci_dl_pdu_rel8_t *rel8_pdu = &dci_pdu->dci_dl_pdu_rel8;
//nfapi_dl_config_dci_dl_pdu *dci_pdu = &dl_config_pdu_list[i].dci_dl_pdu;
//nfapi_dl_config_dci_dl_pdu_rel8_t *rel8_pdu = &dci_pdu->dci_dl_pdu_rel8;
//NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() DCI:transmission_power:%u\n", __FUNCTION__, rel8_pdu->transmission_power);
......@@ -1400,12 +1401,10 @@ int start_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi
}
printf("[PNF] OAI eNB/RU configured\n");
printf("[PNF] About to call init_eNB_afterRU()\n");
init_eNB_afterRU();
printf("[PNF] About to call phy_init_RU()\n");
phy_init_RU(RC.ru[0]);
//printf("[PNF] About to call phy_init_RU() for RC.ru[0]:%p\n", RC.ru[0]);
//phy_init_RU(RC.ru[0]);
printf("[PNF] About to call init_eNB_afterRU()\n");
init_eNB_afterRU();
// Signal to main thread that it can carry on - otherwise RU will startup too quickly and it is not initialised
......@@ -1796,14 +1795,14 @@ void configure_nfapi_pnf(char *vnf_ip_addr, int vnf_p5_port, char *pnf_ip_addr,
void oai_subframe_ind(uint16_t frame, uint16_t subframe)
{
LOG_D(PHY,"%s(frame:%d, subframe:%d)\n", __FUNCTION__, frame, subframe);
//LOG_D(PHY,"%s(frame:%d, subframe:%d)\n", __FUNCTION__, frame, subframe);
//TODO FIXME - HACK - DJP - using a global to bodge it in
if (p7_config_g != NULL && sync_var==0)
{
uint16_t sfn = subframe>=9?frame+1:frame;
uint16_t sf = subframe>=9?0:subframe+1;
uint16_t sfn = frame;//subframe>=9?frame+1:frame;
uint16_t sf = subframe;//subframe>=9?0:subframe+1;
uint16_t sfn_sf = sfn<<4 | sf;
if ((frame % 100 == 0) && subframe==0)
......@@ -1831,7 +1830,7 @@ int oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind)
{
rach_ind->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!!
LOG_I(PHY, "%s() sfn_sf:%d preambles:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(rach_ind->sfn_sf), rach_ind->rach_indication_body.number_of_preambles);
LOG_E(PHY, "%s() sfn_sf:%d preambles:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(rach_ind->sfn_sf), rach_ind->rach_indication_body.number_of_preambles);
return nfapi_pnf_p7_rach_ind(p7_config_g, rach_ind);
}
......@@ -638,27 +638,40 @@ int phy_subframe_indication(struct nfapi_vnf_p7_config* config, uint16_t phy_id,
int phy_rach_indication(struct nfapi_vnf_p7_config* config, nfapi_rach_indication_t* ind)
{
LOG_I(MAC, "%s() NFAPI SFN/SF:%d number_of_preambles:%u\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->rach_indication_body.number_of_preambles);
LOG_E(MAC, "%s() NFAPI SFN/SF:%d number_of_preambles:%u\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->rach_indication_body.number_of_preambles);
struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0];
printf("[VNF] RACH_IND eNB:%p sfn_sf:%d number_of_preambles:%d", eNB, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->rach_indication_body.number_of_preambles);
pthread_mutex_lock(&eNB->UL_INFO_mutex);
eNB->UL_INFO.rach_ind.number_of_preambles=ind->rach_indication_body.number_of_preambles;
eNB->UL_INFO.rach_ind.number_of_preambles = ind->rach_indication_body.number_of_preambles;
eNB->UL_INFO.rach_ind.preamble_list = eNB->preamble_list;
eNB->UL_INFO.rach_ind.tl.tag = NFAPI_RACH_INDICATION_BODY_TAG;
if (eNB->UL_INFO.rach_ind.preamble_list==0)
for (int i=0;i<ind->rach_indication_body.number_of_preambles++;i++)
{
if (ind->rach_indication_body.preamble_list[i].preamble_rel8.tl.tag == NFAPI_PREAMBLE_REL8_TAG)
{
LOG_W(MAC, "%s() Mallocing eNB->UL_INFO.rach_ind.preamble_list but have no code to free it, but should only be needed once...\n", __FUNCTION__);
eNB->UL_INFO.rach_ind.preamble_list = malloc(sizeof(nfapi_preamble_pdu_t)*MAX_NUM_RX_PRACH_PREAMBLES);
printf("preamble[%d]: rnti:%02x preamble:%d timing_advance:%d\n",
i,
ind->rach_indication_body.preamble_list[i].preamble_rel8.rnti,
ind->rach_indication_body.preamble_list[i].preamble_rel8.preamble,
ind->rach_indication_body.preamble_list[i].preamble_rel8.timing_advance
);
}
for(int i=0;i<ind->rach_indication_body.number_of_preambles;i++)
if(ind->rach_indication_body.preamble_list[i].preamble_rel13.tl.tag == NFAPI_PREAMBLE_REL13_TAG)
{
eNB->UL_INFO.rach_ind.preamble_list[0]=ind->rach_indication_body.preamble_list[0];
printf("RACH PREAMBLE REL13 present\n");
}
eNB->preamble_list[i] = ind->rach_indication_body.preamble_list[i];
}
pthread_mutex_unlock(&eNB->UL_INFO_mutex);
// vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data);
//mac_rach_ind(p7_vnf->mac, ind);
return 1;
......
......@@ -174,7 +174,7 @@ int generate_pbch(LTE_eNB_PBCH *eNB_pbch,
pbch_E = (frame_parms->Ncp==NORMAL) ? 1920 : 1728; //RE/RB * #RB * bits/RB (QPSK)
// pbch_E_bytes = pbch_coded_bits>>3;
LOG_D(PHY,"%s(eNB_pbch:%p txdataF:%p amp:%d frame_parms:%p pbch_pdu:%p frame_mod4:%d)\n", __FUNCTION__, eNB_pbch, txdataF, amp, frame_parms, pbch_pdu, frame_mod4==0);
//LOG_D(PHY,"%s(eNB_pbch:%p txdataF:%p amp:%d frame_parms:%p pbch_pdu:%p frame_mod4:%d)\n", __FUNCTION__, eNB_pbch, txdataF, amp, frame_parms, pbch_pdu, frame_mod4==0);
if (frame_mod4==0) {
bzero(pbch_a,PBCH_A>>3);
......
......@@ -38,7 +38,7 @@
#include "SCHED/extern.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
#define PRACH_DEBUG 1
//#define PRACH_DEBUG 1
//#define PRACH_WRITE_OUTPUT_DEBUG 1
uint16_t NCS_unrestricted[16] = {0,13,15,18,22,26,32,38,46,59,76,93,119,167,279,419};
......@@ -1132,7 +1132,7 @@ void rx_prach0(PHY_VARS_eNB *eNB,
uint16_t numshift=0;
uint16_t *prach_root_sequence_map;
uint8_t not_found;
int k;
int k=0;
uint16_t u;
int16_t *Xu;
uint16_t offset;
......@@ -1149,10 +1149,7 @@ void rx_prach0(PHY_VARS_eNB *eNB,
#ifdef Rel14
int prach_ifft_cnt=0;
#endif
#ifdef PRACH_DEBUG
int en0=0;
#endif
int en;
int en=0;
if (ru) {
fp = &ru->frame_parms;
nb_rx = ru->nb_rx;
......@@ -1203,7 +1200,9 @@ void rx_prach0(PHY_VARS_eNB *eNB,
#ifdef Rel14
if (br_flag == 1) {
prach_ifftp = eNB->prach_vars_br.prach_ifft[ce_level];
#ifdef PRACH_DEBUG
frame = eNB->proc.frame_prach_br;
#endif
subframe = eNB->proc.subframe_prach_br;
prachF = eNB->prach_vars_br.prachF;
rxsigF = eNB->prach_vars_br.rxsigF[ce_level];
......@@ -1220,7 +1219,9 @@ void rx_prach0(PHY_VARS_eNB *eNB,
#endif
{
prach_ifftp = eNB->prach_vars.prach_ifft[0];
#ifdef PRACH_DEBUG
frame = eNB->proc.frame_prach;
#endif
subframe = eNB->proc.subframe_prach;
prachF = eNB->prach_vars.prachF;
rxsigF = eNB->prach_vars.rxsigF[0];
......@@ -1232,6 +1233,9 @@ void rx_prach0(PHY_VARS_eNB *eNB,
else {
#ifdef Rel14
if (br_flag == 1) {
#ifdef PRACH_DEBUG
frame = ru->proc.frame_prach_br;
#endif
subframe = ru->proc.subframe_prach_br;
rxsigF = ru->prach_rxsigF_br[ce_level];
#ifdef PRACH_DEBUG
......@@ -1242,6 +1246,9 @@ void rx_prach0(PHY_VARS_eNB *eNB,
else
#endif
{
#ifdef PRACH_DEBUG
frame = ru->proc.frame_prach;
#endif
subframe = ru->proc.subframe_prach;
rxsigF = ru->prach_rxsigF;
#ifdef PRACH_DEBUG
......@@ -1259,16 +1266,29 @@ void rx_prach0(PHY_VARS_eNB *eNB,
// DJP - indexing below in subframe zero takes us off the beginning of the array???
prach[aa] = (int16_t*)&ru->common.rxdata[aa][(subframe*fp->samples_per_tti)-ru->N_TA_offset];
#ifdef PRACH_DEBUG
//int8_t rach_dBm = dB_fixed(rach_pwr) - eNB->rx_total_gain_dB;
//LOG_E(PHY,"RACH %d dBm rx_total_gain_db:%d rach_pwr, rxdata:%d dBm\n", rach_dBm, eNB->rx_total_gain_dB, rach_pwr, rxdata_pwr);
int32_t en0=signal_energy((int32_t*)prach[aa],fp->samples_per_tti);
int8_t dbEn0 = dB_fixed(en0);
int8_t rach_dBm = dbEn0 - eNB->rx_total_gain_dB;
//if ((frame&1023) < 20) LOG_I(PHY,"RU %d, br_flag %d ce_level %d frame %d subframe %d, : prach %p (energy %d)\n",ru->idx,br_flag,ce_level,frame,subframe,prach[aa],dB_fixed(en0=signal_energy(prach[aa],fp->samples_per_tti)));
#ifdef PRACH_WRITE_OUTPUT_DEBUG
if (dbEn0>32 && prach[0]!= NULL)
{
static int counter=0;
en0=signal_energy(prach[aa],fp->samples_per_tti);
int8_t dbEn0 = dB_fixed(en0);
char buffer[80];
//counter++;
sprintf(buffer, "%s%d", "/tmp/prach_rx",counter);
write_output(buffer,"prach_rx",prach[0],fp->samples_per_tti,1,13);
}
#endif
if (dbEn0>32)
LOG_I(PHY,"RU %d, br_flag %d ce_level %d frame %d subframe %d, : prach %p (energy %d) TA:%d\n",ru->idx,br_flag,ce_level,frame,subframe,prach[aa],dbEn0,ru->N_TA_offset);
{
#ifdef PRACH_WRITE_OUTPUT_DEBUG
if (prach[0]!= NULL) write_output("prach_rx","prach_rx",prach[0],fp->samples_per_tti,1,1);
#endif
LOG_I(PHY,"RU %d, br_flag %d ce_level %d frame %d subframe %d per_tti:%d prach:%p (energy %d) TA:%d rach_dBm:%d rxdata:%p index:%d\n",ru->idx,br_flag,ce_level,frame,subframe,fp->samples_per_tti,prach[aa],dbEn0,ru->N_TA_offset,rach_dBm,ru->common.rxdata[aa], (subframe*fp->samples_per_tti)-ru->N_TA_offset);
}
#endif
}
}
......@@ -1351,7 +1371,7 @@ void rx_prach0(PHY_VARS_eNB *eNB,
if (((eNB!=NULL) && (ru->function != NGFI_RAU_IF4p5))||
((eNB==NULL) && (ru->function == NGFI_RRU_IF4p5))) { // compute the DFTs of the PRACH temporal resources
// Do forward transform
LOG_D(PHY,"rx_prach: Doing FFT for N_RB_UL %d\n",fp->N_RB_UL);
LOG_D(PHY,"rx_prach: Doing FFT for N_RB_UL %d nb_rx:%d Ncp:%d\n",fp->N_RB_UL, nb_rx, Ncp);
for (aa=0; aa<nb_rx; aa++) {
AssertFatal(prach[aa]!=NULL,"prach[%d] is null\n",aa);
prach2 = prach[aa] + (Ncp<<1);
......@@ -1456,7 +1476,7 @@ void rx_prach0(PHY_VARS_eNB *eNB,
k+=13;
k*=2;
int dftsize_x2 = fp->ofdm_symbol_size*24;
LOG_D(PHY,"Shifting prach_rxF from %d to 0\n",k);
//LOG_D(PHY,"Shifting prach_rxF from %d to 0\n",k);
if ((k+(839*2)) > dftsize_x2) { // PRACH signal is split around DC
memmove((void*)&rxsigF[aa][dftsize_x2-k],(void*)&rxsigF[aa][0],(k+(839*2)-dftsize_x2)*2);
......
......@@ -33,7 +33,7 @@ int write_output(const char *fname,const char *vname,void *data,int length,int d
int i;
printf("Writing %d elements of type %d to %s\n",length,format,fname);
//printf("Writing %d elements of type %d to %s\n",length,format,fname);
if (format == 10 || format ==11 || format == 12 || format == 13 || format == 14) {
......@@ -68,9 +68,11 @@ int write_output(const char *fname,const char *vname,void *data,int length,int d
case 15:
for (i=0; i<length<<1; i+=(2*dec)) {
fprintf(fp,"%d + j*(%d)\n",((short *)data)[i],((short *)data)[i+1]);
//fprintf(fp,"%d + j*(%d)\n",((short *)data)[i],((short *)data)[i+1]);
fprintf(fp,"%d,%d,",((short *)data)[i],((short *)data)[i+1]);
}
fprintf(fp,"\n");
break;
......
......@@ -1577,7 +1577,7 @@ static inline int release_thread(pthread_mutex_t *mutex,int *instance_cnt,char *
return(-1);
}
LOG_D(PHY, "%s() name:%s instance_cnt:%u - about to decrement\n", __FUNCTION__, name, *instance_cnt);
//LOG_D(PHY, "%s() name:%s instance_cnt:%u - about to decrement\n", __FUNCTION__, name, *instance_cnt);
*instance_cnt=*instance_cnt-1;
......
......@@ -145,7 +145,7 @@ void common_signal_procedures (PHY_VARS_eNB *eNB,int frame, int subframe) {
int **txdataF = eNB->common_vars.txdataF;
uint8_t *pbch_pdu=&eNB->pbch_pdu[0];
LOG_D(PHY,"common_signal_procedures: frame %d, subframe %d fdd:%s dir:%s\n",frame,subframe,fp->frame_type == FDD?"FDD":"TDD", subframe_select(fp,subframe) == SF_DL?"DL":"UL?");
//LOG_D(PHY,"common_signal_procedures: frame %d, subframe %d fdd:%s dir:%s\n",frame,subframe,fp->frame_type == FDD?"FDD":"TDD", subframe_select(fp,subframe) == SF_DL?"DL":"UL?");
// generate Cell-Specific Reference Signals for both slots
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_RS_TX,1);
......@@ -568,7 +568,6 @@ void prach_procedures(PHY_VARS_eNB *eNB,
uint16_t max_preamble[4],max_preamble_energy[4],max_preamble_delay[4];
uint16_t i;
int frame,subframe;
LTE_eNB_PRACH *prach_vars=NULL;
#ifdef Rel14
if (br_flag==1) {
......@@ -679,7 +678,7 @@ void prach_procedures(PHY_VARS_eNB *eNB,
{
if (max_preamble_energy[0] > 350) {
LOG_I(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n",
LOG_E(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n",
eNB->Mod_id,
eNB->CC_id,
frame,
......@@ -715,8 +714,8 @@ void prach_procedures(PHY_VARS_eNB *eNB,
rach_ind.sfn_sf = frame<<4 | subframe;
rach_ind.rach_indication_body = eNB->UL_INFO.rach_ind;
LOG_I(PHY,"\n\n\n\nDJP - this needs to be sent to VNF **********************************************\n\n\n\n");
LOG_I(PHY,"Filling NFAPI indication for RACH : TA %d, Preamble %d, rnti %x, rach_resource_type %d\n",
LOG_E(PHY,"\n\n\n\nDJP - this needs to be sent to VNF **********************************************\n\n\n\n");
LOG_E(PHY,"Filling NFAPI indication for RACH : TA %d, Preamble %d, rnti %x, rach_resource_type %d\n",
eNB->preamble_list[0].preamble_rel8.timing_advance,
eNB->preamble_list[0].preamble_rel8.preamble,
eNB->preamble_list[0].preamble_rel8.rnti,
......@@ -2022,9 +2021,10 @@ void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,const
uci_procedures(eNB,proc);
if (nfapi_pnf == 0 || nfapi_pnf == 1) // If PNF or monolithic
{
pusch_procedures(eNB,proc);
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC, 0 );
......
......@@ -150,7 +150,7 @@ void feptx_ofdm(RU_t *ru) {
}
}
else {
LOG_D(PHY,"feptx_ofdm: Writing to position %d\n",slot_offset);
//LOG_D(PHY,"feptx_ofdm: Writing to position %d\n",slot_offset);
tx_offset = (int)slot_offset;
txdata = (int16_t*)&ru->common.txdata[aa][tx_offset];
......@@ -185,9 +185,11 @@ void feptx_ofdm(RU_t *ru) {
ru->common.txdata[aa][tx_offset] = 0x00000000;
}
}
#if 0
LOG_D(PHY,"feptx_ofdm (TXPATH): frame %d, subframe %d: txp (time %p) %d dB, txp (freq) %d dB\n",
ru->proc.frame_tx,subframe,txdata,dB_fixed(signal_energy((int32_t*)txdata,fp->samples_per_tti)),
dB_fixed(signal_energy_nodc(ru->common.txdataF_BF[aa],2*slot_sizeF)));
#endif
}
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM , 0 );
......@@ -235,9 +237,11 @@ void feptx_prec(RU_t *ru) {
aa);
}
}
#if 0
LOG_D(PHY,"feptx_prec: frame %d, subframe %d: txp (freq) %d dB\n",
ru->proc.frame_tx,subframe,
dB_fixed(signal_energy_nodc(ru->common.txdataF_BF[0],2*fp->symbols_per_tti*fp->ofdm_symbol_size)));
#endif
}
}
}
......
......@@ -310,7 +310,6 @@ void *eNB_app_task(void *args_p)
const char *msg_name = NULL;
instance_t instance;
int result;
int j;
/* for no gcc warnings */
(void)instance;
......
......@@ -140,6 +140,8 @@ void RCconfig_RU(void) {
memset((void*)RC.ru[j],0,sizeof(RU_t));
RC.ru[j]->idx = j;
printf("Creating RC.ru[%d]:%p\n", j, RC.ru[j]);
RC.ru[j]->if_timing = synch_to_ext_device;
if (RC.nb_L1_inst >0)
RC.ru[j]->num_eNB = RUParamList.paramarray[j][RU_ENB_LIST_IDX].numelt;
......@@ -245,8 +247,8 @@ void RCconfig_L1(void) {
if (RC.eNB == NULL) {
RC.eNB = (PHY_VARS_eNB **)malloc((1+MAX_NUM_CCs)*sizeof(PHY_VARS_eNB**));
LOG_I(PHY,"RC.eNB[%d] = %p\n",j,RC.eNB[j]);
RC.eNB = (PHY_VARS_eNB ***)malloc((1+MAX_NUM_CCs)*sizeof(PHY_VARS_eNB**));
LOG_I(PHY,"RC.eNB = %p\n",RC.eNB);
memset(RC.eNB,0,(1+NUMBER_OF_eNB_MAX)*sizeof(PHY_VARS_eNB***));
RC.nb_L1_CC = malloc((1+RC.nb_L1_inst)*sizeof(int));
}
......@@ -297,7 +299,7 @@ void RCconfig_L1(void) {
RC.nb_inst =1; // DJP - feptx_prec uses num_eNB but phy_init_RU uses nb_inst
LOG_I(PHY,"%s() NFAPI PNF mode - RC.nb_inst=1 this is because phy_init_RU() uses that to index and not RC.num_eNB - why the 2 similar variables?\n", __FUNCTION__);
LOG_I(PHY,"%s() NFAPI PNF mode - RC.nb_CC[0]=1 for init_eNB_afterRU()\n", __FUNCTION__, RC.nb_CC[0]);
LOG_I(PHY,"%s() NFAPI PNF mode - RC.nb_CC[0]=%d for init_eNB_afterRU()\n", __FUNCTION__, RC.nb_CC[0]);
LOG_I(PHY,"%s() NFAPI PNF mode - RC.nb_macrlc_inst:%d because used by mac_top_init_eNB()\n", __FUNCTION__, RC.nb_macrlc_inst);
mac_top_init_eNB();
......
......@@ -861,7 +861,6 @@ void schedule_ulsch_rnti(module_id_t module_idP,
UE_list_t *UE_list=&eNB->UE_list;
UE_TEMPLATE *UE_template;
UE_sched_ctrl *UE_sched_ctrl;
int tmode;
int sched_frame=frameP;
int rvidx_tab[4] = {0,2,3,1};
......@@ -870,13 +869,13 @@ void schedule_ulsch_rnti(module_id_t module_idP,
nfapi_hi_dci0_request_body_t *hi_dci0_req = &eNB->HI_DCI0_req[CC_id].hi_dci0_request_body;
nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu;
nfapi_ul_config_request_pdu_t *ul_config_pdu;
//nfapi_ul_config_request_pdu_t *ul_config_pdu;
nfapi_ul_config_request_body_t *ul_req_tmp = &eNB->UL_req_tmp[CC_id][sched_subframeP].ul_config_request_body;
ul_config_pdu = &ul_req_tmp->ul_config_pdu_list[0];
//ul_config_pdu = &ul_req_tmp->ul_config_pdu_list[0];
LOG_D(MAC,"entering ulsch preprocesor\n");
......@@ -1195,7 +1194,7 @@ abort();
LOG_I(MAC,"[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled (PHICH) UE %d (mcs %d, first rb %d, nb_rb %d, TBS %d, harq_pid %d,round %d)\n",
module_idP,harq_pid,rnti,CC_id,frameP,subframeP,UE_id,UE_template->mcs_UL[harq_pid],
UE_template->first_rb_ul[harq_pid], UE_template->nb_rb_ul[harq_pid],
UE_template->TBS_UL[harq_pid],round);
UE_template->TBS_UL[harq_pid],harq_pid,round);
// Add UL_config PDUs
LOG_D(MAC,"[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d\n",
harq_pid,frameP,subframeP,UE_id,rnti,sched_frame,sched_subframeP);
......
......@@ -47,6 +47,7 @@
#include "common/ran_context.h"
extern RAN_CONTEXT_t RC;
extern void openair_rrc_top_init_ue( int eMBMS_active, char* uecap_xer, uint8_t cba_group_active, uint8_t HO_active);
void dl_phy_sync_success(module_id_t module_idP,
frame_t frameP,
......
......@@ -147,7 +147,7 @@ mac_rrc_data_req(
return (RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB1);
} // All RFN mod 8 transmit SIB2-3 in SF 5
else if ((frameP%8) == 1) {
LOG_D(RRC, "%s() frameP%8==1 (frameP:%d) copy into buffer SIB23 size:%d\n", __FUNCTION__, frameP, RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB23);
LOG_D(RRC, "%s() frameP mod 8==1 (frameP:%d) copy into buffer SIB23 size:%d\n", __FUNCTION__, frameP, RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB23);
memcpy(&buffer_pP[0],
RC.rrc[Mod_idP]->carrier[CC_id].SIB23,
RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB23);
......
......@@ -49,6 +49,7 @@
#include "COMMON/platform_constants.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
#include "common/ran_context.h"
#include "gtpv1u_eNB_defs.h"
#undef GTP_DUMP_SOCKET
......
......@@ -190,13 +190,12 @@ RUs = (
}
);
log_config :
{
global_log_level ="info";
log_config = {
global_log_level ="debug";
global_log_verbosity ="medium";
hw_log_level ="info";
hw_log_verbosity ="medium";
phy_log_level ="info";
phy_log_level ="debug";
phy_log_verbosity ="medium";
mac_log_level ="info";
mac_log_verbosity ="high";
......@@ -206,4 +205,4 @@ RUs = (
pdcp_log_verbosity ="medium";
rrc_log_level ="info";
rrc_log_verbosity ="medium";
};
};
log_config =
{
log_config = {
global_log_level ="info";
global_log_verbosity ="medium";
hw_log_level ="info";
hw_log_verbosity ="medium";
phy_log_level ="info";
phy_log_level ="debug";
phy_log_verbosity ="medium";
mac_log_level ="info";
mac_log_verbosity ="high";
......@@ -14,9 +13,7 @@
pdcp_log_verbosity ="medium";
rrc_log_level ="info";
rrc_log_verbosity ="medium";
};
/* eNBs = (); */
};
L1s = (
{
......
......@@ -165,12 +165,12 @@ eNBs =
);
log_config = {
global_log_level ="info";
global_log_level ="crit";
global_log_verbosity ="high";
hw_log_level ="info";
hw_log_verbosity ="medium";
phy_log_level ="info";
phy_log_verbosity ="high";
phy_log_level ="debug";
phy_log_verbosity ="low";
mac_log_level ="info";
mac_log_verbosity ="high";
rlc_log_level ="info";
......
......@@ -389,7 +389,7 @@ int wakeup_rxtx(PHY_VARS_eNB *eNB,RU_t *ru) {
}
++proc_rxtx->instance_cnt_rxtx;
LOG_D(PHY,"%s() %u/%u Just incremented proc->instance_cnt_rxtx:%d\n", __FUNCTION__, proc_rxtx->frame_tx, proc_rxtx->subframe_tx, proc_rxtx->instance_cnt_rxtx);
//LOG_D(PHY,"%s() %u/%u Just incremented proc->instance_cnt_rxtx:%d\n", __FUNCTION__, proc_rxtx->frame_tx, proc_rxtx->subframe_tx, proc_rxtx->instance_cnt_rxtx);
// We have just received and processed the common part of a subframe, say n.
// TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired
......@@ -831,6 +831,8 @@ void init_transport(PHY_VARS_eNB *eNB) {
int j;
LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
LOG_E(PHY, "Initialise transport\n");
for (i=0; i<NUMBER_OF_UE_MAX; i++) {
LOG_I(PHY,"Allocating Transport Channel Buffers for DLSCH, UE %d\n",i);
for (j=0; j<2; j++) {
......@@ -899,7 +901,7 @@ void init_eNB_afterRU(void) {
LOG_I(PHY,"RC.nb_CC[inst]:%d\n", RC.nb_CC[inst]);
for (CC_id=0;CC_id<RC.nb_CC[inst];CC_id++) {
LOG_I(PHY,"RC.nb_CC[inst:%d][CC_id:%d]:%d\n", inst, CC_id, RC.eNB[inst][CC_id]);
LOG_I(PHY,"RC.nb_CC[inst:%d][CC_id:%d]:%p\n", inst, CC_id, RC.eNB[inst][CC_id]);
eNB = RC.eNB[inst][CC_id];
phy_init_lte_eNB(eNB,0,0);
......@@ -907,10 +909,15 @@ void init_eNB_afterRU(void) {
if (0) AssertFatal(eNB->num_RU>0,"Number of RU attached to eNB %d is zero\n",eNB->Mod_id);
LOG_I(PHY,"Mapping RX ports from %d RUs to eNB %d\n",eNB->num_RU,eNB->Mod_id);
eNB->frame_parms.nb_antennas_rx = 0;
LOG_E(PHY,"Overwriting eNB->prach_vars.rxsigF[0]:%p\n", eNB->prach_vars.rxsigF[0]);
eNB->prach_vars.rxsigF[0] = (int16_t**)malloc16(64*sizeof(int16_t*));
#ifdef Rel14
for (int ce_level=0;ce_level<4;ce_level++)
for (int ce_level=0;ce_level<4;ce_level++) {
LOG_E(PHY,"Overwriting eNB->prach_vars_br.rxsigF.rxsigF[0]:%p\n", eNB->prach_vars_br.rxsigF[ce_level]);
eNB->prach_vars_br.rxsigF[ce_level] = (int16_t**)malloc16(64*sizeof(int16_t*));
}
#endif
LOG_I(PHY,"eNB->num_RU:%d\n", eNB->num_RU);
......@@ -945,12 +952,20 @@ void init_eNB_afterRU(void) {
LOG_I(PHY, "%s() ************* DJP ***** eNB->frame_parms.nb_antennas_rx:%d - GOING TO HARD CODE TO 1", __FUNCTION__, eNB->frame_parms.nb_antennas_rx);
eNB->frame_parms.nb_antennas_rx = 1;
}
else
{
LOG_I(PHY," Delete code\n");
}
if (eNB->frame_parms.nb_antennas_tx < 1)
{
LOG_I(PHY, "%s() ************* DJP ***** eNB->frame_parms.nb_antennas_tx:%d - GOING TO HARD CODE TO 1", __FUNCTION__, eNB->frame_parms.nb_antennas_tx);
eNB->frame_parms.nb_antennas_tx = 1;
}
else
{
LOG_I(PHY," Delete code\n");
}
......
......@@ -679,6 +679,7 @@ void fh_if4p5_north_out(RU_t *ru) {
if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 0 );
}
void rx_rf(RU_t *ru,int *frame,int *subframe) {
RU_proc_t *proc = &ru->proc;
......@@ -728,11 +729,13 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) {
proc->subframe_tx = (proc->subframe_rx+4)%10;
proc->frame_tx = (proc->subframe_rx>5) ? (proc->frame_rx+1)&1023 : proc->frame_rx;
#if 0
LOG_D(PHY,"RU %d/%d TS %llu (off %d), frame %d, subframe %d\n",
ru->idx,
0,
(unsigned long long int)proc->timestamp_rx,
(int)ru->ts_offset,proc->frame_rx,proc->subframe_rx);
#endif
// dump VCD output for first RU in list
if (ru == RC.ru[0]) {
......@@ -799,7 +802,7 @@ void tx_rf(RU_t *ru) {
(proc->frame_tx % 10 ==0 && proc->subframe_tx==5)
)
{
LOG_E(PHY,"%s() nb_tx:%d i:%d samples_per_tti:%u subframe_tx:%u txp[i]\n", __FUNCTION__, ru->nb_tx, i, fp->samples_per_tti, proc->subframe_tx, txp[i]);
LOG_E(PHY,"%s() nb_tx:%d i:%d samples_per_tti:%u subframe_tx:%u txp[%d]:%p\n", __FUNCTION__, ru->nb_tx, i, fp->samples_per_tti, proc->subframe_tx, i,txp[i]);
}
}
}
......@@ -813,7 +816,7 @@ void tx_rf(RU_t *ru) {
)
)
{
uint32_t *tx0p = &txp[0];
uint32_t *tx0p = (uint32_t*)txp;
LOG_E(PHY,"%s() nb_tx:%d first_carrier_offset:%u samples_per_tti:%u subframe_tx:%u sf:%u(%u) txp:%2x %2x %2x %2x %2x %2x %2x %2x\n",
__FUNCTION__, ru->nb_tx, fp->first_carrier_offset, fp->samples_per_tti, proc->subframe_tx,
......@@ -885,8 +888,8 @@ void tx_rf(RU_t *ru) {
ru->nb_tx,
flags);
LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, subframe %d\n",ru->idx,
(long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx);
//LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, subframe %d\n",ru->idx,
//(long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );
......@@ -1013,11 +1016,13 @@ static void* ru_thread_prach( void* param ) {
thread_top_init("ru_thread_prach",1,500000L,1000000L,20000000L);
LOG_E(PHY,"In rach thread\n");
while (RC.ru_mask>0) {
usleep(1e6);
LOG_I(PHY,"%s() RACH waiting for RU to be configured\n");
LOG_I(PHY,"%s() RACH waiting for RU to be configured\n", __FUNCTION__);
}
LOG_I(PHY,"%s() RU configured - RACH processing thread running\n");
LOG_I(PHY,"%s() RU configured - RACH processing thread running\n", __FUNCTION__);
while (!oai_exit) {
......@@ -1180,14 +1185,14 @@ void wakeup_eNBs(RU_t *ru) {
int i;
PHY_VARS_eNB **eNB_list = ru->eNB_list;
LOG_D(PHY,"wakeup_eNBs (num %d) for RU %d\n",ru->num_eNB,ru->idx);
//LOG_D(PHY,"wakeup_eNBs (num %d) for RU %d\n",ru->num_eNB,ru->idx);
if (ru->num_eNB==1 && ru->eNB_top!=0) {
// call eNB function directly
char string[20];
sprintf(string,"Incoming RU %d",ru->idx);
LOG_D(PHY,"RU %d Waking up eNB\n",ru->idx);
//LOG_D(PHY,"RU %d Waking up eNB\n",ru->idx);
ru->eNB_top(eNB_list[0],ru->proc.frame_rx,ru->proc.subframe_rx,string);
}
else {
......@@ -1219,7 +1224,7 @@ static inline int wakeup_prach_ru(RU_t *ru) {
ru->eNB_list[0]->proc.frame_prach = ru->proc.frame_rx;
ru->eNB_list[0]->proc.subframe_prach = ru->proc.subframe_rx;
LOG_D(PHY,"RU %d: waking up PRACH thread\n",ru->idx);
//LOG_D(PHY,"RU %d: waking up PRACH thread\n",ru->idx);
// the thread can now be woken up
AssertFatal(pthread_cond_signal(&ru->proc.cond_prach) == 0, "ERROR pthread_cond_signal for RU prach thread\n");
}
......@@ -1486,24 +1491,15 @@ static void* ru_thread( void* param ) {
subframe++;
}
LOG_D(PHY,"RU thread (proc %p), frame %d (%p), subframe %d (%p)\n", proc, frame,&frame,subframe,&subframe);
ru->proc.frame_rx = frame;
ru->proc.subframe_rx = subframe;
ru->proc.frame_tx = subframe>9 ? (frame+1)&1023 : frame;
ru->proc.subframe_tx = subframe+1 % 10;
proc->frame_rx = ru->proc.frame_rx;
proc->subframe_rx = ru->proc.subframe_rx;
// synchronization on input FH interface, acquire signals/data and block
if (ru->fh_south_in) ru->fh_south_in(ru,&frame,&subframe);
else AssertFatal(1==0, "No fronthaul interface at south port");
oai_subframe_ind(frame, subframe);
//LOG_D(PHY,"AFTER fh_south_in - SFN/SF(RX):%d/%d (TX):%d/%d proc:%p ru->proc:%p\n",frame,subframe,proc->frame_tx,proc->subframe_tx,proc,&ru->proc);
oai_subframe_ind(proc->frame_tx, proc->subframe_tx);
if (0 && is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx))
LOG_D(PHY,"RU thread (do_prach %d, is_prach_subframe %d), received frame %d, subframe %d\n",
ru->do_prach,
is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx),
......@@ -1666,6 +1662,7 @@ void init_RU_proc(RU_t *ru) {
#endif
char name[100];
LOG_E(PHY,"Initializing RU proc %d (%s,%s),\n",ru->idx,eNB_functions[ru->function],eNB_timing[ru->if_timing]);
#ifndef OCP_FRAMEWORK
LOG_I(PHY,"Initializing RU proc %d (%s,%s),\n",ru->idx,eNB_functions[ru->function],eNB_timing[ru->if_timing]);
#endif
......@@ -1720,6 +1717,8 @@ void init_RU_proc(RU_t *ru) {
pthread_create( &proc->pthread_FH, attr_FH, ru_thread, (void*)ru );
LOG_E(PHY,"%s() DJP - ru->function:%d\n", __FUNCTION__, ru->function);
if (ru->function == NGFI_RRU_IF4p5) {
pthread_create( &proc->pthread_prach, attr_prach, ru_thread_prach, (void*)ru );
#ifdef Rel14
......@@ -1932,13 +1931,15 @@ void init_RU(char *rf_config_file) {
// read in configuration file)
printf("configuring RU from file\n");
RCconfig_RU();
printf("number of L1 instances %d, number of RU %d\n",RC.nb_L1_inst,RC.nb_RU);
printf("number of L1 instances %d, number of RU %d RC.nb_CC[0]:%d\n",RC.nb_L1_inst,RC.nb_RU, RC.nb_CC[0]);
if (RC.nb_CC != 0)
for (i=0;i<RC.nb_L1_inst;i++)
for (CC_id=0;CC_id<RC.nb_CC[i];CC_id++) RC.eNB[i][CC_id]->num_RU=0;
LOG_E(PHY,"Process RUs RC.nb_RU:%d\n",RC.nb_RU);
for (ru_id=0;ru_id<RC.nb_RU;ru_id++) {
LOG_E(PHY,"Process RC.ru[%d]\n",ru_id);
ru = RC.ru[ru_id];
ru->rf_config_file = rf_config_file;
ru->idx = ru_id;
......@@ -1957,6 +1958,10 @@ void init_RU(char *rf_config_file) {
// DJP - feptx_prec() / feptx_ofdm() parses the eNB_list (based on num_eNB) and copies the txdata_F to txdata in RU
//
}
else
{
LOG_E(PHY,"DJP - delete code above this %s:%d\n", __FILE__, __LINE__);
}
eNB0 = ru->eNB_list[0];
printf("RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south);
......@@ -1971,22 +1976,18 @@ void init_RU(char *rf_config_file) {
memcpy((void*)&ru->frame_parms,(void*)&eNB0->frame_parms,sizeof(LTE_DL_FRAME_PARMS));
// attach all RU to all eNBs in its list/
LOG_E(PHY,"ru->num_eNB:%d eNB0->num_RU:%d\n", ru->num_eNB, eNB0->num_RU);
for (i=0;i<ru->num_eNB;i++) {
eNB0 = ru->eNB_list[i];
eNB0->RU_list[eNB0->num_RU++] = ru;
}
}
}
else
{
printf("eNB0 was NULL - DJP - missing out of copying of frame_params - NOT A GOOD THING TO MISS\n\n\n\n\n");
//extern uint8_t n_rb_dl;
//ru->frame_parms.N_RB_DL = n_rb_dl;
//printf("ru->frame_parms.N_RB_DL:%d\n", ru->frame_parms.N_RB_DL);
}
// LOG_I(PHY,"Initializing RRU descriptor %d : (%s,%s,%d)\n",ru_id,ru_if_types[ru->if_south],eNB_timing[ru->if_timing],ru->function);
LOG_E(PHY,"ru->if_south:%d\n", ru->if_south);
switch (ru->if_south) {
case LOCAL_RF: // this is an RU with integrated RF (RRU, eNB)
if (ru->function == NGFI_RRU_IF5) { // IF5 RRU
......
......@@ -116,6 +116,8 @@ pthread_cond_t nfapi_sync_cond;
pthread_mutex_t nfapi_sync_mutex;
int nfapi_sync_var=-1; //!< protected by mutex \ref nfapi_sync_mutex
uint8_t nfapi_pnf = 0;
pthread_cond_t sync_cond;
pthread_mutex_t sync_mutex;
int sync_var=-1; //!< protected by mutex \ref sync_mutex.
......@@ -209,6 +211,12 @@ uint64_t num_missed_slots=0; // counter for the number of missed slots
extern void reset_opp_meas(void);
extern void print_opp_meas(void);
extern PHY_VARS_UE* init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms,
uint8_t UE_id,
uint8_t abstraction_flag);
extern void init_eNB_afterRU(void);
int transmission_mode=1;
......@@ -838,7 +846,7 @@ void init_openair0() {
void wait_RUs(void) {
LOG_I(PHY,"Waiting for RUs to be configured ...\n");
LOG_I(PHY,"Waiting for RUs to be configured ... RC.ru_mask:%02x\n", RC.ru_mask);
// wait for all RUs to be configured over fronthaul
pthread_mutex_lock(&RC.ru_mutex);
......@@ -847,6 +855,7 @@ void wait_RUs(void) {
while (RC.ru_mask>0) {
pthread_cond_wait(&RC.ru_cond,&RC.ru_mutex);
printf("RC.ru_mask:%02x\n", RC.ru_mask);
}
LOG_I(PHY,"RUs configured\n");
......@@ -890,8 +899,6 @@ static inline void wait_nfapi_init(char *thread_name) {
printf( "NFAPI: got sync (%s)\n", thread_name);
}
uint8_t nfapi_pnf = 0;
int main( int argc, char **argv )
{
int i;
......@@ -1189,6 +1196,23 @@ int main( int argc, char **argv )
}
}
// Will have parsed the config files by now
printf("NFAPI_PNF:%d\n", nfapi_pnf);
if (nfapi_pnf==1) // PNF
{
set_comp_log(PHY, LOG_DEBUG, LOG_FULL, 1);
printf("DJP - forcing PHY to DEBUG - should see similar line if it works\n");
LOG_E(PHY,"%s() DJP - forcing PHY to LOG_DEBUG for PNF\n", __FUNCTION__);
}
else if (nfapi_pnf == 2) // VNF
{
set_comp_log(MAC, LOG_DEBUG, LOG_FULL, 1);
set_comp_log(RRC, LOG_INFO, LOG_FULL, 1);
printf("DJP - forcing MAC to DEBUG - should see similar line if it works\n");
LOG_E(PHY,"%s() DJP - forcing MAC to LOG_DEBUG for VNF\n", __FUNCTION__);
}
......@@ -1279,7 +1303,7 @@ int main( int argc, char **argv )
nfapi_mode_str = "VNF";
break;
}
printf("NFAPI MODE:%s (1-PNF 2-VNF)\n", nfapi_mode_str);
printf("NFAPI MODE:%s\n", nfapi_mode_str);
if (nfapi_pnf==2) // VNF
wait_nfapi_init("main?");
......@@ -1323,7 +1347,13 @@ int main( int argc, char **argv )
config_sync_var=0;
if (nfapi_pnf==1) // PNF
{
//set_comp_log(PHY, LOG_DEBUG, LOG_FULL, 1);
//printf("DJP - forcing PHY to DEBUG - should see similar line if it works\n");
//LOG_E(PHY,"%s() DJP - forcing PHY to LOG_DEBUG for PNF\n", __FUNCTION__);
wait_nfapi_init("main?");
}
printf("wait RUs\n");
wait_RUs();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment