Merge branch 'romankh-development' into development
diff --git a/apps/grgsm_scanner b/apps/grgsm_scanner
index 169a9e5..acd48d9 100755
--- a/apps/grgsm_scanner
+++ b/apps/grgsm_scanner
@@ -38,14 +38,13 @@
 import time
 
 
-#from wideband_receiver import *
+# from wideband_receiver import *
 
 class receiver_with_decoder(grgsm.hier_block):
-
     def __init__(self, OSR=4, chan_num=0, fc=939.4e6, ppm=0, samp_rate=0.2e6):
         grgsm.hier_block.__init__(
             self, "Receiver With Decoder",
-            gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
             gr.io_signature(0, 0, 0),
         )
         self.message_port_register_hier_out("bursts")
@@ -63,7 +62,7 @@
         ##################################################
         # Variables
         ##################################################
-        self.samp_rate_out = samp_rate_out = 1625000.0/6.0*OSR
+        self.samp_rate_out = samp_rate_out = 1625000.0 / 6.0 * OSR
 
         ##################################################
         # Blocks
@@ -88,16 +87,15 @@
         self.msg_connect(self.gsm_control_channels_decoder_0, 'msgs', self, 'msgs')
         self.msg_connect(self.gsm_receiver_0, 'C0', self.gsm_bcch_ccch_demapper_0, 'bursts')
         self.msg_connect(self.gsm_receiver_0, 'measurements', self.gsm_clock_offset_control_0, 'measurements')
-        self.connect((self.gsm_input_0, 0), (self.gsm_receiver_0, 0))    
-        self.connect((self, 0), (self.gsm_input_0, 0))    
-
+        self.connect((self.gsm_input_0, 0), (self.gsm_receiver_0, 0))
+        self.connect((self, 0), (self.gsm_input_0, 0))
 
     def get_OSR(self):
         return self.OSR
 
     def set_OSR(self, OSR):
         self.OSR = OSR
-        self.set_samp_rate_out(1625000.0/6.0*self.OSR)
+        self.set_samp_rate_out(1625000.0 / 6.0 * self.OSR)
         self.gsm_input_0.set_osr(self.OSR)
 
     def get_chan_num(self):
@@ -135,17 +133,16 @@
 
 
 class wideband_receiver(grgsm.hier_block):
-
     def __init__(self, OSR=4, fc=939.4e6, samp_rate=0.4e6):
         grgsm.hier_block.__init__(
             self, "Wideband receiver",
-            gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
             gr.io_signature(0, 0, 0),
         )
         self.message_port_register_hier_out("bursts")
         self.message_port_register_hier_out("msgs")
         self.__init(OSR, fc, samp_rate)
-    
+
     def __init(self, OSR=4, fc=939.4e6, samp_rate=0.4e6):
         ##################################################
         # Parameters
@@ -153,9 +150,9 @@
         self.OSR = OSR
         self.fc = fc
         self.samp_rate = samp_rate
-        self.channels_num = int(samp_rate/0.2e6)
+        self.channels_num = int(samp_rate / 0.2e6)
         self.OSR_PFB = 2
-        
+
         ##################################################
         # Blocks
         ##################################################
@@ -171,15 +168,16 @@
         # Connections
         ##################################################
         self.connect((self, 0), (self.pfb_channelizer_ccf_0, 0))
-        for chan in xrange(0,self.channels_num):
+        for chan in xrange(0, self.channels_num):
             self.connect((self.pfb_channelizer_ccf_0, chan), (self.receivers_with_decoders[chan], 0))
             self.msg_connect(self.receivers_with_decoders[chan], 'bursts', self, 'bursts')
             self.msg_connect(self.receivers_with_decoders[chan], 'msgs', self, 'msgs')
 
     def create_receivers(self):
         self.receivers_with_decoders = {}
-        for chan in xrange(0,self.channels_num):
-            self.receivers_with_decoders[chan] = receiver_with_decoder(fc=self.fc, OSR=self.OSR, chan_num=chan, samp_rate=self.OSR_PFB*0.2e6)
+        for chan in xrange(0, self.channels_num):
+            self.receivers_with_decoders[chan] = receiver_with_decoder(fc=self.fc, OSR=self.OSR, chan_num=chan,
+                                                                       samp_rate=self.OSR_PFB * 0.2e6)
 
     def get_OSR(self):
         return self.OSR
@@ -200,59 +198,54 @@
 
 
 class wideband_scanner(gr.top_block):
-    
     def __init__(self, rec_len=3, sample_rate=2e6, carrier_frequency=939e6, ppm=0, args=""):
-        
         gr.top_block.__init__(self, "Wideband Scanner")
-        
+
         self.rec_len = rec_len
         self.sample_rate = sample_rate
         self.carrier_frequency = carrier_frequency
         self.ppm = ppm
-        
+
         # if no file name is given process data from rtl_sdr source
-        print "Args=",args
-        self.rtlsdr_source = osmosdr.source( args="numchan=" + str(1) + " " + args )
-        
+        print "Args=", args
+        self.rtlsdr_source = osmosdr.source(args="numchan=" + str(1) + " " + args)
+
         self.rtlsdr_source.set_sample_rate(sample_rate)
-        
+
         # capture half of GSM channel lower than channel center (-0.1MHz)
         # this is needed when even number of channels is captured in order to process full captured bandwidth
-        
+
         self.rtlsdr_source.set_center_freq(carrier_frequency - 0.1e6, 0)
-        
+
         # correction of central frequency
-        # if the receiver has large frequency offset 
+        # if the receiver has large frequency offset
         # the value of this variable should be set close to that offset in ppm
         self.rtlsdr_source.set_freq_corr(options.ppm, 0)
-        
+
         self.rtlsdr_source.set_dc_offset_mode(2, 0)
         self.rtlsdr_source.set_iq_balance_mode(0, 0)
         self.rtlsdr_source.set_gain_mode(True, 0)
         self.rtlsdr_source.set_bandwidth(sample_rate, 0)
-    
+
         self.head = blocks.head(gr.sizeof_gr_complex * 1, int(rec_len * sample_rate))
-        
+
         # shift again by -0.1MHz in order to align channel center in 0Hz
-        self.blocks_rotator_cc = blocks.rotator_cc(-2 * pi * 0.1e6 / options.samp_rate) 
-               
+        self.blocks_rotator_cc = blocks.rotator_cc(-2 * pi * 0.1e6 / options.samp_rate)
+
         self.wideband_receiver = wideband_receiver(OSR=4, fc=carrier_frequency, samp_rate=sample_rate)
         self.gsm_extract_system_info = grgsm.extract_system_info()
