Integrate Max's slicer into decoder, change signature for decoder, add pcap_source_b.

git-svn-id: http://op25.osmocom.org/svn/trunk@257 65a5c917-d112-43f1-993d-58c26a4786be
This commit is contained in:
stevie 2011-01-23 00:26:23 +00:00
parent 4b888e7baa
commit 0fbbe4fc99
6 changed files with 564 additions and 10 deletions

View File

@ -78,7 +78,9 @@ _op25_la_SOURCES = \
voice_data_unit.cc \
voice_du_handler.cc \
op25.cc \
op25_decoder_ff.cc \
op25_decoder_bf.cc \
op25_fsk4_slicer_fb.cc \
op25_pcap_source_b.cc \
software_imbe_decoder.cc \
vc55_imbe_decoder.cc \
value_string.cc \

View File

@ -7,33 +7,94 @@
%{
#include "gnuradio_swig_bug_workaround.h"
#include "op25_decoder_ff.h"
#include "op25_decoder_bf.h"
#include "op25_fsk4_slicer_fb.h"
#include "op25_pcap_source_b.h"
#include <stdexcept>
%}
// ----------------------------------------------------------------
/*
* First arg is the package prefix.
* Second arg is the name of the class minus the prefix.
*
* This does some behind-the-scenes magic so we can invoke
* op25_make_decoder_ff from python as op25.decoder_ff.
* op25_make_decoder_bsf from python as op25.decoder_bf.
*/
GR_SWIG_BLOCK_MAGIC(op25, decoder_ff);
GR_SWIG_BLOCK_MAGIC(op25, decoder_bf);
/*
* Publicly-accesible default constuctor function for op25_decoder_ff.
* Publicly-accesible default constuctor function for op25_decoder_bf.
*/
op25_decoder_ff_sptr op25_make_decoder_ff();
op25_decoder_bf_sptr op25_make_decoder_bf();
/*
* The op25_decoder block.
/**
* The op25_decoder_bf block. Accepts a stream of dibit symbols and
* produces an 8KS/s audio stream.
*/
class op25_decoder_ff : public gr_block
class op25_decoder_bf : public gr_block
{
private:
op25_decoder_ff();
op25_decoder_bf();
public:
const char *destination() const;
gr_msg_queue_sptr get_msgq() const;
void set_msgq(gr_msg_queue_sptr msgq);
};
// ----------------------------------------------------------------
/*
* First arg is the package prefix.
* Second arg is the name of the class minus the prefix.
*
* This does some behind-the-scenes magic so we can invoke
* op25_make_slicer_fb from python as op25.slicer_fbf.
*/
GR_SWIG_BLOCK_MAGIC(op25, fsk4_slicer_fb);
/*
* Publicly-accesible default constuctor function for op25_decoder_bf.
*/
op25_fsk4_slicer_fb_sptr op25_make_fsk4_slicer_fb(const std::vector<float> &slice_levels);
/*
* The op25_fsk4_slicer block. Takes a series of float samples and
* partitions them into dibit symbols according to the slices_levels
* provided to the constructor.
*/
class op25_fsk4_slicer_fb : public gr_sync_block
{
private:
op25_fsk4_slicer_fb (const std::vector<float> &slice_levels);
};
// ----------------------------------------------------------------
/*
* First arg is the package prefix.
* Second arg is the name of the class minus the prefix.
*
* This does some behind-the-scenes magic so we can invoke
* op25_make_pcap_source from python as op25.pcap_source.
*/
GR_SWIG_BLOCK_MAGIC(op25, pcap_source_b);
/*
* Publicly-accesible constuctor function for op25_pcap_source.
*/
op25_pcap_source_b_sptr op25_make_pcap_source_b(const char *path, float delay, bool repeat);
/*
* The op25_pcap_source block. Reads symbols from a tcpdump-formatted
* file and produces a stream of symbols of the appropriate size.
*/
class op25_pcap_source_b : public gr_sync_block
{
private:
op25_pcap_source_b(const char *path);
};
// ----------------------------------------------------------------

View File

