Merge pull request #128 from romankh/msg-printing-issue-127

airprobe_decode enhancements

diff --git a/apps/airprobe_decode.py b/apps/airprobe_decode.py
index 74f851a..ceb38ef 100755
--- a/apps/airprobe_decode.py
+++ b/apps/airprobe_decode.py
@@ -28,6 +28,7 @@
 from optparse import OptionParser, OptionGroup
 import collections
 import grgsm
+import pmt
 import socket
 
 
@@ -37,7 +38,8 @@
                  burst_file=None,
                  cfile=None, fc=939.4e6, samp_rate=2e6, arfcn=None,
                  a5=1, a5_kc=None,
-                 speech_file=None, speech_codec=None):
+                 speech_file=None, speech_codec=None,
+                 verbose=False):
 
         gr.top_block.__init__(self, "Airprobe Decode")
 
@@ -58,6 +60,7 @@
             self.kc = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
         self.speech_file = speech_file
         self.speech_codec = speech_codec
+        self.verbose = verbose
 
         ##################################################
         # Blocks
@@ -110,6 +113,9 @@
         self.cch_decoder = grgsm.control_channels_decoder()
 
         self.socket_pdu = blocks.socket_pdu("UDP_CLIENT", "127.0.0.1", "4729", 10000, False)
+        if self.verbose:
+            self.message_printer = grgsm.message_printer(pmt.intern(""), True, True, False)
+
 
         ##################################################
         # Asynch Message Connections
@@ -137,6 +143,8 @@
 
             self.msg_connect(self.bcch_demapper, "bursts", self.cch_decoder, "bursts")
             self.msg_connect(self.cch_decoder, "msgs", self.socket_pdu, "pdus")
+            if self.verbose:
+                self.msg_connect(self.cch_decoder, "msgs", self.message_printer, "msgs")
 
         elif self.chan_mode == 'BCCH_SDCCH4':
             if self.subslot_filter is not None:
@@ -148,9 +156,13 @@
                 self.msg_connect(self.bcch_sdcch4_demapper, "bursts", self.decryption, "bursts")
                 self.msg_connect(self.decryption, "bursts", self.cch_decoder_decrypted, "bursts")
                 self.msg_connect(self.cch_decoder_decrypted, "msgs", self.socket_pdu, "pdus")
+                if self.verbose:
+                    self.msg_connect(self.cch_decoder_decrypted, "msgs", self.message_printer, "msgs")
 
             self.msg_connect(self.bcch_sdcch4_demapper, "bursts", self.cch_decoder, "bursts")
             self.msg_connect(self.cch_decoder, "msgs", self.socket_pdu, "pdus")
+            if self.verbose:
+                self.msg_connect(self.cch_decoder, "msgs", self.message_printer, "msgs")
 
         elif self.chan_mode == 'SDCCH8':
             if self.subslot_filter is not None:
@@ -162,9 +174,13 @@
                 self.msg_connect(self.sdcch8_demapper, "bursts", self.decryption, "bursts")
                 self.msg_connect(self.decryption, "bursts", self.cch_decoder_decrypted, "bursts")
                 self.msg_connect(self.cch_decoder_decrypted, "msgs", self.socket_pdu, "pdus")
+                if self.verbose:
+                    self.msg_connect(self.cch_decoder_decrypted, "msgs", self.message_printer, "msgs")
 
             self.msg_connect(self.sdcch8_demapper, "bursts", self.cch_decoder, "bursts")
             self.msg_connect(self.cch_decoder, "msgs", self.socket_pdu, "pdus")
+            if self.verbose:
+                self.msg_connect(self.cch_decoder, "msgs", self.message_printer, "msgs")
 
         elif self.chan_mode == 'TCHF':
             self.msg_connect(self.timeslot_filter, "out", self.tch_f_demapper, "bursts")
@@ -180,6 +196,9 @@
 
             self.msg_connect(self.tch_f_decoder, "msgs", self.socket_pdu, "pdus")
             self.msg_connect(self.cch_decoder, "msgs", self.socket_pdu, "pdus")
+            if self.verbose:
+                self.msg_connect(self.tch_f_decoder, "msgs", self.message_printer, "msgs")
+                self.msg_connect(self.cch_decoder, "msgs", self.message_printer, "msgs")
             
 
 if __name__ == '__main__':
