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
Michael Black
OpenXG-RAN
Commits
7a00e05b
Commit
7a00e05b
authored
Jun 10, 2018
by
Raymond Knopp
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
tx path debugging, SCI/SLSCH generation seems ok
parent
c6d705d6
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
87 additions
and
33 deletions
+87
-33
openair1/PHY/INIT/lte_init_ue.c
openair1/PHY/INIT/lte_init_ue.c
+1
-0
openair1/PHY/LTE_TRANSPORT/pssch.h
openair1/PHY/LTE_TRANSPORT/pssch.h
+1
-1
openair1/PHY/LTE_TRANSPORT/slsch.c
openair1/PHY/LTE_TRANSPORT/slsch.c
+15
-14
openair1/PHY/impl_defs_lte.h
openair1/PHY/impl_defs_lte.h
+2
-0
openair2/LAYER2/MAC/config_ue.c
openair2/LAYER2/MAC/config_ue.c
+11
-1
openair2/LAYER2/MAC/ue_procedures.c
openair2/LAYER2/MAC/ue_procedures.c
+49
-9
openair2/RRC/LITE/rrc_UE.c
openair2/RRC/LITE/rrc_UE.c
+8
-8
No files found.
openair1/PHY/INIT/lte_init_ue.c
View file @
7a00e05b
...
...
@@ -634,6 +634,7 @@ int phy_config_SL(int Mod_id,SLDCH_t *sldch_rx,SLSCH_t *slsch_rx) {
memcpy
((
void
*
)
&
ue
->
sldch_rx
,(
void
*
)
sldch_rx
,
sizeof
(
SLDCH_t
));
memcpy
((
void
*
)
&
ue
->
slsch_rx
,(
void
*
)
slsch_rx
,
sizeof
(
SLSCH_t
));
ue
->
slsch_active
=
1
;
return
(
0
);
}
...
...
openair1/PHY/LTE_TRANSPORT/pssch.h
View file @
7a00e05b
#
define TRP8_MAX 106
#
include "PHY/defs.h"
const
int
trp8
[
TRP8_MAX
+
1
][
8
]
=
{{
1
,
0
,
0
,
0
,
0
,
0
,
0
,
0
},
{
0
,
1
,
0
,
0
,
0
,
0
,
0
,
0
},
{
0
,
0
,
1
,
0
,
0
,
0
,
0
,
0
},
...
...
openair1/PHY/LTE_TRANSPORT/slsch.c
View file @
7a00e05b
...
...
@@ -338,6 +338,10 @@ void idft_slcch(LTE_DL_FRAME_PARMS *frame_parms,int32_t *z,int slot)
void
pscch_codingmodulation
(
PHY_VARS_UE
*
ue
,
int
frame_tx
,
int
subframe_tx
,
uint32_t
a
,
int
slot
)
{
AssertFatal
(
ue
!=
NULL
,
"UE is null
\n
"
);
AssertFatal
(
frame_tx
>=
0
&&
frame_tx
<
1024
,
"frame %d is illegal
\n
"
,
frame_tx
);
AssertFatal
(
subframe_tx
>=
0
&&
subframe_tx
<
10
,
"subframe %d is illegal
\n
"
,
subframe_tx
);
AssertFatal
(
slot
>=
0
&&
slot
<
2
,
"slot %d is illegal
\n
"
,
slot
);
LTE_UE_PSCCH_TX
*
pscch
=
ue
->
pscch_vars_tx
;
SLSCH_t
*
slsch
=
ue
->
slsch
;
int
tx_amp
;
...
...
@@ -493,7 +497,7 @@ void pscch_codingmodulation(PHY_VARS_UE *ue,int frame_tx,int subframe_tx,uint32_
NULL
,
0
);
ue
->
pscch_generated
=
1
+
slot
;
ue
->
pscch_generated
|=
(
1
+
slot
)
;
ue
->
generate_ul_signal
[
subframe_tx
][
0
]
=
0
;
...
...
@@ -625,8 +629,6 @@ void slsch_codingmodulation(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,int frame_tx,in
void
check_and_generate_pssch
(
PHY_VARS_UE
*
ue
,
UE_rxtx_proc_t
*
proc
,
int
frame_tx
,
int
subframe_tx
)
{
LOG_I
(
PHY
,
"Checking pssch for SFN/SF %d.%d (slsch_active %d)
\n
"
,
frame_tx
,
subframe_tx
,
ue
->
slsch_active
);
AssertFatal
(
frame_tx
<
1024
&&
frame_tx
>=
0
,
"frame %d is illegal
\n
"
,
frame_tx
);
AssertFatal
(
subframe_tx
<
10
&&
subframe_tx
>=
0
,
"subframe %d is illegal
\n
"
,
subframe_tx
);
...
...
@@ -649,6 +651,7 @@ void check_and_generate_pssch(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,int frame_tx,
absSF_modP
=
absSF_offset
%
P
;
LOG_I
(
PHY
,
"Checking pssch for absSF_mod P %d, SubframeBitmapSL_length %d
\n
"
,
absSF_modP
,
slsch
->
SubframeBitmapSL_length
);
// This is the condition for short SCCH bitmap (slsch->SubframeBitmapSL_length bits), check that the current subframe is for SLSCH
if
(
absSF_modP
<
slsch
->
SubframeBitmapSL_length
)
return
;
...
...
@@ -664,17 +667,13 @@ void check_and_generate_pssch(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,int frame_tx,
slsch
->
rvidx
);
// Note : this assumes Ntrp=8 for now
if
(
trp8
[
slsch
->
time_resource_pattern
][
absSF_modP
&
7
]
==
0
)
return
;
/*
// we have an opportunity in this subframe
if
(
absSF_modP
==
0
)
slsch
->
ljmod10
=
0
;
if (absSF_modP ==
1
0) slsch->ljmod10 = 0;
else slsch->ljmod10++;
if
(
slsch
->
ljmod10
==
0
)
slsch
->
ljmod10
=
0
;
*/
slsch_codingmodulation
(
ue
,
proc
,
frame_tx
,
subframe_tx
,
slsch
->
ljmod10
);
if
(
slsch
->
rvidx
==
0
)
slsch
->
rvidx
=
2
;
else
if
(
slsch
->
rvidx
==
2
)
slsch
->
rvidx
=
3
;
else
if
(
slsch
->
rvidx
==
3
)
slsch
->
rvidx
=
1
;
else
slsch
->
rvidx
=
0
;
}
void
check_and_generate_pscch
(
PHY_VARS_UE
*
ue
,
int
frame_tx
,
int
subframe_tx
)
{
...
...
@@ -688,7 +687,8 @@ void check_and_generate_pscch(PHY_VARS_UE *ue,int frame_tx,int subframe_tx) {
uint32_t
absSF
=
(
frame_tx
*
10
)
+
subframe_tx
;
uint32_t
absSF_offset
,
absSF_modP
;
if
(
ue
->
pscch_generated
==
1
)
return
;
LOG_D
(
PHY
,
"Checking pscch for absSF %d
\n
"
,
absSF
);
if
(
ue
->
pscch_generated
==
3
)
return
;
...
...
@@ -704,6 +704,7 @@ void check_and_generate_pscch(PHY_VARS_UE *ue,int frame_tx,int subframe_tx) {
ue
->
pscch_generated
=
0
;
return
;
}
LOG_D
(
PHY
,
"Checking pscch for absSF_modP %d (SubframeBitmalSL_length %d,mask %x)
\n
"
,
absSF_modP
,
slsch
->
SubframeBitmapSL_length
,
slsch
->
bitmap1
);
uint64_t
SFpos
=
((
uint64_t
)
1
)
<<
absSF_modP
;
if
((
SFpos
&
slsch
->
bitmap1
)
==
0
)
return
;
...
...
@@ -730,8 +731,8 @@ void check_and_generate_pscch(PHY_VARS_UE *ue,int frame_tx,int subframe_tx) {
uint32_t
b1
=
slsch
->
n_pscch
%
LPSCCH
;
uint32_t
b2
=
(
slsch
->
n_pscch
+
1
+
(
a1
%
(
LPSCCH
-
1
)))
%
LPSCCH
;
LOG_I
(
PHY
,
"Checking pscch for absSF %d (LPSCCH %d, M_RB_PSCCH_RP %d, a1 %d, a2 %d, b1 %d, b2 %d) pscch_coded %d
\n
"
,
absSF
,
LPSCCH
,
M_RB_PSCCH_RP
,
a1
,
a2
,
b1
,
b2
,
ue
->
pscch_coded
);
LOG_I
(
PHY
,
"Checking pscch for absSF %d (
N_SL_RB_SC %d,
LPSCCH %d, M_RB_PSCCH_RP %d, a1 %d, a2 %d, b1 %d, b2 %d) pscch_coded %d
\n
"
,
absSF
,
slsch
->
N_SL_RB_SC
,
LPSCCH
,
M_RB_PSCCH_RP
,
a1
,
a2
,
b1
,
b2
,
ue
->
pscch_coded
);
ue
->
slsch_sdu_active
=
1
;
...
...
@@ -1472,7 +1473,7 @@ void rx_slsch(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc, int frame_rx,int subframe_rx
// we have an opportunity in this subframe
if
(
absSF_modP
==
slsch
->
SubframeBitmapSL_length
)
slsch
->
ljmod10
=
0
;
else
slsch
->
ljmod10
++
;
if
(
slsch
->
ljmod10
==
0
)
slsch
->
ljmod10
=
0
;
if
(
slsch
->
ljmod10
==
1
0
)
slsch
->
ljmod10
=
0
;
if
(
slsch
->
rvidx
==
0
)
{
// first new transmission in period, get a new packet
ue
->
slsch_decoded
=
0
;
...
...
openair1/PHY/impl_defs_lte.h
View file @
7a00e05b
...
...
@@ -63,6 +63,8 @@
#define NB_RX_ANTENNAS_MAX 64
#define TRP8_MAX 106
#ifdef OCP_FRAMEWORK
#include "enums.h"
#else
...
...
openair2/LAYER2/MAC/config_ue.c
View file @
7a00e05b
...
...
@@ -741,6 +741,16 @@ rrc_mac_config_req_ue(module_id_t Mod_idP,
UE_mac_inst
[
Mod_idP
].
slsch
.
N_SL_RB_data
=
preconfigpool
->
data_TF_ResourceConfig_r12
.
prb_Num_r12
;
UE_mac_inst
[
Mod_idP
].
slsch
.
prb_Start_data
=
preconfigpool
->
data_TF_ResourceConfig_r12
.
prb_Start_r12
;
UE_mac_inst
[
Mod_idP
].
slsch
.
prb_End_data
=
preconfigpool
->
data_TF_ResourceConfig_r12
.
prb_End_r12
;
LOG_I
(
MAC
,
"SLCCH Resource pool (%d,%d,%d)
\n
"
,
UE_mac_inst
[
Mod_idP
].
slsch
.
N_SL_RB_SC
,
UE_mac_inst
[
Mod_idP
].
slsch
.
prb_Start_SC
,
UE_mac_inst
[
Mod_idP
].
slsch
.
prb_End_SC
);
LOG_I
(
MAC
,
"SLSCH Resource pool (%d,%d,%d)
\n
"
,
UE_mac_inst
[
Mod_idP
].
slsch
.
N_SL_RB_data
,
UE_mac_inst
[
Mod_idP
].
slsch
.
prb_Start_data
,
UE_mac_inst
[
Mod_idP
].
slsch
.
prb_End_data
);
AssertFatal
(
preconfigpool
->
sc_Period_r12
<
10
,
"Maximum supported sc_Period is 320ms (sc_Period_r12=%d)
\n
"
,
SL_PeriodComm_r12_sf320
);
UE_mac_inst
[
Mod_idP
].
slsch
.
SL_SC_Period
=
SC_Period
[
preconfigpool
->
sc_Period_r12
];
...
...
@@ -752,7 +762,7 @@ rrc_mac_config_req_ue(module_id_t Mod_idP,
AssertFatal
(
preconfigpool
->
sc_TF_ResourceConfig_r12
.
subframeBitmap_r12
.
present
<=
SubframeBitmapSL_r12_PR_bs40_r12
||
preconfigpool
->
sc_TF_ResourceConfig_r12
.
subframeBitmap_r12
.
present
>
SubframeBitmapSL_r12_PR_NOTHING
,
"PSCCH bitmap limited to 42 bits
\n
"
);
UE_mac_inst
[
Mod_idP
].
slsch
.
SubframeBitmapSL_length
=
SubframeBitmapSL
[
preconfigpool
->
sc_TF_ResourceConfig_r12
.
subframeBitmap_r12
.
present
];
UE_mac_inst
[
Mod_idP
].
slsch
.
SubframeBitmapSL_length
=
SubframeBitmapSL
[
preconfigpool
->
sc_TF_ResourceConfig_r12
.
subframeBitmap_r12
.
present
-
1
];
UE_mac_inst
[
Mod_idP
].
slsch
.
bitmap1
=
*
((
uint64_t
*
)
preconfigpool
->
sc_TF_ResourceConfig_r12
.
subframeBitmap_r12
.
choice
.
bs40_r12
.
buf
);
AssertFatal
(
SL_Preconfiguration_r12
->
ext1
!=
NULL
,
"there is no Rel13 extension in SL preconfiguration
\n
"
);
...
...
openair2/LAYER2/MAC/ue_procedures.c
View file @
7a00e05b
...
...
@@ -3420,6 +3420,8 @@ SLSCH_t *ue_get_slsch(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_
}
*/
extern
const
int
trp8
[
TRP8_MAX
+
1
][
8
];
SLSCH_t
*
ue_get_slsch
(
module_id_t
module_idP
,
int
CC_id
,
frame_t
frameP
,
sub_frame_t
subframeP
)
{
mac_rlc_status_resp_t
rlc_status
,
rlc_status_data
;
...
...
@@ -3430,8 +3432,9 @@ SLSCH_t *ue_get_slsch(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_
int
i
=
0
;
int
mcs
=
19
;
int
L_CRBs
=
10
;
int
RB_start
=
0
;
// Note: this is hard-coded for now for the default SL configuration (4 SF PSCCH, 36 SF PSSCH)
SLSCH_t
*
slsch
=
&
UE_mac_inst
[
module_idP
].
slsch
;
SLSCH_t
*
slsch
=
&
ue
->
slsch
;
AssertFatal
(
slsch
!=
NULL
,
"SLSCH is null
\n
"
);
uint32_t
O
=
slsch
->
SL_OffsetIndicator
;
...
...
@@ -3442,7 +3445,7 @@ SLSCH_t *ue_get_slsch(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_
absSF_modP
=
absSF_offset
%
P
;
LOG_D
(
MAC
,
"Checking SL
SCH for absSF %d
\n
"
,
absSF
);
LOG_D
(
MAC
,
"Checking SL
CCH/SLSCH for absSF %d, ue->sltx_active %d
\n
"
,
absSF
,
ue
->
sltx_active
);
if
(
absSF_modP
==
0
)
{
// this is the first subframe of PSCCH period, check for data and generate SCI
ue
->
sltx_active
=
0
;
...
...
@@ -3488,24 +3491,55 @@ SLSCH_t *ue_get_slsch(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_
}
if
(
ue
->
sltx_active
==
0
)
return
((
SLSCH_t
*
)
NULL
);
slsch
->
ljmod10
=
0
;
slsch
->
rvidx
=
1
;
slsch
->
RB_start
=
RB_start
;
slsch
->
L_CRBs
=
L_CRBs
;
// fill in SCI fields
slsch
->
n_pscch
=
ue
->
sourceL2Id
;
slsch
->
format
=
0
;
slsch
->
freq_hopping_flag
=
0
;
slsch
->
resource_block_coding
=
computeRIV
(
slsch
->
N_SL_RB_data
,
0
,
L_CRBs
);
slsch
->
resource_block_coding
=
computeRIV
(
slsch
->
N_SL_RB_data
,
RB_start
,
L_CRBs
);
slsch
->
time_resource_pattern
=
106
;
// all subframes for Nrp=8
slsch
->
mcs
=
mcs
;
slsch
->
timing_advance_indication
=
0
;
slsch
->
group_destination_id
=
ue
->
destinationL2Id
&
0xff
;
LOG_I
(
MAC
,
"Generated SCI with n_pscch %d, RBC %x, TRP %d, mcs %d, groupid %x
\n
"
,
slsch
->
n_pscch
,
slsch
->
resource_block_coding
,
slsch
->
time_resource_pattern
,
mcs
,
slsch
->
group_destination_id
);
}
// we're in the SCI period
else
if
(
ue
->
sltx_active
==
1
)
{
// every 4th subframe, check for new data from RLC
LOG_I
(
MAC
,
"Configured SCI with n_pscch %d, RBC %x, TRP %d, mcs %d, groupid %x
\n
"
,
slsch
->
n_pscch
,
slsch
->
resource_block_coding
,
slsch
->
time_resource_pattern
,
mcs
,
slsch
->
group_destination_id
);
return
(
slsch
);
}
// we're in the first subframe of the SCI period
else
if
(
ue
->
sltx_active
==
1
&&
absSF_modP
>=
slsch
->
SubframeBitmapSL_length
)
{
// this is SLSCH period and we have allocated the SL TX
// check if this is time for a new SDU query
AssertFatal
(
slsch
->
time_resource_pattern
<=
TRP8_MAX
,
"received Itrp %d: TRP8 is used with Itrp in 0...%d
\n
"
,
slsch
->
time_resource_pattern
,
TRP8_MAX
);
// Note : this assumes Ntrp=8 for now
if
(
trp8
[
slsch
->
time_resource_pattern
][
absSF_modP
&
7
]
==
0
)
return
((
SLSCH_t
*
)
NULL
);
// we have an opportunity in this subframe
if
(
slsch
->
ljmod10
==
10
)
slsch
->
ljmod10
=
0
;
else
slsch
->
ljmod10
++
;
if
(
slsch
->
rvidx
==
1
)
slsch
->
rvidx
=
0
;
else
if
(
slsch
->
rvidx
==
0
)
slsch
->
rvidx
=
2
;
else
if
(
slsch
->
rvidx
==
2
)
slsch
->
rvidx
=
3
;
else
if
(
slsch
->
rvidx
==
3
)
slsch
->
rvidx
=
1
;
if
(
slsch
->
rvidx
>
0
&&
slsch
->
payload_length
>
0
)
{
LOG_I
(
MAC
,
"absSF %d SLSCH TXoP rvidx %d
\n
"
,
absSF
,
slsch
->
rvidx
);
return
slsch
;
}
else
if
(
slsch
->
rvidx
>
0
&&
slsch
->
payload_length
==
0
)
return
((
SLSCH_t
*
)
NULL
);
// 10 PRBs, mcs 19
int
TBS
=
get_TBS_UL
(
mcs
,
L_CRBs
);
int
req
;
rlc_status
=
mac_rlc_status_ind
(
module_idP
,
0x1234
,
0
,
frameP
,
subframeP
,
ENB_FLAG_NO
,
MBMS_FLAG_NO
,
ue
->
slsch_lcid
,
0xFFFF
,
ue
->
sourceL2Id
,
ue
->
destinationL2Id
);
if
(
TBS
<=
rlc_status
.
bytes_in_buffer
)
req
=
TBS
;
else
req
=
rlc_status
.
bytes_in_buffer
;
...
...
@@ -3565,13 +3599,19 @@ SLSCH_t *ue_get_slsch(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_
}
slsch
->
payload_length
=
TBS
;
// fill in SLSCH configuration
return
(
&
ue
->
slsch
);
return
(
slsch
);
}
else
{
slsch
->
payload_length
=
0
;
return
((
SLSCH_t
*
)
NULL
);
}
else
return
((
SLSCH_t
*
)
NULL
);
}
}
else
if
(
ue
->
sltx_active
==
1
&&
absSF_modP
<
slsch
->
SubframeBitmapSL_length
)
{
LOG_I
(
MAC
,
"absSF_mod P %d in SLSCH period
\n
"
,
absSF_modP
);
return
(
slsch
);
// we're in the SCI period
}
return
(
NULL
);
}
openair2/RRC/LITE/rrc_UE.c
View file @
7a00e05b
...
...
@@ -333,20 +333,20 @@ void init_SL_preconfig(UE_RRC_INST *UE, const uint8_t eNB_index )
// Offset set to 0 subframes
preconfigpool
->
sc_TF_ResourceConfig_r12
.
offsetIndicator_r12
.
present
=
SL_OffsetIndicator_r12_PR_small_r12
;
preconfigpool
->
sc_TF_ResourceConfig_r12
.
offsetIndicator_r12
.
choice
.
small_r12
=
0
;
// 4
0
ms SL Period
// 4 ms SL Period
preconfigpool
->
sc_TF_ResourceConfig_r12
.
subframeBitmap_r12
.
present
=
SubframeBitmapSL_r12_PR_bs4_r12
;
preconfigpool
->
sc_TF_ResourceConfig_r12
.
subframeBitmap_r12
.
choice
.
bs4
0
_r12
.
buf
=
CALLOC
(
1
,
1
);
preconfigpool
->
sc_TF_ResourceConfig_r12
.
subframeBitmap_r12
.
choice
.
bs4
0
_r12
.
size
=
1
;
preconfigpool
->
sc_TF_ResourceConfig_r12
.
subframeBitmap_r12
.
choice
.
bs4
0
_r12
.
bits_unused
=
4
;
preconfigpool
->
sc_TF_ResourceConfig_r12
.
subframeBitmap_r12
.
choice
.
bs4_r12
.
buf
=
CALLOC
(
1
,
1
);
preconfigpool
->
sc_TF_ResourceConfig_r12
.
subframeBitmap_r12
.
choice
.
bs4_r12
.
size
=
1
;
preconfigpool
->
sc_TF_ResourceConfig_r12
.
subframeBitmap_r12
.
choice
.
bs4_r12
.
bits_unused
=
4
;
// 1st 4 subframes for PSCCH
preconfigpool
->
sc_TF_ResourceConfig_r12
.
subframeBitmap_r12
.
choice
.
bs4
0
_r12
.
buf
[
0
]
=
0x0F
;
preconfigpool
->
sc_TF_ResourceConfig_r12
.
subframeBitmap_r12
.
choice
.
bs4_r12
.
buf
[
0
]
=
0x0F
;
preconfigpool
->
sc_TxParameters_r12
=
0
;
//SL Data portion
// 20 PRBs for SL communications
preconfigpool
->
sc
_TF_ResourceConfig_r12
.
prb_Num_r12
=
20
;
preconfigpool
->
sc
_TF_ResourceConfig_r12
.
prb_Start_r12
=
5
;
preconfigpool
->
sc
_TF_ResourceConfig_r12
.
prb_End_r12
=
44
;
preconfigpool
->
data
_TF_ResourceConfig_r12
.
prb_Num_r12
=
20
;
preconfigpool
->
data
_TF_ResourceConfig_r12
.
prb_Start_r12
=
5
;
preconfigpool
->
data
_TF_ResourceConfig_r12
.
prb_End_r12
=
44
;
preconfigpool
->
data_CP_Len_r12
=
SL_CP_Len_r12_normal
;
preconfigpool
->
dataHoppingConfig_r12
.
hoppingParameter_r12
=
0
;
...
...
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