Add BCH decoding of network ID (NAC/DUID)

git-svn-id: http://op25.osmocom.org/svn/trunk@89 65a5c917-d112-43f1-993d-58c26a4786be
This commit is contained in:
stevie 2008-06-16 09:41:24 +00:00
parent 5ea83dbf72
commit 504a4f8b54
6 changed files with 285 additions and 27 deletions

View File

@ -10,8 +10,8 @@ unlimited permission to copy, distribute and modify it.
Basic Installation
==================
The commands `./bootstrap; ./configure; make; make install' should
configure, build, and install this package. The following
Briefly, the shell commands `./configure; make; make install' should
configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package.

View File

@ -60,6 +60,7 @@ ourlib_LTLIBRARIES = _op25.la
# These are the source files that go into the shared library
_op25_la_SOURCES = \
abstract_data_unit.cc \
bch.cc \
data_unit.cc \
header.cc \
ldu1.cc \

213
decoder/src/lib/bch.cc Normal file
View File

@ -0,0 +1,213 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* OP25 is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#include <bch.h>
/*
* APCO P25 BCH(64,16,23) encoder.
*/
uint64_t
bch_64_encode(uint16_t val)
{
static const uint64_t encoding_matrix[] = {
0x8000cd930bdd3b2aLL,
0x4000ab5a8e33a6beLL,
0x2000983e4cc4e874LL,
0x10004c1f2662743aLL,
0x0800eb9c98ec0136LL,
0x0400b85d47ab3bb0LL,
0x02005c2ea3d59dd8LL,
0x01002e1751eaceecLL,
0x0080170ba8f56776LL,
0x0040c616dfa78890LL,
0x0020630b6fd3c448LL,
0x00103185b7e9e224LL,
0x000818c2dbf4f112LL,
0x0004c1f2662743a2LL,
0x0002ad6a38ce9afbLL,
0x00019b2617ba7657LL
};
uint64_t cw = 0LL;
for(uint8_t i=0; i < 16; ++i) {
if(val & (1 << (15 - i))) {
cw ^= encoding_matrix[i];
}
}
return cw;
}
/*
* APCO P25 BCH(64,16,23) decoder.
*/
bool
bch_64_decode(uint64_t& cw)
{
int elp[24][22], s[23];
int d[23], L[24], uLu[24];
int locn[11], reg[12];
int i, j, u, q, n;
bool syndrome_error = false;
bool decoded = true;
static const int BCH_GF_EXP[64] = {
1, 2, 4, 8, 16, 32, 3, 6, 12, 24, 48, 35, 5, 10, 20, 40,
19, 38, 15, 30, 60, 59, 53, 41, 17, 34, 7, 14, 28, 56, 51, 37,
9, 18, 36, 11, 22, 44, 27, 54, 47, 29, 58, 55, 45, 25, 50, 39,
13, 26, 52, 43, 21, 42, 23, 46, 31, 62, 63, 61, 57, 49, 33, 0,
};
static const int BCH_GF_LOG[64] = {
-1, 0, 1, 6, 2, 12, 7, 26, 3, 32, 13, 35, 8, 48, 27, 18,
4, 24, 33, 16, 14, 52, 36, 54, 9, 45, 49, 38, 28, 41, 19, 56,
5, 62, 25, 11, 34, 31, 17, 47, 15, 23, 53, 51, 37, 44, 55, 40,
10, 61, 46, 30, 50, 22, 39, 43, 29, 60, 42, 21, 20, 59, 57, 58,
};
// first form the syndromes
for(i = 1; i <= 22; i++) {
s[i] = 0;
for(j = 0; j <= 62; j++) {
if(cw & (1LL << j)) {
s[i] ^= BCH_GF_EXP[(i * j) % 63];
}
}
if(s[i]) {
syndrome_error = true;
}
s[i] = BCH_GF_LOG[s[i]];
}
// if there are errors, compute elp and try to correct them
if(syndrome_error) {
L[0] = 0; uLu[0] = -1; d[0] = 0; elp[0][0] = 0;
L[1] = 0; uLu[1] = 0; d[1] = s[1]; elp[1][0] = 1;
for(i = 1; i <= 21; i++) {
elp[0][i] = -1;
elp[1][i] = 0;
}
u = 0;
do {
++u;
if(-1 == d[u]) {
L[u + 1] = L[u];
for(i = 0; i <= L[u]; i++) {
elp[u + 1][i] = elp[u][i];
elp[u][i] = BCH_GF_LOG[elp[u][i]];
}
} else {
// search for words with greatest uLu(q) for which d(q) != 0
q = u - 1;
while((-1 == d[q]) && (q > 0)) {
--q;
}
// have found first non-zero d(q)
if(q > 0) {
j = q;
do {
--j;
if((d[j] != -1) && (uLu[q] < uLu[j]) ) {
q = j;
}
} while(j > 0);
}
// store degree of new elp polynomial
if(L[u] > L[q] + u - q) {
L[u + 1] = L[u];
} else {
L[u + 1] = L[q] + u - q;
}
// form new elp(x)
for(i = 0; i <= 21; i++) {
elp[u + 1][i] = 0;
}
for(i = 0; i <= L[q]; i++) {
if(elp[q][i] != -1) {
elp[u + 1][i + u - q] = BCH_GF_EXP[(d[u] + 63 - d[q] + elp[q][i]) % 63];
}
}
for(i = 0; i <= L[u]; i++) {
elp[u + 1][i] ^= elp[u][i];
elp[u][i] = BCH_GF_LOG[elp[u][i]];
}
}
uLu[u + 1] = u - L[u + 1];
// form (u+1)th discrepancy
if(u < 22) {
// no discrepancy computed on last iteration
if(s[u + 1] != -1) {
d[u + 1] = BCH_GF_EXP[s[u + 1]];
} else {
d[u + 1] = 0;
}
for(i = 1; i <= L[u + 1]; i++) {
if((s[u + 1 - i] != -1) && (elp[u + 1][i] != 0)) {
d[u + 1] ^= BCH_GF_EXP[(s[u + 1 - i] + BCH_GF_LOG[elp[u + 1][i]]) % 63];
}
}
// put d(u+1) into index form
d[u + 1] = BCH_GF_LOG[d[u + 1]];
}
} while((u < 22) && (L[u + 1] <= 11));
++u;
if(L[u] <= 11) { // Can correct errors
// put elp into index form
for(i = 0; i <= L[u]; i++) {
elp[u][i] = BCH_GF_LOG[elp[u][i]];
}
// Chien search: find roots of the error locator polynomial
for(i = 1; i <= L[u]; i++) {
reg[i] = elp[u][i];
}
n = 0;
for(i = 1; i <= 63; i++) {
q = 1;
for(j = 1; j <= L[u]; j++) {
if(reg[j] != -1) {
reg[j] = (reg[j] + j) % 63;
q ^= BCH_GF_EXP[reg[j]];
}
}
if(0 == q) {
locn[n++] = 63 - i; // store root and error location number indices
}
}
if(n == L[u]) {
// no. roots = degree of elp hence <= t errors
for(i = 0; i < L[u]; i++) {
cw ^= 1LL << (locn[i]);
}
} else {
// elp has degree > t hence cannot solve
decoded = false;
}
} else {
decoded = false;
}
}
return decoded;
}