@ -0,0 +1,123 @@
/* -*- Mode: C++ -*- */
/*
* Copyright 2010, 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.
*/
/*
* config.h is generated by configure. It contains the results
* of probing for features, options etc. It should be the first
* file included in your .cc file.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <op25_fsk4_slicer_fb.h>
#include <gr_io_signature.h>
#include <stdio.h>
/*
* Create a new instance of op25_fsk4_slicer_fb and return
* a boost shared_ptr. This is effectively the public constructor.
*/
op25_fsk4_slicer_fb_sptr
op25_make_fsk4_slicer_fb(const std::vector<float> &slice_levels)
{
return op25_fsk4_slicer_fb_sptr(new op25_fsk4_slicer_fb (slice_levels));
}
/*
* Specify constraints on number of input and output streams.
* This info is used to construct the input and output signatures
* (2nd & 3rd args to gr_block's constructor). The input and
* output signatures are used by the runtime system to
* check that a valid number and type of inputs and outputs
* are connected to this block. In this case, we accept
* only 1 input and 1 output.
*/
static const int MIN_IN = 1; // mininum number of input streams
static const int MAX_IN = 1; // maximum number of input streams
static const int MIN_OUT = 1; // minimum number of output streams
static const int MAX_OUT = 1; // maximum number of output streams
/*
* The private constructor
*/
op25_fsk4_slicer_fb::op25_fsk4_slicer_fb(const std::vector<float> &slice_levels)
: gr_sync_block("fsk4_slicer_fb",
gr_make_io_signature(MIN_IN, MAX_IN, sizeof(float)),
gr_make_io_signature(MIN_OUT, MAX_OUT, sizeof(unsigned char)))
{
d_slice_levels[0] = slice_levels[0];
d_slice_levels[1] = slice_levels[1];
d_slice_levels[2] = slice_levels[2];
d_slice_levels[3] = slice_levels[3];
}
/*
* Our virtual destructor.
*/
op25_fsk4_slicer_fb::~op25_fsk4_slicer_fb()
{
// nothing else required in this example
}
int
op25_fsk4_slicer_fb::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
const float *in = (const float *) input_items[0];
unsigned char *out = (unsigned char *) output_items[0];
for(int i = 0; i < noutput_items; i++){
#if 0
if(in[i] < -2.0) {
out[i] = 3;
} else if(in[i] < 0.0) {
out[i] = 2;
} else if(in[i] < 2.0) {
out[i] = 0;
} else {
out[i] = 1;
}
#endif
uint8_t dibit;
float sym = in[i];
if(d_slice_levels[3] < 0) {
dibit = 1;
if(d_slice_levels[3] <= sym && sym < d_slice_levels[0])
dibit = 3;
} else {
dibit = 3;
if(d_slice_levels[2] <= sym && sym < d_slice_levels[3])
dibit = 1;
}
if(d_slice_levels[0] <= sym && sym < d_slice_levels[1])
dibit = 2;
if(d_slice_levels[1] <= sym && sym < d_slice_levels[2])
dibit = 0;
out[i] = dibit;
}
// Tell runtime system how many output items we produced.
return noutput_items;
}

View File