@@ -243,6 +262,8 @@
                       help="Subslot to decode. Use in combination with channel type BCCH_SDCCH4 and SDCCH8")
     parser.add_option("-b", "--burst-file", dest="burst_file", help="Input file (bursts)")
     parser.add_option("-c", "--cfile", dest="cfile", help="Input file (cfile)")
+    parser.add_option("-v", "--verbose", action="store_true",
+                      help="If set, the decoded messages (with frame number and count) are printed to stdout")
 
     # group cfile options together
     cfile_options = OptionGroup(
@@ -302,7 +323,7 @@
     if options.a5 < 0 or options.a5 > 3:
         parser.error("Invalid A5 version\n")
 
-    if (options.fc is None and options.arfcn is None) or (options.fc is not None and options.arfcn is not None):
+    if options.cfile and (options.fc is None and options.arfcn is None) or (options.fc is not None and options.arfcn is not None):
         parser.error("You have to provide either a frequency or an ARFCN (but not both).\n")
 
     # handle frequency / arfcn input
@@ -347,7 +368,8 @@
                           burst_file=options.burst_file,
                           cfile=options.cfile, arfcn=arfcn, fc=fc, samp_rate=options.samp_rate,
                           a5=options.a5, a5_kc=kc,
-                          speech_file=options.speech_output_file, speech_codec=tch_codecs.get(options.speech_codec))
+                          speech_file=options.speech_output_file, speech_codec=tch_codecs.get(options.speech_codec),
+                          verbose=options.verbose)
 
     # run
     tb.start()
diff --git a/grc/misc_utils/gsm_message_printer.xml b/grc/misc_utils/gsm_message_printer.xml
index 7e390ed..0e93f1b 100644
--- a/grc/misc_utils/gsm_message_printer.xml
+++ b/grc/misc_utils/gsm_message_printer.xml
@@ -4,7 +4,8 @@
   <key>gsm_message_printer</key>
   <import>import grgsm</import>
   <import>import pmt</import>
-  <make>grgsm.message_printer(pmt.intern($prepend_string), $print_gsmtap_header)</make>
+  <make>grgsm.message_printer(pmt.intern($prepend_string), $prepend_fnr,
+    $prepend_frame_count, $print_gsmtap_header)</make>
 
   <param>
     <name>Prepend String</name>
@@ -14,6 +15,34 @@
     <hide>part</hide>
   </param>
   <param>
+    <name>Prepend Frame Number</name>
+    <key>prepend_fnr</key>
+    <value>False</value>
+    <type>bool</type>
+    <option>
+      <name>False</name>
+      <key>False</key>
+    </option>
+    <option>
+      <name>True</name>
+      <key>True</key>
+    </option>
+  </param>
+  <param>
+    <name>Prepend Frame Count</name>
+    <key>prepend_frame_count</key>
+    <value>False</value>
+    <type>bool</type>
+    <option>
+      <name>False</name>
+      <key>False</key>
+    </option>
+    <option>
+      <name>True</name>
+      <key>True</key>
+    </option>
+  </param>
+  <param>
     <name>Print GSMTap header</name>
     <key>print_gsmtap_header</key>
     <value>False</value>
diff --git a/include/grgsm/misc_utils/message_printer.h b/include/grgsm/misc_utils/message_printer.h
index d40352f..04aae94 100644
--- a/include/grgsm/misc_utils/message_printer.h
+++ b/include/grgsm/misc_utils/message_printer.h
@@ -48,7 +48,8 @@
        * class. gsm::message_printer::make is the public interface for
        * creating new instances.
        */
-      static sptr make(pmt::pmt_t prepend_string, bool print_gsmtap_header=false);
+      static sptr make(pmt::pmt_t prepend_string, bool prepend_fnr=false,
+        bool prepend_frame_count=false, bool print_gsmtap_header=false);
     };
 
   } // namespace gsm
diff --git a/lib/misc_utils/bursts_printer_impl.cc b/lib/misc_utils/bursts_printer_impl.cc
index fd93d79..ab134aa 100644
--- a/lib/misc_utils/bursts_printer_impl.cc
+++ b/lib/misc_utils/bursts_printer_impl.cc
@@ -31,8 +31,10 @@
 #include <algorithm>
 #include "bursts_printer_impl.h"
 #include <unistd.h>
-
 #include <iostream>
