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:
parent
5ea83dbf72
commit
504a4f8b54
|
@ -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.
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Reference in New Issue