Implement transceiver interface

This change introduces a new block 'TRX Interface', which is aimed
to provide an interface for external applications, such as Osmocom
MS side stack implementation - OsmocomBB. Currently one allows to
exchange raw GSM bursts between GR-GSM and other applications.

Moreover, there is a new 'trx.py' application, which implements a
simple follow graph, where all demodulated bursts are being sent
to external application via UDP link provided by 'TRX Interface'.
OsmoTRX (Osmocom's fork of OpenBTS transceiver) like control
interface is used to initialize, configure, start and stop the
application. Messages on this interface are human readable ASCII
strings, which contain a command and some related parameters.
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 680c41f..5d3f461 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -69,6 +69,8 @@
     qa_utils/message_source_impl.cc
     qa_utils/message_sink_impl.cc
     decryption/decryption_impl.cc
+    trx_interface/udp_socket.cc
+    trx_interface/trx_impl.cc
 )
 
 
diff --git a/lib/trx_interface/trx_impl.cc b/lib/trx_interface/trx_impl.cc
new file mode 100644
index 0000000..9b9c484
--- /dev/null
+++ b/lib/trx_interface/trx_impl.cc
@@ -0,0 +1,154 @@
+/* -*- c++ -*- */
+/* @file
+ * @author Vadim Yanitskiy <axilirator@gmail.com>
+ * @section LICENSE
+ * 
+ * Gr-gsm 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.
+ * 
+ * Gr-gsm 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 gr-gsm; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ * 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gnuradio/io_signature.h>
+#include <boost/lexical_cast.hpp>
+
+#include "udp_socket.h"
+#include "trx_impl.h"
+
+namespace gr {
+  namespace grgsm {
+
+    trx::sptr
+    trx::make(
+      const std::string &remote_addr,
+      const std::string &base_port)
+    {
+      int base_port_int = boost::lexical_cast<int> (base_port);
+
+      return gnuradio::get_initial_sptr
+        (new trx_impl(remote_addr, base_port_int));
+    }
+
+    /*
+     * The private constructor
+     */
+    trx_impl::trx_impl(const std::string &remote_addr, int base_port)
+    : gr::block("trx",
+        gr::io_signature::make(0, 0, 0),
+        gr::io_signature::make(0, 0, 0))
+    {
+        message_port_register_in(pmt::mp("bursts"));
+        set_msg_handler(pmt::mp("bursts"),
+          boost::bind(&trx_impl::handle_dl_burst, this, _1));
+
+        // Prepare port numbers
+        std::string clck_src_port = boost::lexical_cast<std::string> (base_port + 0);
+        std::string clck_dst_port = boost::lexical_cast<std::string> (base_port + 100);
+        std::string data_src_port = boost::lexical_cast<std::string> (base_port + 2);
+        std::string data_dst_port = boost::lexical_cast<std::string> (base_port + 102);
+
+        // Init DATA interface
+        d_data_sock = new udp_socket(remote_addr, data_src_port, data_dst_port);
+        d_clck_sock = new udp_socket(remote_addr, clck_src_port, clck_dst_port);
+    }
+
+    /*
+     * Our virtual destructor.
+     */
+    trx_impl::~trx_impl()
+    {
+        // Release all UDP sockets and free memory
+        delete d_data_sock;
+        delete d_clck_sock;
+    }
+
+    /*
+     * Create an UDP payload with clock indication
+     */
+    void
+    trx_impl::clck_ind_send(uint32_t frame_nr)
+    {
+      char buf[20];
+      size_t n;
+
+      n = snprintf(buf, 20, "IND CLOCK %u", frame_nr);
+      d_clck_sock->udp_send((uint8_t *) buf, n + 1);
+    }
+
+    /*
+     * Create an UDP payload with burst bits
+     * and some channel data.
+     */
+    void
+    trx_impl::burst_pack(pmt::pmt_t msg, uint8_t *buf)
+    {
+      pmt::pmt_t header_plus_burst = pmt::cdr(msg);
+
+      // Extract GSMTAP header from message
+      gsmtap_hdr *header = (gsmtap_hdr *)
+        pmt::blob_data(header_plus_burst);
+
+      // Pack timeslot index
+      buf[0] = header->timeslot;
+
+      // Extract frame number
+      uint32_t frame_nr = be32toh(header->frame_number);
+
+      // HACK: send clock indications every 51-th frame
+      if (frame_nr % 51 == 0)
+        clck_ind_send(frame_nr);
+
+      // Pack frame number
+      buf[1] = (frame_nr >> 24) & 0xff;
+      buf[2] = (frame_nr >> 16) & 0xff;
+      buf[3] = (frame_nr >>  8) & 0xff;
+      buf[4] = (frame_nr >>  0) & 0xff;
+
+      // Pack RSSI (-dBm)
+      buf[5] = -(uint8_t) header->signal_dbm;
+
+      // Pack correlator timing offset (TOA)
+      // FIXME: where to find this value?
+      buf[6] = 0;
+      buf[7] = 0;
+
+      // Extract bits {0..1} from message
+      // Despite GR-GSM uses int8_t, they are not real sbits {-127..127}
+      uint8_t *burst = (uint8_t *)
+        (pmt::blob_data(header_plus_burst)) + sizeof(gsmtap_hdr);
+
+      // Convert to transceiver interface specific bits {255..0}
+      for (int i = 0; i < 148; i++)
+        buf[8 + i] = burst[i] ? 255 : 0;
+    }
+
+    void
+    trx_impl::handle_dl_burst(pmt::pmt_t msg)
+    {
+      // 8 bytes of header + 148 bytes of burst
+      uint8_t buf[156];
+
+      // Compose a new UDP payload with burst
+      burst_pack(msg, buf);
+
+      // Send a burst
+      d_data_sock->udp_send(buf, 156);
+    }
+
+  } /* namespace grgsm */
+} /* namespace gr */
diff --git a/lib/trx_interface/trx_impl.h b/lib/trx_interface/trx_impl.h
new file mode 100644
index 0000000..41a4788
--- /dev/null
+++ b/lib/trx_interface/trx_impl.h
@@ -0,0 +1,54 @@
+/* -*- c++ -*- */
+/* @file
+ * @author Vadim Yanitskiy <axilirator@gmail.com>
+ * @section LICENSE
+ * 
+ * Gr-gsm 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.
+ * 
+ * Gr-gsm 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 gr-gsm; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ * 
+ */
+
+#ifndef INCLUDED_GRGSM_TRX_IMPL_H
+#define INCLUDED_GRGSM_TRX_IMPL_H
+
+#include <stddef.h>
+
+#include <grgsm/gsmtap.h>
+#include <grgsm/trx_interface/trx.h>
+
+namespace gr {
+  namespace grgsm {
+
+    class trx_impl : public trx
+    {
+     private:
+      udp_socket *d_data_sock;
+      udp_socket *d_clck_sock;
+
+      void clck_ind_send(uint32_t frame_nr);
+      void burst_pack(pmt::pmt_t msg, uint8_t *buf);
+
+     public:
+      trx_impl(const std::string &remote_addr, int base_port);
+      ~trx_impl();
+
+      void handle_dl_burst(pmt::pmt_t msg);
+    };
+
+  } // namespace grgsm
+} // namespace gr
+
+#endif /* INCLUDED_GRGSM_TRX_IMPL_H */
+
diff --git a/lib/trx_interface/udp_socket.cc b/lib/trx_interface/udp_socket.cc
new file mode 100644
index 0000000..4bbf206
--- /dev/null
+++ b/lib/trx_interface/udp_socket.cc
@@ -0,0 +1,117 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio 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.
+ *
+ * GNU Radio 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gnuradio/thread/thread.h>
+#include <gnuradio/io_signature.h>
+#include <gnuradio/blocks/pdu.h>
+#include <pmt/pmt.h>
+
+#include <boost/lexical_cast.hpp>
+#include "udp_socket.h"
+
+using boost::asio::ip::udp;
+
+namespace gr {
+  namespace grgsm {
+
+    udp_socket::udp_socket(
+      const std::string &remote_addr,
+      const std::string &src_port,
+      const std::string &dst_port)
+    {
+      // Resolve remote host address
+      udp::resolver resolver(d_io_service);
+
+      udp::resolver::query rx_query(
+        udp::v4(), remote_addr, src_port,
+        boost::asio::ip::resolver_query_base::passive);
+      udp::resolver::query tx_query(
+        udp::v4(), remote_addr, dst_port,
+        boost::asio::ip::resolver_query_base::passive);
+
+      d_udp_endpoint_rx = *resolver.resolve(rx_query);
+      d_udp_endpoint_tx = *resolver.resolve(tx_query);
+
+      // Create a socket
+      d_udp_socket.reset(new udp::socket(d_io_service, d_udp_endpoint_rx));
+
+      // Setup read handler
+      d_udp_socket->async_receive_from(
+        boost::asio::buffer(d_rxbuf), d_udp_endpoint_rx,
+        boost::bind(&udp_socket::handle_udp_read, this,
+          boost::asio::placeholders::error,
+          boost::asio::placeholders::bytes_transferred));
+
+      // Start server
+      d_thread = gr::thread::thread(
+        boost::bind(&udp_socket::run_io_service, this));
+    }
+
+    udp_socket::~udp_socket()
+    {
+      // Stop server
+      d_io_service.stop();
+      d_thread.interrupt();
+      d_thread.join();
+    }
+
+    void
+    udp_socket::run_io_service(void)
+    {
+      d_io_service.run();
+    }
+
+    void
+    udp_socket::udp_send(uint8_t *data, size_t len)
+    {
+      d_udp_socket->send_to(
+        boost::asio::buffer(data, len),
+        d_udp_endpoint_tx);
+    }
+
+    void
+    udp_socket::handle_udp_read(
+      const boost::system::error_code& error,
+      size_t bytes_transferred)
+    {
+      if (error)
+        return;
+
+      pmt::pmt_t vector = pmt::init_u8vector(bytes_transferred,
+        (const uint8_t *) &d_rxbuf[0]);
+      pmt::pmt_t pdu = pmt::cons(pmt::PMT_NIL, vector);
+
+      // TODO: call handler here
+
+      d_udp_socket->async_receive_from(
+        boost::asio::buffer(d_rxbuf), d_udp_endpoint_rx,
+        boost::bind(&udp_socket::handle_udp_read, this,
+          boost::asio::placeholders::error,
+          boost::asio::placeholders::bytes_transferred));
+    }
+
+  } /* namespace blocks */
+}/* namespace gr */
diff --git a/lib/trx_interface/udp_socket.h b/lib/trx_interface/udp_socket.h
new file mode 100644
index 0000000..2f424c9
--- /dev/null
+++ b/lib/trx_interface/udp_socket.h
@@ -0,0 +1,65 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio 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.
+ *
+ * GNU Radio 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_GRGSM_TRX_UDP_SOCKET_H
+#define INCLUDED_GRGSM_TRX_UDP_SOCKET_H
+
+#include <gnuradio/thread/thread.h>
+
+#include <boost/array.hpp>
+#include <boost/asio.hpp>
+#include <pmt/pmt.h>
+
+namespace gr {
+  namespace grgsm {
+
+    class udp_socket
+    {
+    private:
+      boost::asio::io_service d_io_service;
+      std::vector<char> d_rxbuf;
+      gr::thread::thread d_thread;
+      bool d_started;
+      bool d_finished;
+
+      boost::asio::ip::udp::endpoint d_udp_endpoint_rx;
+      boost::asio::ip::udp::endpoint d_udp_endpoint_tx;
+      boost::shared_ptr<boost::asio::ip::udp::socket> d_udp_socket;
+
+      void handle_udp_read(const boost::system::error_code& error,
+        size_t bytes_transferred);
+      void run_io_service(void);
+
+    public:
+      udp_socket(
+        const std::string &remote_addr,
+        const std::string &src_port,
+        const std::string &dst_port);
+      ~udp_socket();
+
+      void udp_send(uint8_t *data, size_t len);
+    };
+
+  } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_GRGSM_TRX_UDP_SOCKET_H */