-        
-        
+
         self.connect((self.rtlsdr_source, 0), (self.head, 0))
         self.connect((self.head, 0), (self.blocks_rotator_cc, 0))
-        self.connect((self.blocks_rotator_cc, 0), (self.wideband_receiver,0))
+        self.connect((self.blocks_rotator_cc, 0), (self.wideband_receiver, 0))
         self.msg_connect(self.wideband_receiver, 'msgs', self.gsm_extract_system_info, 'msgs')
-        
+
     def set_carrier_frequency(self, carrier_frequency):
         self.carrier_frequency = carrier_frequency
         self.rtlsdr_source.set_center_freq(carrier_frequency - 0.1e6, 0)
 
-       
-        
+
 class channel_info(object):
-    
     def __init__(self, arfcn, freq, cid, lac, mcc, mnc, ccch_conf, power, neighbours, cell_arfcns):
         self.arfcn = arfcn
         self.freq = freq
@@ -264,13 +257,13 @@
         self.power = power
         self.neighbours = neighbours
         self.cell_arfcns = cell_arfcns
-                
+
     def get_verbose_info(self):
         i = "  |---- Configuration: %s\n" % self.get_ccch_conf()
         i += "  |---- Cell ARFCNs: " + ", ".join(map(str, self.cell_arfcns)) + "\n"
         i += "  |---- Neighbour Cells: " + ", ".join(map(str, self.neighbours)) + "\n"
         return i
-        
+
     def get_ccch_conf(self):
         if self.ccch_conf == 0:
             return "1 CCCH, not combined"
@@ -284,17 +277,18 @@
             return "4 CCCH, not combined"
         else:
             return "Unknown"
-        
+
     def getKey(self):
         return self.arfcn
-    
+
     def __cmp__(self, other):
         if hasattr(other, 'getKey'):
             return self.getKey().__cmp__(other.getKey())
-        
+
     def __repr__(self):
-        return "ARFCN: %4u, Freq: %6.1fM, CID: %5u, LAC: %5u, MCC: %3u, MNC: %3u, Pwr: %3i" % (self.arfcn, self.freq/1e6, self.cid, self.lac, self.mcc, self.mnc, self.power)
-            
+        return "ARFCN: %4u, Freq: %6.1fM, CID: %5u, LAC: %5u, MCC: %3u, MNC: %3u, Pwr: %3i" % (
+            self.arfcn, self.freq / 1e6, self.cid, self.lac, self.mcc, self.mnc, self.power)
+
 
 if __name__ == '__main__':
     parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
@@ -302,98 +296,104 @@
     parser.add_option("-b", "--band", dest="band", default="P-GSM",
                       help="Specify the GSM band for the frequency.\nAvailable bands are: " + bands_list)
     parser.add_option("-s", "--samp-rate", dest="samp_rate", type="float", default=2e6,
-        help="Set sample rate [default=%default] - allowed values even_number*0.2e6")
+                      help="Set sample rate [default=%default] - allowed values even_number*0.2e6")
     parser.add_option("-p", "--ppm", dest="ppm", type="intx", default=0,
-        help="Set frequency correction in ppm [default=%default]")
+                      help="Set frequency correction in ppm [default=%default]")
     parser.add_option("-g", "--gain", dest="gain", type="eng_float", default=24.0,
-        help="Set gain [default=%default]")
+                      help="Set gain [default=%default]")
     parser.add_option("", "--args", dest="args", type="string", default="",
-        help="Set device arguments [default=%default]")
+                      help="Set device arguments [default=%default]")
     parser.add_option("--speed", dest="speed", type="intx", default=4,
-        help="Scan speed [default=%default]. Value range 0-5.")
-    parser.add_option("-v", "--verbose", action="store_true", 
+                      help="Scan speed [default=%default]. Value range 0-5.")
+    parser.add_option("-v", "--verbose", action="store_true",
                       help="If set, verbose information output is printed: ccch configuration, cell ARFCN's, neighbour ARFCN's")
-    
+
     """
         Dont forget: sudo sysctl kernel.shmmni=32000
     """
-        
+
     (options, args) = parser.parse_args()
-    
+
     if options.band not in grgsm.arfcn.get_bands():
         parser.error("Invalid GSM band\n")
-        
+
     if options.speed < 0 or options.speed > 5:
         parser.error("Invalid scan speed.\n")
-        
+
     if (options.samp_rate / 0.2e6) % 2 != 0:
         parser.error("Invalid sample rate. Sample rate must be an even numer * 0.2e6")
-        
-    channels_num = int(options.samp_rate/0.2e6)
-    
-    first_arfcn = grgsm.arfcn.get_first_arfcn(options.band)
-    last_arfcn = grgsm.arfcn.get_last_arfcn(options.band)
-    last_center_arfcn = last_arfcn - int((channels_num / 2) - 1)
-        
-    current_freq = grgsm.arfcn.arfcn2downlink(first_arfcn + int(channels_num / 2) - 1, options.band)
-    last_freq = grgsm.arfcn.arfcn2downlink(last_center_arfcn, options.band)
-    stop_freq = last_freq + 0.2e6 * channels_num
-    
-    while current_freq < stop_freq:
-        
-        # silence rtl_sdr output:
-        # open 2 fds
-        null_fds = [os.open(os.devnull, os.O_RDWR) for x in xrange(2)]
-        # save the current file descriptors to a tuple
-        save = os.dup(1), os.dup(2)
-        # put /dev/null fds on 1 and 2
-        os.dup2(null_fds[0], 1)
-        os.dup2(null_fds[1], 2)
-        
-        # instantiate scanner and processor
-        scanner = wideband_scanner(rec_len=6-options.speed, 
-                            sample_rate=options.samp_rate, 
-                            carrier_frequency=current_freq, 
-                            ppm=options.ppm, args=options.args)
 
