1 | #!/usr/bin/env python |
---|
2 | #Transmission and reception, one ata a time on the same antena |
---|
3 | |
---|
4 | from gnuradio import gr, gru, modulation_utils |
---|
5 | from gnuradio import eng_notation |
---|
6 | ##########spectrum sense specific imports |
---|
7 | from gnuradio import optfir, window |
---|
8 | from gnuradio import usrp |
---|
9 | from gnuradio.eng_option import eng_option |
---|
10 | from usrpm import usrp_dbid |
---|
11 | ########## |
---|
12 | from gnuradio.eng_option import eng_option |
---|
13 | from optparse import OptionParser |
---|
14 | from numpy import random |
---|
15 | import random, time, struct, sys, math |
---|
16 | |
---|
17 | # from current dir |
---|
18 | from transmit_path import transmit_path |
---|
19 | from receive_path import receive_path |
---|
20 | |
---|
21 | global sync_status |
---|
22 | sync_status = False #default value is "False"... |
---|
23 | global 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 |
---|
28 | mode = "sync" #default mode of operation... |
---|
29 | class 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########################################################### |
---|
42 | class 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 | |
---|
73 | class 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 | |
---|
85 | class 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 | |
---|
280 | global n_rcvd, n_right |
---|
281 | |
---|
282 | def 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 | |
---|
470 | if __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 | |
---|