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
promise
OpenXG-RAN
Commits
34deaae4
Commit
34deaae4
authored
Sep 26, 2018
by
yilmazt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Working but uncleaned polar_decoder_dci and related code
parent
2f66c11d
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
430 additions
and
32 deletions
+430
-32
openair1/PHY/CODING/TESTBENCH/polartest.c
openair1/PHY/CODING/TESTBENCH/polartest.c
+114
-21
openair1/PHY/CODING/nrPolar_tools/nr_bitwise_operations.c
openair1/PHY/CODING/nrPolar_tools/nr_bitwise_operations.c
+3
-1
openair1/PHY/CODING/nrPolar_tools/nr_polar_decoder.c
openair1/PHY/CODING/nrPolar_tools/nr_polar_decoder.c
+249
-0
openair1/PHY/CODING/nrPolar_tools/nr_polar_defs.h
openair1/PHY/CODING/nrPolar_tools/nr_polar_defs.h
+9
-1
openair1/PHY/CODING/nrPolar_tools/nr_polar_encoder.c
openair1/PHY/CODING/nrPolar_tools/nr_polar_encoder.c
+52
-7
openair1/PHY/CODING/nr_polar_init.c
openair1/PHY/CODING/nr_polar_init.c
+3
-2
No files found.
openair1/PHY/CODING/TESTBENCH/polartest.c
View file @
34deaae4
...
@@ -10,8 +10,9 @@
...
@@ -10,8 +10,9 @@
#include "PHY/CODING/coding_defs.h"
#include "PHY/CODING/coding_defs.h"
#include "SIMULATION/TOOLS/sim.h"
#include "SIMULATION/TOOLS/sim.h"
//
#define DEBUG_DCI_POLAR_PARAMS
#define DEBUG_DCI_POLAR_PARAMS
//#define DEBUG_POLAR_TIMING
//#define DEBUG_POLAR_TIMING
//#define DEBUG_CRC
int
main
(
int
argc
,
char
*
argv
[])
{
int
main
(
int
argc
,
char
*
argv
[])
{
...
@@ -136,27 +137,119 @@ int main(int argc, char *argv[]) {
...
@@ -136,27 +137,119 @@ int main(int argc, char *argv[]) {
currentPtr
=
nr_polar_params
(
nrPolar_params
,
polarMessageType
,
testLength
,
aggregation_level
);
currentPtr
=
nr_polar_params
(
nrPolar_params
,
polarMessageType
,
testLength
,
aggregation_level
);
#ifdef DEBUG_DCI_POLAR_PARAMS
#ifdef DEBUG_DCI_POLAR_PARAMS
uint32_t
dci_pdu
[
4
];
memset
(
dci_pdu
,
0
,
sizeof
(
uint32_t
)
*
4
);
dci_pdu
[
0
]
=
0x01189400
;
printf
(
"dci_pdu: [0]->0x%08x
\t
[1]->0x%08x
\t
[2]->0x%08x
\t
[3]->0x%08x
\n
"
,
dci_pdu
[
0
],
dci_pdu
[
1
],
dci_pdu
[
2
],
dci_pdu
[
3
]);
uint32_t
encoder_output
[
54
];
memset
(
encoder_output
,
0
,
sizeof
(
uint32_t
)
*
54
);
uint16_t
size
=
41
;
uint16_t
rnti
=
3
;
aggregation_level
=
8
;
nr_polar_init
(
&
nrPolar_params
,
1
,
size
,
aggregation_level
);
t_nrPolar_paramsPtr
currentPtrDCI
=
nr_polar_params
(
nrPolar_params
,
1
,
size
,
aggregation_level
);
polar_encoder_dci
(
dci_pdu
,
encoder_output
,
currentPtrDCI
,
rnti
);
for
(
int
i
=
0
;
i
<
54
;
i
++
)
printf
(
"encoder_output: [%2d]->0x%08x
\n
"
,
i
,
encoder_output
[
i
]);
uint8_t
*
encoder_outputByte
=
malloc
(
sizeof
(
uint8_t
)
*
currentPtrDCI
->
encoderLength
);
double
*
channel_output
=
malloc
(
sizeof
(
double
)
*
currentPtrDCI
->
encoderLength
);
uint32_t
dci_estimation
[
4
];
memset
(
dci_estimation
,
0
,
sizeof
(
uint32_t
)
*
4
);
printf
(
"dci_estimation: [0]->0x%08x
\t
[1]->0x%08x
\t
[2]->0x%08x
\t
[3]->0x%08x
\n
"
,
dci_estimation
[
0
],
dci_estimation
[
1
],
dci_estimation
[
2
],
dci_estimation
[
3
]);
nr_bit2byte_uint32_8_t
(
encoder_output
,
currentPtrDCI
->
encoderLength
,
encoder_outputByte
);
printf
(
"[polartest] encoder_outputByte: "
);
for
(
int
i
=
0
;
i
<
currentPtrDCI
->
encoderLength
;
i
++
)
printf
(
"%d-"
,
encoder_outputByte
[
i
]);
printf
(
"
\n
"
);
for
(
int
i
=
0
;
i
<
currentPtrDCI
->
encoderLength
;
i
++
)
{
if
(
encoder_outputByte
[
i
]
==
0
)
{
channel_output
[
i
]
=
1
/
sqrt
(
2
);
}
else
{
channel_output
[
i
]
=
(
-
1
)
/
sqrt
(
2
);
}
}
decoderState
=
polar_decoder_dci
(
channel_output
,
dci_estimation
,
currentPtrDCI
,
NR_POLAR_DECODER_LISTSIZE
,
NR_POLAR_DECODER_PATH_METRIC_APPROXIMATION
,
rnti
);
printf
(
"dci_estimation: [0]->0x%08x
\t
[1]->0x%08x
\t
[2]->0x%08x
\t
[3]->0x%08x
\n
"
,
dci_estimation
[
0
],
dci_estimation
[
1
],
dci_estimation
[
2
],
dci_estimation
[
3
]);
return
0
;
#endif
#ifdef DEBUG_CRC
uint32_t
crc
;
uint32_t
crc
;
unsigned
int
poly24c
=
0xb2b11700
;
unsigned
int
poly24c
=
0xb2b11700
;
testInput
[
0
]
=
0x01189400
;
uint32_t
testInputCRC
[
4
];
printf
(
"testInput: [0]->0x%08x
\t
[1]->0x%08x
\t
[2]->0x%08x
\t
[3]->0x%08x
\n
"
,
testInputCRC
[
0
]
=
0x00291880
;
testInput
[
0
],
testInput
[
1
],
testInput
[
2
],
testInput
[
3
]);
//testInputCRC[0]=0x01189400;
uint8_t
testInput2
[
8
];
testInputCRC
[
1
]
=
0x00000000
;
nr_crc_bit2bit_uint32_8_t
(
testInput
,
32
,
testInput2
);
testInputCRC
[
2
]
=
0x00000000
;
printf
(
"testInput2: [0]->%x
\t
[1]->%x
\t
[2]->%x
\t
[3]->%x
\n
"
testInputCRC
[
3
]
=
0x00000000
;
uint32_t
testInputcrc
=
0x01189400
;
uint32_t
testInputcrc2
=
0x00291880
;
uint8_t
testInputCRC2
[
8
];
nr_crc_bit2bit_uint32_8_t
(
testInputCRC
,
32
,
testInputCRC2
);
printf
(
"testInputCRC2: [0]->%x
\t
[1]->%x
\t
[2]->%x
\t
[3]->%x
\n
"
" [4]->%x
\t
[5]->%x
\t
[6]->%x
\t
[7]->%x
\n
"
,
" [4]->%x
\t
[5]->%x
\t
[6]->%x
\t
[7]->%x
\n
"
,
testInput2
[
0
],
testInput2
[
1
],
testInput2
[
2
],
testInput2
[
3
],
testInputCRC2
[
0
],
testInputCRC2
[
1
],
testInputCRC2
[
2
],
testInputCRC2
[
3
],
testInput2
[
4
],
testInput2
[
5
],
testInput2
[
6
],
testInput2
[
7
]);
testInputCRC2
[
4
],
testInputCRC2
[
5
],
testInputCRC2
[
6
],
testInputCRC2
[
7
]);
printf
(
"crc32: [0]->0x%08x
\n
"
,
crc24c
(
testInput2
,
32
));
unsigned
int
crc41
=
crc24c
(
testInputCRC
,
32
);
printf
(
"crc56: [0]->0x%08x
\n
"
,
crc24c
(
testInput2
,
56
));
unsigned
int
crc65
=
crc24c
(
testInputCRC
,
56
);
crc
=
crc24c
(
testInput
,
testLength
)
>>
8
;
printf
(
"crc41: [0]->0x%08x
\t
crc65: [0]->0x%08x
\n
"
,
crc41
,
crc65
);
for
(
int
i
=
0
;
i
<
32
;
i
++
)
printf
(
"crc41[%d]=%d
\t
crc65[%d]=%d
\n
"
,
i
,(
crc41
>>
i
)
&
1
,
i
,(
crc65
>>
i
)
&
1
);
crc
=
crc24c
(
testInputCRC
,
testLength
)
>>
8
;
for
(
int
i
=
0
;
i
<
24
;
i
++
)
printf
(
"[i]=%d
\n
"
,(
crc
>>
i
)
&
1
);
for
(
int
i
=
0
;
i
<
24
;
i
++
)
printf
(
"[i]=%d
\n
"
,(
crc
>>
i
)
&
1
);
printf
(
"crc: [0]->0x%08x
\n
"
,
crc
);
printf
(
"crc: [0]->0x%08x
\n
"
,
crc
);
testInput
[
testLength
>>
3
]
=
((
uint8_t
*
)
&
crc
)[
2
];
//crcbit(testInputCRC, sizeof(test) - 1, poly24c));
testInput
[
1
+
(
testLength
>>
3
)]
=
((
uint8_t
*
)
&
crc
)[
1
];
testInput
[
2
+
(
testLength
>>
3
)]
=
((
uint8_t
*
)
&
crc
)[
0
];
testInputCRC
[
testLength
>>
3
]
=
((
uint8_t
*
)
&
crc
)[
2
];
printf
(
"testInput: [0]->0x%08x
\t
[1]->0x%08x
\t
[2]->0x%08x
\t
[3]->0x%08x
\n
"
,
testInputCRC
[
1
+
(
testLength
>>
3
)]
=
((
uint8_t
*
)
&
crc
)[
1
];
testInput
[
0
],
testInput
[
1
],
testInput
[
2
],
testInput
[
3
]);
testInputCRC
[
2
+
(
testLength
>>
3
)]
=
((
uint8_t
*
)
&
crc
)[
0
];
printf
(
"testInputCRC: [0]->0x%08x
\t
[1]->0x%08x
\t
[2]->0x%08x
\t
[3]->0x%08x
\n
"
,
testInputCRC
[
0
],
testInputCRC
[
1
],
testInputCRC
[
2
],
testInputCRC
[
3
]);
//uint32_t trial32 = 0xffffffff;
uint32_t
trial32
=
0xf10fffff
;
uint8_t
a
[
4
];
//memcpy(a, &trial32, sizeof(trial32));
*
(
uint32_t
*
)
a
=
trial32
;
unsigned
char
trial
[
4
];
trial
[
0
]
=
0xff
;
trial
[
1
]
=
0xff
;
trial
[
2
]
=
0x0f
;
trial
[
3
]
=
0xf1
;
uint32_t
trialcrc
=
crc24c
(
trial
,
32
);
uint32_t
trialcrc32
=
crc24c
((
uint8_t
*
)
&
trial32
,
32
);
//uint32_t trialcrc32 = crc24c(a, 32);
printf
(
"crcbit(trial = %x
\n
"
,
crcbit
(
trial
,
4
,
poly24c
));
printf
(
"trialcrc = %x
\n
"
,
trialcrc
);
printf
(
"trialcrc32 = %x
\n
"
,
trialcrc32
);
for
(
int
i
=
0
;
i
<
32
;
i
++
)
printf
(
"trialcrc[%2d]=%d
\t
trialcrc32[%2d]=%d
\n
"
,
i
,(
trialcrc
>>
i
)
&
1
,
i
,(
trialcrc32
>>
i
)
&
1
);
//uint8_t nr_polar_A[32] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
uint8_t
nr_polar_A
[
32
]
=
{
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
0
,
0
,
0
,
0
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
0
,
0
,
0
,
1
};
uint8_t
nr_polar_crc
[
24
];
uint8_t
**
crc_generator_matrix
=
crc24c_generator_matrix
(
32
);
nr_matrix_multiplication_uint8_t_1D_uint8_t_2D
(
nr_polar_A
,
crc_generator_matrix
,
nr_polar_crc
,
32
,
24
);
for
(
uint8_t
i
=
0
;
i
<
24
;
i
++
){
nr_polar_crc
[
i
]
=
(
nr_polar_crc
[
i
]
%
2
);
printf
(
"nr_polar_crc[%d]=%d
\n
"
,
i
,
nr_polar_crc
[
i
]);
}
return
0
;
#endif
#endif
#ifdef DEBUG_POLAR_TIMING
#ifdef DEBUG_POLAR_TIMING
...
@@ -207,8 +300,8 @@ int main(int argc, char *argv[]) {
...
@@ -207,8 +300,8 @@ int main(int argc, char *argv[]) {
stop_meas
(
&
timeEncoder
);
stop_meas
(
&
timeEncoder
);
/*printf("encoderOutput: [0]->0x%08x\n", encoderOutput[0]);
/*printf("encoderOutput: [0]->0x%08x\n", encoderOutput[0]);
printf("encoderOutput: [1]->0x%08x\n", encoderOutput[1]);
printf("encoderOutput: [1]->0x%08x\n", encoderOutput[1]);
*/
*/
//Bit-to-byte:
//Bit-to-byte:
nr_bit2byte_uint32_8_t
(
encoderOutput
,
coderLength
,
encoderOutputByte
);
nr_bit2byte_uint32_8_t
(
encoderOutput
,
coderLength
,
encoderOutputByte
);
...
@@ -237,8 +330,8 @@ int main(int argc, char *argv[]) {
...
@@ -237,8 +330,8 @@ int main(int argc, char *argv[]) {
aPrioriArray
);
aPrioriArray
);
stop_meas
(
&
timeDecoder
);
stop_meas
(
&
timeDecoder
);
/*printf("testInput: [0]->0x%08x\n", testInput[0]);
/*printf("testInput: [0]->0x%08x\n", testInput[0]);
printf("estimatedOutput: [0]->0x%08x\n", estimatedOutput[0]);
printf("estimatedOutput: [0]->0x%08x\n", estimatedOutput[0]);
*/
*/
//calculate errors
//calculate errors
if
(
decoderState
==-
1
)
{
if
(
decoderState
==-
1
)
{
...
...
openair1/PHY/CODING/nrPolar_tools/nr_bitwise_operations.c
View file @
34deaae4
...
@@ -23,11 +23,13 @@
...
@@ -23,11 +23,13 @@
void
nr_bit2byte_uint32_8_t
(
uint32_t
*
in
,
uint16_t
arraySize
,
uint8_t
*
out
)
{
void
nr_bit2byte_uint32_8_t
(
uint32_t
*
in
,
uint16_t
arraySize
,
uint8_t
*
out
)
{
uint8_t
arrayInd
=
ceil
(
arraySize
/
32
.
0
);
uint8_t
arrayInd
=
ceil
(
arraySize
/
32
.
0
);
for
(
int
i
=
0
;
i
<
arrayInd
;
i
++
)
{
for
(
int
i
=
0
;
i
<
(
arrayInd
-
1
)
;
i
++
)
{
for
(
int
j
=
0
;
j
<
32
;
j
++
)
{
for
(
int
j
=
0
;
j
<
32
;
j
++
)
{
out
[
j
+
(
i
*
32
)]
=
(
in
[
i
]
>>
j
)
&
1
;
out
[
j
+
(
i
*
32
)]
=
(
in
[
i
]
>>
j
)
&
1
;
}
}
}
}
for
(
int
j
=
0
;
j
<
arraySize
-
((
arrayInd
-
1
)
*
32
);
j
++
)
out
[
j
+
((
arrayInd
-
1
)
*
32
)]
=
(
in
[(
arrayInd
-
1
)]
>>
j
)
&
1
;
}
}
void
nr_byte2bit_uint8_32_t
(
uint8_t
*
in
,
uint16_t
arraySize
,
uint32_t
*
out
)
{
void
nr_byte2bit_uint8_32_t
(
uint8_t
*
in
,
uint16_t
arraySize
,
uint32_t
*
out
)
{
...
...
openair1/PHY/CODING/nrPolar_tools/nr_polar_decoder.c
View file @
34deaae4
...
@@ -785,3 +785,252 @@ int8_t polar_decoder_aPriori_timing(double *input,
...
@@ -785,3 +785,252 @@ int8_t polar_decoder_aPriori_timing(double *input,
nr_byte2bit_uint8_32_t
(
polarParams
->
nr_polar_A
,
polarParams
->
payloadBits
,
out
);
nr_byte2bit_uint8_32_t
(
polarParams
->
nr_polar_A
,
polarParams
->
payloadBits
,
out
);
return
(
0
);
return
(
0
);
}
}
int8_t
polar_decoder_dci
(
double
*
input
,
uint32_t
*
out
,
t_nrPolar_paramsPtr
polarParams
,
uint8_t
listSize
,
uint8_t
pathMetricAppr
,
uint16_t
n_RNTI
)
{
uint8_t
***
bit
=
nr_alloc_uint8_t_3D_array
(
polarParams
->
N
,
(
polarParams
->
n
+
1
),
2
*
listSize
);
uint8_t
**
bitUpdated
=
nr_alloc_uint8_t_2D_array
(
polarParams
->
N
,
(
polarParams
->
n
+
1
));
//0=False, 1=True
uint8_t
**
llrUpdated
=
nr_alloc_uint8_t_2D_array
(
polarParams
->
N
,
(
polarParams
->
n
+
1
));
//0=False, 1=True
double
***
llr
=
nr_alloc_double_3D_array
(
polarParams
->
N
,
(
polarParams
->
n
+
1
),
2
*
listSize
);
uint8_t
**
crcChecksum
=
nr_alloc_uint8_t_2D_array
(
polarParams
->
crcParityBits
,
2
*
listSize
);
double
*
pathMetric
=
malloc
(
sizeof
(
double
)
*
(
2
*
listSize
));
uint8_t
*
crcState
=
malloc
(
sizeof
(
uint8_t
)
*
(
2
*
listSize
));
//0=False, 1=True
uint8_t
extended_crc_scrambling_pattern
[
polarParams
->
crcParityBits
];
for
(
int
i
=
0
;
i
<
(
2
*
listSize
);
i
++
)
{
pathMetric
[
i
]
=
0
;
crcState
[
i
]
=
1
;
}
for
(
int
i
=
0
;
i
<
polarParams
->
N
;
i
++
)
{
llrUpdated
[
i
][
polarParams
->
n
]
=
1
;
bitUpdated
[
i
][
0
]
=
((
polarParams
->
information_bit_pattern
[
i
]
+
1
)
%
2
);
}
uint8_t
**
extended_crc_generator_matrix
=
malloc
(
polarParams
->
K
*
sizeof
(
uint8_t
*
));
//G_P3: K-by-P
uint8_t
**
tempECGM
=
malloc
(
polarParams
->
K
*
sizeof
(
uint8_t
*
));
//G_P2: K-by-P
for
(
int
i
=
0
;
i
<
polarParams
->
K
;
i
++
){
extended_crc_generator_matrix
[
i
]
=
malloc
(
polarParams
->
crcParityBits
*
sizeof
(
uint8_t
));
tempECGM
[
i
]
=
malloc
(
polarParams
->
crcParityBits
*
sizeof
(
uint8_t
));
}
for
(
int
i
=
0
;
i
<
polarParams
->
payloadBits
;
i
++
)
{
for
(
int
j
=
0
;
j
<
polarParams
->
crcParityBits
;
j
++
)
{
tempECGM
[
i
][
j
]
=
polarParams
->
crc_generator_matrix
[
i
+
polarParams
->
crcParityBits
][
j
];
}
}
for
(
int
i
=
polarParams
->
payloadBits
;
i
<
polarParams
->
K
;
i
++
)
{
for
(
int
j
=
0
;
j
<
polarParams
->
crcParityBits
;
j
++
)
{
if
(
(
i
-
polarParams
->
payloadBits
)
==
j
){
tempECGM
[
i
][
j
]
=
1
;
}
else
{
tempECGM
[
i
][
j
]
=
0
;
}
}
}
for
(
int
i
=
0
;
i
<
polarParams
->
K
;
i
++
)
{
for
(
int
j
=
0
;
j
<
polarParams
->
crcParityBits
;
j
++
)
{
extended_crc_generator_matrix
[
i
][
j
]
=
tempECGM
[
polarParams
->
interleaving_pattern
[
i
]][
j
];
}
}
//The index of the last 1-valued bit that appears in each column.
uint16_t
last1ind
[
polarParams
->
crcParityBits
];
for
(
int
j
=
0
;
j
<
polarParams
->
crcParityBits
;
j
++
)
{
for
(
int
i
=
0
;
i
<
polarParams
->
K
;
i
++
)
{
if
(
extended_crc_generator_matrix
[
i
][
j
]
==
1
)
last1ind
[
j
]
=
i
;
}
}
for
(
int
i
=
0
;
i
<
8
;
i
++
)
extended_crc_scrambling_pattern
[
i
]
=
0
;
for
(
int
i
=
8
;
i
<
polarParams
->
crcParityBits
;
i
++
)
{
extended_crc_scrambling_pattern
[
i
]
=
(
n_RNTI
>>
(
23
-
i
))
&
1
;
}
double
*
d_tilde
=
malloc
(
sizeof
(
double
)
*
polarParams
->
N
);
nr_polar_rate_matching
(
input
,
d_tilde
,
polarParams
->
rate_matching_pattern
,
polarParams
->
K
,
polarParams
->
N
,
polarParams
->
encoderLength
);
for
(
int
j
=
0
;
j
<
polarParams
->
N
;
j
++
)
llr
[
j
][
polarParams
->
n
][
0
]
=
d_tilde
[
j
];
/*
* SCL polar decoder.
*/
for
(
int
i
=
0
;
i
<
polarParams
->
crcParityBits
;
i
++
)
{
for
(
int
j
=
0
;
j
<
polarParams
->
crcParityBits
;
j
++
)
crcChecksum
[
i
][
0
]
=
crcChecksum
[
i
][
0
]
+
polarParams
->
crc_generator_matrix
[
j
][
i
];
crcChecksum
[
i
][
0
]
=
(
crcChecksum
[
i
][
0
]
%
2
);
}
uint32_t
nonFrozenBit
=
0
;
uint8_t
currentListSize
=
1
;
uint8_t
decoderIterationCheck
=
0
;
int16_t
checkCrcBits
=-
1
;
uint8_t
listIndex
[
2
*
listSize
],
copyIndex
;
for
(
uint16_t
currentBit
=
0
;
currentBit
<
polarParams
->
N
;
currentBit
++
){
updateLLR
(
llr
,
llrUpdated
,
bit
,
bitUpdated
,
currentListSize
,
currentBit
,
0
,
polarParams
->
N
,
(
polarParams
->
n
+
1
),
pathMetricAppr
);
if
(
polarParams
->
information_bit_pattern
[
currentBit
]
==
0
)
{
//Frozen bit.
updatePathMetric
(
pathMetric
,
llr
,
currentListSize
,
0
,
currentBit
,
pathMetricAppr
);
//approximation=0 --> 11b, approximation=1 --> 12
}
else
{
//Information or CRC bit.
updatePathMetric2
(
pathMetric
,
llr
,
currentListSize
,
currentBit
,
pathMetricAppr
);
for
(
int
i
=
0
;
i
<
currentListSize
;
i
++
)
{
for
(
int
j
=
0
;
j
<
polarParams
->
N
;
j
++
)
{
for
(
int
k
=
0
;
k
<
(
polarParams
->
n
+
1
);
k
++
)
{
bit
[
j
][
k
][
i
+
currentListSize
]
=
bit
[
j
][
k
][
i
];
llr
[
j
][
k
][
i
+
currentListSize
]
=
llr
[
j
][
k
][
i
];}}}
for
(
int
i
=
0
;
i
<
currentListSize
;
i
++
)
{
bit
[
currentBit
][
0
][
i
]
=
0
;
crcState
[
i
+
currentListSize
]
=
crcState
[
i
];
}
for
(
int
i
=
currentListSize
;
i
<
2
*
currentListSize
;
i
++
)
bit
[
currentBit
][
0
][
i
]
=
1
;
bitUpdated
[
currentBit
][
0
]
=
1
;
updateCrcChecksum2
(
crcChecksum
,
extended_crc_generator_matrix
,
currentListSize
,
nonFrozenBit
,
polarParams
->
crcParityBits
);
currentListSize
*=
2
;
//Keep only the best "listSize" number of entries.
if
(
currentListSize
>
listSize
)
{
for
(
uint8_t
i
=
0
;
i
<
2
*
listSize
;
i
++
)
listIndex
[
i
]
=
i
;
nr_sort_asc_double_1D_array_ind
(
pathMetric
,
listIndex
,
currentListSize
);
//sort listIndex[listSize, ..., 2*listSize-1] in descending order.
uint8_t
swaps
,
tempInd
;
for
(
uint8_t
i
=
0
;
i
<
listSize
;
i
++
)
{
swaps
=
0
;
for
(
uint8_t
j
=
listSize
;
j
<
(
2
*
listSize
-
i
)
-
1
;
j
++
)
{
if
(
listIndex
[
j
+
1
]
>
listIndex
[
j
])
{
tempInd
=
listIndex
[
j
];
listIndex
[
j
]
=
listIndex
[
j
+
1
];
listIndex
[
j
+
1
]
=
tempInd
;
swaps
++
;
}
}
if
(
swaps
==
0
)
break
;
}
//First, backup the best "listSize" number of entries.
for
(
int
k
=
(
listSize
-
1
);
k
>
0
;
k
--
)
{
for
(
int
i
=
0
;
i
<
polarParams
->
N
;
i
++
)
{
for
(
int
j
=
0
;
j
<
(
polarParams
->
n
+
1
);
j
++
)
{
bit
[
i
][
j
][
listIndex
[(
2
*
listSize
-
1
)
-
k
]]
=
bit
[
i
][
j
][
listIndex
[
k
]];
llr
[
i
][
j
][
listIndex
[(
2
*
listSize
-
1
)
-
k
]]
=
llr
[
i
][
j
][
listIndex
[
k
]];
}
}
}
for
(
int
k
=
(
listSize
-
1
);
k
>
0
;
k
--
)
{
for
(
int
i
=
0
;
i
<
polarParams
->
crcParityBits
;
i
++
)
{
crcChecksum
[
i
][
listIndex
[(
2
*
listSize
-
1
)
-
k
]]
=
crcChecksum
[
i
][
listIndex
[
k
]];
}
}
for
(
int
k
=
(
listSize
-
1
);
k
>
0
;
k
--
)
crcState
[
listIndex
[(
2
*
listSize
-
1
)
-
k
]]
=
crcState
[
listIndex
[
k
]];
//Copy the best "listSize" number of entries to the first indices.
for
(
int
k
=
0
;
k
<
listSize
;
k
++
)
{
if
(
k
>
listIndex
[
k
])
{
copyIndex
=
listIndex
[(
2
*
listSize
-
1
)
-
k
];
}
else
{
//Use the backup.
copyIndex
=
listIndex
[
k
];
}
for
(
int
i
=
0
;
i
<
polarParams
->
N
;
i
++
)
{
for
(
int
j
=
0
;
j
<
(
polarParams
->
n
+
1
);
j
++
)
{
bit
[
i
][
j
][
k
]
=
bit
[
i
][
j
][
copyIndex
];
llr
[
i
][
j
][
k
]
=
llr
[
i
][
j
][
copyIndex
];
}
}
}
for
(
int
k
=
0
;
k
<
listSize
;
k
++
)
{
if
(
k
>
listIndex
[
k
])
{
copyIndex
=
listIndex
[(
2
*
listSize
-
1
)
-
k
];
}
else
{
//Use the backup.
copyIndex
=
listIndex
[
k
];
}
for
(
int
i
=
0
;
i
<
polarParams
->
crcParityBits
;
i
++
)
{
crcChecksum
[
i
][
k
]
=
crcChecksum
[
i
][
copyIndex
];
}
}
for
(
int
k
=
0
;
k
<
listSize
;
k
++
)
{
if
(
k
>
listIndex
[
k
])
{
copyIndex
=
listIndex
[(
2
*
listSize
-
1
)
-
k
];
}
else
{
//Use the backup.
copyIndex
=
listIndex
[
k
];
}
crcState
[
k
]
=
crcState
[
copyIndex
];
}
currentListSize
=
listSize
;
}
for
(
int
i
=
0
;
i
<
polarParams
->
crcParityBits
;
i
++
)
{
if
(
last1ind
[
i
]
==
nonFrozenBit
)
{
checkCrcBits
=
i
;
break
;
}
}
if
(
checkCrcBits
>
(
-
1
)
)
{
for
(
uint8_t
i
=
0
;
i
<
currentListSize
;
i
++
)
{
if
(
crcChecksum
[
checkCrcBits
][
i
]
!=
extended_crc_scrambling_pattern
[
checkCrcBits
])
{
crcState
[
i
]
=
0
;
//0=False, 1=True
}
}
}
for
(
uint8_t
i
=
0
;
i
<
currentListSize
;
i
++
)
decoderIterationCheck
+=
crcState
[
i
];
if
(
decoderIterationCheck
==
0
)
{
//perror("[SCL polar decoder] All list entries have failed the CRC checks.");
free
(
d_tilde
);
free
(
pathMetric
);
free
(
crcState
);
nr_free_uint8_t_3D_array
(
bit
,
polarParams
->
N
,
(
polarParams
->
n
+
1
));
nr_free_double_3D_array
(
llr
,
polarParams
->
N
,
(
polarParams
->
n
+
1
));
nr_free_uint8_t_2D_array
(
crcChecksum
,
polarParams
->
crcParityBits
);
return
(
-
1
);
}
nonFrozenBit
++
;
decoderIterationCheck
=
0
;
checkCrcBits
=-
1
;
}
}
for
(
uint8_t
i
=
0
;
i
<
2
*
listSize
;
i
++
)
listIndex
[
i
]
=
i
;
nr_sort_asc_double_1D_array_ind
(
pathMetric
,
listIndex
,
currentListSize
);
for
(
uint8_t
i
=
0
;
i
<
fmin
(
listSize
,
(
pow
(
2
,
polarParams
->
crcCorrectionBits
))
);
i
++
)
{
if
(
crcState
[
listIndex
[
i
]]
==
1
)
{
for
(
int
j
=
0
;
j
<
polarParams
->
N
;
j
++
)
polarParams
->
nr_polar_U
[
j
]
=
bit
[
j
][
0
][
listIndex
[
i
]];
//Extract the information bits (û to ĉ)
nr_polar_info_bit_extraction
(
polarParams
->
nr_polar_U
,
polarParams
->
nr_polar_CPrime
,
polarParams
->
information_bit_pattern
,
polarParams
->
N
);
//Deinterleaving (ĉ to b)
nr_polar_deinterleaver
(
polarParams
->
nr_polar_CPrime
,
polarParams
->
nr_polar_B
,
polarParams
->
interleaving_pattern
,
polarParams
->
K
);
//Remove the CRC (â)
for
(
int
j
=
0
;
j
<
polarParams
->
payloadBits
;
j
++
)
polarParams
->
nr_polar_A
[
j
]
=
polarParams
->
nr_polar_B
[
j
];
break
;
}
}
free
(
d_tilde
);
free
(
pathMetric
);
free
(
crcState
);
nr_free_uint8_t_3D_array
(
bit
,
polarParams
->
N
,
(
polarParams
->
n
+
1
));
nr_free_double_3D_array
(
llr
,
polarParams
->
N
,
(
polarParams
->
n
+
1
));
nr_free_uint8_t_2D_array
(
crcChecksum
,
polarParams
->
crcParityBits
);
nr_free_uint8_t_2D_array
(
extended_crc_generator_matrix
,
polarParams
->
K
);
nr_free_uint8_t_2D_array
(
tempECGM
,
polarParams
->
K
);
/*
* Return bits.
*/
nr_byte2bit_uint8_32_t
(
polarParams
->
nr_polar_A
,
polarParams
->
payloadBits
,
out
);
return
(
0
);
}
openair1/PHY/CODING/nrPolar_tools/nr_polar_defs.h
View file @
34deaae4
...
@@ -43,7 +43,7 @@
...
@@ -43,7 +43,7 @@
#include "PHY/CODING/nrPolar_tools/nr_polar_uci_defs.h"
#include "PHY/CODING/nrPolar_tools/nr_polar_uci_defs.h"
#include "PHY/CODING/nrPolar_tools/nr_polar_pbch_defs.h"
#include "PHY/CODING/nrPolar_tools/nr_polar_pbch_defs.h"
#include "PHY/CODING/coding_defs.h"
#include "PHY/CODING/coding_defs.h"
//
#include "SIMULATION/TOOLS/sim.h"
#include "SIMULATION/TOOLS/sim.h"
#define NR_POLAR_DECODER_LISTSIZE 8 //uint8_t
#define NR_POLAR_DECODER_LISTSIZE 8 //uint8_t
#define NR_POLAR_DECODER_PATH_METRIC_APPROXIMATION 0 //uint8_t; 0 --> eq. (8a) and (11b), 1 --> eq. (9) and (12)
#define NR_POLAR_DECODER_PATH_METRIC_APPROXIMATION 0 //uint8_t; 0 --> eq. (8a) and (11b), 1 --> eq. (9) and (12)
...
@@ -92,6 +92,7 @@ struct nrPolar_params {
...
@@ -92,6 +92,7 @@ struct nrPolar_params {
//polar_encoder vectors
//polar_encoder vectors
uint8_t
*
nr_polar_crc
;
uint8_t
*
nr_polar_crc
;
uint8_t
*
nr_polar_aPrime
;
uint8_t
*
nr_polar_aPrime
;
uint8_t
*
nr_polar_APrime
;
uint8_t
*
nr_polar_D
;
uint8_t
*
nr_polar_D
;
uint8_t
*
nr_polar_E
;
uint8_t
*
nr_polar_E
;
...
@@ -141,6 +142,13 @@ int8_t polar_decoder_aPriori_timing(double *input,
...
@@ -141,6 +142,13 @@ int8_t polar_decoder_aPriori_timing(double *input,
double
cpuFreqGHz
,
double
cpuFreqGHz
,
FILE
*
logFile
);
FILE
*
logFile
);
int8_t
polar_decoder_dci
(
double
*
input
,
uint32_t
*
out
,
t_nrPolar_paramsPtr
polarParams
,
uint8_t
listSize
,
uint8_t
pathMetricAppr
,
uint16_t
n_RNTI
);
void
nr_polar_init
(
t_nrPolar_paramsPtr
*
polarParams
,
void
nr_polar_init
(
t_nrPolar_paramsPtr
*
polarParams
,
int8_t
messageType
,
int8_t
messageType
,
uint16_t
messageLength
,
uint16_t
messageLength
,
...
...
openair1/PHY/CODING/nrPolar_tools/nr_polar_encoder.c
View file @
34deaae4
...
@@ -115,19 +115,64 @@ void polar_encoder_dci(uint32_t *in,
...
@@ -115,19 +115,64 @@ void polar_encoder_dci(uint32_t *in,
#ifdef DEBUG_POLAR_ENCODER_DCI
#ifdef DEBUG_POLAR_ENCODER_DCI
printf
(
"[polar_encoder_dci] in: [0]->0x%08x
\t
[1]->0x%08x
\t
[2]->0x%08x
\t
[3]->0x%08x
\n
"
,
in
[
0
],
in
[
1
],
in
[
2
],
in
[
3
]);
printf
(
"[polar_encoder_dci] in: [0]->0x%08x
\t
[1]->0x%08x
\t
[2]->0x%08x
\t
[3]->0x%08x
\n
"
,
in
[
0
],
in
[
1
],
in
[
2
],
in
[
3
]);
#endif
#endif
/*
* Bytewise operations
*/
//(a to a')
//(a to a')
nr_bit2byte_uint32_8_t
(
in
,
polarParams
->
payloadBits
,
polarParams
->
nr_polar_A
);
for
(
int
i
=
0
;
i
<
polarParams
->
crcParityBits
;
i
++
)
polarParams
->
nr_polar_APrime
[
i
]
=
1
;
for
(
int
i
=
0
;
i
<
polarParams
->
payloadBits
;
i
++
)
polarParams
->
nr_polar_APrime
[
i
+
(
polarParams
->
crcParityBits
)]
=
polarParams
->
nr_polar_A
[
i
];
#ifdef DEBUG_POLAR_ENCODER_DCI
printf
(
"[polar_encoder_dci] A: "
);
for
(
int
i
=
0
;
i
<
polarParams
->
payloadBits
;
i
++
)
printf
(
"%d-"
,
polarParams
->
nr_polar_A
[
i
]);
printf
(
"
\n
"
);
printf
(
"[polar_encoder_dci] APrime: "
);
for
(
int
i
=
0
;
i
<
polarParams
->
K
;
i
++
)
printf
(
"%d-"
,
polarParams
->
nr_polar_APrime
[
i
]);
printf
(
"
\n
"
);
printf
(
"[polar_encoder_dci] GP: "
);
for
(
int
i
=
0
;
i
<
polarParams
->
crcParityBits
;
i
++
)
printf
(
"%d-"
,
polarParams
->
crc_generator_matrix
[
0
][
i
]);
printf
(
"
\n
"
);
#endif
//Calculate CRC.
nr_matrix_multiplication_uint8_t_1D_uint8_t_2D
(
polarParams
->
nr_polar_APrime
,
polarParams
->
crc_generator_matrix
,
polarParams
->
nr_polar_crc
,
polarParams
->
K
,
polarParams
->
crcParityBits
);
for
(
uint8_t
i
=
0
;
i
<
polarParams
->
crcParityBits
;
i
++
)
polarParams
->
nr_polar_crc
[
i
]
=
(
polarParams
->
nr_polar_crc
[
i
]
%
2
);
#ifdef DEBUG_POLAR_ENCODER_DCI
printf
(
"[polar_encoder_dci] CRC: "
);
for
(
int
i
=
0
;
i
<
polarParams
->
crcParityBits
;
i
++
)
printf
(
"%d-"
,
polarParams
->
nr_polar_crc
[
i
]);
printf
(
"
\n
"
);
#endif
//Attach CRC to the Transport Block. (a to b)
for
(
uint16_t
i
=
0
;
i
<
polarParams
->
payloadBits
;
i
++
)
polarParams
->
nr_polar_B
[
i
]
=
polarParams
->
nr_polar_A
[
i
];
for
(
uint16_t
i
=
polarParams
->
payloadBits
;
i
<
polarParams
->
K
;
i
++
)
polarParams
->
nr_polar_B
[
i
]
=
polarParams
->
nr_polar_crc
[
i
-
(
polarParams
->
payloadBits
)];
//Scrambling (b to c)
for
(
int
i
=
0
;
i
<
16
;
i
++
)
{
polarParams
->
nr_polar_B
[
polarParams
->
payloadBits
+
8
+
i
]
=
(
polarParams
->
nr_polar_B
[
polarParams
->
payloadBits
+
8
+
i
]
+
((
n_RNTI
>>
(
15
-
i
))
&
1
)
)
%
2
;
}
/* //(a to a')
nr_crc_bit2bit_uint32_8_t(in, polarParams->payloadBits, polarParams->nr_polar_aPrime);
nr_crc_bit2bit_uint32_8_t(in, polarParams->payloadBits, polarParams->nr_polar_aPrime);
//Parity bits computation (p)
//Parity bits computation (p)
polarParams
->
crcBit
=
crc24c
(
polarParams
->
nr_polar_aPrime
,
polarParams->crcBit = crc24c(polarParams->nr_polar_aPrime, (polarParams->payloadBits+polarParams->crcParityBits));
(
polarParams
->
payloadBits
+
polarParams
->
crcParityBits
));
#ifdef DEBUG_POLAR_ENCODER_DCI
#ifdef DEBUG_POLAR_ENCODER_DCI
printf("[polar_encoder_dci] crc: 0x%08x\n", polarParams->crcBit);
printf("[polar_encoder_dci] crc: 0x%08x\n", polarParams->crcBit);
for (int i=0; i<32; i++)
{
printf("%d\n",((polarParams->crcBit)>>i)&1);
}
#endif
#endif
//(a to b)
//(a to b)
/
*
/
/
*
Bytewise operations
//
Bytewise operations
*
/
/
/
uint8_t arrayInd = ceil(polarParams->payloadBits / 8.0);
uint8_t arrayInd = ceil(polarParams->payloadBits / 8.0);
for (int i=0; i<arrayInd-1; i++){
for (int i=0; i<arrayInd-1; i++){
for (int j=0; j<8; j++) {
for (int j=0; j<8; j++) {
...
@@ -144,7 +189,7 @@ void polar_encoder_dci(uint32_t *in,
...
@@ -144,7 +189,7 @@ void polar_encoder_dci(uint32_t *in,
for (int i=0; i<16; i++) {
for (int i=0; i<16; i++) {
polarParams->nr_polar_B[polarParams->payloadBits+8+i] =
polarParams->nr_polar_B[polarParams->payloadBits+8+i] =
( (((polarParams->crcBit)>>(23-i))&1) + ((n_RNTI>>(15-i))&1) ) % 2;
( (((polarParams->crcBit)>>(23-i))&1) + ((n_RNTI>>(15-i))&1) ) % 2;
}
}
*/
#ifdef DEBUG_POLAR_ENCODER_DCI
#ifdef DEBUG_POLAR_ENCODER_DCI
printf
(
"[polar_encoder_dci] B: "
);
printf
(
"[polar_encoder_dci] B: "
);
for
(
int
i
=
0
;
i
<
polarParams
->
K
;
i
++
)
printf
(
"%d-"
,
polarParams
->
nr_polar_B
[
i
]);
for
(
int
i
=
0
;
i
<
polarParams
->
K
;
i
++
)
printf
(
"%d-"
,
polarParams
->
nr_polar_B
[
i
]);
...
...
openair1/PHY/CODING/nr_polar_init.c
View file @
34deaae4
...
@@ -69,6 +69,7 @@ void nr_polar_init(t_nrPolar_paramsPtr *polarParams,
...
@@ -69,6 +69,7 @@ void nr_polar_init(t_nrPolar_paramsPtr *polarParams,
newPolarInitNode
->
payloadBits
=
NR_POLAR_PBCH_PAYLOAD_BITS
;
newPolarInitNode
->
payloadBits
=
NR_POLAR_PBCH_PAYLOAD_BITS
;
newPolarInitNode
->
encoderLength
=
NR_POLAR_PBCH_E
;
newPolarInitNode
->
encoderLength
=
NR_POLAR_PBCH_E
;
newPolarInitNode
->
crcCorrectionBits
=
NR_POLAR_PBCH_CRC_ERROR_CORRECTION_BITS
;
newPolarInitNode
->
crcCorrectionBits
=
NR_POLAR_PBCH_CRC_ERROR_CORRECTION_BITS
;
newPolarInitNode
->
crc_generator_matrix
=
crc24c_generator_matrix
(
newPolarInitNode
->
payloadBits
);
//G_P
}
else
if
(
messageType
==
1
)
{
//DCI
}
else
if
(
messageType
==
1
)
{
//DCI
newPolarInitNode
->
n_max
=
NR_POLAR_DCI_N_MAX
;
newPolarInitNode
->
n_max
=
NR_POLAR_DCI_N_MAX
;
newPolarInitNode
->
i_il
=
NR_POLAR_DCI_I_IL
;
newPolarInitNode
->
i_il
=
NR_POLAR_DCI_I_IL
;
...
@@ -80,6 +81,7 @@ void nr_polar_init(t_nrPolar_paramsPtr *polarParams,
...
@@ -80,6 +81,7 @@ void nr_polar_init(t_nrPolar_paramsPtr *polarParams,
newPolarInitNode
->
payloadBits
=
messageLength
;
newPolarInitNode
->
payloadBits
=
messageLength
;
newPolarInitNode
->
encoderLength
=
aggregation_level
*
108
;
newPolarInitNode
->
encoderLength
=
aggregation_level
*
108
;
newPolarInitNode
->
crcCorrectionBits
=
NR_POLAR_DCI_CRC_ERROR_CORRECTION_BITS
;
newPolarInitNode
->
crcCorrectionBits
=
NR_POLAR_DCI_CRC_ERROR_CORRECTION_BITS
;
newPolarInitNode
->
crc_generator_matrix
=
crc24c_generator_matrix
(
newPolarInitNode
->
payloadBits
+
newPolarInitNode
->
crcParityBits
);
//G_P
}
else
if
(
messageType
==
-
1
)
{
//UCI
}
else
if
(
messageType
==
-
1
)
{
//UCI
}
else
{
}
else
{
...
@@ -89,13 +91,12 @@ void nr_polar_init(t_nrPolar_paramsPtr *polarParams,
...
@@ -89,13 +91,12 @@ void nr_polar_init(t_nrPolar_paramsPtr *polarParams,
newPolarInitNode
->
K
=
newPolarInitNode
->
payloadBits
+
newPolarInitNode
->
crcParityBits
;
// Number of bits to encode.
newPolarInitNode
->
K
=
newPolarInitNode
->
payloadBits
+
newPolarInitNode
->
crcParityBits
;
// Number of bits to encode.
newPolarInitNode
->
N
=
nr_polar_output_length
(
newPolarInitNode
->
K
,
newPolarInitNode
->
encoderLength
,
newPolarInitNode
->
n_max
);
newPolarInitNode
->
N
=
nr_polar_output_length
(
newPolarInitNode
->
K
,
newPolarInitNode
->
encoderLength
,
newPolarInitNode
->
n_max
);
newPolarInitNode
->
n
=
log2
(
newPolarInitNode
->
N
);
newPolarInitNode
->
n
=
log2
(
newPolarInitNode
->
N
);
newPolarInitNode
->
crc_generator_matrix
=
crc24c_generator_matrix
(
newPolarInitNode
->
payloadBits
);
newPolarInitNode
->
G_N
=
nr_polar_kronecker_power_matrices
(
newPolarInitNode
->
n
);
newPolarInitNode
->
G_N
=
nr_polar_kronecker_power_matrices
(
newPolarInitNode
->
n
);
//polar_encoder vectors:
//polar_encoder vectors:
newPolarInitNode
->
nr_polar_crc
=
malloc
(
sizeof
(
uint8_t
)
*
newPolarInitNode
->
crcParityBits
);
newPolarInitNode
->
nr_polar_crc
=
malloc
(
sizeof
(
uint8_t
)
*
newPolarInitNode
->
crcParityBits
);
newPolarInitNode
->
nr_polar_aPrime
=
malloc
(
sizeof
(
uint8_t
)
*
((
ceil
((
newPolarInitNode
->
payloadBits
)
/
32
.
0
)
*
4
)
+
3
));
newPolarInitNode
->
nr_polar_aPrime
=
malloc
(
sizeof
(
uint8_t
)
*
((
ceil
((
newPolarInitNode
->
payloadBits
)
/
32
.
0
)
*
4
)
+
3
));
newPolarInitNode
->
nr_polar_APrime
=
malloc
(
sizeof
(
uint8_t
)
*
newPolarInitNode
->
K
);
newPolarInitNode
->
nr_polar_D
=
malloc
(
sizeof
(
uint8_t
)
*
newPolarInitNode
->
N
);
newPolarInitNode
->
nr_polar_D
=
malloc
(
sizeof
(
uint8_t
)
*
newPolarInitNode
->
N
);
newPolarInitNode
->
nr_polar_E
=
malloc
(
sizeof
(
uint8_t
)
*
newPolarInitNode
->
encoderLength
);
newPolarInitNode
->
nr_polar_E
=
malloc
(
sizeof
(
uint8_t
)
*
newPolarInitNode
->
encoderLength
);
...
...
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