-        # start recording
-        scanner.start()
-        scanner.wait()
-        scanner.stop()
-        
-        # restore file descriptors so we can print the results
-        os.dup2(save[0], 1)
-        os.dup2(save[1], 2)
-        # close the temporary fds
-        os.close(null_fds[0])
-        os.close(null_fds[1])
-        
-        freq_offsets = numpy.fft.ifftshift(numpy.array(range(int(-numpy.floor(channels_num/2)),int(numpy.floor((channels_num+1)/2))))*2e5)
-        detected_c0_channels = scanner.gsm_extract_system_info.get_chans()
-                
-        if detected_c0_channels:
-            chans = numpy.array(scanner.gsm_extract_system_info.get_chans())
-            found_freqs = current_freq + freq_offsets[(chans)]
-            
-            cell_ids = numpy.array(scanner.gsm_extract_system_info.get_cell_id())
-            lacs = numpy.array(scanner.gsm_extract_system_info.get_lac())
-            mccs = numpy.array(scanner.gsm_extract_system_info.get_mcc())
-            mncs = numpy.array(scanner.gsm_extract_system_info.get_mnc())
-            ccch_confs = numpy.array(scanner.gsm_extract_system_info.get_ccch_conf())
-            powers = numpy.array(scanner.gsm_extract_system_info.get_pwrs())
-                        
+    channels_num = int(options.samp_rate / 0.2e6)
+
+    for arfcn_range in grgsm.arfcn.get_arfcn_ranges(options.band):
+        first_arfcn = arfcn_range[0]
+        last_arfcn = arfcn_range[1]
+        last_center_arfcn = last_arfcn - int((channels_num / 2) - 1)
+
+        current_freq = grgsm.arfcn.arfcn2downlink(first_arfcn + int(channels_num / 2) - 1, options.band)
+        last_freq = grgsm.arfcn.arfcn2downlink(last_center_arfcn, options.band)
+        stop_freq = last_freq + 0.2e6 * channels_num
+
+        while current_freq < stop_freq:
+
+            # silence rtl_sdr output:
+            # open 2 fds
+            null_fds = [os.open(os.devnull, os.O_RDWR) for x in xrange(2)]
+            # save the current file descriptors to a tuple
+            save = os.dup(1), os.dup(2)
+            # put /dev/null fds on 1 and 2
+            os.dup2(null_fds[0], 1)
+            os.dup2(null_fds[1], 2)
+
+            # instantiate scanner and processor
+            scanner = wideband_scanner(rec_len=6 - options.speed,
+                                       sample_rate=options.samp_rate,
+                                       carrier_frequency=current_freq,
+                                       ppm=options.ppm, args=options.args)
+
+            # start recording
+            scanner.start()
+            scanner.wait()
+            scanner.stop()
+
+            freq_offsets = numpy.fft.ifftshift(
+                numpy.array(range(int(-numpy.floor(channels_num / 2)), int(numpy.floor((channels_num + 1) / 2)))) * 2e5)
+            detected_c0_channels = scanner.gsm_extract_system_info.get_chans()
+
             found_list = []
-            for i in range(0, len(chans)):
-                cell_arfcn_list = scanner.gsm_extract_system_info.get_cell_arfcns(chans[i])
-                neighbour_list = scanner.gsm_extract_system_info.get_neighbours(chans[i])
 
-                info = channel_info(grgsm.arfcn.downlink2arfcn(found_freqs[i], options.band), found_freqs[i], cell_ids[i], lacs[i], mccs[i], mncs[i], ccch_confs[i], powers[i], neighbour_list, cell_arfcn_list)
-                found_list.append(info)
-                            
+            if detected_c0_channels:
+                chans = numpy.array(scanner.gsm_extract_system_info.get_chans())
+                found_freqs = current_freq + freq_offsets[(chans)]
+
+                cell_ids = numpy.array(scanner.gsm_extract_system_info.get_cell_id())
+                lacs = numpy.array(scanner.gsm_extract_system_info.get_lac())
+                mccs = numpy.array(scanner.gsm_extract_system_info.get_mcc())
+                mncs = numpy.array(scanner.gsm_extract_system_info.get_mnc())
+                ccch_confs = numpy.array(scanner.gsm_extract_system_info.get_ccch_conf())
+                powers = numpy.array(scanner.gsm_extract_system_info.get_pwrs())
+
+                for i in range(0, len(chans)):
+                    cell_arfcn_list = scanner.gsm_extract_system_info.get_cell_arfcns(chans[i])
+                    neighbour_list = scanner.gsm_extract_system_info.get_neighbours(chans[i])
+
+                    info = channel_info(grgsm.arfcn.downlink2arfcn(found_freqs[i], options.band), found_freqs[i],
+                                        cell_ids[i], lacs[i], mccs[i], mncs[i], ccch_confs[i], powers[i],
+                                        neighbour_list, cell_arfcn_list)
+                    found_list.append(info)
+
+            scanner = None
+
+            # restore file descriptors so we can print the results
+            os.dup2(save[0], 1)
+            os.dup2(save[1], 2)
+            # close the temporary fds
+            os.close(null_fds[0])
+            os.close(null_fds[1])
+
             for info in sorted(found_list):
                 print info
                 if options.verbose:
                     print info.get_verbose_info()
-            
-        scanner = None
-        current_freq += channels_num * 0.2e6
+
+            current_freq += channels_num * 0.2e6
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index 59fcdff..dbffa6c 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -51,7 +51,7 @@
 include(GrTest)
 
 set(GR_TEST_TARGET_DEPS gr-gsm)
-set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig)
+set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig:${CMAKE_BINARY_DIR}/python/misc_utils)
 GR_ADD_TEST(qa_decryption ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_decryption.py)
 GR_ADD_TEST(qa_burst_printer ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_burst_printer.py)
 GR_ADD_TEST(qa_message_printer ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_message_printer.py)
@@ -61,7 +61,7 @@
 GR_ADD_TEST(qa_burst_sdcch_subslot_filter ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_burst_sdcch_subslot_filter.py)
 GR_ADD_TEST(qa_burst_fnr_filter ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_burst_fnr_filter.py)
 GR_ADD_TEST(qa_dummy_burst_filter ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_dummy_burst_filter.py)
-#GR_ADD_TEST(qa_arfcn ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_arfcn.py)
+GR_ADD_TEST(qa_arfcn ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_arfcn.py)
 #GR_ADD_TEST(qa_msg_to_tag ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_msg_to_tag.py)
 #GR_ADD_TEST(qa_controlled_fractional_resampler_cc ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_controlled_fractional_resampler_cc.py)
 #GR_ADD_TEST(qa_uplink_downlink_splitter ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_uplink_downlink_splitter.py)
diff --git a/python/misc_utils/arfcn.py b/python/misc_utils/arfcn.py
index e7edfb5..8836501 100644
--- a/python/misc_utils/arfcn.py
+++ b/python/misc_utils/arfcn.py
@@ -23,19 +23,19 @@
 
 import collections
 
