diff --git a/grc/gen_bladerf_blocks.py b/grc/gen_bladerf_blocks.py
index e341930d56f0769434531541ee81f692cc369d11..4bcde974714eb57f6eb143a93086163e53413911 100644
--- a/grc/gen_bladerf_blocks.py
+++ b/grc/gen_bladerf_blocks.py
@@ -192,6 +192,9 @@ outputs:
 outputs:
 % endif
 
+- domain: message
+  id: status
+  optional: true
 - domain: message
   id: pmic_out
   optional: true
diff --git a/lib/bladerf/bladerf_sink_c.cc b/lib/bladerf/bladerf_sink_c.cc
index 415d6c82c64f9c8e9d160c4f5c4f727a726e0fd2..97bfdf4e813863cb4cea6e73ba2a5ecda315957d 100644
--- a/lib/bladerf/bladerf_sink_c.cc
+++ b/lib/bladerf/bladerf_sink_c.cc
@@ -44,12 +44,21 @@
 
 using namespace boost::assign;
 
+const pmt::pmt_t CMD_PORT     = pmt::mp("command");
 const pmt::pmt_t CMD_TIME_KEY = pmt::mp("time");
 const pmt::pmt_t CMD_CHAN_KEY = pmt::mp("chan");
 const pmt::pmt_t CMD_GAIN_KEY = pmt::mp("gain");
 const pmt::pmt_t CMD_FREQ_KEY = pmt::mp("freq");
 const pmt::pmt_t CMD_RATE_KEY = pmt::mp("rate");
 const pmt::pmt_t CMD_BW_KEY   = pmt::mp("bandwidth");
+const pmt::pmt_t CMD_TS_KEY   = pmt::mp("read_ts");
+
+const pmt::pmt_t TAG_TX_TIME  = pmt::mp("tx_time");
+
+const pmt::pmt_t PORT_STATUS      = pmt::mp("status");
+const pmt::pmt_t STATUS_TIMEOUT   = pmt::mp("timeout");
+const pmt::pmt_t STATUS_TIME_PAST = pmt::mp("time_past");
+const pmt::pmt_t STATUS_UNDERRUN  = pmt::mp("underrun");
 
 /******************************************************************************
  * Functions
@@ -83,10 +92,13 @@ bladerf_sink_c::bladerf_sink_c(const std::string &args) :
   setup_blade_messaging();
   
   /* add command port */
