Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
F
FMC ADC 100M 14b 4cha - Testing
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
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
FMC ADC 100M 14b 4cha - Testing
Commits
5aae3b2f
Commit
5aae3b2f
authored
May 11, 2012
by
Matthieu Cattin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
tmp: Working on fmc_adc module.
Adding exception handling, updating interfaces to common modules.
parent
e35d919e
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
182 additions
and
129 deletions
+182
-129
fmc_adc.py
test/fmcadc100m14b4cha/python/fmc_adc.py
+145
-89
test00.py
test/fmcadc100m14b4cha/python/test00.py
+4
-4
test01.py
test/fmcadc100m14b4cha/python/test01.py
+31
-34
test07.py
test/fmcadc100m14b4cha/python/test07.py
+2
-2
No files found.
test/fmcadc100m14b4cha/python/fmc_adc.py
View file @
5aae3b2f
#! /usr/bin/env
python
#! /usr/bin/env
python
# coding: utf8
# Copyright CERN, 2012
# Author: Matthieu Cattin (CERN)
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
# Last modifications: 8/5/2012
# Import standard modules
import
sys
import
rr
import
random
import
time
import
spi
import
ltc217x
import
csr
import
max5442
import
i2c
import
onewire
import
ds18b20
#import mcp9801
import
si57x
import
eeprom_24aa64
import
random
import
math
import
random
# Import specific modules
#import rr
from
csr
import
*
from
onewire
import
*
from
i2c
import
*
from
spi
import
*
from
ds18b20
import
*
from
eeprom_24aa64
import
*
from
ltc217x
import
*
from
max5442
import
*
from
si57x
import
*
# Import register maps
from
fmcadc100m_csr
import
*
# Converts digital value to volts
...
...
@@ -47,8 +65,15 @@ def signed2hex(value):
return
value
# Class to access fmcadc100m14b4cha mezzanine specific Wishbone cores
class
CFmcAdc100Ms
:
class
FmcAdc100mOperationError
(
Exception
):
def
__init__
(
self
,
msg
):
self
.
msg
=
msg
def
__str__
(
self
):
return
(
"FmcAdc100m:
%
s"
%
(
self
.
msg
))
class
CFmcAdc100m
:
FMC_SYS_I2C_ADDR
=
0x60000
EEPROM_ADDR
=
0x50
...
...
@@ -58,11 +83,14 @@ class CFmcAdc100Ms:
FMC_SPI_SS
=
{
'ADC'
:
0
,
'DAC1'
:
1
,
'DAC2'
:
2
,
'DAC3'
:
3
,
'DAC4'
:
4
}
FMC_I2C_ADDR
=
0x80000
#MCP9801_ADDR = 0x48
SI570_ADDR
=
0x55
FMC_ONEWIRE_ADDR
=
0xA0000
FMC_CSR_ADDR
=
0x90000
"""
FMC_CSR = {0x00:'Control register',
0x04:'Status register',
0x08:'Trigger configuration register',
...
...
@@ -90,7 +118,7 @@ class CFmcAdc100Ms:
0x60:'CH4 current value register',
0x64:'CH4 gain calibration register',
0x68:'CH4 offset calibration register',}
FMC_CSR_ADDR
=
0x90000
R_CTL = 0x00
R_STA = 0x04
R_TRIG_CFG = 0x08
...
...
@@ -136,9 +164,12 @@ class CFmcAdc100Ms:
STA_SERDES_SYNCED = 4
FSM_MASK = 0x00000007
"""
FSM_STATES
=
[
'N/A'
,
'IDLE'
,
'PRE_TRIG'
,
'WAIT_TRIG'
,
'POST_TRIG'
,
'DECR_SHOT'
,
'N/A'
,
'others'
]
"""
TRIG_CFG_HW_SEL = 0
TRIG_CFG_EXT_POL = 1
TRIG_CFG_HW_EN = 2
...
...
@@ -148,6 +179,7 @@ class CFmcAdc100Ms:
INT_SEL_MASK = 0xFFFFFFCF
INT_THRES_MASK = 0x0000FFFF
"""
IN_TERM
=
(
1
<<
3
)
IN_TERM_MASK
=
0x08
...
...
@@ -161,7 +193,7 @@ class CFmcAdc100Ms:
def
channel_addr
(
self
,
channel
,
reg
):
if
(
channel
<
1
or
channel
>
4
):
raise
Exception
(
'Channel number not in range (1 to 4).'
)
raise
FmcAdc100mOperationError
(
"Channel number not in range (1 to 4)."
)
else
:
addr
=
(
reg
+
(
0x10
*
(
channel
-
1
)))
#print("Channel %d address: %.2X") % (channel, addr)
...
...
@@ -169,33 +201,48 @@ class CFmcAdc100Ms:
def
__init__
(
self
,
bus
):
self
.
bus
=
bus
# Objects declaration
self
.
fmc_sys_i2c
=
i2c
.
COpenCoresI2C
(
self
.
bus
,
self
.
FMC_SYS_I2C_ADDR
,
249
)
self
.
eeprom_24aa64
=
eeprom_24aa64
.
C24AA64
(
self
.
fmc_sys_i2c
,
self
.
EEPROM_ADDR
)
self
.
fmc_spi
=
spi
.
COpenCoresSPI
(
self
.
bus
,
self
.
FMC_SPI_ADDR
,
self
.
FMC_SPI_DIV
)
self
.
adc_cfg
=
ltc217x
.
CLTC217x
(
self
.
fmc_spi
,
self
.
FMC_SPI_SS
[
'ADC'
])
self
.
fmc_i2c
=
i2c
.
COpenCoresI2C
(
self
.
bus
,
self
.
FMC_I2C_ADDR
,
249
)
self
.
fmc_onewire
=
onewire
.
COpenCoresOneWire
(
self
.
bus
,
self
.
FMC_ONEWIRE_ADDR
,
624
,
124
)
self
.
ds18b20
=
ds18b20
.
CDS18B20
(
self
.
fmc_onewire
,
0
)
self
.
si570
=
si57x
.
CSi57x
(
self
.
fmc_i2c
,
self
.
SI570_ADDR
)
self
.
fmc_adc_csr
=
csr
.
CCSR
(
self
.
bus
,
self
.
FMC_CSR_ADDR
)
self
.
dac_ch1
=
max5442
.
CMAX5442
(
self
.
fmc_spi
,
self
.
FMC_SPI_SS
[
'DAC1'
])
self
.
dac_ch2
=
max5442
.
CMAX5442
(
self
.
fmc_spi
,
self
.
FMC_SPI_SS
[
'DAC2'
])
self
.
dac_ch3
=
max5442
.
CMAX5442
(
self
.
fmc_spi
,
self
.
FMC_SPI_SS
[
'DAC3'
])
self
.
dac_ch4
=
max5442
.
CMAX5442
(
self
.
fmc_spi
,
self
.
FMC_SPI_SS
[
'DAC4'
])
# Set channels gaim to 1
self
.
fmc_adc_csr
.
wr_reg
(
self
.
R_CH1_GAIN
,
0x8000
)
self
.
fmc_adc_csr
.
wr_reg
(
self
.
R_CH2_GAIN
,
0x8000
)
self
.
fmc_adc_csr
.
wr_reg
(
self
.
R_CH3_GAIN
,
0x8000
)
self
.
fmc_adc_csr
.
wr_reg
(
self
.
R_CH4_GAIN
,
0x8000
)
try
:
self
.
fmc_sys_i2c
=
COpenCoresI2C
(
self
.
bus
,
self
.
FMC_SYS_I2C_ADDR
,
249
)
self
.
fmc_i2c
=
COpenCoresI2C
(
self
.
bus
,
self
.
FMC_I2C_ADDR
,
249
)
except
I2CDeviceOperationError
as
e
:
raise
FmcAdc100mOperationError
(
e
)
self
.
eeprom_24aa64
=
C24AA64
(
self
.
fmc_sys_i2c
,
self
.
EEPROM_ADDR
)
self
.
si570
=
CSi57x
(
self
.
fmc_i2c
,
self
.
SI570_ADDR
)
self
.
fmc_onewire
=
COpenCoresOneWire
(
self
.
bus
,
self
.
FMC_ONEWIRE_ADDR
,
624
,
124
)
self
.
ds18b20
=
CDS18B20
(
self
.
fmc_onewire
,
0
)
self
.
fmc_adc_csr
=
CCSR
(
self
.
bus
,
self
.
FMC_CSR_ADDR
,
FMCADC100M_CSR
)
self
.
fmc_spi
=
COpenCoresSPI
(
self
.
bus
,
self
.
FMC_SPI_ADDR
,
self
.
FMC_SPI_DIV
)
self
.
adc_cfg
=
CLTC217x
(
self
.
fmc_spi
,
self
.
FMC_SPI_SS
[
'ADC'
])
self
.
dac_ch
[
1
]
=
CMAX5442
(
self
.
fmc_spi
,
self
.
FMC_SPI_SS
[
'DAC1'
])
self
.
dac_ch
[
2
]
=
CMAX5442
(
self
.
fmc_spi
,
self
.
FMC_SPI_SS
[
'DAC2'
])
self
.
dac_ch
[
3
]
=
CMAX5442
(
self
.
fmc_spi
,
self
.
FMC_SPI_SS
[
'DAC3'
])
self
.
dac_ch
[
4
]
=
CMAX5442
(
self
.
fmc_spi
,
self
.
FMC_SPI_SS
[
'DAC4'
])
# Set channels gain to 1
self
.
fmc_adc_csr
.
set_field
(
'CH1_GAIN'
,
'VAL'
,
0x8000
)
self
.
fmc_adc_csr
.
set_field
(
'CH2_GAIN'
,
'VAL'
,
0x8000
)
self
.
fmc_adc_csr
.
set_field
(
'CH3_GAIN'
,
'VAL'
,
0x8000
)
self
.
fmc_adc_csr
.
set_field
(
'CH4_GAIN'
,
'VAL'
,
0x8000
)
# Enable mezzanine clock and offset DACs
self
.
fmc_adc_csr
.
wr_reg
(
self
.
R_CTL
,
((
1
<<
self
.
CTL_CLK_EN
)
|
(
1
<<
self
.
CTL_OFFSET_DAC_CLR_N
)))
self
.
fmc_adc_csr
.
set_field
(
'CTL'
,
'FMC_CLK_OE'
,
1
)
self
.
fmc_adc_csr
.
set_field
(
'CTL'
,
'OFFSET_DAC_CLR_N'
,
1
)
# Disable ADC test pattern
self
.
adc_cfg
.
dis_testpat
()
#def __del__(self):
# Disable ADC clock and reset offset correction DAC
#self.fmc_adc_csr.wr_reg(self.R_CTL, 0)
def
channel_check
(
self
,
channel
):
if
(
channel
<
1
or
channel
>
4
):
raise
FmcAdc100mOperationError
(
"Channel number
%
d, not in range 1 to 4."
)
else
:
return
channel
# Front panel LED manual control
def
acq_led
(
self
,
state
):
...
...
@@ -230,35 +277,48 @@ class CFmcAdc100Ms:
# print FMC unique ID
def
print_unique_id
(
self
):
print
(
'FMC unique ID:
%.12
X'
)
%
self
.
ds18b20
.
read_serial_number
()
try
:
print
(
'FMC unique ID:
%.12
X'
)
%
self
.
ds18b20
.
read_serial_number
()
except
DS18B20OperationError
as
e
:
raise
FmcAdc100mOperationError
(
e
)
# print FMC temperature
def
print_temp
(
self
):
serial_number
=
self
.
ds18b20
.
read_serial_number
()
print
(
"FMC temperature:
%3.3
f°C"
)
%
self
.
ds18b20
.
read_temp
(
serial_number
)
try
:
serial_number
=
self
.
ds18b20
.
read_serial_number
()
print
(
"FMC temperature:
%3.3
f°C"
)
%
self
.
ds18b20
.
read_temp
(
serial_number
)
except
DS18B20OperationError
as
e
:
raise
FmcAdc100mOperationError
(
e
)
# Returns FMC unique ID
def
get_unique_id
(
self
):
return
self
.
ds18b20
.
read_serial_number
()
try
:
return
self
.
ds18b20
.
read_serial_number
()
except
DS18B20OperationError
as
e
:
raise
FmcAdc100mOperationError
(
e
)
# Returns FMC temperature
def
get_temp
(
self
):
serial_number
=
self
.
ds18b20
.
read_serial_number
()
if
(
serial_number
==
-
1
):
return
-
1
else
:
try
:
serial_number
=
self
.
ds18b20
.
read_serial_number
()
return
self
.
ds18b20
.
read_temp
(
serial_number
)
except
DS18B20OperationError
as
e
:
raise
FmcAdc100mOperationError
(
e
)
# scan FMC i2c bus
def
i2c_scan
(
self
):
print
'
\n
Scan I2C bus'
print
'
\n
Scan
ning FMC
I2C bus'
return
self
.
fmc_i2c
.
scan
()
# scan FMC system i2c bus
def
sys_i2c_scan
(
self
):
print
'
\n
Scan system I2C bus'
print
'
\n
Scan
ning FMC
system I2C bus'
return
self
.
fmc_sys_i2c
.
scan
()
###########################################################################
########## Code to review ##########
# write to EEPROM on system i2c bus
def
sys_i2c_eeprom_write
(
self
,
addr
,
data
):
return
self
.
eeprom_24aa64
.
wr_data
(
addr
,
data
)
...
...
@@ -267,56 +327,52 @@ class CFmcAdc100Ms:
def
sys_i2c_eeprom_read
(
self
,
addr
,
size
):
return
self
.
eeprom_24aa64
.
rd_data
(
addr
,
size
)
###########################################################################
# Set input range
def
set_input_range
(
self
,
channel
,
in_range
):
addr
=
self
.
channel_addr
(
channel
,
self
.
R_CH1_SSR
)
reg
=
(
self
.
IN_TERM_MASK
&
self
.
fmc_adc_csr
.
rd_reg
(
addr
))
#print("ssr reg ch%1d: %.8X") %(channel, reg)
#print('[set_in_range] Channel %d Input range: %s')%(channel,in_range)
if
(
in_range
in
self
.
IN_RANGES
):
reg
|=
self
.
IN_RANGES
[
in_range
]
else
:
raise
Exception
(
'Unsupported parameter.'
)
#print("ssr reg ch%1d: %.8X") %(channel, reg)
self
.
fmc_adc_csr
.
wr_reg
(
addr
,
reg
)
#print("ssr reg ch%1d: %.8X") %(channel, self.fmc_adc_csr.rd_reg(addr))
reg_name
=
'CH'
+
str
(
self
.
channel_check
(
channel
))
+
"_CTL"
try
:
# read channel control register
reg_val
=
self
.
fmc_adc_csr
.
get_reg
(
reg_name
)
# Save input termination bit state
reg_val
=
self
.
IN_TERM_MASK
&
reg_val
#print "[FmcAdc100m] ssr reg ch%1d: %.8X" % (channel, reg_val)
#print "[FmcAdc100m] Channel %d Input range: %s" % (channel,in_range)
if
(
in_range
in
self
.
IN_RANGES
):
reg_val
|=
self
.
IN_RANGES
[
in_range
]
else
:
raise
FmcAdc100mOperationError
(
"Requested input range (
%
s) doesn
\'
t exist."
%
in_range
)
#print "[FmcAdc100m] ssr reg ch%1d: %.8X" % (channel, reg_val)
self
.
fmc_adc_csr
.
set_reg
(
reg_name
,
reg_val
)
#print "[FmcAdc100m] ssr reg ch%1d: %.8X" % (channel, self.fmc_adc_csr.get_reg(reg_name))
except
CSRDeviceOperationError
as
e
:
raise
FmcAdc100mOperationError
(
e
)
# Set SSR register
def
set_ssr
(
self
,
channel
,
value
):
addr
=
self
.
channel_addr
(
channel
,
self
.
R_CH1_SSR
)
self
.
fmc_adc_csr
.
wr_reg
(
addr
,
value
)
reg_name
=
'CH'
+
str
(
self
.
channel_check
(
channel
))
+
"_CTL"
try
:
self
.
fmc_adc_csr
.
set_reg
(
reg_name
,
value
)
except
CSRDeviceOperationError
as
e
:
raise
FmcAdc100mOperationError
(
e
)
# Get SSR register
def
get_ssr
(
self
,
channel
):
addr
=
self
.
channel_addr
(
channel
,
self
.
R_CH1_SSR
)
return
self
.
fmc_adc_csr
.
rd_reg
(
addr
)
reg_name
=
'CH'
+
str
(
self
.
channel_check
(
channel
))
+
"_CTL"
try
:
return
self
.
fmc_adc_csr
.
get_reg
(
reg_name
)
except
CSRDeviceOperationError
as
e
:
raise
FmcAdc100mOperationError
(
e
)
# DC offset calibration
def
dc_offset_calibr
(
self
,
channel
,
offset
):
if
(
1
==
channel
):
self
.
dac_ch1
.
set_offset
(
offset
)
elif
(
2
==
channel
):
self
.
dac_ch2
.
set_offset
(
offset
)
elif
(
3
==
channel
):
self
.
dac_ch3
.
set_offset
(
offset
)
elif
(
4
==
channel
):
self
.
dac_ch4
.
set_offset
(
offset
)
else
:
raise
Exception
(
'Unsupported parameter, channel number from 1 to 4'
)
# Set DC offset
# Set channel DC offset (MAX5442 DAC)
def
set_dc_offset
(
self
,
channel
,
offset
):
if
(
1
==
channel
):
self
.
dac_ch1
.
set_offset
(
offset
)
elif
(
2
==
channel
):
self
.
dac_ch2
.
set_offset
(
offset
)
elif
(
3
==
channel
):
self
.
dac_ch3
.
set_offset
(
offset
)
elif
(
4
==
channel
):
self
.
dac_ch4
.
set_offset
(
offset
)
else
:
raise
Exception
(
'Unsupported parameter, channel number from 1 to 4'
)
ch
=
self
.
channel_check
(
channel
)
try
:
self
.
dac_ch
[
ch
]
.
set_value
(
offset
)
except
MAX5442OperationError
as
e
:
raise
FmcAdc100mOperationError
(
e
)
def
set_dac_corr
(
self
,
corr_data
):
self
.
dac_corr_data
=
corr_data
...
...
test/fmcadc100m14b4cha/python/test00.py
View file @
5aae3b2f
...
...
@@ -5,7 +5,7 @@
# Author: Matthieu Cattin <matthieu.cattin@cern.ch>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
# Last modifications:
7
/5/2012
# Last modifications:
10
/5/2012
# Import system modules
import
sys
...
...
@@ -38,8 +38,8 @@ def main (default_directory='.'):
start_test_time
=
time
.
time
()
print
"================================================================================"
print
"Test00 start
\n
"
print
"
\n
================================================================================"
print
"
==>
Test00 start
\n
"
# SPEC object declaration
print
"Loading hardware access library and opening device.
\n
"
...
...
@@ -70,7 +70,7 @@ def main (default_directory='.'):
# Print carrier CSR registers
carrier
.
print_csr
()
print
"
End of test00
\n
"
print
"
==> End of test00
"
print
"================================================================================"
end_test_time
=
time
.
time
()
print
"Test00 elapsed time:
%.2
f seconds
\n
"
%
(
end_test_time
-
start_test_time
)
...
...
test/fmcadc100m14b4cha/python/test01.py
View file @
5aae3b2f
...
...
@@ -5,16 +5,25 @@
# Author: Matthieu Cattin <matthieu.cattin@cern.ch>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
# Last modifications: 11/5/2012
# Import system modules
import
sys
import
rr
import
time
import
os
# Add common modules location tp path
sys
.
path
.
append
(
'../../../'
)
sys
.
path
.
append
(
'../../../gnurabbit/python/'
)
sys
.
path
.
append
(
'../../../common/'
)
# Import common modules
from
ptsexcept
import
*
import
rr
import
csr
import
fmc_adc
# Import specific modules
from
fmc_adc_spec
import
*
from
fmc_adc
import
*
"""
...
...
@@ -23,46 +32,34 @@ test01: Test 1-wire thermometer and read the unique ID.
Note: Requires test00.py to run first to load the firmware!
"""
CARRIER_CSR
=
0x30000
CSR_TYPE_VER
=
0x00
CSR_BSTM_TYPE
=
0x04
CSR_BSTM_DATE
=
0x08
CSR_STATUS
=
0x0C
CSR_CTRL
=
0x10
def
main
(
default_directory
=
'.'
):
PCB_VER_MASK
=
0x000F
CARRIER_TYPE_MASK
=
0xFFFF0000
# Constants declaration
EXPECTED_BITSTREAM_TYPE
=
0x1
STATUS_FMC_PRES
=
(
1
<<
0
)
STATUS_P2L_PLL_LCK
=
(
1
<<
1
)
STATUS_SYS_PLL_LCK
=
(
1
<<
2
)
STATUS_DDR3_CAL_DONE
=
(
1
<<
3
)
CTRL_LED_GREEN
=
(
1
<<
0
)
CTRL_LED_RED
=
(
1
<<
1
)
CTRL_DAC_CLR_N
=
(
1
<<
2
)
start_test_time
=
time
.
time
(
)
print
"================================================================================"
print
"Test01 start
\n
"
FAMILY_CODE
=
0x28
# SPEC object declaration
print
"Loading hardware access library and opening device.
\n
"
spec
=
rr
.
Gennum
()
def
main
(
default_directory
=
'.'
):
# Carrier object declaration (SPEC board specific part)
try
:
carrier
=
CFmcAdc100mSpec
(
spec
,
EXPECTED_BITSTREAM_TYPE
)
except
FmcAdc100mSpecOperationError
as
e
:
raise
PtsCritical
(
"Carrier init failed, test stopped:
%
s"
%
e
)
"""
path_fpga_loader = '../../../gnurabbit/user/fpga_loader';
path_firmware = '../firmwares/spec_fmcadc100m14b4cha.bin';
# Mezzanine object declaration (FmcAdc100m14b4cha board specific part)
try
:
fmc
=
CFmcAdc100m
(
spec
)
except
FmcAdc100mOperationError
as
e
:
raise
PtsCritical
(
"Mezzanine init failed, test stopped:
%
s"
%
e
)
firmware_loader = os.path.join(default_directory, path_fpga_loader)
bitstream = os.path.join(default_directory, path_firmware)
print firmware_loader + ' ' + bitstream
os.system( firmware_loader + ' ' + bitstream )
time.sleep(2);
"""
# Objects declaration
spec
=
rr
.
Gennum
()
# bind to the SPEC board
carrier_csr
=
csr
.
CCSR
(
spec
,
CARRIER_CSR
)
fmc
=
fmc_adc
.
CFmcAdc100Ms
(
spec
)
# Read unique ID and print to log
unique_id
=
fmc
.
get_unique_id
()
...
...
test/fmcadc100m14b4cha/python/test07.py
View file @
5aae3b2f
...
...
@@ -137,7 +137,7 @@ def main (default_directory='.'):
#---------------------------------------------------------------------------
print
(
'Set positive offset:
%.4
X'
%
OFFSET_POS
)
for
i
in
range
(
1
,
NB_CHANNELS
+
1
):
fmc
.
dc_offset_calibr
(
i
,
OFFSET_POS
)
fmc
.
set_dc_offset
(
i
,
OFFSET_POS
)
time
.
sleep
(
DAC_SET_SLEEP
)
# Read channels
...
...
@@ -172,7 +172,7 @@ def main (default_directory='.'):
#---------------------------------------------------------------------------
print
(
'Set negative offset:
%.4
X'
%
OFFSET_NEG
)
for
i
in
range
(
1
,
NB_CHANNELS
+
1
):
fmc
.
dc_offset_calibr
(
i
,
OFFSET_NEG
)
fmc
.
set_dc_offset
(
i
,
OFFSET_NEG
)
time
.
sleep
(
DAC_SET_SLEEP
)
# Read channels
...
...
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