-
-# first uplink freq, first arfcn, last arfcn, downlink frequence distance
+# first uplink freq, distance between uplink/downlink frequency, list of range tuple
+# each tuple in a range tuple contains: first arfcn of the range, last arfcn of the range, offset of the range
 # entries are ordered by relevance
 __band_conf = collections.OrderedDict([
-    ('P-GSM', {'first_freq': 890.2e6, 'first_arfcn': 1, 'last_arfcn': 124, 'downlink_dist': 45e6}),
-    ('DCS1800', {'first_freq': 1710.2e6, 'first_arfcn': 512, 'last_arfcn': 885, 'downlink_dist': 95e6}),
-    ('PCS1900', {'first_freq': 1850.2e6, 'first_arfcn': 512, 'last_arfcn': 810, 'downlink_dist': 80e6}),
-    ('E-GSM', {'first_freq': 880.2e6, 'first_arfcn': 975, 'last_arfcn': 1023, 'downlink_dist': 45e6}),           
-    ('R-GSM', {'first_freq': 876.2e6, 'first_arfcn': 955, 'last_arfcn': 1023, 'downlink_dist': 45e6}),
-    ('GSM450',{'first_freq': 450.6e6, 'first_arfcn': 259, 'last_arfcn': 293, 'downlink_dist': 10e6}),
-    ('GSM480', {'first_freq': 479e6, 'first_arfcn': 306, 'last_arfcn': 340, 'downlink_dist': 10e6}),
-    ('GSM850', {'first_freq': 824.2e6, 'first_arfcn': 128, 'last_arfcn': 251, 'downlink_dist': 45e6})
-    ])
+    ('P-GSM', {'f_start': 890.0e6, 'distance': 45e6, 'ranges': [(1, 124, 0)]}),
+    ('DCS1800', {'f_start': 1710.2e6, 'distance': 95e6, 'ranges': [(512, 885, 512)]}),
+    ('PCS1900', {'f_start': 1850.2e6, 'distance': 80e6, 'ranges': [(512, 810, 512)]}),
+    ('E-GSM', {'f_start': 890.0e6, 'distance': 45e6, 'ranges': [(0, 124, 0), (975, 1023, 1024)]}),
+    ('R-GSM', {'f_start': 890.0e6, 'distance': 45e6, 'ranges': [(0, 124, 0), (955, 1023, 1024)]}),
+    ('GSM450', {'f_start': 450.6e6, 'distance': 10e6, 'ranges': [(259, 293, 259)]}),
+    ('GSM480', {'f_start': 479e6, 'distance': 10e6, 'ranges': [(306, 340, 306)]}),
+    ('GSM850', {'f_start': 824.2e6, 'distance': 45e6, 'ranges': [(128, 251, 128)]}),
+])
 
 __chan_spacing = 2e5
 
@@ -44,34 +44,17 @@
     return __band_conf.keys()
 
 
-def get_first_arfcn(band):
-    """
-    Returns the first arfcn (i.e. the one with the lowest number) in the given band.
-    """
-    if band in __band_conf:
-        conf = __band_conf.get(band)
-        return conf['first_arfcn']
-
-
-def get_last_arfcn(band):
-    """
-    Returns the last arfcn (i.e. the one with the highest number) in the given band
-    """
-    if band in __band_conf:
-        conf = __band_conf.get(band)
-        return conf['last_arfcn']
-    
-    
 def is_valid_arfcn(arfcn, band):
     """
     Returns True if arfcn is valid in the given band, else False
     """
     if band in __band_conf:
         conf = __band_conf.get(band)
-        first_arfcn = conf['first_arfcn']
-        last_arfcn = conf['last_arfcn']
-        if first_arfcn <= arfcn <= last_arfcn:
-            return True
+        for arfcn_range in conf['ranges']:
+            arfcn_start = arfcn_range[0]
+            arfcn_end = arfcn_range[1]
+            if arfcn_start <= arfcn <= arfcn_end:
+                return True
     return False
 
 
@@ -79,49 +62,63 @@
     """
     Returns True if the given frequency is a valid uplink frequency in the given band
     """
+    result = None
     if band in __band_conf:
         conf = __band_conf.get(band)
-        first_freq = arfcn2uplink(conf['first_arfcn'], band)
-        last_freq = arfcn2uplink(conf['last_arfcn'], band)
-    if first_freq is None or last_freq is None:
-        return False
-    if first_freq <= freq <= last_freq:
-        return True
-    return False
+        result = False
+        for arfcn_range in conf['ranges']:
+            arfcn_start = arfcn_range[0]
+            arfcn_end = arfcn_range[1]
+            first_freq = arfcn2uplink(arfcn_start, band)
+            last_freq = arfcn2uplink(arfcn_end, band)
+            if first_freq is None or last_freq is None:
+                result = False
+            elif first_freq <= freq <= last_freq:
+                result = True
+    return result
 
 
 def is_valid_downlink(freq, band):
     """
     Returns True if the given frequency is a valid downlink frequency in the given band
     """
+    result = None
     if band in __band_conf:
         conf = __band_conf.get(band)
-        first_freq = arfcn2downlink(conf['first_arfcn'], band)
-        last_freq = arfcn2downlink(conf['last_arfcn'], band)
-    if first_freq is None or last_freq is None:
-        return False
-    if first_freq <= freq <= last_freq:
-        return True
-    return False 
+        result = False
+        for arfcn_range in conf['ranges']:
+            arfcn_start = arfcn_range[0]
+            arfcn_end = arfcn_range[1]
+            first_freq = arfcn2downlink(arfcn_start, band)
+            last_freq = arfcn2downlink(arfcn_end, band)
+            if first_freq is None or last_freq is None:
+                result = False
+            elif first_freq <= freq <= last_freq:
+                result = True
+    return result
 
 
 def arfcn2uplink(arfcn, band):
     if band in __band_conf and is_valid_arfcn(arfcn, band):
-
         conf = __band_conf.get(band)
