Commit 671aa4e1 authored by Raymond Knopp's avatar Raymond Knopp

Merge remote-tracking branch 'origin/develop' into ru_rau_enhancement-external-timing

parents b7b48fd6 0c83df3f
This diff is collapsed.
......@@ -21,31 +21,31 @@
-->
<testCaseList>
<TestCaseRequestedList>010101 050101 060101 070101 040101 030101 040301 040501 040601 040602 040603 040604 040605 040641 040401 040201 030201 030111 040301 040511 040611 040612 040613 040614 040615 040651 040401 040201 030201 030121 040301 040521 040621 040622 040623 040661 040401 040201 030201 </TestCaseRequestedList>
<TestCaseRequestedList>010101 050101 060101 070101 040101 030101 040301 040501 040601 040602 040603 040604 040605 040641 040642 040401 040201 030201 030111 040301 040511 040611 040612 040613 040614 040615 040651 040652 040401 040201 030201 030121 040301 040521 040621 040622 040623 040624 040625 040662 040661 040401 040201 030201 </TestCaseRequestedList>
<TestCaseExclusionList></TestCaseExclusionList>
<testCase id="010101">
<class>Build_eNB</class>
<desc>Build eNB (USRP)</desc>
<Build_eNB_args>-w USRP -x -c --eNB</Build_eNB_args>
<Build_eNB_args>-w USRP -c --eNB</Build_eNB_args>
</testCase>
<testCase id="030101">
<class>Initialize_eNB</class>
<desc>Initialize eNB (FDD/Band7/5MHz)</desc>
<Initialize_eNB_args>-O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf</Initialize_eNB_args>
<Initialize_eNB_args>-O ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf --codingw --fepw</Initialize_eNB_args>
</testCase>
<testCase id="030111">
<class>Initialize_eNB</class>
<desc>Initialize eNB (FDD/Band7/10MHz)</desc>
<Initialize_eNB_args>-O ci-scripts/conf_files/enb.band7.tm1.50PRB.usrpb210.conf</Initialize_eNB_args>
<Initialize_eNB_args>-O ci-scripts/conf_files/enb.band7.tm1.50PRB.usrpb210.conf --codingw --fepw</Initialize_eNB_args>
</testCase>
<testCase id="030121">
<class>Initialize_eNB</class>
<desc>Initialize eNB (FDD/Band7/20MHz)</desc>
<Initialize_eNB_args>-O ci-scripts/conf_files/enb.band7.tm1.100PRB.usrpb210.conf</Initialize_eNB_args>
<Initialize_eNB_args>-O ci-scripts/conf_files/enb.band7.tm1.100PRB.usrpb210.conf --codingw --fepw</Initialize_eNB_args>
</testCase>
<testCase id="030201">
......@@ -138,6 +138,14 @@
<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
</testCase>
<testCase id="040642">
<class>Iperf</class>
<desc>iperf (5MHz - UL/9Mbps/UDP)(60 sec)(single-ue profile)</desc>
<iperf_args>-u -b 9M -t 60 -i 1 -R</iperf_args>
<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
<iperf_profile>single-ue</iperf_profile>
</testCase>
<testCase id="040611">
<class>Iperf</class>
<desc>iperf (10MHz - DL/10Mbps/UDP)(60 sec)</desc>
......@@ -182,6 +190,14 @@
<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
</testCase>
<testCase id="040652">
<class>Iperf</class>
<desc>iperf (10MHz - UL/20Mbps/UDP)(60 sec)(single-ue profile)</desc>
<iperf_args>-u -b 20M -t 60 -i 1 -R</iperf_args>
<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
<iperf_profile>single-ue</iperf_profile>
</testCase>
<testCase id="040621">
<class>Iperf</class>
<desc>iperf (20MHz - DL/20Mbps/UDP)(60 sec)</desc>
......@@ -211,7 +227,7 @@
<iperf_profile>single-ue</iperf_profile>
</testCase>
<testCase id="040624">
<testCase id="040625">
<class>Iperf</class>
<desc>iperf (20MHz - DL/70Mbps/UDP)(60 sec)(unbalanced profile)</desc>
<iperf_args>-u -b 70M -t 60 -i 1</iperf_args>
......@@ -226,6 +242,14 @@
<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
</testCase>
<testCase id="040662">
<class>Iperf</class>
<desc>iperf (20MHz - UL/20Mbps/UDP)(60 sec)(single-ue profile)</desc>
<iperf_args>-u -b 20M -t 60 -i 1 -R</iperf_args>
<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
<iperf_profile>single-ue</iperf_profile>
</testCase>
<testCase id="050101">
<class>Initialize_HSS</class>
<desc>Initialize HSS</desc>
......
......@@ -29,13 +29,13 @@
<testCase id="010101">
<class>Build_eNB</class>
<desc>Build eNB (USRP)</desc>
<Build_eNB_args>-w USRP -x -c --eNB</Build_eNB_args>
<Build_eNB_args>-w USRP -c --eNB</Build_eNB_args>
</testCase>
<testCase id="010102">
<class>Build_eNB</class>
<desc>Build eNB (USRP)</desc>
<Build_eNB_args>-w BLADERF -x -c --eNB</Build_eNB_args>
<Build_eNB_args>-w BLADERF -c --eNB</Build_eNB_args>
</testCase>
<testCase id="030101">
......
......@@ -683,7 +683,7 @@ install_asn1c_from_source(){
# better to use a given commit than a branch in case the branch
# is updated and requires modifications in the source of OAI
#git checkout velichkov_s1ap_plus_option_group
git checkout ec830d70bbb014b769810355a2f321a91ccd8a58
git checkout 73d6b23dcec9ab36605b4af884143824392134c1
autoreconf -iv
./configure
make -j`nproc`
......
......@@ -27,4 +27,6 @@ check_vcd:
clean:
rm -f *.o $(GENIDS) core T_IDs.h T_messages.txt.h _check_vcd
cleanall: clean
cd tracer && $(MAKE) clean
......@@ -31,6 +31,12 @@ volatile int _T_freelist_head;
volatile int *T_freelist_head = &_T_freelist_head;
T_cache_t *T_cache;
#if BASIC_SIMULATOR
/* global variables used by T_GET_SLOT, see in T.h */
volatile uint64_t T_next_id;
volatile uint64_t T_active_id;
#endif
static void get_message(int s)
{
char t;
......
......@@ -112,13 +112,37 @@ extern volatile int *T_freelist_head;
extern T_cache_t *T_cache;
extern int *T_active;
/* When running the basic simulator, we may fill the T cache too fast.
* Let's not crash if it's full, just wait.
* Let's serialize write accesses to the T cache. For that, we use a
* 'ticket' mechanism. To acquire a T slot the caller needs to own the
* current active ticket. We also wait for the slot to be free if
* it is already in use.
*/
#if BASIC_SIMULATOR
# define T_BASIC_SIMULATOR_WAIT \
while (T_cache[T_LOCAL_slot].busy) usleep(100)
# define T_GET_SLOT \
do { \
extern volatile uint64_t T_next_id; \
extern volatile uint64_t T_active_id; \
uint64_t id; \
/* get a ticket */ \
id = __sync_fetch_and_add(&T_next_id, 1); \
/* wait for our turn */ \
while (id != __sync_fetch_and_add(&T_active_id, 0)) /* busy wait */; \
/* this is our turn, try to acquire the slot until it's free */ \
do { \
T_LOCAL_busy = __sync_fetch_and_or(&T_cache[T_LOCAL_slot].busy, 0x01); \
if (T_LOCAL_busy & 0x01) usleep(100); \
} while (T_LOCAL_busy & 0x01); \
/* check that there are still some tickets */ \
if (__sync_fetch_and_add(&T_active_id, 0) == 0xffffffffffffffff) { \
printf("T: reached the end of times, bye...\n"); \
abort(); \
} \
/* free our ticket, which signals the next waiter that it's its turn */ \
(void)__sync_fetch_and_add(&T_active_id, 1); \
} while (0)
#else
# define T_BASIC_SIMULATOR_WAIT /* */
# define T_GET_SLOT \
T_LOCAL_busy = __sync_fetch_and_or(&T_cache[T_LOCAL_slot].busy, 0x01);
#endif
/* used at header of Tn, allocates buffer */
......@@ -126,11 +150,12 @@ extern int *T_active;
char *T_LOCAL_buf; \
int T_LOCAL_size = 0; \
int T_LOCAL_slot; \
int T_LOCAL_busy; \
T_LOCAL_slot = __sync_fetch_and_add(T_freelist_head, 1) \
& (T_CACHE_SIZE - 1); \
(void)__sync_fetch_and_and(T_freelist_head, T_CACHE_SIZE - 1); \
T_BASIC_SIMULATOR_WAIT; \
if (T_cache[T_LOCAL_slot].busy) { \
T_GET_SLOT; \
if (T_LOCAL_busy & 0x01) { \
printf("%s:%d:%s: T cache is full - consider increasing its size\n", \
__FILE__, __LINE__, __FUNCTION__); \
abort(); \
......@@ -142,7 +167,7 @@ extern int *T_active;
#define T_COMMIT() \
T_cache[T_LOCAL_slot].length = T_LOCAL_size; \
__sync_synchronize(); \
T_cache[T_LOCAL_slot].busy = 1; \
(void)__sync_fetch_and_or(&T_cache[T_LOCAL_slot].busy, 0x02);
#define T_CHECK_SIZE(len, argnum) \
if (T_LOCAL_size + (len) > T_BUFFER_MAX) { \
......
......@@ -31,6 +31,10 @@
#endif
typedef struct {
/* 'busy' is a bit field
* bit 0: 1 means that slot is acquired by writer
* bit 1: 1 means that slot is ready for consumption
*/
volatile int busy;
char buffer[T_BUFFER_MAX];
int length;
......
......@@ -337,7 +337,7 @@ static void forward(void *_forwarder, char *buf, int size)
static void wait_message(void)
{
while (T_local_cache[T_busylist_head].busy == 0) usleep(1000);
while ((T_local_cache[T_busylist_head].busy & 0x02) == 0) usleep(1000);
}
void T_local_tracer_main(int remote_port, int wait_for_tracer,
......
......@@ -330,6 +330,8 @@ typedef struct RU_t_s{
int in_synch;
/// timing offset
int rx_offset;
/// south out counter
int south_out_cnt;
/// flag to indicate the RU is a slave to another source
int is_slave;
/// flag to indicate that the RU should generate the DMRS sequence in slot 2 (subframe 1) for OTA synchronization and calibration
......
......@@ -2396,12 +2396,12 @@ int RCconfig_S1(MessageDef *msg_p, uint32_t i) {
#endif
}
if (strcmp(*(S1ParamList.paramarray[l][ENB_MME_IP_ADDRESS_PREFERENCE_IDX].strptr), "ipv4") == 0) {
S1AP_REGISTER_ENB_REQ (msg_p).mme_ip_address[j].ipv4 = 1;
S1AP_REGISTER_ENB_REQ (msg_p).mme_ip_address[l].ipv4 = 1;
} else if (strcmp(*(S1ParamList.paramarray[l][ENB_MME_IP_ADDRESS_PREFERENCE_IDX].strptr), "ipv6") == 0) {
S1AP_REGISTER_ENB_REQ (msg_p).mme_ip_address[j].ipv6 = 1;
S1AP_REGISTER_ENB_REQ (msg_p).mme_ip_address[l].ipv6 = 1;
} else if (strcmp(*(S1ParamList.paramarray[l][ENB_MME_IP_ADDRESS_PREFERENCE_IDX].strptr), "no") == 0) {
S1AP_REGISTER_ENB_REQ (msg_p).mme_ip_address[j].ipv4 = 1;
S1AP_REGISTER_ENB_REQ (msg_p).mme_ip_address[j].ipv6 = 1;
S1AP_REGISTER_ENB_REQ (msg_p).mme_ip_address[l].ipv4 = 1;
S1AP_REGISTER_ENB_REQ (msg_p).mme_ip_address[l].ipv6 = 1;
}
}
......
......@@ -386,6 +386,7 @@ set_ul_DAI(int module_idP, int UE_idP, int CC_idP, int frameP,
UE_list->UE_template[CC_idP][UE_idP].DAI_ul[3] = DAI;
break;
}
break;
case 2:
// if ((subframeP==3)||(subframeP==8))
......
......@@ -6881,3 +6881,201 @@ id-EDT-Session ProtocolIE-ID ::= 281
id-CNTypeRestrictions ProtocolIE-ID ::= 282
END
-- **************************************************************
--
-- Container definitions
--
-- **************************************************************
S1AP-Containers {
itu-t (0) identified-organization (4) etsi (0) mobileDomain (0)
eps-Access (21) modules (3) s1ap (1) version1 (1) s1ap-Containers (5) }
DEFINITIONS AUTOMATIC TAGS ::=
BEGIN
-- **************************************************************
--
-- IE parameter types from other modules.
--
-- **************************************************************
IMPORTS
Criticality,
Presence,
PrivateIE-ID,
ProtocolExtensionID,
ProtocolIE-ID
FROM S1AP-CommonDataTypes
maxPrivateIEs,
maxProtocolExtensions,
maxProtocolIEs
FROM S1AP-Constants;
-- **************************************************************
--
-- Class Definition for Protocol IEs
--
-- **************************************************************
S1AP-PROTOCOL-IES ::= CLASS {
&id ProtocolIE-ID UNIQUE,
&criticality Criticality,
&Value,
&presence Presence
}
WITH SYNTAX {
ID &id
CRITICALITY &criticality
TYPE &Value
PRESENCE &presence
}
-- **************************************************************
--
-- Class Definition for Protocol IEs
--
-- **************************************************************
S1AP-PROTOCOL-IES-PAIR ::= CLASS {
&id ProtocolIE-ID UNIQUE,
&firstCriticality Criticality,
&FirstValue,
&secondCriticality Criticality,
&SecondValue,
&presence Presence
}
WITH SYNTAX {
ID &id
FIRST CRITICALITY &firstCriticality
FIRST TYPE &FirstValue
SECOND CRITICALITY &secondCriticality
SECOND TYPE &SecondValue
PRESENCE &presence
}
-- **************************************************************
--
-- Class Definition for Protocol Extensions
--
-- **************************************************************
S1AP-PROTOCOL-EXTENSION ::= CLASS {
&id ProtocolExtensionID UNIQUE,
&criticality Criticality,
&Extension,
&presence Presence
}
WITH SYNTAX {
ID &id
CRITICALITY &criticality
EXTENSION &Extension
PRESENCE &presence
}
-- **************************************************************
--
-- Class Definition for Private IEs
--
-- **************************************************************
S1AP-PRIVATE-IES ::= CLASS {
&id PrivateIE-ID,
&criticality Criticality,
&Value,
&presence Presence
}
WITH SYNTAX {
ID &id
CRITICALITY &criticality
TYPE &Value
PRESENCE &presence
}
-- **************************************************************
--
-- Container for Protocol IEs
--
-- **************************************************************
ProtocolIE-Container {S1AP-PROTOCOL-IES : IEsSetParam} ::=
SEQUENCE (SIZE (0..maxProtocolIEs)) OF
ProtocolIE-Field {{IEsSetParam}}
ProtocolIE-SingleContainer {S1AP-PROTOCOL-IES : IEsSetParam} ::=
ProtocolIE-Field {{IEsSetParam}}
ProtocolIE-Field {S1AP-PROTOCOL-IES : IEsSetParam} ::= SEQUENCE {
id S1AP-PROTOCOL-IES.&id ({IEsSetParam}),
criticality S1AP-PROTOCOL-IES.&criticality ({IEsSetParam}{@id}),
value S1AP-PROTOCOL-IES.&Value ({IEsSetParam}{@id})
}
-- **************************************************************
--
-- Container for Protocol IE Pairs
--
-- **************************************************************
ProtocolIE-ContainerPair {S1AP-PROTOCOL-IES-PAIR : IEsSetParam} ::=
SEQUENCE (SIZE (0..maxProtocolIEs)) OF
ProtocolIE-FieldPair {{IEsSetParam}}
ProtocolIE-FieldPair {S1AP-PROTOCOL-IES-PAIR : IEsSetParam} ::= SEQUENCE {
id S1AP-PROTOCOL-IES-PAIR.&id ({IEsSetParam}),
firstCriticality S1AP-PROTOCOL-IES-PAIR.&firstCriticality ({IEsSetParam}{@id}),
firstValue S1AP-PROTOCOL-IES-PAIR.&FirstValue ({IEsSetParam}{@id}),
secondCriticality S1AP-PROTOCOL-IES-PAIR.&secondCriticality ({IEsSetParam}{@id}),
secondValue S1AP-PROTOCOL-IES-PAIR.&SecondValue ({IEsSetParam}{@id})
}
-- **************************************************************
--
-- Container Lists for Protocol IE Containers
--
-- **************************************************************
ProtocolIE-ContainerList {INTEGER : lowerBound, INTEGER : upperBound, S1AP-PROTOCOL-IES : IEsSetParam} ::=
SEQUENCE (SIZE (lowerBound..upperBound)) OF
ProtocolIE-SingleContainer {{IEsSetParam}}
ProtocolIE-ContainerPairList {INTEGER : lowerBound, INTEGER : upperBound, S1AP-PROTOCOL-IES-PAIR : IEsSetParam} ::=
SEQUENCE (SIZE (lowerBound..upperBound)) OF
ProtocolIE-ContainerPair {{IEsSetParam}}
-- **************************************************************
--
-- Container for Protocol Extensions
--
-- **************************************************************
ProtocolExtensionContainer {S1AP-PROTOCOL-EXTENSION : ExtensionSetParam} ::=
SEQUENCE (SIZE (1..maxProtocolExtensions)) OF
ProtocolExtensionField {{ExtensionSetParam}}
ProtocolExtensionField {S1AP-PROTOCOL-EXTENSION : ExtensionSetParam} ::= SEQUENCE {
id S1AP-PROTOCOL-EXTENSION.&id ({ExtensionSetParam}),
criticality S1AP-PROTOCOL-EXTENSION.&criticality ({ExtensionSetParam}{@id}),
extensionValue S1AP-PROTOCOL-EXTENSION.&Extension ({ExtensionSetParam}{@id})
}
-- **************************************************************
--
-- Container for Private IEs
--
-- **************************************************************
PrivateIE-Container {S1AP-PRIVATE-IES : IEsSetParam } ::=
SEQUENCE (SIZE (1.. maxPrivateIEs)) OF
PrivateIE-Field {{IEsSetParam}}
PrivateIE-Field {S1AP-PRIVATE-IES : IEsSetParam} ::= SEQUENCE {
id S1AP-PRIVATE-IES.&id ({IEsSetParam}),
criticality S1AP-PRIVATE-IES.&criticality ({IEsSetParam}{@id}),
value S1AP-PRIVATE-IES.&Value ({IEsSetParam}{@id})
}
END
......@@ -122,7 +122,6 @@ extern int numerology;
extern int fepw;
extern int single_thread_flag;
extern void phy_init_RU(RU_t*);
extern void phy_free_RU(RU_t*);
......@@ -156,8 +155,10 @@ static inline void fh_if5_south_out(RU_t *ru) {
static inline void fh_if4p5_south_out(RU_t *ru) {
if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
LOG_D(PHY,"Sending IF4p5 for frame %d subframe %d\n",ru->proc.frame_tx,ru->proc.subframe_tx);
if (subframe_select(&ru->frame_parms,ru->proc.subframe_tx)!=SF_UL)
if (subframe_select(&ru->frame_parms,ru->proc.subframe_tx)!=SF_UL) {
send_IF4p5(ru,ru->proc.frame_tx, ru->proc.subframe_tx, IF4p5_PDLFFT);
ru->south_out_cnt++;
}
}
/*************************************************************/
......@@ -1339,7 +1340,7 @@ void fill_rf_config(RU_t *ru, char *rf_config_file) {
cfg->num_rb_dl=fp->N_RB_DL;
cfg->tx_num_channels=ru->nb_tx;
cfg->rx_num_channels=ru->nb_rx;
for (i=0; i<ru->nb_tx; i++) {
cfg->tx_freq[i] = (double)fp->dl_CarrierFreq;
......@@ -1439,6 +1440,7 @@ static void* ru_stats_thread(void* param) {
print_meas(&ru->compression,"compression",NULL,NULL);
print_meas(&ru->transport,"transport",NULL,NULL);
}
LOG_I(PHY,"ru->south_out_cnt = %d\n",ru->south_out_cnt);
}
}
return(NULL);
......@@ -2568,6 +2570,7 @@ void init_RU(char *rf_config_file, clock_source_t clock_source,clock_source_t ti
ru->ts_offset = 0;
ru->in_synch = (ru->is_slave == 1) ? 0 : 1;
ru->cmd = EMPTY;
ru->south_out_cnt= 0;
// use eNB_list[0] as a reference for RU frame parameters
// NOTE: multiple CC_id are not handled here yet!
ru->openair0_cfg.clock_source = clock_source;
......
......@@ -944,7 +944,7 @@ int main( int argc, char **argv )
printf("Reading in command-line options\n");
get_options ();
get_options ();
if (CONFIG_ISFLAGSET(CONFIG_ABORT) ) {
fprintf(stderr,"Getting configuration failed\n");
exit(-1);
......@@ -1133,13 +1133,6 @@ int main( int argc, char **argv )
rt_sleep_ns(10*100000000ULL);
if (nfapi_mode) {
printf("NFAPI*** - mutex and cond created - will block shortly for completion of PNF connection\n");
pthread_cond_init(&sync_cond,NULL);
pthread_mutex_init(&sync_mutex, NULL);
}
if (nfapi_mode)
{
printf("NFAPI*** - mutex and cond created - will block shortly for completion of PNF connection\n");
......
......@@ -65,9 +65,9 @@
#define CONFIG_HLP_UELOOP "get softmodem (UE) to loop through memory instead of acquiring from HW\n"
#define CONFIG_HLP_PHYTST "test UE phy layer, mac disabled\n"
#define CONFIG_HLP_DMAMAP "sets flag for improved EXMIMO UE performance\n"
#define CONFIG_HLP_EXCCLK "tells hardware to use an external clock reference\n"
#define CONFIG_HLP_EXTS "tells hardware to use an external timing reference\n"
#define CONFIG_HLP_DMRSSYNC "tells RU to insert DMRS in subframe 1 slot 0"
#define CONFIG_HLP_CLK "tells hardware to use a clock reference (0:internal, 1:external, 2:gpsdo)\n"
#define CONFIG_HLP_USIM "use XOR autentication algo in case of test usim mode\n"
#define CONFIG_HLP_NOSNGLT "Disables single-thread mode in lte-softmodem\n"
#define CONFIG_HLP_TADV "Set timing_advance\n"
......@@ -163,8 +163,8 @@
{"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, iptr:&phy_test, defintval:0, TYPE_INT, 0}, \
{"usim-test", CONFIG_HLP_USIM, PARAMFLAG_BOOL, u8ptr:&usim_test, defintval:0, TYPE_UINT8, 0}, \
{"mmapped-dma", CONFIG_HLP_DMAMAP, PARAMFLAG_BOOL, uptr:&mmapped_dma, defintval:0, TYPE_INT, 0}, \
{"external-clock", CONFIG_HLP_EXCCLK, PARAMFLAG_BOOL, uptr:&clock_source, defintval:0, TYPE_INT, 0}, \
{"external-timesource", CONFIG_HLP_EXTS, PARAMFLAG_BOOL, uptr:&time_source, defintval:0, TYPE_INT, 0}, \
{"external-clock", CONFIG_HLP_CLK, 0, uptr:&clock_source, defintval:0, TYPE_UINT, 0}, \
{"wait-for-sync", NULL, PARAMFLAG_BOOL, iptr:&wait_for_sync, defintval:0, TYPE_INT, 0}, \
{"single-thread-enable", CONFIG_HLP_NOSNGLT, PARAMFLAG_BOOL, iptr:&single_thread_flag, defintval:0, TYPE_INT, 0}, \
{"threadIQ", NULL, 0, iptr:&(threads.iq), defintval:1, TYPE_INT, 0}, \
......
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