Merge remote-tracking branch 'upstream/master' into ia-collector
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0e92e87..7a88ba6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -58,7 +58,7 @@
     "1.60.0" "1.60" "1.61.0" "1.61" "1.62.0" "1.62" "1.63.0" "1.63" "1.64.0" "1.64"
     "1.65.0" "1.65" "1.66.0" "1.66" "1.67.0" "1.67" "1.68.0" "1.68" "1.69.0" "1.69"
 )
-find_package(Boost "1.35" COMPONENTS filesystem system)
+find_package(Boost "1.35" COMPONENTS filesystem system thread)
 
 if(NOT Boost_FOUND)
     message(FATAL_ERROR "Boost required to compile gr-gsm")
@@ -162,6 +162,6 @@
 ########################################################################
 # Install cmake search helper for this library
 ########################################################################
-install(FILES cmake/Modules/gr-gsmConfig.cmake        
+install(FILES cmake/Modules/gr-gsmConfig.cmake
     DESTINATION lib${LIB_SUFFIX}/cmake/grgsm
 )
diff --git a/README.md b/README.md
index 03200dd..f5612f6 100644
--- a/README.md
+++ b/README.md
@@ -4,9 +4,19 @@
 
 The aim is to provide set of tools for receiving information transmitted by GSM equipment/devices.
 
+Mailing list
+============
+Current gr-gsm project's mailing list address is following:
+
+gr-gsm@googlegroups.com
+
+To join the group with any e-mail addres (google account is not required) use this link:
+
+https://groups.google.com/forum/#!forum/gr-gsm/join
+
 Installation
 ============
-The project is based on *GNU Radio* signal processing framework and takes advantage of its great features like stream tagging and message passing.
+The *gr-gsm* is based on *GNU Radio* signal processing framework and takes advantage of its great features like stream tagging and message passing.
 Presence of *GNU Radio* is therefore a basic requirement for compilation and installation of *gr-gsm*. 
 
 The easiest way to install *gr-gsm* it to use *pybombs* installer (GNU Radio install management system). Installation with this tool was tested on Ubuntu 14.04 and 14.10 (on 14.10 installation will be much faster as compilation of *GNU Radio* is not necessary).
diff --git a/include/grgsm/decryption/decryption.h b/include/grgsm/decryption/decryption.h
index 96d3eca..be0f7cd 100644
--- a/include/grgsm/decryption/decryption.h
+++ b/include/grgsm/decryption/decryption.h
@@ -27,6 +27,7 @@
 
 #include <grgsm/api.h>
 #include <gnuradio/block.h>
+#include <vector>
 
 namespace gr {
   namespace gsm {
diff --git a/include/grgsm/demapping/universal_ctrl_chans_demapper.h b/include/grgsm/demapping/universal_ctrl_chans_demapper.h
index 07264d8..d8114f7 100644
--- a/include/grgsm/demapping/universal_ctrl_chans_demapper.h
+++ b/include/grgsm/demapping/universal_ctrl_chans_demapper.h
@@ -26,6 +26,7 @@
 
 #include <grgsm/api.h>
 #include <gnuradio/block.h>
+#include <vector>
 
 namespace gr {
   namespace gsm {
diff --git a/include/grgsm/misc_utils/extract_system_info.h b/include/grgsm/misc_utils/extract_system_info.h
index c026096..8be10a1 100644
--- a/include/grgsm/misc_utils/extract_system_info.h
+++ b/include/grgsm/misc_utils/extract_system_info.h
@@ -26,6 +26,7 @@
 
 #include <grgsm/api.h>
 #include <gnuradio/block.h>
+#include <vector>
 
 namespace gr {
   namespace gsm {
@@ -49,12 +50,12 @@
        * creating new instances.
        */
       static sptr make();
-      virtual void show() = 0;
       virtual std::vector<int> get_chans() = 0;
       virtual std::vector<int> get_pwrs() = 0;
       virtual std::vector<int> get_lac() = 0;
       virtual std::vector<int> get_cell_id() = 0;
       virtual std::vector<int> get_mnc() = 0;
+      virtual std::vector<int> get_neighbours(int chan_id) = 0;
       virtual void reset() = 0;
     };
 
diff --git a/include/grgsm/receiver/receiver.h b/include/grgsm/receiver/receiver.h
index e5774e9..80124f7 100644
--- a/include/grgsm/receiver/receiver.h
+++ b/include/grgsm/receiver/receiver.h
@@ -28,6 +28,7 @@
 #include <gnuradio/block.h>
 #include <gnuradio/feval.h>
 #include <gnuradio/sync_block.h>
+#include <vector>
 
 namespace gr {
   namespace gsm {
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 7a8cf94..f2d70e3 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -54,19 +54,19 @@
     misc_utils/burst_source_impl.cc
     decryption/decryption_impl.cc )
 
-add_library(gnuradio-gsm SHARED ${grgsm_sources})
-target_link_libraries(gnuradio-gsm ${Boost_LIBRARIES} ${GNURADIO_RUNTIME_LIBRARIES} ${VOLK_LIBRARIES}
+add_library(gnuradio-grgsm SHARED ${grgsm_sources})
+target_link_libraries(gnuradio-grgsm ${Boost_LIBRARIES} ${GNURADIO_RUNTIME_LIBRARIES} ${VOLK_LIBRARIES}
 # libraries required by plotting.h - have troubles to be installed by pybombs
 #    boost_iostreams
 #    boost_system
 #    boost_filesystem
 )
-set_target_properties(gnuradio-gsm PROPERTIES DEFINE_SYMBOL "gnuradio_gsm_EXPORTS")
+set_target_properties(gnuradio-grgsm PROPERTIES DEFINE_SYMBOL "gnuradio_grgsm_EXPORTS")
 
 ########################################################################
 # Install built library files
 ########################################################################
-install(TARGETS gnuradio-gsm
+install(TARGETS gnuradio-grgsm
     LIBRARY DESTINATION lib${LIB_SUFFIX} # .so/.dylib file
     ARCHIVE DESTINATION lib${LIB_SUFFIX} # .lib file
     RUNTIME DESTINATION bin              # .dll file
@@ -92,7 +92,7 @@
 #  ${GNURADIO_RUNTIME_LIBRARIES}
 #  ${Boost_LIBRARIES}
 #  ${CPPUNIT_LIBRARIES}
-#  gnuradio-gsm
+#  gnuradio-grgsm
 #)
 
 #GR_ADD_TEST(test_gsm test-gsm)
diff --git a/lib/decoding/tch_f_decoder_impl.cc b/lib/decoding/tch_f_decoder_impl.cc
index 89b8520..3ec7205 100644
--- a/lib/decoding/tch_f_decoder_impl.cc
+++ b/lib/decoding/tch_f_decoder_impl.cc
@@ -68,6 +68,8 @@
         {
             throw std::runtime_error("TCH/F Decoder: can't open file\n");
         }
+        
+        const unsigned char amr_nb_magic[6] = { 0x23, 0x21, 0x41, 0x4d, 0x52, 0x0a };
 
         if (d_tch_mode != TCH_FS)
         {
diff --git a/lib/decoding/tch_f_decoder_impl.h b/lib/decoding/tch_f_decoder_impl.h
index 4c8a4b9..f6d054b 100644
--- a/lib/decoding/tch_f_decoder_impl.h
+++ b/lib/decoding/tch_f_decoder_impl.h
@@ -73,7 +73,6 @@
                 ViterbiR2O4 mVR204Coder;
                 ViterbiBase *mViterbi;
 
-                const unsigned char amr_nb_magic[6] = { 0x23, 0x21, 0x41, 0x4d, 0x52, 0x0a };
                 unsigned char iBLOCK[2*BLOCKS*iBLOCK_SIZE];
                 unsigned char mAMRFrameHeader;
 
diff --git a/lib/decryption/decryption_impl.h b/lib/decryption/decryption_impl.h
index a39cf4f..aadd861 100644
--- a/lib/decryption/decryption_impl.h
+++ b/lib/decryption/decryption_impl.h
@@ -22,6 +22,7 @@
 #define INCLUDED_GSM_DECRYPTION_IMPL_H
 
 #include <grgsm/decryption/decryption.h>
+#include <vector>
 
 namespace gr {
   namespace gsm {
diff --git a/lib/demapping/universal_ctrl_chans_demapper_impl.cc b/lib/demapping/universal_ctrl_chans_demapper_impl.cc
index c9e461a..8a6bfb5 100644
--- a/lib/demapping/universal_ctrl_chans_demapper_impl.cc
+++ b/lib/demapping/universal_ctrl_chans_demapper_impl.cc
@@ -28,6 +28,7 @@
 #include "universal_ctrl_chans_demapper_impl.h"
 #include <grgsm/endian.h>
 #include <grgsm/gsmtap.h>
+#include <set>
 
 namespace gr {
   namespace gsm {
diff --git a/lib/demapping/universal_ctrl_chans_demapper_impl.h b/lib/demapping/universal_ctrl_chans_demapper_impl.h
index 67e917e..d4e1440 100644
--- a/lib/demapping/universal_ctrl_chans_demapper_impl.h
+++ b/lib/demapping/universal_ctrl_chans_demapper_impl.h
@@ -24,6 +24,7 @@
 #define INCLUDED_GSM_UNIVERSAL_CTRL_CHANS_DEMAPPER_IMPL_H
 
 #include <grgsm/demapping/universal_ctrl_chans_demapper.h>
+#include <vector>
 
 namespace gr {
   namespace gsm {
diff --git a/lib/misc_utils/extract_system_info_impl.cc b/lib/misc_utils/extract_system_info_impl.cc
index 6f65888..0dc43a6 100644
--- a/lib/misc_utils/extract_system_info_impl.cc
+++ b/lib/misc_utils/extract_system_info_impl.cc
@@ -27,10 +27,12 @@
 #include <gnuradio/io_signature.h>
 #include <grgsm/gsmtap.h>
 #include <unistd.h>
-#include <set>
+#include <map>
 #include <iterator>
 #include <algorithm>
 #include <iostream>
+#include <endian.h>
+#include <boost/foreach.hpp>
 
 #include "extract_system_info_impl.h"
 
@@ -43,19 +45,16 @@
         gsmtap_hdr * header = (gsmtap_hdr *)pmt::blob_data(burst_plus_header_blob);
 
         chan_info info;
-        info.id = header->arfcn;
+        info.id = be16toh(header->arfcn);
         info.pwr_db = header->signal_dbm;
-        std::set<chan_info, compare_id>::iterator iter = d_c0_channels.find(info);
 
         boost::mutex::scoped_lock lock(extract_mutex);
-        if(iter != d_c0_channels.end()){
-            info.lac = iter->lac;
-            info.cell_id = iter->cell_id;
-            info.mnc = iter->mnc;
-            d_c0_channels.erase(iter);
-            d_c0_channels.insert(info);
-        } 
-        d_c0_channels.insert(info);
+        
+        if(d_c0_channels.find(info.id) != d_c0_channels.end()){
+            d_c0_channels[info.id].copy_nonzero_elements(info);
+        } else {
+            d_c0_channels[info.id] = info;
+        }
     }
     
     void extract_system_info_impl::process_sysinfo(pmt::pmt_t msg){
@@ -66,131 +65,273 @@
 
         if(msg_elements[2]==0x1b){
             chan_info info;
-            info.id = header->arfcn;             //take arfcn
+            info.id = be16toh(header->arfcn);                            //take arfcn
             info.pwr_db = header->signal_dbm;
             info.cell_id = (msg_elements[3]<<8)+msg_elements[4];         //take cell id
             info.lac = (msg_elements[8]<<8)+msg_elements[9];             //take lac
             info.mnc = (msg_elements[7]>>4);                             //take mnc
-
-            std::set<chan_info, compare_id>::iterator iter = d_c0_channels.find(info);
             boost::mutex::scoped_lock lock(extract_mutex);
-            if(iter != d_c0_channels.end()){
-                d_c0_channels.erase(iter);
+            if(d_c0_channels.find(info.id) != d_c0_channels.end()){
+                d_c0_channels[info.id].copy_nonzero_elements(info);
+            } else {
+                d_c0_channels[info.id] = info;
             }
-            d_c0_channels.insert(info);
         }
         else if(msg_elements[2]==0x1c){
             chan_info info;
-            info.id = header->arfcn;             //take arfcn
+            info.id = be16toh(header->arfcn);                            //take arfcn
             info.pwr_db = header->signal_dbm;
-            info.lac = (msg_elements[6]<<8)+msg_elements[7];       //take lac
-            info.mnc = (msg_elements[5]>>4);                       //take mnc
+            info.lac = (msg_elements[6]<<8)+msg_elements[7];            //take lac
+            info.mnc = (msg_elements[5]>>4);                            //take mnc
 
-            std::set<chan_info, compare_id>::iterator iter = d_c0_channels.find(info);
             boost::mutex::scoped_lock lock(extract_mutex);
-            if(iter != d_c0_channels.end()){
-                d_c0_channels.erase(iter);
-                if(iter->cell_id!=0){
-                    info.cell_id=iter->cell_id;
-                }
+            if(d_c0_channels.find(info.id) != d_c0_channels.end()){
+                d_c0_channels[info.id].copy_nonzero_elements(info);
+            } else {
+                d_c0_channels[info.id] = info;
             }
-            d_c0_channels.insert(info);
+        } else if(msg_elements[2]==0x1a){ //System Information Type 2
+            chan_info info;
+            info.id = be16toh(header->arfcn);                            //take arfcn
+            info.pwr_db = header->signal_dbm;
+            boost::mutex::scoped_lock lock(extract_mutex);
+            //read neighbour cells
+            decode_neighbour_cells(msg_elements, 3, info.id);
+//            unsigned int    byte_nr, arfcn, bit;
+//            arfcn=124;
+//            bit=4;
+//            for (byte_nr = 0; byte_nr <= 15; byte_nr++)            {
+//                while (bit-- != 0)                {
+//                    if (((msg_elements[byte_nr+3] >> bit) & 1) == 1){
+//                        d_c0_channels[info.id].neighbour_cells.insert(arfcn);
+//                    }
+//                    arfcn--;
+//                }
+//                bit=8;
+//            }
+            
+            if(d_c0_channels.find(info.id) != d_c0_channels.end()){
+                d_c0_channels[info.id].copy_nonzero_elements(info);
+            } else {
+                d_c0_channels[info.id] = info;
+            }
         }
     }
     
-    void extract_system_info_impl::show(){
-        std::vector<chan_info> chans(d_c0_channels.begin(), d_c0_channels.end()); 
-        std::vector<chan_info>::iterator iter;
-        //std::sort(chans.begin(), chans.end(), compare_pwr());
-        for(iter=chans.begin(); iter != chans.end(); ++iter){
-            std::cout << static_cast<int>((*iter).id) << "(" << static_cast<int>((*iter).pwr_db) << ") ";
+    void extract_system_info_impl::decode_neighbour_cells(uint8_t * data, unsigned int offset, unsigned int chan_id)
+    {
+        unsigned int  curr_offset, byte, bit, arfcn, format;
+        uint8_t       oct;
+        curr_offset = offset;
+        format = data[curr_offset];
+
+        if ((format & 0xc0) == 0x00)
+        {
+            /* bit map 0 */
+            bit = 4;
+            arfcn = 125;
+            for (byte = 0; byte <= 15; byte++)
+            {
+                oct = data[curr_offset];
+                while (bit-- != 0)
+                {
+                    arfcn--;
+                    if (((oct >> bit) & 1) == 1)
+                    {
+                        d_c0_channels[chan_id].neighbour_cells.insert(arfcn);
+                    }
+                }
+                bit = 8;
+                curr_offset++;
+            }
         }
-        std::cout << std::endl;
+        else if ((format & 0xc8) == 0x80)
+        {
+            /* 1024 range */
+//            dissect_channel_list_n_range(tvb, tree, pinfo, curr_offset, len, 1024);
+        }
+        else if ((format & 0xce) == 0x88)
+        {
+            /* 512 range */
+//            dissect_channel_list_n_range(tvb, tree, pinfo, curr_offset, len, 512);
+        }
+        else if ((format & 0xce) == 0x8a)
+        {
+            /* 256 range */
+//            dissect_channel_list_n_range(tvb, tree, pinfo, curr_offset, len, 256);
+        }
+        else if ((format & 0xce) == 0x8c)
+        {
+            /* 128 range */
+//            dissect_channel_list_n_range(tvb, tree, pinfo, curr_offset, len, 128);
+        }
+        else if ((format & 0xce) == 0x8e)
+        {
+            /* variable bit map */
+            arfcn = ((format & 0x01) << 9) | (data[curr_offset+1] << 1) | ((data[curr_offset+2] & 0x80) >> 7);
+            curr_offset = curr_offset + 2;
+            bit = 7;
+            for(byte = 0; byte <= (15-2); byte++){
+                oct = data[curr_offset];
+                while (bit-- != 0){
+                    arfcn++;
+                    if (((oct >> bit) & 1) == 1){
+                        d_c0_channels[chan_id].neighbour_cells.insert(arfcn);
+                    }
+                }
+                bit = 8;
+                curr_offset++;
+            }
+        }
+
+        return;
     }
     
+//    void extract_system_info_impl::dissect_channel_list_n_range(guint32 offset, guint len, gint range)
+//    {
+//        int        curr_offset = offset, bit_offset, f0, arfcn_orig, w[64], wsize, i;
+//        int        octet, nwi  = 1, jwi=0, imax, iused, arfcn;
+//        uint8_t      list[1024];
+
+//        memset((void*)list,0,sizeof(list));
+
+////        subtree = proto_tree_add_subtree_format(tree,tvb, curr_offset, len,
+////                                                ett_gsm_rr_elem[DE_RR_NEIGH_CELL_DESC], NULL, "Range %d format", range);
+
+//        octet = data[curr_offset];
+//        if (range == 1024) {
+//            f0 = (octet>>2)&1;
+//            if (f0)
+//                list[0] = 1;
+//            arfcn_orig = 0;
+//            wsize = 10;
+//            imax = 16;
+//            bit_offset = curr_offset*8 + 6;
+//        }
+//        else {
+//            bit_offset = curr_offset*8 + 7;
+//            arfcn_orig = (gint) tvb_get_bits(tvb, bit_offset, 10, FALSE);
+////            proto_tree_add_bits_item(subtree, hf_n_range_orig_arfcn, tvb, bit_offset, 10, ENC_BIG_ENDIAN);
+//            bit_offset+=10;
+
+//            list[arfcn_orig] = 1;
+
+//            switch (range) {
+//            case 512:
+//                wsize=9;
+//                imax = 17;
+//                break;
+//            case 256:
+//                wsize=8;
+//                imax = 21;
+//                break;
+//            case 128:
+//                wsize=7;
+//                imax = 28;
+//                break;
+//            default:
+////                DISSECTOR_ASSERT_NOT_REACHED();
+//            }
+//        }
+//        iused = imax;   /* in case the list is actually full */
+
+//        /* extract the variable size w[] elements */
+//        for (i=1; i<=imax; i++) {
+//            w[i] = (gint) tvb_get_bits(tvb, bit_offset, wsize, FALSE);
+////            proto_tree_add_text(subtree, tvb, bit_offset>>3, ((bit_offset+wsize-1)>>3) - (bit_offset>>3) + 1 , "%s %s(%d): %d",
+////                                decode_bits_in_field(bit_offset, wsize, w[i]),
+////                                "W",
+////                                i,
+////                                w[i]);
+//            bit_offset += wsize;
+//            curr_offset = bit_offset>>3;
+
+//            if ((iused == imax) && (w[i] == 0) ) {
+//                iused = i - 1;
+//            }
+//            if ((curr_offset-offset)>len) {
+//                iused = i - 1;
+//                break;
+//            }
+//            if (++jwi == nwi) {       /* check if the number of wi at this wsize has been extracted */
+//                jwi = 0;            /* reset the count of wi at this size */
+//                nwi <<= 1;          /* get twice as many of the next size */
+//                wsize--;            /* make the next size 1 bit smaller */
+//            }
+//        }
+
+//        for (i=1; i<=iused; i++) {
+//            arfcn = (f_k(i, w, range) + arfcn_orig)%1024;
+//            list[arfcn] = 1;
+//        }
+
+////        display_channel_list(list, tvb, tree, offset, curr_offset-offset);
+
+//        return;
+//    }
+    
     std::vector<int> extract_system_info_impl::get_chans()
     {
-        std::vector<chan_info> chans(d_c0_channels.begin(), d_c0_channels.end()); 
-        std::vector<int> chans_ids(chans.size(),-1);
-        //std::sort(chans.begin(), chans.end(), compare_pwr());
-
-        for(int ii; ii < chans.size(); ++ii){
-            chans_ids[ii] = chans[ii].id;
+        std::vector<int> chans_ids;
+        BOOST_FOREACH(chan_info_map::value_type &i, d_c0_channels){
+            chans_ids.push_back(i.second.id);
         }
-        
         return chans_ids;
     }
     
     std::vector<int> extract_system_info_impl::get_lac()
     {
-        std::vector<chan_info> chans(d_c0_channels.begin(), d_c0_channels.end()); 
-        std::vector<int> chans_ids(chans.size(),-1);
-        //std::sort(chans.begin(), chans.end(), compare_pwr());
-
-        for(int ii; ii < chans.size(); ++ii){
-            chans_ids[ii] = chans[ii].lac;
+        std::vector<int> lacs;
+        BOOST_FOREACH(chan_info_map::value_type &i, d_c0_channels){
+            lacs.push_back(i.second.lac);
         }
-        
-        return chans_ids;
+        return lacs;
     }
+    
     std::vector<int> extract_system_info_impl::get_mnc()
     {
-        std::vector<chan_info> chans(d_c0_channels.begin(), d_c0_channels.end()); 
-        std::vector<int> chans_ids(chans.size(),-1);
-        //std::sort(chans.begin(), chans.end(), compare_pwr());
-
-        for(int ii; ii < chans.size(); ++ii){
-            chans_ids[ii] = chans[ii].mnc;
+        std::vector<int> mncs;
+        BOOST_FOREACH(chan_info_map::value_type &i, d_c0_channels){
+            mncs.push_back(i.second.mnc);
         }
-        
-        return chans_ids;
+        return mncs;
     }
+    
     std::vector<int> extract_system_info_impl::get_cell_id()
     {
-        std::vector<chan_info> chans(d_c0_channels.begin(), d_c0_channels.end()); 
-        std::vector<int> chans_ids(chans.size(),-1);
-        //std::sort(chans.begin(), chans.end(), compare_pwr());
-
-        for(int ii; ii < chans.size(); ++ii){
-            chans_ids[ii] = chans[ii].cell_id;
+        std::vector<int> cell_ids;
+        BOOST_FOREACH(chan_info_map::value_type &i, d_c0_channels){
+            cell_ids.push_back(i.second.cell_id);
         }
-        
-        return chans_ids;
+        return cell_ids;
     }
     
     std::vector<int> extract_system_info_impl::get_pwrs()
     {
-        std::vector<chan_info> chans(d_c0_channels.begin(), d_c0_channels.end()); 
-        std::vector<int> pwrs(chans.size(),-1);
-        //std::sort(chans.begin(), chans.end(), compare_pwr());
-
-        for(int ii; ii < chans.size(); ++ii){
-            pwrs[ii] = chans[ii].pwr_db;
+        std::vector<int> pwrs;
+        BOOST_FOREACH(chan_info_map::value_type &i, d_c0_channels){
+            pwrs.push_back(i.second.pwr_db);
         }
-        
         return pwrs;
     }
+    std::vector<int> extract_system_info_impl::get_neighbours(int chan_id)
+    {
+        std::vector<int> neighbour_cells;
+        BOOST_FOREACH(int n, d_c0_channels[chan_id].neighbour_cells){
+            neighbour_cells.push_back(n);
+        }
+        return neighbour_cells;
+    }
     
     void extract_system_info_impl::reset()
     {
-        std::set<chan_info, compare_id>::iterator iter;
-        
-        chan_info info;
-
-        for(iter = d_c0_channels.begin(); iter != d_c0_channels.end(); iter++){
-            info.id = iter->id;
-            info.cell_id = iter->cell_id;    
-            info.lac = iter->lac;            
-            info.mnc = iter->mnc;           
-            info.pwr_db = -111;
-            d_c0_channels.erase(iter);
-            d_c0_channels.insert(info);
-        }
-//        d_c0_channels.clear();
-        
+        d_c0_channels.clear();
         if(!empty_p(pmt::mp("bursts"))){
             delete_head_blocking(pmt::mp("bursts"));
         }
+        if(!empty_p(pmt::mp("msgs"))){
+            delete_head_blocking(pmt::mp("msgs"));
+        }
     }
     
     extract_system_info::sptr
diff --git a/lib/misc_utils/extract_system_info_impl.h b/lib/misc_utils/extract_system_info_impl.h
index 119303d..ea259ad 100644
--- a/lib/misc_utils/extract_system_info_impl.h
+++ b/lib/misc_utils/extract_system_info_impl.h
@@ -24,24 +24,32 @@
 #define INCLUDED_GSM_EXTRACT_SYSTEM_INFO_IMPL_H
 
 #include <grgsm/misc_utils/extract_system_info.h>
-
+#include <set>
+#include <map>
+#include <vector>
 
 namespace gr {
   namespace gsm {
-
     class chan_info {
       public:
         unsigned int id;
         int8_t pwr_db;
         unsigned int arfcn;
-        float freq;
         unsigned int lac;
         unsigned int cell_id;
         unsigned int mnc;
+        std::set<int> neighbour_cells;
         
-        chan_info() :  id(-1), pwr_db(0), arfcn(0), freq(0), lac(0), cell_id(0), mnc(0){}
-        chan_info(const chan_info & info) : id(info.id), pwr_db(info.pwr_db), arfcn(info.arfcn), freq(info.freq), lac(info.lac), cell_id(info.cell_id), mnc(info.mnc){}
+        chan_info() :  id(-1), pwr_db(0), arfcn(0), lac(0), cell_id(0), mnc(0){}
+        chan_info(const chan_info & info) : id(info.id), pwr_db(info.pwr_db), arfcn(info.arfcn), lac(info.lac), cell_id(info.cell_id), mnc(info.mnc){}
         ~chan_info(){}
+        void copy_nonzero_elements(const chan_info & info){
+            pwr_db = info.pwr_db;
+            arfcn = info.arfcn;
+            lac = (info.lac!=0) ? info.lac : lac;
+            cell_id = (info.cell_id!=0) ? info.cell_id : cell_id;
+            mnc = (info.mnc!=0) ? info.mnc : mnc;
+        }
     };
 
 
@@ -58,21 +66,23 @@
         }
     };
 
-
+    typedef std::map<unsigned int, chan_info> chan_info_map;
     class extract_system_info_impl : public extract_system_info
     {
      private:
       void process_bursts(pmt::pmt_t burst);
       void process_sysinfo(pmt::pmt_t msg);
-      std::set<chan_info, compare_id> d_c0_channels;
+      chan_info_map d_c0_channels;
       bool after_reset;
+      void decode_neighbour_cells(uint8_t * data, unsigned int offset, unsigned int chan_id);
+//      void dissect_channel_list_n_range(guint32 offset, guint len, gint range)
      public:
-      virtual void show();
       virtual std::vector<int> get_chans();
       virtual std::vector<int> get_pwrs();
       virtual std::vector<int> get_lac();
       virtual std::vector<int> get_cell_id();
       virtual std::vector<int> get_mnc();
+      virtual std::vector<int> get_neighbours(int chan_id);
       virtual void reset();
       extract_system_info_impl();
       ~extract_system_info_impl();
diff --git a/lib/receiver/cx_channel_hopper_impl.cc b/lib/receiver/cx_channel_hopper_impl.cc
index 3e23910..b67cb15 100644
--- a/lib/receiver/cx_channel_hopper_impl.cc
+++ b/lib/receiver/cx_channel_hopper_impl.cc
@@ -2,22 +2,22 @@
 /* @file
  * @author Piotr Krysik <ptrkrysik@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
@@ -26,6 +26,7 @@
 
 #include <gnuradio/io_signature.h>
 #include <grgsm/gsmtap.h>
+#include <grgsm/endian.h>
 #include "cx_channel_hopper_impl.h"
 
 namespace gr {
@@ -64,7 +65,7 @@
     }
 
     /**
-     * Random number table used for calculating the 
+     * Random number table used for calculating the
      * hopping sequence. Defined in GSM 05.02.
      */
     unsigned char RNTABLE[114] = {
@@ -134,4 +135,3 @@
 
   } /* namespace gsm */
 } /* namespace gr */
-
diff --git a/lib/receiver/cx_channel_hopper_impl.h b/lib/receiver/cx_channel_hopper_impl.h
index 7a52b05..2e630db 100644
--- a/lib/receiver/cx_channel_hopper_impl.h
+++ b/lib/receiver/cx_channel_hopper_impl.h
@@ -24,6 +24,7 @@
 #define INCLUDED_GSM_CX_CHANNEL_HOPPER_IMPL_H
 
 #include <grgsm/receiver/cx_channel_hopper.h>
+#include <vector>
 
 namespace gr {
   namespace gsm {
diff --git a/lib/receiver/receiver_impl.h b/lib/receiver/receiver_impl.h
index f7d7a05..d668e14 100644
--- a/lib/receiver/receiver_impl.h
+++ b/lib/receiver/receiver_impl.h
@@ -27,6 +27,7 @@
 #include <grgsm/gsmtap.h>
 #include <gsm_constants.h>
 #include <receiver_config.h>
+#include <vector>
 
 namespace gr {
   namespace gsm {
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index e3a40cb..4063aea 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -44,7 +44,7 @@
 ########################################################################
 #include(GrTest)
 
-#set(GR_TEST_TARGET_DEPS gnuradio-gsm)
+#set(GR_TEST_TARGET_DEPS gnuradio-grgsm)
 #set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig)
 #GR_ADD_TEST(qa_receiver ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_receiver.py)
 #GR_ADD_TEST(qa_receiver_hier ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_receiver_hier.py)
diff --git a/swig/CMakeLists.txt b/swig/CMakeLists.txt
index 67417dc..7e9e888 100644
--- a/swig/CMakeLists.txt
+++ b/swig/CMakeLists.txt
@@ -35,7 +35,7 @@
     list(APPEND GR_SWIG_INCLUDE_DIRS ${incdir}/gnuradio/swig)
 endforeach(incdir)
 
-set(GR_SWIG_LIBRARIES gnuradio-gsm)
+set(GR_SWIG_LIBRARIES gnuradio-grgsm)
 set(GR_SWIG_DOC_FILE ${CMAKE_CURRENT_BINARY_DIR}/grgsm_swig_doc.i)
 set(GR_SWIG_DOC_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../include)