-        freq_start = conf['first_freq']
-        offset = conf['first_arfcn']
-        # if (band == 'E-GSM' or band == 'R-GSM') and arfcn > 124:
-        #     offset = 1024
-        f = freq_start + (__chan_spacing * (arfcn - offset))
-        return round(f, 1)
+        f_start = conf['f_start']
+        offset = None
+        for arfcn_range in conf['ranges']:
+            arfcn_start = arfcn_range[0]
+            arfcn_end = arfcn_range[1]
+            if arfcn_start <= arfcn <= arfcn_end:
+                offset = arfcn_range[2]
+
+        if offset is not None:
+            f = f_start + (__chan_spacing * (arfcn - offset))
+            return round(f, 1)
     return None
 
 
 def arfcn2downlink(arfcn, band):
     if band in __band_conf and is_valid_arfcn(arfcn, band):
         conf = __band_conf.get(band)
-        distance = conf['downlink_dist']
+        distance = conf['distance']
         return round(arfcn2uplink(arfcn, band) + distance, 1)
     return None
 
@@ -129,16 +126,35 @@
 def uplink2arfcn(freq, band):
     if band in __band_conf and is_valid_uplink(freq, band):
         conf = __band_conf.get(band)
-        freq_start = conf['first_freq']
-        offset = conf['first_arfcn']
-        return int(round(offset + ((freq - freq_start) / __chan_spacing), 0))
+        f_start = conf['f_start']
+        offset = None
+        for arfcn_range in conf['ranges']:
+            arfcn_start = arfcn_range[0]
+            arfcn_end = arfcn_range[1]
+            offset = arfcn_range[2]
+            arfcn = int(round(offset + ((freq - f_start) / __chan_spacing), 0))
+            if arfcn_start <= arfcn <= arfcn_end:
+                return arfcn
     return None
 
 
 def downlink2arfcn(freq, band):
     if band in __band_conf and is_valid_downlink(freq, band):
         conf = __band_conf.get(band)
-        distance = conf['downlink_dist']
+        distance = conf['distance']
         freq_uplink = freq - distance
         return int(round(uplink2arfcn(freq_uplink, band), 0))
     return None
+
+
+def get_arfcn_ranges(band):
+    """
+    Returns a list of arfcn tuples, each with first and last arfcn of the range.
+    """
+    result = []
+    if band in __band_conf:
+        conf = __band_conf.get(band)
+        for arfcn_range in conf['ranges']:
+            arfcn_tuple = (arfcn_range[0], arfcn_range[1])
+            result.append(arfcn_tuple)
+    return result
diff --git a/python/qa_arfcn.py b/python/qa_arfcn.py
index 3e8a5ee..358d436 100755
--- a/python/qa_arfcn.py
+++ b/python/qa_arfcn.py
@@ -28,261 +28,282 @@
 import sys
 
 
-class qa_arfcn (gr_unittest.TestCase):
-   
+class qa_arfcn(gr_unittest.TestCase):
     def test_001_is_valid_arfcn(self):
         self.assertTrue(arfcn.is_valid_arfcn(259, 'GSM450'))
         self.assertTrue(arfcn.is_valid_arfcn(277, 'GSM450'))
         self.assertTrue(arfcn.is_valid_arfcn(293, 'GSM450'))
         self.assertFalse(arfcn.is_valid_arfcn(258, 'GSM450'))
         self.assertFalse(arfcn.is_valid_arfcn(294, 'GSM450'))
-        
+
         self.assertTrue(arfcn.is_valid_arfcn(306, 'GSM480'))
         self.assertTrue(arfcn.is_valid_arfcn(323, 'GSM480'))
         self.assertTrue(arfcn.is_valid_arfcn(340, 'GSM480'))
         self.assertFalse(arfcn.is_valid_arfcn(305, 'GSM480'))
         self.assertFalse(arfcn.is_valid_arfcn(341, 'GSM480'))
-                
+
         self.assertTrue(arfcn.is_valid_arfcn(128, 'GSM850'))
         self.assertTrue(arfcn.is_valid_arfcn(199, 'GSM850'))
         self.assertTrue(arfcn.is_valid_arfcn(251, 'GSM850'))
         self.assertFalse(arfcn.is_valid_arfcn(127, 'GSM480'))
         self.assertFalse(arfcn.is_valid_arfcn(251, 'GSM480'))
-        
+
         self.assertTrue(arfcn.is_valid_arfcn(1, 'P-GSM'))
         self.assertTrue(arfcn.is_valid_arfcn(63, 'P-GSM'))
         self.assertTrue(arfcn.is_valid_arfcn(124, 'P-GSM'))
         self.assertFalse(arfcn.is_valid_arfcn(0, 'P-GSM'))
         self.assertFalse(arfcn.is_valid_arfcn(125, 'P-GSM'))
-        
+
+        self.assertTrue(arfcn.is_valid_arfcn(0, 'E-GSM'))
+        self.assertTrue(arfcn.is_valid_arfcn(1, 'E-GSM'))
+        self.assertTrue(arfcn.is_valid_arfcn(124, 'E-GSM'))
+        self.assertFalse(arfcn.is_valid_arfcn(125, 'E-GSM'))
+
         self.assertTrue(arfcn.is_valid_arfcn(975, 'E-GSM'))
         self.assertTrue(arfcn.is_valid_arfcn(999, 'E-GSM'))
         self.assertTrue(arfcn.is_valid_arfcn(1023, 'E-GSM'))
         self.assertFalse(arfcn.is_valid_arfcn(974, 'E-GSM'))
         self.assertFalse(arfcn.is_valid_arfcn(1024, 'E-GSM'))
-        
+
+        self.assertTrue(arfcn.is_valid_arfcn(0, 'R-GSM'))
+        self.assertTrue(arfcn.is_valid_arfcn(1, 'R-GSM'))
+        self.assertTrue(arfcn.is_valid_arfcn(124, 'R-GSM'))
+        self.assertFalse(arfcn.is_valid_arfcn(125, 'R-GSM'))
+
         self.assertTrue(arfcn.is_valid_arfcn(955, 'R-GSM'))
         self.assertTrue(arfcn.is_valid_arfcn(989, 'R-GSM'))
         self.assertTrue(arfcn.is_valid_arfcn(1023, 'R-GSM'))
         self.assertFalse(arfcn.is_valid_arfcn(954, 'R-GSM'))
         self.assertFalse(arfcn.is_valid_arfcn(1024, 'R-GSM'))
-        
+
         self.assertTrue(arfcn.is_valid_arfcn(512, 'DCS1800'))
         self.assertTrue(arfcn.is_valid_arfcn(732, 'DCS1800'))
         self.assertTrue(arfcn.is_valid_arfcn(885, 'DCS1800'))
         self.assertFalse(arfcn.is_valid_arfcn(511, 'DCS1800'))
         self.assertFalse(arfcn.is_valid_arfcn(886, 'DCS1800'))
