Implemented option to extract only one Immediate Assignment per request reference in the extractor. Enhancement of issue #84
diff --git a/grc/misc_utils/gsm_extract_immediate_assignment.xml b/grc/misc_utils/gsm_extract_immediate_assignment.xml
index 788ea45..64e90d5 100644
--- a/grc/misc_utils/gsm_extract_immediate_assignment.xml
+++ b/grc/misc_utils/gsm_extract_immediate_assignment.xml
@@ -3,7 +3,7 @@
   <name>Extract immediate assignment</name>
   <key>gsm_extract_immediate_assignment</key>
   <import>import grgsm</import>
-  <make>grgsm.extract_immediate_assignment($print_immediate_assignments, $ignore_gprs)</make>
+  <make>grgsm.extract_immediate_assignment($print_immediate_assignments, $ignore_gprs, $unique_references)</make>
 
   <param>
     <name>Print</name>
@@ -33,6 +33,20 @@
       <key>True</key>
     </option>
   </param>
+  <param>
+    <name>Unique per request ref</name>
+    <key>unique_references</key>
+    <value>False</value>
+    <type>bool</type>
+    <option>
+      <name>False</name>
+      <key>False</key>
+    </option>
+    <option>
+      <name>True</name>
+      <key>True</key>
+    </option>
+  </param>
 
   <sink>
     <name>msgs</name>
diff --git a/include/grgsm/misc_utils/extract_immediate_assignment.h b/include/grgsm/misc_utils/extract_immediate_assignment.h
index 361a9c3..ac8a630 100644
--- a/include/grgsm/misc_utils/extract_immediate_assignment.h
+++ b/include/grgsm/misc_utils/extract_immediate_assignment.h
@@ -48,7 +48,7 @@
        * class. gsm::extract_immediate_assignment::make is the public interface for
        * creating new instances.
        */
-      static sptr make(bool print_immediate_assignments=false, bool ignore_gprs=false);
+      static sptr make(bool print_immediate_assignments=false, bool ignore_gprs=false, bool unique_references=false);
       virtual std::vector<int> get_frame_numbers() = 0;
       virtual std::vector<std::string> get_channel_types() = 0;
       virtual std::vector<int> get_timeslots() = 0;
diff --git a/lib/misc_utils/extract_immediate_assignment_impl.cc b/lib/misc_utils/extract_immediate_assignment_impl.cc
index e3bce37..0ce5fd1 100644
--- a/lib/misc_utils/extract_immediate_assignment_impl.cc
+++ b/lib/misc_utils/extract_immediate_assignment_impl.cc
@@ -131,11 +131,22 @@
                 current.arfcn = arfcn;
             }
 
-            // TODO: add option where request reference is set as ID,
-            // so we get only one immediate assignment per reference
             /*
-                msg_elements[7 - 9], octets 5 - 7 in specs : request reference, maybe later
+                msg_elements[7 - 9], octets 5 - 7 in specs, see 10.5.2.30 request reference, maybe later
+            */
+            uint8_t random_access_info = msg_elements[7];
+            uint8_t rr_t1 = (msg_elements[8] >> 3);
+            uint8_t rr_t2 = (msg_elements[9] & 0x1F);
+            uint8_t rr_t3 = (msg_elements[8] & 0x7) << 3;
+            rr_t3 |= (msg_elements[9] >> 5);
+            uint32_t request_fnr = 51*((rr_t3-rr_t2) % 26) + rr_t3 + (51*26*rr_t1);
 
+            // we will use random_access_info and request_fnr together as request_reference in the map,
+            // if unique_references is set true
+            uint32_t request_ref = (random_access_info << 0x16);
+            request_ref |= request_fnr;
+
+            /*
                 msg_elements[10]:   timing advance
             */
             current.timing_advance = msg_elements[10];
@@ -157,9 +168,24 @@
                 current.mobile_allocation = ma;
             }
 
-            d_assignment_map[current.frame_nr] = current;
+            bool is_duplicate = false;
+            if (d_unique_references)
+            {
+                if (d_assignment_map.find(request_ref) != d_assignment_map.end())
+                {
+                    is_duplicate = true;
+                }
+                else
+                {
+                    d_assignment_map[request_ref] = current;
+                }
+            }
+            else
+            {
+                d_assignment_map[current.frame_nr] = current;
+            }
 
-            if (d_print_immediate_assignments)
+            if (d_print_immediate_assignments && !is_duplicate)
             {
                 std::cout << "\n------------------------------------------------\n" << std::endl;
                 std::cout << "FrameNr: " << (unsigned)current.frame_nr << std::endl;
@@ -287,22 +313,24 @@
     }
 
     extract_immediate_assignment::sptr
-    extract_immediate_assignment::make(bool print_immediate_assignments, bool ignore_gprs)
+    extract_immediate_assignment::make(bool print_immediate_assignments, bool ignore_gprs, bool unique_references)
     {
       return gnuradio::get_initial_sptr
-        (new extract_immediate_assignment_impl(print_immediate_assignments, ignore_gprs));
+        (new extract_immediate_assignment_impl(print_immediate_assignments, ignore_gprs, unique_references));
     }
 
     /*
      * The private constructor
      */
-    extract_immediate_assignment_impl::extract_immediate_assignment_impl(bool print_immediate_assignments, bool ignore_gprs)
+    extract_immediate_assignment_impl::extract_immediate_assignment_impl(bool print_immediate_assignments,
+        bool ignore_gprs, bool unique_references)
       : gr::block("extract_immediate_assignment",
               gr::io_signature::make(0, 0, 0),
               gr::io_signature::make(0, 0, 0))
     {
         d_print_immediate_assignments = print_immediate_assignments;
         d_ignore_gprs = ignore_gprs;
+        d_unique_references = unique_references;
         message_port_register_in(pmt::mp("msgs"));
         set_msg_handler(pmt::mp("msgs"), boost::bind(&extract_immediate_assignment_impl::process_message, this, _1));
     }
diff --git a/lib/misc_utils/extract_immediate_assignment_impl.h b/lib/misc_utils/extract_immediate_assignment_impl.h
index 80e02a5..cf007e2 100644
--- a/lib/misc_utils/extract_immediate_assignment_impl.h
+++ b/lib/misc_utils/extract_immediate_assignment_impl.h
@@ -58,6 +58,7 @@
             immediate_assignment_map d_assignment_map;
             bool d_print_immediate_assignments;
             bool d_ignore_gprs;
+            bool d_unique_references;
         public:
             virtual std::vector<int> get_frame_numbers();
             virtual std::vector<std::string> get_channel_types();
@@ -69,7 +70,8 @@
             virtual std::vector<int> get_arfcns();
             virtual std::vector<int> get_timing_advances();
             virtual std::vector<std::string> get_mobile_allocations();
-            extract_immediate_assignment_impl(bool print_immediate_assignments=false, bool ignore_gprs=false);
+            extract_immediate_assignment_impl(bool print_immediate_assignments=false,
+                bool ignore_gprs=false, bool unique_references=false);
             ~extract_immediate_assignment_impl();
     };
   } // namespace gsm