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
canghaiwuhen
OpenXG-RAN
Commits
0bb24834
Commit
0bb24834
authored
May 16, 2017
by
Eric
Committed by
Nick Ho
May 23, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add DCI data structure and NB_eNB_shcedule_RA
parent
3cde6ecb
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
414 additions
and
0 deletions
+414
-0
openair1/PHY/LTE_TRANSPORT/dci_nb_iot.h
openair1/PHY/LTE_TRANSPORT/dci_nb_iot.h
+234
-0
openair1/PHY/LTE_TRANSPORT/defs.h
openair1/PHY/LTE_TRANSPORT/defs.h
+1
-0
openair2/LAYER2/MAC/eNB_scheduler_RA_nb_iot.c
openair2/LAYER2/MAC/eNB_scheduler_RA_nb_iot.c
+166
-0
openair2/LAYER2/MAC/proto_nb_iot.h
openair2/LAYER2/MAC/proto_nb_iot.h
+2
-0
record.txt
record.txt
+11
-0
No files found.
openair1/PHY/LTE_TRANSPORT/dci_nb_iot.h
0 → 100644
View file @
0bb24834
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.0 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file PHY/LTE_TRANSPORT/dci.h
* \brief typedefs for LTE DCI structures from 36-212, V8.6 2009-03. Limited to 5 MHz formats for the moment.Current LTE compliance V8.6 2009-03.
* \author R. Knopp
* \date 2011
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr
* \note
* \warning
*/
#ifndef USER_MODE
#include "PHY/types.h"
#else
#include <stdint.h>
#endif
/// DCI Format Type 0 (180 kHz, 23 bits)
typedef
struct
DCIFormatN0
{
/// type = 0 => DCI Format N0, type = 1 => DCI Format N1, 1 bits
uint8_t
type
;
/// Subcarrier indication, 6 bits
uint8_t
scind
;
/// Resourse Assignment (RU Assignment), 3 bits
uint8_t
ResAssign
;
/// Modulation and Coding Scheme, 4 bits
uint8_t
mcs
;
/// New Data Indicator, 1 bits
uint8_t
ndi
;
/// Scheduling Delay, 2 bits
uint8_t
Scheddly
;
/// Repetition Number, 3 bits
uint8_t
RepNum
;
/// Redundancy version for HARQ (only use 0 and 2), 1 bits
uint8_t
rv
;
/// DCI subframe repetition Number, 2 bits
uint8_t
DCIRep
;
};
typedef
struct
DCIFormatN0
DCIFormatN0_t
;
#define sizeof_DDCIFormatN0_t 23
/// DCI Format Type N1 for User data
struct
DCIFormatN1
{
/// type = 0 => DCI Format N0, type = 1 => DCI Format N1,1bits
uint8_t
type
;
//NPDCCH order indicator (set to 0), 1 bits
uint8_t
orderIndicator
;
// Scheduling Delay,3 bits
uint8_t
Scheddly
;
// Resourse Assignment (RU Assignment),3 bits
uint8_t
ResAssign
;
// Modulation and Coding Scheme,4 bits
uint8_t
mcs
;
// Repetition Number,4 bits
uint8_t
RepNum
;
// New Data Indicator,1 bits
uint8_t
ndi
;
// HARQ-ACK resource,4 bits
uint8_t
HARQackRes
;
// DCI subframe repetition Number,2 bits
uint8_t
DCIRep
;
};
typedef
struct
DCIFormatN1
DCIFormatN1_t
;
#define sizeof_DCIFormatN1_t 23
/// DCI Format Type N1 for initial RA
struct
DCIFormatN1_RA
{
/// type = 0 => DCI Format N0, type = 1 => DCI Format N1, 1 bits
uint8_t
type
;
//NPDCCH order indicator (set to 0),1 bits
uint8_t
orderIndicator
;
// Start number of NPRACH repetiiton, 2 bits
uint8_t
Scheddly
;
// Subcarrier indication of NPRACH, 6 bits
uint8_t
scind
;
// All the remainging bits, 13 bits
uint8_t
remaingingBits
;
};
typedef
struct
DCIFormatN1_RA
DCIFormatN1_RA_t
;
#define sizeof_DCIFormatN1_RA_t 23
/// DCI Format Type N1 for RAR
struct
DCIFormatN1_RAR
{
/// type = 0 => DCI Format N0, type = 1 => DCI Format N1, 1 bits
uint8_t
type
;
//NPDCCH order indicator (set to 0),1 bits
uint8_t
orderIndicator
;
// Scheduling Delay, 3 bits
uint8_t
Scheddly
;
// Resourse Assignment (RU Assignment), 3 bits
uint8_t
ResAssign
;
// Modulation and Coding Scheme, 4 bits
uint8_t
mcs
;
// Repetition Number, 4 bits
uint8_t
RepNum
;
// Reserved 5 bits
uint8_t
Reserved
;
// DCI subframe repetition Number, 2 bits
uint8_t
DCIRep
;
};
typedef
struct
DCIFormatN1_RAR
DCIFormatN1_RAR_t
;
#define sizeof_DCIFormatN1_RAR_t 23
// DCI Format Type N2 for direct indication, 15 bits
struct
DCIFormat2_Ind
{
//Flag for paging(1)/direct indication(0), set to 0,1 bits
uint8_t
type
;
//Direct indication information, 8 bits
uint8_t
directIndInf
;
// Reserved information bits, 6 bits
uint8_t
resInfoBits
;
};
typedef
struct
DCIFormat2_Ind
DCIFormat2_Ind_t
;
#define sizeof_DCIFormat2_Ind_t 15
// DCI Format Type N2 for Paging, 15 bits
struct
DCIFormat2_Pag
{
//Flag for paging(1)/direct indication(0), set to 1,1 bits
uint8_t
type
;
// Resourse Assignment (RU Assignment), 3 bits
uint8_t
ResAssign
;
// Modulation and Coding Scheme, 4 bits
uint8_t
mcs
;
// Repetition Number, 4 bits
uint8_t
RepNum
;
// Reserved 3 bits
uint8_t
DCIRep
;
};
typedef
struct
DCIFormat2_Pag
DCIFormat2_Pagt
;
#define sizeof_DCIFormat2_Pag_t 15
// struct DCI0_5MHz_TDD0 {
// /// type = 0 => DCI Format 0, type = 1 => DCI Format 1A
// uint32_t type:1;
// /// Hopping flag
// uint32_t hopping:1;
// /// RB Assignment (ceil(log2(N_RB_UL*(N_RB_UL+1)/2)) bits)
// uint32_t rballoc:9;
// /// Modulation and Coding Scheme and Redundancy Version
// uint32_t mcs:5;
// /// New Data Indicator
// uint32_t ndi:1;
// /// Power Control
// uint32_t TPC:2;
// /// Cyclic shift
// uint32_t cshift:3;
// /// DAI (TDD)
// uint32_t ulindex:2;
// /// CQI Request
// uint32_t cqi_req:1;
// /// Padding to get to size of DCI1A
// uint32_t padding:2;
// } __attribute__ ((__packed__));
// typedef struct DCI0_5MHz_TDD0 DCI0_5MHz_TDD0_t;
// #define sizeof_DCI0_5MHz_TDD_0_t 27
//Not sure if needed in NB-IoT
// struct DCI_INFO_EXTRACTED {
// /// type = 0 => DCI Format 0, type = 1 => DCI Format 1A
// uint8_t type;
// /// Resource Allocation Header
// uint8_t rah;
// /// HARQ Process
// uint8_t harq_pid;
// /// CQI Request
// uint8_t cqi_req;
// /// SRS Request
// uint8_t srs_req;
// /// Power Control
// uint8_t TPC;
// /// Localized/Distributed VRB
// uint8_t vrb_type;
// /// RB Assignment (ceil(log2(N_RB_DL/P)) bits)
// uint32_t rballoc;
// // Applicable only when vrb_type = 1
// uint8_t Ngap;
// /// Cyclic shift
// uint8_t cshift;
// /// Hopping flag
// uint8_t hopping;
// /// Downlink Assignment Index
// uint8_t dai;
// /// DAI (TDD)
// uint8_t ulindex;
// /// TB swap
// uint8_t tb_swap;
// /// TPMI information for precoding
// uint8_t tpmi;
// /// Redundancy version 2
// uint8_t rv2;
// /// New Data Indicator 2
// uint8_t ndi2;
// /// Modulation and Coding Scheme and Redundancy Version 2
// uint8_t mcs2;
// /// Redundancy version 1
// uint8_t rv1;
// /// New Data Indicator 1
// uint8_t ndi1;
// /// Modulation and Coding Scheme and Redundancy Version 1
// uint8_t mcs1;
// /// Scrambling ID
// uint64_t ap_si_nl_id:3;
// };
// typedef struct DCI_INFO_EXTRACTED DCI_INFO_EXTRACTED_t;
openair1/PHY/LTE_TRANSPORT/defs.h
View file @
0bb24834
...
...
@@ -33,6 +33,7 @@
#define __LTE_TRANSPORT_DEFS__H__
#include "PHY/defs.h"
#include "dci.h"
#include "dci_nb_iot.h"
#include "uci.h"
#ifndef STANDALONE_COMPILE
#include "UTIL/LISTS/list.h"
...
...
openair2/LAYER2/MAC/eNB_scheduler_RA_nb_iot.c
View file @
0bb24834
...
...
@@ -66,6 +66,172 @@
#include "T.h"
void
NB_schedule_RA
(
module_id_t
module_idP
,
frame_t
frameP
,
sub_frame_t
subframeP
)
{
int
CC_id
;
eNB_MAC_INST_NB
*
eNB
=
&
eNB_mac_inst_NB
[
module_idP
];
RA_TEMPLATE_NB
*
RA_template
;
unsigned
char
i
,
harq_pid
,
round
;
int16_t
rrc_sdu_length
;
unsigned
char
lcid
,
offset
;
int
UE_id
=
-
1
;
unsigned
short
TBsize
=
-
1
;
unsigned
short
msg4_padding
,
msg4_post_padding
,
msg4_header
;
DCI_PDU_NB
*
DCI_pdu
;
// start_meas(&eNB->schedule_ra);
for
(
CC_id
=
0
;
CC_id
<
MAX_NUM_CCs
;
CC_id
++
)
{
DCI_pdu
=
&
eNB
->
common_channels
[
CC_id
].
DCI_pdu
;
for
(
i
=
0
;
i
<
NB_RA_PROC_MAX
;
i
++
)
{
RA_template
=
(
RA_TEMPLATE_NB
*
)
&
eNB
->
common_channels
[
CC_id
].
RA_template
[
i
];
if
(
RA_template
->
RA_active
==
TRUE
)
{
LOG_D
(
MAC
,
"[eNB %d][RAPROC] CC_id %d RA %d is active (generate RAR %d, generate_Msg4 %d, wait_ack_Msg4 %d, rnti %x)
\n
"
,
module_idP
,
CC_id
,
i
,
RA_template
->
generate_rar
,
RA_template
->
generate_Msg4
,
RA_template
->
wait_ack_Msg4
,
RA_template
->
rnti
);
if
(
RA_template
->
generate_rar
==
1
)
{
LOG_D
(
MAC
,
"[eNB %d] CC_id %d Frame %d, subframeP %d: Generating RAR DCI (proc %d), RA_active %d format 1A (%d,%d))
\n
"
,
module_idP
,
CC_id
,
frameP
,
subframeP
,
i
,
RA_template
->
RA_active
,
RA_template
->
RA_dci_fmt1
,
RA_template
->
RA_dci_size_bits1
);
//directly fill DCI Filed base on DCI Nq for RAR
((
DCIFormatN1_RAR_t
*
)
&
RA_template
->
RA_alloc_pdu1
[
0
])
->
type
=
1
;
((
DCIFormatN1_RAR_t
*
)
&
RA_template
->
RA_alloc_pdu1
[
0
])
->
orderIndicator
=
0
;
((
DCIFormatN1_RAR_t
*
)
&
RA_template
->
RA_alloc_pdu1
[
0
])
->
Scheddly
=
1
;
//fixed delay approach?
((
DCIFormatN1_RAR_t
*
)
&
RA_template
->
RA_alloc_pdu1
[
0
])
->
ResAssign
=
0
;
((
DCIFormatN1_RAR_t
*
)
&
RA_template
->
RA_alloc_pdu1
[
0
])
->
mcs
=
0
;
//fixes?//fixes? base on CE levels?
((
DCIFormatN1_RAR_t
*
)
&
RA_template
->
RA_alloc_pdu1
[
0
])
->
RepNum
=
0
;
//fixes? base on CE levels?
((
DCIFormatN1_RAR_t
*
)
&
RA_template
->
RA_alloc_pdu1
[
0
])
->
Reserved
=
0
;
((
DCIFormatN1_RAR_t
*
)
&
RA_template
->
RA_alloc_pdu1
[
0
])
->
DCIRep
=
0
;
//fixes?
}
//New appoach for CCE allocaton, delete !CCE_allocation_infeasible..
else
if
(
RA_template
->
generate_Msg4
==
1
)
{
// check for Msg4 Message
UE_id
=
find_UE_id
(
module_idP
,
RA_template
->
rnti
);
if
(
UE_id
==
-
1
)
{
printf
(
"%s:%d:%s: FATAL ERROR
\n
"
,
__FILE__
,
__LINE__
,
__FUNCTION__
);
abort
();
}
if
(
Is_rrc_registered
==
1
)
{
//Fixed mac_rrc_data_req
// Get RRCConnectionSetup for Piggyback
rrc_sdu_length
=
mac_rrc_data_req
(
module_idP
,
CC_id
,
frameP
,
CCCH
,
1
,
// 1 transport block
&
eNB
->
common_channels
[
CC_id
].
CCCH_pdu
.
payload
[
0
],
ENB_FLAG_YES
,
module_idP
,
0
);
// not used in this case
if
(
rrc_sdu_length
==
-
1
)
{
mac_xface
->
macphy_exit
(
"[MAC][eNB Scheduler] CCCH not allocated
\n
"
);
return
;
// not reached
}
else
{
//msg("[MAC][eNB %d] Frame %d, subframeP %d: got %d bytes from RRC\n",module_idP,frameP, subframeP,rrc_sdu_length);
}
}
LOG_D
(
MAC
,
"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: UE_id %d, Is_rrc_registered %d, rrc_sdu_length %d
\n
"
,
module_idP
,
CC_id
,
frameP
,
subframeP
,
UE_id
,
Is_rrc_registered
,
rrc_sdu_length
);
if
(
rrc_sdu_length
>
0
)
{
LOG_I
(
MAC
,
"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Generating Msg4 with RRC Piggyback (RA proc %d, RNTI %x)
\n
"
,
module_idP
,
CC_id
,
frameP
,
subframeP
,
i
,
RA_template
->
rnti
);
// Compute MCS for 3 PRB
msg4_header
=
1
+
6
+
1
;
// CR header, CR CE, SDU header
//need to fixed ndi & msc base on NB-IoT DCI for Msg4
((
DCIFormatN1_t
*
)
&
RA_template
->
RA_alloc_pdu2
[
0
])
->
ndi
=
1
;
if
((
rrc_sdu_length
+
msg4_header
)
<=
22
)
{
((
DCIFormatN1_t
*
)
&
RA_template
->
RA_alloc_pdu2
[
0
])
->
mcs
=
4
;
TBsize
=
22
;
}
else
if
((
rrc_sdu_length
+
msg4_header
)
<=
28
)
{
((
DCIFormatN1_t
*
)
&
RA_template
->
RA_alloc_pdu2
[
0
])
->
mcs
=
5
;
TBsize
=
28
;
}
else
if
((
rrc_sdu_length
+
msg4_header
)
<=
32
)
{
((
DCIFormatN1_t
*
)
&
RA_template
->
RA_alloc_pdu2
[
0
])
->
mcs
=
6
;
TBsize
=
32
;
}
else
if
((
rrc_sdu_length
+
msg4_header
)
<=
41
)
{
((
DCIFormatN1_t
*
)
&
RA_template
->
RA_alloc_pdu2
[
0
])
->
mcs
=
7
;
TBsize
=
41
;
}
else
if
((
rrc_sdu_length
+
msg4_header
)
<=
49
)
{
((
DCIFormatN1_t
*
)
&
RA_template
->
RA_alloc_pdu2
[
0
])
->
mcs
=
8
;
TBsize
=
49
;
}
else
if
((
rrc_sdu_length
+
msg4_header
)
<=
57
)
{
((
DCIFormatN1_t
*
)
&
RA_template
->
RA_alloc_pdu2
[
0
])
->
mcs
=
9
;
TBsize
=
57
;
}
((
DCIFormatN1_t
*
)
&
RA_template
->
RA_alloc_pdu2
[
0
])
->
type
=
1
;
((
DCIFormatN1_t
*
)
&
RA_template
->
RA_alloc_pdu2
[
0
])
->
orderIndicator
=
0
;
((
DCIFormatN1_t
*
)
&
RA_template
->
RA_alloc_pdu2
[
0
])
->
Scheddly
=
1
;
//fixed delay approach?
((
DCIFormatN1_t
*
)
&
RA_template
->
RA_alloc_pdu2
[
0
])
->
ResAssign
=
5
;
//fixed depend on mcs/tbs to Nsf
((
DCIFormatN1_t
*
)
&
RA_template
->
RA_alloc_pdu2
[
0
])
->
RepNum
=
1
;
//fixed base on CE levels
((
DCIFormatN1_t
*
)
&
RA_template
->
RA_alloc_pdu2
[
0
])
->
HARQackRes
=
0
;
//Avoid confict multiple Msg ACk
((
DCIFormatN1_t
*
)
&
RA_template
->
RA_alloc_pdu2
[
0
])
->
DCIRep
=
0
;
//fixed base on CE levels
}
}
else
if
(
RA_template
->
wait_ack_Msg4
==
1
)
{
// check HARQ status and retransmit if necessary
LOG_I
(
MAC
,
"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Checking if Msg4 was acknowledged:
\n
"
,
module_idP
,
CC_id
,
frameP
,
subframeP
);
// Get candidate harq_pid from PHY
mac_xface
->
get_ue_active_harq_pid
(
module_idP
,
CC_id
,
RA_template
->
rnti
,
frameP
,
subframeP
,
&
harq_pid
,
&
round
,
openair_harq_RA
);
if
(
round
>
0
)
{
//RA_template->wait_ack_Msg4++;
// we have to schedule a retransmission
((
DCIFormatN1_t
*
)
&
RA_template
->
RA_alloc_pdu2
[
0
])
->
ndi
=
1
;
// if (!CCE_allocation_infeasible(module_idP,CC_id,0,subframeP,2,RA_template->rnti)) {
// add_ue_spec_dci(DCI_pdu,
// (void*)&RA_template->RA_alloc_pdu2[0],
// RA_template->rnti,
// RA_template->RA_dci_size_bytes2,
// 2,
// RA_template->RA_dci_size_bits2,
// RA_template->RA_dci_fmt2,
// 0);
// printf("MAC: msg4 retransmission for rnti %x (round %d) fsf %d/%d\n", RA_template->rnti, round, frameP, subframeP);
// }
}
else
printf
(
"MAC: msg4 retransmission for rnti %x (round %d) fsf %d/%d CCE allocation failed!
\n
"
,
RA_template
->
rnti
,
round
,
frameP
,
subframeP
);
LOG_W
(
MAC
,
"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Msg4 not acknowledged, adding ue specific dci (rnti %x) for RA (Msg4 Retransmission)
\n
"
,
module_idP
,
CC_id
,
frameP
,
subframeP
,
RA_template
->
rnti
);
}
else
{
/* msg4 not received
if ((round == 0) && (RA_template->wait_ack_Msg4>1){
remove UE instance across all the layers: mac_xface->cancel_RA();
}
*/
printf
(
"MAC: msg4 acknowledged for rnti %x fsf %d/%d, let's configure it
\n
"
,
RA_template
->
rnti
,
frameP
,
subframeP
);
LOG_I
(
MAC
,
"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d : Msg4 acknowledged
\n
"
,
module_idP
,
CC_id
,
frameP
,
subframeP
);
RA_template
->
wait_ack_Msg4
=
0
;
RA_template
->
RA_active
=
FALSE
;
UE_id
=
find_UE_id
(
module_idP
,
RA_template
->
rnti
);
DevAssert
(
UE_id
!=
-
1
);
eNB_mac_inst_NB
[
module_idP
].
UE_list
.
UE_template
[
UE_PCCID
(
module_idP
,
UE_id
)][
UE_id
].
configured
=
TRUE
;
}
}
// RA_active
}
// for i=0 .. N_RA_PROC-1
}
// CC_id
// stop_meas(&eNB->schedule_ra);
}
/*This function should loop all over the preamble index*/
void
NB_initiate_ra_proc
(
module_id_t
module_idP
,
int
CC_id
,
frame_t
frameP
,
uint16_t
preamble_index
,
int16_t
timing_offset
,
sub_frame_t
subframeP
)
{
...
...
openair2/LAYER2/MAC/proto_nb_iot.h
View file @
0bb24834
...
...
@@ -825,6 +825,8 @@ void NB_eNB_dlsch_ulsch_scheduler(module_id_t module_idP, uint8_t cooperation_fl
/* \brief Function to indicate a received preamble on PRACH. It initiates the RA procedure.
In NB-IoT, it indicate preamble using the frequency to indicate the preamble.
*/
void
NB_schedule_RA
(
module_id_t
module_idP
,
frame_t
frameP
,
sub_frame_t
subframeP
)
void
NB_initiate_ra_proc
(
module_id_t
module_idP
,
int
CC_id
,
frame_t
frameP
,
uint16_t
preamble_index
,
int16_t
timing_offset
,
uint8_t
sect_id
,
sub_frame_t
subframe
,
uint8_t
f_id
);
uint8_t
*
NB_get_dlsch_sdu
(
module_id_t
module_idP
,
int
CC_id
,
frame_t
frameP
,
rnti_t
rnti
,
uint8_t
TBindex
);
...
...
record.txt
View file @
0bb24834
...
...
@@ -28,3 +28,14 @@ openair2/Layer2/MAC/eNB_scheduler_RA_nb_iot.c
comment:
Functions: NB_initiate_ra_proc()
5/15
modified: openair1/PHY/INIT/defs.h
modified: openair1/PHY/LTE_TRANSPORT/defs.h
modified: openair2/LAYER2/MAC/eNB_scheduler_RA_nb_iot.c
modified: openair2/LAYER2/MAC/proto_nb_iot.h
comment:
Functions: Add NB_schedule_RA()
Data Structure: Add DCI Upacked format in openair1/PHY/LTE_TRANSPORT/defs.h
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