-        
+
         self.assertTrue(arfcn.is_valid_arfcn(512, 'PCS1900'))
         self.assertTrue(arfcn.is_valid_arfcn(691, 'PCS1900'))
         self.assertTrue(arfcn.is_valid_arfcn(810, 'PCS1900'))
         self.assertFalse(arfcn.is_valid_arfcn(511, 'PCS1900'))
         self.assertFalse(arfcn.is_valid_arfcn(811, 'PCS1900'))
 
-
     def test_002_is_valid_uplink(self):
         self.assertTrue(arfcn.is_valid_uplink(450.6e6, 'GSM450'))
         self.assertTrue(arfcn.is_valid_uplink(457.4e6, 'GSM450'))
         self.assertFalse(arfcn.is_valid_uplink(450.4e6, 'GSM450'))
         self.assertFalse(arfcn.is_valid_uplink(457.6e6, 'GSM450'))
-        
+
         self.assertTrue(arfcn.is_valid_uplink(479e6, 'GSM480'))
         self.assertTrue(arfcn.is_valid_uplink(485.8e6, 'GSM480'))
         self.assertFalse(arfcn.is_valid_uplink(478.8e6, 'GSM480'))
         self.assertFalse(arfcn.is_valid_uplink(486e6, 'GSM480'))
-                
+
         self.assertTrue(arfcn.is_valid_uplink(824.2e6, 'GSM850'))
         self.assertTrue(arfcn.is_valid_uplink(848.8e6, 'GSM850'))
         self.assertFalse(arfcn.is_valid_uplink(824e6, 'GSM850'))
         self.assertFalse(arfcn.is_valid_uplink(849e6, 'GSM850'))
-        
+
         self.assertTrue(arfcn.is_valid_uplink(890.2e6, 'P-GSM'))
         self.assertTrue(arfcn.is_valid_uplink(914.8e6, 'P-GSM'))
         self.assertFalse(arfcn.is_valid_uplink(890e6, 'P-GSM'))
         self.assertFalse(arfcn.is_valid_uplink(915e6, 'P-GSM'))
-        
+
         self.assertTrue(arfcn.is_valid_uplink(880.2e6, 'E-GSM'))
         self.assertTrue(arfcn.is_valid_uplink(889.8e6, 'E-GSM'))
+        self.assertTrue(arfcn.is_valid_uplink(890.0e6, 'E-GSM'))
+        self.assertTrue(arfcn.is_valid_uplink(914.8e6, 'E-GSM'))
         self.assertFalse(arfcn.is_valid_uplink(880e6, 'E-GSM'))
-        self.assertFalse(arfcn.is_valid_uplink(890e6, 'E-GSM'))
-        
+        self.assertFalse(arfcn.is_valid_uplink(915e6, 'E-GSM'))
+
         self.assertTrue(arfcn.is_valid_uplink(876.2e6, 'R-GSM'))
         self.assertTrue(arfcn.is_valid_uplink(889.8e6, 'R-GSM'))
+        self.assertTrue(arfcn.is_valid_uplink(890.0e6, 'R-GSM'))
+        self.assertTrue(arfcn.is_valid_uplink(914.8e6, 'R-GSM'))
         self.assertFalse(arfcn.is_valid_uplink(876e6, 'R-GSM'))
-        self.assertFalse(arfcn.is_valid_uplink(890e6, 'R-GSM'))
-        
+        self.assertFalse(arfcn.is_valid_uplink(915e6, 'R-GSM'))
+
         self.assertTrue(arfcn.is_valid_uplink(1710.2e6, 'DCS1800'))
         self.assertTrue(arfcn.is_valid_uplink(1784.8e6, 'DCS1800'))
         self.assertFalse(arfcn.is_valid_uplink(1710e6, 'DCS1800'))
         self.assertFalse(arfcn.is_valid_uplink(1785e6, 'DCS1800'))
-        
+
         self.assertTrue(arfcn.is_valid_uplink(1850.2e6, 'PCS1900'))
         self.assertTrue(arfcn.is_valid_uplink(1909.8e6, 'PCS1900'))
         self.assertFalse(arfcn.is_valid_uplink(1850e6, 'PCS1900'))
         self.assertFalse(arfcn.is_valid_uplink(1910e6, 'PCS1900'))
 
-
     def test_003_is_valid_downlink(self):
         self.assertTrue(arfcn.is_valid_downlink(460.6e6, 'GSM450'))
         self.assertTrue(arfcn.is_valid_downlink(467.4e6, 'GSM450'))
         self.assertFalse(arfcn.is_valid_downlink(460.4e6, 'GSM450'))
         self.assertFalse(arfcn.is_valid_downlink(467.6e6, 'GSM450'))
-        
+
         self.assertTrue(arfcn.is_valid_downlink(489e6, 'GSM480'))
         self.assertTrue(arfcn.is_valid_downlink(495.8e6, 'GSM480'))
         self.assertFalse(arfcn.is_valid_downlink(488.8e6, 'GSM480'))
         self.assertFalse(arfcn.is_valid_downlink(496e6, 'GSM480'))
-                
+
         self.assertTrue(arfcn.is_valid_downlink(869.2e6, 'GSM850'))
         self.assertTrue(arfcn.is_valid_downlink(893.8e6, 'GSM850'))
         self.assertFalse(arfcn.is_valid_downlink(869e6, 'GSM850'))
         self.assertFalse(arfcn.is_valid_downlink(894e6, 'GSM850'))
-        
+
         self.assertTrue(arfcn.is_valid_downlink(935.2e6, 'P-GSM'))
         self.assertTrue(arfcn.is_valid_downlink(959.8e6, 'P-GSM'))
         self.assertFalse(arfcn.is_valid_downlink(935e6, 'P-GSM'))
         self.assertFalse(arfcn.is_valid_downlink(960e6, 'P-GSM'))
-        
+
         self.assertTrue(arfcn.is_valid_downlink(925.2e6, 'E-GSM'))
         self.assertTrue(arfcn.is_valid_downlink(934.8e6, 'E-GSM'))
+        self.assertTrue(arfcn.is_valid_downlink(935.0e6, 'E-GSM'))
+        self.assertTrue(arfcn.is_valid_downlink(959.8e6, 'E-GSM'))
         self.assertFalse(arfcn.is_valid_downlink(925e6, 'E-GSM'))
