summaryrefslogtreecommitdiffstats
path: root/blocks/src
diff options
context:
space:
mode:
authorstevie <stevie@65a5c917-d112-43f1-993d-58c26a4786be>2011-05-29 10:24:15 +0000
committerstevie <stevie@65a5c917-d112-43f1-993d-58c26a4786be>2011-05-29 10:24:15 +0000
commitda6ffc8343221ca66789c2e9c62506e5653301ea (patch)
tree56bff05ac3c506ff7906583660326c5c076017d9 /blocks/src
parentf76f2bc712353a587782fe11a79b6447c9bbb88a (diff)
Rename 'decoder' to 'blocks'.
git-svn-id: http://op25.osmocom.org/svn/trunk@283 65a5c917-d112-43f1-993d-58c26a4786be
Diffstat (limited to 'blocks/src')
-rw-r--r--blocks/src/Makefile.am22
-rw-r--r--blocks/src/lib/Makefile.am116
-rw-r--r--blocks/src/lib/abstract_data_unit.cc181
-rw-r--r--blocks/src/lib/abstract_data_unit.h191
-rw-r--r--blocks/src/lib/data_unit.cc73
-rw-r--r--blocks/src/lib/data_unit.h142
-rw-r--r--blocks/src/lib/data_unit_handler.cc19
-rw-r--r--blocks/src/lib/data_unit_handler.h71
-rw-r--r--blocks/src/lib/dummy_imbe_decoder.cc37
-rw-r--r--blocks/src/lib/dummy_imbe_decoder.h55
-rw-r--r--blocks/src/lib/hdu.cc224
-rw-r--r--blocks/src/lib/hdu.h144
-rw-r--r--blocks/src/lib/imbe_decoder.cc16
-rw-r--r--blocks/src/lib/imbe_decoder.h90
-rw-r--r--blocks/src/lib/imbe_decoder_factory.cc29
-rw-r--r--blocks/src/lib/ldu1.cc41
-rw-r--r--blocks/src/lib/ldu1.h55
-rw-r--r--blocks/src/lib/ldu2.cc41
-rw-r--r--blocks/src/lib/ldu2.h54
-rw-r--r--blocks/src/lib/logfile_du_handler.cc47
-rw-r--r--blocks/src/lib/logfile_du_handler.h68
-rw-r--r--blocks/src/lib/offline_imbe_decoder.cc63
-rw-r--r--blocks/src/lib/offline_imbe_decoder.h64
-rw-r--r--blocks/src/lib/op25.i109
-rw-r--r--blocks/src/lib/op25_decoder_bf.cc221
-rw-r--r--blocks/src/lib/op25_decoder_bf.h169
-rw-r--r--blocks/src/lib/op25_decoder_ff.cc230
-rw-r--r--blocks/src/lib/op25_decoder_ff.h168
-rw-r--r--blocks/src/lib/op25_fsk4_demod_ff.cc361
-rw-r--r--blocks/src/lib/op25_fsk4_demod_ff.h113
-rw-r--r--blocks/src/lib/op25_fsk4_slicer_fb.cc123
-rw-r--r--blocks/src/lib/op25_fsk4_slicer_fb.h81
-rw-r--r--blocks/src/lib/op25_golay.h206
-rw-r--r--blocks/src/lib/op25_hamming.h186
-rw-r--r--blocks/src/lib/op25_imbe_frame.h427
-rw-r--r--blocks/src/lib/op25_p25_frame.h38
-rw-r--r--blocks/src/lib/op25_pcap_source_b.cc114
-rw-r--r--blocks/src/lib/op25_pcap_source_b.h89
-rw-r--r--blocks/src/lib/op25_yank.h114
-rw-r--r--blocks/src/lib/p25cai_du_handler.cc87
-rw-r--r--blocks/src/lib/p25cai_du_handler.h84
-rw-r--r--blocks/src/lib/pdu.cc67
-rw-r--r--blocks/src/lib/pdu.h74
-rw-r--r--blocks/src/lib/pickle.cc59
-rw-r--r--blocks/src/lib/pickle.h69
-rw-r--r--blocks/src/lib/snapshot_du_handler.cc66
-rw-r--r--blocks/src/lib/snapshot_du_handler.h94
-rw-r--r--blocks/src/lib/software_imbe_decoder.cc1433
-rw-r--r--blocks/src/lib/software_imbe_decoder.h101
-rw-r--r--blocks/src/lib/tdu.cc84
-rw-r--r--blocks/src/lib/tdu.h99
-rw-r--r--blocks/src/lib/tsbk.cc52
-rw-r--r--blocks/src/lib/tsbk.h66
-rw-r--r--blocks/src/lib/value_string.cc116
-rw-r--r--blocks/src/lib/value_string.h49
-rw-r--r--blocks/src/lib/vc55_imbe_decoder.cc87
-rw-r--r--blocks/src/lib/vc55_imbe_decoder.h64
-rw-r--r--blocks/src/lib/voice_data_unit.cc58
-rw-r--r--blocks/src/lib/voice_data_unit.h79
-rw-r--r--blocks/src/lib/voice_du_handler.cc47
-rw-r--r--blocks/src/lib/voice_du_handler.h69
-rw-r--r--blocks/src/python/Makefile.am32
-rwxr-xr-xblocks/src/python/qa_op25.py47
-rw-r--r--blocks/src/python/run_tests.in50
64 files changed, 7725 insertions, 0 deletions
diff --git a/blocks/src/Makefile.am b/blocks/src/Makefile.am
new file mode 100644
index 0000000..52d7757
--- /dev/null
+++ b/blocks/src/Makefile.am
@@ -0,0 +1,22 @@
+#
+# Copyright 2004 Free Software Foundation, Inc.
+#
+# 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.
+#
+
+SUBDIRS = lib python
diff --git a/blocks/src/lib/Makefile.am b/blocks/src/lib/Makefile.am
new file mode 100644
index 0000000..0799bff
--- /dev/null
+++ b/blocks/src/lib/Makefile.am
@@ -0,0 +1,116 @@
+#
+# Copyright 2004,2005,2006,2008 Free Software Foundation, Inc.
+#
+# 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 $(top_srcdir)/Makefile.common
+
+# Install this stuff so that it ends up as the op25.decoder_ff
+# module. This usually ends up at:
+# ${prefix}/lib/python${python_version}/site-packages/gnuradio
+
+ourpythondir = $(grpythondir)
+ourlibdir = $(grpyexecdir)
+
+AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) $(WITH_INCLUDES)
+
+SWIGPYTHONARGS = $(SWIGPYTHONFLAGS) $(SWIGGRFLAGS) $(WITH_SWIG_INCLUDES) \
+ $(WITH_INCLUDES)
+
+ALL_IFILES = \
+ $(LOCAL_IFILES) \
+ $(NON_LOCAL_IFILES)
+
+NON_LOCAL_IFILES = \
+ $(GNURADIO_CORE_INCLUDEDIR)/swig/gnuradio.i
+
+LOCAL_IFILES = \
+ $(top_srcdir)/src/lib/op25.i
+
+# These files are built by SWIG. The first is the C++ glue.
+# The second is the python wrapper that loads the _op25 shared library
+# and knows how to call our extensions.
+
+BUILT_SOURCES = \
+ op25.cc \
+ op25.py
+
+# This gets op25.py installed in the right place
+ourpython_PYTHON = \
+ op25.py
+
+ourlib_LTLIBRARIES = _op25.la
+
+# These are the source files that go into the shared library
+_op25_la_SOURCES = \
+ abstract_data_unit.cc \
+ data_unit.cc \
+ hdu.cc \
+ ldu1.cc \
+ ldu2.cc \
+ pdu.cc \
+ tdu.cc \
+ tsbk.cc \
+ data_unit_handler.cc \
+ logfile_du_handler.cc \
+ p25cai_du_handler.cc \
+ snapshot_du_handler.cc \
+ imbe_decoder.cc \
+ imbe_decoder_factory.cc \
+ dummy_imbe_decoder.cc \
+ offline_imbe_decoder.cc \
+ voice_data_unit.cc \
+ voice_du_handler.cc \
+ op25.cc \
+ op25_decoder_bf.cc \
+ op25_fsk4_demod_ff.cc \
+ op25_fsk4_slicer_fb.cc \
+ op25_pcap_source_b.cc \
+ software_imbe_decoder.cc \
+ vc55_imbe_decoder.cc \
+ value_string.cc \
+ pickle.cc
+
+# magic flags
+_op25_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version
+
+# link the library against some comon swig runtime code and the
+# c++ standard library
+_op25_la_LIBADD = \
+ $(PYTHON_LDFLAGS) \
+ -lstdc++ \
+ -litpp
+
+op25.cc op25.py: $(LOCAL_IFILES) $(ALL_IFILES)
+ $(SWIG) $(SWIGPYTHONARGS) -module op25 -o op25.cc $(LOCAL_IFILES)
+
+# These headers get installed in ${prefix}/include/gnuradio
+grinclude_HEADERS = \
+ op25_decoder_ff.h
+
+# These swig headers get installed in ${prefix}/include/gnuradio/swig
+swiginclude_HEADERS = \
+ $(LOCAL_IFILES)
+
+MOSTLYCLEANFILES = $(BUILT_SOURCES) *.pyc
+
+# Don't distribute output of swig
+dist-hook:
+ @for file in $(BUILT_SOURCES); do echo $(RM) $(distdir)/$$file; done
+ @for file in $(BUILT_SOURCES); do $(RM) $(distdir)/$$file; done
diff --git a/blocks/src/lib/abstract_data_unit.cc b/blocks/src/lib/abstract_data_unit.cc
new file mode 100644
index 0000000..fa00cce
--- /dev/null
+++ b/blocks/src/lib/abstract_data_unit.cc
@@ -0,0 +1,181 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include <abstract_data_unit.h>
+
+#include <algorithm>
+#include <cstring>
+#include <functional>
+#include <iomanip>
+#include <iostream>
+#include <stdexcept>
+#include <sstream>
+#include <utility>
+
+using namespace std;
+
+abstract_data_unit::~abstract_data_unit()
+{
+}
+
+void
+abstract_data_unit::correct_errors()
+{
+ if(is_complete()) {
+ do_correct_errors(d_frame_body);
+ } else {
+ ostringstream msg;
+ msg << "cannot correct errors - frame is not complete" << endl;
+ msg << "(size now: " << frame_size() << ", expected size: " << frame_size_max() << ")" << endl;
+ msg << "func: " << __PRETTY_FUNCTION__ << endl;
+ msg << "file: " << __FILE__ << endl;
+ msg << "line: " << __LINE__ << endl;
+ throw logic_error(msg.str());
+ }
+}
+
+void
+abstract_data_unit::decode_audio(imbe_decoder& imbe)
+{
+ if(is_complete()) {
+ do_decode_audio(d_frame_body, imbe);
+ } else {
+ ostringstream msg;
+ msg << "cannot decode audio - frame is not complete" << endl;
+ msg << "(size now: " << frame_size() << ", expected size: " << frame_size_max() << ")" << endl;
+ msg << "func: " << __PRETTY_FUNCTION__ << endl;
+ msg << "file: " << __FILE__ << endl;
+ msg << "line: " << __LINE__ << endl;
+ throw logic_error(msg.str());
+ }
+}
+
+size_t
+abstract_data_unit::decode_frame(size_t msg_sz, uint8_t *msg)
+{
+ return decode_frame(d_frame_body, msg_sz, msg);
+}
+
+size_t
+abstract_data_unit::decode_frame(const_bit_vector& frame_body, size_t msg_sz, uint8_t *msg)
+{
+ size_t n = 0;
+ if(is_complete()) {
+ if(size() <= msg_sz) {
+ n = extract(frame_body, 0, static_cast<int>(frame_body.size()), msg);
+ } else {
+ ostringstream msg;
+ msg << "cannot decode frame body ";
+ msg << "(msg size: " << msg_sz << ", actual size: " << size() << ")" << endl;
+ msg << "func: " << __PRETTY_FUNCTION__ << endl;
+ msg << "file: " << __FILE__ << endl;
+ msg << "line: " << __LINE__ << endl;
+ throw length_error(msg.str());
+ }
+ } else {
+ ostringstream msg;
+ msg << "cannot decode frame - frame is not complete" << endl;
+ msg << "(size now: " << frame_size() << ", expected size: " << frame_size_max() << ")" << endl;
+ msg << "func: " << __PRETTY_FUNCTION__ << endl;
+ msg << "file: " << __FILE__ << endl;
+ msg << "line: " << __LINE__ << endl;
+ throw logic_error(msg.str());
+ }
+ return n;
+
+}
+
+void
+abstract_data_unit::extend(dibit d)
+{
+ if(frame_size() < frame_size_max()) {
+ d_frame_body.push_back(d & 0x2);
+ d_frame_body.push_back(d & 0x1);
+ } else {
+ ostringstream msg;
+ msg << "cannot extend frame " << endl;
+ msg << "(size now: " << frame_size() << ", expected size: " << frame_size_max() << ")" << endl;
+ msg << "func: " << __PRETTY_FUNCTION__ << endl;
+ msg << "file: " << __FILE__ << endl;
+ msg << "line: " << __LINE__ << endl;
+ throw length_error(msg.str());
+ }
+}
+
+bool
+abstract_data_unit::is_complete() const
+{
+ return frame_size() >= frame_size_max();
+}
+
+uint16_t
+abstract_data_unit::size() const
+{
+ return (7 + frame_size_max()) >> 3;
+}
+
+std::string
+abstract_data_unit::snapshot() const
+{
+ string empty;
+ return empty;
+}
+
+void
+abstract_data_unit::dump(ostream& os) const
+{
+ uint32_t nbits = d_frame_body.size();
+ os << setw(4) << nbits << " ";
+ for(size_t i = 48; i < nbits; ++i) {
+ os << (d_frame_body[i] ? "#" : "-");
+ }
+ os << endl;
+}
+
+abstract_data_unit::abstract_data_unit(const_bit_queue& frame_body) :
+ d_frame_body(frame_body.size())
+{
+ copy(frame_body.begin(), frame_body.end(), d_frame_body.begin());
+}
+
+void
+abstract_data_unit::do_correct_errors(bit_vector& frame_body)
+{
+}
+
+void
+abstract_data_unit::do_decode_audio(const_bit_vector& frame_body, imbe_decoder& imbe)
+{
+}
+
+const_bit_vector&
+abstract_data_unit::frame_body() const
+{
+ return d_frame_body;
+}
+
+uint16_t
+abstract_data_unit::frame_size() const
+{
+ return d_frame_body.size();
+}
diff --git a/blocks/src/lib/abstract_data_unit.h b/blocks/src/lib/abstract_data_unit.h
new file mode 100644
index 0000000..2a84506
--- /dev/null
+++ b/blocks/src/lib/abstract_data_unit.h
@@ -0,0 +1,191 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_ABSTRACT_DATA_UNIT_H
+#define INCLUDED_ABSTRACT_DATA_UNIT_H
+
+#include <data_unit.h>
+#include <string>
+#include <vector>
+#include <op25_yank.h>
+
+#include <itpp/base/vec.h>
+#include <vector>
+
+typedef std::vector<bool> bit_vector;
+typedef const std::vector<bool> const_bit_vector;
+
+/**
+ * Abstract P25 data unit.
+ */
+class abstract_data_unit : public data_unit
+{
+
+public:
+
+ /**
+ * abstract data_unit virtual destructor.
+ */
+ virtual ~abstract_data_unit();
+
+ /**
+ * Apply error correction to this data_unit.
+ *
+ * \precondition is_complete() == true.
+ */
+ virtual void correct_errors();
+
+ /**
+ * Decode compressed audio using the supplied imbe_decoder.
+ *
+ * \precondition is_complete() == true.
+ * \param imbe The imbe_decoder to use to generate the audio.
+ */
+ virtual void decode_audio(imbe_decoder& imbe);
+
+ /**
+ * Decode the frame into an octet vector.
+ *
+ * \precondition is_complete() == true.
+ * \param msg_sz The size of the message buffer.
+ * \param msg A pointer to the message buffer.
+ * \return The number of octets written to msg.
+ */
+ virtual size_t decode_frame(size_t msg_sz, uint8_t *msg);
+
+ /**
+ * Dump this data unit in human readable format to stream s.
+ *
+ * \param s The stream to write on
+ */
+ virtual void dump(std::ostream& os) const;
+
+ /**
+ * Extends this data_unit with the specified dibit. If this
+ * data_unit is already complete a range_error is thrown.
+ *
+ * \precondition is_complete() == false.
+ * \param d The dibit to extend the frame with.
+ * \throws range_error When the frame already is at its maximum size.
+ * \return true when the frame is complete otherwise false.
+ */
+ virtual void extend(dibit d);
+
+ /**
+ * Tests whether this data unit has enough data to begin decoding.
+ *
+ * \return true when this data_unit is complete; otherwise returns
+ * false.
+ */
+ virtual bool is_complete() const;
+
+ /**
+ * Returns the size (in octets) of this data_unit.
+ *
+ * \return The size (in octets) of this data_unit.
+ */
+ virtual uint16_t size() const;
+
+ /**
+ * Return a snapshot of the key fields from this frame in a manner
+ * suitable for display by the UI. The string is encoded as a
+ * pickled Python dictionary.
+ *
+ * \precondition is_complete() == true.
+ * \return A string containing the fields to display.
+ */
+ virtual std::string snapshot() const;
+
+protected:
+
+ /**
+ * abstract_data_unit constructor.
+ *
+ * \param frame_body A const_bit_queue representing the frame body.
+ */
+ abstract_data_unit(const_bit_queue& frame_body);
+
+ /**
+ * Applies error correction code to the specified bit_vector.
+ *
+ * \param frame_body The bit vector to decode.
+ */
+ virtual void do_correct_errors(bit_vector& frame_body);
+
+ /**
+ * Decode compressed audio using the supplied imbe_decoder.
+ *
+ * \precondition is_complete() == true.
+ * \param frame_body The const_bit_vector to decode.
+ * \param imbe The imbe_decoder to use.
+ */
+ virtual void do_decode_audio(const_bit_vector& frame_body, imbe_decoder& imbe);
+
+ /**
+ * Decode frame_body and write the decoded frame contents to msg.
+ *
+ * \param frame_body The bit vector to decode.
+ * \param msg_sz The size of the message buffer.
+ * \param msg A pointer to where the data unit content will be written.
+ * \return The number of octets written to msg.
+ */
+ virtual size_t decode_frame(const_bit_vector& frame_body, size_t msg_sz, uint8_t *msg);
+
+ /**
+ * Returns a string describing the Data Unit ID (DUID).
+ *
+ * \return A string identifying the DUID.
+ */
+ virtual std::string duid_str() const = 0;
+
+ /**
+ * Return a reference to the frame body.
+ */
+ const_bit_vector& frame_body() const;
+
+ /**
+ * Returns the expected size (in bits) of this data_unit. For
+ * variable-length data this should return UINT16_MAX until the
+ * actual length of this frame is known.
+ *
+ * \return The expected size (in bits) of this data_unit when encoded.
+ */
+ virtual uint16_t frame_size_max() const = 0;
+
+ /**
+ * Returns the current size (in bits) of this data_unit.
+ *
+ * \return The current size (in bits) of this data_unit.
+ */
+ virtual uint16_t frame_size() const;
+
+private:
+
+ /**
+ * A bit vector containing the frame body.
+ */
+ bit_vector d_frame_body;
+
+};
+
+#endif /* INCLUDED_ABSTRACT_DATA_UNIT_H */
diff --git a/blocks/src/lib/data_unit.cc b/blocks/src/lib/data_unit.cc
new file mode 100644
index 0000000..9e118c8
--- /dev/null
+++ b/blocks/src/lib/data_unit.cc
@@ -0,0 +1,73 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include <data_unit.h>
+#include <hdu.h>
+#include <ldu1.h>
+#include <ldu2.h>
+#include <pdu.h>
+#include <tdu.h>
+#include <tsbk.h>
+#include <op25_yank.h>
+
+using namespace std;
+
+data_unit_sptr
+data_unit::make_data_unit(const_bit_queue& frame_body)
+{
+ data_unit_sptr d;
+ uint8_t duid = extract(frame_body, 60, 64);
+ switch(duid) {
+ case 0x0:
+ d = data_unit_sptr(new hdu(frame_body));
+ break;
+ case 0x3:
+ d = data_unit_sptr(new tdu(frame_body, false));
+ break;
+ case 0x5:
+ d = data_unit_sptr(new ldu1(frame_body));
+ break;
+ case 0x7:
+ d = data_unit_sptr(new tsbk(frame_body));
+ break;
+ case 0xa:
+ d = data_unit_sptr(new ldu2(frame_body));
+ break;
+ case 0x9: // VSELP "voice PDU"
+ case 0xc:
+ d = data_unit_sptr(new pdu(frame_body));
+ break;
+ case 0xf:
+ d = data_unit_sptr(new tdu(frame_body, true));
+ break;
+ };
+ return d;
+}
+
+data_unit::~data_unit()
+{
+}
+
+data_unit::data_unit()
+{
+}
diff --git a/blocks/src/lib/data_unit.h b/blocks/src/lib/data_unit.h
new file mode 100644
index 0000000..ff40378
--- /dev/null
+++ b/blocks/src/lib/data_unit.h
@@ -0,0 +1,142 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_DATA_UNIT_H
+#define INCLUDED_DATA_UNIT_H
+
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+#include <deque>
+#include <iosfwd>
+#include <imbe_decoder.h>
+#include <stdint.h>
+
+typedef std::deque<bool> bit_queue;
+typedef const std::deque<bool> const_bit_queue;
+
+typedef uint8_t dibit;
+
+typedef std::deque<float> float_queue;
+
+typedef boost::shared_ptr<class data_unit> data_unit_sptr;
+
+/**
+ * A P25 data unit.
+ */
+class data_unit : public boost::noncopyable
+{
+public:
+
+ /**
+ * data_unit (virtual) constructor. Returns a pointer to an
+ * appropriate data_unit instance given the initial frame_body.
+ * \param fs The frame sync value for this data_unit.
+ * \param nid The network ID for this data_unit.
+ * \return A (possibly null-valued) pointer to the data_unit.
+ */
+ static data_unit_sptr make_data_unit(const_bit_queue& frame_body);
+
+ /**
+ * data_unit (virtual) destructor.
+ */
+ virtual ~data_unit();
+
+ /**
+ * Apply error correction to this data_unit.
+ *
+ * \precondition is_complete() == true.
+ */
+ virtual void correct_errors() = 0;
+
+ /**
+ * Decode compressed audio using the supplied imbe_decoder and
+ * writes output to audio.
+ *
+ * \precondition is_complete() == true.
+ * \param imbe The imbe_decoder to use to generate the audio.
+ */
+ virtual void decode_audio(imbe_decoder& imbe) = 0;
+
+ /**
+ * Decode the frame into an octet vector.
+ *
+ * \precondition is_complete() == true.
+ * \param msg_sz The size of the message buffer.
+ * \param msg A pointer to the message buffer.
+ * \return The number of octets written to msg.
+ */
+ virtual size_t decode_frame(size_t msg_sz, uint8_t *msg) = 0;
+
+ /**
+ * Dump this data unit in human readable format to stream s.
+ *
+ * \param s The stream to write on
+ */
+ virtual void dump(std::ostream& os) const = 0;
+
+ /**
+ * Extends this data_unit with the specified dibit. If this
+ * data_unit is already complete a range_error is thrown.
+ *
+ * \precondition is_complete() == false.
+ * \param d The dibit to extend the frame with.
+ * \throws range_error When the frame already is at its maximum size.
+ * \return true when the frame is complete otherwise false.
+ */
+ virtual void extend(dibit d) = 0;
+
+ /**
+ * Tests whether this data unit is complete.
+ *
+ * \return true when this data_unit is complete; otherwise returns
+ * false.
+ * \ see extend()
+ */
+ virtual bool is_complete() const = 0;
+
+ /**
+ * Returns the size (in octets) of the data_unit.
+ *
+ * \return The actual size (in octets) of this data_unit.
+ */
+ virtual uint16_t size() const = 0;
+
+ /**
+ * Return a snapshot of the key fields from this frame in a manner
+ * suitable for display by the UI. The string is encoded using the
+ * Python pickle format allowing for different fields to be
+ * returned.
+ *
+ * \return A string containing the fields to display.
+ */
+ virtual std::string snapshot() const = 0;
+
+protected:
+
+ /**
+ * data_unit default constructor.
+ */
+ data_unit();
+};
+
+#endif /* INCLUDED_DATA_UNIT_H */
diff --git a/blocks/src/lib/data_unit_handler.cc b/blocks/src/lib/data_unit_handler.cc
new file mode 100644
index 0000000..3d1316c
--- /dev/null
+++ b/blocks/src/lib/data_unit_handler.cc
@@ -0,0 +1,19 @@
+#include "data_unit_handler.h"
+
+data_unit_handler::~data_unit_handler()
+{
+}
+
+void
+data_unit_handler::handle(data_unit_sptr du)
+{
+ if(d_next) {
+ d_next->handle(du);
+ }
+}
+
+data_unit_handler::data_unit_handler(data_unit_handler_sptr next) :
+ d_next(next)
+{
+}
+
diff --git a/blocks/src/lib/data_unit_handler.h b/blocks/src/lib/data_unit_handler.h
new file mode 100644
index 0000000..308b6be
--- /dev/null
+++ b/blocks/src/lib/data_unit_handler.h
@@ -0,0 +1,71 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_DATA_UNIT_HANDLER_H
+#define INCLUDED_DATA_UNIT_HANDLER_H
+
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <data_unit.h>
+
+typedef boost::shared_ptr<class data_unit_handler> data_unit_handler_sptr;
+
+/**
+ * P25 data_unit_handler interface.
+ */
+class data_unit_handler : public boost::noncopyable
+{
+
+public:
+
+ /**
+ * data_unit_handler virtual destructor.
+ */
+ virtual ~data_unit_handler();
+
+ /**
+ * Handle a received P25 frame.
+ *
+ * \param du A non-null data_unit_sptr to handle.
+ */
+ virtual void handle(data_unit_sptr du) = 0;
+
+protected:
+
+ /**
+ * data_unit_handler default constructor.
+ *
+ * \param next The next data_unit_handler in this chain.
+ */
+ data_unit_handler(data_unit_handler_sptr next);
+
+private:
+
+ /**
+ * The next data_unit_handler in this chain.
+ */
+ data_unit_handler_sptr d_next;
+
+};
+
+#endif /* INCLUDED_DATA_UNIT_HANDLER_H */
diff --git a/blocks/src/lib/dummy_imbe_decoder.cc b/blocks/src/lib/dummy_imbe_decoder.cc
new file mode 100644
index 0000000..eae8dd3
--- /dev/null
+++ b/blocks/src/lib/dummy_imbe_decoder.cc
@@ -0,0 +1,37 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include <dummy_imbe_decoder.h>
+
+dummy_imbe_decoder::dummy_imbe_decoder()
+{
+}
+
+dummy_imbe_decoder::~dummy_imbe_decoder()
+{
+}
+
+void
+dummy_imbe_decoder::decode(const voice_codeword& cw)
+{
+}
diff --git a/blocks/src/lib/dummy_imbe_decoder.h b/blocks/src/lib/dummy_imbe_decoder.h
new file mode 100644
index 0000000..60b0e27
--- /dev/null
+++ b/blocks/src/lib/dummy_imbe_decoder.h
@@ -0,0 +1,55 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_DUMMY_IMBE_DECODER_H
+#define INCLUDED_DUMMY_IMBE_DECODER_H
+
+#include <imbe_decoder.h>
+
+/**
+ * dummy_imbe_decoder is the imbe_decoder of last resort. It consumes
+ * the voice_codeeword and does nothing.
+ */
+class dummy_imbe_decoder : public imbe_decoder {
+public:
+
+ /**
+ * dummy_imbe_decoder default constructor.
+ */
+ dummy_imbe_decoder();
+
+ /**
+ * dummy_imbe_decoder (virtual) destructor.
+ */
+ virtual ~dummy_imbe_decoder();
+
+ /**
+ * Ignores in_out and generates no audio.
+ *
+ * \param cw IMBE codewords and parity.
+ */
+ virtual void decode(const voice_codeword& cw);
+
+};
+
+#endif /* INCLUDED_DUMMY_IMBE_DECODER_H */
diff --git a/blocks/src/lib/hdu.cc b/blocks/src/lib/hdu.cc
new file mode 100644
index 0000000..ce2df0c
--- /dev/null
+++ b/blocks/src/lib/hdu.cc
@@ -0,0 +1,224 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include <hdu.h>
+#include <iomanip>
+#include <pickle.h>
+#include <sstream>
+#include <value_string.h>
+#include <op25_yank.h>
+
+using namespace std;
+
+hdu::hdu(const_bit_queue& frame_body) :
+ abstract_data_unit(frame_body)
+{
+}
+
+hdu::~hdu()
+{
+}
+
+string
+hdu::duid_str() const
+{
+ return string("HDU");
+}
+
+std::string
+hdu::snapshot() const
+{
+ pickle p;
+ p.add("duid", duid_str());
+ p.add("nac", nac_str());
+ p.add("mfid", mfid_str());
+ p.add("algid", algid_str());
+ p.add("kid", kid_str());
+ p.add("mi", mi_str());
+ p.add("tgid", tgid_str());
+ return p.to_string();
+}
+
+void
+hdu::do_correct_errors(bit_vector& frame)
+{
+ apply_golay_correction(frame);
+ apply_rs_correction(frame);
+}
+
+void
+hdu::apply_golay_correction(bit_vector& frame)
+{
+ static const size_t NOF_GOLAY_CODEWORDS = 36, GOLAY_CODEWORD_SZ = 18;
+ static const size_t GOLAY_CODEWORDS[NOF_GOLAY_CODEWORDS][GOLAY_CODEWORD_SZ] = {
+ { 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131 },
+ { 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 144, 145, 146, 147, 148, 149, 150, 151 },
+ { 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169 },
+ { 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187 },
+ { 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205 },
+ { 206, 207, 208, 209, 210, 211, 212, 213, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225 },
+ { 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243 },
+ { 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261 },
+ { 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279 },
+ { 280, 281, 282, 283, 284, 285, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299 },
+ { 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317 },
+ { 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335 },
+ { 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353 },
+ { 354, 355, 356, 357, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373 },
+ { 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391 },
+ { 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409 },
+ { 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427 },
+ { 428, 429, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447 },
+ { 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465 },
+ { 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483 },
+ { 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501 },
+ { 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521 },
+ { 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539 },
+ { 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557 },
+ { 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 576, 577 },
+ { 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595 },
+ { 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613 },
+ { 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631 },
+ { 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 648, 649, 650, 651 },
+ { 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669 },
+ { 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687 },
+ { 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705 },
+ { 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 720, 721, 722, 723, 724, 725 },
+ { 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743 },
+ { 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761 },
+ { 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779 }
+ };
+ for(size_t i = 0; i < NOF_GOLAY_CODEWORDS; ++i) {
+ uint32_t cw = extract(frame, GOLAY_CODEWORDS[i], GOLAY_CODEWORD_SZ);
+// uint32_t d = golay_decode(cw);
+// uint32 cw = golay_encode(cw);
+// yank_back(d, PAD_SZ, frame, GOLAY_CODEWORDS[i], GOLAY_DATA_SZ);
+ }
+}
+
+void
+hdu::apply_rs_correction(bit_vector& frame)
+{
+#if 0
+ static itpp::Reed_Solomon rs(6, 8, true);
+
+ const size_t rs_codeword[][6] = {
+ };
+ const size_t nof_codeword_bits = sizeof(codeword_bits) / sizeof(codeword_bits[0]);
+
+#endif
+}
+
+uint16_t
+hdu::frame_size_max() const
+{
+ return 792;
+}
+
+string
+hdu::algid_str() const
+{
+ const size_t ALGID_BITS[] = {
+ 356, 357, 360, 361, 374, 375, 376, 377
+ };
+ const size_t ALGID_BITS_SZ = sizeof(ALGID_BITS) / sizeof(ALGID_BITS[0]);
+ uint8_t algid = extract(frame_body(), ALGID_BITS, ALGID_BITS_SZ);
+ return lookup(algid, ALGIDS, ALGIDS_SZ);
+}
+
+string
+hdu::kid_str() const
+{
+ const size_t KID_BITS[] = {
+ 378, 379, 392, 393, 394, 395, 396, 397,
+ 410, 411, 412, 413, 414, 415, 428, 429
+ };
+ const size_t KID_BITS_SZ = sizeof(KID_BITS) / sizeof(KID_BITS[0]);
+ uint16_t kid = extract(frame_body(), KID_BITS, KID_BITS_SZ);
+ ostringstream os;
+ os << hex << showbase << setfill('0') << setw(4) << kid;
+ return os.str();
+}
+
+std::string
+hdu::mi_str() const
+{
+ const size_t MI_BITS[] = {
+ 114, 115, 116, 117, 118, 119, 132, 133,
+ 134, 135, 136, 137, 152, 153, 154, 155,
+ 156, 157, 170, 171, 172, 173, 174, 175,
+ 188, 189, 190, 191, 192, 193, 206, 207,
+ 208, 209, 210, 211, 226, 227, 228, 229,
+ 230, 231, 244, 245, 246, 247, 248, 249,
+ 262, 263, 264, 265, 266, 267, 280, 281,
+ 282, 283, 284, 285, 300, 301, 302, 303,
+ 304, 305, 318, 319, 320, 321, 322, 323,
+ };
+ const size_t MI_BITS_SZ = sizeof(MI_BITS) / sizeof(MI_BITS[0]);
+
+ uint8_t mi[9];
+ extract(frame_body(), MI_BITS, MI_BITS_SZ, mi);
+ ostringstream os;
+ os << "0x";
+ for(size_t i = 0; i < (sizeof(mi) / sizeof(mi[0])); ++i) {
+ uint16_t octet = mi[i];
+ os << hex << setfill('0') << setw(2) << octet;
+ }
+ return os.str();
+}
+
+string
+hdu::mfid_str() const
+{
+ const size_t MFID_BITS[] = {
+ 336, 337, 338, 339, 340, 341, 354, 355
+ };
+ const size_t MFID_BITS_SZ = sizeof(MFID_BITS) / sizeof(MFID_BITS_SZ);
+ uint8_t mfid = extract(frame_body(), MFID_BITS, MFID_BITS_SZ);
+ return lookup(mfid, MFIDS, MFIDS_SZ);
+}
+
+string
+hdu::nac_str() const
+{
+ const size_t NAC_BITS[] = {
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59
+ };
+ const size_t NAC_BITS_SZ = sizeof(NAC_BITS) / sizeof(NAC_BITS[0]);
+ uint32_t nac = extract(frame_body(), NAC_BITS, NAC_BITS_SZ);
+ return lookup(nac, NACS, NACS_SZ);
+}
+
+string
+hdu::tgid_str() const
+{
+ const size_t TGID_BITS[] = {
+ 432, 433, 434, 435, 448, 449, 450, 451,
+ 452, 453, 466, 467, 468, 469, 470, 471
+ };
+ const size_t TGID_BITS_SZ = sizeof(TGID_BITS) / sizeof(TGID_BITS[0]);
+ const uint16_t tgid = extract(frame_body(), TGID_BITS, TGID_BITS_SZ);
+ ostringstream os;
+ os << hex << showbase << setfill('0') << setw(4) << tgid;
+ return os.str();
+}
diff --git a/blocks/src/lib/hdu.h b/blocks/src/lib/hdu.h
new file mode 100644
index 0000000..0877199
--- /dev/null
+++ b/blocks/src/lib/hdu.h
@@ -0,0 +1,144 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_HDU_H
+#define INCLUDED_HDU_H
+
+#include <abstract_data_unit.h>
+
+/**
+ * P25 header data unit (HDU).
+ */
+class hdu : public abstract_data_unit
+{
+
+public:
+
+ /**
+ * hdu constructor.
+ *
+ * \param frame_body A const_bit_queue representing the frame body.
+ */
+ hdu(const_bit_queue& frame_body);
+
+ /**
+ * hdu virtual destructor.
+ */
+ virtual ~hdu();
+
+ /**
+ * Returns a string describing the Data Unit ID (DUID).
+ */
+ std::string duid_str() const;
+
+ /**
+ * Return a snapshot of the key fields from this frame in a manner
+ * suitable for display by the UI. The string is encoded as a
+ * pickled Python dictionary.
+ *
+ * \return A string containing the fields to display.
+ */
+ virtual std::string snapshot() const;
+
+protected:
+
+ /**
+ * Applies error correction code to the specified bit_vector.
+ *
+ * \param frame_body The bit vector to decode.
+ * \return
+ */
+ virtual void do_correct_errors(bit_vector& frame_body);
+
+ /**
+ * Apply Golay error correction code to the specified bit_vector.
+ *
+ * \param frame_body The bit vector to decode.
+ * \return
+ */
+ virtual void apply_golay_correction(bit_vector& frame_body);
+
+ /**
+ * Apply Reed-Solomon error correction code to the specified
+ * bit_vector.
+ *
+ * \param frame_body The bit vector to decode.
+ * \return
+ */
+ virtual void apply_rs_correction(bit_vector& frame_body);
+
+ /**
+ * Returns the expected size (in bits) of this data unit in
+ * bits. For variable-length data this should return UINT16_MAX
+ * until the actual length of this frame is known.
+ *
+ * \return The expected size (in bits) of this data_unit when encoded.
+ */
+ virtual uint16_t frame_size_max() const;
+
+private:
+
+ /**
+ * Return a string describing the encryption algorithm ID (ALGID).
+ *
+ * \return A string identifying the ALGID.
+ */
+ std::string algid_str() const;
+
+ /**
+ * Returns a string describing the key id (KID).
+ *
+ * \return A string identifying the KID.
+ */
+ virtual std::string kid_str() const;
+
+ /**
+ * Returns a string describing the manufacturer ID (MFID).
+ *
+ * \return A string identifying the MFID
+ */
+ virtual std::string mfid_str() const;
+
+ /**
+ * Returns a string describing the message indicator (MI).
+ *
+ * \return A string identifying the MI.
+ */
+ virtual std::string mi_str() const;
+
+ /**
+ * Returns a string describing the Network Access Code (NAC).
+ *
+ * \return A string identifying the NAC.
+ */
+ virtual std::string nac_str() const;
+
+ /**
+ * Returns a string describing the talk group id (TGID).
+ *
+ * \return A string identifying the TGID.
+ */
+ virtual std::string tgid_str() const;
+};
+
+#endif /* INCLUDED_HDU_H */
diff --git a/blocks/src/lib/imbe_decoder.cc b/blocks/src/lib/imbe_decoder.cc
new file mode 100644
index 0000000..b07b3ed
--- /dev/null
+++ b/blocks/src/lib/imbe_decoder.cc
@@ -0,0 +1,16 @@
+#include <imbe_decoder.h>
+
+imbe_decoder::~imbe_decoder()
+{
+}
+
+imbe_decoder::imbe_decoder() :
+ d_audio()
+{
+}
+
+audio_samples*
+imbe_decoder::audio()
+{
+ return &d_audio;
+}
diff --git a/blocks/src/lib/imbe_decoder.h b/blocks/src/lib/imbe_decoder.h
new file mode 100644
index 0000000..e7645f0
--- /dev/null
+++ b/blocks/src/lib/imbe_decoder.h
@@ -0,0 +1,90 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_IMBE_DECODER_H
+#define INCLUDED_IMBE_DECODER_H
+
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <deque>
+#include <vector>
+
+typedef std::deque<float> audio_samples;
+typedef std::vector<bool> voice_codeword;
+
+typedef boost::shared_ptr<class imbe_decoder> imbe_decoder_sptr;
+
+/**
+ * imbe_decoder is the interface to the various mechanisms for
+ * translating P25 voice codewords into audio samples.
+ */
+class imbe_decoder : public boost::noncopyable {
+public:
+
+ /**
+ * imbe_decoder (virtual) constructor. The exact subclass
+ * instantiated depends on some yet-to-be-decided magic.
+ *
+ * \return A shared_ptr to an imbe_decoder.
+ */
+ static imbe_decoder_sptr make();
+
+ /**
+ * imbe_decoder (virtual) destructor.
+ */
+ virtual ~imbe_decoder();
+
+ /**
+ * Decode the compressed IMBE audio.
+ *
+ * \param cw IMBE codeword (including parity check bits).
+ */
+ virtual void decode(const voice_codeword& cw) = 0;
+
+ /**
+ * Returns the audio_samples samples. These are mono samples at
+ * 8KS/s represented as a float in the range -1.0 .. +1.0.
+ *
+ * \return A non-null pointer to a deque<float> of audio samples.
+ */
+ audio_samples *audio();
+
+protected:
+
+ /**
+ * Construct an instance of imbe_decoder. Access is protected
+ * because this is an abstract class and users should call
+ * make_imbe_decoder to construct concrete instances.
+ */
+ imbe_decoder();
+
+private:
+
+ /**
+ * The audio samples produced by the IMBE decoder.
+ */
+ audio_samples d_audio;
+
+};
+
+#endif /* INCLUDED_IMBE_DECODER_H */
diff --git a/blocks/src/lib/imbe_decoder_factory.cc b/blocks/src/lib/imbe_decoder_factory.cc
new file mode 100644
index 0000000..a6238b2
--- /dev/null
+++ b/blocks/src/lib/imbe_decoder_factory.cc
@@ -0,0 +1,29 @@
+#include <dummy_imbe_decoder.h>
+#include <imbe_decoder.h>
+#include <offline_imbe_decoder.h>
+#include <software_imbe_decoder.h>
+#include <vc55_imbe_decoder.h>
+
+#include <cstdlib>
+#include <cstring>
+
+imbe_decoder_sptr
+imbe_decoder::make()
+{
+ imbe_decoder_sptr imbe;
+ const char *imbe_type = getenv("IMBE");
+ if(imbe_type) {
+ if(strcasecmp(imbe_type, "offline") == 0) {
+ imbe = imbe_decoder_sptr(new offline_imbe_decoder());
+ } else if(strcasecmp(imbe_type, "soft") == 0) {
+ imbe = imbe_decoder_sptr(new software_imbe_decoder());
+ } else if(strcasecmp(imbe_type, "vc55") == 0) {
+ imbe = imbe_decoder_sptr(new vc55_imbe_decoder());
+ } else {
+ imbe = imbe_decoder_sptr(new dummy_imbe_decoder());
+ }
+ } else {
+ imbe = imbe_decoder_sptr(new software_imbe_decoder());
+ }
+ return imbe;
+}
diff --git a/blocks/src/lib/ldu1.cc b/blocks/src/lib/ldu1.cc
new file mode 100644
index 0000000..19f9c2f
--- /dev/null
+++ b/blocks/src/lib/ldu1.cc
@@ -0,0 +1,41 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include <ldu1.h>
+
+using std::string;
+
+ldu1::ldu1(const_bit_queue& frame_body) :
+ voice_data_unit(frame_body)
+{
+}
+
+ldu1::~ldu1()
+{
+}
+
+string
+ldu1::duid_str() const
+{
+ return string("LDU1");
+}
diff --git a/blocks/src/lib/ldu1.h b/blocks/src/lib/ldu1.h
new file mode 100644
index 0000000..b9feee8
--- /dev/null
+++ b/blocks/src/lib/ldu1.h
@@ -0,0 +1,55 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_LDU1_H
+#define INCLUDED_LDU1_H
+
+#include <voice_data_unit.h>
+
+/**
+ * P25 Logical Data Unit 1.
+ */
+class ldu1 : public voice_data_unit
+{
+public:
+
+ /**
+ * ldu1 constuctor
+ *
+ * \param frame_body A const_bit_queue representing the frame body.
+ */
+ ldu1(const_bit_queue& frame_body);
+
+ /**
+ * ldu1 (virtual) destuctor
+ */
+ virtual ~ldu1();
+
+ /**
+ * Returns a string describing the Data Unit ID (DUID).
+ */
+ std::string duid_str() const;
+
+};
+
+#endif /* INCLUDED_LDU1_H */
diff --git a/blocks/src/lib/ldu2.cc b/blocks/src/lib/ldu2.cc
new file mode 100644
index 0000000..8638275
--- /dev/null
+++ b/blocks/src/lib/ldu2.cc
@@ -0,0 +1,41 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include <ldu2.h>
+
+using std::string;
+
+ldu2::ldu2(const_bit_queue& frame_body) :
+ voice_data_unit(frame_body)
+{
+}
+
+ldu2::~ldu2()
+{
+}
+
+string
+ldu2::duid_str() const
+{
+ return string("LDU2");
+}
diff --git a/blocks/src/lib/ldu2.h b/blocks/src/lib/ldu2.h
new file mode 100644
index 0000000..508482d
--- /dev/null
+++ b/blocks/src/lib/ldu2.h
@@ -0,0 +1,54 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_LDU2_H
+#define INCLUDED_LDU2_H
+
+#include <voice_data_unit.h>
+
+/**
+ * P25 Logical Data Unit 2.
+ */
+class ldu2 : public voice_data_unit
+{
+public:
+
+ /**
+ * ldu2 constructor.
+ *
+ * \param frame_body A const_bit_queue representing the frame body.
+ */
+ ldu2(const_bit_queue& frame_body);
+
+ /**
+ * ldu2 (virtual) destructor.
+ */
+ virtual ~ldu2();
+
+ /**
+ * Returns a string describing the Data Unit ID (DUID).
+ */
+ std::string duid_str() const;
+};
+
+#endif /* INCLUDED_LDU2_H */
diff --git a/blocks/src/lib/logfile_du_handler.cc b/blocks/src/lib/logfile_du_handler.cc
new file mode 100644
index 0000000..36aa9dc
--- /dev/null
+++ b/blocks/src/lib/logfile_du_handler.cc
@@ -0,0 +1,47 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include <logfile_du_handler.h>
+#include <iomanip>
+#include <stdint.h>
+
+using namespace std;
+
+logfile_du_handler::logfile_du_handler(data_unit_handler_sptr next, const char *filename) :
+ data_unit_handler(next),
+ d_log(filename)
+{
+}
+
+logfile_du_handler::~logfile_du_handler()
+{
+ d_log.flush();
+ d_log.close();
+}
+
+void
+logfile_du_handler::handle(data_unit_sptr du)
+{
+ du->dump(d_log);
+ data_unit_handler::handle(du);
+}
diff --git a/blocks/src/lib/logfile_du_handler.h b/blocks/src/lib/logfile_du_handler.h
new file mode 100644
index 0000000..f06b0f8
--- /dev/null
+++ b/blocks/src/lib/logfile_du_handler.h
@@ -0,0 +1,68 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_LOGFILE_DU_HANDLER_H
+#define INCLUDED_LOGFILE_DU_HANDLER_H
+
+#include <data_unit_handler.h>
+#include <boost/noncopyable.hpp>
+#include <fstream>
+
+/**
+ * logfile_data_unit_handler writes frames to a log file for later inspection.
+ */
+class logfile_du_handler : public data_unit_handler
+{
+
+public:
+
+ /**
+ * logfile_du_handler constructor.
+ *
+ * \param next The next data_unit_handler in the chain.
+ * \param filename The path to the log file.
+ */
+ logfile_du_handler(data_unit_handler_sptr next, const char *filename);
+
+ /**
+ * logfile_du_handler virtual destructor.
+ */
+ virtual ~logfile_du_handler();
+
+ /**
+ * Handle a received P25 frame.
+ *
+ * \param next The next data_unit_handler in this chain.
+ */
+ virtual void handle(data_unit_sptr du);
+
+private:
+
+ /**
+ * The file to which decoded frames are written.
+ */
+ std::ofstream d_log;
+
+};
+
+#endif /* INCLUDED_LOGFILE_DU_HANDLER_H */
diff --git a/blocks/src/lib/offline_imbe_decoder.cc b/blocks/src/lib/offline_imbe_decoder.cc
new file mode 100644
index 0000000..617df66
--- /dev/null
+++ b/blocks/src/lib/offline_imbe_decoder.cc
@@ -0,0 +1,63 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include <cstdio>
+#include <offline_imbe_decoder.h>
+#include <stdint.h>
+#include <op25_yank.h>
+
+using namespace std;
+
+offline_imbe_decoder::offline_imbe_decoder()
+{
+ const char *dev = getenv("IMBE_FILE");
+ if(!dev) {
+ const char *default_filename = "imbe.dat";
+ dev = default_filename;
+ }
+ d_fp = fopen(dev, "w");
+ if(NULL == d_fp) {
+ perror("fopen(dev, \"w\");"); // a warning, not an error
+ }
+}
+
+offline_imbe_decoder::~offline_imbe_decoder()
+{
+ if(d_fp) {
+ fclose(d_fp);
+ }
+}
+
+void
+offline_imbe_decoder::decode(const voice_codeword& cw)
+{
+ if(d_fp) {
+ uint8_t codewords[18];
+ extract(cw, 0, 144, codewords);
+ if(0 == fwrite(codewords, sizeof(codewords), 1, d_fp)) {
+ perror("fwrite(codewords, sizeof(codewords), 1, d_fp)");
+ fclose(d_fp);
+ d_fp = NULL;
+ }
+ }
+}
diff --git a/blocks/src/lib/offline_imbe_decoder.h b/blocks/src/lib/offline_imbe_decoder.h
new file mode 100644
index 0000000..9e45aad
--- /dev/null
+++ b/blocks/src/lib/offline_imbe_decoder.h
@@ -0,0 +1,64 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_OFFLINE_IMBE_DECODER_H
+#define INCLUDED_OFFLINE_IMBE_DECODER_H
+
+#include <imbe_decoder.h>
+
+#include <cstdio>
+
+/**
+ * offline_imbe_decoder dumps voice codewords to file for offline decoding.
+ *
+ */
+class offline_imbe_decoder : public imbe_decoder {
+public:
+
+ /**
+ * offline_imbe_decoder default constructor.
+ */
+ offline_imbe_decoder();
+
+ /**
+ * offline_imbe_decoder (virtual) destructor.
+ */
+ virtual ~offline_imbe_decoder();
+
+ /**
+ * Dump voice_codeword in_out to file.
+ *
+ * \param cw IMBE codewords and parity.
+ */
+ virtual void decode(const voice_codeword& cw);
+
+private:
+
+ /**
+ * The output file.
+ */
+ FILE *d_fp;
+
+};
+
+#endif /* INCLUDED_OFFLINE_IMBE_DECODER_H */
diff --git a/blocks/src/lib/op25.i b/blocks/src/lib/op25.i
new file mode 100644
index 0000000..b92d10b
--- /dev/null
+++ b/blocks/src/lib/op25.i
@@ -0,0 +1,109 @@
+/* -*- C++ -*- */
+
+%feature("autodoc", "1");
+
+%include "exception.i"
+%import "gnuradio.i"
+
+%{
+#include "gnuradio_swig_bug_workaround.h"
+#include "op25_fsk4_demod_ff.h"
+#include "op25_fsk4_slicer_fb.h"
+#include "op25_decoder_bf.h"
+#include "op25_pcap_source_b.h"
+%}
+
+// ----------------------------------------------------------------
+
+/*
+ * This does some behind-the-scenes magic so we can
+ * access fsk4_square_ff from python as fsk4.square_ff
+ */
+GR_SWIG_BLOCK_MAGIC(op25, fsk4_demod_ff);
+
+/*
+ * Publicly-accesible default constuctor function for op25_fsk4_demod_bf.
+ */
+op25_fsk4_demod_ff_sptr op25_make_fsk4_demod_ff(gr_msg_queue_sptr queue, float sample_rate, float symbol_rate);
+
+class op25_fsk4_demod_ff : public gr_block
+{
+private:
+ op25_fsk4_demod_ff(gr_msg_queue_sptr queue, float sample_rate, float symbol_rate);
+};
+
+// ----------------------------------------------------------------
+
+/*
+ * 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);
+};
+
+// ----------------------------------------------------------------
+
+/*
+ * This does some behind-the-scenes magic so we can invoke
+ * op25_make_decoder_bsf from python as op25.decoder_bf.
+ */
+GR_SWIG_BLOCK_MAGIC(op25, decoder_bf);
+
+/*
+ * Publicly-accesible default constuctor function for op25_decoder_bf.
+ */
+op25_decoder_bf_sptr op25_make_decoder_bf();
+
+/**
+ * The op25_decoder_bf block. Accepts a stream of dibit symbols and
+ * produces an 8KS/s audio stream.
+ */
+class op25_decoder_bf : public gr_block
+{
+private:
+ op25_decoder_bf();
+public:
+ const char *destination() const;
+ gr_msg_queue_sptr get_msgq() const;
+ void set_msgq(gr_msg_queue_sptr msgq);
+};
+
+// ----------------------------------------------------------------
+
+/*
+ * This does some behind-the-scenes magic so we can invoke
+ * op25_make_pcap_source_b from python as op25.pcap_source_b.
+ */
+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);
+
+/*
+ * 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, float delay);
+};
+
+// ----------------------------------------------------------------
diff --git a/blocks/src/lib/op25_decoder_bf.cc b/blocks/src/lib/op25_decoder_bf.cc
new file mode 100644
index 0000000..ae68638
--- /dev/null
+++ b/blocks/src/lib/op25_decoder_bf.cc
@@ -0,0 +1,221 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008-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 <itpp/comm/bch.h>
+#include <logfile_du_handler.h>
+#include <offline_imbe_decoder.h>
+#include <op25_decoder_bf.h>
+#include <snapshot_du_handler.h>
+#include <p25cai_du_handler.h>
+#include <voice_du_handler.h>
+#include <op25_yank.h>
+
+using namespace std;
+
+op25_decoder_bf_sptr
+op25_make_decoder_bf()
+{
+ return op25_decoder_bf_sptr(new op25_decoder_bf);
+}
+
+op25_decoder_bf::~op25_decoder_bf()
+{
+}
+
+gr_msg_queue_sptr
+op25_decoder_bf::get_msgq() const
+{
+ return d_snapshot_du_handler->get_msgq();
+}
+
+void
+
+op25_decoder_bf::set_msgq(gr_msg_queue_sptr msgq)
+{
+ d_snapshot_du_handler->set_msgq(msgq);
+}
+
+void
+op25_decoder_bf::forecast(int nof_outputs, gr_vector_int &nof_inputs_reqd)
+{
+ /* This block consumes 4800 symbols/s and produces 8000
+ * samples/s. That's a work rate of 3/5 or 0.6. If no audio output
+ * is available we'll produce silence.
+ */
+ const size_t nof_inputs = nof_inputs_reqd.size();
+ const int nof_samples_reqd = .6 * nof_outputs;
+ fill(&nof_inputs_reqd[0], &nof_inputs_reqd[nof_inputs], nof_samples_reqd);
+}
+
+int
+op25_decoder_bf::general_work(int nof_output_items, gr_vector_int& nof_input_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items)
+{
+ try {
+
+ // process input
+ const uint8_t *in = reinterpret_cast<const uint8_t*>(input_items[0]);
+ for(int i = 0; i < nof_input_items[0]; ++i) {
+ dibit d = in[i] & 0x3;
+ receive_symbol(d);
+ }
+ consume_each(nof_input_items[0]);
+
+ // produce audio
+ audio_samples *samples = d_imbe->audio();
+ float *out = reinterpret_cast<float*>(output_items[0]);
+ const int n = min(static_cast<int>(samples->size()), nof_output_items);
+ if(0 < n) {
+ copy(samples->begin(), samples->begin() + n, out);
+ samples->erase(samples->begin(), samples->begin() + n);
+ }
+ if(n < nof_output_items) {
+ fill(out + n, out + nof_output_items, 0.0);
+ }
+ return nof_output_items;
+
+ } catch(const std::exception& x) {
+ cerr << x.what() << endl;
+ exit(1);
+ } catch(...) {
+ cerr << "unhandled exception" << endl;
+ exit(2); }
+}
+
+const char*
+op25_decoder_bf::destination() const
+{
+ return d_p25cai_du_handler->destination();
+}
+
+op25_decoder_bf::op25_decoder_bf() :
+ gr_block("decoder_bf", gr_make_io_signature(1, 1, sizeof(uint8_t)), gr_make_io_signature(0, 1, sizeof(float))),
+ d_data_unit(),
+ d_data_unit_handler(),
+ d_frame_hdr(),
+ d_imbe(imbe_decoder::make()),
+ d_state(SYNCHRONIZING),
+ d_p25cai_du_handler(NULL)
+{
+ d_p25cai_du_handler = new p25cai_du_handler(d_data_unit_handler, "224.0.0.1", 23456);
+ d_data_unit_handler = data_unit_handler_sptr(d_p25cai_du_handler);
+ d_snapshot_du_handler = new snapshot_du_handler(d_data_unit_handler);
+ d_data_unit_handler = data_unit_handler_sptr(d_snapshot_du_handler);
+ d_data_unit_handler = data_unit_handler_sptr(new voice_du_handler(d_data_unit_handler, d_imbe));
+}
+
+bool
+op25_decoder_bf::correlated()
+{
+ static const bool FS[] = {
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 1, 1, 0, 1, 0, 1,
+ 1, 1, 1, 1, 0, 1, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 1, 1, 1, 0, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1
+ };
+ static const size_t FS_SZ = sizeof(FS)/sizeof(FS[0]);
+
+ uint8_t errs = 0;
+ for(size_t i = 0; i < FS_SZ; ++i) {
+ if(d_frame_hdr[i] ^ FS[i]) {
+ ++errs;
+ }
+ }
+ return (errs <= 4);
+}
+
+data_unit_sptr
+op25_decoder_bf::identified()
+{
+ static const size_t NID[] = {
+ 63, 62, 61, 60, 59, 58, 57, 56,
+ 55, 54, 53, 52, 51, 50, 49, 48,
+ 112, 111, 110, 109, 108, 107, 106, 105,
+ 104, 103, 102, 101, 100, 99, 98, 97,
+ 96, 95, 94, 93, 92, 91, 90, 89,
+ 88, 87, 86, 85, 84, 83, 82, 81,
+ 80, 79, 78, 77, 76, 75, 74, 73,
+ 72, 69, 68, 67, 66, 65, 64,
+ };
+ size_t NID_SZ = sizeof(NID) / sizeof(NID[0]);
+
+ itpp::bvec b(63), zeroes(16);
+ itpp::BCH bch(63, 16, 11, "6 3 3 1 1 4 1 3 6 7 2 3 5 4 5 3", true);
+ yank(d_frame_hdr, NID, NID_SZ, b, 0);
+ b = bch.decode(b);
+ if(b != zeroes) {
+ b = bch.encode(b);
+ yank_back(b, 0, d_frame_hdr, NID, NID_SZ);
+ d_data_unit = data_unit::make_data_unit(d_frame_hdr);
+ } else {
+ data_unit_sptr null;
+ d_data_unit = null;
+ }
+ return d_data_unit;
+}
+
+void
+op25_decoder_bf::receive_symbol(dibit d)
+{
+ d_frame_hdr.push_back(d & 0x2);
+ d_frame_hdr.push_back(d & 0x1);
+ const size_t frame_hdr_sz = d_frame_hdr.size();
+
+ switch(d_state) {
+ case SYNCHRONIZING:
+ if(48 <= frame_hdr_sz) {
+ d_frame_hdr.erase(d_frame_hdr.begin(), d_frame_hdr.begin() + (frame_hdr_sz - 48));
+ if(correlated()) {
+ d_state = IDENTIFYING;
+ }
+ }
+ break;
+ case IDENTIFYING:
+ if(114 == frame_hdr_sz) {
+ if(identified()) {
+ d_state = READING;
+ } else {
+ d_state = SYNCHRONIZING;
+ }
+ }
+ break;
+ case READING:
+ d_data_unit->extend(d);
+ if(d_data_unit->is_complete()) {
+ d_data_unit->correct_errors();
+ d_data_unit_handler->handle(d_data_unit);
+ data_unit_sptr null;
+ d_data_unit = null;
+ d_state = SYNCHRONIZING;
+ }
+ break;
+ }
+}
diff --git a/blocks/src/lib/op25_decoder_bf.h b/blocks/src/lib/op25_decoder_bf.h
new file mode 100644
index 0000000..421bb7d
--- /dev/null
+++ b/blocks/src/lib/op25_decoder_bf.h
@@ -0,0 +1,169 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008-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_DECODER_BF_H
+#define INCLUDED_OP25_DECODER_BF_H
+
+#include <boost/scoped_ptr.hpp>
+#include <data_unit.h>
+#include <data_unit_handler.h>
+#include <gr_block.h>
+#include <gr_msg_queue.h>
+#include <imbe_decoder.h>
+
+typedef boost::shared_ptr<class op25_decoder_bf> op25_decoder_bf_sptr;
+
+op25_decoder_bf_sptr op25_make_decoder_bf();
+
+/**
+ * op25_decoder_bf is a GNU Radio block for decoding APCO P25
+ * signals. This class expects its input to be a stream of dibit
+ * symbols from the demodulator and produces a mono audio
+ * stream.
+ */
+class op25_decoder_bf : public gr_block
+{
+public:
+
+ /**
+ * op25_decoder_bf (virtual) destructor.
+ */
+ virtual ~op25_decoder_bf();
+
+ /**
+ * Estimate nof_input_items_reqd for a given nof_output_items.
+ */
+ virtual void forecast(int nof_output_items, gr_vector_int &nof_input_items_reqd);
+
+ /**
+ * Process symbols into frames.
+ */
+ virtual int general_work(int nof_output_items, gr_vector_int& nof_input_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items);
+
+ /**
+ * Return a pointer to a string identifying the destination of
+ * the received frames.
+ *
+ * \return A pointer to a NUL-terminated character string.
+ */
+ const char *destination() const;
+
+ /**
+ * Accessor for the msgq attribute. Returns a pointer to the msgq
+ * if it exists.
+ *
+ * \return A (possibly NULL) gr_msg_queue_sptr pointing to the message queue.
+ */
+ gr_msg_queue_sptr get_msgq() const;
+
+ /**
+ * Accessor for the msgq attribute. Sets the msgq to point to the
+ * provided message queue object.
+ *
+ * \return A (possibly NULL) gr_msg_queue_sptr pointing to the message queue.
+ */
+ void set_msgq(gr_msg_queue_sptr msgq);
+
+private:
+
+ /**
+ * Expose class to public ctor. Create a new instance of
+ * op25_decoder_bf and wrap it in a shared_ptr. This is effectively
+ * the public constructor.
+ */
+ friend op25_decoder_bf_sptr op25_make_decoder_bf();
+
+ /**
+ * op25_decoder_bf private constructor.
+ */
+ op25_decoder_bf();
+
+ /**
+ * Tests whether d_frame_header correlates with the APCO P25 frame
+ * sync sequence. This method must only be called when the frame
+ * header is larger than 48 bits in length (the minimum size for
+ * the FS).
+ *
+ * \return true if the frame header correlates; otherwise false.
+ */
+ bool correlated();
+
+ /**
+ * Tests whether d_frame_header identifies a known data unit and if
+ * so sets d_data_unit to point to an appropriate instance and
+ * returns a pointer to it. This method must only be called when
+ * the frame header is larger than 114 bits in length (the minimum
+ * size for a frame containing a NID).
+ *
+ * \return A data_unit_sptr pointing to an appropriate data_unit
+ * instance or NULL if the frame header is unrecognized.
+ */
+ data_unit_sptr identified();
+
+ /**
+ * Handle a received symbol.
+ *
+ * \param d The symbol to process.
+ */
+ void receive_symbol(dibit d);
+
+private:
+
+ /**
+ * When d_state == READING the current data unit, otherwise null.
+ */
+ data_unit_sptr d_data_unit;
+
+ /**
+ * The head of a chain of data_unit_handler instances.
+ */
+ data_unit_handler_sptr d_data_unit_handler;
+
+ /**
+ * A bit_queue used to correlate the FS.
+ */
+ bit_queue d_frame_hdr;
+
+ /**
+ * The IMBE decoder to use.
+ */
+ imbe_decoder_sptr d_imbe;
+
+ /**
+ * Valid states for the decoder state model.
+ */
+ enum { SYNCHRONIZING, IDENTIFYING, READING } d_state;
+
+ /**
+ * The p25cai (TUN/TAP) data unit handler.
+ */
+ class p25cai_du_handler *d_p25cai_du_handler;
+
+ /**
+ * The snapshot data unit handler.
+ */
+ class snapshot_du_handler *d_snapshot_du_handler;
+
+};
+
+#endif /* INCLUDED_OP25_DECODER_BF_H */
diff --git a/blocks/src/lib/op25_decoder_ff.cc b/blocks/src/lib/op25_decoder_ff.cc
new file mode 100644
index 0000000..51e6f1d
--- /dev/null
+++ b/blocks/src/lib/op25_decoder_ff.cc
@@ -0,0 +1,230 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008-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 <itpp/comm/bch.h>
+#include <logfile_du_handler.h>
+#include <offline_imbe_decoder.h>
+#include <op25_decoder_ff.h>
+#include <snapshot_du_handler.h>
+#include <p25cai_du_handler.h>
+#include <voice_du_handler.h>
+#include <op25_yank.h>
+
+using namespace std;
+
+op25_decoder_ff_sptr
+op25_make_decoder_ff()
+{
+ return op25_decoder_ff_sptr(new op25_decoder_ff);
+}
+
+op25_decoder_ff::~op25_decoder_ff()
+{
+}
+
+gr_msg_queue_sptr
+op25_decoder_ff::get_msgq() const
+{
+ return d_snapshot_du_handler->get_msgq();
+}
+
+void
+
+op25_decoder_ff::set_msgq(gr_msg_queue_sptr msgq)
+{
+ d_snapshot_du_handler->set_msgq(msgq);
+}
+
+void
+op25_decoder_ff::forecast(int nof_output_items, gr_vector_int &nof_input_items_reqd)
+{
+ /* This block consumes 4800 symbols/s and produces 8000
+ * samples/s. That's a work rate of 3/5 or 0.6. If no audio output
+ * is available we'll produce silence.
+ */
+ const size_t nof_inputs = nof_input_items_reqd.size();
+ const int nof_samples_reqd = .6 * nof_output_items;
+ fill(&nof_input_items_reqd[0], &nof_input_items_reqd[nof_inputs], nof_samples_reqd);
+}
+
+int
+op25_decoder_ff::general_work(int nof_output_items, gr_vector_int& nof_input_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items)
+{
+ try {
+
+ // process input
+ const float *in = reinterpret_cast<const float*>(input_items[0]);
+ for(int i = 0; i < nof_input_items[0]; ++i) {
+ dibit d;
+ if(in[i] < -2.0) {
+ d = 3;
+ } else if(in[i] < 0.0) {
+ d = 2;
+ } else if(in[i] < 2.0) {
+ d = 0;
+ } else {
+ d = 1;
+ }
+ receive_symbol(d);
+ }
+ consume_each(nof_input_items[0]);
+
+ // produce audio
+ audio_samples *samples = d_imbe->audio();
+ float *out = reinterpret_cast<float*>(output_items[0]);
+ const int n = min(static_cast<int>(samples->size()), nof_output_items);
+ if(0 < n) {
+ copy(samples->begin(), samples->begin() + n, out);
+ samples->erase(samples->begin(), samples->begin() + n);
+ }
+ if(n < nof_output_items) {
+ fill(out + n, out + nof_output_items, 0.0);
+ }
+ return nof_output_items;
+
+ } catch(const std::exception& x) {
+ cerr << x.what() << endl;
+ exit(1);
+ } catch(...) {
+ cerr << "unhandled exception" << endl;
+ exit(2); }
+}
+
+const char*
+op25_decoder_ff::destination() const
+{
+ return d_p25cai_du_handler->destination();
+}
+
+op25_decoder_ff::op25_decoder_ff() :
+ gr_block("decoder_ff", gr_make_io_signature(1, 1, sizeof(float)), gr_make_io_signature(0, 1, sizeof(float))),
+ d_data_unit(),
+ d_data_unit_handler(),
+ d_frame_hdr(),
+ d_imbe(imbe_decoder::make()),
+ d_state(SYNCHRONIZING),
+ d_p25cai_du_handler(NULL)
+{
+ d_p25cai_du_handler = new p25cai_du_handler(d_data_unit_handler, "224.0.0.1", 23456);
+ d_data_unit_handler = data_unit_handler_sptr(d_p25cai_du_handler);
+ d_snapshot_du_handler = new snapshot_du_handler(d_data_unit_handler);
+ d_data_unit_handler = data_unit_handler_sptr(d_snapshot_du_handler);
+ d_data_unit_handler = data_unit_handler_sptr(new voice_du_handler(d_data_unit_handler, d_imbe));
+}
+
+bool
+op25_decoder_ff::correlated()
+{
+ static const bool FS[] = {
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 1, 1, 0, 1, 0, 1,
+ 1, 1, 1, 1, 0, 1, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 1, 1, 1, 0, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1
+ };
+ static const size_t FS_SZ = sizeof(FS)/sizeof(FS[0]);
+
+ uint8_t errs = 0;
+ for(size_t i = 0; i < FS_SZ; ++i) {
+ if(d_frame_hdr[i] ^ FS[i]) {
+ ++errs;
+ }
+ }
+ return (errs <= 4);
+}
+
+data_unit_sptr
+op25_decoder_ff::identified()
+{
+ static const size_t NID[] = {
+ 63, 62, 61, 60, 59, 58, 57, 56,
+ 55, 54, 53, 52, 51, 50, 49, 48,
+ 112, 111, 110, 109, 108, 107, 106, 105,
+ 104, 103, 102, 101, 100, 99, 98, 97,
+ 96, 95, 94, 93, 92, 91, 90, 89,
+ 88, 87, 86, 85, 84, 83, 82, 81,
+ 80, 79, 78, 77, 76, 75, 74, 73,
+ 72, 69, 68, 67, 66, 65, 64,
+ };
+ size_t NID_SZ = sizeof(NID) / sizeof(NID[0]);
+
+ itpp::bvec b(63), zeroes(16);
+ itpp::BCH bch(63, 16, 11, "6 3 3 1 1 4 1 3 6 7 2 3 5 4 5 3", true);
+ yank(d_frame_hdr, NID, NID_SZ, b, 0);
+ b = bch.decode(b);
+ if(b != zeroes) {
+ b = bch.encode(b);
+ yank_back(b, 0, d_frame_hdr, NID, NID_SZ);
+ d_data_unit = data_unit::make_data_unit(d_frame_hdr);
+ } else {
+ data_unit_sptr null;
+ d_data_unit = null;
+ }
+ return d_data_unit;
+}
+
+void
+op25_decoder_ff::receive_symbol(dibit d)
+{
+ d_frame_hdr.push_back(d & 0x2);
+ d_frame_hdr.push_back(d & 0x1);
+ const size_t frame_hdr_sz = d_frame_hdr.size();
+
+ switch(d_state) {
+ case SYNCHRONIZING:
+ if(48 <= frame_hdr_sz) {
+ d_frame_hdr.erase(d_frame_hdr.begin(), d_frame_hdr.begin() + (frame_hdr_sz - 48));
+ if(correlated()) {
+ d_state = IDENTIFYING;
+ }
+ }
+ break;
+ case IDENTIFYING:
+ if(114 == frame_hdr_sz) {
+ if(identified()) {
+ d_state = READING;
+ } else {
+ d_state = SYNCHRONIZING;
+ }
+ }
+ break;
+ case READING:
+ d_data_unit->extend(d);
+ if(d_data_unit->is_complete()) {
+ d_data_unit->correct_errors();
+ d_data_unit_handler->handle(d_data_unit);
+ data_unit_sptr null;
+ d_data_unit = null;
+ d_state = SYNCHRONIZING;
+ }
+ break;
+ }
+}
diff --git a/blocks/src/lib/op25_decoder_ff.h b/blocks/src/lib/op25_decoder_ff.h
new file mode 100644
index 0000000..43b6d62
--- /dev/null
+++ b/blocks/src/lib/op25_decoder_ff.h
@@ -0,0 +1,168 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008-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_DECODER_FF_H
+#define INCLUDED_OP25_DECODER_FF_H
+
+#include <boost/scoped_ptr.hpp>
+#include <data_unit.h>
+#include <data_unit_handler.h>
+#include <gr_block.h>
+#include <gr_msg_queue.h>
+#include <imbe_decoder.h>
+
+typedef boost::shared_ptr<class op25_decoder_ff> op25_decoder_ff_sptr;
+
+op25_decoder_ff_sptr op25_make_decoder_ff();
+
+/**
+ * op25_decoder_ff is a GNU Radio block for decoding APCO P25
+ * signals. This class expects its input to be a stream of dibit
+ * symbols from the demodulator and produces a mono audio
+ * stream.
+ */
+class op25_decoder_ff : public gr_block
+{
+public:
+
+ /**
+ * op25_decoder_ff (virtual) destructor.
+ */
+ virtual ~op25_decoder_ff();
+
+ /**
+ * Estimate nof_input_items_reqd for a given nof_output_items.
+ */
+ virtual void forecast(int nof_output_items, gr_vector_int &nof_input_items_reqd);
+
+ /**
+ * Process symbols into frames.
+ */
+ virtual int general_work(int nof_output_items, gr_vector_int& nof_input_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items);
+ /**
+ * Return a pointer to a string identifying the destination of
+ * the received frames.
+ *
+ * \return A pointer to a NUL-terminated character string.
+ */
+ const char *destination() const;
+
+ /**
+ * Accessor for the msgq attribute. Returns a pointer to the msgq
+ * if it exists.
+ *
+ * \return A (possibly NULL) gr_msg_queue_sptr pointing to the message queue.
+ */
+ gr_msg_queue_sptr get_msgq() const;
+
+ /**
+ * Accessor for the msgq attribute. Sets the msgq to point to the
+ * provided message queue object.
+ *
+ * \return A (possibly NULL) gr_msg_queue_sptr pointing to the message queue.
+ */
+ void set_msgq(gr_msg_queue_sptr msgq);
+
+private:
+
+ /**
+ * Expose class to public ctor. Create a new instance of
+ * op25_decoder_ff and wrap it in a shared_ptr. This is effectively
+ * the public constructor.
+ */
+ friend op25_decoder_ff_sptr op25_make_decoder_ff();
+
+ /**
+ * op25_decoder_ff protected constructor.
+ */
+ op25_decoder_ff();
+
+ /**
+ * Tests whether d_frame_header correlates with the APCO P25 frame
+ * sync sequence. This method must only be called when the frame
+ * header is larger than 48 bits in length (the minimum size for
+ * the FS).
+ *
+ * \return true if the frame header correlates; otherwise false.
+ */
+ bool correlated();
+
+ /**
+ * Tests whether d_frame_header identifies a known data unit and if
+ * so sets d_data_unit to point to an appropriate instance and
+ * returns a pointer to it. This method must only be called when
+ * the frame header is larger than 114 bits in length (the minimum
+ * size for a frame containing a NID).
+ *
+ * \return A data_unit_sptr pointing to an appropriate data_unit
+ * instance or NULL if the frame header is unrecognized.
+ */
+ data_unit_sptr identified();
+
+ /**
+ * Handle a received symbol.
+ *
+ * \param d The symbol to process.
+ */
+ void receive_symbol(dibit d);
+
+private:
+
+ /**
+ * When d_state == READING the current data unit, otherwise null.
+ */
+ data_unit_sptr d_data_unit;
+
+ /**
+ * The head of a chain of data_unit_handler instances.
+ */
+ data_unit_handler_sptr d_data_unit_handler;
+
+ /**
+ * A bit_queue used to correlate the FS.
+ */
+ bit_queue d_frame_hdr;
+
+ /**
+ * The IMBE decoder to use.
+ */
+ imbe_decoder_sptr d_imbe;
+
+ /**
+ * Valid states for the decoder state model.
+ */
+ enum { SYNCHRONIZING, IDENTIFYING, READING } d_state;
+
+ /**
+ * The p25cai (TUN/TAP) data unit handler.
+ */
+ class p25cai_du_handler *d_p25cai_du_handler;
+
+ /**
+ * The snapshot data unit handler.
+ */
+ class snapshot_du_handler *d_snapshot_du_handler;
+
+};
+
+#endif /* INCLUDED_OP25_DECODER_FF_H */
diff --git a/blocks/src/lib/op25_fsk4_demod_ff.cc b/blocks/src/lib/op25_fsk4_demod_ff.cc
new file mode 100644
index 0000000..c816841
--- /dev/null
+++ b/blocks/src/lib/op25_fsk4_demod_ff.cc
@@ -0,0 +1,361 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2006, 2007 Frank (Radio Rausch)
+ * Copyright 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 <op25_fsk4_demod_ff.h>
+#include <gr_io_signature.h>
+#include <gr_math.h>
+
+using namespace std;
+
+/*
+ * This table was machine-generated by gen_interpolator_taps.
+ * DO NOT EDIT BY HAND.
+ */
+static const int NTAPS = 8;
+static const int NSTEPS = 128;
+static const float TAPS[NSTEPS+1][NTAPS] = {
+ // -4 -3 -2 -1 0 1 2 3 mu
+ { 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 1.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00 }, // 0/128
+ { -1.54700e-04, 8.53777e-04, -2.76968e-03, 7.89295e-03, 9.98534e-01, -5.41054e-03, 1.24642e-03, -1.98993e-04 }, // 1/128
+ { -3.09412e-04, 1.70888e-03, -5.55134e-03, 1.58840e-02, 9.96891e-01, -1.07209e-02, 2.47942e-03, -3.96391e-04 }, // 2/128
+ { -4.64053e-04, 2.56486e-03, -8.34364e-03, 2.39714e-02, 9.95074e-01, -1.59305e-02, 3.69852e-03, -5.92100e-04 }, // 3/128
+ { -6.18544e-04, 3.42130e-03, -1.11453e-02, 3.21531e-02, 9.93082e-01, -2.10389e-02, 4.90322e-03, -7.86031e-04 }, // 4/128
+ { -7.72802e-04, 4.27773e-03, -1.39548e-02, 4.04274e-02, 9.90917e-01, -2.60456e-02, 6.09305e-03, -9.78093e-04 }, // 5/128
+ { -9.26747e-04, 5.13372e-03, -1.67710e-02, 4.87921e-02, 9.88580e-01, -3.09503e-02, 7.26755e-03, -1.16820e-03 }, // 6/128
+ { -1.08030e-03, 5.98883e-03, -1.95925e-02, 5.72454e-02, 9.86071e-01, -3.57525e-02, 8.42626e-03, -1.35627e-03 }, // 7/128
+ { -1.23337e-03, 6.84261e-03, -2.24178e-02, 6.57852e-02, 9.83392e-01, -4.04519e-02, 9.56876e-03, -1.54221e-03 }, // 8/128
+ { -1.38589e-03, 7.69462e-03, -2.52457e-02, 7.44095e-02, 9.80543e-01, -4.50483e-02, 1.06946e-02, -1.72594e-03 }, // 9/128
+ { -1.53777e-03, 8.54441e-03, -2.80746e-02, 8.31162e-02, 9.77526e-01, -4.95412e-02, 1.18034e-02, -1.90738e-03 }, // 10/128
+ { -1.68894e-03, 9.39154e-03, -3.09033e-02, 9.19033e-02, 9.74342e-01, -5.39305e-02, 1.28947e-02, -2.08645e-03 }, // 11/128
+ { -1.83931e-03, 1.02356e-02, -3.37303e-02, 1.00769e-01, 9.70992e-01, -5.82159e-02, 1.39681e-02, -2.26307e-03 }, // 12/128
+ { -1.98880e-03, 1.10760e-02, -3.65541e-02, 1.09710e-01, 9.67477e-01, -6.23972e-02, 1.50233e-02, -2.43718e-03 }, // 13/128
+ { -2.13733e-03, 1.19125e-02, -3.93735e-02, 1.18725e-01, 9.63798e-01, -6.64743e-02, 1.60599e-02, -2.60868e-03 }, // 14/128
+ { -2.28483e-03, 1.27445e-02, -4.21869e-02, 1.27812e-01, 9.59958e-01, -7.04471e-02, 1.70776e-02, -2.77751e-03 }, // 15/128
+ { -2.43121e-03, 1.35716e-02, -4.49929e-02, 1.36968e-01, 9.55956e-01, -7.43154e-02, 1.80759e-02, -2.94361e-03 }, // 16/128
+ { -2.57640e-03, 1.43934e-02, -4.77900e-02, 1.46192e-01, 9.51795e-01, -7.80792e-02, 1.90545e-02, -3.10689e-03 }, // 17/128
+ { -2.72032e-03, 1.52095e-02, -5.05770e-02, 1.55480e-01, 9.47477e-01, -8.17385e-02, 2.00132e-02, -3.26730e-03 }, // 18/128
+ { -2.86289e-03, 1.60193e-02, -5.33522e-02, 1.64831e-01, 9.43001e-01, -8.52933e-02, 2.09516e-02, -3.42477e-03 }, // 19/128
+ { -3.00403e-03, 1.68225e-02, -5.61142e-02, 1.74242e-01, 9.38371e-01, -8.87435e-02, 2.18695e-02, -3.57923e-03 }, // 20/128
+ { -3.14367e-03, 1.76185e-02, -5.88617e-02, 1.83711e-01, 9.33586e-01, -9.20893e-02, 2.27664e-02, -3.73062e-03 }, // 21/128
+ { -3.28174e-03, 1.84071e-02, -6.15931e-02, 1.93236e-01, 9.28650e-01, -9.53307e-02, 2.36423e-02, -3.87888e-03 }, // 22/128
+ { -3.41815e-03, 1.91877e-02, -6.43069e-02, 2.02814e-01, 9.23564e-01, -9.84679e-02, 2.44967e-02, -4.02397e-03 }, // 23/128
+ { -3.55283e-03, 1.99599e-02, -6.70018e-02, 2.12443e-01, 9.18329e-01, -1.01501e-01, 2.53295e-02, -4.16581e-03 }, // 24/128
+ { -3.68570e-03, 2.07233e-02, -6.96762e-02, 2.22120e-01, 9.12947e-01, -1.04430e-01, 2.61404e-02, -4.30435e-03 }, // 25/128
+ { -3.81671e-03, 2.14774e-02, -7.23286e-02, 2.31843e-01, 9.07420e-01, -1.07256e-01, 2.69293e-02, -4.43955e-03 }, // 26/128
+ { -3.94576e-03, 2.22218e-02, -7.49577e-02, 2.41609e-01, 9.01749e-01, -1.09978e-01, 2.76957e-02, -4.57135e-03 }, // 27/128
+ { -4.07279e-03, 2.29562e-02, -7.75620e-02, 2.51417e-01, 8.95936e-01, -1.12597e-01, 2.84397e-02, -4.69970e-03 }, // 28/128
+ { -4.19774e-03, 2.36801e-02, -8.01399e-02, 2.61263e-01, 8.89984e-01, -1.15113e-01, 2.91609e-02, -4.82456e-03 }, // 29/128
+ { -4.32052e-03, 2.43930e-02, -8.26900e-02, 2.71144e-01, 8.83893e-01, -1.17526e-01, 2.98593e-02, -4.94589e-03 }, // 30/128
+ { -4.44107e-03, 2.50946e-02, -8.52109e-02, 2.81060e-01, 8.77666e-01, -1.19837e-01, 3.05345e-02, -5.06363e-03 }, // 31/128
+ { -4.55932e-03, 2.57844e-02, -8.77011e-02, 2.91006e-01, 8.71305e-01, -1.22047e-01, 3.11866e-02, -5.17776e-03 }, // 32/128
+ { -4.67520e-03, 2.64621e-02, -9.01591e-02, 3.00980e-01, 8.64812e-01, -1.24154e-01, 3.18153e-02, -5.28823e-03 }, // 33/128
+ { -4.78866e-03, 2.71272e-02, -9.25834e-02, 3.10980e-01, 8.58189e-01, -1.26161e-01, 3.24205e-02, -5.39500e-03 }, // 34/128
+ { -4.89961e-03, 2.77794e-02, -9.49727e-02, 3.21004e-01, 8.51437e-01, -1.28068e-01, 3.30021e-02, -5.49804e-03 }, // 35/128
+ { -5.00800e-03, 2.84182e-02, -9.73254e-02, 3.31048e-01, 8.44559e-01, -1.29874e-01, 3.35600e-02, -5.59731e-03 }, // 36/128
+ { -5.11376e-03, 2.90433e-02, -9.96402e-02, 3.41109e-01, 8.37557e-01, -1.31581e-01, 3.40940e-02, -5.69280e-03 }, // 37/128
+ { -5.21683e-03, 2.96543e-02, -1.01915e-01, 3.51186e-01, 8.30432e-01, -1.33189e-01, 3.46042e-02, -5.78446e-03 }, // 38/128
+ { -5.31716e-03, 3.02507e-02, -1.04150e-01, 3.61276e-01, 8.23188e-01, -1.34699e-01, 3.50903e-02, -5.87227e-03 }, // 39/128
+ { -5.41467e-03, 3.08323e-02, -1.06342e-01, 3.71376e-01, 8.15826e-01, -1.36111e-01, 3.55525e-02, -5.95620e-03 }, // 40/128
+ { -5.50931e-03, 3.13987e-02, -1.08490e-01, 3.81484e-01, 8.08348e-01, -1.37426e-01, 3.59905e-02, -6.03624e-03 }, // 41/128
+ { -5.60103e-03, 3.19495e-02, -1.10593e-01, 3.91596e-01, 8.00757e-01, -1.38644e-01, 3.64044e-02, -6.11236e-03 }, // 42/128
+ { -5.68976e-03, 3.24843e-02, -1.12650e-01, 4.01710e-01, 7.93055e-01, -1.39767e-01, 3.67941e-02, -6.18454e-03 }, // 43/128
+ { -5.77544e-03, 3.30027e-02, -1.14659e-01, 4.11823e-01, 7.85244e-01, -1.40794e-01, 3.71596e-02, -6.25277e-03 }, // 44/128
+ { -5.85804e-03, 3.35046e-02, -1.16618e-01, 4.21934e-01, 7.77327e-01, -1.41727e-01, 3.75010e-02, -6.31703e-03 }, // 45/128
+ { -5.93749e-03, 3.39894e-02, -1.18526e-01, 4.32038e-01, 7.69305e-01, -1.42566e-01, 3.78182e-02, -6.37730e-03 }, // 46/128
+ { -6.01374e-03, 3.44568e-02, -1.20382e-01, 4.42134e-01, 7.61181e-01, -1.43313e-01, 3.81111e-02, -6.43358e-03 }, // 47/128
+ { -6.08674e-03, 3.49066e-02, -1.22185e-01, 4.52218e-01, 7.52958e-01, -1.43968e-01, 3.83800e-02, -6.48585e-03 }, // 48/128
+ { -6.15644e-03, 3.53384e-02, -1.23933e-01, 4.62289e-01, 7.44637e-01, -1.44531e-01, 3.86247e-02, -6.53412e-03 }, // 49/128
+ { -6.22280e-03, 3.57519e-02, -1.25624e-01, 4.72342e-01, 7.36222e-01, -1.45004e-01, 3.88454e-02, -6.57836e-03 }, // 50/128
+ { -6.28577e-03, 3.61468e-02, -1.27258e-01, 4.82377e-01, 7.27714e-01, -1.45387e-01, 3.90420e-02, -6.61859e-03 }, // 51/128
+ { -6.34530e-03, 3.65227e-02, -1.28832e-01, 4.92389e-01, 7.19116e-01, -1.45682e-01, 3.92147e-02, -6.65479e-03 }, // 52/128
+ { -6.40135e-03, 3.68795e-02, -1.30347e-01, 5.02377e-01, 7.10431e-01, -1.45889e-01, 3.93636e-02, -6.68698e-03 }, // 53/128
+ { -6.45388e-03, 3.72167e-02, -1.31800e-01, 5.12337e-01, 7.01661e-01, -1.46009e-01, 3.94886e-02, -6.71514e-03 }, // 54/128
+ { -6.50285e-03, 3.75341e-02, -1.33190e-01, 5.22267e-01, 6.92808e-01, -1.46043e-01, 3.95900e-02, -6.73929e-03 }, // 55/128
+ { -6.54823e-03, 3.78315e-02, -1.34515e-01, 5.32164e-01, 6.83875e-01, -1.45993e-01, 3.96678e-02, -6.75943e-03 }, // 56/128
+ { -6.58996e-03, 3.81085e-02, -1.35775e-01, 5.42025e-01, 6.74865e-01, -1.45859e-01, 3.97222e-02, -6.77557e-03 }, // 57/128
+ { -6.62802e-03, 3.83650e-02, -1.36969e-01, 5.51849e-01, 6.65779e-01, -1.45641e-01, 3.97532e-02, -6.78771e-03 }, // 58/128
+ { -6.66238e-03, 3.86006e-02, -1.38094e-01, 5.61631e-01, 6.56621e-01, -1.45343e-01, 3.97610e-02, -6.79588e-03 }, // 59/128
+ { -6.69300e-03, 3.88151e-02, -1.39150e-01, 5.71370e-01, 6.47394e-01, -1.44963e-01, 3.97458e-02, -6.80007e-03 }, // 60/128
+ { -6.71985e-03, 3.90083e-02, -1.40136e-01, 5.81063e-01, 6.38099e-01, -1.44503e-01, 3.97077e-02, -6.80032e-03 }, // 61/128
+ { -6.74291e-03, 3.91800e-02, -1.41050e-01, 5.90706e-01, 6.28739e-01, -1.43965e-01, 3.96469e-02, -6.79662e-03 }, // 62/128
+ { -6.76214e-03, 3.93299e-02, -1.41891e-01, 6.00298e-01, 6.19318e-01, -1.43350e-01, 3.95635e-02, -6.78902e-03 }, // 63/128
+ { -6.77751e-03, 3.94578e-02, -1.42658e-01, 6.09836e-01, 6.09836e-01, -1.42658e-01, 3.94578e-02, -6.77751e-03 }, // 64/128
+ { -6.78902e-03, 3.95635e-02, -1.43350e-01, 6.19318e-01, 6.00298e-01, -1.41891e-01, 3.93299e-02, -6.76214e-03 }, // 65/128
+ { -6.79662e-03, 3.96469e-02, -1.43965e-01, 6.28739e-01, 5.90706e-01, -1.41050e-01, 3.91800e-02, -6.74291e-03 }, // 66/128
+ { -6.80032e-03, 3.97077e-02, -1.44503e-01, 6.38099e-01, 5.81063e-01, -1.40136e-01, 3.90083e-02, -6.71985e-03 }, // 67/128
+ { -6.80007e-03, 3.97458e-02, -1.44963e-01, 6.47394e-01, 5.71370e-01, -1.39150e-01, 3.88151e-02, -6.69300e-03 }, // 68/128
+ { -6.79588e-03, 3.97610e-02, -1.45343e-01, 6.56621e-01, 5.61631e-01, -1.38094e-01, 3.86006e-02, -6.66238e-03 }, // 69/128
+ { -6.78771e-03, 3.97532e-02, -1.45641e-01, 6.65779e-01, 5.51849e-01, -1.36969e-01, 3.83650e-02, -6.62802e-03 }, // 70/128
+ { -6.77557e-03, 3.97222e-02, -1.45859e-01, 6.74865e-01, 5.42025e-01, -1.35775e-01, 3.81085e-02, -6.58996e-03 }, // 71/128
+ { -6.75943e-03, 3.96678e-02, -1.45993e-01, 6.83875e-01, 5.32164e-01, -1.34515e-01, 3.78315e-02, -6.54823e-03 }, // 72/128
+ { -6.73929e-03, 3.95900e-02, -1.46043e-01, 6.92808e-01, 5.22267e-01, -1.33190e-01, 3.75341e-02, -6.50285e-03 }, // 73/128
+ { -6.71514e-03, 3.94886e-02, -1.46009e-01, 7.01661e-01, 5.12337e-01, -1.31800e-01, 3.72167e-02, -6.45388e-03 }, // 74/128
+ { -6.68698e-03, 3.93636e-02, -1.45889e-01, 7.10431e-01, 5.02377e-01, -1.30347e-01, 3.68795e-02, -6.40135e-03 }, // 75/128
+ { -6.65479e-03, 3.92147e-02, -1.45682e-01, 7.19116e-01, 4.92389e-01, -1.28832e-01, 3.65227e-02, -6.34530e-03 }, // 76/128
+ { -6.61859e-03, 3.90420e-02, -1.45387e-01, 7.27714e-01, 4.82377e-01, -1.27258e-01, 3.61468e-02, -6.28577e-03 }, // 77/128
+ { -6.57836e-03, 3.88454e-02, -1.45004e-01, 7.36222e-01, 4.72342e-01, -1.25624e-01, 3.57519e-02, -6.22280e-03 }, // 78/128
+ { -6.53412e-03, 3.86247e-02, -1.44531e-01, 7.44637e-01, 4.62289e-01, -1.23933e-01, 3.53384e-02, -6.15644e-03 }, // 79/128
+ { -6.48585e-03, 3.83800e-02, -1.43968e-01, 7.52958e-01, 4.52218e-01, -1.22185e-01, 3.49066e-02, -6.08674e-03 }, // 80/128
+ { -6.43358e-03, 3.81111e-02, -1.43313e-01, 7.61181e-01, 4.42134e-01, -1.20382e-01, 3.44568e-02, -6.01374e-03 }, // 81/128
+ { -6.37730e-03, 3.78182e-02, -1.42566e-01, 7.69305e-01, 4.32038e-01, -1.18526e-01, 3.39894e-02, -5.93749e-03 }, // 82/128
+ { -6.31703e-03, 3.75010e-02, -1.41727e-01, 7.77327e-01, 4.21934e-01, -1.16618e-01, 3.35046e-02, -5.85804e-03 }, // 83/128
+ { -6.25277e-03, 3.71596e-02, -1.40794e-01, 7.85244e-01, 4.11823e-01, -1.14659e-01, 3.30027e-02, -5.77544e-03 }, // 84/128
+ { -6.18454e-03, 3.67941e-02, -1.39767e-01, 7.93055e-01, 4.01710e-01, -1.12650e-01, 3.24843e-02, -5.68976e-03 }, // 85/128
+ { -6.11236e-03, 3.64044e-02, -1.38644e-01, 8.00757e-01, 3.91596e-01, -1.10593e-01, 3.19495e-02, -5.60103e-03 }, // 86/128
+ { -6.03624e-03, 3.59905e-02, -1.37426e-01, 8.08348e-01, 3.81484e-01, -1.08490e-01, 3.13987e-02, -5.50931e-03 }, // 87/128
+ { -5.95620e-03, 3.55525e-02, -1.36111e-01, 8.15826e-01, 3.71376e-01, -1.06342e-01, 3.08323e-02, -5.41467e-03 }, // 88/128
+ { -5.87227e-03, 3.50903e-02, -1.34699e-01, 8.23188e-01, 3.61276e-01, -1.04150e-01, 3.02507e-02, -5.31716e-03 }, // 89/128
+ { -5.78446e-03, 3.46042e-02, -1.33189e-01, 8.30432e-01, 3.51186e-01, -1.01915e-01, 2.96543e-02, -5.21683e-03 }, // 90/128
+ { -5.69280e-03, 3.40940e-02, -1.31581e-01, 8.37557e-01, 3.41109e-01, -9.96402e-02, 2.90433e-02, -5.11376e-03 }, // 91/128
+ { -5.59731e-03, 3.35600e-02, -1.29874e-01, 8.44559e-01, 3.31048e-01, -9.73254e-02, 2.84182e-02, -5.00800e-03 }, // 92/128
+ { -5.49804e-03, 3.30021e-02, -1.28068e-01, 8.51437e-01, 3.21004e-01, -9.49727e-02, 2.77794e-02, -4.89961e-03 }, // 93/128
+ { -5.39500e-03, 3.24205e-02, -1.26161e-01, 8.58189e-01, 3.10980e-01, -9.25834e-02, 2.71272e-02, -4.78866e-03 }, // 94/128
+ { -5.28823e-03, 3.18153e-02, -1.24154e-01, 8.64812e-01, 3.00980e-01, -9.01591e-02, 2.64621e-02, -4.67520e-03 }, // 95/128
+ { -5.17776e-03, 3.11866e-02, -1.22047e-01, 8.71305e-01, 2.91006e-01, -8.77011e-02, 2.57844e-02, -4.55932e-03 }, // 96/128
+ { -5.06363e-03, 3.05345e-02, -1.19837e-01, 8.77666e-01, 2.81060e-01, -8.52109e-02, 2.50946e-02, -4.44107e-03 }, // 97/128
+ { -4.94589e-03, 2.98593e-02, -1.17526e-01, 8.83893e-01, 2.71144e-01, -8.26900e-02, 2.43930e-02, -4.32052e-03 }, // 98/128
+ { -4.82456e-03, 2.91609e-02, -1.15113e-01, 8.89984e-01, 2.61263e-01, -8.01399e-02, 2.36801e-02, -4.19774e-03 }, // 99/128
+ { -4.69970e-03, 2.84397e-02, -1.12597e-01, 8.95936e-01, 2.51417e-01, -7.75620e-02, 2.29562e-02, -4.07279e-03 }, // 100/128
+ { -4.57135e-03, 2.76957e-02, -1.09978e-01, 9.01749e-01, 2.41609e-01, -7.49577e-02, 2.22218e-02, -3.94576e-03 }, // 101/128
+ { -4.43955e-03, 2.69293e-02, -1.07256e-01, 9.07420e-01, 2.31843e-01, -7.23286e-02, 2.14774e-02, -3.81671e-03 }, // 102/128
+ { -4.30435e-03, 2.61404e-02, -1.04430e-01, 9.12947e-01, 2.22120e-01, -6.96762e-02, 2.07233e-02, -3.68570e-03 }, // 103/128
+ { -4.16581e-03, 2.53295e-02, -1.01501e-01, 9.18329e-01, 2.12443e-01, -6.70018e-02, 1.99599e-02, -3.55283e-03 }, // 104/128
+ { -4.02397e-03, 2.44967e-02, -9.84679e-02, 9.23564e-01, 2.02814e-01, -6.43069e-02, 1.91877e-02, -3.41815e-03 }, // 105/128
+ { -3.87888e-03, 2.36423e-02, -9.53307e-02, 9.28650e-01, 1.93236e-01, -6.15931e-02, 1.84071e-02, -3.28174e-03 }, // 106/128
+ { -3.73062e-03, 2.27664e-02, -9.20893e-02, 9.33586e-01, 1.83711e-01, -5.88617e-02, 1.76185e-02, -3.14367e-03 }, // 107/128
+ { -3.57923e-03, 2.18695e-02, -8.87435e-02, 9.38371e-01, 1.74242e-01, -5.61142e-02, 1.68225e-02, -3.00403e-03 }, // 108/128
+ { -3.42477e-03, 2.09516e-02, -8.52933e-02, 9.43001e-01, 1.64831e-01, -5.33522e-02, 1.60193e-02, -2.86289e-03 }, // 109/128
+ { -3.26730e-03, 2.00132e-02, -8.17385e-02, 9.47477e-01, 1.55480e-01, -5.05770e-02, 1.52095e-02, -2.72032e-03 }, // 110/128
+ { -3.10689e-03, 1.90545e-02, -7.80792e-02, 9.51795e-01, 1.46192e-01, -4.77900e-02, 1.43934e-02, -2.57640e-03 }, // 111/128
+ { -2.94361e-03, 1.80759e-02, -7.43154e-02, 9.55956e-01, 1.36968e-01, -4.49929e-02, 1.35716e-02, -2.43121e-03 }, // 112/128
+ { -2.77751e-03, 1.70776e-02, -7.04471e-02, 9.59958e-01, 1.27812e-01, -4.21869e-02, 1.27445e-02, -2.28483e-03 }, // 113/128
+ { -2.60868e-03, 1.60599e-02, -6.64743e-02, 9.63798e-01, 1.18725e-01, -3.93735e-02, 1.19125e-02, -2.13733e-03 }, // 114/128
+ { -2.43718e-03, 1.50233e-02, -6.23972e-02, 9.67477e-01, 1.09710e-01, -3.65541e-02, 1.10760e-02, -1.98880e-03 }, // 115/128
+ { -2.26307e-03, 1.39681e-02, -5.82159e-02, 9.70992e-01, 1.00769e-01, -3.37303e-02, 1.02356e-02, -1.83931e-03 }, // 116/128
+ { -2.08645e-03, 1.28947e-02, -5.39305e-02, 9.74342e-01, 9.19033e-02, -3.09033e-02, 9.39154e-03, -1.68894e-03 }, // 117/128
+ { -1.90738e-03, 1.18034e-02, -4.95412e-02, 9.77526e-01, 8.31162e-02, -2.80746e-02, 8.54441e-03, -1.53777e-03 }, // 118/128
+ { -1.72594e-03, 1.06946e-02, -4.50483e-02, 9.80543e-01, 7.44095e-02, -2.52457e-02, 7.69462e-03, -1.38589e-03 }, // 119/128
+ { -1.54221e-03, 9.56876e-03, -4.04519e-02, 9.83392e-01, 6.57852e-02, -2.24178e-02, 6.84261e-03, -1.23337e-03 }, // 120/128
+ { -1.35627e-03, 8.42626e-03, -3.57525e-02, 9.86071e-01, 5.72454e-02, -1.95925e-02, 5.98883e-03, -1.08030e-03 }, // 121/128
+ { -1.16820e-03, 7.26755e-03, -3.09503e-02, 9.88580e-01, 4.87921e-02, -1.67710e-02, 5.13372e-03, -9.26747e-04 }, // 122/128
+ { -9.78093e-04, 6.09305e-03, -2.60456e-02, 9.90917e-01, 4.04274e-02, -1.39548e-02, 4.27773e-03, -7.72802e-04 }, // 123/128
+ { -7.86031e-04, 4.90322e-03, -2.10389e-02, 9.93082e-01, 3.21531e-02, -1.11453e-02, 3.42130e-03, -6.18544e-04 }, // 124/128
+ { -5.92100e-04, 3.69852e-03, -1.59305e-02, 9.95074e-01, 2.39714e-02, -8.34364e-03, 2.56486e-03, -4.64053e-04 }, // 125/128
+ { -3.96391e-04, 2.47942e-03, -1.07209e-02, 9.96891e-01, 1.58840e-02, -5.55134e-03, 1.70888e-03, -3.09412e-04 }, // 126/128
+ { -1.98993e-04, 1.24642e-03, -5.41054e-03, 9.98534e-01, 7.89295e-03, -2.76968e-03, 8.53777e-04, -1.54700e-04 }, // 127/128
+ { 0.00000e+00, 0.00000e+00, 0.00000e+00, 1.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00 }, // 128/128
+};
+
+op25_fsk4_demod_ff::~op25_fsk4_demod_ff ()
+{
+}
+
+void
+op25_fsk4_demod_ff::forecast(int nof_outputs, gr_vector_int &nof_inputs_reqd)
+{
+ const int nof_samples_reqd = static_cast<int>(ceil(d_block_rate * nof_outputs));
+ fill(&nof_inputs_reqd[0], &nof_inputs_reqd[nof_inputs_reqd.size()], nof_samples_reqd);
+}
+
+int
+op25_fsk4_demod_ff::general_work (int nof_outputs, gr_vector_int &nof_inputs, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items)
+{
+ int n = 0;
+
+ const float *in = reinterpret_cast<const float*>(input_items[0]);
+ float *out = reinterpret_cast<float*>(output_items[0]);
+
+ // first we run through all provided data
+ for(int i = 0; i < nof_outputs; i++) {
+ if(tracking_loop_mmse(in[i], &out[n])) {
+ ++n;
+ }
+ }
+
+ // send frequency adjusment request if needed
+ send_frequency_correction();
+
+ consume_each(nof_outputs);
+ return n;
+}
+
+op25_fsk4_demod_ff_sptr
+op25_make_fsk4_demod_ff(gr_msg_queue_sptr queue, float sample_rate_Hz, float symbol_rate_Hz)
+{
+ return op25_fsk4_demod_ff_sptr(new op25_fsk4_demod_ff(queue, sample_rate_Hz, symbol_rate_Hz));
+}
+
+op25_fsk4_demod_ff::op25_fsk4_demod_ff (gr_msg_queue_sptr queue, float sample_rate_Hz, float symbol_rate_Hz) :
+ gr_block ("fsk4_demod_ff", gr_make_io_signature(1, 1, sizeof(float)), gr_make_io_signature(1, 1, sizeof(float))),
+ d_block_rate(sample_rate_Hz / symbol_rate_Hz),
+ d_history(new float[NTAPS]),
+ d_history_last(0),
+ d_queue(queue),
+ d_symbol_clock(0.0),
+ d_symbol_spread(2.0), // nominal symbol spread of 2.0 gives outputs at -3, -1, +1, +3
+ d_symbol_time(symbol_rate_Hz / sample_rate_Hz)
+{
+ fine_frequency_correction = 0.0;
+ coarse_frequency_correction = 0.0;
+
+ fill(&d_history[0], &d_history[NTAPS], 0.0);
+}
+
+void
+op25_fsk4_demod_ff::send_frequency_correction()
+{
+ double arg1, arg2;
+
+ // if the queue is full, don't block, drop the data...
+ if(d_queue->full_p())
+ return;
+
+ const double COARSE_FREQUENCY_DEADBAND = 1.66; // gnuradio frequency adjust messages will not be emitted until we exceed this threshold
+
+ if((coarse_frequency_correction < COARSE_FREQUENCY_DEADBAND) && (coarse_frequency_correction > -COARSE_FREQUENCY_DEADBAND))
+ return;
+
+ arg1 = coarse_frequency_correction;
+ arg2 = 0.0;
+ coarse_frequency_correction = 0.0;
+
+ // build & send a message
+ gr_message_sptr msg = gr_make_message(0, arg1, arg2, 0); // vlen() * sizeof(float));
+ d_queue->insert_tail(msg);
+ msg.reset();
+}
+
+bool
+op25_fsk4_demod_ff::tracking_loop_mmse(float input, float *output)
+{
+ d_symbol_clock += d_symbol_time;
+
+ d_history[d_history_last++] = input;
+ d_history_last %= NTAPS;
+
+ if(d_symbol_clock > 1.0) {
+
+ d_symbol_clock -= 1.0;
+
+ // at this point we state that linear interpolation was tried
+ // but found to be slightly inferior. Using MMSE interpolation
+ // shouldn't be a terrible burden
+
+#if 0
+ int imu = min(static_cast<int>(floor(0.5 + (NSTEPS * (d_symbol_clock / d_symbol_time)))), NSTEPS - 1);
+ int imu_p1 = imu + 1;
+#else
+ int imu = (int) floor(0.5 + (NSTEPS * ((d_symbol_clock / d_symbol_time))));
+ int imu_p1 = imu + 1;
+ if (imu >= NSTEPS) {
+ imu = NSTEPS - 1;
+ imu_p1 = NSTEPS;
+ }
+#endif
+
+#if 0
+ double interp = 0.0;
+ double interp_p1 = 0.0;
+ for(size_t i = 0, j = d_history_last; i < NTAPS; ++i) {
+ interp += TAPS[imu][i] * d_history[j];
+ interp_p1 += TAPS[imu_p1][i] * d_history[j];
+ j = (j + 1) % NTAPS;
+ }
+#else
+ size_t j = d_history_last;
+ double interp = 0.0;
+ double interp_p1 = 0.0;
+ for(int i=0; i<NTAPS; i++)
+ {
+ interp += TAPS[imu ][i] * d_history[j];
+ interp_p1 += TAPS[imu_p1][i] * d_history[j];
+ j = (j+1) % NTAPS;
+ }
+#endif
+
+ // our output symbol will be interpolated value corrected for symbol_spread and frequency offset
+ interp -= fine_frequency_correction;
+ interp_p1 -= fine_frequency_correction;
+
+ // output is corrected for symbol deviation (spread)
+ *output = 2.0 * interp / d_symbol_spread;
+
+ // detect received symbol error: basically use a hard decision
+ // and subtract off expected position nominal symbol level which
+ // will be +/- 0.5 * symbol_spread and +/- 1.5 * symbol_spread
+ // remember: nominal symbol_spread will be 2.0
+
+ double symbol_error;
+ const double K_SYMBOL_SPREAD = 0.0100; // tracking loop gain constant
+ if(interp < - d_symbol_spread) {
+ // symbol is -3: Expected at -1.5 * symbol_spread
+ symbol_error = interp + (1.5 * d_symbol_spread);
+ d_symbol_spread -= (symbol_error * 0.5 * K_SYMBOL_SPREAD);
+ } else if(interp < 0.0) {
+ // symbol is -1: Expected at -0.5 * symbol_spread
+ symbol_error = interp + (0.5 * d_symbol_spread);
+ d_symbol_spread -= (symbol_error * K_SYMBOL_SPREAD);
+ } else if(interp < d_symbol_spread) {
+ // symbol is +1: Expected at +0.5 * symbol_spread
+ symbol_error = interp - (0.5 * d_symbol_spread);
+ d_symbol_spread += (symbol_error * K_SYMBOL_SPREAD);
+ } else {
+ // symbol is +3: Expected at +1.5 * symbol_spread
+ symbol_error = interp - (1.5 * d_symbol_spread);
+ d_symbol_spread += (symbol_error * 0.5 * K_SYMBOL_SPREAD);
+ }
+
+ // symbol clock tracking loop gain
+ const double K_SYMBOL_TIMING = 0.025;
+ if(interp_p1 < interp) {
+ d_symbol_clock += symbol_error * K_SYMBOL_TIMING;
+ } else {
+ d_symbol_clock -= symbol_error * K_SYMBOL_TIMING;
+ }
+
+ // constraints on symbol spreading
+ const double SYMBOL_SPREAD_MAX = 2.4; // upper range limit: +20%
+ const double SYMBOL_SPREAD_MIN = 1.6; // lower range limit: -20%
+
+ // it seems reasonable to constrain symbol spread to +/- 20% of nominal 2.0
+ d_symbol_spread = max(d_symbol_spread, SYMBOL_SPREAD_MIN);
+ d_symbol_spread = min(d_symbol_spread, SYMBOL_SPREAD_MAX);
+
+ // coarse tracking loop: for eventually frequency shift request generation
+ static const double K_COARSE_FREQUENCY = 0.00125; // time constant for coarse tracking loop
+ coarse_frequency_correction += ((fine_frequency_correction - coarse_frequency_correction) * K_COARSE_FREQUENCY);
+
+ // fine loop
+ static const double K_FINE_FREQUENCY = 0.125; // internal fast loop (must be this high to acquire symbol sync)
+ fine_frequency_correction += (symbol_error * K_FINE_FREQUENCY);
+
+ return true;
+ }
+ return false;
+}
diff --git a/blocks/src/lib/op25_fsk4_demod_ff.h b/blocks/src/lib/op25_fsk4_demod_ff.h
new file mode 100644
index 0000000..903b479
--- /dev/null
+++ b/blocks/src/lib/op25_fsk4_demod_ff.h
@@ -0,0 +1,113 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2006, 2007 Frank (Radio Rausch)
+ * Copyright 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_FSK4_DEMOD_FF_H
+#define INCLUDED_OP25_FSK4_DEMOD_FF_H
+
+#include <gr_block.h>
+#include <gr_msg_queue.h>
+
+#include <boost/scoped_array.hpp>
+
+typedef boost::shared_ptr<class op25_fsk4_demod_ff> op25_fsk4_demod_ff_sptr;
+
+op25_fsk4_demod_ff_sptr op25_make_fsk4_demod_ff(gr_msg_queue_sptr queue, float sample_rate, float symbol_rate);
+
+/**
+ * op25_fsk4_demod_ff is a GNU Radio block for demodulating APCO P25
+ * CF4M signals. This class expects its input to consist of a 4 level
+ * FSK modulated baseband signal. It produces a stream of symbols.
+ *
+ * All inputs are post FM demodulator and symbol shaping filter data
+ * is normalized before being sent to this block so these parameters
+ * should not need adjusting even when working on different signals.
+ *
+ * Nominal levels are -3, -1, +1, and +3.
+ */
+class op25_fsk4_demod_ff : public gr_block
+{
+public:
+
+ /**
+ * op25_fsk4_demod_ff (virtual) destructor.
+ */
+ virtual ~op25_fsk4_demod_ff();
+
+ /**
+ * Estimate nof_input_items_reqd for a given nof_output_items.
+ */
+ virtual void forecast(int noutput_items, gr_vector_int &inputs_required);
+
+ /**
+ * Process baseband into symbols.
+ */
+ virtual int general_work(int noutput_items, gr_vector_int &ninput_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_fsk4_demod_ff and wrap it in a shared_ptr. This is
+ * effectively the public constructor.
+ */
+ friend op25_fsk4_demod_ff_sptr op25_make_fsk4_demod_ff(gr_msg_queue_sptr queue, float sample_rate, float symbol_rate);
+
+ /**
+ * op25_fsk4_demod_ff private constructor.
+ */
+ op25_fsk4_demod_ff(gr_msg_queue_sptr queue, float sample_rate, float symbol_rate);
+
+ /**
+ * Called when we want the input frequency to be adjusted.
+ */
+ void send_frequency_correction();
+
+ /**
+ * Tracking loop.
+ */
+ bool tracking_loop_mmse(float input, float *output);
+
+private:
+
+ const float d_block_rate;
+
+ boost::scoped_array<float> d_history;
+
+ size_t d_history_last;
+
+ gr_msg_queue_sptr d_queue;
+
+ double d_symbol_clock;
+
+ double d_symbol_spread;
+
+ const float d_symbol_time;
+
+ double fine_frequency_correction;
+
+ double coarse_frequency_correction;
+
+};
+
+#endif /* INCLUDED_OP25_FSK4_DEMOD_FF_H */
diff --git a/blocks/src/lib/op25_fsk4_slicer_fb.cc b/blocks/src/lib/op25_fsk4_slicer_fb.cc
new file mode 100644
index 0000000..4fa9b03
--- /dev/null
+++ b/blocks/src/lib/op25_fsk4_slicer_fb.cc
@@ -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;
+}
diff --git a/blocks/src/lib/op25_fsk4_slicer_fb.h b/blocks/src/lib/op25_fsk4_slicer_fb.h
new file mode 100644
index 0000000..aa7a92b
--- /dev/null
+++ b/blocks/src/lib/op25_fsk4_slicer_fb.h
@@ -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 */
diff --git a/blocks/src/lib/op25_golay.h b/blocks/src/lib/op25_golay.h
new file mode 100644
index 0000000..36a2aab
--- /dev/null
+++ b/blocks/src/lib/op25_golay.h
@@ -0,0 +1,206 @@
+#ifndef INCLUDED_OP25_GOLAY_H
+#define INCLUDED_OP25_GOLAY_H
+
+#include <cstddef>
+#include <stdint.h>
+
+static inline uint32_t
+golay_24_encode(uint32_t code_word_in)
+{
+ static const uint32_t encoding[12] = {
+ 040006165,
+ 020003073,
+ 010007550,
+ 04003664,
+ 02001732,
+ 01006631,
+ 0403315,
+ 0201547,
+ 0106706,
+ 045227,
+ 024476,
+ 014353
+ };
+
+ uint32_t code_word_out = 0;
+ for(uint16_t i = 0; i < 12; i++) {
+ uint32_t temp_word = code_word_in & (1 << (11 - i));
+ if(temp_word >= 1) {
+ code_word_out = code_word_out ^ encoding[i];
+ }
+ }
+ return(code_word_out);
+}
+
+/* APCO Golay(23,11,7) ecoder.
+ *
+ * \param val The 12-bit value to encode.
+ * \return The encoded codeword.
+ */
+
+static inline uint32_t
+golay_23_encode(uint32_t code_word_in)
+{
+ return golay_24_encode(code_word_in) >> 1;
+}
+
+static inline uint32_t
+golay_23_syndrome(uint32_t pattern)
+{
+ uint32_t aux = 0x400000;
+ while(pattern & 0xFFFFF800) {
+ while((aux & pattern) == 0) {
+ aux >>= 1;
+ }
+ pattern ^= (aux >> 11) * 0xC75;
+ }
+ return pattern;
+}
+/* APCO Golay(23,11,7) decoder.
+ *
+ * \param cw The 23-bit codeword to decode.
+ * \return The number of errors detected.
+ */
+
+static inline size_t
+golay_23_decode(uint32_t& cw)
+{
+ static const uint32_t decoding[2048] = {
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 147459,
+ 1, 2, 2, 3, 2, 3, 3, 4268035, 2, 3, 3, 1574915, 3, 2097155, 294915, 4099,
+ 1, 2, 2, 3, 2, 3, 3, 147459, 2, 3, 3, 147459, 3, 147459, 147459, 147458,
+ 2, 3, 3, 32771, 3, 2051, 3149827, 786435, 3, 274435, 4194307, 2162691, 589827, 5275651, 10243, 147459,
+ 1, 2, 2, 3, 2, 3, 3, 2621443, 2, 3, 3, 8195, 3, 1118211, 294915, 4196355,
+ 2, 3, 3, 135171, 3, 2051, 294915, 1064963, 3, 4210691, 294915, 2162691, 294915, 663555, 294914, 294915,
+ 2, 3, 3, 5505027, 3, 2051, 65539, 45059, 3, 557059, 6147, 2162691, 6299651, 262147, 1572867, 147459,
+ 3, 2051, 548867, 2162691, 2051, 2050, 4325379, 2051, 1179651, 2162691, 2162691, 2162690, 20483, 2051, 294915, 2162691,
+ 1, 2, 2, 3, 2, 3, 3, 2621443, 2, 3, 3, 327683, 3, 43011, 5242883, 4099,
+ 2, 3, 3, 32771, 3, 1441795, 18435, 4099, 3, 4210691, 2236419, 4099, 589827, 4099, 4099, 4098,
+ 2, 3, 3, 32771, 3, 4198403, 270339, 1116163, 3, 3145731, 6147, 4726787, 589827, 262147, 2129923, 147459,
+ 3, 32771, 32771, 32770, 589827, 2121731, 4325379, 32771, 589827, 133123, 1327107, 32771, 589826, 589827, 589827, 4099,
+ 2, 3, 3, 2621443, 3, 2621443, 2621443, 2621442, 3, 4210691, 6147, 1212419, 131075, 262147, 90115, 2621443,
+ 3, 4210691, 1114115, 272387, 12291, 98307, 4325379, 2621443, 4210691, 4210690, 524291, 4210691, 3147779, 4210691, 294915, 4099,
+ 3, 204803, 6147, 16387, 1097731, 262147, 4325379, 2621443, 6147, 262147, 6146, 6147, 262147, 262146, 6147, 262147,
+ 2359299, 1576963, 4325379, 32771, 4325379, 2051, 4325378, 4325379, 40963, 4210691, 6147, 2162691, 589827, 262147, 4325379, 1056771,
+ 1, 2, 2, 3, 2, 3, 3, 268291, 2, 3, 3, 8195, 3, 2097155, 5242883, 622595,
+ 2, 3, 3, 32771, 3, 2097155, 655363, 1064963, 3, 2097155, 86019, 4587523, 2097155, 2097154, 10243, 2097155,
+ 2, 3, 3, 32771, 3, 1581059, 65539, 6291459, 3, 4261891, 2883587, 1052675, 36867, 262147, 10243, 147459,
+ 3, 32771, 32771, 32770, 4472835, 200707, 10243, 32771, 1179651, 540675, 10243, 32771, 10243, 2097155, 10242, 10243,
+ 2, 3, 3, 8195, 3, 4358147, 65539, 1064963, 3, 8195, 8195, 8194, 542723, 262147, 2232323, 8195,
+ 3, 851971, 6293507, 1064963, 12291, 1064963, 1064963, 1064962, 1179651, 38915, 524291, 8195, 4259843, 2097155, 294915, 1064963,
+ 3, 2117635, 65539, 657411, 65539, 262147, 65538, 65539, 1179651, 262147, 4243459, 8195, 262147, 262146, 65539, 262147,
+ 1179651, 4202499, 266243, 32771, 2654211, 2051, 65539, 1064963, 1179650, 1179651, 1179651, 2162691, 1179651, 262147, 10243, 4722691,
+ 2, 3, 3, 32771, 3, 81923, 5242883, 139267, 3, 659459, 5242883, 2115587, 5242883, 262147, 5242882, 5242883,
+ 3, 32771, 32771, 32770, 12291, 4720643, 2424835, 32771, 264195, 1122307, 524291, 32771, 180227, 2097155, 5242883, 4099,
+ 3, 32771, 32771, 32770, 2230275, 262147, 544771, 32771, 24579, 262147, 196611, 32771, 262147, 262146, 5242883, 262147,
+ 32771, 32770, 32770, 32769, 1048579, 32771, 32771, 32770, 6295555, 32771, 32771, 32770, 589827, 262147, 10243, 32771,
+ 3, 1050627, 409603, 4263939, 12291, 262147, 34819, 2621443, 2195459, 262147, 524291, 8195, 262147, 262146, 5242883, 262147,
+ 12291, 2228227, 524291, 32771, 12290, 12291, 12291, 1064963, 524291, 4210691, 524290, 524291, 12291, 262147, 524291, 198659,
+ 4718595, 262147, 3153923, 32771, 262147, 262146, 65539, 262147, 262147, 262146, 6147, 262147, 262146, 262145, 262147, 262146,
+ 83971, 32771, 32771, 32770, 12291, 262147, 4325379, 32771, 1179651, 262147, 524291, 32771, 262147, 262146, 2113539, 262147,
+ 1, 2, 2, 3, 2, 3, 3, 1081347, 2, 3, 3, 327683, 3, 2097155, 536579, 4196355,
+ 2, 3, 3, 135171, 3, 2097155, 18435, 786435, 3, 2097155, 4194307, 57347, 2097155, 2097154, 1245187, 2097155,
+ 2, 3, 3, 2107395, 3, 4198403, 65539, 786435, 3, 557059, 4194307, 1052675, 1312771, 73731, 2129923, 147459,
+ 3, 1130499, 4194307, 786435, 172035, 786435, 786435, 786434, 4194307, 133123, 4194306, 4194307, 20483, 2097155, 4194307, 786435,
+ 2, 3, 3, 135171, 3, 286723, 65539, 4196355, 3, 557059, 3162115, 4196355, 131075, 4196355, 4196355, 4196354,
+ 3, 135171, 135171, 135170, 5767171, 98307, 2105347, 135171, 75779, 1310723, 524291, 135171, 20483, 2097155, 294915, 4196355,
+ 3, 557059, 65539, 16387, 65539, 3276803, 65538, 65539, 557059, 557058, 401411, 557059, 20483, 557059, 65539, 4196355,
+ 2359299, 4202499, 1083395, 135171, 20483, 2051, 65539, 786435, 20483, 557059, 4194307, 2162691, 20482, 20483, 20483, 1056771,
+ 2, 3, 3, 327683, 3, 4198403, 18435, 139267, 3, 327683, 327683, 327682, 131075, 1589251, 2129923, 327683,
+ 3, 532483, 18435, 7340035, 18435, 98307, 18434, 18435, 1085443, 133123, 524291, 327683, 4464643, 2097155, 18435, 4099,
+ 3, 4198403, 1703939, 16387, 4198403, 4198402, 2129923, 4198403, 24579, 133123, 2129923, 327683, 2129923, 4198403, 2129922, 2129923,
+ 2359299, 133123, 77827, 32771, 1048579, 4198403, 18435, 786435, 133123, 133122, 4194307, 133123, 589827, 133123, 2129923, 1056771,
+ 3, 1050627, 4235267, 16387, 131075, 98307, 1314819, 2621443, 131075, 2109443, 524291, 327683, 131074, 131075, 131075, 4196355,
+ 2359299, 98307, 524291, 135171, 98307, 98306, 18435, 98307, 524291, 4210691, 524290, 524291, 131075, 98307, 524291, 1056771,
+ 2359299, 16387, 16387, 16386, 534531, 4198403, 65539, 16387, 5308419, 557059, 6147, 16387, 131075, 262147, 2129923, 1056771,
+ 2359298, 2359299, 2359299, 16387, 2359299, 98307, 4325379, 1056771, 2359299, 133123, 524291, 1056771, 20483, 1056771, 1056771, 1056770,
+ 2, 3, 3, 4734979, 3, 2097155, 65539, 139267, 3, 2097155, 165891, 1052675, 2097155, 2097154, 278531, 2097155,
+ 3, 2097155, 1318915, 67587, 2097155, 2097154, 4231171, 2097155, 2097155, 2097154, 524291, 2097155, 2097154, 2097153, 2097155, 2097154,
+ 3, 393219, 65539, 1052675, 65539, 51203, 65538, 65539, 24579, 1052675, 1052675, 1052674, 4849667, 2097155, 65539, 1052675,
+ 530435, 4202499, 2244611, 32771, 1048579, 2097155, 65539, 786435, 360451, 2097155, 4194307, 1052675, 2097155, 2097154, 10243, 2097155,
+ 3, 1050627, 65539, 2392067, 65539, 528387, 65538, 65539, 4460547, 212995, 524291, 8195, 1089539, 2097155, 65539, 4196355,
+ 49155, 4202499, 524291, 135171, 395267, 2097155, 65539, 1064963, 524291, 2097155, 524290, 524291, 2097155, 2097154, 524291, 2097155,
+ 65539, 4202499, 65538, 65539, 65538, 65539, 65537, 65538, 2099203, 557059, 65539, 1052675, 65539, 262147, 65538, 65539,
+ 4202499, 4202498, 65539, 4202499, 65539, 4202499, 65538, 65539, 1179651, 4202499, 524291, 280579, 20483, 2097155, 65539, 163843,
+ 3, 1050627, 2101251, 139267, 819203, 139267, 139267, 139266, 24579, 4227075, 524291, 327683, 71683, 2097155, 5242883, 139267,
+ 4390915, 282627, 524291, 32771, 1048579, 2097155, 18435, 139267, 524291, 2097155, 524290, 524291, 2097155, 2097154, 524291, 2097155,
+ 24579, 2686979, 4458499, 32771, 1048579, 4198403, 65539, 139267, 24578, 24579, 24579, 1052675, 24579, 262147, 2129923, 526339,
+ 1048579, 32771, 32771, 32770, 1048578, 1048579, 1048579, 32771, 24579, 133123, 524291, 32771, 1048579, 2097155, 397315, 4276227,
+ 1050627, 1050626, 524291, 1050627, 6307843, 1050627, 65539, 139267, 524291, 1050627, 524290, 524291, 131075, 262147, 524291, 53251,
+ 524291, 1050627, 524290, 524291, 12291, 98307, 524291, 4456451, 524290, 524291, 524289, 524290, 524291, 2097155, 524290, 524291,
+ 167939, 1050627, 65539, 16387, 65539, 262147, 65538, 65539, 24579, 262147, 524291, 6422531, 262147, 262146, 65539, 262147,
+ 2359299, 4202499, 524291, 32771, 1048579, 671747, 65539, 2103299, 524291, 69635, 524290, 524291, 4229123, 262147, 524291, 1056771,
+ 1, 2, 2, 3, 2, 3, 3, 1081347, 2, 3, 3, 8195, 3, 4980739, 2164739, 4099,
+ 2, 3, 3, 2375683, 3, 2051, 655363, 4099, 3, 229379, 4194307, 4099, 1073155, 4099, 4099, 4098,
+ 2, 3, 3, 593923, 3, 2051, 270339, 6291459, 3, 3145731, 4194307, 296963, 36867, 73731, 1572867, 147459,
+ 3, 2051, 4194307, 1187843, 2051, 2050, 114691, 2051, 4194307, 540675, 4194306, 4194307, 2490371, 2051, 4194307, 4099,
+ 2, 3, 3, 8195, 3, 2051, 4214787, 458755, 3, 8195, 8195, 8194, 131075, 2146307, 1572867, 8195,
+ 3, 2051, 1114115, 4751363, 2051, 2050, 2105347, 2051, 2625539, 1310723, 149507, 8195, 4259843, 2051, 294915, 4099,
+ 3, 2051, 2260995, 16387, 2051, 2050, 1572867, 2051, 344067, 4329475, 1572867, 8195, 1572867, 2051, 1572866, 1572867,
+ 2051, 2050, 266243, 2051, 2050, 2049, 2051, 2050, 40963, 2051, 4194307, 2162691, 2051, 2050, 1572867, 2051,
+ 2, 3, 3, 4327427, 3, 81923, 270339, 4099, 3, 3145731, 573443, 4099, 131075, 4099, 4099, 4098,
+ 3, 532483, 1114115, 4099, 6324227, 4099, 4099, 4098, 264195, 4099, 4099, 4098, 4099, 4098, 4098, 4097,
+ 3, 3145731, 270339, 16387, 270339, 688131, 270338, 270339, 3145731, 3145730, 196611, 3145731, 4212739, 3145731, 270339, 4099,
+ 151555, 4521987, 2623491, 32771, 1048579, 2051, 270339, 4099, 40963, 3145731, 4194307, 4099, 589827, 4099, 4099, 4098,
+ 3, 299011, 1114115, 16387, 131075, 5251075, 34819, 2621443, 131075, 591875, 6553603, 8195, 131074, 131075, 131075, 4099,
+ 1114115, 2228227, 1114114, 1114115, 802819, 2051, 1114115, 4099, 40963, 4210691, 1114115, 4099, 131075, 4099, 4099, 4098,
+ 4718595, 16387, 16387, 16386, 2166787, 2051, 270339, 16387, 40963, 3145731, 6147, 16387, 131075, 262147, 1572867, 4292611,
+ 40963, 2051, 1114115, 16387, 2051, 2050, 4325379, 2051, 40962, 40963, 40963, 917507, 40963, 2051, 2113539, 4099,
+ 2, 3, 3, 8195, 3, 81923, 655363, 6291459, 3, 8195, 8195, 8194, 36867, 1181699, 278531, 8195,
+ 3, 5246979, 655363, 67587, 655363, 303107, 655362, 655363, 264195, 540675, 3178499, 8195, 4259843, 2097155, 655363, 4099,
+ 3, 393219, 1067011, 6291459, 36867, 6291459, 6291459, 6291458, 36867, 540675, 196611, 8195, 36866, 36867, 36867, 6291459,
+ 2170883, 540675, 266243, 32771, 1048579, 2051, 655363, 6291459, 540675, 540674, 4194307, 540675, 36867, 540675, 10243, 1376259,
+ 3, 8195, 8195, 8194, 3407875, 528387, 34819, 8195, 8195, 8194, 8194, 8193, 4259843, 8195, 8195, 8194,
+ 49155, 2228227, 266243, 8195, 4259843, 2051, 655363, 1064963, 4259843, 8195, 8195, 8194, 4259842, 4259843, 4259843, 8195,
+ 4718595, 1146883, 266243, 8195, 155651, 2051, 65539, 6291459, 2099203, 8195, 8195, 8194, 36867, 262147, 1572867, 8195,
+ 266243, 2051, 266242, 266243, 2051, 2050, 266243, 2051, 1179651, 540675, 266243, 8195, 4259843, 2051, 2113539, 163843,
+ 3, 81923, 2101251, 1835011, 81923, 81922, 34819, 81923, 264195, 4227075, 196611, 8195, 2629635, 81923, 5242883, 4099,
+ 264195, 2228227, 4218883, 32771, 1048579, 81923, 655363, 4099, 264194, 264195, 264195, 4099, 264195, 4099, 4099, 4098,
+ 4718595, 14339, 196611, 32771, 1048579, 81923, 270339, 6291459, 196611, 3145731, 196610, 196611, 36867, 262147, 196611, 526339,
+ 1048579, 32771, 32771, 32770, 1048578, 1048579, 1048579, 32771, 264195, 540675, 196611, 32771, 1048579, 4333571, 2113539, 4099,
+ 4718595, 2228227, 34819, 8195, 34819, 81923, 34818, 34819, 1069059, 8195, 8195, 8194, 131075, 262147, 34819, 8195,
+ 2228227, 2228226, 1114115, 2228227, 12291, 2228227, 34819, 4456451, 264195, 2228227, 524291, 8195, 4259843, 1605635, 2113539, 4099,
+ 4718594, 4718595, 4718595, 16387, 4718595, 262147, 34819, 1183747, 4718595, 262147, 196611, 8195, 262147, 262146, 2113539, 262147,
+ 4718595, 2228227, 266243, 32771, 1048579, 2051, 2113539, 598019, 40963, 69635, 2113539, 5244931, 2113539, 262147, 2113538, 2113539,
+ 2, 3, 3, 1081347, 3, 1081347, 1081347, 1081346, 3, 22531, 4194307, 2752515, 131075, 73731, 278531, 1081347,
+ 3, 532483, 4194307, 67587, 331779, 4341763, 2105347, 1081347, 4194307, 1310723, 4194306, 4194307, 559107, 2097155, 4194307, 4099,
+ 3, 393219, 4194307, 16387, 2637827, 73731, 137219, 1081347, 4194307, 73731, 4194306, 4194307, 73731, 73730, 4194307, 73731,
+ 4194307, 2134019, 4194306, 4194307, 1048579, 2051, 4194307, 786435, 4194306, 4194307, 4194305, 4194306, 4194307, 73731, 4194306, 4194307,
+ 3, 6356995, 788483, 16387, 131075, 528387, 2105347, 1081347, 131075, 1310723, 102403, 8195, 131074, 131075, 131075, 4196355,
+ 49155, 1310723, 2105347, 135171, 2105347, 2051, 2105346, 2105347, 1310723, 1310722, 4194307, 1310723, 131075, 1310723, 2105347, 606211,
+ 1060867, 16387, 16387, 16386, 4489219, 2051, 65539, 16387, 2099203, 557059, 4194307, 16387, 131075, 73731, 1572867, 2363395,
+ 720899, 2051, 4194307, 16387, 2051, 2050, 2105347, 2051, 4194307, 1310723, 4194306, 4194307, 20483, 2051, 4194307, 163843,
+ 3, 532483, 2101251, 16387, 131075, 2361347, 4784131, 1081347, 131075, 4227075, 1058819, 327683, 131074, 131075, 131075, 4099,
+ 532483, 532482, 425987, 532483, 1048579, 532483, 18435, 4099, 2179075, 532483, 4194307, 4099, 131075, 4099, 4099, 4098,
+ 100355, 16387, 16387, 16386, 1048579, 4198403, 270339, 16387, 790531, 3145731, 4194307, 16387, 131075, 73731, 2129923, 526339,
+ 1048579, 532483, 4194307, 16387, 1048578, 1048579, 1048579, 2293763, 4194307, 133123, 4194306, 4194307, 1048579, 311299, 4194307, 4099,
+ 131075, 16387, 16387, 16386, 131074, 131075, 131075, 16387, 131074, 131075, 131075, 16387, 131073, 131074, 131074, 131075,
+ 4200451, 532483, 1114115, 16387, 131075, 98307, 2105347, 4456451, 131075, 1310723, 524291, 2131971, 131074, 131075, 131075, 4099,
+ 16387, 16386, 16386, 16385, 131075, 16387, 16387, 16386, 131075, 16387, 16387, 16386, 131074, 131075, 131075, 16387,
+ 2359299, 16387, 16387, 16386, 1048579, 2051, 561155, 16387, 40963, 69635, 4194307, 16387, 131075, 6815747, 329731, 1056771,
+ 3, 393219, 2101251, 67587, 4204547, 528387, 278531, 1081347, 1638403, 4227075, 278531, 8195, 278531, 2097155, 278530, 278531,
+ 49155, 67587, 67587, 67586, 1048579, 2097155, 655363, 67587, 143363, 2097155, 4194307, 67587, 2097155, 2097154, 278531, 2097155,
+ 393219, 393218, 565251, 393219, 1048579, 393219, 65539, 6291459, 2099203, 393219, 4194307, 1052675, 36867, 73731, 278531, 526339,
+ 1048579, 393219, 4194307, 67587, 1048578, 1048579, 1048579, 28675, 4194307, 540675, 4194306, 4194307, 1048579, 2097155, 4194307, 163843,
+ 49155, 528387, 5373955, 8195, 528387, 528386, 65539, 528387, 2099203, 8195, 8195, 8194, 131075, 528387, 278531, 8195,
+ 49154, 49155, 49155, 67587, 49155, 528387, 2105347, 4456451, 49155, 1310723, 524291, 8195, 4259843, 2097155, 1054723, 163843,
+ 2099203, 393219, 65539, 16387, 65539, 528387, 65538, 65539, 2099202, 2099203, 2099203, 8195, 2099203, 5259267, 65539, 163843,
+ 49155, 4202499, 266243, 3670019, 1048579, 2051, 65539, 163843, 2099203, 69635, 4194307, 163843, 794627, 163843, 163843, 163842,
+ 2101251, 4227075, 2101250, 2101251, 1048579, 81923, 2101251, 139267, 4227075, 4227074, 2101251, 4227075, 131075, 4227075, 278531, 526339,
+ 1048579, 532483, 2101251, 67587, 1048578, 1048579, 1048579, 4456451, 264195, 4227075, 524291, 1196035, 1048579, 2097155, 106499, 4099,
+ 1048579, 393219, 2101251, 16387, 1048578, 1048579, 1048579, 526339, 24579, 4227075, 196611, 526339, 1048579, 526339, 526339, 526338,
+ 1048578, 1048579, 1048579, 32771, 1048577, 1048578, 1048578, 1048579, 1048579, 69635, 4194307, 2367491, 1048578, 1048579, 1048579, 526339,
+ 335875, 1050627, 2101251, 16387, 131075, 528387, 34819, 4456451, 131075, 4227075, 524291, 8195, 131074, 131075, 131075, 3211267,
+ 49155, 2228227, 524291, 4456451, 1048579, 4456451, 4456451, 4456450, 524291, 69635, 524290, 524291, 131075, 26627, 524291, 4456451,
+ 4718595, 16387, 16387, 16386, 1048579, 2138115, 65539, 16387, 2099203, 69635, 1343491, 16387, 131075, 262147, 4206595, 526339,
+ 1048579, 69635, 141315, 16387, 1048578, 1048579, 1048579, 4456451, 69635, 69634, 524291, 69635, 1048579, 69635, 2113539, 163843
+ };
+
+ cw &= 0x007fffff;
+ unsigned int correction = decoding[golay_23_syndrome(cw)];
+ cw ^= correction;
+ cw >>= 11;
+ return correction & 3;
+}
+
+#endif /* INCLUDED_OP25_GOLAY_H */
diff --git a/blocks/src/lib/op25_hamming.h b/blocks/src/lib/op25_hamming.h
new file mode 100644
index 0000000..0ab3c7a
--- /dev/null
+++ b/blocks/src/lib/op25_hamming.h
@@ -0,0 +1,186 @@
+#ifndef INCLUDED_OP25_HAMMING_H
+#define INCLUDED_OP25_HAMMING_H
+
+#include <cstddef>
+#include <stdint.h>
+
+/*
+ * APCO Hamming(15,11,3) ecoder.
+ *
+ * \param val The 11-bit value to encode.
+ * \return The encoded codeword.
+ */
+static inline uint16_t
+hamming_15_encode(uint16_t code_word_in)
+{
+ static long int encoding[11] = {
+ 0x400f, 0x200e, 0x100d, 0x080c, 0x040b, 0x020a, 0x0109,
+ 0x0087, 0x0046, 0x0025, 0x0013
+ };
+
+ uint16_t code_word_out = 0u;
+ for(uint8_t i = 0; i < 11; ++i) {
+ if(code_word_in & (1u << (10 - i))) {
+ code_word_out ^= encoding[i];
+ }
+ }
+ return code_word_out;
+}
+
+/*
+ * APCO Hamming(15,11,3) decoder.
+ *
+ * \param cw The 15-bit codeword to decode.
+ * \return The number of errors detected.
+ */
+static inline size_t
+hamming_15_decode(uint16_t& cw)
+{
+ static const int encoding[2048] = {
+ 0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
+ 9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
+ 10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
+ 3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
+ 11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
+ 2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
+ 1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
+ 8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15,
+ 12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
+ 5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
+ 6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
+ 15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
+ 7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
+ 14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
+ 13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
+ 4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
+ 13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
+ 4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
+ 7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
+ 14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
+ 6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
+ 15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
+ 12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
+ 5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
+ 1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
+ 8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15,
+ 11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
+ 2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
+ 10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
+ 3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
+ 0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
+ 9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
+ 14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
+ 7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
+ 4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
+ 13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
+ 5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
+ 12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
+ 15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
+ 6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
+ 2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
+ 11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
+ 8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15,
+ 1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
+ 9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
+ 0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
+ 3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
+ 10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
+ 3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
+ 10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
+ 9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
+ 0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
+ 8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15,
+ 1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
+ 2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
+ 11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
+ 15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
+ 6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
+ 5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
+ 12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
+ 4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
+ 13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
+ 14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
+ 7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
+ 15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
+ 6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
+ 5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
+ 12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
+ 4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
+ 13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
+ 14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
+ 7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
+ 3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
+ 10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
+ 9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
+ 0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
+ 8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15,
+ 1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
+ 2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
+ 11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
+ 2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
+ 11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
+ 8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15,
+ 1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
+ 9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
+ 0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
+ 3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
+ 10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
+ 14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
+ 7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
+ 4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
+ 13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
+ 5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
+ 12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
+ 15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
+ 6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
+ 1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
+ 8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15,
+ 11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
+ 2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
+ 10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
+ 3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
+ 0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
+ 9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
+ 13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
+ 4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
+ 7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
+ 14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
+ 6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
+ 15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
+ 12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
+ 5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
+ 12, 15, 9, 10, 10, 9, 15, 12, 11, 8, 14, 13, 13, 14, 8, 11,
+ 5, 6, 0, 3, 3, 0, 6, 5, 2, 1, 7, 4, 4, 7, 1, 2,
+ 6, 5, 3, 0, 0, 3, 5, 6, 1, 2, 4, 7, 7, 4, 2, 1,
+ 15, 12, 10, 9, 9, 10, 12, 15, 8, 11, 13, 14, 14, 13, 11, 8,
+ 7, 4, 2, 1, 1, 2, 4, 7, 0, 3, 5, 6, 6, 5, 3, 0,
+ 14, 13, 11, 8, 8, 11, 13, 14, 9, 10, 12, 15, 15, 12, 10, 9,
+ 13, 14, 8, 11, 11, 8, 14, 13, 10, 9, 15, 12, 12, 15, 9, 10,
+ 4, 7, 1, 2, 2, 1, 7, 4, 3, 0, 6, 5, 5, 6, 0, 3,
+ 0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7,
+ 9, 10, 12, 15, 15, 12, 10, 9, 14, 13, 11, 8, 8, 11, 13, 14,
+ 10, 9, 15, 12, 12, 15, 9, 10, 13, 14, 8, 11, 11, 8, 14, 13,
+ 3, 0, 6, 5, 5, 6, 0, 3, 4, 7, 1, 2, 2, 1, 7, 4,
+ 11, 8, 14, 13, 13, 14, 8, 11, 12, 15, 9, 10, 10, 9, 15, 12,
+ 2, 1, 7, 4, 4, 7, 1, 2, 5, 6, 0, 3, 3, 0, 6, 5,
+ 1, 2, 4, 7, 7, 4, 2, 1, 6, 5, 3, 0, 0, 3, 5, 6,
+ 8, 11, 13, 14, 14, 13, 11, 8, 15, 12, 10, 9, 9, 10, 12, 15
+ };
+
+ static const int decoding[16] = {
+ 0, 0, 0, 1, 0, 2, 4, 8, 0, 16, 32, 64, 128, 256, 512, 1024
+ };
+
+ size_t errs = 0;
+ uint16_t par = cw & 0xf;
+ cw &= 0xffff;
+ cw >>= 4;
+ uint16_t correction = decoding[encoding[cw] ^ par];
+ if(correction) {
+ cw ^= correction;
+ ++errs;
+ }
+ return errs;
+}
+
+#endif /* INCLUDED_OP25_HAMMING_H */
diff --git a/blocks/src/lib/op25_imbe_frame.h b/blocks/src/lib/op25_imbe_frame.h
new file mode 100644
index 0000000..702ec2f
--- /dev/null
+++ b/blocks/src/lib/op25_imbe_frame.h
@@ -0,0 +1,427 @@
+#ifndef INCLUDED_IMBE_FRAME_H
+#define INCLUDED_IMBE_FRAME_H
+
+#include <cstddef>
+#include <stdint.h>
+#include <vector>
+#include <op25_yank.h>
+#include <op25_golay.h>
+#include <op25_hamming.h>
+
+typedef std::vector<bool> voice_codeword;
+typedef const std::vector<bool> const_bit_vector;
+typedef std::vector<bool> bit_vector;
+
+static const size_t nof_voice_codewords = 9, voice_codeword_sz = 144;
+
+static const uint16_t imbe_ldu_NID_bits[] = {
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73,
+ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
+ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
+ 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113 };
+
+static const uint16_t imbe_ldu_status_bits[] = {
+ 70, 71, 142, 143, 214, 215, 286, 287, 358, 359, 430, 431,
+ 502, 503, 574, 575, 646, 647, 718, 719, 790, 791, 862, 863,
+ 934, 935, 1006, 1007, 1078, 1079, 1150, 1151, 1222, 1223, 1294, 1295,
+ 1366, 1367, 1438, 1439, 1510, 1511, 1582, 1583, 1654, 1655, 1726, 1727 };
+
+static const uint16_t imbe_ldu_lcf_bits[] = {
+ 410, 411, 412, 413, 414, 415, 420, 421,
+ 422, 423, 424, 425, 432, 433, 434, 435,
+ 436, 437, 442, 443, 444, 445, 446, 447,
+ 600, 601, 602, 603, 604, 605, 610, 611,
+ 612, 613, 614, 615, 620, 621, 622, 623,
+ 624, 625, 630, 631, 632, 633, 634, 635,
+ 788, 789, 792, 793, 794, 795, 800, 801,
+ 802, 803, 804, 805, 810, 811, 812, 813,
+ 814, 815, 820, 821, 822, 823, 824, 825 };
+
+// FIXME: separate these into their respective fields
+static const uint16_t imbe_ldu_ls_data_bits[] = {
+ 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421,
+ 422, 423, 424, 425, 426, 427, 428, 429, 432, 433, 434, 435,
+ 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447,
+ 448, 449, 450, 451, 600, 601, 602, 603, 604, 605, 606, 607,
+ 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619,
+ 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631,
+ 632, 633, 634, 635, 636, 637, 638, 639, 788, 789, 792, 793,
+ 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805,
+ 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817,
+ 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829,
+ 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989,
+ 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001,
+ 1002, 1003, 1004, 1005, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015,
+ 1016, 1017, 1018, 1019, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175,
+ 1176, 1177, 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187,
+ 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199,
+ 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1356, 1357, 1358, 1359,
+ 1360, 1361, 1362, 1363, 1364, 1365, 1368, 1369, 1370, 1371, 1372, 1373,
+ 1374, 1375, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385,
+ 1386, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1394, 1395, 1396, 1397,
+ 1546, 1547, 1548, 1549, 1550, 1551, 1552, 1553, 1554, 1555, 1556, 1557,
+ 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1565, 1566, 1567, 1568, 1569,
+ 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1577 };
+
+static const uint16_t voice_codeword_bits[nof_voice_codewords][voice_codeword_sz] = {
+
+ { 114, 121, 126, 133, 138, 147, 152, 159, 164, 171, 176, 183,
+ 188, 195, 200, 207, 212, 221, 226, 233, 238, 245, 250, 257,
+ 115, 120, 127, 132, 139, 146, 153, 158, 165, 170, 177, 182,
+ 189, 194, 201, 206, 213, 220, 227, 232, 239, 244, 251, 256,
+ 116, 123, 128, 135, 140, 149, 154, 161, 166, 173, 178, 185,
+ 190, 197, 202, 209, 216, 223, 228, 235, 240, 247, 252, 259,
+ 117, 122, 129, 134, 141, 148, 155, 160, 167, 172, 179, 184,
+ 191, 196, 203, 208, 217, 222, 229, 234, 241, 246, 253, 258,
+ 118, 125, 130, 137, 144, 151, 156, 163, 168, 175, 180, 187,
+ 192, 199, 204, 211, 218, 225, 230, 237, 242, 249, 254, 261,
+ 119, 124, 131, 136, 145, 150, 157, 162, 169, 174, 181, 186,
+ 193, 198, 205, 210, 219, 224, 231, 236, 243, 248, 255, 260 },
+
+ { 262, 269, 274, 281, 288, 295, 300, 307, 312, 319, 324, 331,
+ 336, 343, 348, 355, 362, 369, 374, 381, 386, 393, 398, 405,
+ 263, 268, 275, 280, 289, 294, 301, 306, 313, 318, 325, 330,
+ 337, 342, 349, 354, 363, 368, 375, 380, 387, 392, 399, 404,
+ 264, 271, 276, 283, 290, 297, 302, 309, 314, 321, 326, 333,
+ 338, 345, 350, 357, 364, 371, 376, 383, 388, 395, 400, 407,
+ 265, 270, 277, 282, 291, 296, 303, 308, 315, 320, 327, 332,
+ 339, 344, 351, 356, 365, 370, 377, 382, 389, 394, 401, 406,
+ 266, 273, 278, 285, 292, 299, 304, 311, 316, 323, 328, 335,
+ 340, 347, 352, 361, 366, 373, 378, 385, 390, 397, 402, 409,
+ 267, 272, 279, 284, 293, 298, 305, 310, 317, 322, 329, 334,
+ 341, 346, 353, 360, 367, 372, 379, 384, 391, 396, 403, 408 },
+
+ { 452, 459, 464, 471, 476, 483, 488, 495, 500, 509, 514, 521,
+ 526, 533, 538, 545, 550, 557, 562, 569, 576, 583, 588, 595,
+ 453, 458, 465, 470, 477, 482, 489, 494, 501, 508, 515, 520,
+ 527, 532, 539, 544, 551, 556, 563, 568, 577, 582, 589, 594,
+ 454, 461, 466, 473, 478, 485, 490, 497, 504, 511, 516, 523,
+ 528, 535, 540, 547, 552, 559, 564, 571, 578, 585, 590, 597,
+ 455, 460, 467, 472, 479, 484, 491, 496, 505, 510, 517, 522,
+ 529, 534, 541, 546, 553, 558, 565, 570, 579, 584, 591, 596,
+ 456, 463, 468, 475, 480, 487, 492, 499, 506, 513, 518, 525,
+ 530, 537, 542, 549, 554, 561, 566, 573, 580, 587, 592, 599,
+ 457, 462, 469, 474, 481, 486, 493, 498, 507, 512, 519, 524,
+ 531, 536, 543, 548, 555, 560, 567, 572, 581, 586, 593, 598 },
+
+ { 640, 649, 654, 661, 666, 673, 678, 685, 690, 697, 702, 709,
+ 714, 723, 728, 735, 740, 747, 752, 759, 764, 771, 776, 783,
+ 641, 648, 655, 660, 667, 672, 679, 684, 691, 696, 703, 708,
+ 715, 722, 729, 734, 741, 746, 753, 758, 765, 770, 777, 782,
+ 642, 651, 656, 663, 668, 675, 680, 687, 692, 699, 704, 711,
+ 716, 725, 730, 737, 742, 749, 754, 761, 766, 773, 778, 785,
+ 643, 650, 657, 662, 669, 674, 681, 686, 693, 698, 705, 710,
+ 717, 724, 731, 736, 743, 748, 755, 760, 767, 772, 779, 784,
+ 644, 653, 658, 665, 670, 677, 682, 689, 694, 701, 706, 713,
+ 720, 727, 732, 739, 744, 751, 756, 763, 768, 775, 780, 787,
+ 645, 652, 659, 664, 671, 676, 683, 688, 695, 700, 707, 712,
+ 721, 726, 733, 738, 745, 750, 757, 762, 769, 774, 781, 786 },
+
+ { 830, 837, 842, 849, 854, 861, 868, 875, 880, 887, 892, 899,
+ 904, 911, 916, 923, 928, 937, 942, 949, 954, 961, 966, 973,
+ 831, 836, 843, 848, 855, 860, 869, 874, 881, 886, 893, 898,
+ 905, 910, 917, 922, 929, 936, 943, 948, 955, 960, 967, 972,
+ 832, 839, 844, 851, 856, 865, 870, 877, 882, 889, 894, 901,
+ 906, 913, 918, 925, 930, 939, 944, 951, 956, 963, 968, 975,
+ 833, 838, 845, 850, 857, 864, 871, 876, 883, 888, 895, 900,
+ 907, 912, 919, 924, 931, 938, 945, 950, 957, 962, 969, 974,
+ 834, 841, 846, 853, 858, 867, 872, 879, 884, 891, 896, 903,
+ 908, 915, 920, 927, 932, 941, 946, 953, 958, 965, 970, 977,
+ 835, 840, 847, 852, 859, 866, 873, 878, 885, 890, 897, 902,
+ 909, 914, 921, 926, 933, 940, 947, 952, 959, 964, 971, 976 },
+
+ { 1020, 1027, 1032, 1039, 1044, 1051, 1056, 1063, 1068, 1075, 1082, 1089,
+ 1094, 1101, 1106, 1113, 1118, 1125, 1130, 1137, 1142, 1149, 1156, 1163,
+ 1021, 1026, 1033, 1038, 1045, 1050, 1057, 1062, 1069, 1074, 1083, 1088,
+ 1095, 1100, 1107, 1112, 1119, 1124, 1131, 1136, 1143, 1148, 1157, 1162,
+ 1022, 1029, 1034, 1041, 1046, 1053, 1058, 1065, 1070, 1077, 1084, 1091,
+ 1096, 1103, 1108, 1115, 1120, 1127, 1132, 1139, 1144, 1153, 1158, 1165,
+ 1023, 1028, 1035, 1040, 1047, 1052, 1059, 1064, 1071, 1076, 1085, 1090,
+ 1097, 1102, 1109, 1114, 1121, 1126, 1133, 1138, 1145, 1152, 1159, 1164,
+ 1024, 1031, 1036, 1043, 1048, 1055, 1060, 1067, 1072, 1081, 1086, 1093,
+ 1098, 1105, 1110, 1117, 1122, 1129, 1134, 1141, 1146, 1155, 1160, 1167,
+ 1025, 1030, 1037, 1042, 1049, 1054, 1061, 1066, 1073, 1080, 1087, 1092,
+ 1099, 1104, 1111, 1116, 1123, 1128, 1135, 1140, 1147, 1154, 1161, 1166 },
+
+ { 1208, 1215, 1220, 1229, 1234, 1241, 1246, 1253, 1258, 1265, 1270, 1277,
+ 1282, 1289, 1296, 1303, 1308, 1315, 1320, 1327, 1332, 1339, 1344, 1351,
+ 1209, 1214, 1221, 1228, 1235, 1240, 1247, 1252, 1259, 1264, 1271, 1276,
+ 1283, 1288, 1297, 1302, 1309, 1314, 1321, 1326, 1333, 1338, 1345, 1350,
+ 1210, 1217, 1224, 1231, 1236, 1243, 1248, 1255, 1260, 1267, 1272, 1279,
+ 1284, 1291, 1298, 1305, 1310, 1317, 1322, 1329, 1334, 1341, 1346, 1353,
+ 1211, 1216, 1225, 1230, 1237, 1242, 1249, 1254, 1261, 1266, 1273, 1278,
+ 1285, 1290, 1299, 1304, 1311, 1316, 1323, 1328, 1335, 1340, 1347, 1352,
+ 1212, 1219, 1226, 1233, 1238, 1245, 1250, 1257, 1262, 1269, 1274, 1281,
+ 1286, 1293, 1300, 1307, 1312, 1319, 1324, 1331, 1336, 1343, 1348, 1355,
+ 1213, 1218, 1227, 1232, 1239, 1244, 1251, 1256, 1263, 1268, 1275, 1280,
+ 1287, 1292, 1301, 1306, 1313, 1318, 1325, 1330, 1337, 1342, 1349, 1354 },
+
+ { 1398, 1405, 1410, 1417, 1422, 1429, 1434, 1443, 1448, 1455, 1460, 1467,
+ 1472, 1479, 1484, 1491, 1496, 1503, 1508, 1517, 1522, 1529, 1534, 1541,
+ 1399, 1404, 1411, 1416, 1423, 1428, 1435, 1442, 1449, 1454, 1461, 1466,
+ 1473, 1478, 1485, 1490, 1497, 1502, 1509, 1516, 1523, 1528, 1535, 1540,
+ 1400, 1407, 1412, 1419, 1424, 1431, 1436, 1445, 1450, 1457, 1462, 1469,
+ 1474, 1481, 1486, 1493, 1498, 1505, 1512, 1519, 1524, 1531, 1536, 1543,
+ 1401, 1406, 1413, 1418, 1425, 1430, 1437, 1444, 1451, 1456, 1463, 1468,
+ 1475, 1480, 1487, 1492, 1499, 1504, 1513, 1518, 1525, 1530, 1537, 1542,
+ 1402, 1409, 1414, 1421, 1426, 1433, 1440, 1447, 1452, 1459, 1464, 1471,
+ 1476, 1483, 1488, 1495, 1500, 1507, 1514, 1521, 1526, 1533, 1538, 1545,
+ 1403, 1408, 1415, 1420, 1427, 1432, 1441, 1446, 1453, 1458, 1465, 1470,
+ 1477, 1482, 1489, 1494, 1501, 1506, 1515, 1520, 1527, 1532, 1539, 1544 },
+
+ { 1578, 1587, 1592, 1599, 1604, 1611, 1616, 1623, 1628, 1635, 1640, 1647,
+ 1652, 1661, 1666, 1673, 1678, 1685, 1690, 1697, 1702, 1709, 1714, 1721,
+ 1579, 1586, 1593, 1598, 1605, 1610, 1617, 1622, 1629, 1634, 1641, 1646,
+ 1653, 1660, 1667, 1672, 1679, 1684, 1691, 1696, 1703, 1708, 1715, 1720,
+ 1580, 1589, 1594, 1601, 1606, 1613, 1618, 1625, 1630, 1637, 1642, 1649,
+ 1656, 1663, 1668, 1675, 1680, 1687, 1692, 1699, 1704, 1711, 1716, 1723,
+ 1581, 1588, 1595, 1600, 1607, 1612, 1619, 1624, 1631, 1636, 1643, 1648,
+ 1657, 1662, 1669, 1674, 1681, 1686, 1693, 1698, 1705, 1710, 1717, 1722,
+ 1584, 1591, 1596, 1603, 1608, 1615, 1620, 1627, 1632, 1639, 1644, 1651,
+ 1658, 1665, 1670, 1677, 1682, 1689, 1694, 1701, 1706, 1713, 1718, 1725,
+ 1585, 1590, 1597, 1602, 1609, 1614, 1621, 1626, 1633, 1638, 1645, 1650,
+ 1659, 1664, 1671, 1676, 1683, 1688, 1695, 1700, 1707, 1712, 1719, 1724 },
+
+ };
+
+#if DEBUG
+/*
+ * Convert bit vector to hex dump format and print
+ */
+static inline void
+dump_cw(const voice_codeword& cw, int len, FILE* fp) // len in bytes
+{
+ int i, j;
+ for (i = 0; i < len; i++){
+ int p = 0;
+ for (j = 0; j < 8; j++){
+ p = (p << 1) + cw[ i*8 + j ];
+ }
+ fprintf(fp, "%02x ", p);
+ if (!((i+1) % 16))
+ fprintf(fp, "\n");
+ }
+ fprintf(fp, "\n");
+}
+#endif
+
+static inline void
+imbe_store_bits(voice_codeword& cw, int s, int l, uint32_t v)
+{
+ for (int i = l-1; i >= s; i--) {
+ cw[i] = v & 1;
+ v >>= 1;
+ }
+}
+
+static inline uint32_t
+pngen15(uint32_t& Pr)
+{
+ int n = 0;
+ for(int i = 14; i >= 0; --i) {
+ Pr = (173 * Pr + 13849) & 0xffffu;
+ if(Pr & 32768) {
+ n += (1 << i);
+ }
+ }
+ return n;
+}
+
+static inline uint32_t
+pngen23(uint32_t& Pr)
+{
+ int n = 0;
+ for(int i = 22; i >= 0; --i) {
+ Pr = (173 * Pr + 13849) & 0xffffu;
+ if(Pr & 32768) {
+ n += (1 << i);
+ }
+ }
+ return n;
+}
+
+/* APCO IMBE header decoder.
+ *
+ * extracts 88 bits of IMBE parameters given an input 144-bit frame
+ *
+ * \param cw Codeword containing bits to be decoded
+ * \param u0-u7 Result output vectors
+ */
+
+static inline void
+imbe_header_decode(const voice_codeword& cw, uint32_t& u0, uint32_t& u1, uint32_t& u2, uint32_t& u3, uint32_t& u4, uint32_t& u5, uint32_t& u6, uint32_t& u7, uint32_t& E0, uint32_t& ET)
+{
+ ET = 0;
+
+ size_t errs = 0;
+ uint32_t v0 = extract(cw, 0, 23);
+ errs = golay_23_decode(v0);
+ u0 = v0;
+ E0 = ET;
+
+ uint32_t pn = u0 << 4;
+ uint32_t m1 = pngen23(pn);
+ uint32_t v1 = extract(cw, 23, 46) ^ m1;
+ errs += golay_23_decode(v1);
+ u1 = v1;
+
+ uint32_t m2 = pngen23(pn);
+ uint32_t v2 = extract(cw, 46, 69) ^ m2;
+ errs += golay_23_decode(v2);
+ u2 = v2;
+
+ uint32_t m3 = pngen23(pn);
+ uint32_t v3 = extract(cw, 69, 92) ^ m3;
+ errs += golay_23_decode(v3);
+ u3 = v3;
+
+ uint32_t m4 = pngen15(pn);
+ uint16_t v4 = extract(cw, 92, 107) ^ m4;
+ errs += hamming_15_decode(v4);
+ u4 = v4;
+
+ uint32_t m5 = pngen15(pn);
+ uint16_t v5 = extract(cw, 107, 122) ^ m5;
+ errs += hamming_15_decode(v5);
+ u5 = v5;
+
+ uint32_t m6 = pngen15(pn);
+ uint16_t v6 = extract(cw, 122, 137) ^ m6;
+ errs += hamming_15_decode(v6);
+ u6 = v6;
+
+ u7 = extract(cw, 137, 144);
+ u7 <<= 1; /* so that bit0 is free (see note about BOT bit */
+}
+
+/* APCO IMBE header encoder.
+ *
+ * given 88 bits of IMBE parameters, construct output 144-bit IMBE codeword
+ *
+ * \param cw Codeword into which 144 bits of results are placed
+ * \param u0-u7 input parameters
+ */
+
+static inline void
+imbe_header_encode(voice_codeword& cw, uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3, uint32_t u4, uint32_t u5, uint32_t u6, uint32_t u7)
+{
+ // given input 88-bit IMBE frame (in u0-u7),
+ // add golay / hamming bits to produce a 144-bit frame.
+ uint32_t c0, c1, c2, c3, c4, c5, c6, c7;
+
+ uint32_t pn = u0 << 4;
+
+ c0 = golay_23_encode(u0);
+ imbe_store_bits(cw, 0, 23, c0);
+
+ uint32_t m1 = pngen23(pn);
+ c1 = golay_23_encode(u1) ^ m1;
+ imbe_store_bits(cw, 23, 46, c1);
+
+ uint32_t m2 = pngen23(pn);
+ c2 = golay_23_encode(u2) ^ m2;
+ imbe_store_bits(cw, 46, 69, c2);
+
+ uint32_t m3 = pngen23(pn);
+ c3 = golay_23_encode(u3) ^ m3;
+ imbe_store_bits(cw, 69, 92, c3);
+
+ uint32_t m4 = pngen15(pn);
+ c4 = hamming_15_encode(u4) ^ m4;
+ imbe_store_bits(cw, 92, 107, c4);
+
+ uint32_t m5 = pngen15(pn);
+ c5 = hamming_15_encode(u5) ^ m5;
+ imbe_store_bits(cw, 107, 122, c5);
+
+ uint32_t m6 = pngen15(pn);
+ c6 = hamming_15_encode(u6) ^ m6;
+ imbe_store_bits(cw, 122, 137, c6);
+
+ c7 = u7;
+ imbe_store_bits(cw, 137, 144, c7 >> 1);
+}
+
+static inline void
+imbe_deinterleave (const_bit_vector& frame_body, voice_codeword& cw, uint32_t frame_nr)
+{
+ for(size_t j = 0; j < voice_codeword_sz; ++j) {
+ cw[j] = frame_body[voice_codeword_bits[frame_nr][j]];
+ }
+}
+
+
+static inline void
+imbe_interleave(bit_vector& frame_body, const voice_codeword& cw, uint32_t frame_nr)
+{
+ for(size_t j = 0; j < voice_codeword_sz; ++j) {
+ frame_body[voice_codeword_bits[frame_nr][j]] = cw[j];
+ }
+}
+
+static inline void
+imbe_frame_unpack(uint8_t *A, uint32_t& u0, uint32_t& u1, uint32_t& u2, uint32_t& u3, uint32_t& u4, uint32_t& u5, uint32_t& u6, uint32_t& u7, uint32_t& E0, uint32_t& ET)
+{
+ E0 = A[0];
+ ET = A[1];
+ u0 = A[4] + (E0 & 240) * 16;
+ u1 = A[5] + (E0 & 15) * 256;
+ u2 = A[6] + (ET & 240) * 16;
+ u3 = A[7] + (ET & 15) * 256;
+ E0 = A[2];
+ ET = A[3];
+ u4 = A[8] + (E0 & 224) * 8;
+ u5 = A[9] + (E0 & 28) * 64;
+ u6 = A[10] + (ET & 128) * 2 + (E0 & 3) * 512;
+ u7 = ET & 127;
+ E0 = A[11];
+ if(E0 & 192) exit(4);
+ ET = E0 & 3;
+ E0 = (E0 & 84) / 4;
+}
+
+/*
+ * Given a 144-bit IMBE frame(cw),
+ * 1. Decode frame to error-corrected 88-bit format
+ * 2. Re-encode frame into 144-bit format with refreshed Hamming/Golay encoding
+ * 3. FIXME: track decoding error rates and stats
+ */
+static inline void
+imbe_regenerate_frame(bit_vector& cw) {
+ unsigned int u0 = 0;
+ unsigned int u1,u2,u3,u4,u5,u6,u7;
+ unsigned int E0 = 0;
+ unsigned int ET = 0;
+
+ // PN/Hamming/Golay - etc.
+ imbe_header_decode(cw, u0, u1, u2, u3, u4, u5, u6, u7, E0, ET) ;
+#if DEBUG
+ printf("u_0: %x\r\nu_1: %x\r\nu_2: %x\r\nu_3: %x\r\nu_4: %x\r\nu_5: %x\r\nu_6: %x\r\nu_7: %x\r\n\r\n", u0, u1, u2, u3, u4, u5, u6, u7>>1);
+#endif
+ imbe_header_encode(cw, u0, u1, u2, u3, u4, u5, u6, u7);
+}
+
+/*
+ * process voice units (ldu1 or ldu2)
+ * perform error correction for each of the nine embedded 144-bit frames
+ * by regenerating the error-correction coding bits
+ */
+static inline void
+imbe_regenerate_voice_unit(bit_vector& frame_body) {
+ voice_codeword cw(voice_codeword_sz);
+#if DEBUG
+ dump_cw(frame_body, 216, stderr);
+#endif
+ for(size_t i = 0; i < nof_voice_codewords; ++i) {
+ imbe_deinterleave(frame_body, cw, i);
+ imbe_regenerate_frame(cw);
+ imbe_interleave(frame_body, cw, i);
+ }
+#if DEBUG
+ dump_cw(frame_body, 216, stderr);
+#endif
+}
+
+#endif /* INCLUDED_IMBE_FRAME_H */
diff --git a/blocks/src/lib/op25_p25_frame.h b/blocks/src/lib/op25_p25_frame.h
new file mode 100644
index 0000000..f60b2c8
--- /dev/null
+++ b/blocks/src/lib/op25_p25_frame.h
@@ -0,0 +1,38 @@
+#ifndef INCLUDED_OP25_P25_FRAME_H
+#define INCLUDED_OP25_P25_FRAME_H 1
+
+static const size_t P25_VOICE_FRAME_SIZE = 1728;
+static const size_t P25_HEADER_SYMBOLS = 24 + 32 + 1;
+static const size_t P25_HEADER_BITS = P25_HEADER_SYMBOLS * 2;
+
+static const uint64_t P25_FRAME_SYNC_MAGIC = 0x5575F5FF77FFLL;
+static const uint64_t P25_FRAME_SYNC_REV_P = 0x5575F5FF77FFLL ^ 0xAAAAAAAAAAAALL;
+static const uint64_t P25_FRAME_SYNC_MASK = 0xFFFFFFFFFFFFLL;
+
+/* Given a 64-bit frame header word and a frame body which is to be initialized
+ * 1. Place flags at beginning of frame body
+ * 2. Store 64-bit frame header word
+ * 3. FIXME Place first status symbol
+ */
+static inline void
+p25_setup_frame_header(bit_vector& frame_body, uint64_t hw) {
+ uint64_t acc = P25_FRAME_SYNC_MAGIC;
+ for (int i=47; i>=0; i--) {
+ frame_body[ i ] = acc & 1;
+ acc >>= 1;
+ }
+ acc = hw;
+ for (int i=113; i>=72; i--) {
+ frame_body[ i ] = acc & 1;
+ acc >>= 1;
+ }
+ // FIXME: insert proper status dibit bits at 70, 71
+ frame_body[70] = 1;
+ frame_body[71] = 0;
+ for (int i=69; i>=48; i--) {
+ frame_body[ i ] = acc & 1;
+ acc >>= 1;
+ }
+}
+
+#endif /* INCLUDED_OP25_P25_FRAME_H */
diff --git a/blocks/src/lib/op25_pcap_source_b.cc b/blocks/src/lib/op25_pcap_source_b.cc
new file mode 100644
index 0000000..234de64
--- /dev/null
+++ b/blocks/src/lib/op25_pcap_source_b.cc
@@ -0,0 +1,114 @@
+/* -*- 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.
+ */
+
+#define __STDC_CONSTANT_MACROS
+
+#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 <stdlib.h>
+#include <stdexcept>
+#include <strings.h>
+
+#define PCAP_DONT_INCLUDE_PCAP_BPF_H
+#include <pcap/pcap.h>
+
+using namespace std;
+
+op25_pcap_source_b_sptr
+op25_make_pcap_source_b(const char *path, float delay)
+{
+ return op25_pcap_source_b_sptr(new op25_pcap_source_b(path, delay));
+}
+
+op25_pcap_source_b::~op25_pcap_source_b()
+{
+}
+
+int
+op25_pcap_source_b::work(int nof_output_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items)
+{
+ try {
+ const size_t OCTETS_AVAIL = octets_.size();
+ uint8_t *out = reinterpret_cast<uint8_t*>(output_items[0]);
+ const int OCTETS_REQD = static_cast<size_t>(nof_output_items);
+ for(int i = 0; i < OCTETS_REQD; ++i) {
+ out[i] = octets_[loc_++];
+ loc_ %= OCTETS_AVAIL;
+ }
+ return OCTETS_REQD;
+ } catch(const std::exception& x) {
+ cerr << x.what() << endl;
+ exit(EXIT_FAILURE);
+ } catch(...) {
+ cerr << "unhandled exception" << endl;
+ exit(EXIT_FAILURE);
+ }
+
+}
+
+op25_pcap_source_b::op25_pcap_source_b(const char *path, float delay) :
+ gr_sync_block ("pcap_source_b",
+ gr_make_io_signature (0, 0, 0),
+ gr_make_io_signature (1, 1, sizeof(uint8_t))),
+ loc_(0),
+ octets_(/* delay * 1200, 0 */)
+{
+ char err[PCAP_ERRBUF_SIZE];
+ pcap_t *pcap = pcap_open_offline(path, err);
+ if(pcap) {
+ struct pcap_pkthdr hdr;
+ for(const uint8_t *octets; octets = pcap_next(pcap, &hdr);) {
+ const size_t ETHERNET_SZ = 14;
+ const size_t IP_SZ = 20;
+ const size_t UDP_SZ = 8;
+ const size_t P25CAI_OFS = ETHERNET_SZ + IP_SZ + UDP_SZ;
+ if(P25CAI_OFS < hdr.caplen) {
+ const size_t FRAME_SZ = hdr.caplen - P25CAI_OFS;
+#if 0
+ // push some zero octets to separate frames
+ const size_t SILENCE_OCTETS = 48;
+ octets_.resize(octets_.size() + SILENCE_OCTETS, 0);
+#endif
+ // push octets from frame payload into local buffer
+ octets_.reserve(octets_.size() + hdr.caplen - P25CAI_OFS);
+ for(size_t i = 0; i < FRAME_SZ; ++i) {
+ octets_.push_back(octets[P25CAI_OFS + i]);
+ }
+ }
+ }
+ pcap_close(pcap);
+ } else {
+ cerr << "error: failed to open " << path;
+ cerr << " (" << err << ")" << endl;
+ exit(EXIT_FAILURE);
+ }
+}
diff --git a/blocks/src/lib/op25_pcap_source_b.h b/blocks/src/lib/op25_pcap_source_b.h
new file mode 100644
index 0000000..0ab6618
--- /dev/null
+++ b/blocks/src/lib/op25_pcap_source_b.h
@@ -0,0 +1,89 @@
+/* -*- 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>
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+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);
+
+/**
+ * op25_pcap_source_b is a GNU Radio block for reading from a
+ * tcpdump-formatted capture file and producing a stream of octets.
+ */
+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.
+ */
+ friend op25_pcap_source_b_sptr op25_make_pcap_source_b(const char *path, float delay);
+
+ /**
+ * 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.
+ */
+ op25_pcap_source_b(const char *path, float delay);
+
+private:
+
+ /**
+ * The next octet to be read from the input file.
+ */
+ size_t loc_;
+
+ /**
+ * Symbols from the input file.
+ */
+ std::vector<uint8_t> octets_;
+
+};
+
+#endif /* INCLUDED_OP25_PCAP_SOURCE_B_H */
diff --git a/blocks/src/lib/op25_yank.h b/blocks/src/lib/op25_yank.h
new file mode 100644
index 0000000..621c316
--- /dev/null
+++ b/blocks/src/lib/op25_yank.h
@@ -0,0 +1,114 @@
+#ifndef INCLUDED_SWAB_H
+#define INCLUDED_SWAB_H
+
+/**
+ * Yank in[bits[0]..bits[bits_sz]) to out[where,where+bits_sz).
+ *
+ * \param in A const reference to the source.
+ * \param bits An array specifying the ordinals of the bits to copy.
+ * \param bits_sz The size of the bits array.
+ * \param out A reference to the destination.
+ * \param where The offset of the first bit to write.
+ */
+template <class X, class Y>
+void yank(const X& in, const size_t bits[], size_t bits_sz, Y& out, size_t where)
+{
+ for(size_t i = 0; i < bits_sz; ++i) {
+ out[where+i] = in[bits[i]];
+ }
+}
+
+/**
+ * Yank back from in[where,where+bits_sz) to out[bits[0]..bits[bits_sz]).
+ *
+ * \param in A const reference to the source.
+ * \param where The offset of the first bit to read.
+ * \param out A reference to the destination.
+ * \param bits An array specifying the ordinals of the bits to copy.
+ * \param bits_sz The size of the bits array.
+ */
+template <class X, class Y>
+void yank_back(const X& in, size_t where, Y& out, const size_t bits[], size_t bits_sz)
+{
+ for(size_t i = 0; i < bits_sz; ++i) {
+ out[bits[i]] = in[where+i];
+ }
+}
+
+/**
+ * Extract a bit_vector in[begin,end) to an octet buffer.
+ *
+ * \param in A const reference to the source.
+ * \param begin The offset of the first bit to extract (the MSB).
+ * \param end The offset of the end bit.
+ * \param out Address of the octet buffer to write into.
+ * \return The number of octers written.
+ */
+template<class X>
+size_t extract(const X& in, int begin, int end, uint8_t *out)
+{
+ const size_t out_sz = (7 + end - begin) / 8;
+ std::fill(out, out + out_sz, 0);
+ for(int i = begin, j = 0; i < end; ++i, ++j) {
+ out[j / 8] |= (in[i] ? 1 << (7 - (j % 8)) : 0);
+ }
+ return out_sz;
+}
+
+/**
+ * Extract a bit_vector in[bits[0)..bits[bits_sz)) to an octet buffer.
+ *
+ * \param in A const reference to the source.
+ * \param bits An array specifying the ordinals of the bits to extract.
+ * \param bits_sz The size of the bits array.
+ * \param out Address of the octet buffer to write into.
+ * \return The number of octers written.
+ */
+template<class X>
+size_t extract(const X& in, const size_t bits[], size_t bits_sz, uint8_t *out)
+{
+ const size_t out_sz = (7 + bits_sz) / 8;
+ std::fill(out, out + out_sz, 0);
+ for(size_t i = 0; i < bits_sz; ++i) {
+ out[i / 8] ^= in[bits[i]] << (7 - (i % 8));
+ }
+ return out_sz;
+}
+
+/**
+ * Extract value of bits from in[bits[0..bits_sz)).
+ *
+ * \param in The input const_bit_vector.
+ * \param begin The offset of the first bit to extract (the MSB).
+ * \param end The offset of the end bit.
+ * \return A uint64_t containing the value
+ */
+template<class X>
+uint64_t extract(const X& in, int begin, int end)
+{
+ uint64_t x = 0LL;
+ for(int i = begin; i < end; ++i) {
+ x = (x << 1) | (in[i] ? 1 : 0);
+ }
+ return x;
+}
+
+/**
+ * Extract value of bits from in[bits[0..bits_sz)).
+ *
+ * \param in A const reference to the source.
+ * \param bits An array specifying the ordinals of the bits to extract.
+ * \param bits_sz The size of the bits array.
+ * \return A uint64_t containing the value
+ */
+template<class X>
+uint64_t extract(const X& in, const size_t bits[], size_t bits_sz)
+{
+ uint64_t x = 0LL;
+ for(size_t i = 0; i < bits_sz; ++i) {
+ x = (x << 1) | (in[bits[i]] ? 1 : 0);
+ }
+ return x;
+}
+
+#endif // INCLUDED_SWAB_H
diff --git a/blocks/src/lib/p25cai_du_handler.cc b/blocks/src/lib/p25cai_du_handler.cc
new file mode 100644
index 0000000..7628042
--- /dev/null
+++ b/blocks/src/lib/p25cai_du_handler.cc
@@ -0,0 +1,87 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008-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.
+ */
+
+#include <arpa/inet.h>
+#include <cstdio>
+#include <cstring>
+#include <errno.h>
+#include <iomanip>
+#include <netinet/in.h>
+#include <p25cai_du_handler.h>
+#include <sstream>
+#include <sys/socket.h>
+#include <sys/socket.h>
+
+using namespace std;
+
+p25cai_du_handler::p25cai_du_handler(data_unit_handler_sptr next, const char *addr, int port) :
+ data_unit_handler(next),
+ d_cai(-1),
+ d_address("Unavailable")
+{
+ struct sockaddr_in sin;
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ inet_aton(addr, &sin.sin_addr);
+ d_cai = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if(-1 != d_cai) {
+ if(-1 != connect(d_cai, (struct sockaddr*) &sin, sizeof(sin))) {
+ ostringstream address;
+ address << addr << ":" << port;
+ d_address = address.str();
+ } else {
+ printf("error %d: %s\n", errno, strerror(errno));
+ perror("connect(d_tap, (struct sockaddr*) &sin, sizeof(sin))");
+ close(d_cai);
+ d_cai = -1;
+ }
+ } else {
+ perror("socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)");
+ d_cai = -1;
+ }
+}
+
+p25cai_du_handler::~p25cai_du_handler()
+{
+ if(-1 != d_cai) {
+ close(d_cai);
+ }
+}
+
+const char*
+p25cai_du_handler::destination() const
+{
+ return d_address.c_str();
+}
+
+void
+p25cai_du_handler::handle(data_unit_sptr du)
+{
+ if(-1 != d_cai) {
+ const size_t CAI_SZ = du->size();
+ uint8_t cai[CAI_SZ];
+ du->decode_frame(CAI_SZ, cai);
+ write(d_cai, cai, CAI_SZ);
+ }
+ data_unit_handler::handle(du);
+}
diff --git a/blocks/src/lib/p25cai_du_handler.h b/blocks/src/lib/p25cai_du_handler.h
new file mode 100644
index 0000000..4a601bb
--- /dev/null
+++ b/blocks/src/lib/p25cai_du_handler.h
@@ -0,0 +1,84 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008-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_P25CAI_DU_HANDLER_H
+#define INCLUDED_P25CAI_DU_HANDLER_H
+
+#include <data_unit_handler.h>
+#include <string>
+
+/**
+ * This data_unit_handler forwards received frames using p25cai - a
+ * straighforward encapsulation of the P25 CAI in a UDP datagram. This
+ * format is understood by Wireshark and replaces the use of TUN/TAP
+ * which require root privileges and are not present by default on
+ * some platforms.
+ */
+class p25cai_du_handler : public data_unit_handler
+{
+
+public:
+
+ /**
+ * p25cai_du_handler constructor.
+ *
+ * \param next The next data_unit_handler.
+ * \param addr The address of the receiver.
+ * \param port The port number of the receiver.
+ */
+ p25cai_du_handler(data_unit_handler_sptr next, const char *addr, int port);
+
+ /**
+ * p25cai_du_handler virtual destructor.
+ */
+ virtual ~p25cai_du_handler();
+
+ /**
+ * Handle a received P25 frame.
+ *
+ * \param du A non-null data_unit_sptr to handle.
+ */
+ virtual void handle(data_unit_sptr du);
+
+ /**
+ * Return a pointer to a string identifying the destination address.
+ *
+ * \return A pointer to a NUL-terminated character string.
+ */
+ const char *destination() const;
+
+private:
+
+ /**
+ * file descriptor for the UDP socket.
+ */
+ int32_t d_cai;
+
+ /**
+ * A string identifying the address of the receiver.
+ */
+ std::string d_address;
+
+};
+
+#endif /* INCLUDED_P25CAI_DU_HANDLER_H */
diff --git a/blocks/src/lib/pdu.cc b/blocks/src/lib/pdu.cc
new file mode 100644
index 0000000..5b479af
--- /dev/null
+++ b/blocks/src/lib/pdu.cc
@@ -0,0 +1,67 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include <pdu.h>
+
+using std::string;
+
+pdu::pdu(const_bit_queue& frame_body) :
+ abstract_data_unit(frame_body)
+{
+}
+pdu::~pdu()
+{
+}
+
+string
+pdu::duid_str() const
+{
+ return string("PDU");
+}
+
+void
+pdu::do_correct_errors(bit_vector& frame_body)
+{
+}
+
+uint16_t
+pdu::frame_size_max() const
+{
+#if 1
+ const size_t HEADER_BLOCK_SIZE = 720;
+ return HEADER_BLOCK_SIZE;
+#else
+ const size_t MIN_HEADER_BLOCK_SZ = 312;
+ // after HEADER_BLOCK_SIZE bits have been read we can then use the
+ // header contents to decide on frame_size_max
+
+ size_t n = MIN_HEADER_BLOCK_SZ;
+ if(n < ) {
+ static const size_t BITS[] = {};
+ static const size_t BITS_SZ = sizeof(BITS) / sizeof(BITS[0]);
+ n = extract();
+ }
+ return n;
+
+#endif
+}
diff --git a/blocks/src/lib/pdu.h b/blocks/src/lib/pdu.h
new file mode 100644
index 0000000..87ad58e
--- /dev/null
+++ b/blocks/src/lib/pdu.h
@@ -0,0 +1,74 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_PDU_H
+#define INCLUDED_PDU_H
+
+#include <abstract_data_unit.h>
+
+/**
+ * P25 packet data unit (PDU).
+ */
+class pdu : public abstract_data_unit
+{
+public:
+
+ /**
+ * P25 packet data unit (PDU) constructor.
+ *
+ * \param frame_body A const_bit_queue representing the frame body.
+ */
+ pdu(const_bit_queue& frame_body);
+
+ /**
+ * pdu (virtual) destructor.
+ */
+ virtual ~pdu();
+
+ /**
+ * Returns a string describing the Data Unit ID (DUID).
+ */
+ std::string duid_str() const;
+
+protected:
+
+ /**
+ * Applies error correction code to the specified bit_vector.
+ *
+ * \param frame_body The bit vector to decode.
+ * \return
+ */
+ virtual void do_correct_errors(bit_vector& frame_body);
+
+ /**
+ * Returns the expected size (in bits) of this data unit in
+ * bits. For variable-length data this should return UINT16_MAX
+ * until the actual length of this frame is known.
+ *
+ * \return The expected size (in bits) of this data_unit when encoded.
+ */
+ virtual uint16_t frame_size_max() const;
+
+};
+
+#endif /* INCLUDED_PDU_H */
diff --git a/blocks/src/lib/pickle.cc b/blocks/src/lib/pickle.cc
new file mode 100644
index 0000000..e50aafe
--- /dev/null
+++ b/blocks/src/lib/pickle.cc
@@ -0,0 +1,59 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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.
+*/
+
+#include <pickle.h>
+
+#include <iomanip>
+#include <sstream>
+
+using namespace std;
+
+pickle::pickle()
+{
+}
+
+pickle::~pickle()
+{
+}
+
+void
+pickle::add(string key, string value)
+{
+ map_[key] = value;
+}
+
+string
+pickle::to_string() const
+{
+ size_t n = 1;
+ ostringstream os;
+ os << "(dp" << n++ << endl;
+ for(stringmap::const_iterator i(map_.begin()); i != map_.end(); ++i) {
+ os << "S'" << i->first << "'" << endl;
+ os << "p" << n++ << endl;
+ os << "S'" << i->second << "'" << endl;
+ os << "p" << n++ << endl << "s";
+ }
+ os << "." << endl;
+ return os.str();
+}
diff --git a/blocks/src/lib/pickle.h b/blocks/src/lib/pickle.h
new file mode 100644
index 0000000..048a635
--- /dev/null
+++ b/blocks/src/lib/pickle.h
@@ -0,0 +1,69 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_PICKLE_H
+#define INCLUDED_PICKLE_H
+
+#include <abstract_data_unit.h>
+
+#include <map>
+
+/**
+ * A pickled Python dictionary. Used to pass stuff to the UI.
+ */
+class pickle
+{
+
+public:
+
+ /**
+ * pickle constructor.
+ *
+ * \param frame_body A const_bit_queue representing the frame body.
+ */
+ pickle();
+
+ /**
+ * pickle virtual destructor.
+ */
+ ~pickle();
+
+ /**
+ * Add a key/value pair to the pickled dictionary
+ */
+ void add(std::string key, std::string value);
+
+ /**
+ * Returns a string describing the Data Unit ID (DUID).
+ */
+ std::string to_string() const;
+
+private:
+
+ typedef std::map<std::string, std::string> stringmap;
+
+ stringmap map_;
+
+};
+
+#endif /* INCLUDED_PICKLE_H */
diff --git a/blocks/src/lib/snapshot_du_handler.cc b/blocks/src/lib/snapshot_du_handler.cc
new file mode 100644
index 0000000..222f5ed
--- /dev/null
+++ b/blocks/src/lib/snapshot_du_handler.cc
@@ -0,0 +1,66 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include <cstring>
+#include <snapshot_du_handler.h>
+#include <string>
+
+using std::string;
+
+snapshot_du_handler::snapshot_du_handler(data_unit_handler_sptr next) :
+ data_unit_handler(next),
+ d_data_units(0)
+{
+}
+
+snapshot_du_handler::~snapshot_du_handler()
+{
+}
+
+void
+snapshot_du_handler::handle(data_unit_sptr du)
+{
+ if(d_msgq) {
+ string snapshot(du->snapshot());
+ if(snapshot.size() > 0) {
+ const size_t snapshot_sz = snapshot.size() + 1;
+ gr_message_sptr msg = gr_make_message(/*type*/0, /*arg1*/++d_data_units, /*arg2*/0, snapshot_sz);
+ char *snapshot_data = reinterpret_cast<char*>(msg->msg());
+ memcpy(snapshot_data, snapshot.c_str(), snapshot_sz);
+ d_msgq->handle(msg);
+ }
+ }
+ data_unit_handler::handle(du);
+}
+
+gr_msg_queue_sptr
+snapshot_du_handler::get_msgq() const
+{
+ return d_msgq;
+}
+
+void
+snapshot_du_handler::set_msgq(gr_msg_queue_sptr msgq)
+{
+ d_msgq = msgq;
+}
diff --git a/blocks/src/lib/snapshot_du_handler.h b/blocks/src/lib/snapshot_du_handler.h
new file mode 100644
index 0000000..3f92120
--- /dev/null
+++ b/blocks/src/lib/snapshot_du_handler.h
@@ -0,0 +1,94 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_SNAPSHOT_DU_HANDLER_H
+#define INCLUDED_SNAPSHOT_DU_HANDLER_H
+
+#include <data_unit_handler.h>
+#include <gr_msg_queue.h>
+#include <boost/noncopyable.hpp>
+
+/**
+ * snapshot_du_handler. Writes traffic snapshots to a msg_queue based
+ * on the HDU frame contents. The format used is that of a pickled
+ * python dictionary allowing the other end of the queue to pick only
+ * those fields of interest and ignore the rest.
+ */
+class snapshot_du_handler : public data_unit_handler
+{
+
+public:
+
+ /**
+ * snapshot_du_handler constructor.
+ *
+ * \param next The next data_unit_handler in the chain.
+ * \param msgq A non-null msg_queue_sptr to the msg_queue to use.
+ */
+ snapshot_du_handler(data_unit_handler_sptr next);
+
+ /**
+ * snapshot_du_handler virtual destructor.
+ */
+ virtual ~snapshot_du_handler();
+
+ /**
+ * Handle a received P25 frame.
+ *
+ * \param du A non-null data_unit_sptr to handle.
+ */
+ virtual void handle(data_unit_sptr du);
+
+ /**
+ * Accessor for the msgq attribute. Returns a pointer to the msgq
+ * if it exists.
+ *
+ * \return A (possibly NULL) gr_msg_queue_sptr pointing to the message queue.
+ */
+ gr_msg_queue_sptr get_msgq() const;
+
+ /**
+ * Accessor for the msgq attribute. Sets the msgq to point to the
+ * provided message queue object.
+ *
+ * \return A (possibly NULL) gr_msg_queue_sptr pointing to the message queue.
+ */
+ void set_msgq(gr_msg_queue_sptr msgq);
+
+private:
+
+ /**
+ * Count of the data units seen so far.
+ */
+ uint32_t d_data_units;
+
+ /**
+ * The msg_queue to which decoded frames are written.
+ */
+ gr_msg_queue_sptr d_msgq;
+
+};
+
+
+
+#endif /* INCLUDED_SNAPSHOT_DU_HANDLER_H */
diff --git a/blocks/src/lib/software_imbe_decoder.cc b/blocks/src/lib/software_imbe_decoder.cc
new file mode 100644
index 0000000..1801027
--- /dev/null
+++ b/blocks/src/lib/software_imbe_decoder.cc
@@ -0,0 +1,1433 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008-2009 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.
+ */
+
+#include <software_imbe_decoder.h>
+#include <op25_yank.h>
+#include <op25_imbe_frame.h>
+
+#include <algorithm>
+#include <cstdio>
+#include <cstdlib>
+#include <op25_golay.h>
+#include <op25_hamming.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+#include <string.h>
+
+static const int BMTn[3600] = {
+ 3, 3, 4, 5, 6, 7, 8, 3, 4, 5, 6, 7, 8, 9, 3, 4,
+ 5, 6, 7, 8, 9, 10, 3, 4, 5, 6, 7, 8, 9, 10, 3, 4,
+ 5, 6, 7, 8, 9, 10, 3, 1, 1, 1, 2, 2, 4, 5, 6, 7,
+ 8, 9, 10, 3, 4, 5, 6, 7, 8, 9, 10, 3, 4, 5, 6, 7,
+ 8, 9, 10, 3, 4, 5, 6, 7, 8, 9, 10, 3, 4, 8, 3, 4,
+ 5, 6, 7, 8, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7,
+ 8, 9, 10, 3, 4, 5, 6, 7, 8, 9, 10, 11, 3, 4, 5, 6,
+ 7, 8, 1, 1, 1, 1, 2, 2, 9, 10, 11, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 3, 4, 5, 6, 7, 8, 9, 10, 11, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 8, 3, 4, 5, 8, 3, 4, 5, 6, 7,
+ 8, 9, 3, 4, 5, 6, 7, 8, 9, 10, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 1, 1,
+ 1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 3, 8, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8,
+ 9, 10, 3, 4, 5, 6, 7, 8, 9, 10, 11, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 3, 4, 5, 1, 1, 1, 1, 2, 2, 6, 7,
+ 8, 9, 10, 11, 12, 13, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 3, 4, 5, 8,
+ 9, 3, 4, 5, 6, 7, 8, 9, 10, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 3, 4, 5, 6,
+ 7, 8, 9, 1, 1, 1, 1, 1, 2, 2, 10, 11, 12, 13, 14, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 3, 8, 9, 3, 4, 5, 6, 7, 8,
+ 9, 3, 4, 5, 6, 7, 8, 9, 10, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 14, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 1,
+ 1, 1, 1, 2, 2, 13, 14, 15, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 3, 9, 3, 4, 5, 6, 8, 9, 3, 4, 5, 6, 7, 8,
+ 9, 10, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 1, 1, 1, 1, 2, 2,
+ 16, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 3, 4, 5,
+ 8, 9, 3, 4, 5, 6, 7, 8, 9, 10, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 3, 4, 1, 1, 1, 1, 1, 1, 2, 2, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 3, 4, 3, 4, 5, 6, 7, 8,
+ 9, 10, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 3, 4, 5, 6, 1,
+ 1, 1, 1, 1, 1, 2, 2, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 3, 3, 4, 5, 6, 7, 8, 10, 11, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 3, 4, 5, 6, 7, 8, 1, 1, 1, 1, 1, 1,
+ 2, 2, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 3, 3,
+ 4, 5, 8, 10, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 3, 4, 5,
+ 6, 7, 8, 9, 10, 1, 1, 1, 1, 1, 1, 1, 2, 2, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 3, 3, 4, 5, 8, 10, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 16, 19, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 12, 13, 14, 15, 16, 17, 19,
+ 20, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 3, 4, 5, 10, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 20,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 1, 1, 1, 1,
+ 1, 1, 2, 2, 14, 15, 16, 17, 18, 20, 21, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 3,
+ 4, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 15, 18, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+ 17, 18, 19, 21, 22, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 3, 3, 4, 5, 6, 7,
+ 8, 10, 11, 13, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 16, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 19, 20, 22, 23, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 3, 3, 4, 5, 6, 7, 8, 11, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 21, 23, 24, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 3, 3, 4, 5, 6, 8, 11, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 17, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 20, 21, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 23, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 3, 3, 4, 5, 8,
+ 11, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21,
+ 24, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 3, 3, 4, 5, 8, 11, 3, 4, 5, 6,
+ 7, 8, 9, 11, 12, 14, 17, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 25, 26, 3, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2, 2, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 3, 4, 5, 8, 11, 3, 4, 5, 6, 7, 8, 9, 11, 12, 14,
+ 18, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 22, 23, 26, 3, 4, 5, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 2, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 3, 4, 5, 11,
+ 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 19, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 23, 27, 3,
+ 4, 5, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 3, 4, 5, 3, 4, 5, 6, 7, 8,
+ 9, 12, 13, 16, 20, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 20, 21, 24, 28, 3, 4, 5, 6, 7, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 3, 4, 3, 4, 5, 6, 7, 8, 9, 12, 13, 16, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21,
+ 24, 28, 3, 4, 5, 6, 7, 8, 9, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 3, 4, 3,
+ 4, 5, 6, 7, 8, 9, 12, 13, 16, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 24, 29, 3, 4, 5,
+ 6, 7, 8, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 3, 3, 4, 5, 6, 7, 8, 9,
+ 12, 13, 16, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 20, 21, 25, 30, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 3, 3, 4, 5, 6, 7, 8, 12, 16, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 22, 26, 31,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2, 2, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 3, 3,
+ 4, 5, 6, 7, 8, 12, 17, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 22, 23, 27, 32, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 32, 33, 34, 35, 3, 3, 4, 5, 6, 7, 8,
+ 13, 18, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 18,
+ 19, 23, 24, 28, 33, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 33, 34, 35, 36, 3, 3, 4, 5, 6, 8, 13, 18, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 23, 28, 33, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 3,
+ 3, 4, 5, 6, 8, 13, 18, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 13, 14, 15, 16, 18, 19, 23, 28, 34, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 2, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 3, 3, 4, 5, 6, 8,
+ 13, 18, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 18,
+ 19, 23, 24, 29, 35, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32,
+ 33, 35, 36, 37, 38, 3, 3, 4, 5, 6, 8, 13, 18, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 13, 14, 15, 18, 19, 24, 25, 30, 36, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 36, 37, 38, 39,
+ 3, 3, 4, 5, 8, 13, 19, 3, 4, 5, 6, 7, 8, 9, 10, 13,
+ 14, 15, 16, 19, 20, 25, 26, 31, 37, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2, 2, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 31, 32, 33, 34, 35, 37, 38, 39, 40, 3, 3, 4, 5, 8,
+ 14, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 20, 21,
+ 26, 27, 32, 38, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 33,
+ 34, 35, 38, 39, 40, 41, 3, 3, 4, 5, 8, 14, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 14, 15, 16, 17, 20, 21, 26, 32, 38, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 38, 39, 40, 41,
+ 42, 3, 3, 4, 5, 8, 14, 3, 4, 5, 6, 7, 8, 9, 10, 14,
+ 15, 16, 17, 20, 21, 26, 32, 39, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 32, 33, 34, 35, 36, 39, 40, 41, 42, 43, 3, 3, 4, 5,
+ 8, 14, 3, 4, 5, 6, 7, 8, 9, 10, 14, 15, 16, 20, 21, 26,
+ 27, 33, 40, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 33, 34, 35,
+ 36, 37, 40, 41, 42, 43, 44, 3, 4, 5, 8, 14, 3, 4, 5, 6,
+ 7, 8, 9, 10, 14, 15, 16, 20, 21, 27, 28, 34, 41, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 34, 35, 36, 37, 38, 41, 42, 43,
+ 44, 45, 3, 4, 5, 8, 14, 3, 4, 5, 6, 7, 8, 9, 10, 14,
+ 15, 16, 21, 22, 28, 29, 35, 42, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 2, 2, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31, 32, 35, 36, 37, 38, 39, 42, 43, 44, 45, 3, 4, 5,
+ 8, 15, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 22, 23, 29,
+ 30, 36, 43, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 36, 37, 38, 39, 43, 44, 45, 46, 3, 4, 5, 8, 15, 3, 4, 5,
+ 6, 7, 8, 9, 10, 15, 16, 17, 22, 23, 29, 30, 36, 43, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 20, 21, 22,
+ 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 36, 37, 38, 39, 43, 44,
+ 45, 46, 47, 3, 4, 5, 8, 15, 3, 4, 5, 6, 7, 8, 9, 10,
+ 15, 16, 17, 22, 23, 29, 30, 36, 44, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2, 2, 20, 21, 22, 23, 24, 25, 26, 27,
+ 29, 30, 31, 32, 33, 36, 37, 38, 39, 40, 44, 45, 46, 47, 3, 4,
+ 5, 8, 15, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 22, 23, 29,
+ 30, 37, 45, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 37,
+ 38, 39, 40, 41, 45, 46, 47, 48, 49, 3, 4, 8, 15, 3, 4, 5,
+ 6, 7, 8, 9, 15, 16, 17, 22, 23, 30, 31, 38, 46, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 22, 23,
+ 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 38, 39, 40, 41, 42, 46,
+ 47, 48, 49, 50, 3, 4, 8, 15, 3, 4, 5, 6, 7, 8, 9, 15,
+ 16, 17, 23, 24, 31, 32, 39, 47, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 22, 23, 24, 25, 26, 27, 28,
+ 29, 31, 32, 33, 34, 35, 39, 40, 41, 42, 43, 47, 48, 49, 50, 3,
+ 4, 8, 16, 3, 4, 5, 6, 7, 8, 9, 10, 16, 17, 18, 24, 25,
+ 32, 33, 40, 48, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 16, 17, 18, 19, 20, 21, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 2, 22, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35,
+ 36, 40, 41, 42, 43, 44, 48, 49, 50, 51, 3, 4, 8, 16, 3, 4,
+ 5, 6, 7, 8, 9, 10, 16, 17, 18, 24, 25, 32, 33, 40, 48, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20,
+ 21, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 22,
+ 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 40, 41, 42, 43,
+ 48, 49, 50, 51, 52, 3, 4, 8, 16, 3, 4, 5, 6, 7, 8, 9,
+ 10, 16, 17, 18, 24, 25, 32, 33, 40, 49, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 22, 24, 25, 26, 27, 28,
+ 29, 30, 32, 33, 34, 35, 36, 40, 41, 42, 43, 44, 49, 50, 51, 52
+};
+
+static const int BMTb[3600] = {
+ 512, 256, 256, 256, 256, 256, 256, 128, 128, 128, 128, 128, 128, 128, 64, 64,
+ 64, 64, 64, 64, 64, 64, 32, 32, 32, 32, 32, 32, 32, 32, 16, 16,
+ 16, 16, 16, 16, 16, 16, 8, 4, 2, 1, 4, 2, 8, 8, 8, 8,
+ 8, 8, 8, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2,
+ 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 256, 256, 256, 128, 128,
+ 128, 128, 128, 128, 64, 64, 64, 64, 64, 64, 64, 32, 32, 32, 32, 32,
+ 32, 32, 32, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8,
+ 8, 8, 8, 4, 2, 1, 4, 2, 8, 8, 8, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 256, 128, 128, 128, 128, 64, 64, 64, 64, 64,
+ 64, 64, 32, 32, 32, 32, 32, 32, 32, 32, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 2,
+ 1, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 128, 128, 64, 64, 64, 64, 64, 64, 64, 32, 32, 32, 32, 32, 32,
+ 32, 32, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 4, 4, 4, 8, 4, 2, 1, 4, 2, 4, 4,
+ 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 64, 64, 64, 64,
+ 64, 32, 32, 32, 32, 32, 32, 32, 32, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4,
+ 4, 4, 4, 16, 8, 4, 2, 1, 4, 2, 4, 4, 4, 4, 4, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 64, 64, 64, 32, 32, 32, 32, 32, 32,
+ 32, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 16, 8,
+ 4, 2, 1, 4, 2, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 64, 64, 32, 32, 32, 32, 32, 32, 16, 16, 16, 16, 16, 16,
+ 16, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 16, 8, 4, 2, 1, 4, 2,
+ 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 32, 32, 32,
+ 32, 32, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 2, 2, 32, 16, 8, 4, 2, 1, 4, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 32, 32, 16, 16, 16, 16, 16, 16,
+ 16, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 32,
+ 16, 8, 4, 2, 1, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 32, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 32, 16, 8, 4, 2, 1,
+ 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 32, 16,
+ 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2,
+ 2, 2, 2, 2, 2, 64, 32, 16, 8, 4, 2, 1, 4, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 32, 16, 16, 16, 16, 16, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 64, 32, 16, 8, 4, 2, 1, 4, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 64, 32, 16, 8, 4,
+ 2, 1, 4, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16,
+ 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 128, 64, 32, 16, 8, 4, 2, 1, 4, 2,
+ 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 128, 64, 32, 16, 8, 4, 2, 1, 4, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 16, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 128, 64, 32, 16,
+ 8, 4, 2, 1, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 16, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 256, 128, 64, 32, 16, 8, 4, 2, 1,
+ 4, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 8, 8, 8,
+ 8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 256, 128, 64, 32, 16, 8, 4, 2, 1, 4, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 16, 8, 8, 8, 8, 8, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 256, 128, 64,
+ 32, 16, 8, 4, 2, 1, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 1, 1, 512, 256, 128, 64, 32, 16, 8, 4,
+ 2, 1, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 8, 8,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 4, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 8, 8, 8, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 512, 256,
+ 128, 64, 32, 16, 8, 4, 2, 1, 4, 2, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 8, 8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 1, 1, 1, 1, 1, 1, 1, 1024, 512, 256, 128, 64, 32, 16,
+ 8, 4, 2, 1, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 4,
+ 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 8, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1024,
+ 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 4, 2, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 8, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2048, 1024, 512, 256, 128, 64,
+ 32, 16, 8, 4, 2, 1, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 4,
+ 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2,
+ 1, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 4, 4, 4, 4, 4, 4,
+ 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 4, 2, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 8, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2048, 1024, 512, 256, 128,
+ 64, 32, 16, 8, 4, 2, 1, 4, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8,
+ 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4,
+ 2, 1, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 4, 4, 4, 4, 4,
+ 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 4, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 8, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2048, 1024, 512, 256,
+ 128, 64, 32, 16, 8, 4, 2, 1, 4, 2, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 8, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2048, 1024, 512, 256, 128, 64, 32, 16, 8,
+ 4, 2, 1, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 4, 4, 4, 4,
+ 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 4, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 8, 4, 4, 4, 4, 4, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2048, 1024, 512,
+ 256, 128, 64, 32, 16, 8, 4, 2, 1, 4, 2, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 8, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2048, 1024, 512, 256, 128, 64, 32, 16,
+ 8, 4, 2, 1, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 4, 4, 4,
+ 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 4,
+ 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2048, 1024,
+ 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 4, 2, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2048, 1024, 512, 256, 128, 64, 32,
+ 16, 8, 4, 2, 1, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4,
+ 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1,
+ 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2048,
+ 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 4, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2048, 1024, 512, 256, 128, 64,
+ 32, 16, 8, 4, 2, 1, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4,
+ 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2,
+ 1, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 4, 2, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2048, 1024, 512, 256, 128,
+ 64, 32, 16, 8, 4, 2, 1, 4, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,
+ 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4,
+ 2, 1, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 4, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2048, 1024, 512, 256,
+ 128, 64, 32, 16, 8, 4, 2, 1, 4, 2, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+static const int BitCount[1512] = {
+ 10, 9, 9, 9, 9, 9, 8, 7, 9, 9, 8, 8, 8, 9, 7, 6,
+ 5, 8, 8, 8, 7, 7, 9, 7, 6, 5, 4, 8, 7, 7, 7, 7,
+ 8, 7, 6, 5, 4, 3, 7, 7, 7, 6, 6, 7, 7, 6, 5, 4,
+ 3, 3, 7, 6, 6, 6, 6, 7, 7, 5, 4, 4, 3, 4, 3, 7,
+ 6, 6, 6, 5, 6, 7, 5, 4, 4, 3, 3, 3, 3, 6, 6, 6,
+ 5, 5, 6, 6, 5, 4, 4, 3, 3, 3, 3, 2, 6, 6, 5, 5,
+ 5, 5, 5, 5, 4, 4, 4, 3, 3, 2, 3, 2, 6, 5, 5, 5,
+ 5, 5, 4, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 6, 5, 5,
+ 4, 4, 5, 4, 5, 4, 4, 3, 3, 3, 3, 2, 3, 2, 1, 6,
+ 5, 5, 4, 4, 5, 4, 5, 4, 4, 3, 3, 2, 3, 2, 1, 3,
+ 2, 1, 5, 5, 5, 4, 4, 4, 4, 5, 4, 4, 3, 3, 2, 2,
+ 3, 2, 1, 3, 2, 1, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 3, 2, 3, 2, 2, 3, 2, 1, 2, 2, 1, 5, 4, 4, 4, 4,
+ 4, 3, 4, 4, 3, 4, 3, 2, 3, 2, 2, 2, 2, 1, 2, 2,
+ 1, 5, 4, 4, 4, 4, 4, 3, 3, 4, 3, 3, 3, 3, 2, 3,
+ 2, 1, 2, 2, 1, 2, 2, 1, 5, 4, 4, 4, 3, 4, 3, 3,
+ 4, 3, 3, 3, 3, 2, 3, 2, 1, 2, 2, 1, 2, 1, 1, 1,
+ 5, 4, 4, 3, 3, 4, 3, 3, 4, 3, 3, 3, 2, 2, 3, 2,
+ 1, 2, 2, 1, 1, 2, 2, 1, 1, 5, 4, 4, 3, 3, 4, 3,
+ 2, 4, 3, 2, 3, 2, 2, 3, 2, 2, 1, 2, 2, 1, 1, 2,
+ 2, 1, 1, 4, 4, 4, 3, 3, 4, 3, 2, 4, 3, 2, 3, 2,
+ 2, 2, 3, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, 4, 4,
+ 4, 3, 3, 3, 3, 2, 4, 3, 2, 2, 3, 2, 2, 2, 3, 2,
+ 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 4, 4, 4, 3, 3, 3,
+ 3, 2, 2, 3, 3, 2, 2, 3, 2, 2, 1, 3, 2, 1, 1, 2,
+ 1, 1, 1, 2, 1, 1, 1, 4, 4, 3, 3, 3, 3, 3, 2, 2,
+ 3, 3, 2, 2, 3, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 1,
+ 2, 1, 1, 1, 1, 4, 4, 3, 3, 3, 3, 3, 2, 2, 3, 3,
+ 2, 2, 3, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 1, 1, 2,
+ 1, 1, 1, 0, 4, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2,
+ 2, 3, 2, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2,
+ 1, 1, 1, 1, 4, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2,
+ 2, 3, 2, 2, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1,
+ 2, 1, 1, 1, 0, 4, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2,
+ 2, 2, 2, 3, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1,
+ 1, 0, 2, 1, 1, 1, 0, 4, 3, 3, 3, 3, 3, 2, 2, 2,
+ 1, 3, 2, 2, 2, 1, 3, 2, 1, 1, 1, 2, 2, 1, 1, 1,
+ 2, 1, 1, 1, 0, 2, 1, 1, 1, 0, 4, 3, 3, 3, 2, 3,
+ 2, 2, 2, 1, 3, 2, 2, 2, 2, 3, 2, 1, 1, 1, 2, 1,
+ 1, 1, 1, 2, 1, 1, 1, 0, 2, 1, 1, 1, 1, 0, 4, 3,
+ 3, 3, 2, 3, 2, 2, 2, 1, 3, 2, 2, 2, 1, 3, 2, 1,
+ 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0, 2, 1, 1,
+ 1, 1, 0, 4, 3, 3, 3, 2, 3, 2, 2, 2, 1, 3, 2, 2,
+ 2, 1, 3, 2, 1, 1, 1, 2, 2, 1, 1, 1, 0, 2, 1, 1,
+ 1, 1, 0, 2, 1, 1, 1, 0, 0, 4, 3, 3, 3, 2, 3, 2,
+ 2, 2, 1, 3, 2, 2, 1, 1, 3, 2, 1, 1, 1, 1, 2, 2,
+ 1, 1, 1, 0, 2, 1, 1, 1, 1, 0, 2, 1, 1, 1, 0, 0,
+ 4, 3, 3, 2, 2, 3, 2, 2, 1, 1, 3, 2, 2, 2, 1, 1,
+ 3, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 0, 2, 1, 1, 1,
+ 1, 0, 2, 1, 1, 1, 0, 0, 4, 3, 3, 2, 2, 3, 2, 2,
+ 2, 1, 1, 3, 2, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2,
+ 2, 1, 1, 1, 0, 2, 1, 1, 1, 0, 0, 2, 1, 1, 1, 0,
+ 0, 4, 3, 3, 2, 2, 3, 2, 2, 2, 1, 1, 3, 2, 2, 2,
+ 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0, 2, 1,
+ 1, 1, 0, 0, 2, 1, 1, 1, 1, 0, 0, 4, 3, 3, 2, 2,
+ 3, 2, 2, 1, 1, 1, 3, 2, 2, 2, 1, 1, 2, 2, 1, 1,
+ 1, 1, 2, 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 0, 0, 2,
+ 1, 1, 1, 1, 0, 0, 4, 3, 3, 2, 2, 3, 2, 2, 1, 1,
+ 1, 3, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1,
+ 1, 1, 0, 0, 2, 1, 1, 1, 1, 0, 0, 2, 1, 1, 1, 1,
+ 0, 0, 3, 3, 3, 2, 2, 3, 2, 2, 1, 1, 1, 3, 2, 2,
+ 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 0,
+ 0, 2, 1, 1, 1, 1, 0, 0, 2, 1, 1, 1, 1, 0, 0, 3,
+ 3, 3, 2, 2, 3, 2, 2, 1, 1, 1, 3, 2, 2, 1, 1, 1,
+ 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 0, 0, 2,
+ 1, 1, 1, 1, 0, 0, 2, 1, 1, 1, 0, 0, 0, 3, 3, 3,
+ 2, 2, 3, 2, 2, 1, 1, 1, 1, 3, 2, 2, 1, 1, 1, 1,
+ 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 0, 0, 2, 1,
+ 1, 1, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 3, 3, 3, 2,
+ 2, 3, 2, 2, 1, 1, 1, 1, 3, 2, 2, 1, 1, 1, 1, 2,
+ 2, 1, 1, 1, 1, 0, 2, 2, 1, 1, 1, 0, 0, 2, 1, 1,
+ 1, 0, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, 3, 3, 3, 2,
+ 2, 3, 2, 2, 1, 1, 1, 1, 3, 2, 2, 1, 1, 1, 1, 2,
+ 2, 1, 1, 1, 1, 0, 2, 2, 1, 1, 1, 0, 0, 2, 1, 1,
+ 1, 1, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 3, 3, 3,
+ 2, 2, 3, 2, 2, 1, 1, 1, 1, 3, 2, 1, 1, 1, 1, 1,
+ 2, 2, 1, 1, 1, 1, 0, 2, 2, 1, 1, 1, 0, 0, 0, 2,
+ 1, 1, 1, 1, 0, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, 3,
+ 3, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1, 3, 2, 2, 1, 1,
+ 1, 1, 2, 2, 1, 1, 1, 1, 1, 0, 2, 2, 1, 1, 1, 0,
+ 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, 2, 1, 1, 1, 1, 0,
+ 0, 0, 3, 3, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1, 3, 2,
+ 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 0, 2, 2,
+ 1, 1, 1, 0, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, 2, 1,
+ 1, 1, 0, 0, 0, 0, 3, 3, 2, 2, 2, 3, 2, 2, 1, 1,
+ 1, 1, 0, 3, 2, 2, 1, 1, 1, 1, 0, 2, 2, 1, 1, 1,
+ 1, 1, 0, 2, 2, 1, 1, 1, 0, 0, 0, 2, 1, 1, 1, 1,
+ 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 3, 3, 2, 2, 2,
+ 3, 2, 2, 1, 1, 1, 1, 0, 3, 2, 2, 1, 1, 1, 1, 0,
+ 2, 2, 1, 1, 1, 1, 1, 0, 2, 2, 1, 1, 1, 0, 0, 0,
+ 2, 1, 1, 1, 0, 0, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0,
+ 0, 3, 3, 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 0, 3, 2,
+ 2, 1, 1, 1, 1, 0, 2, 2, 1, 1, 1, 1, 1, 0, 2, 2,
+ 1, 1, 1, 0, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, 0, 2,
+ 1, 1, 1, 0, 0, 0, 0, 0
+};
+
+static const float StepSize[1512] = {
+ 0.003100, 0.004020, 0.003360, 0.002900, 0.002640, 0.006140, 0.012280, 0.024560, 0.006200, 0.004020, 0.006720, 0.005800, 0.005280, 0.006140, 0.024560, 0.046050,
+ 0.085960, 0.012400, 0.008040, 0.006720, 0.011600, 0.010560, 0.006140, 0.024560, 0.046050, 0.085960, 0.122800, 0.012400, 0.016080, 0.013440, 0.011600, 0.010560,
+ 0.012280, 0.024560, 0.046050, 0.085960, 0.122800, 0.199550, 0.024800, 0.016080, 0.013440, 0.021750, 0.019800, 0.024560, 0.024560, 0.046050, 0.085960, 0.122800,
+ 0.199550, 0.156650, 0.024800, 0.030150, 0.025200, 0.021750, 0.019800, 0.024560, 0.024560, 0.085960, 0.122800, 0.122800, 0.156650, 0.122800, 0.156650, 0.024800,
+ 0.030150, 0.025200, 0.021750, 0.036960, 0.046050, 0.024560, 0.085960, 0.122800, 0.096400, 0.199550, 0.156650, 0.199550, 0.156650, 0.046500, 0.030150, 0.025200,
+ 0.040600, 0.036960, 0.046050, 0.046050, 0.085960, 0.096400, 0.122800, 0.156650, 0.199550, 0.156650, 0.199550, 0.204850, 0.046500, 0.030150, 0.047040, 0.040600,
+ 0.036960, 0.085960, 0.085960, 0.067480, 0.122800, 0.096400, 0.122800, 0.156650, 0.199550, 0.204850, 0.199550, 0.204850, 0.046500, 0.056280, 0.047040, 0.040600,
+ 0.036960, 0.085960, 0.096400, 0.085960, 0.067480, 0.122800, 0.156650, 0.199550, 0.156650, 0.199550, 0.204850, 0.260950, 0.204850, 0.046500, 0.056280, 0.047040,
+ 0.058000, 0.052800, 0.085960, 0.096400, 0.085960, 0.096400, 0.122800, 0.156650, 0.199550, 0.156650, 0.199550, 0.204850, 0.199550, 0.204850, 0.248400, 0.046500,
+ 0.056280, 0.047040, 0.058000, 0.052800, 0.085960, 0.096400, 0.085960, 0.096400, 0.122800, 0.156650, 0.199550, 0.204850, 0.199550, 0.204850, 0.248400, 0.199550,
+ 0.204850, 0.248400, 0.086800, 0.056280, 0.047040, 0.058000, 0.052800, 0.122800, 0.096400, 0.085960, 0.096400, 0.122800, 0.156650, 0.199550, 0.204850, 0.175950,
+ 0.199550, 0.204850, 0.248400, 0.199550, 0.204850, 0.248400, 0.086800, 0.056280, 0.067200, 0.058000, 0.052800, 0.122800, 0.096400, 0.122800, 0.096400, 0.122800,
+ 0.156650, 0.175950, 0.199550, 0.204850, 0.175950, 0.199550, 0.204850, 0.248400, 0.260950, 0.204850, 0.248400, 0.086800, 0.080400, 0.067200, 0.058000, 0.052800,
+ 0.122800, 0.156650, 0.122800, 0.096400, 0.134550, 0.122800, 0.156650, 0.175950, 0.199550, 0.204850, 0.175950, 0.260950, 0.204850, 0.248400, 0.260950, 0.204850,
+ 0.248400, 0.086800, 0.080400, 0.067200, 0.058000, 0.052800, 0.122800, 0.156650, 0.134550, 0.122800, 0.156650, 0.134550, 0.199550, 0.156650, 0.175950, 0.199550,
+ 0.204850, 0.248400, 0.260950, 0.204850, 0.248400, 0.260950, 0.204850, 0.248400, 0.086800, 0.080400, 0.067200, 0.058000, 0.085800, 0.122800, 0.156650, 0.134550,
+ 0.122800, 0.156650, 0.134550, 0.199550, 0.156650, 0.175950, 0.199550, 0.204850, 0.248400, 0.260950, 0.204850, 0.248400, 0.260950, 0.289200, 0.248400, 0.228000,
+ 0.086800, 0.080400, 0.067200, 0.094250, 0.085800, 0.122800, 0.156650, 0.134550, 0.122800, 0.156650, 0.134550, 0.199550, 0.204850, 0.175950, 0.199550, 0.204850,
+ 0.248400, 0.260950, 0.204850, 0.248400, 0.228000, 0.260950, 0.204850, 0.248400, 0.228000, 0.086800, 0.080400, 0.067200, 0.094250, 0.085800, 0.122800, 0.156650,
+ 0.175950, 0.122800, 0.156650, 0.175950, 0.199550, 0.204850, 0.175950, 0.199550, 0.204850, 0.175950, 0.228000, 0.260950, 0.204850, 0.248400, 0.228000, 0.260950,
+ 0.204850, 0.248400, 0.228000, 0.124000, 0.080400, 0.067200, 0.094250, 0.085800, 0.122800, 0.156650, 0.175950, 0.122800, 0.156650, 0.175950, 0.199550, 0.204850,
+ 0.175950, 0.161500, 0.199550, 0.204850, 0.248400, 0.228000, 0.260950, 0.204850, 0.248400, 0.228000, 0.260950, 0.289200, 0.248400, 0.228000, 0.124000, 0.080400,
+ 0.067200, 0.094250, 0.085800, 0.199550, 0.156650, 0.175950, 0.122800, 0.156650, 0.175950, 0.161500, 0.199550, 0.204850, 0.175950, 0.161500, 0.199550, 0.204850,
+ 0.248400, 0.228000, 0.260950, 0.289200, 0.248400, 0.228000, 0.260950, 0.289200, 0.248400, 0.228000, 0.124000, 0.080400, 0.067200, 0.094250, 0.085800, 0.199550,
+ 0.156650, 0.175950, 0.161500, 0.199550, 0.156650, 0.175950, 0.161500, 0.199550, 0.204850, 0.175950, 0.228000, 0.199550, 0.204850, 0.248400, 0.228000, 0.260950,
+ 0.289200, 0.248400, 0.228000, 0.260950, 0.289200, 0.248400, 0.228000, 0.124000, 0.080400, 0.109200, 0.094250, 0.085800, 0.199550, 0.156650, 0.175950, 0.161500,
+ 0.199550, 0.156650, 0.175950, 0.161500, 0.199550, 0.204850, 0.175950, 0.228000, 0.260950, 0.204850, 0.248400, 0.228000, 0.260950, 0.289200, 0.248400, 0.228000,
+ 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.124000, 0.080400, 0.109200, 0.094250, 0.085800, 0.199550, 0.156650, 0.175950, 0.161500, 0.199550, 0.156650,
+ 0.175950, 0.161500, 0.199550, 0.204850, 0.175950, 0.228000, 0.260950, 0.204850, 0.248400, 0.228000, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.260950,
+ 0.289200, 0.248400, 0.228000, 0.000000, 0.124000, 0.130650, 0.109200, 0.094250, 0.085800, 0.199550, 0.156650, 0.175950, 0.161500, 0.199550, 0.156650, 0.175950,
+ 0.161500, 0.199550, 0.204850, 0.248400, 0.228000, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.260950,
+ 0.289200, 0.248400, 0.228000, 0.214800, 0.124000, 0.130650, 0.109200, 0.094250, 0.085800, 0.199550, 0.204850, 0.175950, 0.161500, 0.199550, 0.204850, 0.175950,
+ 0.161500, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800,
+ 0.260950, 0.289200, 0.248400, 0.228000, 0.000000, 0.124000, 0.130650, 0.109200, 0.094250, 0.085800, 0.199550, 0.204850, 0.175950, 0.161500, 0.199550, 0.204850,
+ 0.175950, 0.161500, 0.152150, 0.199550, 0.204850, 0.248400, 0.228000, 0.214800, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.260950, 0.289200, 0.248400,
+ 0.228000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.000000, 0.124000, 0.130650, 0.109200, 0.094250, 0.085800, 0.199550, 0.204850, 0.175950, 0.161500,
+ 0.214800, 0.199550, 0.204850, 0.175950, 0.161500, 0.214800, 0.199550, 0.204850, 0.248400, 0.228000, 0.214800, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800,
+ 0.260950, 0.289200, 0.248400, 0.228000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.000000, 0.124000, 0.130650, 0.109200, 0.094250, 0.112200, 0.199550,
+ 0.204850, 0.175950, 0.161500, 0.214800, 0.199550, 0.204850, 0.175950, 0.161500, 0.152150, 0.199550, 0.204850, 0.248400, 0.228000, 0.214800, 0.260950, 0.289200,
+ 0.248400, 0.228000, 0.214800, 0.260950, 0.289200, 0.248400, 0.228000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.124000, 0.130650,
+ 0.109200, 0.094250, 0.112200, 0.199550, 0.204850, 0.175950, 0.161500, 0.214800, 0.199550, 0.204850, 0.175950, 0.161500, 0.214800, 0.199550, 0.204850, 0.248400,
+ 0.228000, 0.214800, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.260950, 0.289200, 0.248400,
+ 0.228000, 0.214800, 0.000000, 0.124000, 0.130650, 0.109200, 0.094250, 0.112200, 0.199550, 0.204850, 0.175950, 0.161500, 0.214800, 0.199550, 0.204850, 0.175950,
+ 0.161500, 0.214800, 0.199550, 0.204850, 0.248400, 0.228000, 0.214800, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.000000, 0.260950, 0.289200, 0.248400,
+ 0.228000, 0.214800, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.000000, 0.000000, 0.124000, 0.130650, 0.109200, 0.094250, 0.112200, 0.199550, 0.204850,
+ 0.175950, 0.161500, 0.214800, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.199550, 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.260950, 0.204850,
+ 0.248400, 0.228000, 0.214800, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.000000, 0.000000,
+ 0.124000, 0.130650, 0.109200, 0.123250, 0.112200, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.199550, 0.204850, 0.175950, 0.161500, 0.214800, 0.207600,
+ 0.199550, 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000,
+ 0.214800, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.000000, 0.000000, 0.124000, 0.130650, 0.109200, 0.123250, 0.112200, 0.199550, 0.204850, 0.175950,
+ 0.161500, 0.214800, 0.207600, 0.199550, 0.204850, 0.175950, 0.161500, 0.214800, 0.207600, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.260950,
+ 0.204850, 0.248400, 0.228000, 0.214800, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.000000,
+ 0.000000, 0.124000, 0.130650, 0.109200, 0.123250, 0.112200, 0.199550, 0.204850, 0.175950, 0.161500, 0.214800, 0.207600, 0.199550, 0.204850, 0.175950, 0.161500,
+ 0.214800, 0.207600, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.260950, 0.289200,
+ 0.248400, 0.228000, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.124000, 0.130650, 0.109200, 0.123250, 0.112200,
+ 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.207600, 0.199550, 0.204850, 0.175950, 0.161500, 0.214800, 0.207600, 0.260950, 0.204850, 0.248400, 0.228000,
+ 0.214800, 0.207600, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.260950,
+ 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.124000, 0.130650, 0.109200, 0.123250, 0.112200, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800,
+ 0.207600, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.207600, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.260950, 0.204850, 0.248400,
+ 0.228000, 0.214800, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800,
+ 0.000000, 0.000000, 0.201500, 0.130650, 0.109200, 0.123250, 0.112200, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.207600, 0.199550, 0.204850, 0.175950,
+ 0.228000, 0.214800, 0.207600, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.198000, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.000000,
+ 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.201500,
+ 0.130650, 0.109200, 0.123250, 0.112200, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.207600, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.207600,
+ 0.198000, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.198000, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.260950,
+ 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.000000, 0.000000, 0.000000, 0.201500, 0.130650, 0.109200,
+ 0.123250, 0.112200, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.207600, 0.198000, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.207600, 0.198000,
+ 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.198000, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.260950, 0.289200,
+ 0.248400, 0.228000, 0.000000, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.000000, 0.000000, 0.000000, 0.201500, 0.130650, 0.109200, 0.123250,
+ 0.112200, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.207600, 0.198000, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.207600, 0.198000, 0.260950,
+ 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.000000, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400,
+ 0.228000, 0.000000, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.000000, 0.201500, 0.130650, 0.109200, 0.123250,
+ 0.112200, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.207600, 0.198000, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.207600, 0.198000, 0.260950,
+ 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.000000, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400,
+ 0.228000, 0.214800, 0.000000, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.000000, 0.000000, 0.000000, 0.000000, 0.201500, 0.130650, 0.109200,
+ 0.123250, 0.112200, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.207600, 0.198000, 0.199550, 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.198000,
+ 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.000000, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.000000, 0.260950,
+ 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.000000, 0.201500,
+ 0.130650, 0.142800, 0.123250, 0.112200, 0.199550, 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.198000, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800,
+ 0.207600, 0.198000, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.198000, 0.000000, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.000000,
+ 0.000000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.000000,
+ 0.000000, 0.000000, 0.201500, 0.130650, 0.142800, 0.123250, 0.112200, 0.199550, 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.198000, 0.199550, 0.204850,
+ 0.175950, 0.228000, 0.214800, 0.207600, 0.198000, 0.204000, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.198000, 0.000000, 0.260950, 0.204850,
+ 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.000000, 0.260950, 0.289200,
+ 0.248400, 0.228000, 0.000000, 0.000000, 0.000000, 0.000000, 0.201500, 0.130650, 0.142800, 0.123250, 0.112200, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800,
+ 0.207600, 0.198000, 0.000000, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.207600, 0.198000, 0.000000, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800,
+ 0.207600, 0.198000, 0.000000, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800,
+ 0.000000, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.000000, 0.000000, 0.000000, 0.000000, 0.201500, 0.130650, 0.142800, 0.123250, 0.112200,
+ 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.207600, 0.198000, 0.000000, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.207600, 0.198000, 0.000000,
+ 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.198000, 0.000000, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.000000,
+ 0.260950, 0.289200, 0.248400, 0.228000, 0.000000, 0.000000, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.201500, 0.130650, 0.142800, 0.123250, 0.112200, 0.199550, 0.204850, 0.175950, 0.228000, 0.214800, 0.207600, 0.198000, 0.000000, 0.199550, 0.204850,
+ 0.175950, 0.228000, 0.214800, 0.207600, 0.198000, 0.000000, 0.260950, 0.204850, 0.248400, 0.228000, 0.214800, 0.207600, 0.198000, 0.000000, 0.260950, 0.204850,
+ 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.000000, 0.260950, 0.289200, 0.248400, 0.228000, 0.214800, 0.000000, 0.000000, 0.000000, 0.000000, 0.260950,
+ 0.289200, 0.248400, 0.228000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000
+};
+
+static const float AnnexE[64] = {
+ -2.842205, -2.694235, -2.558260, -2.382850, -2.221042, -2.095574, -1.980845, -1.836058, -1.645556, -1.417658, -1.261301, -1.125631, -0.958207, -0.781591, -0.555837, -0.346976,
+ -0.147249, 0.027755, 0.211495, 0.388380, 0.552873, 0.737223, 0.932197, 1.139032, 1.320995, 1.483433, 1.648297, 1.801447, 1.942731, 2.118613, 2.321486, 2.504443,
+ 2.653909, 2.780654, 2.925355, 3.076390, 3.220825, 3.402869, 3.585096, 3.784606, 3.955521, 4.155636, 4.314009, 4.444150, 4.577542, 4.735552, 4.909493, 5.085264,
+ 5.254767, 5.411894, 5.568094, 5.738523, 5.919215, 6.087701, 6.280685, 6.464201, 6.647736, 6.834672, 7.022583, 7.211777, 7.471016, 7.738948, 8.124863, 8.695827
+};
+
+static const float ws[211] = {
+ 0.000000, 0.020000, 0.040000, 0.060000, 0.080000, 0.100000, 0.120000, 0.140000, 0.160000, 0.180000, 0.200000, 0.220000, 0.240000, 0.260000, 0.280000, 0.300000,
+ 0.320000, 0.340000, 0.360000, 0.380000, 0.400000, 0.420000, 0.440000, 0.460000, 0.480000, 0.500000, 0.520000, 0.540000, 0.560000, 0.580000, 0.600000, 0.620000,
+ 0.640000, 0.660000, 0.680000, 0.700000, 0.720000, 0.740000, 0.760000, 0.780000, 0.800000, 0.820000, 0.840000, 0.860000, 0.880000, 0.900000, 0.920000, 0.940000,
+ 0.960000, 0.980000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
+ 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
+ 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
+ 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
+ 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
+ 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
+ 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
+ 1.000000, 0.980000, 0.960000, 0.940000, 0.920000, 0.900000, 0.880000, 0.860000, 0.840000, 0.820000, 0.800000, 0.780000, 0.760000, 0.740000, 0.720000, 0.700000,
+ 0.680000, 0.660000, 0.640000, 0.620000, 0.600000, 0.580000, 0.560000, 0.540000, 0.520000, 0.500000, 0.480000, 0.460000, 0.440000, 0.420000, 0.400000, 0.380000,
+ 0.360000, 0.340000, 0.320000, 0.300000, 0.280000, 0.260000, 0.240000, 0.220000, 0.200000, 0.180000, 0.160000, 0.140000, 0.120000, 0.100000, 0.080000, 0.060000,
+ 0.040000, 0.020000, 0.000000
+};
+
+static const float woaa[105] = {
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.040799, 1.083189, 1.127142, 1.172608, 1.219512, 1.267748, 1.317176, 1.367615,
+ 1.418842, 1.470588, 1.522534, 1.574307, 1.625488, 1.675603, 1.724138, 1.770538, 1.814224, 1.854599, 1.891074, 1.923077, 1.950078, 1.971609, 1.987282, 1.996805,
+ 2.000000, 1.996805, 1.987282, 1.971609, 1.950078, 1.923077, 1.891074, 1.854599, 1.814224, 1.770538, 1.724138, 1.675603, 1.625488, 1.574307, 1.522534, 1.470588,
+ 1.418842, 1.367615, 1.317176, 1.267748, 1.219512, 1.172608, 1.127142, 1.083189, 1.040799
+};
+
+static const float PhzNz[57] = {
+ 0.000000, 3.002978, -0.385743, -1.804058, 0.708389, 3.080091, 0.234237, -2.601564, 2.564900, 0.101063, -0.241570, -2.283176, 0.460491, -1.611275, 2.258339, -2.055267,
+ 1.733923, 2.517236, -1.766211, 0.897032, -2.360999, -0.280836, -2.714514, 2.100092, 2.300326, -1.158767, -2.044268, -2.668387, -2.578737, 0.185036, 1.551429, 2.726814,
+ 2.655614, 3.046857, 0.834348, -0.513595, 1.466037, 0.691121, 0.127319, -2.034924, -1.070655, 0.456588, -2.278682, 1.229021, -2.139595, -0.119750, -0.301534, 0.029391,
+ 0.068775, 0.520336, 2.339119, -0.808328, 1.332154, 2.929768, -0.338316, 0.022767, -1.063795
+};
+
+static const float Ui[129] = {
+ 460.246094, 90.698601, -140.362900, 3.415093, 99.369812, 445.443207, 522.042786, 252.818405, 125.521202, -119.443199, -342.607910, -393.066895, -494.564301, -284.859009, 351.480896, 660.536377,
+ 149.394104, -654.466980, -845.040527, -496.079102, -155.383499, 313.371399, 370.925110, -207.061905, -49.371632, 355.883392, -295.865509, -950.418823, -646.136597, 154.876801, 475.990295, 251.149902,
+ 275.690796, 176.195206, 39.321491, 323.984711, 3.765467, -740.295471, -684.010681, 22.967060, 532.828186, 327.829803, -17.576559, 36.373402, -144.939194, -400.725189, 59.048889, 408.261597,
+ -3.164414, -207.470093, -76.218567, -8.249402, 56.827209, -221.976196, -346.998199, -139.244995, -582.422485, -1028.400024, -727.781982, -406.098907, -191.811295, 41.401581, -151.480103, -641.985779,
+ -607.550781, -400.055786, -678.727417, -376.449890, 434.718109, 239.750504, -470.508392, -552.972717, -148.247299, 153.369507, 113.672798, 29.017599, 31.270840, -13.290440, -250.178604, -504.166809,
+ -8.738471, 669.869019, 43.365711, -669.164429, -29.603149, 114.396599, -495.633301, -105.838203, 90.404091, -299.971100, 154.039200, 380.408691, 111.480400, 158.179993, -205.268204, -386.008087,
+ -62.792370, -327.508087, -488.555298, 15.982190, 264.942902, 171.169998, 112.966904, -209.006302, -364.411591, 367.667999, 417.925293, -867.776184, -1286.915039, -779.282288, -557.706482, -184.866501,
+ 189.383804, 140.763107, 143.058304, 522.142395, 586.625122, -52.709290, 46.055168, 955.700806, 807.637085, -213.939499, -450.946411, 209.997101, 114.041298, -608.001221, -67.676140, 800.976929,
+ 918.058594
+};
+
+static const float Uq[129] = {
+ 0.000000, 15.557470, -141.517395, 4.850000, 20.818390, -31.850750, 240.388107, 359.115509, 353.314514, -34.321480, -683.943787, -426.828705, 251.196106, 648.932800, 583.257080, -272.161804,
+ -696.480774, -616.009888, -730.197388, -275.599213, -71.369781, -246.298599, 353.591187, 383.542999, -457.883911, -573.009827, 123.842796, 808.834473, 590.295227, -116.924400, 4.462234, 300.142792,
+ -398.965790, -1374.654053, -1271.543945, -306.073090, 175.326508, 330.696106, 640.043701, 308.004608, -163.072403, 10.378300, -113.961601, -623.374390, -714.512207, -384.877991, 71.181877, 261.299896,
+ 129.764801, -8.331214, -68.725418, 88.997963, 276.388611, -133.622498, -673.724915, -355.871704, -137.479996, -829.466675, -936.803223, -471.582794, -615.728271, -670.887085, -713.287109, -1046.473022,
+ -679.554688, -198.067902, -328.069305, -487.968994, -368.145203, 482.697296, 1213.579956, 528.013977, -148.013107, 88.007896, 349.561005, 483.642792, -11.267410, -765.563721, -95.221008, 1021.109985,
+ 810.747620, 291.417908, 516.477783, 771.458984, 430.919586, -105.049500, -259.056702, -412.976807, -776.695312, -506.850098, -208.051407, -624.956421, -280.915710, 302.574402, -349.600403, -520.683228,
+ 278.127899, 446.518799, 21.136551, -178.466400, 262.635498, 683.496704, 448.290802, 360.132202, 334.482605, -306.716003, -777.159912, -433.828796, 88.513657, 278.588989, 94.746696, -541.088989,
+ -645.232483, 321.504211, 801.454773, 511.169189, 164.987106, -538.676819, -971.696228, -735.475586, -533.916626, -355.275909, -234.147903, -468.023285, -691.458313, -533.001770, -291.729004, -199.716904,
+ 0.000000
+};
+
+software_imbe_decoder::software_imbe_decoder()
+{
+ int i,j;
+ //initialize
+ Old = 1; New = 0;
+ psi1 = 0.0;
+ for(i=0; i < 58; i++) {
+ for(j=0; j < 2; j++) {
+ log2Mu[i][j] = 0.0;
+ }
+ }
+ for(i=0; i < 57; i++) {
+ for(j=0; j < 2; j++) {
+ phi[i][j] = 0.0;
+ }
+ }
+ for(i=0; i < 256; i++) {
+ Olduw[i] = 0.0;
+ }
+}
+
+software_imbe_decoder::~software_imbe_decoder()
+{
+}
+
+void
+software_imbe_decoder::decode(const voice_codeword& cw)
+{
+ // process input 144-bit IMBE frame - converts to 88-bit frame
+ unsigned int u0 = 0;
+ unsigned int u1,u2,u3,u4,u5,u6,u7;
+ unsigned int E0 = 0;
+ unsigned int ET = 0;
+ unsigned char O[12];
+
+ // PN/Hamming/Golay - etc.
+ imbe_header_decode(cw, u0, u1, u2, u3, u4, u5, u6, u7, E0, ET) ;
+
+ //replace the sync bit(LSB of u7) with the BOT flag
+ u7 = u7 | 0x01; //ECC procedure called above always returns u7 LSB = 0
+
+ O[0] = (((u0 / 16) & 240) + (u1 / 256));
+ O[1] = (((u2 / 16) & 240) + (u3 / 256));
+ O[2] = (((u4 / 8) & 224) + ((u5 / 64) & 28) + (u6 / 512));
+ O[3] = (((u6 / 2) & 128) + u7);
+ O[4] = (u0 & 255);
+ O[5] = (u1 & 255);
+ O[6] = (u2 & 255);
+ O[7] = (u3 & 255);
+ O[8] = (u4 & 255);
+ O[9] = (u5 & 255);
+ O[10] = (u6 & 255);
+ O[11] = E0 + 4 * ET;
+
+ decode_audio(O); // process 88-bit frame
+}
+
+void
+software_imbe_decoder::adaptive_smoothing(float SE, float ER, float ET)
+{
+ float VM;
+ float YM;
+ int ell;
+
+ if(ER <= .005 && ET <= 4) {
+ VM = 1E+38; //infinity
+ } else if( ER <= .0125 && ET == 0) { //(guessing typo in std)
+ VM = 45.255 * powf(SE, .375) / exp(277.6 * ER);
+ } else {
+ VM = 1.414 * powf(SE, .375);
+ }
+
+ float AM = 0;
+ for(ell = 1; ell <= L; ell++) {
+ if(M[ell][ New] > VM) vee[ell][ New] = 1; //CAUTION:
+ AM = AM + M[ell][ New]; //smoothed vee(ell) replaces unsmoothed!
+ }
+
+ float TM = (ER <= .005 && ET <= 6) ? 20480 : 6000 - 300 * ET; // + TM; /* ToDo: uninitialized! */
+ if(TM <= AM) {
+ YM = TM / AM;
+ for(ell = 1; ell <= L; ell++) {
+ M[ell][ New] = M[ell][New] * YM;
+ }
+ }
+}
+
+void
+software_imbe_decoder::fft(float REX[], float IMX[])
+{
+ int I;
+ int J;
+ int K;
+ int H;
+ int KpH;
+ int Ht2;
+ float tmp_f;
+ float l_Ui, l_Uq, Theta, Si, Sq, Ti, Xi, Tq, Xq;
+
+ J = 64;
+ for(I = 1; I <= 126; I++) {
+#define SWAP(x,y) tmp_f=x;x=y;y=tmp_f
+ if(I < J) { SWAP(REX[J], REX[I]); SWAP(IMX[J], IMX[I]); }
+#undef SWAP
+ K = 64;
+ while(K <= J) { J = J - K; K = K / 2; }
+ J = J + K;
+ }
+
+ H = 1;
+ for(I = 1; I <= 7; I++) {
+ Ht2 = H * 2; l_Ui = 1; l_Uq = 0;
+ Theta = M_PI / H; Si = cos(Theta); Sq = -sin(Theta);
+ for(J = 1; J <= H; J++) {
+ for(K = J - 1; K <= 127; K+=Ht2) {
+ KpH = K + H;
+
+ Ti = REX[KpH] * l_Ui - IMX[KpH] * l_Uq; Xi = REX[K];
+ Tq = REX[KpH] * l_Uq + IMX[KpH] * l_Ui; Xq = IMX[K];
+
+ REX[KpH] = Xi - Ti; REX[K] = Xi + Ti;
+ IMX[KpH] = Xq - Tq; IMX[K] = Xq + Tq;
+ }
+ Ti = l_Ui;
+ l_Ui = Ti * Si - l_Uq * Sq;
+ l_Uq = Ti * Sq + l_Uq * Si;
+ }
+ H = Ht2;
+ }
+
+}
+
+void
+software_imbe_decoder::decode_audio(uint8_t *A)
+{
+ uint32_t u0, u1, u2, u3, u4, u5, u6, u7, E0, ET;
+ int K;
+ int en, tmp_f;
+ float SE = 0, ER = 0;
+
+ imbe_frame_unpack(A, u0, u1, u2, u3, u4, u5, u6, u7, E0, ET);
+
+ ER = .95 * ER + .000365 * ET;
+ if( ER > .0875) {
+ // Huh?!
+ } else if(u0 >= 3328 || E0 >= 2 || ET >=(10 + 40 * ER)) {
+ // Whuh?!
+ } else {
+ K = rearrange(u0, u1, u2, u3, u4, u5, u6, u7); // re-arrange the bits from u to b (ToDo: make 'b' return value ???)
+ decode_vuv(K);
+
+ int Len3, Start3, Len8, Start8;
+ Len3 = L - 1;
+ Start3 =((Len3 * (Len3 - 1)) / 2) - 28;
+ Len8 = L - 6;
+ Start8 =((Len8 * (Len8 - 1)) / 2) - 3;
+
+ decode_spectral_amplitudes(Start3, Start8);
+ enhance_spectral_amplitudes(SE);
+ adaptive_smoothing(SE, ER, ET);
+
+ // (8000 samp/sec) * (1 sec / 50 compressed voice frames) = 160 samples/frame
+
+ //synth:
+ synth_unvoiced();// ToDo: make suv return value?
+ synth_voiced(); // ToDo: make sv return value?
+
+ //output:
+ audio_samples *samples = audio();
+ for(en = 0; en <= 159; en++) {
+ // The unvoiced samples are loud and the voiced are low...I don't know why.
+ // Most of the difference is compensated by removing the 146.6433 factor
+ // in the synth_unvoiced procedure. The final tweak is done by raising the
+ // voiced samples:
+ float sample = suv[en] + sv[en] * 4; //balance v/uv loudness
+// if(abs((int)sample) > 32767) {
+// sample = 32767 * (sample < 0) ? -1 : 1; // * sgn(sample)
+// }
+ sample /= 16384.0; /* 32768.0 - but audio amplitude is not full range of int16 */
+ samples->push_back(sample);
+ }
+ }
+ OldL = L;
+ Oldw0 = w0;
+ tmp_f = Old; Old = New; New = tmp_f;
+}
+
+void
+software_imbe_decoder::decode_spectral_amplitudes(int Start3, int Start8)
+{
+ float G[7]; //Can we use C(1 to 6,1) for this?
+ int J[7];
+ float C[7][ 11] ;
+ float T[57];
+
+ float Tmp ;
+ float Tk ;
+ float TD;
+ float Tp ;
+
+ int P3, P8, eye, jay, kay, ell, em, iTk;
+
+ P3 = Start3; P8 = Start8;
+
+ G[1] = AnnexE[bee[2]];
+
+ for(eye = 2; eye <= 6; eye++) {
+ G[eye] = StepSize[P3] *(bee[eye + 1] - powf(2 ,(BitCount[P3] - 1)) + .5);
+ P3 = P3 + 1;
+ }
+
+ for(eye = 1; eye <= 6; eye++) {
+ Tmp = G[1];
+ for(em = 2; em <= 6; em++) {
+ Tmp = Tmp + 2 * G[em] * cos(M_PI *(em - 1) *(eye - .5) / 6);
+ }
+ //R(eye) = Tmp
+ C[eye][1] = Tmp;
+ }
+
+ ell = 8;
+ for(eye = 1; eye <= 6; eye++) {
+ J[eye] =(L + eye - 1) / 6; //Prediction Residual Block Length
+ // FOR kay = 2 TO J(eye)
+ for(kay = 2; kay <= J[eye]; kay++) {
+ C[eye][ kay] = StepSize[P3] *(bee[ell] - powf(2 ,(BitCount[P3] - 1)) + .5);
+ P3 = P3 + 1; P8 = P8 + 1; ell = ell + 1;
+ }
+ }
+
+ ell = 0;
+ for(eye = 1; eye <= 6; eye++) {
+ for(jay = 1; jay <= J[eye]; jay++) {
+ Tmp = C[eye][ 1];
+ // FOR kay = 2 TO J(eye)
+ for(kay = 2; kay <= J[eye]; kay++) {
+ Tmp = Tmp + 2 * C[eye][ kay] * cos(M_PI *(kay - 1) *(jay - .5) / J[eye]);
+ }
+ ell = ell + 1; T[ell] = Tmp;
+ }
+ }
+ if(ell != L) exit(1);
+
+ // *******
+ // we have the residuals in T(ell); now to sum with the predictions
+ // *******
+
+ // first, set up the assumptions about the previous frame values
+ // Note: L means L(0); OldL means L(-1)
+ if(OldL == 0) { OldL = 30; for( ell = 0; ell <= 57; ell++) { log2Mu[ell][ Old] = 1; } }
+ for(ell = OldL + 1; ell <= L + 1; ell++) { log2Mu[ell][ Old] = log2Mu[OldL][ Old]; }
+
+ // make the predictions and sum with T(ell)
+ if(L <= 15)
+ Tp = .4;
+ else if(L <= 24)
+ Tp = .03 * L - .05;
+ else
+ Tp = .7;
+
+ Tmp = 0;
+ for(ell = 1; ell <= L; ell++) {
+ Tk =((float)OldL /(float)L) *(float)ell;
+ iTk =(int) Tk;
+ TD = Tk - iTk;
+ // temporarily use Mu(ell, New) as temp
+ Mu[ell][ New] = Tp *((1 - TD) * log2Mu[iTk][ Old] + TD * log2Mu[iTk + 1][ Old]);
+ Tmp = Tmp + Mu[ell][ New];
+ }
+ Tmp = Tmp / L;
+ for(ell = 1; ell <= L; ell++) {
+ log2Mu[ell][ New] = T[ell] + Mu[ell][ New] - Tmp;
+ // Mu(ell, New) no longer temp
+ Mu[ell][ New] = powf(2 ,log2Mu[ell][ New]);
+ }
+}
+
+void
+software_imbe_decoder::decode_vuv(int K)
+{
+ int bee1, ell, kay;
+ bee1 = bee[1];
+ for(ell = 1; ell <= L; ell++) {
+ if(ell <= 36)
+ kay =(ell + 2) / 3;
+ else
+ kay = 12;
+
+ //vee(ell, New) = (bee1 \(2 ^(K - kay))) - 2 *(bee1 \(2 ^(K + 1 - kay)))
+ vee[ell][ New] = ((bee1 & (1 << (K - kay))) > 0) ? 1 : 0;
+ }
+}
+
+void
+software_imbe_decoder::enhance_spectral_amplitudes(float& SE)
+{
+ float RM0;
+ float RM1;
+ float Tmp;
+ float K1;
+ float K2;
+ float K3;
+ float W;
+ int ell;
+
+ RM0 = 0; RM1 = 0;
+ for(ell = 1; ell <= L; ell++) {
+ Tmp = powf(Mu[ell][ New] , 2);
+ RM0 = RM0 + Tmp;
+ RM1 = RM1 + Tmp * cos(w0 * ell);
+ }
+
+ K1 = .96 * M_PI /(w0 * RM0 *(powf(RM0 , 2) - powf(RM1 , 2)));
+ K2 = powf(RM0 , 2) + powf(RM1 , 2);
+ K3 = 2 * RM0 * RM1;
+
+ Tmp = 0;
+ for(ell = 1; ell <= L; ell++) {
+ W = sqrt(Mu[ell][ New]) * powf((K1 *(K2 - K3 * cos(w0 * ell))) , .25);
+ if((8 * ell) <= L)
+ M[ell][ New] = Mu[ell][ New];
+ else if(W > 1.2)
+ M[ell][ New] = Mu[ell][ New] * 1.2;
+ else if(W < .5)
+ M[ell][ New] = Mu[ell][ New] * .5;
+ else
+ M[ell][ New] = Mu[ell][ New] * W;
+ Tmp = Tmp + powf(M[ell][ New] , 2);
+ }
+
+ Tmp = sqrt(RM0 / Tmp);
+
+ for(ell = 1; ell <= L; ell++) {
+ M[ell][ New] = M[ell][ New] * Tmp;
+ }
+
+ // update SE
+ SE = .95 * SE + .05 * RM0; if(SE < 10000) SE = 10000;
+
+}
+
+void
+software_imbe_decoder::ifft(float FDi[], float FDq[], float TD[]) // ToDo: replace "real IFFT" with fftw3 IFFT proc!
+{
+ //Inverse FFT:
+ // transform 129-point freq domain(FDx) to 256-point time domain(TD)
+
+ float Ai[128];
+ float Aq[128];
+
+ int I;
+ int J;
+ int K;
+ int H;
+ float l_Ui, l_Uq, Si, Sq, Ti, Tq, Xi, Xq;
+
+ for(I = 0; I <= 63; I++) {
+ J = I + 64; //64 to 127
+ K = I * 2; //0 to 126(step 2)
+ H = 128 - K; //128 to 2(step 2)
+ Ai[I] = FDi[K] + FDq[K];
+ Aq[I] = FDi[K + 1] + FDq[K + 1];
+ Ai[J] = FDi[H] - FDq[H];
+ Aq[J] = FDi[H - 1] - FDq[H - 1];
+ }
+
+ fft(Ai, Aq);
+
+ for(I = 1; I <= 63; I++) {
+ J = 128 - I; //127 to 65
+ K = I + 128; //129 to 191
+ H = J + 128; //255 to 193
+ FDi[K] = (Aq[I] + Aq[J]) / 2;
+ FDi[H] = FDi[K] ; //a
+ FDq[K] = -(Ai[I] - Ai[J]) / 2;
+ FDq[H] = -FDq[K] ; //b
+ FDi[I] = (Ai[I] + Ai[J]) / 2;
+ FDi[J] = FDi[I] ; //c
+ FDq[I] = (Aq[I] - Aq[J]) / 2;
+ FDq[J] = -FDq[I] ; //d
+ }
+
+ // I,J=64 K,H=192
+ FDi[192] = Aq[64]; //a
+ FDq[192] = 0 ; //b
+ FDi[64] = Ai[64] ; //c (new)
+ FDq[64] = 0 ; //d
+
+ //I=0 J,K=128 H=256 ( Ax(128) wraps to Ax(0))
+ FDi[128] = Aq[0] ; //a
+ FDq[128] = 0 ; //b
+ FDi[0] = Ai[0] ; //c (new)
+ FDq[0] = 0 ; //d
+
+ l_Ui = 1; l_Uq = 0;
+ Si = cos(M_PI / 128); Sq = -sin(M_PI / 128);
+ for(I = 0; I <= 127; I++) {
+ J = I + 128 ; //128 TO 255
+
+ Ti = FDi[J] * l_Ui - FDq[J] * l_Uq; Xi = FDi[I];
+ Tq = FDi[J] * l_Uq + FDq[J] * l_Ui; Xq = FDq[I];
+
+
+ TD[I + 128] =((Xi + Ti) -(Xq + Tq));
+ TD[I ] =((Xi - Ti) -(Xq - Tq));
+
+ Ti = l_Ui;
+ l_Ui = Ti * Si - l_Uq * Sq;
+ l_Uq = Ti * Sq + l_Uq * Si;
+ }
+}
+
+uint16_t
+software_imbe_decoder::rearrange(uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3, uint32_t u4, uint32_t u5, uint32_t u6, uint32_t u7)
+{
+ int K;
+ int I, ubit, Seq, col;
+
+ bee[0] =((u0 / 16) & 0xfc) |((u7 / 2) & 3);
+
+ w0 = 4 * M_PI /(bee[0] + 39.5);
+
+ L =(int)(.9254 * floorf((M_PI / w0) + .25)); if(L < 9 || L > 56) exit(2);
+
+ if( L > 36) {
+ K = 12;
+ } else {
+ K =((L + 2) / 3);
+ if(K > 12)
+ exit(3);
+ }
+
+ for(I = 1; I <= L + 1; I++) { bee[I] = 0; }
+
+ bee[2] =(u0 & 56) |((u7 / 8) & 1);
+
+
+ Seq =(L - 9) * 75;
+
+ ubit = 4;
+ for(I = 0; I <= 2; I++) {
+ if( u0 & ubit) {
+ col = BMTn[Seq];
+ bee[col] = bee[col] + BMTb[Seq];
+ }
+ Seq = Seq + 1;
+ ubit = ubit / 2;
+ }
+
+ ubit = 2048;
+ for(I = 0; I <= 11; I++) {
+ if(u1 & ubit){
+ col = BMTn[Seq];
+ bee[col] = bee[col] + BMTb[Seq];
+ }
+ Seq = Seq + 1; ubit = ubit / 2;
+ }
+
+ ubit = 2048;
+ for(I = 0; I <= 11; I++) {
+ if(u2 & ubit){
+ col = BMTn[Seq];
+ bee[col] = bee[col] + BMTb[Seq];
+ }
+ Seq = Seq + 1;
+ ubit = ubit / 2;
+ }
+
+ ubit = 2048;
+ for(I = 0; I <= 11; I++) {
+ if(u3 & ubit) {
+ col = BMTn[Seq];
+ bee[col] = bee[col] + BMTb[Seq];
+ }
+ Seq = Seq + 1;
+ ubit = ubit / 2;
+ }
+
+ ubit = 1024;
+ for(I = 0; I <= 10; I++) {
+ if(u4 & ubit) {
+ col = BMTn[Seq];
+ bee[col] = bee[col] + BMTb[Seq];
+ }
+ Seq = Seq + 1;
+ ubit = ubit / 2;
+ }
+
+ ubit = 1024;
+ for(I = 0; I <= 10; I++) {
+ if(u5 & ubit) {
+ col = BMTn[Seq];
+ bee[col] = bee[col] + BMTb[Seq];
+ }
+ Seq = Seq + 1;
+ ubit = ubit / 2;
+ }
+
+ ubit = 1024;
+ for(I = 0; I <= 10; I++) {
+ if(u6 & ubit){
+ col = BMTn[Seq];
+ bee[col] = bee[col] + BMTb[Seq];
+ }
+ Seq = Seq + 1;
+ ubit = ubit / 2;
+ }
+
+ ubit = 64;
+ for(I = 4; I <= 6; I++) {
+ if(u7 & ubit) {
+ col = BMTn[Seq];
+ bee[col] = bee[col] + BMTb[Seq];
+ }
+ Seq = Seq + 1;
+ ubit = ubit / 2;
+ }
+
+ return K;
+}
+
+void
+software_imbe_decoder::synth_unvoiced()
+{
+ float Uwi[256];
+ float Uwq[256];
+ float uw[256];
+
+ float Tmp;
+
+ int ell, bl, em, al, en;
+
+ ell = 0; bl =(int) ceilf(128 / M_PI *(ell + .5) * w0);
+ for(em = 0; em <= bl - 1; em++) {
+ Uwi[em] = 0; Uwq[em] = 0;
+ }
+
+ Luv = 0;
+ for(ell = 1; ell <= L; ell++) {
+ al = bl; bl =(int) ceilf(128 / M_PI * (ell + .5) * w0);
+ if(vee[ell][New]) {
+ // FOR em = al TO bl - 1
+ for(em = al; em <= bl - 1; em++) {
+ Uwi[em] = 0; Uwq[em] = 0;
+ }
+ } else {
+ Luv = Luv + 1;
+ //precompute Tmp = <most of big hairy equation>
+ Tmp = 0;
+ // FOR en = al TO bl - 1
+ for(en = al; en <= bl - 1; en++) {
+ Tmp += powf(Ui[en], 2) + pow(Uq[en], 2);
+ }
+ Tmp = M[ell][New] / sqrt(Tmp /(bl - al)); //too loud with 146.6433 factor
+ //now do the rest of b.h.e.
+ for(em = al; em <= bl - 1; em++) {
+ Uwi[em] =(Ui[em]) * Tmp;
+ Uwq[em] =(Uq[em]) * Tmp;
+ }
+ }
+ }
+ // finally do over-freq
+ // FOR em = bl TO 128
+ for(em = bl; em <= 128; em++) {
+ Uwi[em] = 0; Uwq[em] = 0;
+ }
+
+ ifft(Uwi, Uwq, uw);
+
+ // ws(n)*uw(n,-1) + ws(n-159)*uw(n-159,0) uw(-128 to 127)
+ //suv(n) = --------------------------------------
+ // (ws(n)^2) +(ws(n-159)^2) ws(-105 to 105)
+
+ for(en = 0; en <= 55; en++) {
+ suv[en] = Olduw[en+128];
+ }
+ for(en = 56; en <= 104; en++) {
+ suv[en] =(ws[en+105] * Olduw[en+128] + ws[en - 55] * uw[en - 32]) * woaa[en];
+ }
+ for(en = 105; en <= 159; en++) {
+ suv[en] = uw[en - 32];
+ }
+
+ for(en = -128; en <= 127; en++) {
+ Olduw[en+128] = uw[en+128];
+ }
+}
+
+void
+software_imbe_decoder::synth_voiced()
+{
+ float MaxL;
+ float Tmp;
+ float Dpl;
+ float Dwl;
+ float THa;
+ float THb;
+ float MNew;
+ float MOld;
+ float Mb;
+
+ int ell, en;
+
+ if( L > OldL) {
+ MaxL = L;
+ } else {
+ MaxL = OldL;
+ }
+
+ psi1 = psi1 +(Oldw0 + w0) * 80;
+ psi1 = remainderf(psi1, 2 * M_PI); // ToDo: decide if its 2pi or pi^2
+
+ for(ell = 1; ell <= L/4; ell++) {
+ phi[ell][ New] = psi1 * ell;
+ }
+ Tmp = Luv / L;
+ for(; ell <= MaxL; ell++) {
+ phi[ell][ New] = psi1 * ell + Tmp * PhzNz[ell];
+ }
+
+ for(en = 0; en <= 159; en++) {
+ sv[en] = 0;
+ }
+
+ for(ell = 1; ell <= MaxL; ell++) {
+
+ if(ell > L) {
+ MNew = 0;
+ } else {
+ MNew = M[ell][ New];
+ }
+
+ if(ell > OldL) {
+ MOld = 0;
+ } else {
+ MOld = M[ell][ Old];
+ }
+
+ if(vee[ell][ New]) {
+ if ( vee[ell][ Old]) {
+ if(ell < 8 && fabsf(w0 - Oldw0) < .1 * w0) { // (fine transition)
+ const double PI_SQUARED = M_PI * M_PI;
+ const double INV_PI_SQUARED = 1.0 / PI_SQUARED;
+ Dpl = phi[ell][ New] - phi[ell][ Old] -(Oldw0 + w0) * ell * 80;
+ Dwl = .00625 * (Dpl - PI_SQUARED * floorf((Dpl + M_PI) * INV_PI_SQUARED));
+ THa = (Oldw0 * (float)ell + Dwl);
+ THb = (w0 - Oldw0) * ell * .003125;
+ Mb = .00625 *(MNew - MOld);
+ for(en = 0; en <= 159; en++) {
+ sv[en] = sv[en] +(MOld + en * Mb) * cos(phi[ell][ Old] +(THa + THb * en) * en);
+ }
+ } else { // (coarse transition)
+ for(en = 0; en <= 55; en++) {
+ sv[en] = sv[en] + ws[en+105] * MOld * cos(Oldw0 * en * ell + phi[ell] [ Old]);
+ }
+ for(en = 56; en <= 105; en++) {
+ sv[en] = sv[en] + ws[en+105] * MOld * cos(Oldw0 * en * ell + phi[ell][ Old]);
+ sv[en] = sv[en] + ws[en-55] * MNew * cos(w0 *(en - 160) * ell + phi[ell][ New]);
+ }
+ for(en = 106; en <= 159; en++) {
+ sv[en] = sv[en] + ws[en-55] * MNew * cos(w0 *(en - 160) * ell + phi[ell][ New]);
+ }
+ }
+ } else {
+ for(en = 56; en <= 159; en++) {
+ sv[en] = sv[en] + ws[en-55] * MNew * cos(w0 *(en - 160) * ell + phi[ell][ New]);
+ }
+ }
+ } else {
+ if( vee[ell][Old]) {
+ for(en = 0; en <= 105; en++) {
+ sv[en] = sv[en] + ws[en+105] * MOld * cos(Oldw0 * en * ell + phi[ell][ Old]);
+ }
+ }
+ }
+ }
+}
+
diff --git a/blocks/src/lib/software_imbe_decoder.h b/blocks/src/lib/software_imbe_decoder.h
new file mode 100644
index 0000000..4ef515f
--- /dev/null
+++ b/blocks/src/lib/software_imbe_decoder.h
@@ -0,0 +1,101 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008-2009 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_SOFTWARE_IMBE_DECODER_H
+#define INCLUDED_SOFTWARE_IMBE_DECODER_H
+
+#include <imbe_decoder.h>
+
+#include <stdint.h>
+
+/**
+ * A software implementation of the imbe_decoder interface.
+ */
+class software_imbe_decoder : public imbe_decoder {
+public:
+
+ /**
+ * Default constructor for the software_imbe_decoder.
+ */
+ software_imbe_decoder();
+
+ /**
+ * Destructor for the software_imbe_decoder.
+ */
+ virtual ~software_imbe_decoder();
+
+ /**
+ * Decode the compressed audio.
+ *
+ * \cw in IMBE codeword (including parity check bits).
+ */
+ virtual void decode(const voice_codeword& cw);
+
+private:
+
+ //NOTE: Single-letter variable names are upper case only; Lower
+ // case if needed is spelled. e.g. L, ell
+
+ // global Seq ER ?
+
+ int bee[58]; //Encoded Spectral Amplitudes
+ float M[57][2]; //Enhanced Spectral Amplitudes
+ float Mu[57][2]; //Unenhanced Spectral Amplitudes
+ int vee[57][2]; //V/UV decisions
+ float suv[160]; //Unvoiced samples
+ float sv[160]; //Voiced samples
+ float log2Mu[58][2];
+ float Olduw[256];
+ float psi1;
+ float phi[57][2];
+
+ int Old;
+ int New;
+ int L;
+ int OldL;
+ float w0;
+ float Oldw0;
+ float Luv; //number of unvoiced spectral amplitudes
+
+ char sym_b[4096];
+ char RxData[4096];
+ int sym_bp;
+ int ErFlag;
+
+ uint32_t pngen15(uint32_t& pn);
+ uint32_t pngen23(uint32_t& pn);
+ void decode_audio(uint8_t *);
+ void decode_spectral_amplitudes(int, int );
+ void decode_vuv(int );
+ void adaptive_smoothing(float, float, float );
+ void fft(float i[], float q[]);
+ void enhance_spectral_amplitudes(float&);
+ void ifft(float i[], float q[], float[]);
+ uint16_t rearrange(uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3, uint32_t u4, uint32_t u5, uint32_t u6, uint32_t u7);
+ void synth_unvoiced();
+ void synth_voiced();
+ void unpack(uint8_t *buf, uint32_t& u0, uint32_t& u1, uint32_t& u2, uint32_t& u3, uint32_t& u4, uint32_t& u5, uint32_t& u6, uint32_t& u7, uint32_t& E0, uint32_t& ET);
+};
+
+
+#endif /* INCLUDED_SOFTWARE_IMBE_DECODER_H */
diff --git a/blocks/src/lib/tdu.cc b/blocks/src/lib/tdu.cc
new file mode 100644
index 0000000..e5cfdde
--- /dev/null
+++ b/blocks/src/lib/tdu.cc
@@ -0,0 +1,84 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include <itpp/base/vec.h>
+#include <itpp/comm/reedsolomon.h>
+#include <tdu.h>
+#include <op25_yank.h>
+
+using std::string;
+
+tdu::tdu(const_bit_queue& frame_body, bool has_link_control) :
+ abstract_data_unit(frame_body),
+ d_has_link_control(has_link_control)
+{
+}
+
+tdu::~tdu()
+{
+}
+
+string
+tdu::duid_str() const
+{
+ return string("TDU");
+}
+
+void
+tdu::do_correct_errors(bit_vector& frame)
+{
+ if(d_has_link_control) {
+ apply_golay_correction(frame);
+ apply_rs_correction(frame);
+ }
+}
+
+void
+tdu::apply_golay_correction(bit_vector& frame)
+{
+}
+
+void
+tdu::apply_rs_correction(bit_vector& frame)
+{
+#if 0
+ static itpp::Reed_Solomon rs(63, 17, true);
+ itpp::bvec b(70);
+ swab(frame, 114, 122, b, 0);
+ swab(frame, 122, 126, b, 8);
+ swab(frame, 138, 142, b, 12);
+ swab(frame, 144, 152, b, 16);
+ swab(frame, 164, 176, b, 24);
+ swab(frame, 188, 200, b, 36);
+ swab(frame, 212, 213, b, 48);
+ swab(frame, 216, 226, b, 50);
+ swab(frame, 238, 250, b, 60);
+ itpp::bvec bd(rs.decode(b));
+#endif
+}
+
+uint16_t
+tdu::frame_size_max() const
+{
+ return d_has_link_control ? 432 : 144;
+}
diff --git a/blocks/src/lib/tdu.h b/blocks/src/lib/tdu.h
new file mode 100644
index 0000000..bb5c678
--- /dev/null
+++ b/blocks/src/lib/tdu.h
@@ -0,0 +1,99 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_TDU_H
+#define INCLUDED_TDU_H
+
+#include <abstract_data_unit.h>
+
+/**
+ * P25 terminator data unit (TDU).
+ */
+class tdu : public abstract_data_unit
+{
+public:
+
+ /**
+ * tdu constructor.
+ *
+ * \param frame_body A const_bit_queue representing the frame body.
+ * \param has_link_control true if frame has link control data, otherwise false.
+ */
+ tdu(const_bit_queue& frame_body, bool has_link_control);
+
+ /**
+ * tdu constructor.
+ */
+ virtual ~tdu();
+
+ /**
+ * Returns a string describing the Data Unit ID (DUID).
+ */
+ std::string duid_str() const;
+
+protected:
+
+ /**
+ * Applies error correction code to the specified bit_vector.
+ *
+ * \param frame_body The bit vector to decode.
+ * \return
+ */
+ virtual void do_correct_errors(bit_vector& frame_body);
+
+ /**
+ * Apply Golay error correction code to the specified bit_vector.
+ *
+ * \param frame_body The bit vector to decode.
+ * \return
+ */
+ virtual void apply_golay_correction(bit_vector& frame_body);
+
+ /**
+ * Apply Reed-Solomon error correction code to the specified
+ * bit_vector.
+ *
+ * \param frame_body The bit vector to decode.
+ * \return
+ */
+ virtual void apply_rs_correction(bit_vector& frame_body);
+
+ /**
+ * Returns the expected size (in bits) of this data unit in
+ * bits. For variable-length data this should return UINT16_MAX
+ * until the actual length of this frame is known.
+ *
+ * \return The expected size (in bits) of this data_unit when encoded.
+ */
+ virtual uint16_t frame_size_max() const;
+
+private:
+
+ /**
+ * Does this TDU have a link_control field?
+ */
+ bool d_has_link_control;
+
+};
+
+#endif /* INCLUDED_TDU_H */
diff --git a/blocks/src/lib/tsbk.cc b/blocks/src/lib/tsbk.cc
new file mode 100644
index 0000000..7320ace
--- /dev/null
+++ b/blocks/src/lib/tsbk.cc
@@ -0,0 +1,52 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include <tsbk.h>
+
+using namespace std;
+
+tsbk::tsbk(const_bit_queue& frame_body) :
+ abstract_data_unit(frame_body)
+{
+}
+
+tsbk::~tsbk()
+{
+}
+
+string
+tsbk::duid_str() const
+{
+ return string("TSBK");
+}
+
+uint16_t
+tsbk::frame_size_max() const
+{
+#if 1
+ return 720;
+#else
+ // todo: check this out!
+ return 358;
+#endif
+}
diff --git a/blocks/src/lib/tsbk.h b/blocks/src/lib/tsbk.h
new file mode 100644
index 0000000..08e1001
--- /dev/null
+++ b/blocks/src/lib/tsbk.h
@@ -0,0 +1,66 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_TSBK_H
+#define INCLUDED_TSBK_H
+
+#include <abstract_data_unit.h>
+
+/**
+ * P25 trunking signalling block (TSBK).
+ */
+class tsbk : public abstract_data_unit
+{
+
+public:
+
+ /**
+ * tsbk constructor.
+ *
+ * \param frame_body A const_bit_queue representing the frame body.
+ */
+ tsbk(const_bit_queue& frame_body);
+
+ /**
+ * tsbk virtual destructor.
+ */
+ virtual ~tsbk();
+
+ /**
+ * Returns a string describing the Data Unit ID (DUID).
+ */
+ std::string duid_str() const;
+
+protected:
+
+ /**
+ * Returns the expected size (in bits) of this data unit in
+ * bits.
+ *
+ * \return The expected size (in bits) of this data_unit when encoded.
+ */
+ virtual uint16_t frame_size_max() const;
+
+};
+
+#endif /* INCLUDED_TSBK_H */
diff --git a/blocks/src/lib/value_string.cc b/blocks/src/lib/value_string.cc
new file mode 100644
index 0000000..fdaf7c3
--- /dev/null
+++ b/blocks/src/lib/value_string.cc
@@ -0,0 +1,116 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include <iomanip>
+#include <sstream>
+#include <value_string.h>
+
+using namespace std;
+
+struct value_string {
+ uint16_t value;
+ const char *label;
+};
+
+string
+lookup(uint16_t value, const value_string mappings[], size_t mappings_sz)
+{
+ for(size_t i = 0; i < mappings_sz; ++i) {
+ if(mappings[i].value == value) {
+ return mappings[i].label;
+ }
+ }
+ ostringstream os;
+ os << "Unknown (" << hex << showbase << value << ")";
+ return os.str();
+}
+
+const value_string ALGIDS[] = {
+ /* Type I */
+ { 0x00, "ACCORDION 1.3" },
+ { 0x01, "BATON (Auto Even)" },
+ { 0x02, "FIREFLY Type 1" },
+ { 0x03, "MAYFLY Type 1" },
+ { 0x04, "SAVILLE" },
+ { 0x41, "BATON (Auto Odd)" },
+ /* Type III */
+ { 0x80, "Plain" },
+ { 0x81, "DES-OFB" },
+ { 0x82, "2 key Triple DES" },
+ { 0x83, "3 key Triple DES" },
+ { 0x84, "AES-256" },
+ /* Motorola proprietary */
+ { 0x9F, "Motorola DES-XL" },
+ { 0xA0, "Motorola DVI-XL" },
+ { 0xA1, "Motorola DVP-XL" },
+ { 0xAA, "Motorola ADP" },
+};
+const size_t ALGIDS_SZ = sizeof(ALGIDS) / sizeof(ALGIDS[0]);
+
+
+const value_string MFIDS[] = {
+ { 0x00, "Standard MFID (pre-2001)" },
+ { 0x01, "Standard MFID (post-2001)" },
+ { 0x09, "Aselsan Inc." },
+ { 0x10, "Relm / BK Radio" },
+ { 0x18, "EADS Public Safety Inc." },
+ { 0x20, "Cycomm" },
+ { 0x28, "Efratom Time and Frequency Products, Inc" },
+ { 0x30, "Com-Net Ericsson" },
+ { 0x34, "Etherstack" },
+ { 0x38, "Datron" },
+ { 0x40, "Icom" },
+ { 0x48, "Garmin" },
+ { 0x50, "GTE" },
+ { 0x55, "IFR Systems" },
+ { 0x5A, "INIT Innovations in Transportation, Inc" },
+ { 0x60, "GEC-Marconi" },
+ { 0x64, "Harris Corp." },
+ { 0x68, "Kenwood Communications" },
+ { 0x70, "Glenayre Electronics" },
+ { 0x74, "Japan Radio Co." },
+ { 0x78, "Kokusai" },
+ { 0x7C, "Maxon" },
+ { 0x80, "Midland" },
+ { 0x86, "Daniels Electronics Ltd." },
+ { 0x90, "Motorola" },
+ { 0xA0, "Thales" },
+ { 0xA4, "M/A-COM" },
+ { 0xB0, "Raytheon" },
+ { 0xC0, "SEA" },
+ { 0xC8, "Securicor" },
+ { 0xD0, "ADI" },
+ { 0xD8, "Tait Electronics" },
+ { 0xE0, "Teletec" },
+ { 0xF0, "Transcrypt International" },
+ { 0xF8, "Vertex Standard" },
+ { 0xFC, "Zetron, Inc" },
+};
+const size_t MFIDS_SZ = sizeof(MFIDS) / sizeof(MFIDS[0]);
+
+const value_string NACS[] = {
+ { 0x293, "Default NAC" },
+ { 0xF7E, "Receiver to open on any NAC" },
+ { 0xF7F, "Repeater to receive and retransmit any NAC" },
+};
+const size_t NACS_SZ = sizeof(NACS) / sizeof(NACS[0]);
diff --git a/blocks/src/lib/value_string.h b/blocks/src/lib/value_string.h
new file mode 100644
index 0000000..f8c686e
--- /dev/null
+++ b/blocks/src/lib/value_string.h
@@ -0,0 +1,49 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_VALUE_STRING
+#define INCLUDED_VALUE_STRING
+
+#include <stdint.h>
+#include <string>
+
+/*
+ * Look up a value in a value_string array.
+ *
+ */
+extern std::string lookup(uint16_t value, const class value_string mappings[], size_t mappings_sz);
+
+/*
+ * Look up tables.
+ */
+
+extern const value_string ALGIDS[];
+extern const size_t ALGIDS_SZ;
+
+extern const value_string MFIDS[];
+extern const size_t MFIDS_SZ;
+
+extern const value_string NACS[];
+extern const size_t NACS_SZ;
+
+#endif // INCLUDED_VALUE_STRING
diff --git a/blocks/src/lib/vc55_imbe_decoder.cc b/blocks/src/lib/vc55_imbe_decoder.cc
new file mode 100644
index 0000000..6ba8663
--- /dev/null
+++ b/blocks/src/lib/vc55_imbe_decoder.cc
@@ -0,0 +1,87 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fcntl.h>
+#include <sstream>
+#include <stdexcept>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <vc55_imbe_decoder.h>
+#include <op25_yank.h>
+
+using namespace std;
+
+vc55_imbe_decoder::vc55_imbe_decoder()
+{
+ const char *dev = getenv("IMBE_DEV");
+ const char *default_dev = "/dev/ttyS0";
+ dev = dev ? dev : default_dev;
+ d_fd = open(dev, O_WRONLY | O_NOCTTY);
+ if(-1 != d_fd) {
+ struct termios options;
+ if(-1 != tcgetattr(d_fd, &options)) {
+ cfsetospeed(&options, B115200);
+ options.c_cflag |= (CLOCAL | CREAD | CS8);
+ options.c_cflag &= ~(CSTOPB | PARENB | CRTSCTS | IXON);
+ if(-1 == tcsetattr(d_fd, TCSANOW, &options)) {
+ ostringstream msg;
+ msg << "tcsetattr(fd, TCSANOW, &options): " << strerror(errno) << endl;
+ msg << "func: " << __PRETTY_FUNCTION__ << endl;
+ msg << "file: " << __FILE__ << endl;
+ msg << "line: " << __LINE__ << endl;
+ throw runtime_error(msg.str());
+ }
+ }
+ } else {
+ perror("open(dev, O_WRONLY | O_NOCTTY)"); // a warning, not an error
+ }
+}
+
+vc55_imbe_decoder::~vc55_imbe_decoder()
+{
+ if(-1 != d_fd) {
+ close(d_fd);
+ }
+}
+
+void
+vc55_imbe_decoder::decode(const voice_codeword& cw)
+{
+ if(-1 != d_fd) {
+ uint8_t packet[20];
+ packet[0] = 0x56;
+ packet[1] = 0xf0;
+ extract(cw, 0, 144, &packet[2]);
+ if(-1 == write(d_fd, packet, sizeof(packet))) {
+ perror("write(d_fd, packet, sizeof(packet))");
+ close(d_fd);
+ d_fd = -1;
+ }
+ }
+}
diff --git a/blocks/src/lib/vc55_imbe_decoder.h b/blocks/src/lib/vc55_imbe_decoder.h
new file mode 100644
index 0000000..7d0b38f
--- /dev/null
+++ b/blocks/src/lib/vc55_imbe_decoder.h
@@ -0,0 +1,64 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_VC55_IMBE_DECODER_H
+#define INCLUDED_VC55_IMBE_DECODER_H
+
+#include <imbe_decoder.h>
+
+/**
+ * vc55_imbe_decoder uses the VC55PR vocoder to decode voice. Note
+ * that the VC55 produces audio but this is not fed back to the flow
+ * graph.
+ *
+ */
+class vc55_imbe_decoder : public imbe_decoder {
+public:
+
+ /**
+ * vc55_imbe_decoder default constructor.
+ */
+ vc55_imbe_decoder();
+
+ /**
+ * vc55_imbe_decoder (virtual) destructor.
+ */
+ virtual ~vc55_imbe_decoder();
+
+ /**
+ * Passess the voice_codeword in_out to the VC55PR device.
+ *
+ * \param cw IMBE codewords and parity.
+ */
+ virtual void decode(const voice_codeword& cw);
+
+private:
+
+ /**
+ * File descriptor for the actual terminal device.
+ */
+ int32_t d_fd;
+
+};
+
+#endif /* INCLUDED_VC55_IMBE_DECODER_H */
diff --git a/blocks/src/lib/voice_data_unit.cc b/blocks/src/lib/voice_data_unit.cc
new file mode 100644
index 0000000..adb20ff
--- /dev/null
+++ b/blocks/src/lib/voice_data_unit.cc
@@ -0,0 +1,58 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include <sstream>
+#include <voice_data_unit.h>
+#include <op25_imbe_frame.h>
+
+using namespace std;
+
+voice_data_unit::~voice_data_unit()
+{
+}
+
+voice_data_unit::voice_data_unit(const_bit_queue& frame_body) :
+ abstract_data_unit(frame_body)
+{
+}
+
+void
+voice_data_unit::do_correct_errors(bit_vector& frame_body)
+{
+}
+
+void
+voice_data_unit::do_decode_audio(const_bit_vector& frame_body, imbe_decoder& imbe)
+{
+ voice_codeword cw(voice_codeword_sz);
+ for(size_t i = 0; i < nof_voice_codewords; ++i) {
+ imbe_deinterleave(frame_body, cw, i);
+ imbe.decode(cw);
+ }
+}
+
+uint16_t
+voice_data_unit::frame_size_max() const
+{
+ return 1728;
+}
diff --git a/blocks/src/lib/voice_data_unit.h b/blocks/src/lib/voice_data_unit.h
new file mode 100644
index 0000000..5f2494f
--- /dev/null
+++ b/blocks/src/lib/voice_data_unit.h
@@ -0,0 +1,79 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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_VOICE_DATA_UNIT_H
+#define INCLUDED_VOICE_DATA_UNIT_H
+
+#include <abstract_data_unit.h>
+
+/**
+ * P25 Logical Data Unit 1 (compressed IBME voice).
+ */
+class voice_data_unit : public abstract_data_unit
+{
+public:
+
+ /**
+ * voice_data_unit (virtual) destuctor
+ */
+ virtual ~voice_data_unit();
+
+protected:
+
+ /**
+ * voice_data_unit constuctor
+ *
+ * \param frame_body A const_bit_queue representing the frame body.
+ */
+ voice_data_unit(const_bit_queue& frame_body);
+
+ /**
+ * Applies error correction code to the specified bit_vector. Not
+ * that this function removes the PN sequences from the source
+ * frame.
+ *
+ * \param frame_body The bit vector to decode.
+ * \return
+ */
+ virtual void do_correct_errors(bit_vector& frame_body);
+
+ /**
+ * Decode compressed audio using the supplied imbe_decoder.
+ *
+ * \param frame_body The const_bit_vector to decode.
+ * \param imbe The imbe_decoder to use to generate the audio.
+ */
+ virtual void do_decode_audio(const_bit_vector& frame_body, imbe_decoder& imbe);
+
+ /**
+ * Returns the expected size (in bits) of this data_unit. For
+ * variable-length data this should return UINT16_MAX until the
+ * actual length of this frame is known.
+ *
+ * \return The expected size (in bits) of this data_unit when encoded.
+ */
+ virtual uint16_t frame_size_max() const;
+
+};
+
+#endif /* INCLUDED_VOICE_DATA_UNIT_H */
diff --git a/blocks/src/lib/voice_du_handler.cc b/blocks/src/lib/voice_du_handler.cc
new file mode 100644
index 0000000..816b1b2
--- /dev/null
+++ b/blocks/src/lib/voice_du_handler.cc
@@ -0,0 +1,47 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include <voice_du_handler.h>
+
+#include <cstdio>
+#include <stdint.h>
+
+using namespace std;
+
+voice_du_handler::voice_du_handler(data_unit_handler_sptr next, imbe_decoder_sptr decoder) :
+ data_unit_handler(next),
+ d_decoder(decoder)
+{
+}
+
+
+voice_du_handler::~voice_du_handler()
+{
+}
+
+void
+voice_du_handler::handle(data_unit_sptr du)
+{
+ du->decode_audio(*d_decoder);
+ data_unit_handler::handle(du);
+}
diff --git a/blocks/src/lib/voice_du_handler.h b/blocks/src/lib/voice_du_handler.h
new file mode 100644
index 0000000..f826e50
--- /dev/null
+++ b/blocks/src/lib/voice_du_handler.h
@@ -0,0 +1,69 @@
+/* -*- C++ -*- */
+
+/*
+ * Copyright 2009 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_VOICE_DU_HANDLER_H
+#define INCLUDED_VOICE_DU_HANDLER_H
+
+#include <data_unit_handler.h>
+#include <imbe_decoder.h>
+
+#include <boost/noncopyable.hpp>
+
+/**
+ * voice_data_unit_handler performs IMBE decoding.
+ */
+class voice_du_handler : public data_unit_handler
+{
+
+public:
+
+ /**
+ * voice_du_handler constructor.
+ *
+ * \param next The next data_unit_handler in the chain.
+ * \param decoder An imbe_decoder_sptr to the IMBE decoder to use.
+ */
+ voice_du_handler(data_unit_handler_sptr next, imbe_decoder_sptr decoder);
+
+ /**
+ * voice_du_handler virtual destructor.
+ */
+ virtual ~voice_du_handler();
+
+ /**
+ * Handle a received P25 frame.
+ *
+ * \param next The next data_unit_handler in this chain.
+ */
+ virtual void handle(data_unit_sptr du);
+
+private:
+
+ /**
+ * The IMBE decder to use.
+ */
+ imbe_decoder_sptr d_decoder;
+
+};
+
+#endif /* INCLUDED_VOICE_DU_HANDLER_H */
diff --git a/blocks/src/python/Makefile.am b/blocks/src/python/Makefile.am
new file mode 100644
index 0000000..2ed2678
--- /dev/null
+++ b/blocks/src/python/Makefile.am
@@ -0,0 +1,32 @@
+#
+# Copyright 2004 Free Software Foundation, Inc.
+#
+# 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 $(top_srcdir)/Makefile.common
+
+EXTRA_DIST = run_tests.in
+
+
+TESTS = \
+ run_tests
+
+
+noinst_PYTHON = \
+ qa_op25.py
diff --git a/blocks/src/python/qa_op25.py b/blocks/src/python/qa_op25.py
new file mode 100755
index 0000000..4f347c1
--- /dev/null
+++ b/blocks/src/python/qa_op25.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+#
+# Copyright 2008 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.
+#
+
+from gnuradio import gr, gr_unittest
+import op25
+
+# import os
+#
+# print 'Blocked waiting for GDB attach (pid = %d)' % (os.getpid(),)
+# raw_input("Press Enter to continue...")
+
+class qa_op25(gr_unittest.TestCase):
+
+ def setUp(self):
+ self.tb = gr.top_block()
+
+ def tearDown(self):
+ self.tb = None
+
+ def test_constructor(self):
+ empty_sequence = ()
+ src = gr.vector_source_b(empty_sequence, False)
+ # msgq = gr.msg_queue()
+ p25 = op25.decoder_bf()
+ self.tb.connect(src, p25)
+
+if __name__ == '__main__':
+ gr_unittest.main ()
diff --git a/blocks/src/python/run_tests.in b/blocks/src/python/run_tests.in
new file mode 100644
index 0000000..6e4b83e
--- /dev/null
+++ b/blocks/src/python/run_tests.in
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+# All this strange PYTHONPATH manipulation is required to run our
+# tests using our just built shared library and swig-generated python
+# code prior to installation.
+
+# build tree == src tree unless you're doing a VPATH build.
+# If you don't know what a VPATH build is, you're not doing one. Relax...
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+
+# Where to look in the build tree for our shared library
+libbld=@abs_top_builddir@/src/lib
+# Where to look in the src tree for swig generated python code
+libsrc=@abs_top_srcdir@/src/lib
+# Where to look in the src tree for hand written python code
+py=@abs_top_srcdir@/src/python
+
+# Where to look for installed GNU Radio python modules
+# FIXME this is wrong on a distcheck. We really need to ask gnuradio-core
+# where it put its python files.
+installed_pythondir=@pythondir@
+installed_pyexecdir=@pyexecdir@
+
+PYTHONPATH="$libbld:$libbld/.libs:$libsrc:$py:$installed_pythondir:$installed_pyexecdir:$PYTHONPATH"
+#PYTHONPATH="$libbld:$libbld/.libs:$libsrc:$py:$installed_pythondir:$installed_pyexecdir"
+
+export PYTHONPATH
+
+#
+# This is the simple part...
+# Run everything that matches qa_*.py and return the final result.
+#
+
+ok=yes
+for file in @srcdir@/qa_*.py
+do
+ if ! $file
+ then
+ ok=no
+ fi
+done
+
+if [ $ok = yes ]
+then
+ exit 0
+else
+ exit 1
+fi