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
819ea956
Commit
819ea956
authored
Oct 07, 2019
by
lipingyu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
lte-enb-nbiot.c debug
parent
dccb3b51
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
8 additions
and
310 deletions
+8
-310
openair1/PHY/defs_eNB.h
openair1/PHY/defs_eNB.h
+3
-1
targets/RT/USER/lte-enb-nbiot.c
targets/RT/USER/lte-enb-nbiot.c
+4
-308
targets/RT/USER/lte-ru.c
targets/RT/USER/lte-ru.c
+1
-1
No files found.
openair1/PHY/defs_eNB.h
View file @
819ea956
...
...
@@ -381,7 +381,7 @@ typedef struct RU_t_s{
int
num_eNB
;
/// list of eNBs using this RU
struct
PHY_VARS_eNB_s
*
eNB_list
[
NUMBER_OF_eNB_MAX
];
/// list of
eNBs
using this RU
/// list of
NB-IoT
using this RU
struct
PHY_VARS_eNB_NB_IoT_s
*
eNB_nbiot_list
[
NUMBER_OF_eNB_MAX
];
/// Mapping of antenna ports to RF chain index
openair0_rf_map
rf_map
;
...
...
@@ -425,6 +425,8 @@ typedef struct RU_t_s{
#endif
/// function pointer to eNB entry routine
void
(
*
eNB_top
)(
struct
PHY_VARS_eNB_s
*
eNB
,
int
frame_rx
,
int
subframe_rx
,
char
*
string
,
struct
RU_t_s
*
ru
);
/// function pointer to NB-IoT entry routine
void
(
*
eNB_nb_iot_top
)(
struct
PHY_VARS_eNB_NB_IoT_s
*
eNB
,
int
frame_rx
,
int
subframe_rx
,
char
*
string
,
struct
RU_t_s
*
ru
);
/// Timing statistics
time_stats_t
ofdm_demod_stats
;
/// Timing statistics (TX)
...
...
targets/RT/USER/lte-enb-nbiot.c
View file @
819ea956
...
...
@@ -116,6 +116,7 @@ extern volatile int start_eNB;
extern
volatile
int
oai_exit
;
extern
int
oaisim_flag
;
extern
openair0_config_t
openair0_cfg
[
MAX_CARDS
];
extern
uint16_t
sf_ahead
;
uint8_t
seqno
;
//sequence number
static
int
time_offset
[
4
]
=
{
0
,
0
,
0
,
0
};
...
...
@@ -557,185 +558,7 @@ void init_eNB_NB_IoT(eNB_func_NB_IoT_t node_function[], eNB_timing_NB_IoT_t node
LOG_I
(
PHY
,
"Registering with MAC interface module sucessfully
\n
"
);
#ifndef OCP_FRAMEWORK
LOG_I
(
PHY
,
"Initializing eNB %d CC_id %d : (%s,%s)
\n
"
,
inst
,
CC_id
,
eNB_functions
[
node_function
[
CC_id
]],
eNB_timing
[
node_timing
[
CC_id
]]);
#endif
switch
(
node_function
[
CC_id
])
{
case
NGFI_RRU_IF5_NB_IoT
:
eNB
->
do_prach
=
NULL
;
eNB
->
do_precoding
=
0
;
eNB
->
fep
=
eNB_fep_rru_if5_NB_IoT
;
eNB
->
td
=
NULL
;
eNB
->
te
=
NULL
;
eNB
->
proc_uespec_rx
=
NULL
;
eNB
->
proc_tx
=
NULL
;
eNB
->
tx_fh
=
NULL
;
eNB
->
rx_fh
=
rx_rf_NB_IoT
;
eNB
->
start_rf
=
start_rf_NB_IoT
;
eNB
->
start_if
=
start_if_NB_IoT
;
eNB
->
fh_asynch
=
fh_if5_asynch_DL_NB_IoT
;
if
(
oaisim_flag
==
0
)
{
ret
=
openair0_device_load
(
&
eNB
->
rfdevice
,
&
openair0_cfg
[
CC_id
]);
if
(
ret
<
0
)
{
printf
(
"Exiting, cannot initialize rf device
\n
"
);
exit
(
-
1
);
}
}
eNB
->
rfdevice
.
host_type
=
RRU_HOST
;
eNB
->
ifdevice
.
host_type
=
RRU_HOST
;
ret
=
openair0_transport_load
(
&
eNB
->
ifdevice
,
&
openair0_cfg
[
CC_id
],
eNB
->
eth_params
);
printf
(
"openair0_transport_init returns %d for CC_id %d
\n
"
,
ret
,
CC_id
);
if
(
ret
<
0
)
{
printf
(
"Exiting, cannot initialize transport protocol
\n
"
);
exit
(
-
1
);
}
malloc_IF5_buffer
(
eNB
);
break
;
case
NGFI_RRU_IF4p5_NB_IoT
:
eNB
->
do_precoding
=
0
;
eNB
->
do_prach
=
do_prach_NB_IoT
;
eNB
->
fep
=
eNB_fep_full_NB_IoT
;
//(single_thread_flag==1) ? eNB_fep_full_2thread : eNB_fep_full;
eNB
->
td
=
NULL
;
eNB
->
te
=
NULL
;
eNB
->
proc_uespec_rx
=
NULL
;
eNB
->
proc_tx
=
NULL
;
//proc_tx_rru_if4p5;
eNB
->
tx_fh
=
NULL
;
eNB
->
rx_fh
=
rx_rf_NB_IoT
;
eNB
->
fh_asynch
=
fh_if4p5_asynch_DL_NB_IoT
;
eNB
->
start_rf
=
start_rf_NB_IoT
;
eNB
->
start_if
=
start_if_NB_IoT
;
if
(
oaisim_flag
==
0
)
{
ret
=
openair0_device_load
(
&
eNB
->
rfdevice
,
&
openair0_cfg
[
CC_id
]);
if
(
ret
<
0
)
{
printf
(
"Exiting, cannot initialize rf device
\n
"
);
exit
(
-
1
);
}
}
eNB
->
rfdevice
.
host_type
=
RRU_HOST
;
eNB
->
ifdevice
.
host_type
=
RRU_HOST
;
printf
(
"loading transport interface ...
\n
"
);
ret
=
openair0_transport_load
(
&
eNB
->
ifdevice
,
&
openair0_cfg
[
CC_id
],
eNB
->
eth_params
);
printf
(
"openair0_transport_init returns %d for CC_id %d
\n
"
,
ret
,
CC_id
);
if
(
ret
<
0
)
{
printf
(
"Exiting, cannot initialize transport protocol
\n
"
);
exit
(
-
1
);
}
malloc_IF4p5_buffer
(
eNB
);
break
;
case
eNodeB_3GPP_NB_IoT
:
eNB
->
do_precoding
=
eNB
->
frame_parms
.
nb_antennas_tx
!=
eNB
->
frame_parms
.
nb_antenna_ports_eNB
;
eNB
->
do_prach
=
do_prach_NB_IoT
;
eNB
->
fep
=
eNB_fep_full_NB_IoT
;
//(single_thread_flag==1) ? eNB_fep_full_2thread : eNB_fep_full;
eNB
->
td
=
ulsch_decoding_data_NB_IoT
;
//(single_thread_flag==1) ? ulsch_decoding_data_2thread : ulsch_decoding_data;
eNB
->
te
=
dlsch_encoding_NB_IoT
;
//(single_thread_flag==1) ? dlsch_encoding_2threads : dlsch_encoding;
////////////////////// NB-IoT testing ////////////////////
//eNB->proc_uespec_rx = phy_procedures_eNB_uespec_RX;
eNB
->
proc_uespec_rx
=
phy_procedures_eNB_uespec_RX_NB_IoT
;
eNB
->
proc_tx
=
proc_tx_full_NB_IoT
;
eNB
->
tx_fh
=
NULL
;
eNB
->
rx_fh
=
rx_rf_NB_IoT
;
eNB
->
start_rf
=
start_rf_NB_IoT
;
eNB
->
start_if
=
NULL
;
eNB
->
fh_asynch
=
NULL
;
if
(
oaisim_flag
==
0
)
{
ret
=
openair0_device_load
(
&
eNB
->
rfdevice
,
&
openair0_cfg
[
CC_id
]);
if
(
ret
<
0
)
{
printf
(
"Exiting, cannot initialize rf device
\n
"
);
exit
(
-
1
);
}
}
eNB
->
rfdevice
.
host_type
=
RRU_HOST
;
eNB
->
ifdevice
.
host_type
=
RRU_HOST
;
break
;
case
eNodeB_3GPP_BBU_NB_IoT
:
eNB
->
do_precoding
=
eNB
->
frame_parms
.
nb_antennas_tx
!=
eNB
->
frame_parms
.
nb_antenna_ports_eNB
;
eNB
->
do_prach
=
do_prach_NB_IoT
;
eNB
->
fep
=
eNB_fep_full_NB_IoT
;
//(single_thread_flag==1) ? eNB_fep_full_2thread : eNB_fep_full;
eNB
->
td
=
ulsch_decoding_data_NB_IoT
;
//(single_thread_flag==1) ? ulsch_decoding_data_2thread : ulsch_decoding_data;
eNB
->
te
=
dlsch_encoding_NB_IoT
;
//(single_thread_flag==1) ? dlsch_encoding_2threads : dlsch_encoding;
eNB
->
proc_uespec_rx
=
phy_procedures_eNB_uespec_RX
;
eNB
->
proc_tx
=
proc_tx_full_NB_IoT
;
if
(
eNB
->
node_timing
==
synch_to_other
)
{
eNB
->
tx_fh
=
tx_fh_if5_mobipass_NB_IoT
;
eNB
->
rx_fh
=
rx_fh_slave_NB_IoT
;
eNB
->
fh_asynch
=
fh_if5_asynch_UL_NB_IoT
;
}
else
{
eNB
->
tx_fh
=
tx_fh_if5_NB_IoT
;
eNB
->
rx_fh
=
rx_fh_if5_NB_IoT
;
eNB
->
fh_asynch
=
NULL
;
}
eNB
->
start_rf
=
NULL
;
eNB
->
start_if
=
start_if_NB_IoT
;
eNB
->
rfdevice
.
host_type
=
RRU_HOST
;
eNB
->
ifdevice
.
host_type
=
RRU_HOST
;
ret
=
openair0_transport_load
(
&
eNB
->
ifdevice
,
&
openair0_cfg
[
CC_id
],
eNB
->
eth_params
);
printf
(
"openair0_transport_init returns %d for CC_id %d
\n
"
,
ret
,
CC_id
);
if
(
ret
<
0
)
{
printf
(
"Exiting, cannot initialize transport protocol
\n
"
);
exit
(
-
1
);
}
malloc_IF5_buffer
(
eNB
);
break
;
case
NGFI_RCC_IF4p5_NB_IoT
:
eNB
->
do_precoding
=
0
;
eNB
->
do_prach
=
do_prach_NB_IoT
;
eNB
->
fep
=
NULL
;
eNB
->
td
=
ulsch_decoding_data_NB_IoT
;
//(single_thread_flag==1) ? ulsch_decoding_data_2thread : ulsch_decoding_data;
eNB
->
te
=
dlsch_encoding_NB_IoT
;
//(single_thread_flag==1) ? dlsch_encoding_2threads : dlsch_encoding;
eNB
->
proc_uespec_rx
=
phy_procedures_eNB_uespec_RX_NB_IoT
;
eNB
->
proc_tx
=
proc_tx_high_NB_IoT
;
eNB
->
tx_fh
=
tx_fh_if4p5_NB_IoT
;
eNB
->
rx_fh
=
rx_fh_if4p5_NB_IoT
;
eNB
->
start_rf
=
NULL
;
eNB
->
start_if
=
start_if_NB_IoT
;
eNB
->
fh_asynch
=
(
eNB
->
node_timing
==
synch_to_other
)
?
fh_if4p5_asynch_UL_NB_IoT
:
NULL
;
eNB
->
rfdevice
.
host_type
=
RRU_HOST
;
eNB
->
ifdevice
.
host_type
=
RRU_HOST
;
ret
=
openair0_transport_load
(
&
eNB
->
ifdevice
,
&
openair0_cfg
[
CC_id
],
eNB
->
eth_params
);
printf
(
"openair0_transport_init returns %d for CC_id %d
\n
"
,
ret
,
CC_id
);
if
(
ret
<
0
)
{
printf
(
"Exiting, cannot initialize transport protocol
\n
"
);
exit
(
-
1
);
}
malloc_IF4p5_buffer
(
eNB
);
break
;
case
NGFI_RAU_IF4p5_NB_IoT
:
eNB
->
do_precoding
=
0
;
eNB
->
do_prach
=
do_prach_NB_IoT
;
eNB
->
fep
=
NULL
;
eNB
->
td
=
ulsch_decoding_data_NB_IoT
;
//(single_thread_flag==1) ? ulsch_decoding_data_2thread : ulsch_decoding_data;
eNB
->
te
=
dlsch_encoding_NB_IoT
;
//(single_thread_flag==1) ? dlsch_encoding_2threads : dlsch_encoding;
eNB
->
proc_uespec_rx
=
phy_procedures_eNB_uespec_RX_NB_IoT
;
eNB
->
proc_tx
=
proc_tx_high_NB_IoT
;
eNB
->
tx_fh
=
tx_fh_if4p5_NB_IoT
;
eNB
->
rx_fh
=
rx_fh_if4p5_NB_IoT
;
eNB
->
fh_asynch
=
(
eNB
->
node_timing
==
synch_to_other
)
?
fh_if4p5_asynch_UL_NB_IoT
:
NULL
;
eNB
->
start_rf
=
NULL
;
eNB
->
start_if
=
start_if_NB_IoT
;
eNB
->
rfdevice
.
host_type
=
RRU_HOST
;
eNB
->
ifdevice
.
host_type
=
RRU_HOST
;
ret
=
openair0_transport_load
(
&
eNB
->
ifdevice
,
&
openair0_cfg
[
CC_id
],
eNB
->
eth_params
);
printf
(
"openair0_transport_init returns %d for CC_id %d
\n
"
,
ret
,
CC_id
);
if
(
ret
<
0
)
{
printf
(
"Exiting, cannot initialize transport protocol
\n
"
);
exit
(
-
1
);
}
break
;
malloc_IF4p5_buffer
(
eNB
);
}
if
(
setup_eNB_buffers
(
PHY_vars_eNB_NB_IoT_g
[
inst
],
&
openair0_cfg
[
CC_id
])
!=
0
)
{
printf
(
"Exiting, cannot initialize eNodeB Buffers
\n
"
);
...
...
@@ -743,7 +566,7 @@ void init_eNB_NB_IoT(eNB_func_NB_IoT_t node_function[], eNB_timing_NB_IoT_t node
}
}
init_eNB_proc_NB_IoT
(
inst
);
//
init_eNB_proc_NB_IoT(inst);
}
sleep
(
1
);
...
...
@@ -753,134 +576,7 @@ void init_eNB_NB_IoT(eNB_func_NB_IoT_t node_function[], eNB_timing_NB_IoT_t node
}
void
init_eNB_proc_NB_IoT
(
int
inst
)
{
int
i
=
0
;
int
CC_id
;
PHY_VARS_eNB_NB_IoT
*
eNB
;
eNB_proc_NB_IoT_t
*
proc
;
eNB_rxtx_proc_NB_IoT_t
*
proc_rxtx
;
pthread_attr_t
*
attr0
=
NULL
,
*
attr1
=
NULL
,
*
attr_FH
=
NULL
,
*
attr_prach
=
NULL
,
*
attr_asynch
=
NULL
,
*
attr_single
=
NULL
,
*
attr_fep
=
NULL
,
*
attr_td
=
NULL
,
*
attr_te
=
NULL
,
*
attr_synch
=
NULL
;
for
(
CC_id
=
0
;
CC_id
<
MAX_NUM_CCs
;
CC_id
++
)
{
eNB
=
PHY_vars_eNB_NB_IoT_g
[
inst
][
CC_id
];
#ifndef OCP_FRAMEWORK
LOG_I
(
PHY
,
"Initializing eNB %d CC_id %d (%s,%s),
\n
"
,
inst
,
CC_id
,
eNB_functions
[
eNB
->
node_function
],
eNB_timing
[
eNB
->
node_timing
]);
#endif
proc
=
&
eNB
->
proc
;
proc_rxtx
=
proc
->
proc_rxtx
;
proc_rxtx
[
0
].
instance_cnt_rxtx
=
-
1
;
proc_rxtx
[
1
].
instance_cnt_rxtx
=
-
1
;
proc
->
instance_cnt_prach
=
-
1
;
proc
->
instance_cnt_FH
=
-
1
;
proc
->
instance_cnt_asynch_rxtx
=
-
1
;
proc
->
CC_id
=
CC_id
;
proc
->
instance_cnt_synch
=
-
1
;
proc
->
first_rx
=
1
;
proc
->
first_tx
=
1
;
proc
->
frame_offset
=
0
;
for
(
i
=
0
;
i
<
10
;
i
++
)
proc
->
symbol_mask
[
i
]
=
0
;
pthread_mutex_init
(
&
proc_rxtx
[
0
].
mutex_rxtx
,
NULL
);
pthread_mutex_init
(
&
proc_rxtx
[
1
].
mutex_rxtx
,
NULL
);
pthread_cond_init
(
&
proc_rxtx
[
0
].
cond_rxtx
,
NULL
);
pthread_cond_init
(
&
proc_rxtx
[
1
].
cond_rxtx
,
NULL
);
pthread_mutex_init
(
&
proc
->
mutex_prach
,
NULL
);
pthread_mutex_init
(
&
proc
->
mutex_asynch_rxtx
,
NULL
);
pthread_mutex_init
(
&
proc
->
mutex_synch
,
NULL
);
pthread_cond_init
(
&
proc
->
cond_prach
,
NULL
);
pthread_cond_init
(
&
proc
->
cond_FH
,
NULL
);
pthread_cond_init
(
&
proc
->
cond_asynch_rxtx
,
NULL
);
pthread_cond_init
(
&
proc
->
cond_synch
,
NULL
);
pthread_attr_init
(
&
proc
->
attr_FH
);
pthread_attr_init
(
&
proc
->
attr_prach
);
pthread_attr_init
(
&
proc
->
attr_synch
);
pthread_attr_init
(
&
proc
->
attr_asynch_rxtx
);
pthread_attr_init
(
&
proc
->
attr_single
);
pthread_attr_init
(
&
proc
->
attr_fep
);
pthread_attr_init
(
&
proc
->
attr_td
);
pthread_attr_init
(
&
proc
->
attr_te
);
pthread_attr_init
(
&
proc_rxtx
[
0
].
attr_rxtx
);
pthread_attr_init
(
&
proc_rxtx
[
1
].
attr_rxtx
);
#ifndef DEADLINE_SCHEDULER
attr0
=
&
proc_rxtx
[
0
].
attr_rxtx
;
attr1
=
&
proc_rxtx
[
1
].
attr_rxtx
;
attr_FH
=
&
proc
->
attr_FH
;
attr_prach
=
&
proc
->
attr_prach
;
attr_synch
=
&
proc
->
attr_synch
;
attr_asynch
=
&
proc
->
attr_asynch_rxtx
;
attr_single
=
&
proc
->
attr_single
;
attr_fep
=
&
proc
->
attr_fep
;
attr_td
=
&
proc
->
attr_td
;
attr_te
=
&
proc
->
attr_te
;
#endif
if
(
eNB
->
single_thread_flag
==
0
)
{
//the two threads that manage tw consecutive subframes
pthread_create
(
&
proc_rxtx
[
0
].
pthread_rxtx
,
attr0
,
eNB_thread_rxtx_NB_IoT
,
&
proc_rxtx
[
0
]
);
pthread_create
(
&
proc_rxtx
[
1
].
pthread_rxtx
,
attr1
,
eNB_thread_rxtx_NB_IoT
,
&
proc_rxtx
[
1
]
);
pthread_create
(
&
proc
->
pthread_FH
,
attr_FH
,
eNB_thread_FH_NB_IoT
,
&
eNB
->
proc
);
}
else
{
pthread_create
(
&
proc
->
pthread_single
,
attr_single
,
eNB_thread_single_NB_IoT
,
&
eNB
->
proc
);
init_fep_thread
(
eNB
,
attr_fep
);
/*
init_td_thread(eNB,attr_td);
init_te_thread(eNB,attr_te);
*/
}
pthread_create
(
&
proc
->
pthread_prach
,
attr_prach
,
eNB_thread_prach_NB_IoT
,
&
eNB
->
proc
);
pthread_create
(
&
proc
->
pthread_synch
,
attr_synch
,
eNB_thread_synch_NB_IoT
,
eNB
);
if
((
eNB
->
node_timing
==
synch_to_other
)
||
(
eNB
->
node_function
==
NGFI_RRU_IF5_NB_IoT
)
||
(
eNB
->
node_function
==
NGFI_RRU_IF4p5_NB_IoT
))
pthread_create
(
&
proc
->
pthread_asynch_rxtx
,
attr_asynch
,
eNB_thread_asynch_rxtx_NB_IoT
,
&
eNB
->
proc
);
char
name
[
16
];
if
(
eNB
->
single_thread_flag
==
0
)
{
snprintf
(
name
,
sizeof
(
name
),
"RXTX0 %d"
,
i
);
pthread_setname_np
(
proc_rxtx
[
0
].
pthread_rxtx
,
name
);
snprintf
(
name
,
sizeof
(
name
),
"RXTX1 %d"
,
i
);
pthread_setname_np
(
proc_rxtx
[
1
].
pthread_rxtx
,
name
);
snprintf
(
name
,
sizeof
(
name
),
"FH %d"
,
i
);
pthread_setname_np
(
proc
->
pthread_FH
,
name
);
}
else
{
snprintf
(
name
,
sizeof
(
name
),
" %d"
,
i
);
pthread_setname_np
(
proc
->
pthread_single
,
name
);
}
}
//for multiple CCs: setup master and slaves
/*
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
eNB = PHY_vars_eNB_g[inst][CC_id];
if (eNB->node_timing == synch_to_ext_device) { //master
eNB->proc.num_slaves = MAX_NUM_CCs-1;
eNB->proc.slave_proc = (eNB_proc_t**)malloc(eNB->proc.num_slaves*sizeof(eNB_proc_t*));
for (i=0; i< eNB->proc.num_slaves; i++) {
if (i < CC_id) eNB->proc.slave_proc[i] = &(PHY_vars_eNB_g[inst][i]->proc);
if (i >= CC_id) eNB->proc.slave_proc[i] = &(PHY_vars_eNB_g[inst][i+1]->proc);
}
}
}
*/
/* setup PHY proc TX sync mechanism */
pthread_mutex_init
(
&
sync_phy_proc
.
mutex_phy_proc_tx
,
NULL
);
pthread_cond_init
(
&
sync_phy_proc
.
cond_phy_proc_tx
,
NULL
);
sync_phy_proc
.
phy_proc_CC_id
=
0
;
}
targets/RT/USER/lte-ru.c
View file @
819ea956
...
...
@@ -1182,7 +1182,7 @@ void wakeup_L1s(RU_t *ru) {
}
}
// call NB-IOT RX/TX entry-point from ru_thread directly
if
(
ru
->
eNB_nb_iot_top
!=
0
)
ru
->
eNB_nb_iot_top
(
eNB_nb
_
iot_list
[
0
],
proc
->
frame_rx
,
proc
->
subframe_rx
,
string
,
ru
);
if
(
ru
->
eNB_nb_iot_top
!=
0
)
ru
->
eNB_nb_iot_top
(
eNB_nbiot_list
[
0
],
proc
->
frame_rx
,
proc
->
subframe_rx
,
string
,
ru
);
}
/*
AssertFatal(0==pthread_mutex_lock(&ruproc->mutex_eNBs),"");
...
...
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