trx_interface: implement incoming data handler

This change implements a receive path for UL bursts, namely
the OsmoTRX style header conversation to GSMTAP.
diff --git a/grc/trx_interface/gsm_trx.xml b/grc/trx_interface/gsm_trx.xml
index 71c88ef..f73b5fd 100644
--- a/grc/trx_interface/gsm_trx.xml
+++ b/grc/trx_interface/gsm_trx.xml
@@ -24,6 +24,11 @@
     <type>message</type>
   </sink>
 
+  <source>
+    <name>bursts</name>
+    <type>message</type>
+  </source>
+
   <doc>
       OsmoTRX like UDP interface for external applications.
 
diff --git a/lib/trx_interface/trx_impl.cc b/lib/trx_interface/trx_impl.cc
index abcd45e..48ef51a 100644
--- a/lib/trx_interface/trx_impl.cc
+++ b/lib/trx_interface/trx_impl.cc
@@ -30,6 +30,9 @@
 #include "udp_socket.h"
 #include "trx_impl.h"
 
+#define BURST_SIZE     148
+#define DATA_IF_MTU    160
+
 namespace gr {
   namespace grgsm {
 
@@ -53,6 +56,9 @@
         gr::io_signature::make(0, 0, 0))
     {
         message_port_register_in(pmt::mp("bursts"));
+        message_port_register_out(pmt::mp("bursts"));
+
+        // Bind a port handler
         set_msg_handler(pmt::mp("bursts"),
           boost::bind(&trx_impl::handle_dl_burst, this, _1));
 
@@ -62,9 +68,15 @@
         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);
+        // Init DATA & CLCK interfaces
+        d_data_sock = new udp_socket(remote_addr,
+          data_src_port, data_dst_port, DATA_IF_MTU);
+        d_clck_sock = new udp_socket(remote_addr,
+          clck_src_port, clck_dst_port, DATA_IF_MTU);
+
+        // Bind DATA interface handler
+        d_data_sock->udp_rx_handler = boost::bind(
+          &trx_impl::handle_ul_burst, this, _1, _2);
     }
 
     /*
@@ -156,5 +168,56 @@
       d_data_sock->udp_send(buf, 158);
     }
 
+    void
+    trx_impl::handle_ul_burst(uint8_t *payload, size_t len)
+    {
+      // Check length according to the protocol
+      if (len != 154)
+        return;
+
+      /* Make sure TS index is correct */
+      if (payload[0] >= 8)
+        return;
+
+      /* Unpack and check frame number */
+      uint32_t fn = (payload[1] << 24)
+        | (payload[2] << 16)
+        | (payload[3] << 8)
+        | payload[4];
+
+      if (fn >= 2715648)
+        return;
+
+      // Prepare a buffer for GSMTAP header and burst
+      uint8_t buf[sizeof(gsmtap_hdr) + BURST_SIZE];
+
+      // Set up pointer to GSMTAP header structure
+      struct gsmtap_hdr *header = (struct gsmtap_hdr *) buf;
+      memset(header, 0x00, sizeof(struct gsmtap_hdr));
+
+      // Fill in basic info
+      header->version = GSMTAP_VERSION;
+      header->hdr_len = sizeof(gsmtap_hdr) / 4;
+      header->type = GSMTAP_TYPE_UM_BURST;
+
+      // Set timeslot index and frame number
+      header->timeslot = payload[0];
+      header->frame_number = htobe32(fn);
+
+      // HACK: use GSMTAP_BURST_NORMAL for now
+      // FIXME: We will need to distinguish between RACN and NORMAL
+      header->sub_type = GSMTAP_BURST_NORMAL;
+
+      // Copy burst bits (0 & 1) for source message
+      memcpy(buf + sizeof(gsmtap_hdr), payload + 6, BURST_SIZE);
+
+      // Create a pmt blob
+      pmt::pmt_t blob = pmt::make_blob(buf, sizeof(gsmtap_hdr) + BURST_SIZE);
+      pmt::pmt_t msg = pmt::cons(pmt::PMT_NIL, blob);
+
+      /* Send a message to the output */
+      message_port_pub(pmt::mp("bursts"), msg);
+    }
+
   } /* namespace grgsm */
 } /* namespace gr */
diff --git a/lib/trx_interface/trx_impl.h b/lib/trx_interface/trx_impl.h
index 41a4788..29545b1 100644
--- a/lib/trx_interface/trx_impl.h
+++ b/lib/trx_interface/trx_impl.h
@@ -45,6 +45,7 @@
       ~trx_impl();
 
       void handle_dl_burst(pmt::pmt_t msg);
+      void handle_ul_burst(uint8_t *payload, size_t len);
     };
 
   } // namespace grgsm
diff --git a/lib/trx_interface/udp_socket.cc b/lib/trx_interface/udp_socket.cc
index 4bbf206..be4bb66 100644
--- a/lib/trx_interface/udp_socket.cc
+++ b/lib/trx_interface/udp_socket.cc
@@ -40,8 +40,12 @@
     udp_socket::udp_socket(
       const std::string &remote_addr,
       const std::string &src_port,
-      const std::string &dst_port)
+      const std::string &dst_port,
+      size_t mtu)
     {
+      // Resize receive buffer according to MTU value
+      d_rxbuf.resize(mtu);
+
       // Resolve remote host address
       udp::resolver resolver(d_io_service);
 
@@ -100,11 +104,9 @@
       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
+      // Call incoming data handler
+      if (udp_rx_handler != NULL)
+        udp_rx_handler((uint8_t *) &d_rxbuf[0], bytes_transferred);
 
       d_udp_socket->async_receive_from(
         boost::asio::buffer(d_rxbuf), d_udp_endpoint_rx,
diff --git a/lib/trx_interface/udp_socket.h b/lib/trx_interface/udp_socket.h
index 2f424c9..5bcc42b 100644
--- a/lib/trx_interface/udp_socket.h
+++ b/lib/trx_interface/udp_socket.h
@@ -25,8 +25,10 @@
 
 #include <gnuradio/thread/thread.h>
 
+#include <boost/function.hpp>
 #include <boost/array.hpp>
 #include <boost/asio.hpp>
+#include <boost/bind.hpp>
 #include <pmt/pmt.h>
 
 namespace gr {
@@ -53,10 +55,12 @@
       udp_socket(
         const std::string &remote_addr,
         const std::string &src_port,
-        const std::string &dst_port);
+        const std::string &dst_port,
+        size_t mtu);
       ~udp_socket();
 
       void udp_send(uint8_t *data, size_t len);
+      boost::function<void (uint8_t *, size_t)> udp_rx_handler;
     };
 
   } /* namespace blocks */