bptc: simplified
parent
1f073cf902
commit
b7c07ac7b3
@ -1,296 +1,72 @@
|
|||||||
// Package bptc implements the BPTC(196, 96) Block Product Turbo Code
|
|
||||||
package bptc
|
package bptc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/pd0mz/go-dmr/bit"
|
"github.com/pd0mz/go-dmr/bit"
|
||||||
|
"github.com/pd0mz/go-dmr/fec"
|
||||||
)
|
)
|
||||||
|
|
||||||
type vector [4]bit.Bit
|
func Process(info bit.Bits, payload []byte) error {
|
||||||
|
if len(info) < 196 {
|
||||||
// hamming(15, 11, 3) checking of a matrix row (15 total bits, 11 data bits,
|
return fmt.Errorf("bptc: info size %d too small, need at least 196 bits", len(info))
|
||||||
// min. distance: 3) See page 135 of the DMR Air Interface protocol
|
|
||||||
// specification for the generator matrix. A generator matrix looks like this:
|
|
||||||
// G = [Ik | P]. The parity check matrix is: H = [-P^T|In-k] In binary codes,
|
|
||||||
// then -P = P, so the negation is unnecessary. We can get the parity check
|
|
||||||
// matrix only by transposing the generator matrix. We then take a data row,
|
|
||||||
// and multiply it with each row of the parity check matrix, then xor each
|
|
||||||
// resulting row bits together with the corresponding parity check bit. The xor
|
|
||||||
// result (error vector) should be 0, if it's not, it can be used to determine
|
|
||||||
// the location of the erroneous bit using the generator matrix (P).
|
|
||||||
func hamming_15_11_3_parity(data bit.Bits, errorVector *vector) {
|
|
||||||
if data == nil || len(data) < 11 || errorVector == nil {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
if len(payload) < 12 {
|
||||||
var e = *errorVector
|
return fmt.Errorf("bptc: payload size %d too small, need at least 12 bytes", len(payload))
|
||||||
e[0] = (data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[5] ^ data[7] ^ data[8])
|
|
||||||
e[1] = (data[1] ^ data[2] ^ data[3] ^ data[4] ^ data[6] ^ data[8] ^ data[9])
|
|
||||||
e[2] = (data[2] ^ data[3] ^ data[4] ^ data[5] ^ data[7] ^ data[9] ^ data[10])
|
|
||||||
e[3] = (data[0] ^ data[1] ^ data[2] ^ data[4] ^ data[6] ^ data[7] ^ data[10])
|
|
||||||
}
|
|
||||||
|
|
||||||
func hamming_15_11_3_check(data bit.Bits, errorVector *vector) bool {
|
|
||||||
if data == nil || len(data) < 15 || errorVector == nil {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hamming_15_11_3_parity(data, errorVector)
|
var (
|
||||||
|
i, j, k uint32
|
||||||
var e = *errorVector
|
datafr = make(bit.Bits, 196)
|
||||||
e[0] ^= data[11]
|
extracted = make(bit.Bits, 96)
|
||||||
e[1] ^= data[12]
|
)
|
||||||
e[2] ^= data[13]
|
|
||||||
e[3] ^= data[14]
|
|
||||||
|
|
||||||
return e[0] == 0 && e[1] == 0 && e[2] == 0 && e[3] == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func hamming_13_9_3_parity(data bit.Bits, errorVector *vector) {
|
// Deinterleave bits
|
||||||
if data == nil || len(data) < 9 || errorVector == nil {
|
for i = 1; i < 197; i++ {
|
||||||
return
|
datafr[i-1] = info[((i * 181) % 196)]
|
||||||
}
|
}
|
||||||
|
|
||||||
var e = *errorVector
|
// Zero reserved bits
|
||||||
e[0] = (data[0] ^ data[1] ^ data[3] ^ data[5] ^ data[6])
|
for i = 0; i < 3; i++ {
|
||||||
e[1] = (data[0] ^ data[1] ^ data[2] ^ data[4] ^ data[6] ^ data[7])
|
datafr[0*15+i] = 0
|
||||||
e[2] = (data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[5] ^ data[7] ^ data[8])
|
|
||||||
e[3] = (data[0] ^ data[2] ^ data[4] ^ data[5] ^ data[8])
|
|
||||||
}
|
|
||||||
|
|
||||||
// hamming(13, 9, 3) checking of a matrix column (13 total bits, 9 data bits,
|
|
||||||
// min. distance: 3)
|
|
||||||
func hamming_13_9_3_check(data bit.Bits, errorVector *vector) bool {
|
|
||||||
if data == nil || len(data) < 13 || errorVector == nil {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hamming_13_9_3_parity(data, errorVector)
|
for i = 0; i < 15; i++ {
|
||||||
|
var codeword uint32
|
||||||
var e = *errorVector
|
for j = 0; j < 13; j++ {
|
||||||
e[0] ^= data[9]
|
codeword <<= 1
|
||||||
e[1] ^= data[10]
|
codeword |= uint32(datafr[j*15+i])
|
||||||
e[2] ^= data[11]
|
|
||||||
e[3] ^= data[12]
|
|
||||||
|
|
||||||
return e[0] == 0 && e[1] == 0 && e[2] == 0 && e[3] == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
var hamming_15_11_generator_matrix = bit.Bits{
|
|
||||||
1, 0, 0, 1,
|
|
||||||
1, 1, 0, 1,
|
|
||||||
1, 1, 1, 1,
|
|
||||||
1, 1, 1, 0,
|
|
||||||
0, 1, 1, 1,
|
|
||||||
1, 0, 1, 0,
|
|
||||||
0, 1, 0, 1,
|
|
||||||
1, 0, 1, 1,
|
|
||||||
1, 1, 0, 0,
|
|
||||||
0, 1, 1, 0,
|
|
||||||
0, 0, 1, 1,
|
|
||||||
|
|
||||||
1, 0, 0, 0, // These are used to determine errors in the hamming checksum bits.
|
|
||||||
0, 1, 0, 0,
|
|
||||||
0, 0, 1, 0,
|
|
||||||
0, 0, 0, 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
func hamming_15_11_3_error_position(errorVector *vector) int {
|
|
||||||
if errorVector == nil {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
var e = *errorVector
|
|
||||||
for row := 0; row < 15; row++ {
|
|
||||||
if hamming_15_11_generator_matrix[row*4] == e[0] &&
|
|
||||||
hamming_15_11_generator_matrix[row*4+1] == e[1] &&
|
|
||||||
hamming_15_11_generator_matrix[row*4+2] == e[2] &&
|
|
||||||
hamming_15_11_generator_matrix[row*4+3] == e[3] {
|
|
||||||
return row
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
var hamming_13_9_generator_matrix = bit.Bits{
|
|
||||||
1, 1, 1, 1,
|
|
||||||
1, 1, 1, 0,
|
|
||||||
0, 1, 1, 1,
|
|
||||||
0, 1, 1, 1,
|
|
||||||
0, 1, 0, 1,
|
|
||||||
1, 0, 1, 1,
|
|
||||||
1, 1, 0, 0,
|
|
||||||
0, 1, 1, 0,
|
|
||||||
0, 0, 1, 1,
|
|
||||||
|
|
||||||
1, 0, 0, 0, // These are used to determine errors in the hamming checksum bits.
|
fec.Hamming15_11_3_Correct(&codeword)
|
||||||
0, 1, 0, 0,
|
codeword &= 0x01ff
|
||||||
0, 0, 1, 0,
|
for j = 0; j < 9; j++ {
|
||||||
0, 0, 0, 1,
|
datafr[j*15+i] = bit.Bit((codeword >> (8 - j)) & 1)
|
||||||
}
|
|
||||||
|
|
||||||
func hamming_13_9_3_error_position(errorVector *vector) int {
|
|
||||||
if errorVector == nil {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
var e = *errorVector
|
|
||||||
for row := 0; row < 13; row++ {
|
|
||||||
if hamming_13_9_generator_matrix[row*4] == e[0] &&
|
|
||||||
hamming_13_9_generator_matrix[row*4+1] == e[1] &&
|
|
||||||
hamming_13_9_generator_matrix[row*4+2] == e[2] &&
|
|
||||||
hamming_13_9_generator_matrix[row*4+3] == e[3] {
|
|
||||||
return row
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1
|
for j = 0; j < 9; j++ {
|
||||||
}
|
var codeword uint32
|
||||||
|
for i = 0; i < 15; i++ {
|
||||||
func Dump(bits bit.Bits) {
|
codeword <<= 1
|
||||||
if len(bits) != 196 {
|
codeword |= uint32(datafr[j*15+i])
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var row, col int
|
|
||||||
|
|
||||||
fmt.Println("BPTC(196, 96) matrix:")
|
|
||||||
fmt.Print(" |")
|
|
||||||
for col = 0; col < 15; col++ {
|
|
||||||
fmt.Printf("%x", col)
|
|
||||||
if col == 10 {
|
|
||||||
fmt.Print(" ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Println("\n --+----------- ----")
|
|
||||||
for row = 0; row < 13; row++ {
|
|
||||||
fmt.Printf(" %.2d|", row)
|
|
||||||
for col = 0; col < 11; col++ {
|
|
||||||
// +1 because the first bit is R(3) and it's not used
|
|
||||||
// so we can ignore that.
|
|
||||||
fmt.Printf("%d", bits[col+row*15+1])
|
|
||||||
}
|
|
||||||
fmt.Print(" ")
|
|
||||||
for ; col < 15; col++ {
|
|
||||||
// +1 because the first bit is R(3) and it's not used
|
|
||||||
// so we can ignore that.
|
|
||||||
fmt.Printf("%d", bits[col+row*15+1])
|
|
||||||
}
|
|
||||||
fmt.Println("")
|
|
||||||
if row == 8 {
|
|
||||||
fmt.Println(" :")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func CheckAndRepair(bits bit.Bits) (bool, error) {
|
|
||||||
if bits == nil || len(bits) != 196 {
|
|
||||||
return false, errors.New("expected 196 input bits")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
cb = make([]bit.Bit, 13)
|
|
||||||
errorVector = vector{}
|
|
||||||
)
|
|
||||||
for col := 0; col < 15; col++ {
|
|
||||||
for row := 0; row < 13; row++ {
|
|
||||||
// +1 because the first bit is R(3) and it's not used so we can ignore that.
|
|
||||||
cb[row] = bits[col+row*15+1]
|
|
||||||
}
|
}
|
||||||
|
fec.Hamming15_11_3_Correct(&codeword)
|
||||||
if !hamming_13_9_3_check(cb, &errorVector) {
|
for i = 0; i < 11; i++ {
|
||||||
wrong := hamming_13_9_3_error_position(&errorVector)
|
datafr[j*15+10-i] = bit.Bit((codeword >> i) & 1)
|
||||||
if wrong < 0 {
|
|
||||||
return false, fmt.Errorf("dmr/bptc(196, 96): hamming(13, 9) check error in column #%d, can't repair", col)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix bit error
|
|
||||||
bits[col+wrong*15+1] ^= 1
|
|
||||||
for row := 0; row < 13; row++ {
|
|
||||||
// +1 because the first bit is R(3) and it's not used so we can ignore that.
|
|
||||||
cb[row] = bits[col+row*15+1]
|
|
||||||
}
|
|
||||||
|
|
||||||
if !hamming_13_9_3_check(cb, &errorVector) {
|
|
||||||
return false, fmt.Errorf("dmr/bptc(196, 96): hamming(13, 9) check error in column #%d, couldn't repair", col)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for row := 0; row < 9; row++ {
|
// Extract data bits
|
||||||
// +1 because the first bit is R(3) and it's not used so we can ignore that.
|
for i, k = 3, 0; i < 11; i, k = i+1, k+1 {
|
||||||
if !hamming_15_11_3_check(bits[row*15+1:], &errorVector) {
|
extracted[k] = datafr[0*15+i]
|
||||||
wrong := hamming_15_11_3_error_position(&errorVector)
|
|
||||||
if wrong < 0 {
|
|
||||||
return false, fmt.Errorf("dmr/bptc(196, 96): hamming(15, 11) check error in row #%d, can't repair", row)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix bit error
|
|
||||||
bits[row*15+wrong+1] ^= 1
|
|
||||||
if !hamming_15_11_3_check(bits[row*15+1:], &errorVector) {
|
|
||||||
return false, fmt.Errorf("dmr/bptc (196,96): hamming(15,11) check error, couldn't repair row #%d", row)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
for j = 1; j < 9; j++ {
|
||||||
return true, nil
|
for i = 0; i < 11; i, k = i+1, k+1 {
|
||||||
}
|
extracted[k] = datafr[j*15+i]
|
||||||
|
|
||||||
// Extract the data bits from the given deinterleaved info bits array (discards BPTC bits).
|
|
||||||
func Extract(bits bit.Bits) bit.Bits {
|
|
||||||
var e = make([]bit.Bit, 96)
|
|
||||||
copy(e[0:8], bits[4:12])
|
|
||||||
copy(e[8:19], bits[16:27])
|
|
||||||
copy(e[19:30], bits[31:42])
|
|
||||||
copy(e[30:41], bits[46:57])
|
|
||||||
copy(e[41:52], bits[61:72])
|
|
||||||
copy(e[52:63], bits[76:87])
|
|
||||||
copy(e[63:74], bits[91:102])
|
|
||||||
copy(e[74:85], bits[106:117])
|
|
||||||
copy(e[85:96], bits[121:132])
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// New BPTC(196, 96) payload from 96 data bits.
|
|
||||||
func New(bits bit.Bits) bit.Bits {
|
|
||||||
var (
|
|
||||||
dbp int
|
|
||||||
errorVector = vector{}
|
|
||||||
p = make([]bit.Bit, 196)
|
|
||||||
)
|
|
||||||
|
|
||||||
for row := 0; row < 9; row++ {
|
|
||||||
if row == 0 {
|
|
||||||
for col := 3; col < 11; col++ {
|
|
||||||
// +1 because the first bit is R(3) and it's not used so we can ignore that.
|
|
||||||
p[col+1] = bits[dbp]
|
|
||||||
dbp++
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for col := 0; col < 11; col++ {
|
|
||||||
// +1 because the first bit is R(3) and it's not used so we can ignore that.
|
|
||||||
p[col+row*15+1] = bits[dbp]
|
|
||||||
dbp++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// +1 because the first bit is R(3) and it's not used so we can ignore that.
|
|
||||||
hamming_15_11_3_parity(p[row*15+1:], &errorVector)
|
|
||||||
p[row*15+11+1] = errorVector[0]
|
|
||||||
p[row*15+12+1] = errorVector[1]
|
|
||||||
p[row*15+13+1] = errorVector[2]
|
|
||||||
p[row*15+14+1] = errorVector[3]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for col := 0; col < 15; col++ {
|
copy(payload, extracted.Bytes())
|
||||||
var cb = make([]bit.Bit, 9)
|
|
||||||
for row := 0; row < 9; row++ {
|
|
||||||
cb[row] = p[col+row*15+1]
|
|
||||||
}
|
|
||||||
hamming_13_9_3_parity(cb, &errorVector)
|
|
||||||
p[col+135+1] = errorVector[0]
|
|
||||||
p[col+135+15+1] = errorVector[1]
|
|
||||||
p[col+135+30+1] = errorVector[2]
|
|
||||||
p[col+135+45+1] = errorVector[3]
|
|
||||||
}
|
|
||||||
|
|
||||||
return p
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,133 @@
|
|||||||
|
package bptc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/pd0mz/go-dmr/bit"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Decode(bits bit.Bits, deinterleave bool) (bit.Bits, error) {
|
||||||
|
var debits bit.Bits
|
||||||
|
if deinterleave {
|
||||||
|
debits = Deinterleave(bits)
|
||||||
|
} else {
|
||||||
|
debits = bits
|
||||||
|
}
|
||||||
|
if err := Check(bits); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return Extract(debits), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deinterleave raw bits
|
||||||
|
func Deinterleave(r bit.Bits) bit.Bits {
|
||||||
|
// The first bit is R(3) which is not used so can be ignored
|
||||||
|
var d = make(bit.Bits, 196)
|
||||||
|
var i int
|
||||||
|
for a := 0; a < 196; a++ {
|
||||||
|
i = (a * 181) % 196
|
||||||
|
d[a] = r[i]
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hamming(13, 9, 3) check
|
||||||
|
func Hamming1393(debits bit.Bits) (bool, bit.Bits) {
|
||||||
|
var err = make(bit.Bits, 4)
|
||||||
|
err[0] = debits[0] ^ debits[1] ^ debits[3] ^ debits[5] ^ debits[6]
|
||||||
|
err[1] = debits[0] ^ debits[1] ^ debits[2] ^ debits[4] ^ debits[6] ^ debits[7]
|
||||||
|
err[2] = debits[0] ^ debits[1] ^ debits[2] ^ debits[3] ^ debits[5] ^ debits[7] ^ debits[8]
|
||||||
|
err[3] = debits[0] ^ debits[2] ^ debits[4] ^ debits[5] ^ debits[8]
|
||||||
|
return (err[0] == debits[9]) && (err[1] == debits[10]) && (err[2] == debits[11]) && (err[3] == debits[12]), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hamming(15, 11, 3) check
|
||||||
|
func Hamming15113(debits bit.Bits) (bool, bit.Bits) {
|
||||||
|
var err = make(bit.Bits, 4)
|
||||||
|
err[0] = debits[0] ^ debits[1] ^ debits[2] ^ debits[3] ^ debits[5] ^ debits[7] ^ debits[8]
|
||||||
|
err[1] = debits[1] ^ debits[2] ^ debits[3] ^ debits[4] ^ debits[6] ^ debits[8] ^ debits[9]
|
||||||
|
err[2] = debits[2] ^ debits[3] ^ debits[4] ^ debits[5] ^ debits[7] ^ debits[9] ^ debits[10]
|
||||||
|
err[3] = debits[0] ^ debits[1] ^ debits[2] ^ debits[4] ^ debits[6] ^ debits[7] ^ debits[10]
|
||||||
|
return (err[0] == debits[11]) && (err[1] == debits[12]) && (err[2] == debits[13]) && (err[3] == debits[14]), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check each row with a Hamming (15,11,3) code
|
||||||
|
func Check(debits bit.Bits) error {
|
||||||
|
var (
|
||||||
|
row = make(bit.Bits, 15)
|
||||||
|
col = make(bit.Bits, 13)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Run through each of the 9 rows containing data
|
||||||
|
for r := 0; r < 9; r++ {
|
||||||
|
p := (r * 15) + 1
|
||||||
|
for a := 0; a < 15; a++ {
|
||||||
|
row[a] = debits[p]
|
||||||
|
}
|
||||||
|
if ok, _ := Hamming15113(row); !ok {
|
||||||
|
return fmt.Errorf("hamming(15, 11, 3) check failed on row #%d", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run through each of the 15 columns
|
||||||
|
for c := 0; c < 15; c++ {
|
||||||
|
p := c + 1
|
||||||
|
for a := 0; a < 13; a++ {
|
||||||
|
col[a] = debits[p]
|
||||||
|
p += 15
|
||||||
|
}
|
||||||
|
if ok, _ := Hamming1393(col); !ok {
|
||||||
|
return fmt.Errorf("hamming(13, 9, 3) check failed on col #%d", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the 96 bits of data
|
||||||
|
func Extract(debits bit.Bits) bit.Bits {
|
||||||
|
var (
|
||||||
|
out = make(bit.Bits, 96)
|
||||||
|
a, pos int
|
||||||
|
)
|
||||||
|
|
||||||
|
for a = 4; a <= 11; a++ {
|
||||||
|
out[pos] = debits[a]
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
for a = 16; a <= 26; a++ {
|
||||||
|
out[pos] = debits[a]
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
for a = 31; a <= 41; a++ {
|
||||||
|
out[pos] = debits[a]
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
for a = 46; a <= 56; a++ {
|
||||||
|
out[pos] = debits[a]
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
for a = 61; a <= 71; a++ {
|
||||||
|
out[pos] = debits[a]
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
for a = 76; a <= 86; a++ {
|
||||||
|
out[pos] = debits[a]
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
for a = 91; a <= 101; a++ {
|
||||||
|
out[pos] = debits[a]
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
for a = 106; a <= 116; a++ {
|
||||||
|
out[pos] = debits[a]
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
for a = 121; a <= 131; a++ {
|
||||||
|
out[pos] = debits[a]
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
@ -1,35 +0,0 @@
|
|||||||
package bptc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
"pd0mz/go-dmr/bit"
|
|
||||||
)
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func Test(t *testing.T) {
|
|
||||||
for i := 0; i < 100; i++ {
|
|
||||||
test := make(bit.Bits, 96)
|
|
||||||
for b := 0; b < 96; b++ {
|
|
||||||
if rand.Uint32() > 0x7fffffff {
|
|
||||||
test[b].Flip()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bptc := New(test)
|
|
||||||
if len(bptc) != 196 {
|
|
||||||
t.Fatalf("expected 196 bits, got %d", len(bptc))
|
|
||||||
}
|
|
||||||
if testing.Verbose() {
|
|
||||||
Dump(bptc)
|
|
||||||
}
|
|
||||||
corrupt := rand.Intn(10)
|
|
||||||
bptc[corrupt].Flip()
|
|
||||||
if ok, err := CheckAndRepair(bptc); !ok {
|
|
||||||
t.Fatalf("check and repair failed: %v", err)
|
|
||||||
}
|
|
||||||
bptc[corrupt].Flip()
|
|
||||||
back := Extract(bptc)
|
|
||||||
if len(test) != len(back) {
|
|
||||||
t.Fatalf("expected %d bits, got %d", len(test), len(back))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue