root/vtcross/branches/sriram/benchmark_txrxnode1.py @ 327

Revision 327, 18.9 KB (checked in by sriram, 15 years ago)

Have added the spectrum sense part to code

  • Property svn:executable set to *
Line 
1#!/usr/bin/env python
2#Transmission and reception, one ata a time on the same antena
3
4from gnuradio import gr, gru, modulation_utils
5from gnuradio import eng_notation
6##########spectrum sense specific imports
7from gnuradio import optfir, window
8from gnuradio import usrp
9from gnuradio.eng_option import eng_option
10from usrpm import usrp_dbid
11##########
12from gnuradio.eng_option import eng_option
13from optparse import OptionParser
14from numpy import random
15import random, time, struct, sys, math
16
17# from current dir
18from transmit_path import transmit_path
19from receive_path import receive_path
20
21global sync_status
22sync_status = False #default value is "False"...
23global mode
24#Defining modes of operation
25#sync = synchronizing with other node before data transfer
26#traffic = data transfer
27#spec_sense = sensing spectrum for primary user
28mode = "sync" #default mode of operation...
29class my_top_block(gr.top_block):
30
31    def __init__(self, mod_class, demod_class,
32                 rx_callback, options_tx,options_rx):
33
34        gr.top_block.__init__(self)
35        self.rxpath = receive_path(demod_class, rx_callback, options_rx)
36        self.txpath = transmit_path(mod_class, options_tx)
37        self.connect(self.txpath);
38        self.connect(self.rxpath);
39
40
41##################### Spectrum sense specific classes###########################################################
42class tune(gr.feval_dd):
43    """
44    This class allows C++ code to callback into python.
45    """
46    def __init__(self, tb):
47        gr.feval_dd.__init__(self)
48        self.tb = tb
49
50    def eval(self, ignore):
51        """
52        This method is called from gr.bin_statistics_f when it wants to change
53        the center frequency.  This method tunes the front end to the new center
54        frequency, and returns the new frequency as its result.
55        """
56        try:
57            # We use this try block so that if something goes wrong from here
58            # down, at least we'll have a prayer of knowing what went wrong.
59            # Without this, you get a very mysterious:
60            #
61            #   terminate called after throwing an instance of 'Swig::DirectorMethodException'
62            #   Aborted
63            #
64            # message on stderr.  Not exactly helpful ;)
65
66            new_freq = self.tb.set_next_freq()
67            return new_freq
68
69        except Exception, e:
70            print "tune: Exception: ", e
71
72
73class parse_msg(object):
74    def __init__(self, msg):
75        self.center_freq = msg.arg1()
76        self.vlen = int(msg.arg2())
77        assert(msg.length() == self.vlen * gr.sizeof_float)
78
79        # FIXME consider using Numarray or NumPy vector
80        t = msg.to_string()
81        self.raw_data = t
82        self.data = struct.unpack('%df' % (self.vlen,), t)
83
84
85class spec_sense_top_block(gr.top_block):
86
87    def __init__(self,min_f,max_f):
88        gr.top_block.__init__(self)
89
90        usage = "usage: %prog [options] min_freq max_freq"
91        parser = OptionParser(option_class=eng_option, usage=usage)
92        parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=(0,0),
93                          help="select USRP Rx side A or B (default=A)")
94        parser.add_option("-g", "--gain", type="eng_float", default=None,
95                          help="set gain in dB (default is midpoint)")
96        parser.add_option("", "--tune-delay", type="eng_float", default=1e-3, metavar="SECS",
97                          help="time to delay (in seconds) after changing frequency [default=%default]")
98        parser.add_option("", "--dwell-delay", type="eng_float", default=10e-3, metavar="SECS",
99                          help="time to dwell (in seconds) at a given frequncy [default=%default]")
100        parser.add_option("-F", "--fft-size", type="int", default=256,
101                          help="specify number of FFT bins [default=%default]")
102        parser.add_option("-d", "--decim", type="intx", default=16,
103                          help="set decimation to DECIM [default=%default]")
104        parser.add_option("", "--real-time", action="store_true", default=False,
105                          help="Attempt to enable real-time scheduling")
106        parser.add_option("-B", "--fusb-block-size", type="int", default=0,
107                          help="specify fast usb block size [default=%default]")
108        parser.add_option("-N", "--fusb-nblocks", type="int", default=0,
109                          help="specify number of fast usb blocks [default=%default]")
110
111        (options, args) = parser.parse_args()
112        #if len(args) != 2:
113         #   parser.print_help()
114         #   sys.exit(1)
115
116        #self.min_freq = eng_notation.str_to_num(args[0])
117        self.min_freq = float(min_f) # setting min and max frequency inside the init rather than taking it from the command line
118        #self.max_freq = eng_notation.str_to_num(args[1])
119        self.max_freq = float(max_f)
120
121        if self.min_freq > self.max_freq:
122            self.min_freq, self.max_freq = self.max_freq, self.min_freq   # swap them
123
124        self.fft_size = options.fft_size
125
126
127        if not options.real_time:
128            realtime = False
129        else:
130            # Attempt to enable realtime scheduling
131            r = gr.enable_realtime_scheduling()
132            if r == gr.RT_OK:
133                realtime = True
134            else:
135                realtime = False
136                print "Note: failed to enable realtime scheduling"
137
138        # If the user hasn't set the fusb_* parameters on the command line,
139        # pick some values that will reduce latency.
140
141        if 1:
142            if options.fusb_block_size == 0 and options.fusb_nblocks == 0:
143                if realtime:                        # be more aggressive
144                    options.fusb_block_size = gr.prefs().get_long('fusb', 'rt_block_size', 1024)
145                    options.fusb_nblocks    = gr.prefs().get_long('fusb', 'rt_nblocks', 16)
146                else:
147                    options.fusb_block_size = gr.prefs().get_long('fusb', 'block_size', 4096)
148                    options.fusb_nblocks    = gr.prefs().get_long('fusb', 'nblocks', 16)
149   
150        #print "fusb_block_size =", options.fusb_block_size
151        #print "fusb_nblocks    =", options.fusb_nblocks
152
153        # build graph
154       
155        self.u = usrp.source_c(fusb_block_size=options.fusb_block_size,
156                               fusb_nblocks=options.fusb_nblocks)
157
158
159        adc_rate = self.u.adc_rate()                # 64 MS/s
160        usrp_decim = options.decim
161        self.u.set_decim_rate(usrp_decim)
162        usrp_rate = adc_rate / usrp_decim
163
164        self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec))
165        self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec)
166        print "Using RX d'board %s" % (self.subdev.side_and_name(),)
167
168
169        s2v = gr.stream_to_vector(gr.sizeof_gr_complex, self.fft_size)
170
171        mywindow = window.blackmanharris(self.fft_size)
172        fft = gr.fft_vcc(self.fft_size, True, mywindow)
173        power = 0
174        for tap in mywindow:
175            power += tap*tap
176           
177        c2mag = gr.complex_to_mag_squared(self.fft_size)
178        print "print c2mag ",c2mag,"\n"
179        # FIXME the log10 primitive is dog slow
180        log = gr.nlog10_ff(10, self.fft_size,
181                           -20*math.log10(self.fft_size)-10*math.log10(power/self.fft_size))
182               
183        # Set the freq_step to 75% of the actual data throughput.
184        # This allows us to discard the bins on both ends of the spectrum.
185
186        self.freq_step = 0.75 * usrp_rate
187        self.min_center_freq = self.min_freq + self.freq_step/2
188        nsteps = math.ceil((self.max_freq - self.min_freq) / self.freq_step)
189        self.max_center_freq = self.min_center_freq + (nsteps * self.freq_step)
190
191        self.next_freq = self.min_center_freq
192       
193        tune_delay  = max(0, int(round(options.tune_delay * usrp_rate / self.fft_size)))  # in fft_frames
194        dwell_delay = max(1, int(round(options.dwell_delay * usrp_rate / self.fft_size))) # in fft_frames
195
196        self.msgq = gr.msg_queue(16)
197        self._tune_callback = tune(self)        # hang on to this to keep it from being GC'd
198        stats = gr.bin_statistics_f(self.fft_size, self.msgq,
199                                    self._tune_callback, tune_delay, dwell_delay)
200
201        # FIXME leave out the log10 until we speed it up
202        #self.connect(self.u, s2v, fft, c2mag, log, stats)
203        self.connect(self.u, s2v, fft, c2mag, stats)
204
205        if options.gain is None:
206            # if no gain was specified, use the mid-point in dB
207            g = self.subdev.gain_range()
208            options.gain = float(g[0]+g[1])/2
209
210        self.set_gain(options.gain)
211        print "gain =", options.gain
212
213
214    def set_next_freq(self):
215        target_freq = self.next_freq
216        self.next_freq = self.next_freq + self.freq_step
217        if self.next_freq >= self.max_center_freq:
218            self.next_freq = self.min_center_freq
219
220        if not self.set_freq(target_freq):
221            print "Failed to set frequency to", target_freq
222
223        return target_freq
224                         
225
226    def set_freq(self, target_freq):
227        """
228        Set the center frequency we're interested in.
229
230        @param target_freq: frequency in Hz
231        @rypte: bool
232
233        Tuning is a two step process.  First we ask the front-end to
234        tune as close to the desired frequency as it can.  Then we use
235        the result of that operation and our target_frequency to
236        determine the value for the digital down converter.
237        """
238        return self.u.tune(0, self.subdev, target_freq)
239
240
241    def set_gain(self, gain):
242        self.subdev.set_gain(gain)
243
244    def set_min_max_freq(self,minimum,maximum):# setting min and max frequency
245        self.min_freq = float(minimum)
246        self.max_freq = float(maximum)
247
248    def get_avg_power(self,trials):
249        power_sum = 0 #sum of powers(each power value is determined by adding the 'fft square' points..these fft square points are essentially points from  the PSD curve...and adding them gives us the power contained in the spectrum)
250        counter = 0
251        _trials = int(trials)
252        while counter < _trials :
253
254                # Get the next message sent from the C++ code (blocking call).
255                # It contains the center frequency and the mag squared of the fft
256                m = parse_msg(self.msgq.delete_head())
257                print "printing mag sq of fft ",sum(m.data),"\n"
258                #if sum(m.data) > 1e12:
259                power_sum = power_sum + sum(m.data)
260                # Print center freq so we know that something is happening...
261                #print m.center_freq
262                counter +=1
263                # FIXME do something useful with the data...
264       
265                # m.data are the mag_squared of the fft output (they are in the
266                # standard order.  I.e., bin 0 == DC.)
267                # You'll probably want to do the equivalent of "fftshift" on them
268                # m.raw_data is a string that contains the binary floats.
269                # You could write this as binary to a file.
270
271        avg_power = power_sum/_trials
272        print "printing average power ",avg_power,"\n"
273        return avg_power
274
275######################## end of spectrum sense specific classes #############################################################
276
277       
278#//////main////// 
279
280global n_rcvd, n_right
281
282def main():
283    global n_rcvd, n_right,sync_status,mode
284    n_rcvd = 0
285    n_right = 0
286    def send_pkt(self, payload='', eof=False):
287        return self.txpath.send_pkt(payload, eof)
288
289    def rx_callback(ok, payload):
290        #print "inside rx callback"
291        global n_rcvd, n_right, sync_status,mode
292        (pktno,) = struct.unpack('!H', payload[0:2])
293        #temp = struct.unpack('!s', payload[3:10])
294        #print "printing the elements of packet",temp,"!!!!!!!!!!!\n"
295        if mode == "sync":
296        #####################################################
297                (sync_signal,) = struct.unpack('!s', payload[2])
298                (sync_signal_red,) = struct.unpack('!s', payload[3])  #redundant sync bit
299                (data_channel,) = struct.unpack('!s', payload[4])
300                (data_channel_red,) = struct.unpack('!s', payload[5])  #redundant channel bit
301                #print "printing the elements of packet  ",sync_signal,"  !!!!!!!!!!!  ",sync_signal_red," !!!!!\n"   
302                #print "printing the channel  ",data_channel_red,"  !!!!!!!!!!!  ",data_channel_red," !!!!!\n"
303                if ok: #== True :# and str(sync_signal) == 'o' and str(sync_signal_red) == 'o':
304                        #print "inside if"
305                        if ok: #== True: #str(data_channel) == str(data_channel_red):
306                                #print "inside if1$$$$$"
307                                if str(data_channel) == str(ch):
308                                        #print "inside if2"
309                                        sync_status = True
310                                        tb.stop()
311                                        #print "after tb stop ans sync status is ",sync_status," sync status\n"
312                                        #print "received a sync packet on channel %s\n" %(data_channel)
313                                        #data = 'o'+'o'+str(data_channel)+str(data_channel)
314                                        #print "sending this data",data,"@@@@@\n"
315                                        #pktno=0
316                                        #ack_payload = struct.pack('!H', pktno & 0xffff) + data
317                                        #print "printing the ack packet",ack_payload,"$$$$$\n"
318                                        #k=0
319                                        #while k < 10000:
320                                        #print "inside while"
321                                        #send_pkt(tb,ack_payload) #sending back the acknowledgement
322                                        #k=k+1
323        #####################################################
324       
325        n_rcvd += 1
326        if ok:
327            n_right += 1
328
329        #print "ok = %5s  pktno = %4d  n_rcvd = %4d  n_right = %4d" % (
330            #ok, pktno, n_rcvd, n_right)
331
332    mods = modulation_utils.type_1_mods()
333    demods = modulation_utils.type_1_demods()
334
335    #setting up the tx options parser
336    parser_tx = OptionParser(option_class=eng_option, conflict_handler="resolve")
337    expert_grp_tx = parser_tx.add_option_group("Expert_tx")
338    print "printing Expert_tx group",expert_grp_tx,"printing Expert_tx group"
339    parser_tx.add_option("-m", "--modulation", type="choice", choices=mods.keys(),
340                      default='gmsk',
341                      help="Select modulation from: %s [default=%%default]"
342                            % (', '.join(mods.keys()),))
343
344    parser_tx.add_option("-s", "--size", type="eng_float", default=1500,
345                      help="set packet size [default=%default]")
346    parser_tx.add_option("-M", "--megabytes", type="eng_float", default=1.0,
347                      help="set megabytes to transmit [default=%default]")
348    parser_tx.add_option("","--discontinuous", action="store_true", default=False,
349                      help="enable discontinous transmission (bursts of 5 packets)")
350    parser_tx.add_option("","--from-file", default=None,
351                      help="use file for packet contents")
352    print "printing parser_tx",parser_tx,"printing parser_tx"
353    transmit_path.add_options(parser_tx, expert_grp_tx)
354
355    for mod in mods.values():
356        mod.add_options(expert_grp_tx)
357
358    (options_tx, args_tx) = parser_tx.parse_args ()
359
360    if len(args_tx) != 0:
361        parser_tx.print_help()
362        sys.exit(1)
363    ############# Setting some default values for tx side of the block
364    options_tx.tx_freq = 462.5625e6 #setting default tx_freq value
365    options_tx.samples_per_symbol =  2
366    options_tx.modulation = 'dbpsk'
367    #############
368    if options_tx.tx_freq is None:
369        sys.stderr.write("You must specify -f FREQ or --freq FREQ\n")
370        parser_tx.print_help(sys.stderr)
371        sys.exit(1)
372
373    if options_tx.from_file is not None:
374        source_file = open(options_tx.from_file, 'r')
375    print "printing modulation type",mods[options_tx.modulation],"**"
376    # build the graph
377    print "printing tx options",options_tx,"&&&&\n"
378    #tb = my_top_block(mods[options_tx.modulation], options_tx)
379
380    #r = gr.enable_realtime_scheduling()
381    #if r != gr.RT_OK:
382    #   print "Warning: failed to enable realtime scheduling"
383
384    #setting up rx options parser
385   
386    # Create Options Parser:
387    parser_rx = OptionParser (option_class=eng_option, conflict_handler="resolve")
388    print "printing parser_rx",parser_rx,"!!!!!\n"
389    print "after option parser"
390    expert_grp_rx = parser_rx.add_option_group("Expert_rx")
391    print "printing expert group rx",expert_grp_rx,"@@@@\n"
392    parser_rx.add_option("-m", "--modulation", type="choice", choices=demods.keys(),
393                      default='gmsk',
394                      help="Select modulation from: %s [default=%%default]"
395                            % (', '.join(demods.keys()),))
396    print "inside rx option parser"
397    receive_path.add_options(parser_rx, expert_grp_rx)
398
399    for mod in demods.values():
400        mod.add_options(expert_grp_rx)
401
402    (options_rx, args_rx) = parser_rx.parse_args ()
403
404    if len(args_rx) != 0:
405        parser_rx.print_help(sys.stderr)
406        sys.exit(1)
407    ############# Setting some default values for rx side of the block
408    options_rx.rx_freq = 462.5625e6 #setting default rx_freq value
409    options_rx.samples_per_symbol =  2
410    options_rx.modulation = 'dbpsk'
411    #############
412    if options_rx.rx_freq is None:
413        sys.stderr.write("You must specify -f FREQ or --freq FREQ\n")
414        parser_rx.print_help(sys.stderr)
415        sys.exit(1)
416    print "printing rx options",options_rx,"&&&&\n"
417
418
419
420    ######################## adding another top block for usrp spectrum sense ########################
421    trials = 10
422    default_min_freq = 462.4825e6 #80 Khz to the left of channel 1 (462.5625e6) in frs band
423    default_max_freq = 462.6425e6 #80 Khz to the right of channel 1 (462.5625e6) in frs band
424    tb_spec_sense = spec_sense_top_block(default_min_freq,default_min_freq)
425    tb_spec_sense.subdev.select_rx_antenna('RX2')
426    tb_spec_sense.start()              # start executing flow graph in another thread...
427    avg = tb_spec_sense.get_avg_power(trials)
428    print "printing the average power ",avg, "\n"
429    tb_spec_sense.stop()   
430   
431
432    ##################################################################################################
433
434    # build the graph
435
436    tb = my_top_block(mods[options_tx.modulation],
437                     demods[options_rx.modulation],
438                     rx_callback,options_tx,
439                     options_rx)
440    r = gr.enable_realtime_scheduling()
441    if r != gr.RT_OK:
442       print "Warning: failed to enable realtime scheduling"
443
444    #tb.start()
445    # generate and send packets
446    #print "printing megamytes",options_tx.megabytes,"  $$$$\n"
447   
448    #n = 0
449    #pktno = 0
450    #pkt_size = int(options_tx.size)
451    #options_tx.megabytes = 0.000048
452   
453    #options_tx.size = 6 #2 bytes for packet size,2 bytes for the synchronization request(including redundant bit) and 2 bits to specify the channel number(including redundant bit)
454   
455   
456    myfile = file("logfile.txt", 'w')
457    myfile.write("")
458    #sending sync packet-format
459    global ch
460    check =True
461    #ch = random.randint(1, 7)#which channel to send information on...this is the second data packet of the synchronization frame
462    #resend = 5; #number of times a batch of sync packets is sent on a channel before trying a different channel
463    running = True
464    #resend_count= 0 #initializing resend count
465    #while running
466   
467   
468
469
470if __name__ == '__main__':
471    try:
472        main()
473    except KeyboardInterrupt:
474        pass
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517   
518
519
520
Note: See TracBrowser for help on using the browser.