nxdn tx
This commit is contained in:
parent
5e01df4883
commit
921a1d8ea0
|
@ -2,7 +2,7 @@
|
|||
|
||||
#################################################################################
|
||||
#
|
||||
# Multiprotocol Digital Voice TX (C) Copyright 2017 Max H. Parke KA1RBI
|
||||
# Multiprotocol Digital Voice TX (C) Copyright 2017, 2018, 2019, 2020 Max H. Parke KA1RBI
|
||||
#
|
||||
# This file is part of OP25
|
||||
#
|
||||
|
@ -40,18 +40,22 @@ from op25_c4fm_mod import p25_mod_bf
|
|||
sys.path.append('..')
|
||||
from gr_gnuplot import float_sink_f
|
||||
|
||||
RC_FILTER = {'dmr': 'rrc', 'p25': 'rc', 'ysf': 'rrc', 'dstar': None}
|
||||
RC_FILTER = {'dmr': 'rrc', 'p25': 'rc', 'ysf': 'rrc', 'dstar': None, 'nxdn48': 'nxdn48', 'nxdn96': 'nxdn96'}
|
||||
|
||||
output_gains = {
|
||||
'dmr': 5.5,
|
||||
'dstar': 0.95,
|
||||
'p25': 4.5,
|
||||
'ysf': 5.5
|
||||
'ysf': 5.5,
|
||||
'nxdn48': 1.0,
|
||||
'nxdn96': 1.0
|
||||
}
|
||||
gain_adjust = {
|
||||
'dmr': 3.0,
|
||||
'dstar': 7.5,
|
||||
'ysf': 4.0
|
||||
'ysf': 4.0,
|
||||
'nxdn48': 1.0,
|
||||
'nxdn96': 1.0
|
||||
}
|
||||
gain_adjust_fullrate = {
|
||||
'p25': 2.0,
|
||||
|
@ -61,7 +65,9 @@ mod_adjust = { # rough values
|
|||
'dmr': 0.35,
|
||||
'dstar': 0.075,
|
||||
'p25': 0.33,
|
||||
'ysf': 0.42
|
||||
'ysf': 0.42,
|
||||
'nxdn48': 1.66667,
|
||||
'nxdn96': 1.93
|
||||
}
|
||||
|
||||
class my_top_block(gr.top_block):
|
||||
|
@ -94,7 +100,7 @@ class my_top_block(gr.top_block):
|
|||
parser.add_option("-N", "--gains", type="string", default=None, help="gain settings")
|
||||
parser.add_option("-O", "--audio-output", type="string", default="default", help="pcm output device name. E.g., hw:0,0 or /dev/dsp")
|
||||
parser.add_option("-o", "--output-file", type="string", default=None, help="specify the output file")
|
||||
parser.add_option("-p", "--protocol", type="choice", default=None, choices=('dmr', 'dstar', 'p25', 'ysf'), help="specify protocol: dmr, dstar, p25, ysf")
|
||||
parser.add_option("-p", "--protocol", type="choice", default=None, choices=('dmr', 'dstar', 'p25', 'ysf', 'nxdn48', 'nxdn96'), help="specify protocol: dmr, dstar, p25, ysf, nxdn48, nxdn96")
|
||||
parser.add_option("-q", "--frequency-correction", type="float", default=0.0, help="ppm")
|
||||
parser.add_option("-Q", "--frequency", type="float", default=0.0, help="Hz")
|
||||
parser.add_option("-r", "--repeat", action="store_true", default=False, help="input file repeat")
|
||||
|
@ -108,14 +114,14 @@ class my_top_block(gr.top_block):
|
|||
|
||||
max_inputs = 1
|
||||
|
||||
if options.protocol is None:
|
||||
print 'protocol [-p] option missing'
|
||||
if options.protocol is None:
|
||||
print ('protocol [-p] option missing')
|
||||
sys.exit(0)
|
||||
|
||||
if options.protocol == 'ysf' or options.protocol == 'dmr' or options.protocol == 'dstar':
|
||||
assert options.config_file # dstar, dmr and ysf require config file ("-c FILENAME" option)
|
||||
if options.protocol == 'ysf' or options.protocol == 'dmr' or options.protocol == 'dstar' or options.protocol.startswith('nxdn'):
|
||||
assert options.config_file # dstar, dmr, ysf, and nxdn require config file ("-c FILENAME" option)
|
||||
|
||||
output_gain = output_gains[options.protocol]
|
||||
output_gain = output_gains[options.protocol]
|
||||
|
||||
if options.test: # input file is in symbols of size=char
|
||||
ENCODER = blocks.file_source(gr.sizeof_char, options.test, True)
|
||||
|
@ -142,6 +148,8 @@ class my_top_block(gr.top_block):
|
|||
ENCODER.set_gain_adjust(gain_adjust_fullrate['ysf'])
|
||||
else:
|
||||
ENCODER.set_gain_adjust(gain_adjust['ysf'])
|
||||
elif options.protocol.startswith('nxdn'):
|
||||
ENCODER = op25_repeater.nxdn_tx_sb(options.verbose, options.config_file, options.protocol == 'nxdn96')
|
||||
if options.protocol == 'p25' and not options.test:
|
||||
ENCODER.set_gain_adjust(gain_adjust_fullrate[options.protocol])
|
||||
elif not options.test and not options.protocol == 'ysf':
|
||||
|
@ -209,14 +217,14 @@ class my_top_block(gr.top_block):
|
|||
f1 = float(options.if_rate) / options.alt_modulator_rate
|
||||
i1 = int(options.if_rate / options.alt_modulator_rate)
|
||||
if f1 - i1 > 1e-3:
|
||||
print '*** Error, sdr rate %d not an integer multiple of alt modulator rate %d - ratio=%f' % (options.if_rate, options.alt_modulator_rate, f1)
|
||||
print ('*** Error, sdr rate %d not an integer multiple of alt modulator rate %d - ratio=%f' % (options.if_rate, options.alt_modulator_rate, f1))
|
||||
sys.exit(0)
|
||||
a_resamp = filter.pfb.arb_resampler_fff(options.alt_modulator_rate / float(options.modulator_rate))
|
||||
sys.stderr.write('adding resampler for rate change %d ===> %d\n' % (options.modulator_rate, options.alt_modulator_rate))
|
||||
interp = filter.rational_resampler_fff(options.if_rate / options.alt_modulator_rate, 1)
|
||||
self.connect(MOD, AMP, a_resamp, interp, self.fm_modulator, self.u)
|
||||
else:
|
||||
interp = filter.rational_resampler_fff(options.if_rate / options.modulator_rate, 1)
|
||||
interp = filter.rational_resampler_fff(options.if_rate // options.modulator_rate, 1)
|
||||
self.connect(MOD, AMP, interp, self.fm_modulator, self.u)
|
||||
else:
|
||||
self.connect(MOD, AMP, OUT)
|
||||
|
@ -232,12 +240,12 @@ class my_top_block(gr.top_block):
|
|||
gain_names = self.u.get_gain_names()
|
||||
for name in gain_names:
|
||||
range = self.u.get_gain_range(name)
|
||||
print "gain: name: %s range: start %d stop %d step %d" % (name, range[0].start(), range[0].stop(), range[0].step())
|
||||
print ("gain: name: %s range: start %d stop %d step %d" % (name, range[0].start(), range[0].stop(), range[0].step()))
|
||||
if options.gains:
|
||||
for tuple in options.gains.split(","):
|
||||
name, gain = tuple.split(":")
|
||||
gain = int(gain)
|
||||
print "setting gain %s to %d" % (name, gain)
|
||||
print ("setting gain %s to %d" % (name, gain))
|
||||
self.u.set_gain(gain, name)
|
||||
|
||||
self.u.set_sample_rate(options.if_rate)
|
||||
|
@ -246,7 +254,7 @@ class my_top_block(gr.top_block):
|
|||
#self.u.set_bandwidth(options.if_rate)
|
||||
|
||||
if __name__ == "__main__":
|
||||
print 'Multiprotocol Digital Voice TX (C) Copyright 2017 Max H. Parke KA1RBI'
|
||||
print ('Multiprotocol Digital Voice TX (C) Copyright 2017-2020 Max H. Parke KA1RBI')
|
||||
try:
|
||||
my_top_block().run()
|
||||
except KeyboardInterrupt:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#################################################################################
|
||||
#
|
||||
# Multiprotocol Digital Voice TX (C) Copyright 2017 Max H. Parke KA1RBI
|
||||
# Multiprotocol Digital Voice TX (C) Copyright 2017, 2018, 2019, 2020 Max H. Parke KA1RBI
|
||||
#
|
||||
# This file is part of OP25
|
||||
#
|
||||
|
@ -73,6 +73,9 @@ class pipeline(gr.hier_block2):
|
|||
elif protocol == 'ysf':
|
||||
assert config_file
|
||||
ENCODER = op25_repeater.ysf_tx_sb(verbose, config_file, fullrate_mode)
|
||||
elif protocol.startswith('nxdn'):
|
||||
assert config_file
|
||||
ENCODER = op25_repeater.nxdn_tx_sb(verbose, config_file, protocol == 'nxdn96')
|
||||
ENCODER.set_gain_adjust(gain_adjust)
|
||||
|
||||
MOD = p25_mod_bf(output_sample_rate = sample_rate, dstar = (protocol == 'dstar'), bt = bt, rc = RC_FILTER[protocol])
|
||||
|
@ -89,7 +92,7 @@ class pipeline(gr.hier_block2):
|
|||
else:
|
||||
self.connect(self, ENCODER, MOD)
|
||||
|
||||
INTERP = filter.rational_resampler_fff(if_rate / sample_rate, 1)
|
||||
INTERP = filter.rational_resampler_fff(if_rate // sample_rate, 1)
|
||||
|
||||
MIXER = blocks.multiply_cc()
|
||||
LO = analog.sig_source_c(if_rate, analog.GR_SIN_WAVE, if_freq, 1.0, 0)
|
||||
|
@ -126,15 +129,21 @@ class my_top_block(gr.top_block):
|
|||
f1 = float(options.if_rate) / options.modulator_rate
|
||||
i1 = int(options.if_rate / options.modulator_rate)
|
||||
if f1 - i1 > 1e-3:
|
||||
print '*** Error, sdr rate %d not an integer multiple of modulator rate %d - ratio=%f' % (options.if_rate, options.modulator_rate, f1)
|
||||
print ('*** Error, sdr rate %d not an integer multiple of modulator rate %d - ratio=%f' % (options.if_rate, options.modulator_rate, f1))
|
||||
sys.exit(1)
|
||||
|
||||
protocols = 'dmr p25 dstar ysf'.split()
|
||||
protocols = 'nxdn48 dmr dstar ysf p25'.split()
|
||||
|
||||
start_freq = options.frequency
|
||||
end_freq = options.frequency + options.if_offset * (len(protocols)-1)
|
||||
tune_freq = (start_freq + end_freq) // 2
|
||||
print ('start %d end %d center tune %d' % (start_freq, end_freq, tune_freq))
|
||||
|
||||
bw = options.if_offset * len(protocols) + 50000
|
||||
if bw > options.if_rate:
|
||||
print '*** Error, a %d Hz band is required for %d channels and guardband.' % (bw, len(protocols))
|
||||
print '*** Either reduce channel spacing using -o (current value is %d Hz),' % (options.if_offset)
|
||||
print '*** or increase SDR output sample rate using -i (current rate is %d Hz)' % (options.if_rate)
|
||||
print ('*** Error, a %d Hz band is required for %d channels and guardband.' % (bw, len(protocols)))
|
||||
print ('*** Either reduce channel spacing using -o (current value is %d Hz),' % (options.if_offset) )
|
||||
print ('*** or increase SDR output sample rate using -i (current rate is %d Hz)' % (options.if_rate) )
|
||||
sys.exit(1)
|
||||
|
||||
max_inputs = 1
|
||||
|
@ -155,7 +164,7 @@ class my_top_block(gr.top_block):
|
|||
|
||||
SUM = blocks.add_cc()
|
||||
input_repeat = True
|
||||
for i in xrange(len(protocols)):
|
||||
for i in range(len(protocols)):
|
||||
SOURCE = blocks.file_source(gr.sizeof_short, options.file, input_repeat)
|
||||
protocol = protocols[i]
|
||||
if (options.fullrate_mode and protocol == 'ysf') or protocol == 'p25':
|
||||
|
@ -168,15 +177,19 @@ class my_top_block(gr.top_block):
|
|||
cfg = 'ysf-cfg.dat'
|
||||
elif protocols[i] == 'dstar':
|
||||
cfg = 'dstar-cfg.dat'
|
||||
elif protocols[i].startswith('nxdn'):
|
||||
cfg = 'nxdn-cfg.dat'
|
||||
else:
|
||||
cfg = None
|
||||
|
||||
this_freq = start_freq + i * options.if_offset
|
||||
if_freq = this_freq - tune_freq
|
||||
print ('%s\t%d\t%d\t%d' % (protocols[i], this_freq, tune_freq, if_freq))
|
||||
CHANNEL = pipeline(
|
||||
protocol = protocols[i],
|
||||
output_gain = output_gains[protocols[i]],
|
||||
gain_adjust = gain_adj,
|
||||
mod_adjust = mod_adjust[protocols[i]],
|
||||
if_freq = (i - len(protocols)/2) * options.if_offset,
|
||||
if_freq = if_freq,
|
||||
if_rate = options.if_rate,
|
||||
sample_rate = options.modulator_rate,
|
||||
bt = options.bt,
|
||||
|
@ -187,29 +200,30 @@ class my_top_block(gr.top_block):
|
|||
|
||||
self.u = osmosdr.sink (options.args)
|
||||
AMP = blocks.multiply_const_cc(1.0 / float(len(protocols)))
|
||||
self.setup_sdr_output(options)
|
||||
self.setup_sdr_output(options, tune_freq)
|
||||
|
||||
self.connect(SUM, AMP, self.u)
|
||||
|
||||
def setup_sdr_output(self, options):
|
||||
def setup_sdr_output(self, options, tune_freq):
|
||||
gain_names = self.u.get_gain_names()
|
||||
for name in gain_names:
|
||||
range = self.u.get_gain_range(name)
|
||||
print "gain: name: %s range: start %d stop %d step %d" % (name, range[0].start(), range[0].stop(), range[0].step())
|
||||
print ("gain: name: %s range: start %d stop %d step %d" % (name, range[0].start(), range[0].stop(), range[0].step()))
|
||||
if options.gains:
|
||||
for tuple in options.gains.split(","):
|
||||
name, gain = tuple.split(":")
|
||||
gain = int(gain)
|
||||
print "setting gain %s to %d" % (name, gain)
|
||||
print ("setting gain %s to %d" % (name, gain))
|
||||
self.u.set_gain(gain, name)
|
||||
|
||||
print 'setting sample rate'
|
||||
print ('setting sample rate %d' % options.if_rate)
|
||||
self.u.set_sample_rate(options.if_rate)
|
||||
self.u.set_center_freq(options.frequency)
|
||||
print ('setting SDR tuning frequency %d' % tune_freq)
|
||||
self.u.set_center_freq(tune_freq)
|
||||
self.u.set_freq_corr(options.frequency_correction)
|
||||
|
||||
if __name__ == "__main__":
|
||||
print 'Multiprotocol Digital Voice TX (C) Copyright 2017 Max H. Parke KA1RBI'
|
||||
print ('Multiprotocol Digital Voice TX (C) Copyright 2017-2020 Max H. Parke KA1RBI')
|
||||
try:
|
||||
my_top_block().run()
|
||||
except KeyboardInterrupt:
|
||||
|
|
|
@ -159,7 +159,7 @@ class gmsk_taps(object):
|
|||
self.span = span
|
||||
self.bt = bt
|
||||
|
||||
self.samples_per_symbol = self.sample_rate / self.symbol_rate
|
||||
self.samples_per_symbol = self.sample_rate // self.symbol_rate
|
||||
self.ntaps = self.span * self.samples_per_symbol
|
||||
|
||||
def generate(self):
|
||||
|
@ -216,7 +216,10 @@ class p25_mod_bf(gr.hier_block2):
|
|||
gr.io_signature(1, 1, gr.sizeof_char), # Input signature
|
||||
gr.io_signature(1, 1, gr.sizeof_float)) # Output signature
|
||||
|
||||
input_sample_rate = 4800 # P25 baseband symbol rate
|
||||
input_sample_rate = 4800 # P25/ysf/dmr/dstar baseband symbol rate
|
||||
if rc == 'nxdn48':
|
||||
input_sample_rate = 2400 # only exception is nxdn48 = 2400 rate
|
||||
|
||||
intermediate_rate = 48000
|
||||
self._interp_factor = intermediate_rate / input_sample_rate
|
||||
|
||||
|
@ -235,13 +238,15 @@ class p25_mod_bf(gr.hier_block2):
|
|||
|
||||
self.generator = generator
|
||||
|
||||
assert rc is None or rc == 'rc' or rc == 'rrc'
|
||||
assert rc is None or rc == 'rc' or rc == 'rrc' or rc.startswith('nxdn')
|
||||
if rc:
|
||||
coeffs = filter.firdes.root_raised_cosine(1.0, intermediate_rate, input_sample_rate, 0.2, 91)
|
||||
if rc == 'rc':
|
||||
coeffs = c4fm_taps(sample_rate=intermediate_rate).generate()
|
||||
elif self.dstar:
|
||||
coeffs = gmsk_taps(sample_rate=intermediate_rate, bt=self.bt).generate()
|
||||
elif rc.startswith('nxdn'):
|
||||
coeffs = c4fm_taps(sample_rate=intermediate_rate, generator=transfer_function_nxdn_tx, symbol_rate=input_sample_rate).generate()
|
||||
elif not rc:
|
||||
coeffs = c4fm_taps(sample_rate=intermediate_rate, generator=self.generator).generate()
|
||||
self.filter = filter.interp_fir_filter_fff(self._interp_factor, coeffs)
|
||||
|
|
|
@ -29,5 +29,6 @@ install(FILES
|
|||
ambe_encoder_sb.h
|
||||
ysf_tx_sb.h
|
||||
dstar_tx_sb.h
|
||||
nxdn_tx_sb.h
|
||||
fsk4_slicer_fb.h DESTINATION include/op25_repeater
|
||||
)
|
||||
|
|
|
@ -28,6 +28,7 @@ list(APPEND op25_repeater_sources
|
|||
ambe_encoder_sb_impl.cc
|
||||
dmr_bs_tx_bb_impl.cc
|
||||
ysf_tx_sb_impl.cc
|
||||
nxdn_tx_sb_impl.cc
|
||||
dstar_tx_sb_impl.cc
|
||||
vocoder_impl.cc
|
||||
gardner_costas_cc_impl.cc
|
||||
|
|
|
@ -121,7 +121,7 @@ void nxdn_descramble(uint8_t dibits[], int len) {
|
|||
}
|
||||
}
|
||||
|
||||
static inline void decode_cac(const uint8_t dibits[], int len) {
|
||||
static inline void decode_cac(const uint8_t dibits[], int len, uint8_t*answer, int*answer_len) {
|
||||
uint8_t cacbits[300];
|
||||
uint8_t deperm[300];
|
||||
uint8_t depunc[350];
|
||||
|
@ -151,13 +151,25 @@ static inline void decode_cac(const uint8_t dibits[], int len) {
|
|||
}
|
||||
trellis_decode(decode, depunc, 171);
|
||||
crc = crc16(decode, 171, 0xc3ee);
|
||||
if (crc != 0)
|
||||
if (crc != 0) {
|
||||
*answer_len = 0;
|
||||
return; // ignore msg if crc failed
|
||||
}
|
||||
uint8_t msg_type = load_i(decode+8, 8) & 0x3f;
|
||||
// result length after crc and 3 zero bits removed = 152 = 19 bytes
|
||||
for (int i=0; i<19; i++) {
|
||||
uint8_t c = 0;
|
||||
for (int j=0; j<8; j++) {
|
||||
c = (c << 1) | (decode[(i*8)+j] & 1);
|
||||
}
|
||||
answer[i] = c;
|
||||
}
|
||||
assert (*answer_len >= 19);
|
||||
*answer_len = 19; /* return 19 bytes */
|
||||
// todo: forward CAC message
|
||||
}
|
||||
|
||||
void nxdn_frame(const uint8_t dibits[], int ndibits) {
|
||||
void nxdn_frame(const uint8_t dibits[], int ndibits, uint8_t*answer, int*answer_len) {
|
||||
uint8_t descrambled[182];
|
||||
uint8_t lich;
|
||||
uint8_t lich_test;
|
||||
|
@ -171,6 +183,8 @@ void nxdn_frame(const uint8_t dibits[], int ndibits) {
|
|||
lich |= (descrambled[i] >> 1) << (7-i);
|
||||
/* todo: parity check & process LICH */
|
||||
if (lich >> 1 == 0x01)
|
||||
decode_cac(descrambled+8, 150);
|
||||
decode_cac(descrambled+8, 150, answer, answer_len);
|
||||
else
|
||||
*answer_len = 0;
|
||||
/* todo: process E: 12 dibits at descrambed+158; */
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#ifndef INCLUDED_NXDN_H
|
||||
#define INCLUDED_NXDN_H
|
||||
|
||||
void nxdn_frame(const uint8_t dibits[], int ndibits);
|
||||
void nxdn_frame(const uint8_t dibits[], int ndibits, uint8_t*answer, int*answer_len);
|
||||
void nxdn_descramble(uint8_t dibits[], int len);
|
||||
|
||||
#endif /* INCLUDED_NXDN_H */
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
/* 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_CONV_SYNC_MAGIC = 0xcdf59d5dfLL;
|
||||
static const uint64_t NXDN_FS6E_SYNC_MAGIC = 0xcdf5975d7LL;
|
||||
|
||||
#endif /* INCLUDED_NXDN_CONST_H */
|
||||
|
|
|
@ -274,12 +274,11 @@ static const int MAX_OUT = 1;
|
|||
d_verbose_flag(verbose_flag),
|
||||
d_config_file(config_file),
|
||||
d_nxdn96_mode(nxdn96_mode),
|
||||
d_output_amount(0),
|
||||
d_output_amount((nxdn96_mode) ? 384 : 192);
|
||||
d_sacch_seq(0),
|
||||
d_lich(0),
|
||||
d_ran(0)
|
||||
{
|
||||
d_output_amount = (nxdn96_mode) ? 384 : 192;
|
||||
set_output_multiple(d_output_amount);
|
||||
memset(d_acch, 0, sizeof(d_acch));
|
||||
config();
|
||||
|
|
|
@ -458,6 +458,8 @@ void rx_sync::rx_sym(const uint8_t sym)
|
|||
uint8_t tmpcw[144];
|
||||
bool ysf_fullrate;
|
||||
uint8_t dbuf[182];
|
||||
int answer_len=0;
|
||||
uint8_t answer[128];
|
||||
|
||||
d_symbol_count ++;
|
||||
d_sync_reg = (d_sync_reg << 2) | (sym & 3);
|
||||
|
@ -540,16 +542,15 @@ void rx_sync::rx_sym(const uint8_t sym)
|
|||
}
|
||||
break;
|
||||
case RX_TYPE_NXDN_CAC:
|
||||
nxdn_frame(symbol_ptr+22, 170);
|
||||
answer_len = sizeof(answer);
|
||||
nxdn_frame(symbol_ptr+22, 170, answer, &answer_len);
|
||||
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);
|
||||
for (int vcw = 0; vcw < 4; vcw++)
|
||||
codeword(dbuf+38+36*vcw, CODEWORD_NXDN_EHR, 0);
|
||||
break;
|
||||
case RX_N_TYPES:
|
||||
assert(0==1); /* should not occur */
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "op25_repeater/ambe_encoder_sb.h"
|
||||
#include "op25_repeater/dmr_bs_tx_bb.h"
|
||||
#include "op25_repeater/ysf_tx_sb.h"
|
||||
#include "op25_repeater/nxdn_tx_sb.h"
|
||||
#include "op25_repeater/dstar_tx_sb.h"
|
||||
%}
|
||||
|
||||
|
@ -28,6 +29,9 @@ GR_SWIG_BLOCK_MAGIC2(op25_repeater, dmr_bs_tx_bb);
|
|||
%include "op25_repeater/ysf_tx_sb.h"
|
||||
GR_SWIG_BLOCK_MAGIC2(op25_repeater, ysf_tx_sb);
|
||||
|
||||
%include "op25_repeater/nxdn_tx_sb.h"
|
||||
GR_SWIG_BLOCK_MAGIC2(op25_repeater, nxdn_tx_sb);
|
||||
|
||||
%include "op25_repeater/dstar_tx_sb.h"
|
||||
GR_SWIG_BLOCK_MAGIC2(op25_repeater, dstar_tx_sb);
|
||||
|
||||
|
|
Loading…
Reference in New Issue