Commit b0bc5e65 authored by WEI-TAI CHEN's avatar WEI-TAI CHEN

merge develop-nr

parents dbdcf5b2 940eae3e
#ifndef _NFAPI_INTERFACE_NR_H_
#define _NFAPI_INTERFACE_NR_H_
#ifndef _NFAPI_NR_INTERFACE_H_
#define _NFAPI_NR_INTERFACE_H_
#include "nfapi_interface.h"
......@@ -199,7 +199,7 @@ typedef struct {
typedef struct {
nfapi_p4_p5_message_header_t header;
uint8_t num_tlv;
uint8_t num_tlv;
nfapi_nr_subframe_config_t subframe_config;
nfapi_nr_rf_config_t rf_config;
nfapi_nr_sch_config_t sch_config;
......@@ -221,7 +221,7 @@ typedef enum {
NFAPI_NR_DL_DCI_FORMAT_2_0,
NFAPI_NR_DL_DCI_FORMAT_2_1,
NFAPI_NR_DL_DCI_FORMAT_2_2,
NFAPI_NR_DL_DCI_FORMAT_2_3,
NFAPI_NR_DL_DCI_FORMAT_2_3
} nfapi_nr_dl_dci_format_e;
typedef enum {
......@@ -229,22 +229,118 @@ typedef enum {
NFAPI_NR_UL_DCI_FORMAT_1_0,
} nfapi_nr_ul_dci_format_e;
typedef enum {
NFAPI_NR_RNTI_new = 0,
NFAPI_NR_RNTI_C,
NFAPI_NR_RNTI_RA,
NFAPI_NR_RNTI_P,
NFAPI_NR_RNTI_CS,
NFAPI_NR_RNTI_TC,
NFAPI_NR_RNTI_SP_CSI,
NFAPI_NR_RNTI_SI,
NFAPI_NR_RNTI_SFI,
NFAPI_NR_RNTI_INT,
NFAPI_NR_RNTI_TPC_PUSCH,
NFAPI_NR_RNTI_TPC_PUCCH,
NFAPI_NR_RNTI_TPC_SRS
} nfapi_nr_rnti_type_e ;
// P7 Sub Structures
//formats 0_0 and 0_1
typedef struct {
nfapi_tl_t tl;
// conf
uint8_t dci_format;
uint8_t cce_idx;
uint8_t aggregation_level;
uint16_t rnti;
// DCI fields
} nfapi_nr_dl_config_dci_dl_pdu_rel15_t;
#define NFAPI_NR_DL_CONFIG_REQUEST_DCI_DL_PDU_REL15_TAG
nfapi_tl_t tl;
uint8_t cce_idx;
uint8_t aggregation_level;
uint16_t rnti;
uint8_t dci_format; //1 bit
uint16_t frequency_domain_resource_assignment; //up to 9 bits
uint8_t time_domain_resource_assignment; //0, 1, 2, 3 or 4 bits
uint8_t frequency_hopping_flag; //1 bit
uint8_t mcs; //5 bits
uint8_t new_data_indicator; //1 bit
uint8_t redundancy_version; //2 bits
uint8_t harq_process; //4 bits
uint8_t tpc; //2 bits
uint16_t padding;
uint8_t ul_sul_indicator; //0 or 1 bit
uint8_t carrier_indicator; //0 or 3 bits
uint8_t bwp_indicator; //0, 1 or 2 bits
uint8_t downlink_assignment_index1; //1 or 2 bits
uint8_t downlink_assignment_index2; //0 or 2 bits
uint8_t srs_resource_indicator;
uint8_t precoding_information;
uint8_t antenna_ports;
uint8_t srs_request;
uint8_t csi_request;
uint8_t cbgti; //CBG Transmission Information: 0, 2, 4, 6 or 8 bits
uint8_t ptrs_dmrs_association;
uint8_t beta_offset_indicator; //0 or 2 bits
uint8_t dmrs_sequence_initialization; //0 or 1 bit
uint8_t ul_sch_indicator; //1 bit
} nfapi_nr_ul_config_dci_ul_pdu_rel15_t;
//#define NFAPI_NR_UL_CONFIG_REQUEST_DCI_UL_PDU_REL15_TAG 0x????
//formats 1_0, 1_1, 2_0, 2_1, 2_2 and 2_3
typedef struct {
nfapi_nr_dl_config_dci_dl_pdu_rel15_t dci_dl_pdu_rel15;
} nfapi_nr_dl_config_dci_dl_pdu;
nfapi_tl_t tl;
uint8_t cce_idx;
uint8_t aggregation_level;
uint16_t rnti;
uint8_t dci_format; //1 bit
uint16_t frequency_domain_resource_assignment; //up to 9 bits
uint8_t ra_preamble_index; //6 bits
uint8_t ul_sul_indicator; //1 bit
uint8_t ss_pbch_index; //6 bits
uint8_t prach_mask_index; //4 bits
uint16_t reserved; //1_0/C-RNTI:10 bits, 1_0/P-RNTI: 6 bits, 1_0/SI-&RA-RNTI: 16 bits
uint8_t time_domain_resource_assignment; //0, 1, 2, 3 or 4 bits
uint8_t vrb_to_prb_mapping; //0 or 1 bit
uint8_t mcs; //5 bits
uint8_t new_data_indicator; //1 bit
uint8_t redundancy_version; //2 bits
uint8_t harq_process; //4 bits
uint8_t downlink_assignment_index; //0, 2 or 4 bits
uint8_t tpc; //2 bits
uint8_t pucch_resource_indicator; //3 bits
uint8_t pdsch_to_harq_feedback_timing_indicator; //0, 1, 2 or 3 bits
uint8_t short_messages_indicator; //2 bits
uint8_t short_messages; //8 bits
uint8_t tb_scaling; //2 bits
uint8_t carrier_indicator; //0 or 3 bits
uint8_t bwp_indicator; //0, 1 or 2 bits
uint8_t prb_bundling_size_indicator; //0 or 1 bits
uint8_t rate_matching_indicator; //0, 1 or 2 bits
uint8_t zp_csi_rs_trigger; //0, 1 or 2 bits
uint8_t antenna_ports; //4, 5 or 6 bits
uint8_t transmission_configuration_indication; //0 or 3 bits
uint8_t srs_request; //2 bits
uint8_t cbgti; //CBG Transmission Information: 0, 2, 4, 6 or 8 bits
uint8_t cbgfi; //CBG Flushing Out Information: 0 or 1 bit
uint8_t dmrs_sequence_initialization; //0 or 1 bit
uint8_t slot_format_indicator_count;
uint8_t *slot_format_indicators;
uint8_t pre_emption_indication_count;
uint16_t *pre_emption_indications; //14 bit
uint8_t block_number_count;
uint8_t *block_numbers;
} nfapi_nr_dl_config_dci_dl_pdu_rel15_t;
//#define NFAPI_NR_DL_CONFIG_REQUEST_DCI_DL_PDU_REL15_TAG 0x????
typedef struct{
......@@ -319,6 +415,7 @@ typedef struct {
uint8_t pdu_size;
union {
nfapi_nr_dl_config_dci_dl_pdu_rel15_t dci_dl_pdu_rel15;
nfapi_nr_ul_config_dci_ul_pdu_rel15_t dci_ul_pdu_rel15;
nfapi_nr_dl_config_bch_pdu_rel15_t bch_pdu_rel15;
nfapi_nr_dl_config_dlsch_pdu_rel15_t dlsch_pdu_rel15;
nfapi_nr_dl_config_pch_pdu_rel15_t pch_pdu_rel15;
......@@ -326,7 +423,6 @@ typedef struct {
nfapi_nr_dl_config_npdcch_pdu_rel15_t npdcch_pdu_rel15;
nfapi_nr_dl_config_ndlsch_pdu_rel15_t ndlsch_pdu_rel15;
};
} nfapi_nr_dl_config_request_pdu_t;
typedef struct {
......
......@@ -230,7 +230,7 @@ void phy_config_request(PHY_Config_t *phy_config) {
uint8_t Mod_id = phy_config->Mod_id;
int CC_id = phy_config->CC_id;
nfapi_config_request_t *cfg = phy_config->cfg;
nfapi_nr_config_request_t *cfg = phy_config->cfg;
NR_DL_FRAME_PARMS *fp;
PHICH_RESOURCE_t phich_resource_table[4]={oneSixth,half,one,two};
......@@ -345,7 +345,7 @@ void install_schedule_handlers(IF_Module_t *if_inst)
/*void nr_phy_config_request(PHY_VARS_gNB *gNB)
{
NR_DL_FRAME_PARMS *fp = &gNB->frame_parms;
nfapi_config_request_t *gNB_config = &gNB->gNB_config;
nfapi_nr_config_request_t *gNB_config = &gNB->gNB_config;
//overwrite for new NR parameters
gNB_config->nfapi_config.rf_bands.rf_band[0] = 22;
......
......@@ -151,7 +151,7 @@ int nr_init_frame_parms(nfapi_nr_config_request_t* config,
return 0;
}
int nr_init_frame_parms_ue(nfapi_config_request_t* config,
int nr_init_frame_parms_ue(nfapi_nr_config_request_t* config,
NR_DL_FRAME_PARMS *frame_parms)
{
......
......@@ -375,7 +375,7 @@ void phy_config_request(PHY_Config_t *phy_config);
int init_frame_parms(LTE_DL_FRAME_PARMS *frame_parms,uint8_t osf);
void dump_frame_parms(LTE_DL_FRAME_PARMS *frame_parms);
int nr_init_frame_parms(nfapi_nr_config_request_t* config, NR_DL_FRAME_PARMS *frame_parms);
int nr_init_frame_parms_ue(nfapi_config_request_t* config, NR_DL_FRAME_PARMS *frame_parms);
int nr_init_frame_parms_ue(nfapi_nr_config_request_t* config, NR_DL_FRAME_PARMS *frame_parms);
void nr_dump_frame_parms(NR_DL_FRAME_PARMS *frame_parms);
int phy_init_nr_gNB(PHY_VARS_gNB *gNB, unsigned char is_secondary_gNB, unsigned char abstraction_flag);
void nr_phy_config_request(NR_PHY_Config_t *gNB);
......
......@@ -130,7 +130,7 @@ uint8_t nr_generate_dci_top(NR_DCI_ALLOC_t dci_alloc,
int32_t** txdataF,
int16_t amp,
NR_DL_FRAME_PARMS* frame_parms,
nfapi_config_request_t* config)
nfapi_nr_config_request_t* config)
{
return 0;
}
......@@ -18,50 +18,13 @@
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef __PHY_NR_TRANSPORT_DCI__H
#define __PHY_NR_TRANSPORT_DCI__H
#include "defs_gNB.h"
typedef enum {
nr_dci_format_0_0=0,
nr_dci_format_0_1,
nr_dci_format_2_0,
nr_dci_format_2_1,
nr_dci_format_2_2,
nr_dci_format_2_3,
nr_dci_format_1_0,
nr_dci_format_1_1,
} nr_dci_format_e;
typedef enum {
nr_rnti_type_SI_RNTI=0,
nr_rnti_type_RA_RNTI,
nr_rnti_type_C_RNTI,
nr_rnti_type_TC_RNTI,
nr_rnti_type_CS_RNTI,
nr_rnti_type_P_RNTI
} nr_rnti_type_e;
typedef struct {
/// Length of DCI in bits
uint8_t size;
/// Aggregation level
uint8_t L;
/// Position of first CCE of the dci
int firstCCE;
/// flag to indicate that this is a RA response
boolean_t ra_flag;
/// rnti
nr_rnti_type_e rnti;
/// Format
DCI_format_t format;
/// DCI pdu
uint8_t dci_pdu[8];
} NR_DCI_ALLOC_t;
typedef unsigned __int128 uint128_t;
uint8_t nr_get_dci_size(nr_dci_format_e format,
nr_rnti_type_e rnti,
......@@ -72,6 +35,6 @@ uint8_t nr_generate_dci_top(NR_DCI_ALLOC_t dci_alloc,
int32_t** txdataF,
int16_t amp,
NR_DL_FRAME_PARMS* frame_parms,
nfapi_config_request_t* config)
nfapi_nr_config_request_t* config)
#endif //__PHY_NR_TRANSPORT_DCI__H
......@@ -212,6 +212,8 @@ int nr_generate_pbch(NR_gNB_PBCH *pbch,
uint8_t idx=0;
uint16_t M;
uint8_t nushift;
uint8_t *xbyte = pbch->pbch_a;
memset((void*) xbyte, 0, 1);
LOG_I(PHY, "PBCH generation started\n");
......@@ -223,13 +225,10 @@ int nr_generate_pbch(NR_gNB_PBCH *pbch,
#ifdef DEBUG_PBCH_ENCODING
printf("Byte endian fix:\n");
for (int i=0; i<4; i++)
printf("pbch_a[%d]: 0x%04x\n", i, pbch->pbch_a[i]);
printf("pbch_a[%d]: 0x%04x\n", i, pbch->pbch_a[i]);
#endif
// Extra byte generation
uint8_t *xbyte = pbch->pbch_a;
//memset((void*) xbyte, 0, 1);
for (int i=0; i<4; i++)
(*xbyte) ^= ((sfn>>i)&1)<<i; // 4 lsb of sfn
......
......@@ -45,10 +45,10 @@
#include "PHY/NR_REFSIG/refsig_defs_ue.h"
extern openair0_config_t openair0_cfg[];
static nfapi_config_request_t config_t;
static nfapi_config_request_t* config =&config_t;
static nfapi_nr_config_request_t config_t;
static nfapi_nr_config_request_t* config =&config_t;
/* forward declarations */
void set_default_frame_parms_single(nfapi_config_request_t *config, NR_DL_FRAME_PARMS *frame_parms);
void set_default_frame_parms_single(nfapi_nr_config_request_t *config, NR_DL_FRAME_PARMS *frame_parms);
//#define DEBUG_INITIAL_SYNCH
......@@ -164,7 +164,7 @@ int nr_initial_sync(PHY_VARS_NR_UE *ue, runmode_t mode)
NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
int ret=-1;
int aarx,rx_power=0;
//nfapi_config_request_t* config;
//nfapi_nr_config_request_t* config;
/*offset parameters to be updated from higher layer */
k_ssb =0;
......
......@@ -34,7 +34,7 @@
#define __PHY_DEFS_NR_COMMON__H__
#include "defs_common.h"
#include "nfapi_interface.h"
#include "nfapi_nr_interface.h"
#include "impl_defs_nr.h"
#include "PHY/CODING/nrPolar_tools/nr_polar_defs.h"
......
......@@ -32,7 +32,8 @@
#include "PHY_INTERFACE/phy_interface.h"
#include "SCHED/sched_eNB.h"
nr_subframe_t nr_subframe_select(nfapi_nr_config_request_t *cfg,unsigned char subframe);
lte_subframe_t nr_subframe_select (nfapi_nr_config_request_t *cfg, unsigned char subframe);
void nr_set_ssb_first_subcarrier(nfapi_nr_config_request_t *cfg, NR_DL_FRAME_PARMS *fp);
void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, gNB_rxtx_proc_t *proc, int do_meas);
void nr_init_feptx_thread(RU_t *ru,pthread_attr_t *attr_feptx);
......
#ifndef _RRC_LIST_H_
#define _RRC_LIST_H_
#define RRC_LIST_TYPE(T, N) \
struct { \
T *entries[N]; \
int next[N]; \
int prev[N]; \
int start; \
int count; \
}
// initial function for the certain list, storage number of entry, initial pointer and corresponding links
#define RRC_LIST_INIT(list, c) \
do { \
int iterator; \
(list).count = (c); \
for(iterator=0; iterator<c; ++iterator){ \
(list).entries[iterator] = NULL; \
(list).next[iterator] = -1; \
(list).prev[iterator] = -1; \
(list).start = -1; \
} \
}while(0)
// check the entry by id first then update or create new entry.
#define RRC_LIST_MOD_ADD(list, new, id_name) \
do { \
int iterator; \
for(iterator=(list).start; iterator!=-1; iterator=(list).next[iterator]){ \
if((new)->id_name == (list).entries[iterator]->id_name){ \
(list).entries[iterator] = (new); \
break; \
} \
} \
if(iterator==-1){ \
for(iterator=0; iterator<(list).count; ++iterator){ \
if((list).entries[iterator] == NULL){ \
(list).next[iterator] = (list).start; \
(list).prev[iterator] = -1; \
if((list).start != -1){ \
(list).prev[list.start] = iterator; \
} \
(list).start = iterator; \
(list).entries[iterator] = (new); \
break; \
} \
} \
} \
}while(0)
// search entries by id, unlink from the list and output free pointer for upper function to release memory
#define RRC_LIST_MOD_REL(list, id_name, id, free) \
do{ \
int iterator; \
for(iterator=(list).start; iterator!=-1; iterator=(list).next[iterator]){ \
if(id == (list).entries[iterator]->id_name){ \
if((list).prev[iterator] == -1){ \
(list).start = (list).next[iterator]; \
}else{ \
(list).next[(list).prev[iterator]] = (list).next[iterator]; \
} \
if((list).next[iterator] != -1){ \
(list).prev[(list).next[iterator]] = (list).prev[iterator]; \
} \
(free) = (list).entries[iterator]; \
(list).entries[iterator] = NULL; \
break; \
} \
} \
}while(0)
#define RRC_LIST_FOREACH(list, i) \
for((i)=(list).start; (i) != -1; (i)=(list).next[i])
#define RRC_LIST_ENTRY(list, i) \
list.entries[i]
#endif
\ No newline at end of file
......@@ -600,7 +600,7 @@ void fh_if5_north_asynch_in(RU_t *ru,int *frame,int *subframe) {
void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *subframe) {
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
nfapi_config_request_t *cfg = &ru->gNB_list[0]->gNB_config;
nfapi_nr_config_request_t *cfg = &ru->gNB_list[0]->gNB_config;
RU_proc_t *proc = &ru->proc;
uint16_t packet_type;
......@@ -782,7 +782,7 @@ void tx_rf(RU_t *ru) {
RU_proc_t *proc = &ru->proc;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
nfapi_config_request_t *cfg = &ru->gNB_list[0]->gNB_config;
nfapi_nr_config_request_t *cfg = &ru->gNB_list[0]->gNB_config;
void *txp[ru->nb_tx];
unsigned int txs;
int i;
......@@ -1281,7 +1281,7 @@ int setup_RU_buffers(RU_t *ru) {
//uint16_t N_TA_offset = 0;
NR_DL_FRAME_PARMS *frame_parms;
//nfapi_config_request_t *gNB_config = ru->gNB_list[0]->gNB_config; //tmp index
//nfapi_nr_config_request_t *gNB_config = ru->gNB_list[0]->gNB_config; //tmp index
if (ru) {
frame_parms = ru->nr_frame_parms;
......@@ -1841,7 +1841,7 @@ void configure_ru(int idx,
RU_t *ru = RC.ru[idx];
RRU_config_t *config = (RRU_config_t *)arg;
RRU_capabilities_t *capabilities = (RRU_capabilities_t*)arg;
nfapi_config_request_t *gNB_config = &ru->gNB_list[0]->gNB_config;
nfapi_nr_config_request_t *gNB_config = &ru->gNB_list[0]->gNB_config;
int ret;
LOG_I(PHY, "Received capabilities from RRU %d\n",idx);
......@@ -1885,7 +1885,7 @@ void configure_rru(int idx,
RRU_config_t *config = (RRU_config_t *)arg;
RU_t *ru = RC.ru[idx];
nfapi_config_request_t *gNB_config = &ru->gNB_list[0]->gNB_config;
nfapi_nr_config_request_t *gNB_config = &ru->gNB_list[0]->gNB_config;
ru->nr_frame_parms->eutra_band = config->band_list[0];
ru->nr_frame_parms->dl_CarrierFreq = config->tx_freq[0];
......
......@@ -61,8 +61,8 @@
#include "T.h"
extern double cpuf;
static nfapi_config_request_t config_t;
static nfapi_config_request_t* config =&config_t;
static nfapi_nr_config_request_t config_t;
static nfapi_nr_config_request_t* config =&config_t;
#define FRAME_PERIOD 100000000ULL
#define DAQ_PERIOD 66667ULL
......
......@@ -181,7 +181,7 @@ int otg_enabled;
//int number_of_cards = 1;
static NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs];
static nfapi_config_request_t *config[MAX_NUM_CCs];
static nfapi_nr_config_request_t *config[MAX_NUM_CCs];
int16_t node_synch_ref[MAX_NUM_CCs];
uint32_t target_dl_mcs = 28; //maximum allowed mcs
......@@ -245,7 +245,7 @@ int emulate_rf = 0;
threads_t threads= {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
/* forward declarations */
void set_default_frame_parms(nfapi_config_request_t *config[MAX_NUM_CCs], NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]);
void set_default_frame_parms(nfapi_nr_config_request_t *config[MAX_NUM_CCs], NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]);
/* see file openair2/LAYER2/MAC/main.c for why abstraction_flag is needed
......@@ -551,7 +551,7 @@ static void get_options (int argc, char **argv) {
uint32_t online_log_messages;
uint32_t glog_level, glog_verbosity;
uint32_t start_telnetsrv;
nfapi_config_request_t *config[MAX_NUM_CCs];
nfapi_nr_config_request_t *config[MAX_NUM_CCs];
paramdef_t cmdline_params[] =CMDLINE_PARAMS_DESC ;
paramdef_t cmdline_logparams[] =CMDLINE_LOGPARAMS_DESC ;
......@@ -628,7 +628,7 @@ int T_port = 2021; /* default port to listen to to wait for the tracer */
int T_dont_fork = 0; /* default is to fork, see 'T_init' to understand */
#endif
void set_default_frame_parms(nfapi_config_request_t *config[MAX_NUM_CCs], NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) {
void set_default_frame_parms(nfapi_nr_config_request_t *config[MAX_NUM_CCs], NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) {
int CC_id;
......@@ -636,7 +636,7 @@ int T_dont_fork = 0; /* default is to fork, see 'T_init' to understand */
frame_parms[CC_id] = (NR_DL_FRAME_PARMS*) malloc(sizeof(NR_DL_FRAME_PARMS));
/* Set some default values that may be overwritten while reading options */
frame_parms[CC_id] = (NR_DL_FRAME_PARMS*) malloc(sizeof(NR_DL_FRAME_PARMS));
config[CC_id] = (nfapi_config_request_t*) malloc(sizeof(nfapi_config_request_t));
config[CC_id] = (nfapi_nr_config_request_t*) malloc(sizeof(nfapi_nr_config_request_t));
config[CC_id]->subframe_config.numerology_index_mu.value =1;
config[CC_id]->subframe_config.duplex_mode.value = 1; //FDD
config[CC_id]->subframe_config.dl_cyclic_prefix_type.value = 0; //NORMAL
......@@ -695,7 +695,7 @@ int T_dont_fork = 0; /* default is to fork, see 'T_init' to understand */
}
void set_default_frame_parms_single(nfapi_config_request_t *config, NR_DL_FRAME_PARMS *frame_parms) {
void set_default_frame_parms_single(nfapi_nr_config_request_t *config, NR_DL_FRAME_PARMS *frame_parms) {
//int CC_id;
......@@ -703,7 +703,7 @@ void set_default_frame_parms_single(nfapi_config_request_t *config, NR_DL_FRAME_
frame_parms = (NR_DL_FRAME_PARMS*) malloc(sizeof(NR_DL_FRAME_PARMS));
/* Set some default values that may be overwritten while reading options */
frame_parms = (NR_DL_FRAME_PARMS*) malloc(sizeof(NR_DL_FRAME_PARMS));
config = (nfapi_config_request_t*) malloc(sizeof(nfapi_config_request_t));
config = (nfapi_nr_config_request_t*) malloc(sizeof(nfapi_nr_config_request_t));
config->subframe_config.numerology_index_mu.value =1;
config->subframe_config.duplex_mode.value = 1; //FDD
config->subframe_config.dl_cyclic_prefix_type.value = 0; //NORMAL
......
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