parent
5601e5290e
commit
e79d7eaabc
@ -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 */ |
||||
|
@ -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 */ |
@ -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 */ |
@ -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
|
@ -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
|
Loading…
Reference in new issue