You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
4.4 KiB
Go

package bptc
import (
"fmt"
"os"
"github.com/pd0mz/go-dmr"
)
var (
debug bool
// deinterleave matrix
dm = [256]uint8{}
)
func init() {
debug = os.Getenv("DEBUG_DMR_BPTC") != ""
var i uint32
for i = 0; i < 0x100; i++ {
dm[i] = uint8((i * 181) % 196)
}
}
func dump(bits []byte) {
for row := 0; row < 13; row++ {
if row == 0 {
fmt.Printf("col # ")
for col := 0; col < 15; col++ {
fmt.Printf("%02d ", col+1)
if col == 10 {
fmt.Print("| ")
}
}
fmt.Println("")
}
if row == 9 {
fmt.Println(" ------------------------------- ------------")
}
for col := 0; col < 15; col++ {
if col == 0 {
fmt.Printf("row #%02d: ", row+1)
}
fmt.Printf(" %d ", bits[col+row*15+1])
if col == 10 {
fmt.Print("| ")
}
}
fmt.Println("")
}
}
func Decode(info, data []byte) error {
if len(info) < 196 {
return fmt.Errorf("bptc: info size %d too small, need at least 196 bits", len(info))
}
if len(data) < 12 {
return fmt.Errorf("bptc: data size %d too small, need at least 12 bytes", len(data))
}
var (
i, j, k uint32
bits = make([]byte, 196)
temp = make([]byte, 196)
)
// Deinterleave
for i = 1; i < 197; i++ {
bits[i-1] = info[dm[i]]
}
if debug {
dump(bits)
}
// Hamming checks
if err := hamming_check(bits); err != nil {
//return err
//log.Warningf("hamming check failed: %v", err)
}
// Extract data bits
for i, k = 3, 0; i < 11; i, k = i+1, k+1 {
temp[k] = bits[0*15+i]
}
for j = 1; j < 9; j++ {
for i = 0; i < 11; i, k = i+1, k+1 {
temp[k] = bits[j*15+i]
}
}
copy(data, dmr.BitsToBytes(temp))
return nil
}
func Encode(data, info []byte) error {
if len(data) < 12 {
return fmt.Errorf("bptc: data size %d too small, need at least 12 bytes", len(data))
}
if len(info) < 196 {
return fmt.Errorf("bptc: info size %d too small, need at least 196 bits", len(info))
}
var (
bits = dmr.BytesToBits(data)
temp = make([]byte, 196)
errs = make([]byte, 4)
cols = make([]byte, 13)
)
var c, r, k uint32
for r = 0; r < 9; r++ {
if r == 0 {
for c = 3; c < 11; c, k = c+1, k+1 {
temp[c] = bits[k]
}
} else {
for c = 0; c < 11; c, k = c+1, k+1 {
temp[c+r*15] = bits[k]
}
}
hamming_15_11_3_parity(temp[r*15:], errs)
temp[r*15+11] = errs[0]
temp[r*15+12] = errs[1]
temp[r*15+13] = errs[2]
temp[r*15+14] = errs[3]
}
for c = 0; c < 15; c++ {
for r = 0; r < 9; r++ {
cols[r] = temp[c+r*15+1]
}
hamming_13_9_3_parity(cols, errs)
temp[c+135+1] = errs[0]
temp[c+135+15+1] = errs[1]
temp[c+135+30+1] = errs[2]
temp[c+135+45+1] = errs[3]
}
if debug {
dump(temp)
}
// Interleave
for k = 1; k < 197; k++ {
info[dm[k]] = temp[k-1]
}
return nil
}
// Hamming(13, 9, 3) check
func hamming_13_9_3_parity(bits, errs []byte) bool {
errs[0] = bits[0] ^ bits[1] ^ bits[3] ^ bits[5] ^ bits[6]
errs[1] = bits[0] ^ bits[1] ^ bits[2] ^ bits[4] ^ bits[6] ^ bits[7]
errs[2] = bits[0] ^ bits[1] ^ bits[2] ^ bits[3] ^ bits[5] ^ bits[7] ^ bits[8]
errs[3] = bits[0] ^ bits[2] ^ bits[4] ^ bits[5] ^ bits[8]
return (errs[0] == bits[9]) && (errs[1] == bits[10]) && (errs[2] == bits[11]) && (errs[3] == bits[12])
}
// Hamming(15, 11, 3) check
func hamming_15_11_3_parity(bits, errs []byte) bool {
errs[0] = bits[0] ^ bits[1] ^ bits[2] ^ bits[3] ^ bits[5] ^ bits[7] ^ bits[8]
errs[1] = bits[1] ^ bits[2] ^ bits[3] ^ bits[4] ^ bits[6] ^ bits[8] ^ bits[9]
errs[2] = bits[2] ^ bits[3] ^ bits[4] ^ bits[5] ^ bits[7] ^ bits[9] ^ bits[10]
errs[3] = bits[0] ^ bits[1] ^ bits[2] ^ bits[4] ^ bits[6] ^ bits[7] ^ bits[10]
return (errs[0] == bits[11]) && (errs[1] == bits[12]) && (errs[2] == bits[13]) && (errs[3] == bits[14])
}
// hamming_check checks each row with a Hamming(15,11,3) code and each column with Hamming(13, 9, 3)
func hamming_check(bits []byte) error {
var (
c, r, k uint32
row = make([]byte, 15)
col = make([]byte, 13)
errs = make([]byte, 4)
)
// Run through each of the 9 rows containing data
for r = 0; r < 9; r++ {
k = r*15 + 1
for a := 0; a < 15; a++ {
row[a] = bits[k]
}
if !hamming_15_11_3_parity(row, errs) {
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++ {
k = c + 1
for a := 0; a < 13; a, k = a+1, k+15 {
col[a] = bits[k]
}
if !hamming_13_9_3_parity(col, errs) {
return fmt.Errorf("hamming(13, 9, 3) check failed on col #%d", c)
}
}
return nil
}