-        self.assertFalse(arfcn.is_valid_downlink(935e6, 'E-GSM'))
-        
+        self.assertFalse(arfcn.is_valid_downlink(960e6, 'E-GSM'))
+
         self.assertTrue(arfcn.is_valid_downlink(921.2e6, 'R-GSM'))
         self.assertTrue(arfcn.is_valid_downlink(934.8e6, 'R-GSM'))
+        self.assertTrue(arfcn.is_valid_downlink(935.0e6, 'R-GSM'))
+        self.assertTrue(arfcn.is_valid_downlink(959.8e6, 'R-GSM'))
         self.assertFalse(arfcn.is_valid_downlink(921e6, 'R-GSM'))
-        self.assertFalse(arfcn.is_valid_downlink(935e6, 'R-GSM'))
-        
+        self.assertFalse(arfcn.is_valid_downlink(960e6, 'R-GSM'))
+
         self.assertTrue(arfcn.is_valid_downlink(1805.2e6, 'DCS1800'))
         self.assertTrue(arfcn.is_valid_downlink(1879.8e6, 'DCS1800'))
         self.assertFalse(arfcn.is_valid_downlink(1805e6, 'DCS1800'))
         self.assertFalse(arfcn.is_valid_downlink(1880e6, 'DCS1800'))
-        
+
         self.assertTrue(arfcn.is_valid_downlink(1930.2e6, 'PCS1900'))
         self.assertTrue(arfcn.is_valid_downlink(1989.8e6, 'PCS1900'))
         self.assertFalse(arfcn.is_valid_downlink(1930e6, 'PCS1900'))
         self.assertFalse(arfcn.is_valid_downlink(1990e6, 'PCS1900'))
-        
+
     def test_004_arfcn2uplink(self):
         self.assertEqual(450.6e6, arfcn.arfcn2uplink(259, 'GSM450'))
         self.assertEqual(457.4e6, arfcn.arfcn2uplink(293, 'GSM450'))
-        
+
         self.assertEqual(479e6, arfcn.arfcn2uplink(306, 'GSM480'))
         self.assertEqual(485.8e6, arfcn.arfcn2uplink(340, 'GSM480'))
-        
+
         self.assertEqual(824.2e6, arfcn.arfcn2uplink(128, 'GSM850'))
         self.assertEqual(848.8e6, arfcn.arfcn2uplink(251, 'GSM850'))
-        
+
         self.assertEqual(890.2e6, arfcn.arfcn2uplink(1, 'P-GSM'))
         self.assertEqual(914.8e6, arfcn.arfcn2uplink(124, 'P-GSM'))
-        
+
+        self.assertEqual(890.0e6, arfcn.arfcn2uplink(0, 'E-GSM'))
+        self.assertEqual(914.8e6, arfcn.arfcn2uplink(124, 'E-GSM'))
         self.assertEqual(880.2e6, arfcn.arfcn2uplink(975, 'E-GSM'))
         self.assertEqual(889.8e6, arfcn.arfcn2uplink(1023, 'E-GSM'))
-        
+
+        self.assertEqual(890.0e6, arfcn.arfcn2uplink(0, 'R-GSM'))
+        self.assertEqual(914.8e6, arfcn.arfcn2uplink(124, 'R-GSM'))
         self.assertEqual(876.2e6, arfcn.arfcn2uplink(955, 'R-GSM'))
         self.assertEqual(889.8e6, arfcn.arfcn2uplink(1023, 'R-GSM'))
-        
+
         self.assertEqual(1710.2e6, arfcn.arfcn2uplink(512, 'DCS1800'))
         self.assertEqual(1784.8e6, arfcn.arfcn2uplink(885, 'DCS1800'))
-        
+
         self.assertEqual(1850.2e6, arfcn.arfcn2uplink(512, 'PCS1900'))
         self.assertEqual(1909.8e6, arfcn.arfcn2uplink(810, 'PCS1900'))
-        
+
     def test_005_arfcn2downlink(self):
         self.assertEqual(460.6e6, arfcn.arfcn2downlink(259, 'GSM450'))
         self.assertEqual(467.4e6, arfcn.arfcn2downlink(293, 'GSM450'))
-        
+
         self.assertEqual(489e6, arfcn.arfcn2downlink(306, 'GSM480'))
         self.assertEqual(495.8e6, arfcn.arfcn2downlink(340, 'GSM480'))
-        
+
         self.assertEqual(869.2e6, arfcn.arfcn2downlink(128, 'GSM850'))
         self.assertEqual(893.8e6, arfcn.arfcn2downlink(251, 'GSM850'))
-        
+
         self.assertEqual(935.2e6, arfcn.arfcn2downlink(1, 'P-GSM'))
         self.assertEqual(959.8e6, arfcn.arfcn2downlink(124, 'P-GSM'))
-        
+
+        self.assertEqual(935.0e6, arfcn.arfcn2downlink(0, 'E-GSM'))
+        self.assertEqual(959.8e6, arfcn.arfcn2downlink(124, 'E-GSM'))
         self.assertEqual(925.2e6, arfcn.arfcn2downlink(975, 'E-GSM'))
         self.assertEqual(934.8e6, arfcn.arfcn2downlink(1023, 'E-GSM'))
-        
+
+        self.assertEqual(935.0e6, arfcn.arfcn2downlink(0, 'R-GSM'))
+        self.assertEqual(959.8e6, arfcn.arfcn2downlink(124, 'R-GSM'))
         self.assertEqual(921.2e6, arfcn.arfcn2downlink(955, 'R-GSM'))
         self.assertEqual(934.8e6, arfcn.arfcn2downlink(1023, 'R-GSM'))
-        
+
         self.assertEqual(1805.2e6, arfcn.arfcn2downlink(512, 'DCS1800'))
         self.assertEqual(1879.8e6, arfcn.arfcn2downlink(885, 'DCS1800'))
-        
+
         self.assertEqual(1930.2e6, arfcn.arfcn2downlink(512, 'PCS1900'))
         self.assertEqual(1989.8e6, arfcn.arfcn2downlink(810, 'PCS1900'))
-        
+
     def test_006_uplink2arfcn(self):
         self.assertEqual(259, arfcn.uplink2arfcn(450.6e6, 'GSM450'))
         self.assertEqual(293, arfcn.uplink2arfcn(457.4e6, 'GSM450'))
