Imported Upstream version 3.0.4
[debian/gnuradio] / gr-usrp / src / usrp_multi.py
1 #
2 # Copyright 2005 Free Software Foundation, Inc.
3
4 # This file is part of GNU Radio
5
6 # GNU Radio is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3, or (at your option)
9 # any later version.
10
11 # GNU Radio is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15
16 # You should have received a copy of the GNU General Public License
17 # along with GNU Radio; see the file COPYING.  If not, write to
18 # the Free Software Foundation, Inc., 51 Franklin Street,
19 # Boston, MA 02110-1301, USA.
20
21
22 import math
23 from gnuradio import gr, gru
24 from gnuradio.gr import hier_block_base
25 from gnuradio import usrp
26 from gnuradio import usrp1              # usrp Rev 1 and later
27 from gnuradio import blks
28 import usrp_prims
29 import sys
30
31
32 class multi_source_align(object):
33     def __init__(self, fg, master_serialno,decim,nchan=2,pga_gain=0.0,cordic_freq=0.0,mux=None,align_interval=-1):
34         """
35         Align multiple sources (usrps) using samplenumbers in the first channel.
36
37         Takes two ore more sources producing interleaved shorts.
38                                 produces nchan * nsources gr_complex output streams.
39
40         @param nchan: number of interleaved channels in source
41         @param align_interval: number of samples to minimally skip between alignments
42                                                        default = -1 which means align only once per work call.
43         @param master_serial_no: serial number of the source which must be the master.
44
45
46         Exported sub-blocks (attributes):
47           master_source
48           slave_source
49           usrp_master
50           usrp_slave
51         """
52         mode=usrp.FPGA_MODE_NORMAL
53         mode = mode | usrp_prims.bmFR_MODE_RX_COUNTING_32BIT #(1 << 2) #usrp1.FPGA_MODE_COUNTING_32BIT
54         align=gr.align_on_samplenumbers_ss (nchan,align_interval) 
55         self.usrp_master = None
56         self.usrp_slave = None
57         # um is master usrp
58         # us is slave usrp
59         if mux is None:
60           mux=self.get_default_mux()  #Note that all channels have shifted left because of the added 32 bit counter channel
61         
62         u1 = usrp.source_s (1, decim, nchan, gru.hexint(mux), mode,fpga_filename="multi_2rxhb_2tx.rbf" )
63         u0 = usrp.source_s (0, decim, nchan, gru.hexint(mux), mode,fpga_filename="multi_2rxhb_2tx.rbf" )
64         print 'usrp[0] serial',u0.serial_number()
65         print 'usrp[1] serial',u1.serial_number()
66         #default, choose the second found usrp as master (which is usually the usrp which was first plugged in)
67         um_index=1
68         um=u1
69         us_index=0
70         us=u0
71         if (not (master_serialno is None)): #((master_serialno>0) | (master_serialno <-2)):
72           if (u0.serial_number() == master_serialno):
73             um_index=0
74             um=u0
75             us_index=1
76             us=u1
77           elif (u1.serial_number() != master_serialno):              
78               errorstring = 'Error. requested master_serialno ' + master_serialno +' not found\n'
79               errorstring = errorstring + 'Available are:\n'
80               errorstring = errorstring + 'usrp[1] serial_no = ' + u1.serial_number() +'\n' 
81               errorstring = errorstring + 'usrp[0] serial_no = ' + u0.serial_number() +'\n'
82               print errorstring
83               raise ValueError, errorstring
84           else: #default, just choose the first found usrp as master
85             um_index=0
86             um=u0
87             us_index=1
88             us=u1
89
90         self.usrp_master=um
91         self.usrp_slave=us
92         print 'usrp_master=usrp[%i] serial_no = %s' % (um_index,self.usrp_master.serial_number() ,)
93         print 'usrp_slave=usrp[%i] serial_no = %s' % (us_index,self.usrp_slave.serial_number() ,)
94         self.subdev_mAr = usrp.selected_subdev(self.usrp_master, (0,0))
95         self.subdev_mBr = usrp.selected_subdev(self.usrp_master, (1,0))
96         self.subdev_sAr = usrp.selected_subdev(self.usrp_slave, (0,0))
97         self.subdev_sBr = usrp.selected_subdev(self.usrp_slave, (1,0))
98         #throttle = gr.throttle(gr.sizeof_gr_complex, input_rate)
99         if not (pga_gain is None):
100           um.set_pga (0, pga_gain)
101           um.set_pga (1, pga_gain)
102
103           us.set_pga (0, pga_gain)
104           us.set_pga (1, pga_gain)
105
106         self.input_rate = um.adc_freq () / um.decim_rate ()
107         deintm=gr.deinterleave(gr.sizeof_gr_complex) 
108         deints=gr.deinterleave(gr.sizeof_gr_complex)
109         nullsinkm=gr.null_sink(gr.sizeof_gr_complex)
110         nullsinks=gr.null_sink(gr.sizeof_gr_complex)
111
112         tocomplexm=gr.interleaved_short_to_complex()
113         tocomplexs=gr.interleaved_short_to_complex()
114
115         fg.connect(um,(align,0))
116         fg.connect(us,(align,1))
117         fg.connect((align,0),tocomplexm)
118         fg.connect((align,1),tocomplexs)
119         fg.connect(tocomplexm,deintm)
120         fg.connect(tocomplexs,deints)
121         fg.connect((deintm,0),nullsinkm) #The counters are not usefull for the user but must be connected to something
122         fg.connect((deints,0),nullsinks) #The counters are not usefull for the user but must be connected to something
123         if 4==nchan:
124           nullsinkm3=gr.null_sink(gr.sizeof_gr_complex)
125           nullsinks3=gr.null_sink(gr.sizeof_gr_complex)
126           fg.connect((deintm,3), nullsinkm3) #channel 4 is not used but must be connected
127           fg.connect((deints,3), nullsinks3) #channel 4 is not used but must be connected
128
129         self.fg=fg
130         self.master_source=deintm
131         self.slave_source=deints
132
133         if not (cordic_freq is None):
134           um.set_rx_freq (1, cordic_freq)
135           um.set_rx_freq (0, cordic_freq)
136           us.set_rx_freq (1, cordic_freq)
137           us.set_rx_freq (0, cordic_freq)
138
139         self.enable_master_and_slave()
140         # add an idle handler
141         self.unsynced=True
142
143         # wire the block together
144         #hier_block_multi_tail.__init__(self, fg, nchan,deintm,deints)
145  
146     def get_default_mux(self):
147         return 0x10321032     # Note that all channels have shifted left because of the added 32 bit counter channel  
148
149     def get_master_source_c(self):
150         return self.master_source
151
152     def get_slave_source_c(self):
153         return self.slave_source
154
155     def get_master_usrp(self):
156         return self.usrp_master
157
158     def get_slave_usrp(self):
159         return self.usrp_slave
160
161     def enable_master_and_slave(self):
162         # Warning, allways FIRST enable the slave before you enable the master
163         # This is to be sure you don't have two masters connecting to each other
164         # Otherwise you could ruin your hardware because the two sync outputs would be connected together
165
166         #SLAVE
167         #disable master, enable slave and set sync pulse to zero
168         reg_mask = usrp_prims.bmFR_RX_SYNC_SLAVE | usrp_prims.bmFR_RX_SYNC_MASTER | usrp_prims.bmFR_RX_SYNC
169         self.usrp_slave._u._write_fpga_reg_masked(usrp_prims.FR_RX_MASTER_SLAVE, usrp_prims.bmFR_RX_SYNC_SLAVE,reg_mask)
170         #set SYNC slave iopin on daughterboards RXA as input
171         oe = 0 # set rx_a_io[bitnoFR_RX_SYNC_INPUT_IOPIN] as input
172         oe_mask = usrp_prims.bmFR_RX_SYNC_INPUT_IOPIN 
173         self.usrp_slave._u._write_oe(0,oe,oe_mask)
174         #Now it is save to enable the master
175
176         #MASTER
177         #enable master, disable slave and set sync pulse to zero
178         reg_mask = usrp_prims.bmFR_RX_SYNC_SLAVE | usrp_prims.bmFR_RX_SYNC_MASTER | usrp_prims.bmFR_RX_SYNC
179         self.usrp_master._u._write_fpga_reg_masked(usrp_prims.FR_RX_MASTER_SLAVE,usrp_prims.bmFR_RX_SYNC_MASTER,reg_mask)
180         #set SYNC master iopin on daughterboards RXA as output
181         oe = usrp_prims.bmFR_RX_SYNC_OUTPUT_IOPIN # set rx_a_io[bitnoFR_RX_SYNC_OUTPUT_IOPIN] as output
182         oe_mask = usrp_prims.bmFR_RX_SYNC_OUTPUT_IOPIN 
183         self.usrp_master._u._write_oe(0,oe,oe_mask)
184
185     def sync_usrps(self, evt):
186         self.sync()
187
188     def sync(self):
189         result=False
190         result = self.usrp_master._u._write_fpga_reg_masked (usrp_prims.FR_RX_MASTER_SLAVE, usrp_prims.bmFR_RX_SYNC, usrp_prims.bmFR_RX_SYNC )
191         #There should be a small delay here, but the time it takes to get the sync to the usrp is long enough
192         #turn sync pulse off
193         result  = result & self.usrp_master._u._write_fpga_reg_masked (usrp_prims.FR_RX_MASTER_SLAVE,0 ,usrp_prims.bmFR_RX_SYNC);
194         return result;
195
196     def nullsink_counters(self):
197         nullsinkm=gr.null_sink(gr.sizeof_gr_complex)
198         nullsinks=gr.null_sink(gr.sizeof_gr_complex)
199         self.fg.connect((self.master_source,0),nullsinkm)
200         self.fg.connect((self.slave_source,0),nullsinks)
201
202
203     def print_db_info(self):
204         print "MASTER RX d'board %s" % (self.subdev_mAr.side_and_name(),)
205         print "MASTER RX d'board %s" % (self.subdev_mBr.side_and_name(),)
206         #print "TX d'board %s" % (self.subdev_At.side_and_name(),)
207         #print "TX d'board %s" % (self.subdev_Bt.side_and_name(),)
208         print "SLAVE RX d'board %s" % (self.subdev_sAr.side_and_name(),)
209         print "SLAVE RX d'board %s" % (self.subdev_sBr.side_and_name(),)
210         #print "TX d'board %s" % (self.subdev_At.side_and_name(),)
211         #print "TX d'board %s" % (self.subdev_Bt.side_and_name(),)
212
213     def tune_all_rx(self,target_freq):
214         result = True
215         r1 =  usrp.tune(self.usrp_master, 0, self.subdev_mAr, target_freq)
216         if r1 is None:
217           result=False
218         r2 = usrp.tune(self.usrp_master, 1, self.subdev_mBr, target_freq)
219         if r2 is None:
220           result=False
221         r3 = usrp.tune(self.usrp_slave, 0, self.subdev_sAr, target_freq)
222         if r3 is None:
223           result=False
224         r4 = usrp.tune(self.usrp_slave, 1, self.subdev_sBr, target_freq)
225         if r4 is None:
226           result=False
227         return result,r1,r2,r3,r4
228
229     def set_gain_all_rx(self, gain):
230         self.subdev_mAr.set_gain(gain)
231         self.subdev_mBr.set_gain(gain)
232         self.subdev_sAr.set_gain(gain)
233         self.subdev_sBr.set_gain(gain)