-  message_port_register_in(pmt::mp("command"));
-  set_msg_handler(pmt::mp("command"),
+  message_port_register_in(CMD_PORT);
+  set_msg_handler(CMD_PORT,
     [this](const pmt::pmt_t& msg){ handle_command(msg); });
 
+  /* add status port */
+  message_port_register_out(PORT_STATUS);
+
   dict_t dict = params_to_dict(args);
 
   /* Perform src/sink agnostic initializations */
@@ -285,6 +297,15 @@ int bladerf_sink_c::work(int noutput_items,
     BLADERF_WARNING("bladerf_sync_tx error: " << bladerf_strerror(status));
     ++_failures;
 
+    if (status == BLADERF_ERR_TIMEOUT) {
+      pmt::pmt_t msg = pmt::cons(STATUS_TIMEOUT, pmt::PMT_T);
+      message_port_pub(PORT_STATUS, msg);
+    } else if (status == BLADERF_ERR_TIME_PAST) {
+      pmt::pmt_t msg = pmt::cons(STATUS_TIME_PAST, pmt::from_uint64(0));
+      message_port_pub(PORT_STATUS, msg);
+      --_failures; // do not count towards consecutive failures
+    }
+
     if (_failures >= MAX_CONSECUTIVE_FAILURES) {
       BLADERF_WARNING("Consecutive error limit hit. Shutting down.");
       return WORK_DONE;
@@ -661,6 +682,10 @@ void bladerf_sink_c::handle_command(const pmt::pmt_t& msg)
       set_bandwidth(bw, chan);
     } else if (key == CMD_TIME_KEY || key == CMD_CHAN_KEY) {
       // skip time and channel keys
+    } else if (key == CMD_TS_KEY) {
+      uint64_t ts = get_timestamp();
+      pmt::pmt_t msg = pmt::cons(TAG_TX_TIME, pmt::from_uint64(ts));
+      message_port_pub(PORT_STATUS, msg);
     } else {
       BLADERF_WARNING("Unknown command (" << key << ")");
     }
diff --git a/lib/bladerf/bladerf_source_c.cc b/lib/bladerf/bladerf_source_c.cc
index c585327cc18342f487a57d388be3965d7dcb1a22..ed08c14b5d4bab1b46eb0bbdcc87e56a37ae5909 100644
--- a/lib/bladerf/bladerf_source_c.cc
+++ b/lib/bladerf/bladerf_source_c.cc
@@ -44,6 +44,7 @@
 
 using namespace boost::assign;
 
+const pmt::pmt_t CMD_PORT     = pmt::mp("command");
 const pmt::pmt_t CMD_TIME_KEY = pmt::mp("time");
 const pmt::pmt_t CMD_CHAN_KEY = pmt::mp("chan");
 const pmt::pmt_t CMD_GAIN_KEY = pmt::mp("gain");
@@ -51,10 +52,16 @@ const pmt::pmt_t CMD_FREQ_KEY = pmt::mp("freq");
 const pmt::pmt_t CMD_RATE_KEY = pmt::mp("rate");
 const pmt::pmt_t CMD_BW_KEY   = pmt::mp("bandwidth");
 const pmt::pmt_t CMD_TAG_KEY  = pmt::mp("tag");
+const pmt::pmt_t CMD_TS_KEY   = pmt::mp("read_ts");
 
-const pmt::pmt_t TAG_RX_TIME  = pmt::mp("rx_time");
-const pmt::pmt_t TAG_RX_RATE  = pmt::mp("rx_rate");
-const pmt::pmt_t TAG_RX_FREQ  = pmt::mp("rx_freq");
+const pmt::pmt_t TAG_RX_TIME = pmt::mp("rx_time");
+const pmt::pmt_t TAG_RX_RATE = pmt::mp("rx_rate");
+const pmt::pmt_t TAG_RX_FREQ = pmt::mp("rx_freq");
+
+const pmt::pmt_t PORT_STATUS      = pmt::mp("status");
+const pmt::pmt_t STATUS_TIMEOUT   = pmt::mp("timeout");
+const pmt::pmt_t STATUS_TIME_PAST = pmt::mp("time_past");
+const pmt::pmt_t STATUS_OVERRUN   = pmt::mp("overrun");
 
 /******************************************************************************
  * Functions
@@ -93,10 +100,13 @@ bladerf_source_c::bladerf_source_c(const std::string &args) :
   setup_blade_messaging();
 
   /* add command port */
-  message_port_register_in(pmt::mp("command"));
-  set_msg_handler(pmt::mp("command"),
+  message_port_register_in(CMD_PORT);
+  set_msg_handler(CMD_PORT,
     [this](const pmt::pmt_t& msg) { handle_command(msg); });
 
+  /* add status port */
+  message_port_register_out(PORT_STATUS);
+
   /* Loopback */
   set_loopback_mode(dict.count("loopback") ? dict["loopback"] : "none");
 
@@ -292,6 +302,17 @@ int bladerf_source_c::work(int noutput_items,
                     % bladerf_strerror(status)));
     ++_failures;
 
+    // status port message
+    if (status == BLADERF_ERR_TIMEOUT) {
+      pmt::pmt_t msg = pmt::cons(STATUS_TIMEOUT, pmt::PMT_T);
+      message_port_pub(PORT_STATUS, msg);
+    } else if (status == BLADERF_ERR_TIME_PAST) {
+      pmt::pmt_t msg = pmt::cons(STATUS_TIME_PAST,
+                                 pmt::from_uint64(meta.timestamp));
+      message_port_pub(PORT_STATUS, msg);
+      --_failures; // do not count towards consecutive failures
+    }
+
     if (_failures >= MAX_CONSECUTIVE_FAILURES) {
       BLADERF_WARNING("Consecutive error limit hit. Shutting down.");
       return WORK_DONE;
@@ -306,6 +327,9 @@ int bladerf_source_c::work(int noutput_items,
   if (meta_ptr != NULL && (meta.status & BLADERF_META_STATUS_OVERRUN)) {
     overrun = true;
     actual_count = meta.actual_count;
+
+    pmt::pmt_t msg = pmt::cons(STATUS_OVERRUN, pmt::PMT_T);
+    message_port_pub(PORT_STATUS, msg);
   }
 
   // convert from int16_t to float
@@ -736,6 +760,10 @@ void bladerf_source_c::handle_command(const pmt::pmt_t& msg)
       _add_tag = true;
     } else if (key == CMD_TIME_KEY || key == CMD_CHAN_KEY) {
       // skip time and channel keys
+    } else if (key == CMD_TS_KEY) {
+      uint64_t ts = get_timestamp();
+      pmt::pmt_t msg = pmt::cons(TAG_RX_TIME, pmt::from_uint64(ts));
+      message_port_pub(PORT_STATUS, msg);
     } else {
       BLADERF_WARNING("Unknown command (" << key << ")");
     }
diff --git a/lib/sink_impl.cc b/lib/sink_impl.cc
index 17e29717bc5eeb90cf0edaab186415d4e93dccce..85d91d218cd36f1200a2d7ad599d5c569abffb91 100644
--- a/lib/sink_impl.cc
+++ b/lib/sink_impl.cc
@@ -29,6 +29,7 @@ namespace gr {
         message_port_register_hier_in(pmt::mp("pmic_in"));
         message_port_register_hier_in(pmt::mp("command"));
         message_port_register_hier_out(pmt::mp("pmic_out"));
+        message_port_register_hier_out(pmt::mp("status"));
 
         auto dev_list = bladerf_sink_c::get_devices();
         if(dev_list.size() == 0)
@@ -44,6 +45,7 @@ namespace gr {
         msg_connect(self(), pmt::mp("pmic_in"), device_, pmt::mp("pmic_in"));
         msg_connect(self(), pmt::mp("command"), device_, pmt::mp("command"));
         msg_connect(device_, pmt::mp("pmic_out"), self(), pmt::mp("pmic_out"));
+        msg_connect(device_, pmt::mp("status"), self(), pmt::mp("status"));
     }
 
     /*
diff --git a/lib/source_impl.cc b/lib/source_impl.cc
index 17cfdab036e37d48e4c3f0352a40a60b91b40408..bdbb4130798e895c7e7b3a8f4a6476fc5f75b903 100644
--- a/lib/source_impl.cc
+++ b/lib/source_impl.cc
@@ -27,6 +27,7 @@ namespace gr {
         message_port_register_hier_in(pmt::mp("pmic_in"));
         message_port_register_hier_in(pmt::mp("command"));
         message_port_register_hier_out(pmt::mp("pmic_out"));
+        message_port_register_hier_out(pmt::mp("status"));
 
         auto dev_list = bladerf_source_c::get_devices();
         if(dev_list.size() == 0)
@@ -55,6 +56,7 @@ namespace gr {
         msg_connect(self(), pmt::mp("pmic_in"), device_, pmt::mp("pmic_in"));
         msg_connect(self(), pmt::mp("command"), device_, pmt::mp("command"));
         msg_connect(device_, pmt::mp("pmic_out"), self(), pmt::mp("pmic_out"));
+        msg_connect(device_, pmt::mp("status"), self(), pmt::mp("status"));
      }
 
     source_impl::~source_impl()