Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
OpenXG-RAN
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
spbro
OpenXG-RAN
Commits
612c8632
Commit
612c8632
authored
Jan 24, 2019
by
Florian Kaltenberger
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fixing memory leaks in PBCH RX and FAPI
adding function dci_req for UE disabling handle_dci for now
parent
f2d5cfae
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
95 additions
and
45 deletions
+95
-45
nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h
nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h
+2
-1
openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
+29
-34
openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
+1
-0
openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
+6
-6
openair1/SIMULATION/NR_PHY/dlsim.c
openair1/SIMULATION/NR_PHY/dlsim.c
+1
-1
openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
+55
-2
targets/RT/USER/nr-ue.c
targets/RT/USER/nr-ue.c
+1
-1
No files found.
nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h
View file @
612c8632
...
...
@@ -197,10 +197,11 @@ typedef struct {
}
fapi_nr_rx_indication_body_t
;
///
#define NFAPI_RX_IND_MAX_PDU 100
typedef
struct
{
uint32_t
sfn_slot
;
uint16_t
number_pdus
;
fapi_nr_rx_indication_body_t
*
rx_indication_body
;
fapi_nr_rx_indication_body_t
rx_indication_body
[
NFAPI_RX_IND_MAX_PDU
]
;
}
fapi_nr_rx_indication_t
;
typedef
struct
{
...
...
openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
View file @
612c8632
...
...
@@ -51,8 +51,8 @@ uint16_t nr_pbch_extract(int **rxdataF,
int
**
rxdataF_ext
,
int
**
dl_ch_estimates_ext
,
uint32_t
symbol
,
uint32_t
s_offset
,
uint32_t
high_speed_flag
,
int
is_synchronized
,
NR_DL_FRAME_PARMS
*
frame_parms
)
{
...
...
@@ -65,18 +65,15 @@ uint16_t nr_pbch_extract(int **rxdataF,
unsigned
int
rx_offset
=
frame_parms
->
first_carrier_offset
+
frame_parms
->
ssb_start_subcarrier
;
//and
if
(
rx_offset
>=
frame_parms
->
ofdm_symbol_size
)
rx_offset
-=
frame_parms
->
ofdm_symbol_size
;
int
s_offset
=
0
;
AssertFatal
(
symbol
>=
1
&&
symbol
<
5
,
"symbol %d illegal for PBCH extraction
\n
"
,
symbol
);
if
(
is_synchronized
==
1
)
s_offset
=
4
;
for
(
aarx
=
0
;
aarx
<
frame_parms
->
nb_antennas_rx
;
aarx
++
)
{
rxF
=
&
rxdataF
[
aarx
][(
symbol
+
s_offset
)
*
frame_parms
->
ofdm_symbol_size
];
rxF_ext
=
&
rxdataF_ext
[
aarx
][
(
symbol
+
s_offset
)
*
(
20
*
12
)
];
rxF_ext
=
&
rxdataF_ext
[
aarx
][
symbol
*
20
*
12
];
#ifdef DEBUG_PBCH
printf
(
"extract_rbs (nushift %d): rx_offset=%d, symbol %d
\n
"
,
frame_parms
->
nushift
,
(
rx_offset
+
((
symbol
+
s_offset
)
*
(
frame_parms
->
ofdm_symbol_size
))),
symbol
);
...
...
@@ -143,7 +140,7 @@ uint16_t nr_pbch_extract(int **rxdataF,
//printf("dl_ch0 addr %p\n",dl_ch0);
dl_ch0_ext
=
&
dl_ch_estimates_ext
[
aarx
][
(
symbol
+
s_offset
)
*
(
20
*
12
)
];
dl_ch0_ext
=
&
dl_ch_estimates_ext
[
aarx
][
symbol
*
20
*
12
];
for
(
rb
=
0
;
rb
<
20
;
rb
++
)
{
j
=
0
;
...
...
@@ -268,8 +265,7 @@ void nr_pbch_channel_compensation(int **rxdataF_ext,
int
**
dl_ch_estimates_ext
,
int
**
rxdataF_comp
,
NR_DL_FRAME_PARMS
*
frame_parms
,
uint8_t
symbol
,
int
is_synchronized
,
uint32_t
symbol
,
uint8_t
output_shift
)
{
...
...
@@ -290,14 +286,11 @@ void nr_pbch_channel_compensation(int **rxdataF_ext,
#endif
AssertFatal
((
symbol
>
0
&&
symbol
<
4
&&
is_synchronized
==
0
)
||
(
symbol
>
4
&&
symbol
<
8
&&
is_synchronized
==
1
),
"symbol %d is illegal for PBCH DM-RS (is_synchronized %d)
\n
"
,
symbol
,
is_synchronized
);
AssertFatal
((
symbol
>
0
&&
symbol
<
4
),
"symbol %d is illegal for PBCH DM-RS
\n
"
,
symbol
);
if
(
symbol
==
2
||
symbol
==
6
)
nb_re
=
72
;
if
(
symbol
==
2
)
nb_re
=
72
;
// printf("comp: symbol %d : nb_re %d\n",symbol,nb_re);
...
...
@@ -559,31 +552,35 @@ int nr_rx_pbch( PHY_VARS_NR_UE *ue,
// clear LLR buffer
memset
(
nr_ue_pbch_vars
->
llr
,
0
,
NR_POLAR_PBCH_E
);
int
first_symbol
=
1
;
if
(
ue
->
is_synchronized
>
0
)
first_symbol
+=
4
;
int
symbol_offset
=
1
;
if
(
ue
->
is_synchronized
>
0
)
symbol_offset
=
4
;
else
symbol_offset
=
0
;
#ifdef DEBUG_PBCH
//printf("address dataf %p",nr_ue_common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[subframe_rx]].rxdataF);
write_output
(
"rxdataF0_pbch.m"
,
"rxF0pbch"
,
&
nr_ue_common_vars
->
common_vars_rx_data_per_thread
[
ue
->
current_thread_id
[
subframe_rx
]].
rxdataF
[
0
][
first_symbol
*
frame_parms
->
ofdm_symbol_size
],
frame_parms
->
ofdm_symbol_size
*
3
,
1
,
1
);
&
nr_ue_common_vars
->
common_vars_rx_data_per_thread
[
ue
->
current_thread_id
[
subframe_rx
]].
rxdataF
[
0
][
(
symbol_offset
+
1
)
*
frame_parms
->
ofdm_symbol_size
],
frame_parms
->
ofdm_symbol_size
*
3
,
1
,
1
);
#endif
for
(
symbol
=
first_symbol
;
symbol
<
(
first_symbol
+
3
);
symbol
++
)
{
// symbol refers to symbol within SSB. symbol_offset is the offset of the SSB wrt start of slot
for
(
symbol
=
1
;
symbol
<
4
;
symbol
++
)
{
nr_pbch_extract
(
nr_ue_common_vars
->
common_vars_rx_data_per_thread
[
ue
->
current_thread_id
[
subframe_rx
]].
rxdataF
,
nr_ue_common_vars
->
common_vars_rx_data_per_thread
[
ue
->
current_thread_id
[
subframe_rx
]].
dl_ch_estimates
[
eNB_id
],
nr_ue_pbch_vars
->
rxdataF_ext
,
nr_ue_pbch_vars
->
dl_ch_estimates_ext
,
symbol
-
first_symbol
+
1
,
symbol
,
symbol_offset
,
high_speed_flag
,
ue
->
is_synchronized
,
frame_parms
);
#ifdef DEBUG_PBCH
LOG_I
(
PHY
,
"[PHY] PBCH Symbol %d ofdm size %d
\n
"
,
symbol
,
frame_parms
->
ofdm_symbol_size
);
LOG_I
(
PHY
,
"[PHY] PBCH starting channel_level
\n
"
);
#endif
if
(
symbol
==
1
||
symbol
==
5
)
{
if
(
symbol
==
1
)
{
max_h
=
nr_pbch_channel_level
(
nr_ue_pbch_vars
->
dl_ch_estimates_ext
,
frame_parms
,
symbol
);
...
...
@@ -599,7 +596,6 @@ int nr_rx_pbch( PHY_VARS_NR_UE *ue,
nr_ue_pbch_vars
->
rxdataF_comp
,
frame_parms
,
symbol
,
ue
->
is_synchronized
,
nr_ue_pbch_vars
->
log2_maxh
);
// log2_maxh+I0_shift
/*if (frame_parms->nb_antennas_rx > 1)
...
...
@@ -615,7 +611,7 @@ int nr_rx_pbch( PHY_VARS_NR_UE *ue,
return(-1);
}
*/
if
(
symbol
==
(
first_symbol
+
1
)
)
{
if
(
symbol
==
1
)
{
nr_pbch_quantize
(
pbch_e_rx
,
(
short
*
)
&
(
nr_ue_pbch_vars
->
rxdataF_comp
[
0
][
symbol
*
240
]),
144
);
...
...
@@ -633,7 +629,7 @@ int nr_rx_pbch( PHY_VARS_NR_UE *ue,
}
#ifdef DEBUG_PBCH
write_output
(
"rxdataF_comp.m"
,
"rxFcomp"
,
&
nr_ue_pbch_vars
->
rxdataF_comp
[
0
][
240
*
first_symbol
],
240
*
3
,
1
,
1
);
write_output
(
"rxdataF_comp.m"
,
"rxFcomp"
,
&
nr_ue_pbch_vars
->
rxdataF_comp
[
0
][
240
],
240
*
3
,
1
,
1
);
#endif
...
...
@@ -644,7 +640,7 @@ int nr_rx_pbch( PHY_VARS_NR_UE *ue,
#ifdef DEBUG_PBCH
//pbch_e_rx = &nr_ue_pbch_vars->llr[0];
short
*
p
=
(
short
*
)
&
(
nr_ue_pbch_vars
->
rxdataF_comp
[
0
][
first_symbol
*
20
*
12
]);
short
*
p
=
(
short
*
)
&
(
nr_ue_pbch_vars
->
rxdataF_comp
[
0
][
20
*
12
]);
for
(
int
cnt
=
0
;
cnt
<
864
;
cnt
++
)
printf
(
"pbch rx llr %d
\n
"
,
*
(
pbch_e_rx
+
cnt
));
...
...
@@ -720,14 +716,13 @@ int nr_rx_pbch( PHY_VARS_NR_UE *ue,
ue
->
dl_indication
.
rx_ind
=
&
ue
->
rx_ind
;
// hang on rx_ind instance
//ue->rx_ind.sfn_slot = 0; //should be set by higher-1-layer, i.e. clean_and_set_if_instance()
ue
->
rx_ind
.
number_pdus
=
ue
->
rx_ind
.
number_pdus
+
1
;
ue
->
rx_ind
.
rx_indication_body
=
(
fapi_nr_rx_indication_body_t
*
)
malloc
(
sizeof
(
fapi_nr_rx_indication_body_t
));
ue
->
rx_ind
.
rx_indication_body
->
pdu_type
=
FAPI_NR_RX_PDU_TYPE_MIB
;
ue
->
rx_ind
.
rx_indication_body
->
mib_pdu
.
pdu
=
&
decoded_output
[
0
];
ue
->
rx_ind
.
rx_indication_body
->
mib_pdu
.
additional_bits
=
xtra_byte
;
ue
->
rx_ind
.
rx_indication_body
->
mib_pdu
.
ssb_index
=
ssb_index
;
// confirm with TCL
ue
->
rx_ind
.
rx_indication_body
->
mib_pdu
.
ssb_length
=
Lmax
;
// confirm with TCL
ue
->
rx_ind
.
rx_indication_body
->
mib_pdu
.
cell_id
=
frame_parms
->
Nid_cell
;
// confirm with TCL
ue
->
rx_ind
.
rx_indication_body
[
0
].
pdu_type
=
FAPI_NR_RX_PDU_TYPE_MIB
;
ue
->
rx_ind
.
rx_indication_body
[
0
].
mib_pdu
.
pdu
=
&
decoded_output
[
0
];
ue
->
rx_ind
.
rx_indication_body
[
0
].
mib_pdu
.
additional_bits
=
xtra_byte
;
ue
->
rx_ind
.
rx_indication_body
[
0
].
mib_pdu
.
ssb_index
=
ssb_index
;
// confirm with TCL
ue
->
rx_ind
.
rx_indication_body
[
0
].
mib_pdu
.
ssb_length
=
Lmax
;
// confirm with TCL
ue
->
rx_ind
.
rx_indication_body
[
0
].
mib_pdu
.
cell_id
=
frame_parms
->
Nid_cell
;
// confirm with TCL
ue
->
rx_ind
.
number_pdus
=
1
;
if
(
ue
->
if_inst
&&
ue
->
if_inst
->
dl_indication
)
ue
->
if_inst
->
dl_indication
(
&
ue
->
dl_indication
);
...
...
openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
View file @
612c8632
...
...
@@ -254,3 +254,4 @@ int8_t nr_ue_phy_config_request(nr_phy_config_t *phy_config){
return
0
;
}
openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
View file @
612c8632
...
...
@@ -56,7 +56,7 @@
//#define DEBUG_PHY_PROC
#define NR_PDCCH_SCHED
//
#define NR_PDCCH_SCHED_DEBUG
#define NR_PDCCH_SCHED_DEBUG
//#define NR_PUCCH_SCHED
//#define NR_PUCCH_SCHED_DEBUG
...
...
@@ -3350,14 +3350,14 @@ int nr_ue_pdcch_procedures(uint8_t eNB_id,PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *
ue
->
dci_ind
.
dci_list
[
i
].
dci_format
=
dci_alloc_rx
[
i
].
format
;
ue
->
dci_ind
.
dci_list
[
i
].
n_CCE
=
dci_alloc_rx
[
i
].
firstCCE
;
ue
->
dci_ind
.
dci_list
[
i
].
N_CCE
=
(
int
)
dci_alloc_rx
[
i
].
L
;
ue
->
dci_ind
.
number_of_dcis
=
ue
->
dci_ind
.
number_of_dcis
+
1
;
memcpy
(
&
ue
->
dci_ind
.
dci_list
[
i
].
dci
,
&
nr_dci_info_extracted
,
sizeof
(
fapi_nr_dci_pdu_rel15_t
)
);
memcpy
(
&
ue
->
dci_ind
.
dci_list
[
i
].
dci
,
&
nr_dci_info_extracted
,
sizeof
(
fapi_nr_dci_pdu_rel15_t
)
);
// TODO: check where should we send up this message.
// ue->if_inst->dl_indication(&ue->dl_indication);
}
// end for loop dci_cnt
// TODO: check where should we send up this message.
ue
->
if_inst
->
dl_indication
(
&
ue
->
dl_indication
);
#if UE_TIMING_TRACE
stop_meas
(
&
ue
->
dlsch_rx_pdcch_stats
);
#endif
...
...
openair1/SIMULATION/NR_PHY/dlsim.c
View file @
612c8632
...
...
@@ -622,7 +622,7 @@ int main(int argc, char **argv)
uint32_t
number_of_search_space_per_slot
=
1
;
uint32_t
first_symbol_index
=
0
;
uint32_t
search_space_duration
;
// element of search space
uint32_t
search_space_duration
=
0
;
// element of search space
uint32_t
coreset_duration
;
// element of coreset
coreset_duration
=
num_symbols
*
number_of_search_space_per_slot
;
...
...
openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
View file @
612c8632
...
...
@@ -33,6 +33,7 @@
#include "NR_IF_Module.h"
#include "mac_proto.h"
#include "assertions.h"
#include "LAYER2/NR_MAC_UE/mac_extern.h"
#include <stdio.h>
...
...
@@ -134,7 +135,7 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info){
for
(
i
=
0
;
i
<
dl_info
->
dci_ind
->
number_of_dcis
;
++
i
){
printf
(
">>>NR_IF_Module i=%d, dl_info->dci_ind->number_of_dcis=%d
\n
"
,
i
,
dl_info
->
dci_ind
->
number_of_dcis
);
fapi_nr_dci_pdu_rel15_t
*
dci
=
&
dl_info
->
dci_ind
->
dci_list
[
i
].
dci
;
/*
ret_mask |= (handle_dci(
dl_info->module_id,
dl_info->cc_id,
...
...
@@ -142,7 +143,7 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info){
dci,
(dl_info->dci_ind->dci_list+i)->rnti,
(dl_info->dci_ind->dci_list+i)->dci_format)) << FAPI_NR_DCI_IND;
*/
/*switch((dl_info->dci_ind->dci_list+i)->dci_type){
case FAPI_NR_DCI_TYPE_0_0:
...
...
@@ -224,6 +225,9 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info){
}
}
//clean up nr_downlink_indication_t *dl_info
dl_info
->
rx_ind
=
NULL
;
dl_info
->
dci_ind
=
NULL
;
AssertFatal
(
nr_ue_if_module_inst
[
module_id
]
!=
NULL
,
"IF module is void!
\n
"
);
nr_ue_if_module_inst
[
module_id
]
->
scheduled_response
(
&
mac
->
scheduled_response
);
...
...
@@ -256,3 +260,52 @@ int nr_ue_if_module_kill(uint32_t module_id) {
}
return
0
;
}
int
nr_ue_dcireq
(
nr_dcireq_t
*
dcireq
)
{
fapi_nr_dl_config_request_t
*
dl_config
=&
dcireq
->
dl_config_req
;
// Type0 PDCCH search space
dl_config
->
number_pdus
=
1
;
dl_config
->
dl_config_list
[
0
].
pdu_type
=
FAPI_NR_DL_CONFIG_TYPE_DCI
;
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
rnti
=
0
;
// to be set
uint64_t
mask
=
0x0
;
uint16_t
num_rbs
=
24
;
uint16_t
rb_offset
=
0
;
uint16_t
cell_id
=
0
;
uint16_t
num_symbols
=
2
;
for
(
int
i
=
0
;
i
<
(
num_rbs
/
6
);
++
i
){
// 38.331 Each bit corresponds a group of 6 RBs
mask
=
mask
>>
1
;
mask
=
mask
|
0x100000000000
;
}
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
coreset
.
frequency_domain_resource
=
mask
;
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
coreset
.
rb_offset
=
rb_offset
;
// additional parameter other than coreset
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
coreset
.
duration
=
num_symbols
;
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
coreset
.
cce_reg_mapping_type
=
CCE_REG_MAPPING_TYPE_INTERLEAVED
;
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
coreset
.
cce_reg_interleaved_reg_bundle_size
=
6
;
// L 38.211 7.3.2.2
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
coreset
.
cce_reg_interleaved_interleaver_size
=
2
;
// R 38.211 7.3.2.2
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
coreset
.
cce_reg_interleaved_shift_index
=
cell_id
;
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
coreset
.
precoder_granularity
=
PRECODER_GRANULARITY_SAME_AS_REG_BUNDLE
;
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
coreset
.
pdcch_dmrs_scrambling_id
=
cell_id
;
uint32_t
number_of_search_space_per_slot
=
1
;
uint32_t
first_symbol_index
=
0
;
uint32_t
search_space_duration
=
0
;
// element of search space
uint32_t
coreset_duration
;
// element of coreset
coreset_duration
=
num_symbols
*
number_of_search_space_per_slot
;
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
number_of_candidates
[
0
]
=
table_38213_10_1_1_c2
[
0
];
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
number_of_candidates
[
1
]
=
table_38213_10_1_1_c2
[
1
];
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
number_of_candidates
[
2
]
=
table_38213_10_1_1_c2
[
2
];
// CCE aggregation level = 4
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
number_of_candidates
[
3
]
=
table_38213_10_1_1_c2
[
3
];
// CCE aggregation level = 8
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
number_of_candidates
[
4
]
=
table_38213_10_1_1_c2
[
4
];
// CCE aggregation level = 16
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
duration
=
search_space_duration
;
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
monitoring_symbols_within_slot
=
(
0x3fff
<<
first_symbol_index
)
&
(
0x3fff
>>
(
14
-
coreset_duration
-
first_symbol_index
))
&
0x3fff
;
dl_config
->
dl_config_list
[
0
].
dci_config_pdu
.
dci_config_rel15
.
N_RB_BWP
=
106
;
}
targets/RT/USER/nr-ue.c
View file @
612c8632
...
...
@@ -687,7 +687,7 @@ static void *UE_thread_rxn_txnp4(void *arg) {
UE
->
dcireq
.
cc_id
=
0
;
UE
->
dcireq
.
frame
=
proc
->
frame_rx
;
UE
->
dcireq
.
slot
=
proc
->
nr_tti_rx
;
//UE->if_inst->dcireq(&UE->dcireq);
nr_ue_dcireq
(
&
UE
->
dcireq
);
//to be replaced with function pointer later
#ifdef UE_SLOT_PARALLELISATION
phy_procedures_slot_parallelization_nrUE_RX
(
UE
,
proc
,
0
,
0
,
1
,
UE
->
mode
,
no_relay
,
NULL
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment