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
zzha zzha
OpenXG-RAN
Commits
c0f7e458
Commit
c0f7e458
authored
Apr 20, 2023
by
francescomani
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
rework and adjust size of config_request mac vectors
parent
15822a0a
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
41 additions
and
100 deletions
+41
-100
openair1/SIMULATION/NR_PHY/dlsim.c
openair1/SIMULATION/NR_PHY/dlsim.c
+1
-1
openair2/LAYER2/NR_MAC_UE/config_ue.c
openair2/LAYER2/NR_MAC_UE/config_ue.c
+18
-32
openair2/LAYER2/NR_MAC_UE/mac_proto.h
openair2/LAYER2/NR_MAC_UE/mac_proto.h
+1
-1
openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
+0
-14
openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
+9
-3
openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c
openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c
+12
-49
No files found.
openair1/SIMULATION/NR_PHY/dlsim.c
View file @
c0f7e458
...
...
@@ -888,7 +888,7 @@ int main(int argc, char **argv)
//Configure UE
NR_BCCH_BCH_Message_t
*
mib
=
get_new_MIB_NR
(
scc
);
nr_rrc_mac_config_req_mib
(
0
,
0
,
0
,
mib
,
false
);
nr_rrc_mac_config_req_mib
(
0
,
0
,
0
,
mib
->
message
.
choice
.
mib
,
false
);
nr_rrc_mac_config_req_scg
(
0
,
0
,
0
,
secondaryCellGroup
);
nr_dcireq_t
dcireq
;
...
...
openair2/LAYER2/NR_MAC_UE/config_ue.c
View file @
c0f7e458
...
...
@@ -693,6 +693,21 @@ void configure_current_BWP(NR_UE_MAC_INST_t *mac,
}
void
init_config_request
(
NR_UE_MAC_INST_t
*
mac
)
{
if
(
mac
->
dl_config_request
==
NULL
&&
mac
->
ul_config_request
==
NULL
)
{
int
scs
=
mac
->
mib
->
subCarrierSpacingCommon
;
if
(
mac
->
frequency_range
==
FR2
)
scs
+=
2
;
int
slots_per_frame
=
nr_slots_per_frame
[
scs
];
LOG_I
(
NR_MAC
,
"Initializing dl and ul config_request. num_slots = %d
\n
"
,
slots_per_frame
);
mac
->
dl_config_request
=
calloc
(
slots_per_frame
,
sizeof
(
*
mac
->
dl_config_request
));
mac
->
ul_config_request
=
calloc
(
slots_per_frame
,
sizeof
(
*
mac
->
ul_config_request
));
for
(
int
i
=
0
;
i
<
slots_per_frame
;
i
++
)
pthread_mutex_init
(
&
(
mac
->
ul_config_request
[
i
].
mutex_ul_config
),
NULL
);
}
}
void
nr_rrc_mac_config_req_mib
(
module_id_t
module_id
,
uint8_t
gNB_index
,
int
cc_idP
,
...
...
@@ -701,9 +716,9 @@ void nr_rrc_mac_config_req_mib(module_id_t module_id,
{
NR_UE_MAC_INST_t
*
mac
=
get_mac_inst
(
module_id
);
AssertFatal
(
mib
,
"MIB should not be NULL
\n
"
);
if
(
mac
->
dl_config_request
==
NULL
)
// for SIB1 reception
mac
->
dl_config_request
=
calloc
(
NR_MAX_SLOTS_PER_FRAME
,
sizeof
(
*
mac
->
dl_config_request
));
// initialize dl and ul config_request upon first reception of MIB
mac
->
mib
=
mib
;
// update by every reception
init_config_request
(
mac
);
mac
->
phy_config
.
Mod_id
=
module_id
;
mac
->
phy_config
.
CC_id
=
cc_idP
;
mac
->
get_sib1
=
sched_sib1
;
...
...
@@ -721,30 +736,6 @@ void nr_rrc_mac_config_req_sib1(module_id_t module_id,
config_common_ue_sa
(
mac
,
module_id
,
cc_idP
);
configure_current_BWP
(
mac
,
scc
,
NULL
);
fapi_nr_config_request_t
*
cfg
=
&
mac
->
phy_config
.
config_req
;
int
num_slots_ul
=
nr_slots_per_frame
[
mac
->
mib
->
subCarrierSpacingCommon
];
if
(
cfg
->
cell_config
.
frame_duplex_type
==
TDD
){
num_slots_ul
=
scc
->
tdd_UL_DL_ConfigurationCommon
->
pattern1
.
nrofUplinkSlots
;
if
(
scc
->
tdd_UL_DL_ConfigurationCommon
->
pattern1
.
nrofUplinkSymbols
>
0
)
{
num_slots_ul
++
;
}
}
LOG_I
(
NR_MAC
,
"Initializing ul_config_request. num_slots_ul = %d
\n
"
,
num_slots_ul
);
mac
->
ul_config_request
=
calloc
(
num_slots_ul
,
sizeof
(
*
mac
->
ul_config_request
));
for
(
int
i
=
0
;
i
<
num_slots_ul
;
i
++
)
pthread_mutex_init
(
&
(
mac
->
ul_config_request
[
i
].
mutex_ul_config
),
NULL
);
int
num_slots_dl
=
nr_slots_per_frame
[
mac
->
mib
->
subCarrierSpacingCommon
];
if
(
cfg
->
cell_config
.
frame_duplex_type
==
TDD
)
{
num_slots_dl
=
scc
->
tdd_UL_DL_ConfigurationCommon
->
pattern1
.
nrofDownlinkSlots
;
if
(
scc
->
tdd_UL_DL_ConfigurationCommon
->
pattern1
.
nrofDownlinkSymbols
>
0
)
{
num_slots_dl
++
;
}
}
LOG_I
(
NR_MAC
,
"Initializing dl_config_request. num_slots_dl = %d
\n
"
,
num_slots_dl
);
mac
->
dl_config_request
=
realloc
(
mac
->
dl_config_request
,
num_slots_dl
*
sizeof
(
*
mac
->
dl_config_request
));
memset
(
mac
->
dl_config_request
,
0
,
num_slots_dl
*
sizeof
(
fapi_nr_dl_config_request_t
));
// Setup the SSB to Rach Occasionsif (cell_group_config->spCellConfig) { mapping according to the config
build_ssb_to_ro_map
(
mac
);
if
(
!
get_softmodem_params
()
->
emulate_l1
)
...
...
@@ -789,10 +780,6 @@ void nr_rrc_mac_config_req_mcg(module_id_t module_id,
free
(
mac
->
scc_SIB
);
mac
->
scc_SIB
=
NULL
;
}
int
num_slots
=
mac
->
scc
->
tdd_UL_DL_ConfigurationCommon
->
pattern1
.
nrofUplinkSlots
;
if
(
mac
->
scc
->
tdd_UL_DL_ConfigurationCommon
->
pattern1
.
nrofUplinkSymbols
>
0
)
{
num_slots
++
;
}
mac
->
state
=
UE_NOT_SYNC
;
mac
->
ra
.
ra_state
=
RA_UE_IDLE
;
mac
->
physCellId
=
*
mac
->
scc
->
physCellId
;
...
...
@@ -802,7 +789,6 @@ void nr_rrc_mac_config_req_mcg(module_id_t module_id,
mac
->
synch_request
.
synch_req
.
target_Nid_cell
=
mac
->
physCellId
;
mac
->
if_module
->
synch_request
(
&
mac
->
synch_request
);
}
mac
->
ul_config_request
=
calloc
(
num_slots
,
sizeof
(
*
mac
->
ul_config_request
));
config_common_ue
(
mac
,
module_id
,
cc_idP
);
mac
->
crnti
=
cell_group_config
->
spCellConfig
->
reconfigurationWithSync
->
newUE_Identity
;
LOG_I
(
MAC
,
"Configuring CRNTI %x
\n
"
,
mac
->
crnti
);
...
...
@@ -827,7 +813,7 @@ void nr_rrc_mac_config_req_scg(module_id_t module_id,
NR_UE_MAC_INST_t
*
mac
=
get_mac_inst
(
module_id
);
RA_config_t
*
ra
=
&
mac
->
ra
;
AssertFatal
(
scell_group_config
==
NULL
,
"scell_group_config cannot be NULL
\n
"
);
AssertFatal
(
scell_group_config
,
"scell_group_config cannot be NULL
\n
"
);
mac
->
cg
=
scell_group_config
;
mac
->
servCellIndex
=
*
scell_group_config
->
spCellConfig
->
servCellIndex
;
...
...
openair2/LAYER2/NR_MAC_UE/mac_proto.h
View file @
c0f7e458
...
...
@@ -438,7 +438,7 @@ static uint8_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac,
dci_pdu_rel15_t
*
dci_pdu_rel15
,
int
slot
);
fapi_nr_ul_config_request_t
*
get_ul_config_request
(
NR_UE_MAC_INST_t
*
mac
,
int
slot
);
fapi_nr_ul_config_request_t
*
get_ul_config_request
(
NR_UE_MAC_INST_t
*
mac
,
int
slot
,
int
fb_time
);
fapi_nr_dl_config_request_t
*
get_dl_config_request
(
NR_UE_MAC_INST_t
*
mac
,
int
slot
);
void
fill_ul_config
(
fapi_nr_ul_config_request_t
*
ul_config
,
frame_t
frame_tx
,
int
slot_tx
,
uint8_t
pdu_type
);
...
...
openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
View file @
c0f7e458
...
...
@@ -78,20 +78,6 @@ NR_UE_MAC_INST_t * nr_l2_init_ue(NR_UE_RRC_INST_t* rrc_inst) {
// free memory
free_nr_noS1_bearer_config
(
&
rbconfig
,
&
rlc_rbconfig
);
}
// Allocate memory for ul_config_request in the mac instance. This is now a pointer and will
// point to a list of structures (one for each UL slot) to store PUSCH scheduling parameters
// received from UL DCI.
if
(
nr_ue_mac_inst
->
scc
)
{
NR_TDD_UL_DL_ConfigCommon_t
*
tdd
=
nr_ue_mac_inst
->
scc
->
tdd_UL_DL_ConfigurationCommon
;
int
num_slots_ul
=
tdd
?
tdd
->
pattern1
.
nrofUplinkSlots
:
nr_slots_per_frame
[
*
nr_ue_mac_inst
->
scc
->
ssbSubcarrierSpacing
];
if
(
tdd
&&
nr_ue_mac_inst
->
scc
->
tdd_UL_DL_ConfigurationCommon
->
pattern1
.
nrofUplinkSymbols
>
0
)
{
num_slots_ul
++
;
}
LOG_D
(
NR_MAC
,
"In %s: Initializing ul_config_request. num_slots_ul = %d
\n
"
,
__FUNCTION__
,
num_slots_ul
);
nr_ue_mac_inst
->
ul_config_request
=
(
fapi_nr_ul_config_request_t
*
)
calloc
(
num_slots_ul
,
sizeof
(
fapi_nr_ul_config_request_t
));
for
(
int
i
=
0
;
i
<
num_slots_ul
;
i
++
)
pthread_mutex_init
(
&
(
nr_ue_mac_inst
->
ul_config_request
[
i
].
mutex_ul_config
),
NULL
);
}
}
else
{
LOG_I
(
MAC
,
"Running without CellGroupConfig
\n
"
);
...
...
openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
View file @
c0f7e458
...
...
@@ -181,6 +181,12 @@ void nr_ue_init_mac(module_id_t module_idP)
// mac->scheduling_info.PathlossChange_db = nr_get_db_dl_PathlossChange(mac->scheduling_info.PathlossChange);
// mac->PHR_reporting_active = 0;
mac
->
first_sync_frame
=
-
1
;
mac
->
get_sib1
=
false
;
mac
->
phy_config_request_sent
=
false
;
mac
->
state
=
UE_NOT_SYNC
;
memset
(
&
mac
->
ssb_measurements
,
0
,
sizeof
(
mac
->
ssb_measurements
));
for
(
int
i
=
0
;
i
<
NR_MAX_NUM_LCID
;
i
++
)
{
LOG_D
(
NR_MAC
,
"[UE%d] Applying default logical channel config for LCGID %d
\n
"
,
module_idP
,
i
);
...
...
@@ -511,7 +517,7 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr
if
(
ret
!=
-
1
){
// Get UL config request corresponding slot_tx
fapi_nr_ul_config_request_t
*
ul_config
=
get_ul_config_request
(
mac
,
slot_tx
);
fapi_nr_ul_config_request_t
*
ul_config
=
get_ul_config_request
(
mac
,
slot_tx
,
tda_info
.
k2
);
if
(
!
ul_config
)
{
LOG_W
(
MAC
,
"In %s: ul_config request is NULL. Probably due to unexpected UL DCI in frame.slot %d.%d. Ignoring DCI!
\n
"
,
__FUNCTION__
,
frame
,
slot
);
...
...
@@ -580,7 +586,7 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr
if
(
ret
!=
-
1
){
// Get UL config request corresponding slot_tx
fapi_nr_ul_config_request_t
*
ul_config
=
get_ul_config_request
(
mac
,
slot_tx
);
fapi_nr_ul_config_request_t
*
ul_config
=
get_ul_config_request
(
mac
,
slot_tx
,
tda_info
.
k2
);
if
(
!
ul_config
)
{
LOG_W
(
MAC
,
"In %s: ul_config request is NULL. Probably due to unexpected UL DCI in frame.slot %d.%d. Ignoring DCI!
\n
"
,
__FUNCTION__
,
frame
,
slot
);
...
...
@@ -4132,7 +4138,7 @@ int nr_ue_process_rar(nr_downlink_indication_t *dl_info, int pdu_id)
if
(
ret
!=
-
1
){
fapi_nr_ul_config_request_t
*
ul_config
=
get_ul_config_request
(
mac
,
slot_tx
);
fapi_nr_ul_config_request_t
*
ul_config
=
get_ul_config_request
(
mac
,
slot_tx
,
tda_info
.
k2
);
uint16_t
rnti
=
mac
->
crnti
;
if
(
!
ul_config
)
{
...
...
openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c
View file @
c0f7e458
...
...
@@ -107,31 +107,19 @@ void fill_scheduled_response(nr_scheduled_response_t *scheduled_response,
* This function returns the UL config corresponding to a given UL slot
* from MAC instance .
*/
fapi_nr_ul_config_request_t
*
get_ul_config_request
(
NR_UE_MAC_INST_t
*
mac
,
int
slot
)
fapi_nr_ul_config_request_t
*
get_ul_config_request
(
NR_UE_MAC_INST_t
*
mac
,
int
slot
,
int
fb_time
)
{
NR_TDD_UL_DL_ConfigCommon_t
*
tdd_config
=
mac
->
scc
==
NULL
?
mac
->
scc_SIB
->
tdd_UL_DL_ConfigurationCommon
:
mac
->
scc
->
tdd_UL_DL_ConfigurationCommon
;
//Check if requested on the right slot
AssertFatal
(
is_nr_UL_slot
(
tdd_config
,
slot
,
mac
->
frame_type
)
!=
0
,
"
%s called at wrong slot %d
\n
"
,
__func__
,
slot
);
AssertFatal
(
is_nr_UL_slot
(
tdd_config
,
slot
,
mac
->
frame_type
)
!=
0
,
"
UL config_request called at wrong slot %d
\n
"
,
slot
);
// Calculate the index of the UL slot in mac->ul_config_request list. This is
// based on the TDD pattern (slot configuration period) and number of UL+mixed
// slots in the period. TS 38.213 Sec 11.1
int
mu
=
mac
->
current_UL_BWP
.
scs
;
const
int
n
=
nr_slots_per_frame
[
mu
];
const
int
num_slots_per_tdd
=
tdd_config
?
(
n
>>
(
7
-
tdd_config
->
pattern1
.
dl_UL_TransmissionPeriodicity
))
:
n
;
const
int
num_slots_ul
=
tdd_config
?
(
tdd_config
->
pattern1
.
nrofUplinkSlots
+
(
tdd_config
->
pattern1
.
nrofUplinkSymbols
!=
0
))
:
n
;
int
index
=
slot
%
num_slots_ul
;
LOG_D
(
NR_MAC
,
"In %s slots per %s: %d, num_slots %d, index %d
\n
"
,
__FUNCTION__
,
tdd_config
?
"TDD"
:
"FDD"
,
num_slots_per_tdd
,
num_slots_ul
,
index
);
if
(
mac
->
ul_config_request
)
return
&
mac
->
ul_config_request
[
index
];
AssertFatal
(
fb_time
<
n
,
"Cannot schedule to a slot more than 1 frame away, ul_config_request is not big enough
\n
"
);
if
(
mac
->
ul_config_request
)
return
&
mac
->
ul_config_request
[
slot
];
else
{
LOG_E
(
NR_MAC
,
"mac->ul_config_request not set
\n
"
);
return
NULL
;
...
...
@@ -144,33 +132,8 @@ fapi_nr_ul_config_request_t *get_ul_config_request(NR_UE_MAC_INST_t *mac, int sl
*/
fapi_nr_dl_config_request_t
*
get_dl_config_request
(
NR_UE_MAC_INST_t
*
mac
,
int
slot
)
{
int
index
;
if
(
!
mac
->
scc
&&
!
mac
->
scc_SIB
)
index
=
0
;
else
{
NR_TDD_UL_DL_ConfigCommon_t
*
tdd_config
=
mac
->
scc
==
NULL
?
mac
->
scc_SIB
->
tdd_UL_DL_ConfigurationCommon
:
mac
->
scc
->
tdd_UL_DL_ConfigurationCommon
;
//Check if requested on the right slot
AssertFatal
(
is_nr_DL_slot
(
tdd_config
,
slot
)
!=
0
,
"%s called at wrong slot %d
\n
"
,
__func__
,
slot
);
// Calculate the index of the DL slot in mac->ul_config_request list. This is
// based on the TDD pattern (slot configuration period) and number of DL+mixed
// slots in the period. TS 38.213 Sec 11.1
int
mu
=
mac
->
current_UL_BWP
.
scs
;
const
int
n
=
nr_slots_per_frame
[
mu
];
const
int
num_slots_per_tdd
=
tdd_config
?
(
n
>>
(
7
-
tdd_config
->
pattern1
.
dl_UL_TransmissionPeriodicity
))
:
n
;
const
int
num_slots_dl
=
tdd_config
?
(
tdd_config
->
pattern1
.
nrofDownlinkSlots
+
(
tdd_config
->
pattern1
.
nrofDownlinkSymbols
!=
0
))
:
n
;
index
=
slot
%
num_slots_dl
;
LOG_D
(
NR_MAC
,
"In %s slots per %s: %d, num_slots %d, index %d
\n
"
,
__FUNCTION__
,
tdd_config
?
"TDD"
:
"FDD"
,
num_slots_per_tdd
,
num_slots_dl
,
index
);
}
if
(
mac
->
dl_config_request
)
return
&
mac
->
dl_config_request
[
index
];
if
(
mac
->
dl_config_request
)
return
&
mac
->
dl_config_request
[
slot
];
else
{
LOG_E
(
NR_MAC
,
"mac->dl_config_request not set
\n
"
);
return
NULL
;
...
...
@@ -928,7 +891,7 @@ void nr_ue_aperiodic_srs_scheduling(NR_UE_MAC_INST_t *mac, long resource_trigger
}
int
sched_frame
=
frame
+
(
slot
+
slot_offset
>=
n_slots_frame
)
%
1024
;
fapi_nr_ul_config_request_t
*
ul_config
=
get_ul_config_request
(
mac
,
sched_slot
);
fapi_nr_ul_config_request_t
*
ul_config
=
get_ul_config_request
(
mac
,
sched_slot
,
slot_offset
);
fapi_nr_ul_config_srs_pdu
*
srs_config_pdu
=
&
ul_config
->
ul_config_list
[
ul_config
->
number_pdus
].
srs_config_pdu
;
configure_srs_pdu
(
mac
,
srs_resource
,
srs_config_pdu
,
0
,
0
);
fill_ul_config
(
ul_config
,
sched_frame
,
sched_slot
,
FAPI_NR_UL_CONFIG_TYPE_SRS
);
...
...
@@ -981,7 +944,7 @@ bool nr_ue_periodic_srs_scheduling(module_id_t mod_id, frame_t frame, slot_t slo
// Check if UE should transmit the SRS
if
((
frame
*
n_slots_frame
+
slot
-
offset
)
%
period
==
0
)
{
fapi_nr_ul_config_request_t
*
ul_config
=
get_ul_config_request
(
mac
,
slot
);
fapi_nr_ul_config_request_t
*
ul_config
=
get_ul_config_request
(
mac
,
slot
,
0
);
fapi_nr_ul_config_srs_pdu
*
srs_config_pdu
=
&
ul_config
->
ul_config_list
[
ul_config
->
number_pdus
].
srs_config_pdu
;
configure_srs_pdu
(
mac
,
srs_resource
,
srs_config_pdu
,
period
,
offset
);
...
...
@@ -1070,7 +1033,7 @@ void nr_ue_ul_scheduler(nr_uplink_indication_t *ul_info)
NR_UE_MAC_INST_t
*
mac
=
get_mac_inst
(
mod_id
);
RA_config_t
*
ra
=
&
mac
->
ra
;
fapi_nr_ul_config_request_t
*
ul_config
=
get_ul_config_request
(
mac
,
slot_tx
);
fapi_nr_ul_config_request_t
*
ul_config
=
get_ul_config_request
(
mac
,
slot_tx
,
0
);
if
(
!
ul_config
)
LOG_E
(
NR_MAC
,
"mac->ul_config is null!
\n
"
);
...
...
@@ -2239,7 +2202,7 @@ void nr_ue_pucch_scheduler(module_id_t module_idP, frame_t frameP, int slotP, vo
if
(
num_res
>
1
)
multiplex_pucch_resource
(
mac
,
pucch
,
num_res
);
fapi_nr_ul_config_request_t
*
ul_config
=
get_ul_config_request
(
mac
,
slotP
);
fapi_nr_ul_config_request_t
*
ul_config
=
get_ul_config_request
(
mac
,
slotP
,
0
);
pthread_mutex_lock
(
&
ul_config
->
mutex_ul_config
);
for
(
int
j
=
0
;
j
<
num_res
;
j
++
)
{
if
(
pucch
[
j
].
n_harq
+
pucch
[
j
].
n_sr
+
pucch
[
j
].
n_csi
!=
0
)
{
...
...
@@ -2504,7 +2467,7 @@ void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_frame_t s
if
(
ra
->
ra_state
!=
GENERATE_PREAMBLE
)
return
;
fapi_nr_ul_config_request_t
*
ul_config
=
get_ul_config_request
(
mac
,
slotP
);
fapi_nr_ul_config_request_t
*
ul_config
=
get_ul_config_request
(
mac
,
slotP
,
0
);
if
(
!
ul_config
)
{
LOG_E
(
NR_MAC
,
"mac->ul_config is null!
\n
"
);
return
;
...
...
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