diff --git a/include/dsd.h b/include/dsd.h index a6fb88c..82c1f94 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -1032,6 +1032,8 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2 //end void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType); void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182]); +//Osmocom OP25 12 Rate Trellis Decoder (for NXDN, M17, YSF, etc) +void trellis_decode(uint8_t result[], const uint8_t source[], int result_len); //OP25 NXDN CRC functions int load_i(const uint8_t val[], int len); diff --git a/src/3.c b/src/3.c index 4b113aa..bb2351a 100644 --- a/src/3.c +++ b/src/3.c @@ -2,6 +2,86 @@ * 3.c * Placeholder File 3 -- This file is for temporary code storage * + * A 1/2 Rate Convolutional Decoder for NXDN/M17/YSF + * Used as a secondary decoder in case convolutional decoder fails (second opinion) + *-----------------------------------------------------------------------------*/ + +#include "dsd.h" + +static const int PARITY[] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1}; + +// trellis_1_2 encode: source is in bits, result in bits +void trellis_encode(uint8_t result[], const uint8_t source[], int result_len, int reg) +{ + for (int i=0; i>1]; + result[i] = PARITY[reg & 0x19]; + result[i+1] = PARITY[reg & 0x17]; + } +} + +// simplified trellis 2:1 decode; source and result in bits +// assumes that encoding was done with NTEST trailing zero bits +// result_len should be set to the actual number of data bits +// in the original unencoded message (excl. these trailing bits) +void trellis_decode(uint8_t result[], const uint8_t source[], int result_len) +{ + int reg = 0; + int min_d; + int min_bt; + static const int NTEST = 4; + static const int NTESTC = 1 << NTEST; + uint8_t bt[NTEST]; + uint8_t tt[NTEST*2]; + int dstats[4]; + int sum; + for (int p=0; p < 4; p++) + dstats[p] = 0; + for (int p=0; p < result_len; p++) { + for (int i=0; i>3; + bt[1] = (i&4)>>2; + bt[2] = (i&2)>>1; + bt[3] = (i&1); + trellis_encode(tt, bt, NTEST*2, reg); + sum=0; + for (int j=0; j 3) ? 3 : min_d] += 1; + } + + //debug output + // fprintf (stderr, "\n stats\t%d %d %d %d\n", dstats[0], dstats[1], dstats[2], dstats[3]); +} + +//Original Copyright/License + +/* -*- c++ -*- */ +/* + * NXDN Encoder/Decoder (C) Copyright 2019 Max H. Parke KA1RBI * + * This file is part of OP25 * - *-----------------------------------------------------------------------------*/ \ No newline at end of file + * This 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. + * + * This software 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 this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ diff --git a/src/nxdn_deperm.c b/src/nxdn_deperm.c index ed5f461..043a10d 100644 --- a/src/nxdn_deperm.c +++ b/src/nxdn_deperm.c @@ -52,7 +52,7 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144]) uint8_t deperm[144]; //144 uint8_t depunc[192]; //192 uint8_t trellis_buf[96]; //96 - uint16_t crc = 0; //crc calculated by function + uint16_t crc = 1; //crc calculated by function uint16_t check = 0; //crc from payload for comparison int out; @@ -111,6 +111,30 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144]) check = check | trellis_buf[84+i]; //80 } + //debug + // if (crc == check) + // fprintf (stderr, " Pass 1 "); + + //if the crc fails, attempt again with the other trellis decoder + if (crc != check) + { + //debug + // fprintf (stderr, " Pass 2 "); + crc = 1; check = 0; + memset (trellis_buf, 0, sizeof(trellis_buf)); + memset (m_data, 0, sizeof(m_data)); + trellis_decode(trellis_buf, depunc, 92); + //fill m_data bytes with trellis_buf + for(int i = 0; i < 12; i++) + m_data[i] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8); + crc = crc12f (trellis_buf, 84); + for (int i = 0; i < 12; i++) + { + check = check << 1; + check = check | trellis_buf[i+84]; + } + } + if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf); // else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf); @@ -145,7 +169,7 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60]) memset (trellis_buf, 0, sizeof(trellis_buf)); int o = 0; - uint8_t crc = 0; //value computed by crc6 on payload + uint8_t crc = 1; //value computed by crc6 on payload uint8_t check = 0; //value pulled from last 6 bits int sf = 0; int ran = 0; @@ -212,6 +236,30 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60]) check = check | trellis_buf[i+26]; } + //debug + // if (crc == check) + // fprintf (stderr, " Pass 1 "); + + //if the crc fails, attempt again with the other trellis decoder + if (crc != check) + { + //debug + // fprintf (stderr, " Pass 2 "); + crc = 1; check = 0; + memset (trellis_buf, 0, sizeof(trellis_buf)); + memset (m_data, 0, sizeof(m_data)); + trellis_decode(trellis_buf, depunc, 32); + //fill m_data bytes with trellis_buf + for(int i = 0; i < 4; i++) + m_data[i] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8); + crc = crc6(trellis_buf, 26); //32 + for (int i = 0; i < 6; i++) + { + check = check << 1; + check = check | trellis_buf[i+26]; + } + } + //FIRST! If part of a non_superframe, and CRC is good, send directly to NXDN_Elements_Content_decode if (state->nxdn_sacch_non_superframe == TRUE) { @@ -284,12 +332,12 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60]) fprintf (stderr, "PF %d/4", part_of_frame+1); - if (crc != check) - { - fprintf (stderr, "%s", KRED); - fprintf (stderr, " (CRC ERR)"); - fprintf (stderr, "%s", KNRM); - } + // if (crc != check) + // { + // fprintf (stderr, "%s", KRED); + // fprintf (stderr, " (CRC ERR)"); + // fprintf (stderr, "%s", KNRM); + // } //reset scrambler seed to key value on new superframe if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1) state->payload_miN = 0; @@ -319,16 +367,16 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60]) NXDN_SACCH_Full_decode (opts, state); } - // if (opts->payload == 1) - // { - // fprintf (stderr, "\n"); - // fprintf (stderr, " SACCH SF Segment #%d ", part_of_frame+1); - // for (int i = 0; i < 4; i++) - // { - // fprintf (stderr, "[%02X]", m_data[i]); - // } - // // if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", crc, check); - // } + if (opts->payload == 1) + { + fprintf (stderr, "\n"); + fprintf (stderr, " SACCH SF Segment #%d ", part_of_frame+1); + for (int i = 0; i < 4; i++) + { + fprintf (stderr, "[%02X]", m_data[i]); + } + if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", crc, check); + } }