Commit 245f1e06 authored by rmagueta's avatar rmagueta

Improvements in RA-Msg4

parent ab3794e6
......@@ -654,20 +654,20 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr
} else {
if (ra->RA_window_cnt >= 0 && rnti == ra->ra_rnti){
dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_RA_DLSCH;
pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = NULL;
} else {
dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_DLSCH;
if(pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition == NULL)
pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition=calloc(1,sizeof(*pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition));
}
if( (ra->RA_window_cnt >= 0 && rnti == ra->ra_rnti) || (rnti == ra->t_crnti) ) {
dlsch_config_pdu_1_0->BWPSize = NRRIV2BW(mac->scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
dlsch_config_pdu_1_0->BWPStart = NRRIV2PRBOFFSET(mac->scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = NULL;
} else {
dlsch_config_pdu_1_0->BWPSize = NRRIV2BW(mac->DLbwp[0]->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
dlsch_config_pdu_1_0->BWPStart = NRRIV2PRBOFFSET(mac->DLbwp[0]->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
dlsch_config_pdu_1_0->SubcarrierSpacing = mac->DLbwp[0]->bwp_Common->genericParameters.subcarrierSpacing;
if(pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition == NULL)
pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition=calloc(1,sizeof(*pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition));
}
BWPSize = n_RB_DLBWP;
......
......@@ -909,7 +909,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra
LOG_I(NR_MAC,"[gNB %d][RAPROC] CC_id %d Frame %d, slotP %d: Generating RA-Msg2 DCI, rnti 0x%x, state %d\n",
module_idP, CC_id, frameP, slotP, ra->RA_rnti, ra->state);
AssertFatal(ra->secondaryCellGroup, "no secondaryCellGroup for RNTI %04x\n", ra->crnti);
AssertFatal(ra->secondaryCellGroup, "no secondaryCellGroup for RNTI %04x\n", ra->RA_rnti);
AssertFatal(ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count == 1,
"downlinkBWP_ToAddModList has %d BWP!\n",
......@@ -1054,53 +1054,42 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra
if (ra->Msg4_frame == frameP && ra->Msg4_slot == slotP ) {
uint8_t time_domain_assignment = 0;
uint8_t mcsIndex = 0;
uint8_t mac_sdu[30] = {};
uint8_t mac_pdu[100] = {};
uint16_t mac_pdu_length = 0;
const int offset = nr_write_ce_dlsch_pdu(module_idP, nr_mac->sched_ctrlCommon, (unsigned char *)mac_pdu, 255, ra->cont_res_id);
mac_pdu_length += offset;
uint8_t mac_sdu[30];
uint16_t mac_sdu_length = mac_rrc_nr_data_req(module_idP, CC_id, frameP, CCCH, ra->rnti, 1, mac_sdu);
NR_SearchSpace_t *ss = nr_mac->sched_ctrlCommon->search_space;
NR_BWP_Downlink_t *bwp = nr_mac->sched_ctrlCommon->active_bwp;
NR_ControlResourceSet_t *coreset = nr_mac->sched_ctrlCommon->coreset;
NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
long BWPSize = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
long BWPStart = NRRIV2PRBOFFSET(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
// Bytes to be transmitted
uint16_t mac_sdu_length = mac_rrc_nr_data_req(module_idP, CC_id, frameP, CCCH, ra->rnti, 1, mac_sdu);
uint16_t mac_pdu_length = nr_write_ce_dlsch_pdu(module_idP, nr_mac->sched_ctrlCommon, (unsigned char *)mac_pdu, 255, ra->cont_res_id);
((NR_MAC_SUBHEADER_SHORT *) &mac_pdu[mac_pdu_length])->R = 0;
((NR_MAC_SUBHEADER_SHORT *) &mac_pdu[mac_pdu_length])->F = 0;
((NR_MAC_SUBHEADER_SHORT *) &mac_pdu[mac_pdu_length])->LCID = DL_SCH_LCID_CCCH;
((NR_MAC_SUBHEADER_SHORT *) &mac_pdu[mac_pdu_length])->L = mac_sdu_length * 8;
mac_pdu_length += 2;
memcpy(&mac_pdu[mac_pdu_length], mac_sdu, sizeof(uint8_t) * mac_sdu_length);
mac_pdu_length += mac_sdu_length;
LOG_I(NR_MAC, "[gNB %d] Got %d bytes from CCCH\n", module_idP, mac_sdu_length);
//int header_length_total = 1 + 6 + 2 + (mac_sdu_length >= 128);
//int payload_length = mac_sdu_length + header_length_total;
int mcsIndex = 0;
int mcsTableIndex = 0;
int startSymbolAndLength = 0;
int StartSymbolIndex = 2;
int NrOfSymbols = 12;
int StartSymbolIndex_tmp = 0;
int NrOfSymbols_tmp = 0;
int x_Overhead = 0;
int time_domain_assignment = 0;
int rbStart = 0;
int rbSize = 0;
uint8_t nr_of_candidates = 0;
uint8_t aggregation_level = 0;
uint16_t *vrb_map = cc[CC_id].vrb_map;
// Calculate number of symbols
int startSymbolIndex, nrOfSymbols;
const int startSymbolAndLength = bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[time_domain_assignment]->startSymbolAndLength;
SLIV2SL(startSymbolAndLength, &startSymbolIndex, &nrOfSymbols);
AssertFatal(startSymbolIndex >= 0, "StartSymbolIndex is negative\n");
NR_SearchSpace_t *ss = nr_mac->sched_ctrlCommon->search_space;
NR_BWP_Downlink_t *bwp = nr_mac->sched_ctrlCommon->active_bwp;
NR_ControlResourceSet_t *coreset = nr_mac->sched_ctrlCommon->coreset;
NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
uint16_t dlDmrsSymbPos = fill_dmrs_mask(nr_mac->sched_ctrlCommon->active_bwp->bwp_Dedicated->pdsch_Config->choice.setup,
nr_mac->common_channels->ServingCellConfigCommon->dmrs_TypeA_Position,
nrOfSymbols,
startSymbolIndex);
long BWPSize = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
long BWPStart = NRRIV2PRBOFFSET(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
uint16_t N_DMRS_SLOT = get_num_dmrs(dlDmrsSymbPos);
long dmrsConfigType = bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type == NULL ? 0 : 1;
uint8_t N_PRB_DMRS = 0;
......@@ -1111,18 +1100,26 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra
N_PRB_DMRS = nr_mac->sched_ctrlCommon->numDmrsCdmGrpsNoData * 4;
}
uint8_t N_DMRS_SLOT = get_num_dmrs_symbols(NULL,
RC.nrmac[module_idP]->common_channels->ServingCellConfigCommon->dmrs_TypeA_Position,
NrOfSymbols,
StartSymbolIndex);
uint8_t mcsTableIdx = 0;
if (bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table == NULL)
mcsTableIdx = 0;
else{
if (*bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table == 0)
mcsTableIdx = 1;
else
mcsTableIdx = 2;
}
int rbStart = 0;
int rbSize = 0;
uint32_t TBS = 0;
uint8_t tb_scaling = 0;
uint16_t *vrb_map = cc[CC_id].vrb_map;
do {
rbSize++;
TBS = nr_compute_tbs(nr_get_Qm_dl(mcsIndex, mcsTableIndex),
nr_get_code_rate_dl(mcsIndex, mcsTableIndex),
rbSize, NrOfSymbols, N_PRB_DMRS * N_DMRS_SLOT,0, 0,1) >> 3;
TBS = nr_compute_tbs(nr_get_Qm_dl(mcsIndex, mcsTableIdx),
nr_get_code_rate_dl(mcsIndex, mcsTableIdx),
rbSize, nrOfSymbols, N_PRB_DMRS * N_DMRS_SLOT, 0, tb_scaling,1) >> 3;
} while (rbStart + rbSize < BWPSize && !vrb_map[rbStart + rbSize] && TBS < mac_pdu_length);
for (int i = 0; (i < rbSize) && (rbStart <= (BWPSize - rbSize)); i++) {
......@@ -1133,7 +1130,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra
}
if (rbStart > (BWPSize - rbSize)) {
LOG_E(NR_MAC, "%s(): cannot find free vrb_map for RA RNTI %04x!\n", __func__, ra->RA_rnti);
LOG_E(NR_MAC, "%s(): cannot find free vrb_map for RNTI %04x!\n", __func__, ra->rnti);
return;
}
......@@ -1144,17 +1141,12 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra
return;
}
uint8_t aggregation_level;
uint8_t nr_of_candidates;
find_aggregation_candidates(&aggregation_level, &nr_of_candidates, ss);
int CCEIndex = allocate_nr_CCEs(nr_mac,
bwp,
coreset,
aggregation_level,
0,
0,
nr_of_candidates);
int CCEIndex = allocate_nr_CCEs(nr_mac, bwp, coreset, aggregation_level,0,0,nr_of_candidates);
if (CCEIndex < 0) {
LOG_E(NR_MAC, "%s(): cannot find free CCE for RNTI %04x!\n", __func__, ra->rnti);
LOG_E(MAC, "%s(): cannot find free CCE for RA RNTI %04x!\n", __func__, ra->rnti);
return;
}
......@@ -1187,44 +1179,33 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra
LOG_I(NR_MAC,"[gNB %d] [RAPROC] CC_id %d Frame %d, slotP %d: Generating RA-Msg4 DCI, state %d\n", module_idP, CC_id, frameP, slotP, ra->state);
AssertFatal(ra->secondaryCellGroup, "no secondaryCellGroup for RNTI %04x\n", ra->rnti);
AssertFatal(ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count == 1,
"downlinkBWP_ToAddModList has %d BWP!\n",
ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count);
pdsch_pdu_rel15->pduBitmap = 0;
pdsch_pdu_rel15->rnti = ra->rnti;
// SCF222: PDU index incremented for each PDSCH PDU sent in TX control message. This is used to associate control
// information to data and is reset every slot.
const int pduindex = nr_mac->pdu_index[CC_id]++;
pdsch_pdu_rel15->pduBitmap = 0;
pdsch_pdu_rel15->rnti = ra->rnti;
pdsch_pdu_rel15->pduIndex = pduindex;
pdsch_pdu_rel15->BWPSize = BWPSize;
pdsch_pdu_rel15->BWPStart = BWPStart;
pdsch_pdu_rel15->SubcarrierSpacing = bwp->bwp_Common->genericParameters.subcarrierSpacing;
pdsch_pdu_rel15->CyclicPrefix = 0;
pdsch_pdu_rel15->NrOfCodewords = 1;
pdsch_pdu_rel15->targetCodeRate[0] = nr_get_code_rate_dl(mcsIndex,mcsTableIndex);
pdsch_pdu_rel15->targetCodeRate[0] = nr_get_code_rate_dl(mcsIndex,mcsTableIdx);
pdsch_pdu_rel15->qamModOrder[0] = 2;
pdsch_pdu_rel15->mcsIndex[0] = mcsIndex;
/*
if (bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table == NULL) {
pdsch_pdu_rel15->mcsTable[0] = 0;
} else {
if (*bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table == 0) {
pdsch_pdu_rel15->mcsTable[0] = 1;
} else {
pdsch_pdu_rel15->mcsTable[0] = 2;
}
}
*/
pdsch_pdu_rel15->mcsTable[0] = mcsTableIdx;
pdsch_pdu_rel15->rvIndex[0] = 0;
pdsch_pdu_rel15->dataScramblingId = *scc->physCellId;
pdsch_pdu_rel15->nrOfLayers = 1;
pdsch_pdu_rel15->transmissionScheme = 0;
pdsch_pdu_rel15->refPoint = 0;
pdsch_pdu_rel15->dmrsConfigType = bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type == NULL ? 0 : 1;
pdsch_pdu_rel15->dmrsConfigType = dmrsConfigType;
pdsch_pdu_rel15->dlDmrsScramblingId = *scc->physCellId;
pdsch_pdu_rel15->SCID = 0;
pdsch_pdu_rel15->numDmrsCdmGrpsNoData = 2;
......@@ -1233,23 +1214,12 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra
pdsch_pdu_rel15->rbStart = rbStart;
pdsch_pdu_rel15->rbSize = rbSize;
pdsch_pdu_rel15->VRBtoPRBMapping = 0;
pdsch_pdu_rel15->StartSymbolIndex = startSymbolIndex;
pdsch_pdu_rel15->NrOfSymbols = nrOfSymbols;
pdsch_pdu_rel15->dlDmrsSymbPos = dlDmrsSymbPos;
// FIXME: should use Initial BWP and maybe Default values from TS 38.214 Table 5.1.2.1.1-1
for (int i=0; i<bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.count; i++) {
startSymbolAndLength = bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[i]->startSymbolAndLength;
SLIV2SL(startSymbolAndLength, &StartSymbolIndex_tmp, &NrOfSymbols_tmp);
//if (NrOfSymbols_tmp < NrOfSymbols) {
NrOfSymbols = NrOfSymbols_tmp;
StartSymbolIndex = StartSymbolIndex_tmp;
time_domain_assignment = i; // this is short PDSCH added to the config to fit mixed slot
//}
break;
}
AssertFatal(StartSymbolIndex >= 0, "StartSymbolIndex is negative\n");
pdsch_pdu_rel15->StartSymbolIndex = StartSymbolIndex;
pdsch_pdu_rel15->NrOfSymbols = NrOfSymbols;
pdsch_pdu_rel15->dlDmrsSymbPos = fill_dmrs_mask(NULL, scc->dmrs_TypeA_Position, NrOfSymbols, StartSymbolIndex);
int x_Overhead = 0;
nr_get_tbs_dl(&dl_tti_pdsch_pdu->pdsch_pdu, x_Overhead, pdsch_pdu_rel15->numDmrsCdmGrpsNoData, tb_scaling);
// Fill PDCCH DL DCI PDU
nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci];
......@@ -1270,7 +1240,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra
dci_payload.time_domain_assignment.val = time_domain_assignment;
dci_payload.vrb_to_prb_mapping.val = 0;
dci_payload.mcs = pdsch_pdu_rel15->mcsIndex[0];
dci_payload.tb_scaling = 0;
dci_payload.tb_scaling = tb_scaling;
LOG_D(NR_MAC,
"[RAPROC] DCI type 1 payload: freq_alloc %d (%d,%d,%d), time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d \n",
......@@ -1301,16 +1271,8 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra
pdsch_pdu_rel15->BWPSize,
nr_mac->sched_ctrlCommon->active_bwp->bwp_Id);
x_Overhead = 0;
nr_get_tbs_dl(&dl_tti_pdsch_pdu->pdsch_pdu, x_Overhead, pdsch_pdu_rel15->numDmrsCdmGrpsNoData, dci_payload.tb_scaling);
//LOG_I(NR_MAC, "Configuring DL_TX in %d.%d: TBS %d, header_length_total %d, sdu_length_total %d,cont_res_len %d, post_padding %d \n", frameP, slotP,
// TBS, header_length_total, payload_length, cont_res_len, post_padding);
// DL TX request
nfapi_nr_pdu_t *tx_req = &nr_mac->TX_req[CC_id].pdu_list[nr_mac->TX_req[CC_id].Number_of_PDUs];
memcpy(&tx_req->TLVs[0].value.direct, mac_pdu, sizeof(uint8_t) * TBS);
tx_req->PDU_length = TBS;
tx_req->PDU_index = pduindex;
......@@ -1324,22 +1286,24 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra
for (int rb = 0; rb < pdsch_pdu_rel15->rbSize; rb++) {
vrb_map[rb + pdsch_pdu_rel15->rbStart] = 1;
}
ra->state = WAIT_Msg4_ACK;
LOG_D(MAC,"BWPSize: %i\n", pdcch_pdu_rel15->BWPSize);
LOG_D(MAC,"BWPStart: %i\n", pdcch_pdu_rel15->BWPStart);
LOG_D(MAC,"SubcarrierSpacing: %i\n", pdcch_pdu_rel15->SubcarrierSpacing);
LOG_D(MAC,"CyclicPrefix: %i\n", pdcch_pdu_rel15->CyclicPrefix);
LOG_D(MAC,"StartSymbolIndex: %i\n", pdcch_pdu_rel15->StartSymbolIndex);
LOG_D(MAC,"DurationSymbols: %i\n", pdcch_pdu_rel15->DurationSymbols);
for(int n=0;n<6;n++) LOG_D(MAC,"FreqDomainResource[%i]: %x\n",n, pdcch_pdu_rel15->FreqDomainResource[n]);
LOG_D(MAC,"CceRegMappingType: %i\n", pdcch_pdu_rel15->CceRegMappingType);
LOG_D(MAC,"RegBundleSize: %i\n", pdcch_pdu_rel15->RegBundleSize);
LOG_D(MAC,"InterleaverSize: %i\n", pdcch_pdu_rel15->InterleaverSize);
LOG_D(MAC,"CoreSetType: %i\n", pdcch_pdu_rel15->CoreSetType);
LOG_D(MAC,"ShiftIndex: %i\n", pdcch_pdu_rel15->ShiftIndex);
LOG_D(MAC,"precoderGranularity: %i\n", pdcch_pdu_rel15->precoderGranularity);
LOG_D(MAC,"numDlDci: %i\n", pdcch_pdu_rel15->numDlDci);
LOG_D(NR_MAC,"BWPSize: %i\n", pdcch_pdu_rel15->BWPSize);
LOG_D(NR_MAC,"BWPStart: %i\n", pdcch_pdu_rel15->BWPStart);
LOG_D(NR_MAC,"SubcarrierSpacing: %i\n", pdcch_pdu_rel15->SubcarrierSpacing);
LOG_D(NR_MAC,"CyclicPrefix: %i\n", pdcch_pdu_rel15->CyclicPrefix);
LOG_D(NR_MAC,"StartSymbolIndex: %i\n", pdcch_pdu_rel15->StartSymbolIndex);
LOG_D(NR_MAC,"DurationSymbols: %i\n", pdcch_pdu_rel15->DurationSymbols);
for(int n=0;n<6;n++) LOG_D(NR_MAC,"FreqDomainResource[%i]: %x\n",n, pdcch_pdu_rel15->FreqDomainResource[n]);
LOG_D(NR_MAC,"CceRegMappingType: %i\n", pdcch_pdu_rel15->CceRegMappingType);
LOG_D(NR_MAC,"RegBundleSize: %i\n", pdcch_pdu_rel15->RegBundleSize);
LOG_D(NR_MAC,"InterleaverSize: %i\n", pdcch_pdu_rel15->InterleaverSize);
LOG_D(NR_MAC,"CoreSetType: %i\n", pdcch_pdu_rel15->CoreSetType);
LOG_D(NR_MAC,"ShiftIndex: %i\n", pdcch_pdu_rel15->ShiftIndex);
LOG_D(NR_MAC,"precoderGranularity: %i\n", pdcch_pdu_rel15->precoderGranularity);
LOG_D(NR_MAC,"numDlDci: %i\n", pdcch_pdu_rel15->numDlDci);
ra->state = WAIT_Msg4_ACK;
LOG_I(MAC,"[gNB %d][RAPROC] Frame %d, Subframe %d: RA state %d\n", module_idP, frameP, slotP, ra->state);
}
}
......
......@@ -49,7 +49,6 @@ nr_mac_rrc_data_ind_ue(
const uint8_t* pduP,
const sdu_size_t pdu_len){
sdu_size_t sdu_size = 0;
protocol_ctxt_t ctxt;
switch(channel){
case NR_BCCH_BCH:
......@@ -62,7 +61,7 @@ nr_mac_rrc_data_ind_ue(
case CCCH:
if (pdu_len>0) {
LOG_T(NR_RRC,"[UE %d] Received SDU for CCCH on SRB %ld from gNB %d\n",module_id,channel & RAB_OFFSET,gNB_index);
LOG_T(NR_RRC,"[UE %d] Received SDU for CCCH on SRB %u from gNB %d\n",module_id,channel & RAB_OFFSET,gNB_index);
MessageDef *message_p;
int msg_sdu_size = CCCH_SDU_SIZE;
......
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