summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax <ikj1234i@yahoo.com>2017-12-22 20:08:10 -0500
committerMax <ikj1234i@yahoo.com>2017-12-22 20:08:10 -0500
commite79d7eaabc3420c5e2197af4f2eea82a9c83d5f6 (patch)
treeb6e38b8c62b88907ff6fe0d9351f21298524ebda
parent5601e5290ee053b1638b27dac5b3fd6935cbd3ab (diff)
rx_sync additions
-rw-r--r--op25/gr-op25_repeater/include/op25_repeater/CMakeLists.txt1
-rw-r--r--op25/gr-op25_repeater/include/op25_repeater/frame_assembler.h59
-rw-r--r--op25/gr-op25_repeater/lib/CMakeLists.txt4
-rw-r--r--op25/gr-op25_repeater/lib/frame_assembler_impl.cc96
-rw-r--r--op25/gr-op25_repeater/lib/frame_assembler_impl.h70
-rw-r--r--op25/gr-op25_repeater/lib/rx_sync.cc377
-rw-r--r--op25/gr-op25_repeater/lib/rx_sync.h122
7 files changed, 729 insertions, 0 deletions
diff --git a/op25/gr-op25_repeater/include/op25_repeater/CMakeLists.txt b/op25/gr-op25_repeater/include/op25_repeater/CMakeLists.txt
index 0fbd32c..b93833a 100644
--- a/op25/gr-op25_repeater/include/op25_repeater/CMakeLists.txt
+++ b/op25/gr-op25_repeater/include/op25_repeater/CMakeLists.txt
@@ -25,6 +25,7 @@ install(FILES
vocoder.h
gardner_costas_cc.h
p25_frame_assembler.h
+ frame_assembler.h
ambe_encoder_sb.h
fsk4_slicer_fb.h DESTINATION include/op25_repeater
)
diff --git a/op25/gr-op25_repeater/include/op25_repeater/frame_assembler.h b/op25/gr-op25_repeater/include/op25_repeater/frame_assembler.h
new file mode 100644
index 0000000..086a1ba
--- /dev/null
+++ b/op25/gr-op25_repeater/include/op25_repeater/frame_assembler.h
@@ -0,0 +1,59 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2017 Max H. Parke KA1RBI
+ *
+ * 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.
+ */
+
+
+#ifndef INCLUDED_OP25_REPEATER_FRAME_ASSEMBLER_H
+#define INCLUDED_OP25_REPEATER_FRAME_ASSEMBLER_H
+
+#include <op25_repeater/api.h>
+#include <gnuradio/block.h>
+#include <gnuradio/msg_queue.h>
+
+namespace gr {
+ namespace op25_repeater {
+
+ /*!
+ * \brief <+description of block+>
+ * \ingroup op25_repeater
+ *
+ */
+ class OP25_REPEATER_API frame_assembler : virtual public gr::block
+ {
+ public:
+ typedef boost::shared_ptr<frame_assembler> sptr;
+
+ /*!
+ * \brief Return a shared_ptr to a new instance of op25_repeater::frame_assembler.
+ *
+ * To avoid accidental use of raw pointers, op25_repeater::frame_assembler's
+ * constructor is in a private implementation
+ * class. op25_repeater::frame_assembler::make is the public interface for
+ * creating new instances.
+ */
+ static sptr make(const char* options, int debug, gr::msg_queue::sptr queue);
+ virtual void set_xormask(const char*p) {}
+ virtual void set_slotid(int slotid) {}
+ };
+
+ } // namespace op25_repeater
+} // namespace gr
+
+#endif /* INCLUDED_OP25_REPEATER_FRAME_ASSEMBLER_H */
+
diff --git a/op25/gr-op25_repeater/lib/CMakeLists.txt b/op25/gr-op25_repeater/lib/CMakeLists.txt
index 361f266..8e73154 100644
--- a/op25/gr-op25_repeater/lib/CMakeLists.txt
+++ b/op25/gr-op25_repeater/lib/CMakeLists.txt
@@ -32,6 +32,7 @@ list(APPEND op25_repeater_sources
vocoder_impl.cc
gardner_costas_cc_impl.cc
p25_frame_assembler_impl.cc
+ frame_assembler_impl.cc
fsk4_slicer_fb_impl.cc )
list(APPEND op25_repeater_sources
@@ -52,6 +53,9 @@ list(APPEND op25_repeater_sources
ambe.c
mbelib.c
ambe_encoder.cc
+ rx_sync.cc
+ op25_audio.cc
+ CCITTChecksumReverse.cpp
)
add_library(gnuradio-op25_repeater SHARED ${op25_repeater_sources})
diff --git a/op25/gr-op25_repeater/lib/frame_assembler_impl.cc b/op25/gr-op25_repeater/lib/frame_assembler_impl.cc
new file mode 100644
index 0000000..8760a1f
--- /dev/null
+++ b/op25/gr-op25_repeater/lib/frame_assembler_impl.cc
@@ -0,0 +1,96 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Max H. Parke KA1RBI
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gnuradio/io_signature.h>
+#include "frame_assembler_impl.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <vector>
+#include <sys/time.h>
+
+namespace gr {
+ namespace op25_repeater {
+
+ void frame_assembler_impl::set_xormask(const char*p) {
+ }
+
+ void frame_assembler_impl::set_slotid(int slotid) {
+ }
+
+ frame_assembler::sptr
+ frame_assembler::make(const char* options, int debug, gr::msg_queue::sptr queue)
+ {
+ return gnuradio::get_initial_sptr
+ (new frame_assembler_impl(options, debug, queue));
+ }
+
+ /*
+ * The private constructor
+ */
+
+ /*
+ * Our virtual destructor.
+ */
+ frame_assembler_impl::~frame_assembler_impl()
+ {
+ }
+
+static const int MIN_IN = 1; // mininum number of input streams
+static const int MAX_IN = 1; // maximum number of input streams
+
+/*
+ * The private constructor
+ */
+ frame_assembler_impl::frame_assembler_impl(const char* options, int debug, gr::msg_queue::sptr queue)
+ : gr::block("frame_assembler",
+ gr::io_signature::make (MIN_IN, MAX_IN, sizeof (char)),
+ gr::io_signature::make (0, 0, 0)),
+ d_msg_queue(queue),
+ d_sync(options, debug)
+{
+}
+
+int
+frame_assembler_impl::general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+
+ const uint8_t *in = (const uint8_t *) input_items[0];
+
+ for (int i=0; i<ninput_items[0]; i++)
+ d_sync.rx_sym(in[i]);
+ consume_each(ninput_items[0]);
+ // Tell runtime system how many output items we produced.
+ return 0;
+}
+
+ } /* namespace op25_repeater */
+} /* namespace gr */
diff --git a/op25/gr-op25_repeater/lib/frame_assembler_impl.h b/op25/gr-op25_repeater/lib/frame_assembler_impl.h
new file mode 100644
index 0000000..a869c5e
--- /dev/null
+++ b/op25/gr-op25_repeater/lib/frame_assembler_impl.h
@@ -0,0 +1,70 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Max H. Parke KA1RBI
+ *
+ * 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.
+ */
+
+#ifndef INCLUDED_OP25_REPEATER_FRAME_ASSEMBLER_IMPL_H
+#define INCLUDED_OP25_REPEATER_FRAME_ASSEMBLER_IMPL_H
+
+#include <op25_repeater/frame_assembler.h>
+
+#include <gnuradio/msg_queue.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <deque>
+
+#include "rx_sync.h"
+
+typedef std::deque<uint8_t> dibit_queue;
+
+namespace gr {
+ namespace op25_repeater {
+
+ class frame_assembler_impl : public frame_assembler
+ {
+ private:
+ int d_debug;
+ gr::msg_queue::sptr d_msg_queue;
+ rx_sync d_sync;
+
+ // internal functions
+
+ void queue_msg(int duid);
+ void set_xormask(const char*p) ;
+ void set_slotid(int slotid) ;
+
+ public:
+
+ public:
+ frame_assembler_impl(const char* options, int debug, gr::msg_queue::sptr queue);
+ ~frame_assembler_impl();
+
+ // Where all the action really happens
+
+ int general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } // namespace op25_repeater
+} // namespace gr
+
+#endif /* INCLUDED_OP25_REPEATER_FRAME_ASSEMBLER_IMPL_H */
diff --git a/op25/gr-op25_repeater/lib/rx_sync.cc b/op25/gr-op25_repeater/lib/rx_sync.cc
new file mode 100644
index 0000000..1ca7f8e
--- /dev/null
+++ b/op25/gr-op25_repeater/lib/rx_sync.cc
@@ -0,0 +1,377 @@
+// P25 Decoder (C) Copyright 2013, 2014, 2015, 2016, 2017 Max H. Parke KA1RBI
+//
+// 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 <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+#include <iostream>
+#include <deque>
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "rx_sync.h"
+
+#include "bit_utils.h"
+
+#include "check_frame_sync.h"
+
+#include "p25p2_vf.h"
+#include "mbelib.h"
+#include "ambe.h"
+#include "rs.h"
+#include "crc16.h"
+
+#include "ysf_const.h"
+#include "dmr_const.h"
+#include "p25_frame.h"
+#include "op25_imbe_frame.h"
+#include "software_imbe_decoder.h"
+#include "op25_audio.h"
+
+namespace gr{
+ namespace op25_repeater{
+
+void rx_sync::cbuf_insert(const uint8_t c) {
+ d_cbuf[d_cbuf_idx] = c;
+ d_cbuf[d_cbuf_idx + CBUF_SIZE] = c;
+ d_cbuf_idx = (d_cbuf_idx + 1) % CBUF_SIZE;
+}
+
+void rx_sync::sync_reset(void) {
+ d_threshold = 0;
+ d_shift_reg = 0;
+ d_unmute_until[0] = 0;
+ d_unmute_until[1] = 0;
+}
+
+static int ysf_decode_fich(const uint8_t src[100], uint8_t dest[32]) { // input is 100 dibits, result is 32 bits
+// return -1 on decode error, else 0
+ static const int pc[] = {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};
+ uint8_t buf[100];
+ for (int i=0; i<20; i++) {
+ for (int j=0; j<5; j++) {
+ buf[j+i*5] = src[i+j*20];
+ }
+ }
+ uint8_t dr = 0;
+ uint8_t ans[100];
+ /* fake trellis decode */
+ /* TODO: make less fake */
+ for (int i=0; i<100; i++) {
+ uint8_t sym = buf[i];
+ uint8_t d0 = ((dr << 1) | 0) & 0x1f;
+ uint8_t r0 = (pc[ d0 & 0x19 ] << 1) + pc[ d0 & 0x17];
+ uint8_t d1 = ((dr << 1) | 1) & 0x1f;
+ uint8_t r1 = (pc[ d1 & 0x19 ] << 1) + pc[ d1 & 0x17];
+ if (sym == r0) {
+ ans[i] = 0;
+ dr = d0;
+ } else if (sym == r1) {
+ ans[i] = 1;
+ dr = d1;
+ } else {
+ return -1; /* decode error */
+ }
+ }
+ uint8_t fich_bits[12*4];
+ store_i(gly24128Dec(load_i(ans+24*0, 24)), fich_bits+12*0, 12);
+ store_i(gly24128Dec(load_i(ans+24*1, 24)), fich_bits+12*1, 12);
+ store_i(gly24128Dec(load_i(ans+24*2, 24)), fich_bits+12*2, 12);
+ store_i(gly24128Dec(load_i(ans+24*3, 24)), fich_bits+12*3, 12);
+ uint16_t crc_result = crc16(fich_bits, 48);
+ if (crc_result != 0)
+ return -1; // crc failure
+ memcpy(dest, fich_bits, 32);
+ return 0;
+}
+
+void rx_sync::ysf_sync(const uint8_t dibitbuf[], bool& ysf_fullrate, bool& unmute) {
+ uint8_t fich_buf[32];
+ int rc = ysf_decode_fich(dibitbuf+20, fich_buf);
+ if (rc == 0) {
+ uint32_t fich = load_i(fich_buf, 32);
+ uint32_t dt = (fich >> 8) & 3;
+ d_shift_reg = dt;
+ }
+ switch(d_shift_reg) {
+ case 0: // voice/data mode 1
+ unmute = false;
+ break;
+ case 1: // data mode
+ unmute = false;
+ break;
+ case 2: // voice/data mode 2
+ unmute = true;
+ ysf_fullrate = false;
+ break;
+ case 3: // voice fr mode
+ unmute = true;
+ ysf_fullrate = true;
+ break;
+ }
+ if (d_debug > 5 && !unmute)
+ fprintf(stderr, "ysf_sync: muting audio: dt: %d, rc: %d\n", d_shift_reg, rc);
+}
+
+void rx_sync::dmr_sync(const uint8_t bitbuf[], int& current_slot, bool& unmute) {
+ static const int slot_ids[] = {0, 1, 0, 0, 1, 1, 0, 1};
+ int tact;
+ int chan;
+ int fstype;
+ uint8_t tactbuf[sizeof(cach_tact_bits)];
+
+ for (size_t i=0; i<sizeof(cach_tact_bits); i++)
+ tactbuf[i] = bitbuf[cach_tact_bits[i]];
+ tact = hamming_7_4_decode[load_i(tactbuf, 7)];
+ chan = (tact>>2) & 1;
+ d_shift_reg = (d_shift_reg << 1) + chan;
+ current_slot = slot_ids[d_shift_reg & 7];
+
+ uint64_t sync = load_reg64(bitbuf + (MODE_DATA[RX_TYPE_DMR].sync_offset << 1), MODE_DATA[RX_TYPE_DMR].sync_len);
+ if (check_frame_sync(DMR_VOICE_SYNC_MAGIC ^ sync, d_threshold, MODE_DATA[RX_TYPE_DMR].sync_len))
+ fstype = 1;
+ else if (check_frame_sync(DMR_IDLE_SYNC_MAGIC ^ sync, d_threshold, MODE_DATA[RX_TYPE_DMR].sync_len))
+ fstype = 2;
+ else
+ fstype = 0;
+ if (fstype > 0)
+ d_expires = d_symbol_count + MODE_DATA[d_current_type].expiration;
+ if (fstype == 1) {
+ if (!d_unmute_until[current_slot] && d_debug > 5)
+ fprintf(stderr, "unmute slot %d\n", current_slot);
+ d_unmute_until[current_slot] = d_symbol_count + MODE_DATA[d_current_type].expiration;
+ } else if (fstype == 2) {
+ if (d_unmute_until[current_slot] && d_debug > 5)
+ fprintf(stderr, "mute slot %d\n", current_slot);
+ d_unmute_until[current_slot] = 0;
+ }
+ if (d_unmute_until[current_slot] <= d_symbol_count) {
+ d_unmute_until[current_slot] = 0;
+ }
+ unmute = d_unmute_until[current_slot] > 0;
+}
+
+rx_sync::rx_sync(const char * options, int debug) : // constructor
+ d_symbol_count(0),
+ d_sync_reg(0),
+ d_cbuf_idx(0),
+ d_current_type(RX_TYPE_NONE),
+ d_rx_count(0),
+ d_expires(0),
+ d_stereo(false),
+ d_debug(debug),
+ d_audio(options, debug)
+{
+ mbe_initMbeParms (&cur_mp[0], &prev_mp[0], &enh_mp[0]);
+ mbe_initMbeParms (&cur_mp[1], &prev_mp[1], &enh_mp[1]);
+ sync_reset();
+}
+
+rx_sync::~rx_sync() // destructor
+{
+}
+
+
+void rx_sync::codeword(const uint8_t* cw, const enum codeword_types codeword_type, int slot_id) {
+ static const int x=4;
+ static const int y=26;
+ static const uint8_t majority[8] = {0,0,0,1,0,1,1,1};
+
+ int b[9];
+ uint8_t buf[4*26];
+ uint8_t tmp_codeword [144];
+ uint32_t E0, ET;
+ uint32_t u[8];
+ bool do_fullrate = false;
+ bool do_silence = false;
+ voice_codeword fullrate_cw(voice_codeword_sz);
+
+ switch(codeword_type) {
+ case CODEWORD_DMR:
+ interleaver.process_vcw(cw, b);
+ if (b[0] < 120)
+ mbe_dequantizeAmbe2250Parms(&cur_mp[slot_id], &prev_mp[slot_id], b);
+ break;
+ case CODEWORD_DSTAR:
+ interleaver.decode_dstar(cw, b, false);
+ if (b[0] < 120)
+ mbe_dequantizeAmbe2400Parms(&cur_mp[slot_id], &prev_mp[slot_id], b);
+ break;
+ case CODEWORD_YSF_HALFRATE: // 104 bits
+ for (int i=0; i<x; i++) {
+ for (int j=0; j<y; j++)
+ buf[j+i*y] = cw[i+j*x];
+ }
+ ysf_scramble(buf, 104);
+ for (int i=0; i<27; i++)
+ tmp_codeword[i] = majority[ (buf[0+i*3] << 2) | (buf[1+i*3] << 1) | buf[2+i*3] ];
+
+ memcpy(tmp_codeword+27, buf+81, 22);
+ decode_49bit(b, tmp_codeword);
+ if (b[0] < 120)
+ mbe_dequantizeAmbe2250Parms(&cur_mp[slot_id], &prev_mp[slot_id], b);
+ break;
+ case CODEWORD_P25P2:
+ break;
+ case CODEWORD_P25P1: // 144 bits
+ for (int i=0; i<144; i++)
+ fullrate_cw[i] = cw[i];
+ imbe_header_decode(fullrate_cw, u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], E0, ET);
+ do_fullrate = true;
+ break;
+ case CODEWORD_YSF_FULLRATE: // 144 bits
+ for (int i=0; i<144; i++)
+ fullrate_cw[i] = cw[ysf_permutation[i]];
+ imbe_header_decode(fullrate_cw, u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], E0, ET);
+ do_fullrate = true;
+ break;
+ }
+ mbe_moveMbeParms (&cur_mp[slot_id], &prev_mp[slot_id]);
+ if (do_fullrate) {
+ d_software_decoder[slot_id].decode(fullrate_cw);
+ } else { /* halfrate */
+ if (b[0] >= 120) {
+ do_silence = true;
+ } else {
+ d_software_decoder[slot_id].decode_tap(cur_mp[slot_id].L, 0, cur_mp[slot_id].w0, &cur_mp[slot_id].Vl[1], &cur_mp[slot_id].Ml[1]);
+ }
+ }
+ audio_samples *samples = d_software_decoder[slot_id].audio();
+ float snd;
+ int16_t samp_buf[NSAMP_OUTPUT];
+ for (int i=0; i < NSAMP_OUTPUT; i++) {
+ if ((!do_silence) && samples->size() > 0) {
+ snd = samples->front();
+ samples->pop_front();
+ } else {
+ snd = 0;
+ }
+ if (do_fullrate)
+ snd *= 32768.0;
+ samp_buf[i] = snd;
+ }
+ output(samp_buf, slot_id);
+}
+
+void rx_sync::output(int16_t * samp_buf, const ssize_t slot_id) {
+ if (!d_stereo) {
+ d_audio.send_audio_channel(samp_buf, NSAMP_OUTPUT * sizeof(int16_t), slot_id);
+ return;
+ }
+}
+
+void rx_sync::rx_sym(const uint8_t sym)
+{
+ uint8_t bitbuf[864*2];
+ enum rx_types sync_detected = RX_TYPE_NONE;
+ int current_slot;
+ bool unmute;
+ uint8_t tmpcw[144];
+ bool ysf_fullrate;
+
+ d_symbol_count ++;
+ d_sync_reg = (d_sync_reg << 2) | (sym & 3);
+ for (int i = 1; i < RX_N_TYPES; i++) {
+ if (check_frame_sync(MODE_DATA[i].sync ^ d_sync_reg, (i == d_current_type) ? d_threshold : 0, MODE_DATA[i].sync_len)) {
+ sync_detected = (enum rx_types) i;
+ break;
+ }
+ }
+ cbuf_insert(sym);
+ if (d_current_type == RX_TYPE_NONE && sync_detected == RX_TYPE_NONE)
+ return;
+ d_rx_count ++;
+ if (sync_detected != RX_TYPE_NONE) {
+ if (d_current_type != sync_detected) {
+ d_current_type = sync_detected;
+ d_expires = d_symbol_count + MODE_DATA[d_current_type].expiration;
+ d_rx_count = 0;
+ }
+ if (d_rx_count != MODE_DATA[d_current_type].sync_offset + (MODE_DATA[d_current_type].sync_len >> 1)) {
+ if (d_debug)
+ fprintf(stderr, "resync at count %d for protocol %s\n", d_rx_count, MODE_DATA[d_current_type].type);
+ sync_reset();
+ d_rx_count = MODE_DATA[d_current_type].sync_offset + (MODE_DATA[d_current_type].sync_len >> 1);
+ } else {
+ d_threshold = std::min(d_threshold + 1, 2);
+ }
+ d_expires = d_symbol_count + MODE_DATA[d_current_type].expiration;
+ }
+ if (d_symbol_count >= d_expires) {
+ if (d_debug)
+ fprintf(stderr, "%s: timeout, symbol %d\n", MODE_DATA[d_current_type].type, d_symbol_count);
+ d_current_type = RX_TYPE_NONE;
+ return;
+ }
+ if (d_rx_count < MODE_DATA[d_current_type].fragment_len)
+ return;
+ d_rx_count = 0;
+ int start_idx = d_cbuf_idx + CBUF_SIZE - MODE_DATA[d_current_type].fragment_len;
+ assert (start_idx >= 0);
+ uint8_t * symbol_ptr = d_cbuf+start_idx;
+ uint8_t * bit_ptr = symbol_ptr;
+ if (d_current_type != RX_TYPE_DSTAR) {
+ dibits_to_bits(bitbuf, symbol_ptr, MODE_DATA[d_current_type].fragment_len);
+ bit_ptr = bitbuf;
+ }
+ switch (d_current_type) {
+ case RX_TYPE_NONE:
+ break;
+ case RX_TYPE_P25:
+ for (unsigned int codeword_ct=0; codeword_ct < nof_voice_codewords; codeword_ct++) {
+ for (unsigned int i=0; i<voice_codeword_sz; i++)
+ tmpcw[i] = bit_ptr[voice_codeword_bits[codeword_ct][i]];
+ codeword(tmpcw, CODEWORD_P25P1, 0); // 144 bits
+ }
+ break;
+ case RX_TYPE_DMR:
+ dmr_sync(bit_ptr, current_slot, unmute);
+ if (!unmute)
+ break;
+ codeword(symbol_ptr+12, CODEWORD_DMR, current_slot);
+ memcpy(tmpcw, symbol_ptr+48, 18);
+ memcpy(tmpcw+18, symbol_ptr+90, 18);
+ codeword(tmpcw, CODEWORD_DMR, current_slot);
+ codeword(symbol_ptr+108, CODEWORD_DMR, current_slot);
+ break;
+ case RX_TYPE_DSTAR:
+ codeword(bit_ptr, CODEWORD_DSTAR, 0); // 72 bits = 72 symbols
+ break;
+ case RX_TYPE_YSF:
+ ysf_sync(symbol_ptr, ysf_fullrate, unmute);
+ if (!unmute)
+ break;
+ for (int vcw = 0; vcw < 5; vcw++) {
+ if (ysf_fullrate) {
+ codeword(bit_ptr + 2*(vcw*72 + 120), CODEWORD_YSF_FULLRATE, 0); // 144 bits
+ } else { /* halfrate */
+ codeword(bit_ptr + 2*(vcw*72 + 120 + 20), CODEWORD_YSF_HALFRATE, 0); // 104 bits
+ }
+ }
+ break;
+ case RX_N_TYPES:
+ assert(0==1); /* should not occur */
+ break;
+ }
+}
+ } // end namespace op25_repeater
+} // end namespace gr
diff --git a/op25/gr-op25_repeater/lib/rx_sync.h b/op25/gr-op25_repeater/lib/rx_sync.h
new file mode 100644
index 0000000..bbad158
--- /dev/null
+++ b/op25/gr-op25_repeater/lib/rx_sync.h
@@ -0,0 +1,122 @@
+// P25 Decoder (C) Copyright 2013, 2014, 2015, 2016, 2017 Max H. Parke KA1RBI
+//
+// 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_RX_SYNC_H
+#define INCLUDED_RX_SYNC_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+#include <iostream>
+#include <deque>
+#include <assert.h>
+
+#include "bit_utils.h"
+#include "check_frame_sync.h"
+
+#include "p25p2_vf.h"
+#include "mbelib.h"
+#include "ambe.h"
+
+#include "ysf_const.h"
+#include "dmr_const.h"
+#include "p25_frame.h"
+#include "op25_imbe_frame.h"
+#include "software_imbe_decoder.h"
+#include "op25_audio.h"
+
+namespace gr{
+ namespace op25_repeater{
+
+static const uint64_t DSTAR_FRAME_SYNC_MAGIC = 0x444445101440LL; // expanded into dibits
+
+enum rx_types {
+ RX_TYPE_NONE=0,
+ RX_TYPE_P25,
+ RX_TYPE_DMR,
+ RX_TYPE_DSTAR,
+ RX_TYPE_YSF,
+ RX_N_TYPES
+}; // also used as array index
+
+static const struct _mode_data {
+ const char * type;
+ int sync_len;
+ int sync_offset;
+ int fragment_len; // symbols
+ int expiration;
+ uint64_t sync;
+} MODE_DATA[RX_N_TYPES] = {
+ {"NONE", 0,0,0,0,0},
+ {"P25", 48,0,864,1728, P25_FRAME_SYNC_MAGIC},
+ {"DMR", 48,66,144,1728, DMR_VOICE_SYNC_MAGIC},
+ {"DSTAR", 48,72,96,2016*2, DSTAR_FRAME_SYNC_MAGIC},
+ {"YSF", 40,0,480,480*2, YSF_FRAME_SYNC_MAGIC}
+}; // index order must match rx_types enum
+
+enum codeword_types {
+ CODEWORD_P25P1,
+ CODEWORD_P25P2,
+ CODEWORD_DMR,
+ CODEWORD_DSTAR,
+ CODEWORD_YSF_FULLRATE,
+ CODEWORD_YSF_HALFRATE
+};
+
+class rx_sync {
+public:
+ void rx_sym(const uint8_t sym);
+ void sync_reset(void);
+ rx_sync(const char * options, int debug);
+ ~rx_sync();
+private:
+ void cbuf_insert(const uint8_t c);
+ void dmr_sync(const uint8_t bitbuf[], int& current_slot, bool& unmute);
+ void ysf_sync(const uint8_t dibitbuf[], bool& ysf_fullrate, bool& unmute);
+ void codeword(const uint8_t* cw, const enum codeword_types codeword_type, int slot_id);
+ void output(int16_t * samp_buf, const ssize_t slot_id);
+ static const int CBUF_SIZE=864;
+ static const int NSAMP_OUTPUT = 160;
+
+ unsigned int d_symbol_count;
+ uint64_t d_sync_reg;
+ uint8_t d_cbuf[CBUF_SIZE*2];
+ unsigned int d_cbuf_idx;
+ enum rx_types d_current_type;
+ int d_threshold;
+ int d_rx_count;
+ unsigned int d_expires;
+ int d_shift_reg;
+ unsigned int d_unmute_until[2];
+ p25p2_vf interleaver;
+ mbe_parms cur_mp[2];
+ mbe_parms prev_mp[2];
+ mbe_parms enh_mp[2];
+ software_imbe_decoder d_software_decoder[2];
+ std::deque<int16_t> d_output_queue[2];
+ bool d_stereo;
+ int d_debug;
+ op25_audio d_audio;
+};
+
+ } // end namespace op25_repeater
+} // end namespace gr
+#endif // INCLUDED_RX_SYNC_H