+extern "C" {
+    #include <osmocom/gsm/a5.h>
+}
 
 namespace gr {
   namespace gsm {
@@ -77,12 +79,8 @@
 
         if (d_prepend_frame_count)
         {
-            // calculate frame count for A5
-            uint16_t t1 = frame_nr/1326;
-            uint8_t t2 = frame_nr % 26;
-            uint8_t t3 = frame_nr % 51;
-            uint32_t frame_count = (t1<<11)|(t3<<5)|t2;
-            std::cout << frame_count;
+            // calculate fn count using libosmogsm
+            std::cout << osmo_a5_fn_count(frame_nr);
         }
 
         if (d_prepend_fnr || d_prepend_frame_count)
diff --git a/lib/misc_utils/message_printer_impl.cc b/lib/misc_utils/message_printer_impl.cc
index 2599f65..1da65e9 100644
--- a/lib/misc_utils/message_printer_impl.cc
+++ b/lib/misc_utils/message_printer_impl.cc
@@ -28,6 +28,9 @@
 #include <stdio.h>
 #include "message_printer_impl.h"
 #include "grgsm/gsmtap.h"
+extern "C" {
+    #include <osmocom/gsm/a5.h>
+}
 
 namespace gr {
   namespace gsm {
@@ -37,10 +40,30 @@
         pmt::pmt_t message_plus_header_blob = pmt::cdr(msg);
         uint8_t * message_plus_header = (uint8_t *)pmt::blob_data(message_plus_header_blob);
         size_t message_plus_header_len=pmt::blob_length(message_plus_header_blob);
-        
         gsmtap_hdr * header = (gsmtap_hdr *)message_plus_header;
+        uint32_t frame_nr = be32toh(header->frame_number);
         
         std::cout << d_prepend_string;
+        if (d_prepend_fnr)
+        {
+            std::cout << frame_nr;
+        }
+
+        if (d_prepend_fnr && d_prepend_frame_count)
+        {
+            std::cout << " ";
+        }
+
+        if (d_prepend_frame_count)
+        {
+            // calculate fn count using libosmogsm
+            std::cout << osmo_a5_fn_count(frame_nr);
+        }
+
+        if (d_prepend_fnr || d_prepend_frame_count)
+        {
+            std::cout << ": ";
+        }
         
         int start_index = sizeof(gsmtap_hdr);
         
@@ -57,21 +80,26 @@
     }
 
     message_printer::sptr
-    message_printer::make(pmt::pmt_t prepend_string, bool print_gsmtap_header)
+    message_printer::make(pmt::pmt_t prepend_string, bool prepend_fnr,
+        bool prepend_frame_count, bool print_gsmtap_header)
     {
       return gnuradio::get_initial_sptr
-        (new message_printer_impl(prepend_string, print_gsmtap_header));
+        (new message_printer_impl(prepend_string, prepend_fnr,
+            prepend_frame_count, print_gsmtap_header));
     }
 
     /*
      * The private constructor
      */
-    message_printer_impl::message_printer_impl(pmt::pmt_t prepend_string, bool print_gsmtap_header)
+    message_printer_impl::message_printer_impl(pmt::pmt_t prepend_string, bool prepend_fnr,
+        bool prepend_frame_count, bool print_gsmtap_header)
       : gr::block("message_printer",
               gr::io_signature::make(0, 0, 0),
               gr::io_signature::make(0, 0, 0))
     {
         d_prepend_string = prepend_string;
+        d_prepend_fnr = prepend_fnr;
+        d_prepend_frame_count = prepend_frame_count;
         d_print_gsmtap_header = print_gsmtap_header;
         message_port_register_in(pmt::mp("msgs"));
         set_msg_handler(pmt::mp("msgs"), boost::bind(&message_printer_impl::message_print, this, _1));
diff --git a/lib/misc_utils/message_printer_impl.h b/lib/misc_utils/message_printer_impl.h
index e44288b..86d27d7 100644
--- a/lib/misc_utils/message_printer_impl.h
+++ b/lib/misc_utils/message_printer_impl.h
@@ -33,9 +33,12 @@
      private:
       void message_print(pmt::pmt_t msg);
       pmt::pmt_t d_prepend_string;
+      bool d_prepend_fnr;
+      bool d_prepend_frame_count;
       bool d_print_gsmtap_header;
      public:
-      message_printer_impl(pmt::pmt_t prepend_string, bool print_gsmtap_header=false);
+      message_printer_impl(pmt::pmt_t prepend_string, bool prepend_fnr=false,
+        bool prepend_frame_count=false, bool print_gsmtap_header=false);
       ~message_printer_impl();
     };