39
decoder/src/lib/bch.h Normal file
View File

@ -0,0 +1,39 @@
/* -*- C++ -*- */
/*
* Copyright 2008 Steve Glass
*
* This file is part of OP25.
*
* OP25 is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* OP25 is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OP25; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
* 02110-1301, USA.
*/
#ifndef INCLUDED_BCH_H
#define INCLUDED_BCH_H
#include <stdint.h>
/*
* BCH encode val and return the result.
*/
extern uint64_t bch_64_encode(uint16_t val);
/*
* BCH decode codeword cw and correct errors. If successful, the cw is
* error-corrected and true is returned; otherwise returns false.
*/
extern bool bch_64_decode(uint64_t& cw);
#endif /* INCLUDED_BCH_H */

View File

@ -20,6 +20,7 @@
* 02110-1301, USA.
*/
#include <bch.h>
#include <data_unit.h>
#include <header.h>
#include <ldu1.h>
@ -27,32 +28,37 @@
#include <packet.h>
#include <terminator.h>
/*
* Construct a data unit given the initial frame_sync and network ID.
*/
data_unit_sptr
data_unit::make_data_unit(uint64_t frame_sync, uint64_t network_ID)
{
data_unit_sptr d;
uint8_t type = (network_ID >> 48) & 0xf;
switch(type) {
case 0x0:
d = data_unit_sptr(new header(frame_sync, network_ID));
break;
case 0x3:
d = data_unit_sptr(new terminator(frame_sync, network_ID, false));
break;
case 0x5:
d = data_unit_sptr(new ldu1(frame_sync, network_ID));
break;
case 0xa:
d = data_unit_sptr(new ldu2(frame_sync, network_ID));
break;
case 0x9: // VSELP "voice packet"
case 0xc:
d = data_unit_sptr(new packet(frame_sync, network_ID));
break;
case 0xf:
d = data_unit_sptr(new terminator(frame_sync, network_ID, true));
break;
};
if(bch_64_decode(network_ID)) {
uint8_t type = (network_ID >> 48) & 0xf;
switch(type) {
case 0x0:
d = data_unit_sptr(new header(frame_sync, network_ID));
break;
case 0x3:
d = data_unit_sptr(new terminator(frame_sync, network_ID, false));
break;
case 0x5:
d = data_unit_sptr(new ldu1(frame_sync, network_ID));
break;
case 0xa:
d = data_unit_sptr(new ldu2(frame_sync, network_ID));
break;
case 0x9: // VSELP "voice packet"
case 0xc:
d = data_unit_sptr(new packet(frame_sync, network_ID));
break;
case 0xf:
d = data_unit_sptr(new terminator(frame_sync, network_ID, true));
break;
};
}
return d;
}

View File

@ -46,7 +46,7 @@ op25_decoder_f::~op25_decoder_f()
}
/*
* Take an incoming float value, convert to a symbol and process.
* Take an incoming float value, convert to a dibit symbol and process.
*/
int
op25_decoder_f::work(int nof_output_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items)
@ -125,7 +125,6 @@ op25_decoder_f::identifies(dibit d)
d_network_ID |= d;
const size_t LAST_NETWORK_ID_SYMBOL = 56;
if(LAST_NETWORK_ID_SYMBOL == d_symbol) {
// ToDo: BCH (64,16,23) decoding
identified = true;
}
return identified;
@ -181,7 +180,7 @@ op25_decoder_f::sync_receive_symbol(dibit d)
if(d_data_unit->complete(d)) {
gr_message_sptr msg(d_data_unit->decode());
if(msg) {
// ToDo: prefix frame with status symbols + other header stuff
// ToDo: prefix frame with status symbols
d_msgq->insert_tail(msg);
}
++d_data_units;