@ -0,0 +1,81 @@
/* -*- c++ -*- */
/*
* Copyright 2010 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 2, 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., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef INCLUDED_OP25_FSK4_SLICER_FB_H
#define INCLUDED_OP25_FSK4_SLICER_FB_H
#include <gr_sync_block.h>
/**
* We use boost::shared_ptr's instead of raw pointers for all access
* to gr_blocks (and many other data structures). The shared_ptr gets
* us transparent reference counting, which greatly simplifies storage
* management issues. This is especially helpful in our hybrid
* C++ / Python system.
*
* See http://www.boost.org/libs/smart_ptr/smart_ptr.htm
*
* As a convention, the _sptr suffix indicates a boost::shared_ptr
*/
typedef boost::shared_ptr<class op25_fsk4_slicer_fb> op25_fsk4_slicer_fb_sptr;
/**
* Return a shared_ptr to a new instance of op25_fsk4_slicer_fb. To
* avoid accidental use of raw pointers, op25_fsk4_slicer_fb's
* constructor is private. op25_make_fsk4_slicer_fb is the public
* interface for creating new instances.
*/
op25_fsk4_slicer_fb_sptr op25_make_fsk4_slicer_fb (const std::vector<float> &slice_levels);
/**
* Produce a stream of dibits, given a stream of floats in [-3,-1,1,3].
* \ingroup block
*
* This uses the preferred technique: subclassing gr_sync_block.
*/
class op25_fsk4_slicer_fb : public gr_sync_block
{
public:
virtual ~op25_fsk4_slicer_fb ();
virtual int work (int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
private:
/**
* The friend declaration allows op25_make_fsk4_slicer_fb to access
* the private constructor.
*/
friend op25_fsk4_slicer_fb_sptr op25_make_fsk4_slicer_fb (const std::vector<float> &slice_levels);
op25_fsk4_slicer_fb (const std::vector<float> &slice_levels);
float d_slice_levels[4];
};
#endif /* INCLUDED_OP25_FSK4_SLICER_FB_H */

View File

@ -0,0 +1,135 @@
/* -*- C++ -*- */
/*
* Copyright 2010,2011 Steve Glass
*
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <algorithm>
#include <gr_io_signature.h>
#include <iostream>
#include <iomanip>
#include <math.h>
#include <op25_pcap_source_b.h>
#include <stdint.h>
#include <stdexcept>
#include <strings.h>
using namespace std;
op25_pcap_source_b_sptr
op25_make_pcap_source_b(const char *path, float delay, bool repeat)
{
return op25_pcap_source_b_sptr(new op25_pcap_source_b(path, delay, repeat));
}
op25_pcap_source_b::~op25_pcap_source_b()
{
if(pcap_) {
pcap_close(pcap_);
pcap_ = NULL;
}
}
int
op25_pcap_source_b::work(int nof_output_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items)
{
try {
uint8_t *out = reinterpret_cast<uint8_t*>(output_items[0]);
const size_t SYMS_REQD = static_cast<size_t>(nof_output_items);
if(symbols_.size() < SYMS_REQD) {
read_at_least(SYMS_REQD);
}
const size_t SYMS_AVAIL = min(symbols_.size(), SYMS_REQD);
copy(symbols_.begin(), symbols_.begin() + SYMS_AVAIL, out);
symbols_.erase(symbols_.begin(), symbols_.begin() + SYMS_AVAIL);
fill(out + SYMS_AVAIL, out + SYMS_REQD, 0);
return(0 == SYMS_AVAIL ? -1 : SYMS_REQD);
} catch(const std::exception& x) {
cerr << x.what() << endl;
exit(1);
} catch(...) {
cerr << "unhandled exception" << endl;
exit(2);
}
}
op25_pcap_source_b::op25_pcap_source_b(const char *path, float delay, bool repeat) :
gr_sync_block ("pcap_source_b", gr_make_io_signature (0, 0, 0), gr_make_io_signature (1, 1, sizeof(uint8_t))),
path_(path),
DELAY_(delay),
repeat_(repeat),
pcap_(NULL),
prev_is_present_(false),
SYMBOLS_PER_SEC_(4800.0)
{
char err[PCAP_ERRBUF_SIZE];
pcap_ = pcap_open_offline(path_.c_str(), err);
}
float
op25_pcap_source_b::ifs(const struct pcap_pkthdr& NOW, const struct pcap_pkthdr& PREV, const size_t HEADER_SZ) const
{
double t1 = (PREV.ts.tv_usec / 1e6);
double adj = (NOW.len - HEADER_SZ) * 4.0 / SYMBOLS_PER_SEC_;
double t2 = (NOW.ts.tv_sec - PREV.ts.tv_sec) + (NOW.ts.tv_usec / 1e6);
return static_cast<float>(t2 - adj - t1);
}
uint_least32_t
op25_pcap_source_b::read_at_least(const size_t NSYMS_REQD)
{
size_t n = 0;
struct pcap_pkthdr hdr;
const size_t ETHERNET_SZ = 14;
while(pcap_ && n < NSYMS_REQD) {
const uint8_t *octets = pcap_next(pcap_, &hdr);
if(octets) {
// push inter-frame silence symbols
const float N = (prev_is_present_ ? ifs(hdr, prev_, ETHERNET_SZ) : DELAY_);
const uint_least32_t NSYMS = roundl(N * (1 / SYMBOLS_PER_SEC_));
for(uint_least32_t i = 0; i < NSYMS; ++i, ++n) {
symbols_.push_back(0);
}
// push symbols from frame payload
for(size_t i = ETHERNET_SZ; i < hdr.caplen; ++i, ++n) {
for(int16_t j = 6; j >= 0; j -= 2) {
dibit d = (octets[i] >> j) & 0x3;
symbols_.push_back(d);
}
}
prev_ = hdr;
prev_is_present_ = true;
} else {
pcap_close(pcap_);
pcap_ = NULL;
if(repeat_) {
// re-open the file
char err[PCAP_ERRBUF_SIZE];
pcap_ = pcap_open_offline(path_.c_str(), err);
prev_is_present_ = false;
}
}
}
return n;
}

View File

@ -0,0 +1,152 @@
/* -*- C++ -*- */
/*
* Copyright 2010-2011 Steve Glass
*
* 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_OP25_PCAP_SOURCE_B_H
#define INCLUDED_OP25_PCAP_SOURCE_B_H
#include <boost/shared_ptr.hpp>
#include <gr_sync_block.h>
#define PCAP_DONT_INCLUDE_PCAP_BPF_H
#include <pcap/pcap.h>
#include <stdint.h>
#include <string>
#include <deque>
typedef boost::shared_ptr<class op25_pcap_source_b> op25_pcap_source_b_sptr;
op25_pcap_source_b_sptr op25_make_pcap_source_b(const char *path, float delay, bool repeat);
/**
* op25_pcap_source_b is a GNU Radio block for reading from a
* tcpdump-formatted capture file and producing a stream of dibit symbols.
*/
class op25_pcap_source_b : public gr_sync_block
{
public:
/**
* op25_pcap_source_b (virtual) destructor.
*/
virtual ~op25_pcap_source_b();
/**
* Process symbols into frames.
*/
virtual int work(int nof_output_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items);
private:
/**
* Expose class to public ctor. Create a new instance of
* op25_pcap_source_b and wrap it in a shared_ptr. This is
* effectively the public constructor.
*
* \param path The path to the tcpdump-formatted input file.
* \param delay The number of seconds to delay before sending the first frame.
* \param repeat Loop back to beginning when EOF is encountered.
*/
friend op25_pcap_source_b_sptr op25_make_pcap_source_b(const char *path, float delay, bool repeat);
/**
* op25_pcap_source_b protected constructor.
*
* \param path The path to the tcpdump-formatted input file.
* \param delay The number of seconds to delay before sending the first frame.
* \param repeat Loop back to beginning when EOF is encountered.
*/
op25_pcap_source_b(const char *path, float delay, bool repeat);
/**
* Compute the interframe space between the frames NOW and PREV and
* taking care to ignore HEADER_SZ octets of the frame length. The
* timestamps are presumed to be taken at the end of the frame.
*
* \param NOW The pcap_pkthdr for the most recent frame.
* \param PREV The pcap_pkthdr for the previous frame.
* \param HEADER_SZ The number of octets in the packet header.
* \return The interframe space expressed in seconds.
*/
float ifs(const struct pcap_pkthdr& NOW, const struct pcap_pkthdr& PREV, const size_t HEADER_SZ) const;
/**
* Read at least NYSMS_REQD symbols from the tcpdump-formatted
* file. This method populates the symbols_ queue and may return
* less than NSYMS_REQD when at end-of-file. When there is no more
* data it returns zero.
*
* \param nsyms_reqd The number of symbols required.
* \return The actual number of symbols read.
*/
uint_least32_t read_at_least(size_t nsyms_reqd);
private:
/**
* Path to the pcap file.
*/
std::string path_;
/**
* Delay (in seconds) before injecting first frame.
*/
const float DELAY_;
/**
* Repeat the stream when at end?
*/
bool repeat_;
/**
* Handle to the pcap file.
*/
pcap_t *pcap_;
/**
* Details for previous frame.
*/
struct pcap_pkthdr prev_;
/**
* Is prev_ present?
*/
bool prev_is_present_;
/**
* Define dibit type
*/
typedef uint8_t dibit;
/**
* Queue of dibit symbols.
*/
std::deque<dibit> symbols_;
/**
* The number of symbols/s produced by this block.
*/
const float SYMBOLS_PER_SEC_;
};
#endif /* INCLUDED_OP25_PCAP_SOURCE_B_H */