nxdn48 initial checkin for rx
This commit is contained in:
parent
538ae6015b
commit
140a76ac76
|
@ -129,7 +129,8 @@ class channel(object):
|
||||||
if dev.args.startswith('audio:'):
|
if dev.args.startswith('audio:'):
|
||||||
self.demod = p25_demodulator.p25_demod_fb(
|
self.demod = p25_demodulator.p25_demod_fb(
|
||||||
input_rate = dev.sample_rate,
|
input_rate = dev.sample_rate,
|
||||||
filter_type = config['filter_type'])
|
filter_type = config['filter_type'],
|
||||||
|
symbol_rate = self.symbol_rate)
|
||||||
else:
|
else:
|
||||||
self.demod = p25_demodulator.p25_demod_cb(
|
self.demod = p25_demodulator.p25_demod_cb(
|
||||||
input_rate = dev.sample_rate,
|
input_rate = dev.sample_rate,
|
||||||
|
|
|
@ -98,6 +98,8 @@ class p25_demod_base(gr.hier_block2):
|
||||||
if ntaps & 1 == 0:
|
if ntaps & 1 == 0:
|
||||||
ntaps += 1
|
ntaps += 1
|
||||||
coeffs = filter.firdes.root_raised_cosine(1.0, if_rate, symbol_rate, excess_bw, ntaps)
|
coeffs = filter.firdes.root_raised_cosine(1.0, if_rate, symbol_rate, excess_bw, ntaps)
|
||||||
|
if filter_type == 'nxdn':
|
||||||
|
coeffs = op25_c4fm_mod.c4fm_taps(sample_rate=self.if_rate, span=9, generator=op25_c4fm_mod.transfer_function_nxdn).generate()
|
||||||
if filter_type == 'gmsk':
|
if filter_type == 'gmsk':
|
||||||
# lifted from gmsk.py
|
# lifted from gmsk.py
|
||||||
_omega = sps
|
_omega = sps
|
||||||
|
@ -393,7 +395,7 @@ class p25_demod_cb(p25_demod_base):
|
||||||
elif src == 'diffdec':
|
elif src == 'diffdec':
|
||||||
self.connect(self.diffdec, sink)
|
self.connect(self.diffdec, sink)
|
||||||
elif src == 'mixer':
|
elif src == 'mixer':
|
||||||
self.connect(self.mixer, sink)
|
self.connect(self.agc, sink)
|
||||||
elif src == 'src':
|
elif src == 'src':
|
||||||
self.connect(self, sink)
|
self.connect(self, sink)
|
||||||
elif src == 'bpf':
|
elif src == 'bpf':
|
||||||
|
|
|
@ -49,14 +49,14 @@ _def_span = 13 #desired number of impulse response coeffs, in units of symbols
|
||||||
_def_gmsk_span = 4
|
_def_gmsk_span = 4
|
||||||
_def_bt = 0.25
|
_def_bt = 0.25
|
||||||
|
|
||||||
def transfer_function_rx():
|
def transfer_function_rx(symbol_rate=_def_symbol_rate):
|
||||||
# p25 c4fm de-emphasis filter
|
# p25 c4fm de-emphasis filter
|
||||||
# Specs undefined above 2,880 Hz. It would be nice to have a sharper
|
# Specs undefined above 2,880 Hz. It would be nice to have a sharper
|
||||||
# rolloff, but this filter is cheap enough....
|
# rolloff, but this filter is cheap enough....
|
||||||
xfer = [] # frequency domain transfer function
|
xfer = [] # frequency domain transfer function
|
||||||
for f in xrange(0,4800):
|
for f in xrange(0,symbol_rate):
|
||||||
# D(f)
|
# D(f)
|
||||||
t = pi * f / 4800
|
t = pi * f / symbol_rate
|
||||||
if t < 1e-6:
|
if t < 1e-6:
|
||||||
df = 1.0
|
df = 1.0
|
||||||
else:
|
else:
|
||||||
|
@ -64,7 +64,7 @@ def transfer_function_rx():
|
||||||
xfer.append(df)
|
xfer.append(df)
|
||||||
return xfer
|
return xfer
|
||||||
|
|
||||||
def transfer_function_tx():
|
def transfer_function_tx(symbol_rate=_def_symbol_rate):
|
||||||
xfer = [] # frequency domain transfer function
|
xfer = [] # frequency domain transfer function
|
||||||
for f in xrange(0, 2881): # specs cover 0 - 2,880 Hz
|
for f in xrange(0, 2881): # specs cover 0 - 2,880 Hz
|
||||||
# H(f)
|
# H(f)
|
||||||
|
@ -82,7 +82,7 @@ def transfer_function_tx():
|
||||||
xfer.append(pf * hf)
|
xfer.append(pf * hf)
|
||||||
return xfer
|
return xfer
|
||||||
|
|
||||||
def transfer_function_dmr():
|
def transfer_function_dmr(symbol_rate=_def_symbol_rate):
|
||||||
xfer = [] # frequency domain transfer function
|
xfer = [] # frequency domain transfer function
|
||||||
for f in xrange(0, 2881): # specs cover 0 - 2,880 Hz
|
for f in xrange(0, 2881): # specs cover 0 - 2,880 Hz
|
||||||
if f < 1920:
|
if f < 1920:
|
||||||
|
@ -94,6 +94,32 @@ def transfer_function_dmr():
|
||||||
xfer = np.sqrt(xfer) # root cosine
|
xfer = np.sqrt(xfer) # root cosine
|
||||||
return xfer
|
return xfer
|
||||||
|
|
||||||
|
def transfer_function_nxdn(symbol_rate=_def_symbol_rate):
|
||||||
|
assert symbol_rate == 2400 or symbol_rate == 4800
|
||||||
|
T = 1.0 / symbol_rate
|
||||||
|
a = 0.2 # rolloff
|
||||||
|
fl = int(0.5+(1-a)/(2*T))
|
||||||
|
fh = int(0.5+(1+a)/(2*T))
|
||||||
|
|
||||||
|
xfer = []
|
||||||
|
for f in xrange(0, symbol_rate):
|
||||||
|
if f < fl:
|
||||||
|
hf = 1.0
|
||||||
|
elif f >= fl and f <= fh:
|
||||||
|
hf = cos((T/(4*a)) * (2*pi*f - pi*(1-a)/T))
|
||||||
|
else:
|
||||||
|
hf = 0.0
|
||||||
|
x = pi * f * T
|
||||||
|
if f <= fh:
|
||||||
|
if x == 0 or sin(x) == 0:
|
||||||
|
df = 1.0
|
||||||
|
else:
|
||||||
|
df = x / sin(x)
|
||||||
|
else:
|
||||||
|
df = 2.0
|
||||||
|
xfer.append(hf * df)
|
||||||
|
return xfer
|
||||||
|
|
||||||
class c4fm_taps(object):
|
class c4fm_taps(object):
|
||||||
"""Generate filter coefficients as per P25 C4FM spec"""
|
"""Generate filter coefficients as per P25 C4FM spec"""
|
||||||
def __init__(self, filter_gain = 1.0, sample_rate=_def_output_sample_rate, symbol_rate=_def_symbol_rate, span=_def_span, generator=transfer_function_tx):
|
def __init__(self, filter_gain = 1.0, sample_rate=_def_output_sample_rate, symbol_rate=_def_symbol_rate, span=_def_span, generator=transfer_function_tx):
|
||||||
|
@ -105,7 +131,7 @@ class c4fm_taps(object):
|
||||||
self.generator = generator
|
self.generator = generator
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
impulse_response = np.fft.fftshift(np.fft.irfft(self.generator(), self.sample_rate))
|
impulse_response = np.fft.fftshift(np.fft.irfft(self.generator(symbol_rate=self.symbol_rate), self.sample_rate))
|
||||||
start = np.argmax(impulse_response) - (self.ntaps-1) / 2
|
start = np.argmax(impulse_response) - (self.ntaps-1) / 2
|
||||||
coeffs = impulse_response[start: start+self.ntaps]
|
coeffs = impulse_response[start: start+self.ntaps]
|
||||||
gain = self.filter_gain / sum(coeffs)
|
gain = self.filter_gain / sum(coeffs)
|
||||||
|
|
|
@ -57,6 +57,7 @@ list(APPEND op25_repeater_sources
|
||||||
op25_audio.cc
|
op25_audio.cc
|
||||||
CCITTChecksumReverse.cpp
|
CCITTChecksumReverse.cpp
|
||||||
value_string.cc
|
value_string.cc
|
||||||
|
nxdn.cc
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(gnuradio-op25_repeater SHARED ${op25_repeater_sources})
|
add_library(gnuradio-op25_repeater SHARED ${op25_repeater_sources})
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
/* -*- c++ -*- */
|
||||||
|
/*
|
||||||
|
* NXDN Encoder/Decoder (C) Copyright 2019 Max H. Parke KA1RBI
|
||||||
|
*
|
||||||
|
* This file is part of OP25
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "bit_utils.h"
|
||||||
|
|
||||||
|
#include "nxdn.h"
|
||||||
|
|
||||||
|
static const uint16_t perm_25_12[300] = { // perumtation schedule for 25x12
|
||||||
|
0,12,24,36,48,60,72,84,96,108,120,132,144,156,168,180,192,204,216,228,240,252,264,276,288,
|
||||||
|
1,13,25,37,49,61,73,85,97,109,121,133,145,157,169,181,193,205,217,229,241,253,265,277,289,
|
||||||
|
2,14,26,38,50,62,74,86,98,110,122,134,146,158,170,182,194,206,218,230,242,254,266,278,290,
|
||||||
|
3,15,27,39,51,63,75,87,99,111,123,135,147,159,171,183,195,207,219,231,243,255,267,279,291,
|
||||||
|
4,16,28,40,52,64,76,88,100,112,124,136,148,160,172,184,196,208,220,232,244,256,268,280,292,
|
||||||
|
5,17,29,41,53,65,77,89,101,113,125,137,149,161,173,185,197,209,221,233,245,257,269,281,293,
|
||||||
|
6,18,30,42,54,66,78,90,102,114,126,138,150,162,174,186,198,210,222,234,246,258,270,282,294,
|
||||||
|
7,19,31,43,55,67,79,91,103,115,127,139,151,163,175,187,199,211,223,235,247,259,271,283,295,
|
||||||
|
8,20,32,44,56,68,80,92,104,116,128,140,152,164,176,188,200,212,224,236,248,260,272,284,296,
|
||||||
|
9,21,33,45,57,69,81,93,105,117,129,141,153,165,177,189,201,213,225,237,249,261,273,285,297,
|
||||||
|
10,22,34,46,58,70,82,94,106,118,130,142,154,166,178,190,202,214,226,238,250,262,274,286,298,
|
||||||
|
11,23,35,47,59,71,83,95,107,119,131,143,155,167,179,191,203,215,227,239,251,263,275,287,299};
|
||||||
|
|
||||||
|
static const uint8_t scramble_t[] = {
|
||||||
|
2, 5, 6, 7, 10, 12, 14, 16, 17, 22, 23, 25, 26, 27, 28, 30, 33, 34, 36, 37, 38, 41, 45, 47,
|
||||||
|
52, 54, 56, 57, 59, 62, 63, 64, 65, 66, 67, 69, 70, 73, 76, 79, 81, 82, 84, 85, 86, 87, 88,
|
||||||
|
89, 92, 95, 96, 98, 100, 103, 104, 107, 108, 116, 117, 121, 122, 125, 127, 131, 132, 134,
|
||||||
|
137, 139, 140, 141, 142, 143, 144, 145, 147, 151, 153, 154, 158, 159, 160, 162, 164, 165,
|
||||||
|
168, 170, 171, 174, 175, 176, 177, 181};
|
||||||
|
|
||||||
|
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};
|
||||||
|
|
||||||
|
static inline uint16_t crc16(const uint8_t buf[], int len, uint32_t crc) {
|
||||||
|
uint32_t poly = (1<<12) + (1<<5) + (1<<0);
|
||||||
|
for(int i=0; i<len; i++) {
|
||||||
|
uint8_t bit = buf[i] & 1;
|
||||||
|
crc = ((crc << 1) | bit) & 0x1ffff;
|
||||||
|
if (crc & 0x10000)
|
||||||
|
crc = (crc & 0xffff) ^ poly;
|
||||||
|
}
|
||||||
|
crc = crc ^ 0xffff;
|
||||||
|
return crc & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trellis_1_2 encode: source is in bits, result in bits
|
||||||
|
static inline void trellis_encode(uint8_t result[], const uint8_t source[], int result_len, int reg)
|
||||||
|
{
|
||||||
|
for (int i=0; i<result_len; i+=2) {
|
||||||
|
reg = (reg << 1) | source[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)
|
||||||
|
static inline 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<NTESTC; i++) {
|
||||||
|
bt[0] = (i&8)>>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<NTEST*2; j++) {
|
||||||
|
sum += tt[j] ^ source[p*2+j];
|
||||||
|
}
|
||||||
|
if (i == 0 || sum < min_d) {
|
||||||
|
min_d = sum;
|
||||||
|
min_bt = bt[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result[p] = min_bt;
|
||||||
|
reg = (reg << 1) | min_bt;
|
||||||
|
dstats[(min_d > 3) ? 3 : min_d] += 1;
|
||||||
|
}
|
||||||
|
// fprintf (stderr, "stats\t%d %d %d %d\n", dstats[0], dstats[1], dstats[2], dstats[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nxdn_descramble(uint8_t dibits[], int len) {
|
||||||
|
for (int i=0; i<sizeof(scramble_t); i++) {
|
||||||
|
if (scramble_t[i] >= len)
|
||||||
|
break;
|
||||||
|
dibits[scramble_t[i]] ^= 0x2; // invert sign of scrambled dibits
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void decode_cac(const uint8_t dibits[], int len) {
|
||||||
|
uint8_t cacbits[300];
|
||||||
|
uint8_t deperm[300];
|
||||||
|
uint8_t depunc[350];
|
||||||
|
uint8_t decode[171];
|
||||||
|
int id=0;
|
||||||
|
uint16_t crc;
|
||||||
|
|
||||||
|
dibits_to_bits(cacbits, dibits, 150);
|
||||||
|
for (int i=0; i<300; i++) {
|
||||||
|
deperm[perm_25_12[i]] = cacbits[i];
|
||||||
|
}
|
||||||
|
for (int i=0; i<25; i++) {
|
||||||
|
depunc[id++] = deperm[i*12];
|
||||||
|
depunc[id++] = deperm[i*12+1];
|
||||||
|
depunc[id++] = deperm[i*12+2];
|
||||||
|
depunc[id++] = 0;
|
||||||
|
depunc[id++] = deperm[i*12+3];
|
||||||
|
depunc[id++] = deperm[i*12+4];
|
||||||
|
depunc[id++] = deperm[i*12+5];
|
||||||
|
depunc[id++] = deperm[i*12+6];
|
||||||
|
depunc[id++] = deperm[i*12+7];
|
||||||
|
depunc[id++] = deperm[i*12+8];
|
||||||
|
depunc[id++] = deperm[i*12+9];
|
||||||
|
depunc[id++] = 0;
|
||||||
|
depunc[id++] = deperm[i*12+10];
|
||||||
|
depunc[id++] = deperm[i*12+11];
|
||||||
|
}
|
||||||
|
trellis_decode(decode, depunc, 171);
|
||||||
|
crc = crc16(decode, 171, 0xc3ee);
|
||||||
|
if (crc != 0)
|
||||||
|
return; // ignore msg if crc failed
|
||||||
|
uint8_t msg_type = load_i(decode+8, 8) & 0x3f;
|
||||||
|
// todo: forward CAC message
|
||||||
|
}
|
||||||
|
|
||||||
|
void nxdn_frame(const uint8_t dibits[], int ndibits) {
|
||||||
|
uint8_t descrambled[182];
|
||||||
|
uint8_t lich;
|
||||||
|
uint8_t lich_test;
|
||||||
|
uint8_t bit72[72];
|
||||||
|
|
||||||
|
assert (ndibits >= 170);
|
||||||
|
memcpy(descrambled, dibits, ndibits);
|
||||||
|
nxdn_descramble(descrambled, ndibits);
|
||||||
|
lich = 0;
|
||||||
|
for (int i=0; i<8; i++)
|
||||||
|
lich |= (descrambled[i] >> 1) << (7-i);
|
||||||
|
/* todo: parity check & process LICH */
|
||||||
|
if (lich >> 1 == 0x01)
|
||||||
|
decode_cac(descrambled+8, 150);
|
||||||
|
/* todo: process E: 12 dibits at descrambed+158; */
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
//
|
||||||
|
// NXDN Encoder (C) Copyright 2019 Max H. Parke KA1RBI
|
||||||
|
// thx gr-ysf fr_vch_decoder_bb_impl.cc * Copyright 2015 Mathias Weyland *
|
||||||
|
//
|
||||||
|
// 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_NXDN_H
|
||||||
|
#define INCLUDED_NXDN_H
|
||||||
|
|
||||||
|
void nxdn_frame(const uint8_t dibits[], int ndibits);
|
||||||
|
void nxdn_descramble(uint8_t dibits[], int len);
|
||||||
|
|
||||||
|
#endif /* INCLUDED_NXDN_H */
|
|
@ -0,0 +1,32 @@
|
||||||
|
//
|
||||||
|
// NXDN Encoder (C) Copyright 2019 Max H. Parke KA1RBI
|
||||||
|
// thx gr-ysf fr_vch_decoder_bb_impl.cc * Copyright 2015 Mathias Weyland *
|
||||||
|
//
|
||||||
|
// 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_NXDN_CONST_H
|
||||||
|
#define INCLUDED_NXDN_CONST_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* postamble + frame sync (FS) */
|
||||||
|
static const uint64_t NXDN_POSTFS_SYNC_MAGIC = 0x5775fdcdf59LL;
|
||||||
|
/* frame sync + scrambled rendition of LICH=0x6e (a halfrate voice 4V) */
|
||||||
|
static const uint64_t NXDN_FS6E_SYNC_MAGIC = 0xcdf5975d7LL;
|
||||||
|
|
||||||
|
#endif /* INCLUDED_NXDN_CONST_H */
|
|
@ -207,6 +207,7 @@ void rx_sync::codeword(const uint8_t* cw, const enum codeword_types codeword_typ
|
||||||
|
|
||||||
switch(codeword_type) {
|
switch(codeword_type) {
|
||||||
case CODEWORD_DMR:
|
case CODEWORD_DMR:
|
||||||
|
case CODEWORD_NXDN_EHR: // halfrate
|
||||||
interleaver.process_vcw(cw, b);
|
interleaver.process_vcw(cw, b);
|
||||||
if (b[0] < 120)
|
if (b[0] < 120)
|
||||||
mbe_dequantizeAmbe2250Parms(&cur_mp[slot_id], &prev_mp[slot_id], b);
|
mbe_dequantizeAmbe2250Parms(&cur_mp[slot_id], &prev_mp[slot_id], b);
|
||||||
|
@ -287,6 +288,7 @@ void rx_sync::rx_sym(const uint8_t sym)
|
||||||
bool unmute;
|
bool unmute;
|
||||||
uint8_t tmpcw[144];
|
uint8_t tmpcw[144];
|
||||||
bool ysf_fullrate;
|
bool ysf_fullrate;
|
||||||
|
uint8_t dbuf[182];
|
||||||
|
|
||||||
d_symbol_count ++;
|
d_symbol_count ++;
|
||||||
d_sync_reg = (d_sync_reg << 2) | (sym & 3);
|
d_sync_reg = (d_sync_reg << 2) | (sym & 3);
|
||||||
|
@ -368,6 +370,18 @@ void rx_sync::rx_sym(const uint8_t sym)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case RX_TYPE_NXDN_CAC:
|
||||||
|
nxdn_frame(symbol_ptr+22, 170);
|
||||||
|
break;
|
||||||
|
case RX_TYPE_NXDN_EHR:
|
||||||
|
memcpy(dbuf, symbol_ptr+10, sizeof(dbuf));
|
||||||
|
nxdn_descramble(dbuf, sizeof(dbuf));
|
||||||
|
// todo: process SACCH
|
||||||
|
codeword(dbuf+38+36*0, CODEWORD_NXDN_EHR, 0);
|
||||||
|
codeword(dbuf+38+36*1, CODEWORD_NXDN_EHR, 0);
|
||||||
|
codeword(dbuf+38+36*2, CODEWORD_NXDN_EHR, 0);
|
||||||
|
codeword(dbuf+38+36*3, CODEWORD_NXDN_EHR, 0);
|
||||||
|
break;
|
||||||
case RX_N_TYPES:
|
case RX_N_TYPES:
|
||||||
assert(0==1); /* should not occur */
|
assert(0==1); /* should not occur */
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
#include "op25_imbe_frame.h"
|
#include "op25_imbe_frame.h"
|
||||||
#include "software_imbe_decoder.h"
|
#include "software_imbe_decoder.h"
|
||||||
#include "op25_audio.h"
|
#include "op25_audio.h"
|
||||||
|
#include "nxdn_const.h"
|
||||||
|
#include "nxdn.h"
|
||||||
|
|
||||||
namespace gr{
|
namespace gr{
|
||||||
namespace op25_repeater{
|
namespace op25_repeater{
|
||||||
|
@ -54,6 +56,8 @@ enum rx_types {
|
||||||
RX_TYPE_DMR,
|
RX_TYPE_DMR,
|
||||||
RX_TYPE_DSTAR,
|
RX_TYPE_DSTAR,
|
||||||
RX_TYPE_YSF,
|
RX_TYPE_YSF,
|
||||||
|
RX_TYPE_NXDN_EHR,
|
||||||
|
RX_TYPE_NXDN_CAC,
|
||||||
RX_N_TYPES
|
RX_N_TYPES
|
||||||
}; // also used as array index
|
}; // also used as array index
|
||||||
|
|
||||||
|
@ -69,7 +73,9 @@ static const struct _mode_data {
|
||||||
{"P25", 48,0,864,1728, P25_FRAME_SYNC_MAGIC},
|
{"P25", 48,0,864,1728, P25_FRAME_SYNC_MAGIC},
|
||||||
{"DMR", 48,66,144,1728, DMR_VOICE_SYNC_MAGIC},
|
{"DMR", 48,66,144,1728, DMR_VOICE_SYNC_MAGIC},
|
||||||
{"DSTAR", 48,72,96,2016*2, DSTAR_FRAME_SYNC_MAGIC},
|
{"DSTAR", 48,72,96,2016*2, DSTAR_FRAME_SYNC_MAGIC},
|
||||||
{"YSF", 40,0,480,480*2, YSF_FRAME_SYNC_MAGIC}
|
{"YSF", 40,0,480,480*2, YSF_FRAME_SYNC_MAGIC},
|
||||||
|
{"NXDN_EHR", 36,0,192,192*2, NXDN_FS6E_SYNC_MAGIC},
|
||||||
|
{"NXDN_CAC", 44,0,192,192*2, NXDN_POSTFS_SYNC_MAGIC}
|
||||||
}; // index order must match rx_types enum
|
}; // index order must match rx_types enum
|
||||||
|
|
||||||
enum codeword_types {
|
enum codeword_types {
|
||||||
|
@ -78,7 +84,8 @@ enum codeword_types {
|
||||||
CODEWORD_DMR,
|
CODEWORD_DMR,
|
||||||
CODEWORD_DSTAR,
|
CODEWORD_DSTAR,
|
||||||
CODEWORD_YSF_FULLRATE,
|
CODEWORD_YSF_FULLRATE,
|
||||||
CODEWORD_YSF_HALFRATE
|
CODEWORD_YSF_HALFRATE,
|
||||||
|
CODEWORD_NXDN_EHR
|
||||||
};
|
};
|
||||||
|
|
||||||
class rx_sync {
|
class rx_sync {
|
||||||
|
|
Loading…
Reference in New Issue