Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
P
PPSi
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
50
Issues
50
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
PPSi
Commits
6bc8b47d
Commit
6bc8b47d
authored
Jun 06, 2019
by
li hongming
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
support new cute-wr-a7 board
parent
e3a99db4
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
277 additions
and
123 deletions
+277
-123
faults.c
arch-wrpc/faults.c
+1
-1
wrc_ptp_ppsi.c
arch-wrpc/wrc_ptp_ppsi.c
+193
-73
wrpc-calibration.c
arch-wrpc/wrpc-calibration.c
+7
-5
wrpc-spll.c
arch-wrpc/wrpc-spll.c
+18
-11
wrpc.h
arch-wrpc/wrpc.h
+3
-2
hal_shmem.h
arch-wrs/include/libwr/hal_shmem.h
+5
-3
fsm.c
fsm.c
+1
-1
ieee1588_types.h
include/ppsi/ieee1588_types.h
+1
-1
state-wr-abscal.c
proto-ext-whiterabbit/state-wr-abscal.c
+3
-0
wr-servo.c
proto-ext-whiterabbit/wr-servo.c
+14
-2
state-initializing.c
proto-standard/state-initializing.c
+5
-2
wrpc-socket.c
time-wrpc/wrpc-socket.c
+6
-5
wrpc-time.c
time-wrpc/wrpc-time.c
+2
-2
wrs-socket.c
time-wrs/wrs-socket.c
+18
-15
No files found.
arch-wrpc/faults.c
View file @
6bc8b47d
...
...
@@ -8,7 +8,7 @@
#include "wrpc.h"
#include <errno.h>
#include "shell.h"
#include "syscon.h"
#include "
dev/
syscon.h"
extern
struct
pp_instance
ppi_static
[
wr_num_ports
];
extern
int
frame_rx_delay_us
;
...
...
arch-wrpc/wrc_ptp_ppsi.c
View file @
6bc8b47d
This diff is collapsed.
Click to expand it.
arch-wrpc/wrpc-calibration.c
View file @
6bc8b47d
...
...
@@ -5,7 +5,7 @@
* Released to the public domain
*/
#include <endpoint.h>
#include <
dev/
endpoint.h>
#include <ppsi/ppsi.h>
#include <softpll_ng.h>
#include <hal_exports.h>
...
...
@@ -18,10 +18,10 @@ int wrpc_read_calibration_data(struct pp_instance *ppi,
uint32_t
*
deltaTx
,
uint32_t
*
deltaRx
,
int32_t
*
fix_alpha
,
int32_t
*
clock_period
)
{
int
port
=
atoi
(
ppi
->
iface_name
[
2
]
);
int
port
=
atoi
(
&
(
ppi
->
iface_name
[
2
])
);
struct
hal_port_state
state
;
wrpc_get_port_state
(
&
state
,
p
pi
->
iface_name
);
wrpc_get_port_state
(
&
state
,
p
ort
);
/* check if the data is available */
if
(
fix_alpha
)
...
...
@@ -87,12 +87,14 @@ int wrpc_calibration_pattern_enable(struct pp_instance *ppi,
unsigned
int
calibrationPattern
,
unsigned
int
calibrationPatternLen
)
{
ep_cal_pattern_enable
(
atoi
(
&
ppi
->
iface_name
[
2
]));
int
port
=
atoi
(
&
(
ppi
->
iface_name
[
2
]));
ep_cal_pattern_enable
(
port
);
return
WR_HW_CALIB_OK
;
}
int
wrpc_calibration_pattern_disable
(
struct
pp_instance
*
ppi
)
{
ep_cal_pattern_disable
(
atoi
(
&
ppi
->
iface_name
[
2
]));
int
port
=
atoi
(
&
(
ppi
->
iface_name
[
2
]));
ep_cal_pattern_disable
(
port
);
return
WR_HW_CALIB_OK
;
}
arch-wrpc/wrpc-spll.c
View file @
6bc8b47d
...
...
@@ -7,19 +7,19 @@
#include <stdint.h>
#include <ppsi/ppsi.h>
#include <pps_gen.h>
#include <
dev/
pps_gen.h>
#include <softpll_ng.h>
#include "../proto-ext-whiterabbit/wr-constants.h"
#include <rxts_calibrator.h>
#include <
dev/
rxts_calibrator.h>
#include "wrpc.h"
extern
uint32_t
cal_phase_transition
[];
int
wrpc_spll_locking_enable
(
struct
pp_instance
*
ppi
)
{
int
port
=
atoi
(
&
ppi
->
iface_name
[
2
]
);
spll_init
(
SPLL_MODE_SLAVE
,
port
,
1
);
spll_enable_ptracker
(
port
,
1
);
int
port
=
atoi
(
&
(
ppi
->
iface_name
[
2
])
);
spll_init
(
SPLL_MODE_SLAVE
,
2
*
port
,
1
);
spll_enable_ptracker
(
2
*
port
,
1
);
rxts_calibration_start
(
port
);
return
WR_SPLL_OK
;
}
...
...
@@ -29,7 +29,7 @@ int wrpc_spll_locking_poll(struct pp_instance *ppi, int grandmaster)
int
locked
;
int
i
;
static
int
t24p_calibrated
[
wr_num_ports
]
=
{
0
,
0
};
int
port
=
atoi
(
&
ppi
->
iface_name
[
2
]
);
int
port
=
atoi
(
&
(
ppi
->
iface_name
[
2
])
);
locked
=
spll_check_lock
(
0
);
/* both slave and gm mode */
...
...
@@ -58,18 +58,25 @@ int wrpc_spll_locking_disable(struct pp_instance *ppi)
int
wrpc_spll_enable_ptracker
(
struct
pp_instance
*
ppi
)
{
spll_enable_ptracker
(
atoi
(
&
ppi
->
iface_name
[
2
]),
1
);
int
port
=
atoi
(
&
(
ppi
->
iface_name
[
2
]));
// for rx clock
spll_enable_ptracker
(
2
*
port
,
1
);
// for tx clock
spll_enable_ptracker
(
2
*
port
+
1
,
1
);
return
WR_SPLL_OK
;
}
int
wrpc_enable_timing_output
(
struct
pp_instance
*
ppi
,
int
enable
)
{
int
port
=
atoi
(
&
(
ppi
->
iface_name
[
2
]));
if
(
enable
==
WR_DSPOR
(
ppi
)
->
ppsOutputOn
)
return
WR_SPLL_OK
;
WR_DSPOR
(
ppi
)
->
ppsOutputOn
=
enable
;
shw_pps_gen_enable_output
(
enable
);
shw_pps_gen_time_valid
(
enable
);
if
(
port
==
0
)
shw_pps_gen_enable_output
(
enable
);
// For LED of SFP0.
else
shw_pps_gen_time_valid
(
enable
);
// For LED of SFP1.
// shw_pps_gen_unmask_output(enable); // For generation of timing signals.
return
WR_SPLL_OK
;
}
...
...
@@ -83,7 +90,7 @@ int wrpc_adjust_counters(int64_t adjust_sec, int32_t adjust_nsec)
if
(
adjust_sec
)
shw_pps_gen_adjust
(
PPSG_ADJUST_SEC
,
adjust_sec
);
if
(
adjust_nsec
)
shw_pps_gen_adjust
(
PPSG_ADJUST_NSEC
,
adjust_nsec
);
shw_pps_gen_adjust
(
PPSG_ADJUST_NSEC
,
adjust_nsec
);
return
0
;
}
...
...
arch-wrpc/wrpc.h
View file @
6bc8b47d
...
...
@@ -20,8 +20,9 @@
#define WRC_MODE_SLAVE 3
#define WRC_MODE_ABSCAL 4
#define WRC_MODE_CASCADED 5
#define WRC_MODE_CASCADED_MASTER_ONLY 6
extern
int
ptp_mode
[
2
];
extern
int
ptp_mode
[
wr_num_ports
];
int
wrc_ptp_init
(
void
);
int
wrc_ptp_set_mode
(
int
mode
,
int
port
);
...
...
@@ -66,6 +67,6 @@ int wrpc_calibration_pattern_enable(struct pp_instance *ppi,
unsigned
int
calibrationPattern
,
unsigned
int
calibrationPatternLen
);
int
wrpc_calibration_pattern_disable
(
struct
pp_instance
*
ppi
);
int
wrpc_get_port_state
(
struct
hal_port_state
*
p
ort
,
const
char
*
port_name
);
int
wrpc_get_port_state
(
struct
hal_port_state
*
p
s
,
int
port
);
#endif
/* __WRPC_H */
arch-wrs/include/libwr/hal_shmem.h
View file @
6bc8b47d
...
...
@@ -85,9 +85,11 @@ struct hal_port_state {
/* calibration data */
hal_port_calibration_t
calib
;
/* current DMTD loopback phase (ps) and whether is it valid or not */
uint32_t
phase_val
;
int
phase_val_valid
;
/* current DMTD loopback phase and whether is it valid or not */
uint32_t
phase_rx_val
;
int
phase_rx_val_valid
;
uint32_t
phase_tx_val
;
int
phase_tx_val_valid
;
int
tx_cal_pending
,
rx_cal_pending
;
/* locking FSM state */
int
lock_state
;
...
...
fsm.c
View file @
6bc8b47d
...
...
@@ -92,7 +92,7 @@ static int leave_current_state(struct pp_instance *ppi)
ppi
->
flags
&=
~
PPI_FLAGS_WAITING
;
pp_diag_fsm
(
ppi
,
ppi
->
current_state_item
->
name
,
STATE_LEAVE
,
0
);
/* next_delay unused: go to new state now */
return
10
0
;
return
0
;
}
/*
...
...
include/ppsi/ieee1588_types.h
View file @
6bc8b47d
...
...
@@ -45,7 +45,7 @@ typedef struct Integer64 {
typedef
struct
UInteger64
{
uint32_t
lsb
;
uint32_t
msb
;
uint32_t
msb
;
}
UInteger64
;
struct
TimeInterval
{
/* page 12 (32) -- never used */
...
...
proto-ext-whiterabbit/state-wr-abscal.c
View file @
6bc8b47d
...
...
@@ -26,6 +26,7 @@ static int next_pps_ms(struct pp_instance *ppi, struct pp_time *t)
int
wr_abscal
(
struct
pp_instance
*
ppi
,
uint8_t
*
pkt
,
int
plen
)
{
struct
pp_time
t
;
struct
wr_dsport
*
wrp
=
WR_DSPOR
(
ppi
);
int
len
,
i
;
if
(
ppi
->
is_new_state
)
{
...
...
@@ -38,6 +39,8 @@ int wr_abscal(struct pp_instance *ppi, uint8_t *pkt, int plen)
if
(
pp_timeout
(
ppi
,
PP_TO_EXT_0
))
{
uint64_t
secs
=
t
.
secs
;
// wrp->ops->enable_timing_output(ppi, 1);
/* Wait for the second to tick */
while
(
ppi
->
t_ops
->
get
(
ppi
,
&
t
),
t
.
secs
==
secs
)
;
...
...
proto-ext-whiterabbit/wr-servo.c
View file @
6bc8b47d
...
...
@@ -184,7 +184,7 @@ int wr_servo_init(struct pp_instance *ppi)
&
s
->
fiber_fix_alpha
,
&
s
->
clock_period_ps
)
!=
WR_HW_CALIB_OK
)
return
-
1
;
wrp
->
ops
->
enable_timing_output
(
ppi
,
0
);
//
wrp->ops->enable_timing_output(ppi, 0);
strncpy
(
s
->
if_name
,
ppi
->
cfg
.
iface_name
,
sizeof
(
s
->
if_name
));
/*
...
...
@@ -455,6 +455,7 @@ int wr_servo_update(struct pp_instance *ppi)
&&
locking_poll_ret
!=
WR_SPLL_CALIB_NOT_READY
)
{
pp_diag
(
ppi
,
servo
,
1
,
"PLL OutOfLock, should restart sync
\n
"
);
wrp
->
ops
->
enable_timing_output
(
ppi
,
0
);
shw_pps_gen_unmask_output
(
0
);
/* TODO check
* DSPOR(ppi)->doRestart = TRUE; */
}
...
...
@@ -495,6 +496,8 @@ int wr_servo_update(struct pp_instance *ppi)
* Else, we must ensure we leave this status towards
* fine tuning
*/
wrp
->
ops
->
enable_timing_output
(
ppi
,
0
);
shw_pps_gen_unmask_output
(
0
);
s
->
state
=
WR_SYNC_PHASE
;
break
;
...
...
@@ -502,13 +505,15 @@ int wr_servo_update(struct pp_instance *ppi)
wrp
->
ops
->
adjust_counters
(
0
,
ts_offset_ticks
);
s
->
flags
|=
WR_FLAG_WAIT_HW
;
s
->
state
=
WR_SYNC_PHASE
;
wrp
->
ops
->
enable_timing_output
(
ppi
,
0
);
shw_pps_gen_unmask_output
(
0
);
break
;
case
WR_SYNC_PHASE
:
pp_diag
(
ppi
,
servo
,
2
,
"oldsetp %i, offset %i:%04i
\n
"
,
s
->
cur_setpoint
,
ts_offset_ticks
,
ts_offset_picos
);
s
->
cur_setpoint
+=
ts_offset_picos
;
s
->
cur_setpoint
+=
(
ts_offset_picos
*
7
/
8
)
;
wrp
->
ops
->
adjust_phase
(
s
->
cur_setpoint
);
s
->
flags
|=
WR_FLAG_WAIT_HW
;
...
...
@@ -526,6 +531,8 @@ int wr_servo_update(struct pp_instance *ppi)
pp_diag
(
ppi
,
time
,
1
,
"system time set to %li TAI
\n
"
,
(
long
)
ppi
->
t4
.
secs
);
}
wrp
->
ops
->
enable_timing_output
(
ppi
,
0
);
shw_pps_gen_unmask_output
(
0
);
break
;
case
WR_WAIT_OFFSET_STABLE
:
...
...
@@ -534,8 +541,13 @@ int wr_servo_update(struct pp_instance *ppi)
remaining_offset
=
abs
(
ts_offset_picos
);
if
(
remaining_offset
<
WR_SERVO_OFFSET_STABILITY_THRESHOLD
)
{
wrp
->
ops
->
enable_timing_output
(
ppi
,
1
);
shw_pps_gen_unmask_output
(
1
);
s
->
delta_ms_prev
=
s
->
delta_ms
;
s
->
state
=
WR_TRACK_PHASE
;
}
else
if
(
remaining_offset
>
5
*
WR_SERVO_OFFSET_STABILITY_THRESHOLD
)
{
s
->
missed_iters
=
0
;
s
->
state
=
WR_SYNC_PHASE
;
}
else
{
s
->
missed_iters
++
;
}
...
...
proto-standard/state-initializing.c
View file @
6bc8b47d
...
...
@@ -42,7 +42,7 @@ int pp_initializing(struct pp_instance *ppi, unsigned char *pkt, int plen)
struct
DSPort
*
dsport
=
DSPOR
(
ppi
);
struct
pp_runtime_opts
*
opt
=
OPTS
(
ppi
);
int
ret
=
0
;
int
port
=
atoi
(
&
ppi
->
iface_name
[
2
]
);
int
port
=
atoi
(
&
(
ppi
->
iface_name
[
2
])
);
if
(
ppi
->
n_ops
->
init
(
ppi
)
<
0
)
/* it must handle being called twice */
goto
failure
;
...
...
@@ -56,7 +56,10 @@ int pp_initializing(struct pp_instance *ppi, unsigned char *pkt, int plen)
id
[
1
]
=
mac
[
1
];
id
[
2
]
=
mac
[
2
];
id
[
3
]
=
0xff
;
id
[
4
]
=
0xfe
;
if
(
ppi
->
role
!=
PPSI_ROLE_MASTER
)
id
[
4
]
=
0xff
;
else
id
[
4
]
=
0xfe
;
id
[
5
]
=
mac
[
3
];
id
[
6
]
=
mac
[
4
];
id
[
7
]
=
mac
[
5
];
...
...
time-wrpc/wrpc-socket.c
View file @
6bc8b47d
...
...
@@ -8,8 +8,8 @@
#include "ptpdump.h"
#include "../arch-wrpc/wrpc.h"
#include <syscon.h>
/* wrpc-sw */
#include <endpoint.h>
/* wrpc-sw */
#include <
dev/
syscon.h>
/* wrpc-sw */
#include <
dev/
endpoint.h>
/* wrpc-sw */
#include <ptpd_netif.h>
/* wrpc-sw */
int
frame_rx_delay_us
;
/* set by faults.c */
...
...
@@ -40,7 +40,7 @@ static int wrpc_open_ch(struct pp_instance *ppi)
mac_addr_t
mac
;
struct
wr_sockaddr
addr
;
char
*
macaddr
=
PP_MCAST_MACADDRESS
;
int
port
=
atoi
(
&
ppi
->
iface_name
[
2
]
);
int
port
=
atoi
(
&
(
ppi
->
iface_name
[
2
])
);
if
(
CONFIG_HAS_P2P
&&
ppi
->
mech
==
PP_P2P_MECH
)
macaddr
=
PP_PDELAY_MACADDRESS
;
...
...
@@ -69,7 +69,7 @@ static int wrpc_net_recv(struct pp_instance *ppi, void *pkt, int len,
struct
wr_timestamp
wr_ts
;
struct
wr_sockaddr
addr
;
sock
=
ppi
->
ch
[
PP_NP_EVT
].
custom
;
int
port
=
atoi
(
&
ppi
->
iface_name
[
2
]
);
int
port
=
atoi
(
&
(
ppi
->
iface_name
[
2
])
);
got
=
ptpd_netif_recvfrom
(
sock
,
&
addr
,
pkt
,
len
,
&
wr_ts
,
port
);
if
(
got
<=
0
)
return
got
;
...
...
@@ -128,7 +128,7 @@ static int wrpc_net_send(struct pp_instance *ppi, void *pkt, int len,
struct
wr_sockaddr
addr
;
struct
pp_time
*
t
=
&
ppi
->
last_snt_time
;
int
is_pdelay
=
pp_msgtype_info
[
msgtype
].
is_pdelay
;
int
port
=
atoi
(
&
ppi
->
iface_name
[
2
]
);
int
port
=
atoi
(
&
(
ppi
->
iface_name
[
2
])
);
static
const
uint8_t
macaddr
[
2
][
ETH_ALEN
]
=
{
[
PP_E2E_MECH
]
=
PP_MCAST_MACADDRESS
,
[
PP_P2P_MECH
]
=
PP_PDELAY_MACADDRESS
,
...
...
@@ -159,6 +159,7 @@ static int wrpc_net_send(struct pp_instance *ppi, void *pkt, int len,
if
(
t
)
{
t
->
secs
=
wr_ts
.
sec
;
t
->
scaled_nsecs
=
(
int64_t
)
wr_ts
.
nsec
<<
16
;
t
->
scaled_nsecs
+=
wr_ts
.
phase
*
(
1
<<
16
)
/
1000
;
if
(
!
wr_ts
.
correct
)
mark_incorrect
(
t
);
...
...
time-wrpc/wrpc-time.c
View file @
6bc8b47d
...
...
@@ -6,8 +6,8 @@
* Released according to the GNU LGPL, version 2.1 or any later version.
*/
#include <ppsi/ppsi.h>
#include "pps_gen.h"
/* in wrpc-sw */
#include "syscon.h"
/* in wrpc-sw */
#include "
dev/
pps_gen.h"
/* in wrpc-sw */
#include "
dev/
syscon.h"
/* in wrpc-sw */
static
int
wrpc_time_get
(
struct
pp_instance
*
ppi
,
struct
pp_time
*
t
)
{
...
...
time-wrs/wrs-socket.c
View file @
6bc8b47d
...
...
@@ -58,9 +58,12 @@ typedef struct
struct
wrs_socket
{
/* parameters for linearization of RX timestamps */
uint32_t
clock_period
;
uint32_t
phase_transition
;
uint32_t
dmtd_phase
;
int
dmtd_phase_valid
;
uint32_t
phase_transition_rx
;
uint32_t
dmtd_phase_rx
;
uint32_t
phase_transition_tx
;
uint32_t
dmtd_phase_tx
;
int
dmtd_phase_rx_valid
;
int
dmtd_phase_tx_valid
;
timeout_t
dmtd_update_tmo
;
};
...
...
@@ -118,8 +121,8 @@ static void update_dmtd(struct wrs_socket *s, struct pp_instance *ppi)
p
=
pp_wrs_lookup_port
(
ppi
->
iface_name
);
if
(
!
p
)
return
;
s
->
dmtd_phase
=
p
->
phase
_val
;
s
->
dmtd_phase_
valid
=
p
->
phase
_val_valid
;
s
->
dmtd_phase
_rx
=
p
->
phase_rx
_val
;
s
->
dmtd_phase_
rx_valid
=
p
->
phase_rx
_val_valid
;
tmo_restart
(
&
s
->
dmtd_update_tmo
);
}
...
...
@@ -131,18 +134,18 @@ static void update_dmtd(struct wrs_socket *s, struct pp_instance *ppi)
* -- ARub 2016-10
*/
static
void
wrs_linearize_rx_timestamp
(
struct
pp_time
*
ts
,
int32_t
dmtd_phase
,
int
cntr_ahead
,
int
transition_point
,
int32_t
dmtd_phase
_rx
,
int
cntr_ahead
,
int
transition_point
,
int
clock_period
)
{
int
trip_lo
,
trip_hi
;
int
phase
;
pp_diag
(
NULL
,
ext
,
3
,
"linearize ts %s and phase %i
\n
"
,
fmt_time
(
ts
),
dmtd_phase
);
fmt_time
(
ts
),
dmtd_phase
_rx
);
pp_diag
(
NULL
,
ext
,
3
,
" (ahead %i tpoint %i, period %i
\n
"
,
cntr_ahead
,
transition_point
,
clock_period
);
phase
=
clock_period
-
1
-
dmtd_phase
;
phase
=
clock_period
-
1
-
dmtd_phase
_rx
;
/* calculate the range within which falling edge timestamp is stable
* (no possible transitions) */
...
...
@@ -167,7 +170,7 @@ static void wrs_linearize_rx_timestamp(struct pp_time *ts,
/* check if the phase is before the counter transition value
* and eventually increase the counter by 1 to simulate a
* timestamp transition exactly at s->phase_transition
* timestamp transition exactly at s->phase_transition
_rx
* DMTD phase value */
if
(
inside_range
(
trip_lo
,
transition_point
,
phase
))
ts
->
scaled_nsecs
+=
(
clock_period
/
1000LL
)
<<
16
;
...
...
@@ -250,9 +253,9 @@ static int wrs_recv_msg(struct pp_instance *ppi, int fd, void *pkt, int len,
if
(
!
WR_DSPOR
(
ppi
)
->
wrModeOn
)
{
goto
drop
;
}
if
(
s
->
dmtd_phase_valid
)
{
wrs_linearize_rx_timestamp
(
t
,
s
->
dmtd_phase
,
cntr_ahead
,
s
->
phase_transition
,
s
->
clock_period
);
if
(
s
->
dmtd_phase_
rx_
valid
)
{
wrs_linearize_rx_timestamp
(
t
,
s
->
dmtd_phase
_rx
,
cntr_ahead
,
s
->
phase_transition
_rx
,
s
->
clock_period
);
}
else
{
mark_incorrect
(
t
);
}
...
...
@@ -656,10 +659,10 @@ static int wrs_net_init(struct pp_instance *ppi)
* constant here (ARub)
*/
s
->
clock_period
=
16000
;
/* REF_CLOCK_PERIOD_PS */
s
->
phase_transition
=
0
;
/* DEFAULT_T2_PHASE_TRANS */
s
->
dmtd_phase
=
p
->
phase
_val
;
s
->
phase_transition
_rx
=
DEFAULT_T2_PHASE_TRANS
;
/* DEFAULT_T2_PHASE_TRANS */
s
->
dmtd_phase
_rx
=
p
->
phase_rx
_val
;
s
->
dmtd_phase_valid
=
0
;
s
->
dmtd_phase_
rx_
valid
=
0
;
ppi
->
ch
[
PP_NP_GEN
].
arch_data
=
s
;
ppi
->
ch
[
PP_NP_EVT
].
arch_data
=
s
;
...
...
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