-        
+
         self.assertEqual(306, arfcn.uplink2arfcn(479e6, 'GSM480'))
         self.assertEqual(340, arfcn.uplink2arfcn(485.8e6, 'GSM480'))
-        
+
         self.assertEqual(128, arfcn.uplink2arfcn(824.2e6, 'GSM850'))
         self.assertEqual(251, arfcn.uplink2arfcn(848.8e6, 'GSM850'))
-        
+
         self.assertEqual(1, arfcn.uplink2arfcn(890.2e6, 'P-GSM'))
         self.assertEqual(124, arfcn.uplink2arfcn(914.8e6, 'P-GSM'))
-        
+
+        self.assertEqual(0, arfcn.uplink2arfcn(890.0e6, 'E-GSM'))
+        self.assertEqual(124, arfcn.uplink2arfcn(914.8e6, 'E-GSM'))
         self.assertEqual(975, arfcn.uplink2arfcn(880.2e6, 'E-GSM'))
         self.assertEqual(1023, arfcn.uplink2arfcn(889.8e6, 'E-GSM'))
-        
+
+        self.assertEqual(0, arfcn.uplink2arfcn(890.0e6, 'R-GSM'))
+        self.assertEqual(124, arfcn.uplink2arfcn(914.8e6, 'R-GSM'))
         self.assertEqual(955, arfcn.uplink2arfcn(876.2e6, 'R-GSM'))
         self.assertEqual(1023, arfcn.uplink2arfcn(889.8e6, 'R-GSM'))
-        
+
         self.assertEqual(512, arfcn.uplink2arfcn(1710.2e6, 'DCS1800'))
         self.assertEqual(885, arfcn.uplink2arfcn(1784.8e6, 'DCS1800'))
-        
+
         self.assertEqual(512, arfcn.uplink2arfcn(1850.2e6, 'PCS1900'))
         self.assertEqual(810, arfcn.uplink2arfcn(1909.8e6, 'PCS1900'))
-        
+
     def test_007_downlink2arfcn(self):
         self.assertEqual(259, arfcn.downlink2arfcn(460.6e6, 'GSM450'))
         self.assertEqual(293, arfcn.downlink2arfcn(467.4e6, 'GSM450'))
-        
+
         self.assertEqual(306, arfcn.downlink2arfcn(489e6, 'GSM480'))
         self.assertEqual(340, arfcn.downlink2arfcn(495.8e6, 'GSM480'))
-        
+
         self.assertEqual(128, arfcn.downlink2arfcn(869.2e6, 'GSM850'))
         self.assertEqual(251, arfcn.downlink2arfcn(893.8e6, 'GSM850'))
-        
+
         self.assertEqual(1, arfcn.downlink2arfcn(935.2e6, 'P-GSM'))
         self.assertEqual(124, arfcn.downlink2arfcn(959.8e6, 'P-GSM'))
-        
+
+        self.assertEqual(0, arfcn.downlink2arfcn(935.0e6, 'E-GSM'))
+        self.assertEqual(124, arfcn.downlink2arfcn(959.8e6, 'E-GSM'))
         self.assertEqual(975, arfcn.downlink2arfcn(925.2e6, 'E-GSM'))
         self.assertEqual(1023, arfcn.downlink2arfcn(934.8e6, 'E-GSM'))
-        
+
+        self.assertEqual(0, arfcn.downlink2arfcn(935.0e6, 'R-GSM'))
+        self.assertEqual(124, arfcn.downlink2arfcn(959.8e6, 'R-GSM'))
         self.assertEqual(955, arfcn.downlink2arfcn(921.2e6, 'R-GSM'))
         self.assertEqual(1023, arfcn.downlink2arfcn(934.8e6, 'R-GSM'))
-        
+
         self.assertEqual(512, arfcn.downlink2arfcn(1805.2e6, 'DCS1800'))
         self.assertEqual(885, arfcn.downlink2arfcn(1879.8e6, 'DCS1800'))
-        
+
         self.assertEqual(512, arfcn.downlink2arfcn(1930.2e6, 'PCS1900'))
         self.assertEqual(810, arfcn.downlink2arfcn(1989.8e6, 'PCS1900'))
-        
-    def test_008_firstarfcn(self):
-        self.assertEqual(259, arfcn.get_first_arfcn('GSM450'))
-        self.assertEqual(306, arfcn.get_first_arfcn('GSM480'))
-        self.assertEqual(128, arfcn.get_first_arfcn('GSM850'))
-        self.assertEqual(1, arfcn.get_first_arfcn('P-GSM'))
-        self.assertEqual(975, arfcn.get_first_arfcn('E-GSM'))
-        self.assertEqual(955, arfcn.get_first_arfcn('R-GSM'))
-        self.assertEqual(512, arfcn.get_first_arfcn('DCS1800'))
-        self.assertEqual(512, arfcn.get_first_arfcn('PCS1900'))
 
-    def test_009_firstarfcn(self):
-        self.assertEqual(293, arfcn.get_last_arfcn('GSM450'))
-        self.assertEqual(340, arfcn.get_last_arfcn('GSM480'))
-        self.assertEqual(251, arfcn.get_last_arfcn('GSM850'))
-        self.assertEqual(124, arfcn.get_last_arfcn('P-GSM'))
-        self.assertEqual(1023, arfcn.get_last_arfcn('E-GSM'))
-        self.assertEqual(1023, arfcn.get_last_arfcn('R-GSM'))
-        self.assertEqual(885, arfcn.get_last_arfcn('DCS1800'))
-        self.assertEqual(810, arfcn.get_last_arfcn('PCS1900'))        
-        
+    def test_008_get_arfcn_ranges(self):
+        self.assertEqual(1, len(arfcn.get_arfcn_ranges('GSM450')))
+        self.assertEqual(1, len(arfcn.get_arfcn_ranges('GSM480')))
+        self.assertEqual(1, len(arfcn.get_arfcn_ranges('GSM850')))
+        self.assertEqual(1, len(arfcn.get_arfcn_ranges('P-GSM')))
+        self.assertEqual(2, len(arfcn.get_arfcn_ranges('E-GSM')))
+        self.assertEqual(2, len(arfcn.get_arfcn_ranges('R-GSM')))
+        self.assertEqual(1, len(arfcn.get_arfcn_ranges('DCS1800')))
+        self.assertEqual(1, len(arfcn.get_arfcn_ranges('PCS1900')))
+
+
 if __name__ == '__main__':
     gr_unittest.run(qa_arfcn, "qa_arfcn.xml")
-