diff options
-rw-r--r-- | gr-uhd/doc/uhd.dox | 88 | ||||
-rw-r--r-- | gr-uhd/examples/grc/uhd_msg_tune.grc | 1174 | ||||
-rw-r--r-- | gr-uhd/lib/usrp_block_impl.cc | 302 | ||||
-rw-r--r-- | gr-uhd/lib/usrp_block_impl.h | 45 | ||||
-rw-r--r-- | gr-uhd/lib/usrp_sink_impl.cc | 38 | ||||
-rw-r--r-- | gr-uhd/lib/usrp_source_impl.cc | 14 |
6 files changed, 1009 insertions, 652 deletions
diff --git a/gr-uhd/doc/uhd.dox b/gr-uhd/doc/uhd.dox index 2a2658dde6..27a1475566 100644 --- a/gr-uhd/doc/uhd.dox +++ b/gr-uhd/doc/uhd.dox @@ -31,48 +31,92 @@ http://files.ettus.com/manual/annotated.html \section uhd_command_syntax Command Syntax The UHD sink and source can be controlled by a message port. These message ports -take commands, which are PMTs formatted as such: +take commands, which are PMTs formatted as described in \ref msg_passing_commands. + +There is a legacy format, which will be deprecated in the future, where commands may +be tuples, formatted as: (command, value, [channel]) -A command PMT is either a pair or a tuple. If it's a tuple, it must have either 2 or 3 elements. -Any other type of PMT will throw an error. +See older versions of this manual for documentation on this deprecated command format. -The `command` part is a string, which defines the command. `value` is a PMT whose format depends -on the command issued. Finally, `channel` is an integer PMT value that specifies which channel -this command shall be specified on. If this value is omitted, then it either applies this command -to all channels or channel zero, depending on which command is used. +In general, every command consists of one or more key/value pairs (either stored as a +PMT pair, or a dictionary). A full list of keys is listed below. Example: \code{.cpp} -pmt::pmt_t command = pmt::cons( // We make a pair, but pmt::make_tuple() is also valid! - pmt::mp("freq"), // Use the 'freq' command, which sets the frequency +pmt::pmt_t command = pmt::cons( // Make a pair + pmt::mp("freq"), // Key is 'freq' => sets the frequency pmt::mp(1.1e9) // Set the frequency to 1.1 GHz ); +// Now pass 'command' into the USRP block's command port \endcode This PMT would set the frequency to 1.1 GHz on all channels. We make use of the pmt::mp() function which automatically sets the PMT types. Assume we only want to set the frequency on channel 1 -(i.e. the second channel). In this case, we must construct a tuple: +(i.e. the second channel). In this case, we must construct a dictionary: \code{.cpp} -pmt::pmt_t command = pmt::make_tuple( - pmt::mp("freq"), // Use the 'freq' command, which sets the frequency - pmt::mp(1.1e9) // Set the frequency to 1.1 GHz - pmt::mp(1) // Select channel 1 -); +pmt::pmt_t command = pmt::make_dict(); +pmt::dict_add(command, pmt::mp("freq"), pmt::mp(1.1e9)); // Specify frequency +pmt::dict_add(command, pmt::mp("chan"), pmt::mp(1)); // Specify channel +// Now pass 'command' into the USRP block's command port +\endcode + +This command structure becomes more intuitive when thinking of sending the command PMT +as a function call, where the key/value pairs are argument names and values, respectively. +In the above example, the behaviour is the same as if calling +\code{.python} +usrp_source.set_center_freq(freq=1.1e9, chan=1) +\endcode +The main difference is that we can add more properties to the same +command PMT, e.g. as such: +\code{.cpp} +// 'command' is the same PMT as in the previous example +pmt::dict_add(command, pmt::mp("gain"), pmt::mp(23.0)); // Specify gain +pmt::dict_add(command, pmt::mp("antenna"), pmt::mp("TX/RX")); // Switch antenna +// Now pass 'command' into the USRP block's command port \endcode +When the USRP block interprets this command PMT, all properties will be +set. + + +\subsection uhd_command_syntax_cmds Common command keys + +The following command keys are understood by both UHD Source and Sink: + +Command name | Value Type | Description +-------------|--------------|------------------------------------------------------------- +`chan` | int | Specifies a channel. If this is not given, either all channels are chosen, or channel 0, depending on the action. A value of -1 forces 'all channels', where possible. +`gain` | double | Sets the Tx or Rx gain (in dB). Defaults to all channels. +`freq` | double | Sets the Tx or Rx frequency. Defaults to all channels. If specified without `lo_offset`, it will set the LO offset to zero. +`lo_offset` | double | Sets an LO offset. Defaults to all channels. Note this does not affect the effective center frequency. +`tune` | tune_request | Like freq, but sets a full tune request (i.e. center frequency and DSP offset). Defaults to all channels. +`lo_freq` | double | For fully manual tuning: Set the LO frequency (RF frequency). Conflicts with `freq`, `lo_offset`, and `tune`. +`dsp_freq` | double | For fully manual tuning: Set the DSP frequency (CORDIC frequency). Conflicts with `freq`, `lo_offset`, and `tune`. +`rate` | double | See usrp_block::set_samp_rate(). *Always* affects all channels. +`bandwidth` | double | See usrp_block::set_bandwidth(). Defaults to all channels. +`time` | timestamp | Sets a command time. See usrp_block::set_command_time(). A value of PMT_NIL will clear the command time. +`mboard` | int | Specify mboard index, where applicable. +`antenna` | string | See usrp_block::set_antenna(). Defaults to all channels. + +Special types: +- tune_request: Like a uhd::tune_request_t, but always uses POLICY_AUTO. This is a pair, composed of (target_frequency, lo_offset) +- timestamp: A pair composed of (long full_secs, double frac_secs). Similar to uhd::time_spec_t -\subsection uhd_command_syntax_cmds Common commands +\b Note: Not all commands are affected by `time`. See the UHD manual for details on timed commands. -The following commands are understood by both UHD Source and Sink: +\subsection uhd_command_syntax_multi_vs_single Dictionaries vs pairs -Command name | Value Type | Description --------------|------------|------------------------------------------------------------- -`freq` | double | Sets the Tx or Rx frequency. Defaults to all channels. -`lo_offset` | double | Sets an LO offset. Defaults to all channels. -`gain` | double | Sets the Tx or Rx gain (in dB). Defaults to all channels. +Given the choices, it may be unclear if it's preferable to send multiple commands +to the USRP block with a single key/value pair each, or send a single dict with +all the values. +In general, the dictionary should be preferred. It has some distinct advantages: +- If it carries a timestamp, this timestamp is valid for all key/value pairs it + may be applied to. +- All settings will be applied at once. With multiple messages, other blocks might + be sending interfering messages while the messages are being processed. \section uhd_configuring Configuring a UHD object diff --git a/gr-uhd/examples/grc/uhd_msg_tune.grc b/gr-uhd/examples/grc/uhd_msg_tune.grc index 1d0a953bfb..0111142757 100644 --- a/gr-uhd/examples/grc/uhd_msg_tune.grc +++ b/gr-uhd/examples/grc/uhd_msg_tune.grc @@ -3,59 +3,189 @@ <flow_graph> <timestamp>Tue Jul 8 12:08:19 2014</timestamp> <block> - <key>variable</key> + <key>options</key> <param> - <key>id</key> - <value>samp_rate</value> + <key>author</key> + <value></value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>description</key> + <value>Tune a UHD source from a QT sink via messages (double-click a frequency to tune)</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>value</key> - <value>2e6</value> + <key>_coordinate</key> + <value>(-1, -2)</value> </param> <param> - <key>alias</key> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>generate_options</key> + <value>qt_gui</value> + </param> + <param> + <key>id</key> + <value>uhd_tune_msg</value> + </param> + <param> + <key>max_nouts</key> + <value>0</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>run_options</key> + <value>prompt</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>thread_safe_setters</key> <value></value> </param> <param> + <key>title</key> + <value>UHD Message Tuner</value> + </param> + <param> + <key>window_size</key> + <value>1280, 1024</value> + </param> + </block> + <block> + <key>variable_qtgui_entry</key> + <param> <key>comment</key> <value></value> </param> <param> + <key>value</key> + <value>pmt.to_pmt({'antenna': 'TX/RX', 'gain': 23.0, 'chan': 0})</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> <key>_coordinate</key> - <value>(1, 102)</value> + <value>(112, 347)</value> + </param> + <param> + <key>gui_hint</key> + <value></value> </param> <param> <key>_rotation</key> <value>0</value> </param> + <param> + <key>id</key> + <value>cmd_msg</value> + </param> + <param> + <key>label</key> + <value>Command Message</value> + </param> + <param> + <key>type</key> + <value>raw</value> + </param> </block> <block> - <key>variable</key> + <key>variable_qtgui_range</key> <param> - <key>id</key> - <value>initial_fc</value> + <key>comment</key> + <value></value> + </param> + <param> + <key>value</key> + <value>.8</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>value</key> - <value>100e6</value> + <key>_coordinate</key> + <value>(103, 99)</value> </param> <param> - <key>alias</key> + <key>gui_hint</key> <value></value> </param> <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>gain</value> + </param> + <param> + <key>label</key> + <value>Gain</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>start</key> + <value>0</value> + </param> + <param> + <key>step</key> + <value>.01</value> + </param> + <param> + <key>stop</key> + <value>1</value> + </param> + <param> + <key>rangeType</key> + <value>float</value> + </param> + <param> + <key>widget</key> + <value>counter_slider</value> + </param> + </block> + <block> + <key>variable</key> + <param> <key>comment</key> <value></value> </param> <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> <key>_coordinate</key> <value>(-2, 172)</value> </param> @@ -63,368 +193,401 @@ <key>_rotation</key> <value>0</value> </param> + <param> + <key>id</key> + <value>initial_fc</value> + </param> + <param> + <key>value</key> + <value>100e6</value> + </param> </block> <block> - <key>uhd_usrp_source</key> + <key>variable</key> <param> - <key>id</key> - <value>uhd_usrp_source_0</value> + <key>comment</key> + <value></value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>type</key> - <value>fc32</value> + <key>_coordinate</key> + <value>(1, 102)</value> </param> <param> - <key>otw</key> - <value></value> + <key>_rotation</key> + <value>0</value> </param> <param> - <key>stream_args</key> - <value></value> + <key>id</key> + <value>samp_rate</value> </param> <param> - <key>stream_chans</key> - <value>[]</value> + <key>value</key> + <value>2e6</value> </param> + </block> + <block> + <key>blocks_message_strobe</key> <param> - <key>dev_addr</key> - <value>""</value> + <key>alias</key> + <value></value> </param> <param> - <key>dev_args</key> - <value>""</value> + <key>comment</key> + <value></value> </param> <param> - <key>sync</key> + <key>affinity</key> <value></value> </param> <param> - <key>clock_rate</key> - <value>0.0</value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>num_mboards</key> - <value>1</value> + <key>_coordinate</key> + <value>(96, 275)</value> </param> <param> - <key>clock_source0</key> - <value></value> + <key>_rotation</key> + <value>0</value> </param> <param> - <key>time_source0</key> - <value></value> + <key>id</key> + <value>blocks_message_strobe_0</value> </param> <param> - <key>sd_spec0</key> - <value></value> + <key>maxoutbuf</key> + <value>0</value> </param> <param> - <key>clock_source1</key> - <value></value> + <key>msg</key> + <value>cmd_msg</value> </param> <param> - <key>time_source1</key> - <value></value> + <key>minoutbuf</key> + <value>0</value> </param> <param> - <key>sd_spec1</key> - <value></value> + <key>period</key> + <value>2000</value> </param> + </block> + <block> + <key>qtgui_freq_sink_x</key> <param> - <key>clock_source2</key> - <value></value> + <key>autoscale</key> + <value>False</value> </param> <param> - <key>time_source2</key> - <value></value> + <key>average</key> + <value>0.1</value> </param> <param> - <key>sd_spec2</key> - <value></value> + <key>bw</key> + <value>samp_rate</value> </param> <param> - <key>clock_source3</key> + <key>alias</key> <value></value> </param> <param> - <key>time_source3</key> - <value></value> + <key>fc</key> + <value>initial_fc</value> </param> <param> - <key>sd_spec3</key> + <key>comment</key> <value></value> </param> <param> - <key>clock_source4</key> - <value></value> + <key>ctrlpanel</key> + <value>False</value> </param> <param> - <key>time_source4</key> + <key>affinity</key> <value></value> </param> <param> - <key>sd_spec4</key> - <value></value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>clock_source5</key> - <value></value> + <key>fftsize</key> + <value>1024</value> </param> <param> - <key>time_source5</key> - <value></value> + <key>_coordinate</key> + <value>(536, 251)</value> </param> <param> - <key>sd_spec5</key> + <key>gui_hint</key> <value></value> </param> <param> - <key>clock_source6</key> - <value></value> + <key>_rotation</key> + <value>180</value> </param> <param> - <key>time_source6</key> - <value></value> + <key>grid</key> + <value>True</value> </param> <param> - <key>sd_spec6</key> - <value></value> + <key>id</key> + <value>qtgui_freq_sink_x_0</value> </param> <param> - <key>clock_source7</key> - <value></value> + <key>legend</key> + <value>True</value> </param> <param> - <key>time_source7</key> - <value></value> + <key>alpha1</key> + <value>1.0</value> </param> <param> - <key>sd_spec7</key> + <key>color1</key> + <value>"blue"</value> + </param> + <param> + <key>label1</key> <value></value> </param> <param> - <key>nchan</key> + <key>width1</key> <value>1</value> </param> <param> - <key>samp_rate</key> - <value>samp_rate</value> + <key>alpha10</key> + <value>1.0</value> </param> <param> - <key>center_freq0</key> - <value>initial_fc</value> + <key>color10</key> + <value>"dark blue"</value> </param> <param> - <key>gain0</key> - <value>gain</value> + <key>label10</key> + <value></value> </param> <param> - <key>norm_gain0</key> - <value>True</value> + <key>width10</key> + <value>1</value> </param> <param> - <key>ant0</key> - <value></value> + <key>alpha2</key> + <value>1.0</value> </param> <param> - <key>bw0</key> - <value>0</value> + <key>color2</key> + <value>"red"</value> </param> <param> - <key>center_freq1</key> - <value>0</value> + <key>label2</key> + <value></value> </param> <param> - <key>gain1</key> - <value>0</value> + <key>width2</key> + <value>1</value> </param> <param> - <key>norm_gain1</key> - <value>False</value> + <key>alpha3</key> + <value>1.0</value> </param> <param> - <key>ant1</key> - <value></value> + <key>color3</key> + <value>"green"</value> </param> <param> - <key>bw1</key> - <value>0</value> + <key>label3</key> + <value></value> </param> <param> - <key>center_freq2</key> - <value>0</value> + <key>width3</key> + <value>1</value> </param> <param> - <key>gain2</key> - <value>0</value> + <key>alpha4</key> + <value>1.0</value> </param> <param> - <key>norm_gain2</key> - <value>False</value> + <key>color4</key> + <value>"black"</value> </param> <param> - <key>ant2</key> + <key>label4</key> <value></value> </param> <param> - <key>bw2</key> - <value>0</value> + <key>width4</key> + <value>1</value> </param> <param> - <key>center_freq3</key> - <value>0</value> + <key>alpha5</key> + <value>1.0</value> </param> <param> - <key>gain3</key> - <value>0</value> + <key>color5</key> + <value>"cyan"</value> </param> <param> - <key>norm_gain3</key> - <value>False</value> + <key>label5</key> + <value></value> </param> <param> - <key>ant3</key> - <value></value> + <key>width5</key> + <value>1</value> </param> <param> - <key>bw3</key> - <value>0</value> + <key>alpha6</key> + <value>1.0</value> </param> <param> - <key>center_freq4</key> - <value>0</value> + <key>color6</key> + <value>"magenta"</value> </param> <param> - <key>gain4</key> - <value>0</value> + <key>label6</key> + <value></value> </param> <param> - <key>norm_gain4</key> - <value>False</value> + <key>width6</key> + <value>1</value> </param> <param> - <key>ant4</key> - <value></value> + <key>alpha7</key> + <value>1.0</value> </param> <param> - <key>bw4</key> - <value>0</value> + <key>color7</key> + <value>"yellow"</value> </param> <param> - <key>center_freq5</key> - <value>0</value> + <key>label7</key> + <value></value> </param> <param> - <key>gain5</key> - <value>0</value> + <key>width7</key> + <value>1</value> </param> <param> - <key>norm_gain5</key> - <value>False</value> + <key>alpha8</key> + <value>1.0</value> </param> <param> - <key>ant5</key> - <value></value> + <key>color8</key> + <value>"dark red"</value> </param> <param> - <key>bw5</key> - <value>0</value> + <key>label8</key> + <value></value> </param> <param> - <key>center_freq6</key> - <value>0</value> + <key>width8</key> + <value>1</value> </param> <param> - <key>gain6</key> - <value>0</value> + <key>alpha9</key> + <value>1.0</value> </param> <param> - <key>norm_gain6</key> - <value>False</value> + <key>color9</key> + <value>"dark green"</value> </param> <param> - <key>ant6</key> + <key>label9</key> <value></value> </param> <param> - <key>bw6</key> - <value>0</value> + <key>width9</key> + <value>1</value> </param> <param> - <key>center_freq7</key> + <key>maxoutbuf</key> <value>0</value> </param> <param> - <key>gain7</key> + <key>minoutbuf</key> <value>0</value> </param> <param> - <key>norm_gain7</key> + <key>name</key> + <value>QT GUI Plot</value> + </param> + <param> + <key>nconnections</key> + <value>1</value> + </param> + <param> + <key>showports</key> <value>False</value> </param> <param> - <key>ant7</key> - <value></value> + <key>freqhalf</key> + <value>True</value> </param> <param> - <key>bw7</key> + <key>tr_chan</key> <value>0</value> </param> <param> - <key>center_freq8</key> - <value>0</value> + <key>tr_level</key> + <value>0.0</value> </param> <param> - <key>gain8</key> - <value>0</value> + <key>tr_mode</key> + <value>qtgui.TRIG_MODE_FREE</value> </param> <param> - <key>norm_gain8</key> - <value>False</value> + <key>tr_tag</key> + <value>""</value> </param> <param> - <key>ant8</key> - <value></value> + <key>type</key> + <value>complex</value> </param> <param> - <key>bw8</key> - <value>0</value> + <key>update_time</key> + <value>0.10</value> </param> <param> - <key>center_freq9</key> - <value>0</value> + <key>wintype</key> + <value>firdes.WIN_BLACKMAN_hARRIS</value> </param> <param> - <key>gain9</key> - <value>0</value> + <key>ymax</key> + <value>-40</value> </param> <param> - <key>norm_gain9</key> - <value>False</value> + <key>ymin</key> + <value>-120</value> </param> + </block> + <block> + <key>uhd_usrp_source</key> <param> - <key>ant9</key> + <key>alias</key> <value></value> </param> <param> - <key>bw9</key> - <value>0</value> + <key>ant0</key> + <value></value> </param> <param> - <key>center_freq10</key> + <key>bw0</key> <value>0</value> </param> <param> - <key>gain10</key> - <value>0</value> + <key>center_freq0</key> + <value>initial_fc</value> </param> <param> - <key>norm_gain10</key> - <value>False</value> + <key>norm_gain0</key> + <value>True</value> + </param> + <param> + <key>gain0</key> + <value>gain</value> </param> <param> <key>ant10</key> @@ -435,16 +598,16 @@ <value>0</value> </param> <param> - <key>center_freq11</key> + <key>center_freq10</key> <value>0</value> </param> <param> - <key>gain11</key> - <value>0</value> + <key>norm_gain10</key> + <value>False</value> </param> <param> - <key>norm_gain11</key> - <value>False</value> + <key>gain10</key> + <value>0</value> </param> <param> <key>ant11</key> @@ -455,16 +618,16 @@ <value>0</value> </param> <param> - <key>center_freq12</key> + <key>center_freq11</key> <value>0</value> </param> <param> - <key>gain12</key> - <value>0</value> + <key>norm_gain11</key> + <value>False</value> </param> <param> - <key>norm_gain12</key> - <value>False</value> + <key>gain11</key> + <value>0</value> </param> <param> <key>ant12</key> @@ -475,16 +638,16 @@ <value>0</value> </param> <param> - <key>center_freq13</key> + <key>center_freq12</key> <value>0</value> </param> <param> - <key>gain13</key> - <value>0</value> + <key>norm_gain12</key> + <value>False</value> </param> <param> - <key>norm_gain13</key> - <value>False</value> + <key>gain12</key> + <value>0</value> </param> <param> <key>ant13</key> @@ -495,16 +658,16 @@ <value>0</value> </param> <param> - <key>center_freq14</key> + <key>center_freq13</key> <value>0</value> </param> <param> - <key>gain14</key> - <value>0</value> + <key>norm_gain13</key> + <value>False</value> </param> <param> - <key>norm_gain14</key> - <value>False</value> + <key>gain13</key> + <value>0</value> </param> <param> <key>ant14</key> @@ -515,16 +678,16 @@ <value>0</value> </param> <param> - <key>center_freq15</key> + <key>center_freq14</key> <value>0</value> </param> <param> - <key>gain15</key> - <value>0</value> + <key>norm_gain14</key> + <value>False</value> </param> <param> - <key>norm_gain15</key> - <value>False</value> + <key>gain14</key> + <value>0</value> </param> <param> <key>ant15</key> @@ -535,16 +698,16 @@ <value>0</value> </param> <param> - <key>center_freq16</key> + <key>center_freq15</key> <value>0</value> </param> <param> - <key>gain16</key> - <value>0</value> + <key>norm_gain15</key> + <value>False</value> </param> <param> - <key>norm_gain16</key> - <value>False</value> + <key>gain15</key> + <value>0</value> </param> <param> <key>ant16</key> @@ -555,16 +718,16 @@ <value>0</value> </param> <param> - <key>center_freq17</key> + <key>center_freq16</key> <value>0</value> </param> <param> - <key>gain17</key> - <value>0</value> + <key>norm_gain16</key> + <value>False</value> </param> <param> - <key>norm_gain17</key> - <value>False</value> + <key>gain16</key> + <value>0</value> </param> <param> <key>ant17</key> @@ -575,16 +738,16 @@ <value>0</value> </param> <param> - <key>center_freq18</key> + <key>center_freq17</key> <value>0</value> </param> <param> - <key>gain18</key> - <value>0</value> + <key>norm_gain17</key> + <value>False</value> </param> <param> - <key>norm_gain18</key> - <value>False</value> + <key>gain17</key> + <value>0</value> </param> <param> <key>ant18</key> @@ -595,16 +758,16 @@ <value>0</value> </param> <param> - <key>center_freq19</key> + <key>center_freq18</key> <value>0</value> </param> <param> - <key>gain19</key> - <value>0</value> + <key>norm_gain18</key> + <value>False</value> </param> <param> - <key>norm_gain19</key> - <value>False</value> + <key>gain18</key> + <value>0</value> </param> <param> <key>ant19</key> @@ -615,18 +778,38 @@ <value>0</value> </param> <param> - <key>center_freq20</key> + <key>center_freq19</key> <value>0</value> </param> <param> - <key>gain20</key> + <key>norm_gain19</key> + <value>False</value> + </param> + <param> + <key>gain19</key> <value>0</value> </param> <param> - <key>norm_gain20</key> + <key>ant1</key> + <value></value> + </param> + <param> + <key>bw1</key> + <value>0</value> + </param> + <param> + <key>center_freq1</key> + <value>0</value> + </param> + <param> + <key>norm_gain1</key> <value>False</value> </param> <param> + <key>gain1</key> + <value>0</value> + </param> + <param> <key>ant20</key> <value></value> </param> @@ -635,16 +818,16 @@ <value>0</value> </param> <param> - <key>center_freq21</key> + <key>center_freq20</key> <value>0</value> </param> <param> - <key>gain21</key> - <value>0</value> + <key>norm_gain20</key> + <value>False</value> </param> <param> - <key>norm_gain21</key> - <value>False</value> + <key>gain20</key> + <value>0</value> </param> <param> <key>ant21</key> @@ -655,16 +838,16 @@ <value>0</value> </param> <param> - <key>center_freq22</key> + <key>center_freq21</key> <value>0</value> </param> <param> - <key>gain22</key> - <value>0</value> + <key>norm_gain21</key> + <value>False</value> </param> <param> - <key>norm_gain22</key> - <value>False</value> + <key>gain21</key> + <value>0</value> </param> <param> <key>ant22</key> @@ -675,16 +858,16 @@ <value>0</value> </param> <param> - <key>center_freq23</key> + <key>center_freq22</key> <value>0</value> </param> <param> - <key>gain23</key> - <value>0</value> + <key>norm_gain22</key> + <value>False</value> </param> <param> - <key>norm_gain23</key> - <value>False</value> + <key>gain22</key> + <value>0</value> </param> <param> <key>ant23</key> @@ -695,16 +878,16 @@ <value>0</value> </param> <param> - <key>center_freq24</key> + <key>center_freq23</key> <value>0</value> </param> <param> - <key>gain24</key> - <value>0</value> + <key>norm_gain23</key> + <value>False</value> </param> <param> - <key>norm_gain24</key> - <value>False</value> + <key>gain23</key> + <value>0</value> </param> <param> <key>ant24</key> @@ -715,16 +898,16 @@ <value>0</value> </param> <param> - <key>center_freq25</key> + <key>center_freq24</key> <value>0</value> </param> <param> - <key>gain25</key> - <value>0</value> + <key>norm_gain24</key> + <value>False</value> </param> <param> - <key>norm_gain25</key> - <value>False</value> + <key>gain24</key> + <value>0</value> </param> <param> <key>ant25</key> @@ -735,16 +918,16 @@ <value>0</value> </param> <param> - <key>center_freq26</key> + <key>center_freq25</key> <value>0</value> </param> <param> - <key>gain26</key> - <value>0</value> + <key>norm_gain25</key> + <value>False</value> </param> <param> - <key>norm_gain26</key> - <value>False</value> + <key>gain25</key> + <value>0</value> </param> <param> <key>ant26</key> @@ -755,16 +938,16 @@ <value>0</value> </param> <param> - <key>center_freq27</key> + <key>center_freq26</key> <value>0</value> </param> <param> - <key>gain27</key> - <value>0</value> + <key>norm_gain26</key> + <value>False</value> </param> <param> - <key>norm_gain27</key> - <value>False</value> + <key>gain26</key> + <value>0</value> </param> <param> <key>ant27</key> @@ -775,16 +958,16 @@ <value>0</value> </param> <param> - <key>center_freq28</key> + <key>center_freq27</key> <value>0</value> </param> <param> - <key>gain28</key> - <value>0</value> + <key>norm_gain27</key> + <value>False</value> </param> <param> - <key>norm_gain28</key> - <value>False</value> + <key>gain27</key> + <value>0</value> </param> <param> <key>ant28</key> @@ -795,16 +978,16 @@ <value>0</value> </param> <param> - <key>center_freq29</key> + <key>center_freq28</key> <value>0</value> </param> <param> - <key>gain29</key> - <value>0</value> + <key>norm_gain28</key> + <value>False</value> </param> <param> - <key>norm_gain29</key> - <value>False</value> + <key>gain28</key> + <value>0</value> </param> <param> <key>ant29</key> @@ -815,504 +998,401 @@ <value>0</value> </param> <param> - <key>center_freq30</key> - <value>0</value> - </param> - <param> - <key>gain30</key> + <key>center_freq29</key> <value>0</value> </param> <param> - <key>norm_gain30</key> + <key>norm_gain29</key> <value>False</value> </param> <param> - <key>ant30</key> - <value></value> + <key>gain29</key> + <value>0</value> </param> <param> - <key>bw30</key> - <value>0</value> + <key>ant2</key> + <value></value> </param> <param> - <key>center_freq31</key> + <key>bw2</key> <value>0</value> </param> <param> - <key>gain31</key> + <key>center_freq2</key> <value>0</value> </param> <param> - <key>norm_gain31</key> + <key>norm_gain2</key> <value>False</value> </param> <param> - <key>ant31</key> - <value></value> - </param> - <param> - <key>bw31</key> + <key>gain2</key> <value>0</value> </param> <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>affinity</key> + <key>ant30</key> <value></value> </param> <param> - <key>minoutbuf</key> + <key>bw30</key> <value>0</value> </param> <param> - <key>maxoutbuf</key> + <key>center_freq30</key> <value>0</value> </param> <param> - <key>comment</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(336, 8)</value> + <key>norm_gain30</key> + <value>False</value> </param> <param> - <key>_rotation</key> + <key>gain30</key> <value>0</value> </param> - </block> - <block> - <key>qtgui_freq_sink_x</key> - <param> - <key>id</key> - <value>qtgui_freq_sink_x_0</value> - </param> <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>type</key> - <value>complex</value> + <key>ant31</key> + <value></value> </param> <param> - <key>name</key> - <value>QT GUI Plot</value> + <key>bw31</key> + <value>0</value> </param> <param> - <key>fftsize</key> - <value>1024</value> + <key>center_freq31</key> + <value>0</value> </param> <param> - <key>freqhalf</key> - <value>True</value> + <key>norm_gain31</key> + <value>False</value> </param> <param> - <key>wintype</key> - <value>firdes.WIN_BLACKMAN_hARRIS</value> + <key>gain31</key> + <value>0</value> </param> <param> - <key>fc</key> - <value>initial_fc</value> + <key>ant3</key> + <value></value> </param> <param> - <key>bw</key> - <value>samp_rate</value> + <key>bw3</key> + <value>0</value> </param> <param> - <key>grid</key> - <value>True</value> + <key>center_freq3</key> + <value>0</value> </param> <param> - <key>autoscale</key> + <key>norm_gain3</key> <value>False</value> </param> <param> - <key>average</key> - <value>0.1</value> - </param> - <param> - <key>ymin</key> - <value>-120</value> - </param> - <param> - <key>ymax</key> - <value>-40</value> + <key>gain3</key> + <value>0</value> </param> <param> - <key>nconnections</key> - <value>1</value> + <key>ant4</key> + <value></value> </param> <param> - <key>update_time</key> - <value>0.10</value> + <key>bw4</key> + <value>0</value> </param> <param> - <key>gui_hint</key> - <value></value> + <key>center_freq4</key> + <value>0</value> </param> <param> - <key>showports</key> + <key>norm_gain4</key> <value>False</value> </param> <param> - <key>tr_mode</key> - <value>qtgui.TRIG_MODE_FREE</value> + <key>gain4</key> + <value>0</value> </param> <param> - <key>tr_level</key> - <value>0.0</value> + <key>ant5</key> + <value></value> </param> <param> - <key>tr_chan</key> + <key>bw5</key> <value>0</value> </param> <param> - <key>tr_tag</key> - <value>""</value> + <key>center_freq5</key> + <value>0</value> </param> <param> - <key>ctrlpanel</key> + <key>norm_gain5</key> <value>False</value> </param> <param> - <key>legend</key> - <value>True</value> + <key>gain5</key> + <value>0</value> </param> <param> - <key>label1</key> + <key>ant6</key> <value></value> </param> <param> - <key>width1</key> - <value>1</value> - </param> - <param> - <key>color1</key> - <value>"blue"</value> - </param> - <param> - <key>alpha1</key> - <value>1.0</value> - </param> - <param> - <key>label2</key> - <value></value> + <key>bw6</key> + <value>0</value> </param> <param> - <key>width2</key> - <value>1</value> + <key>center_freq6</key> + <value>0</value> </param> <param> - <key>color2</key> - <value>"red"</value> + <key>norm_gain6</key> + <value>False</value> </param> <param> - <key>alpha2</key> - <value>1.0</value> + <key>gain6</key> + <value>0</value> </param> <param> - <key>label3</key> + <key>ant7</key> <value></value> </param> <param> - <key>width3</key> - <value>1</value> - </param> - <param> - <key>color3</key> - <value>"green"</value> - </param> - <param> - <key>alpha3</key> - <value>1.0</value> - </param> - <param> - <key>label4</key> - <value></value> + <key>bw7</key> + <value>0</value> </param> <param> - <key>width4</key> - <value>1</value> + <key>center_freq7</key> + <value>0</value> </param> <param> - <key>color4</key> - <value>"black"</value> + <key>norm_gain7</key> + <value>False</value> </param> <param> - <key>alpha4</key> - <value>1.0</value> + <key>gain7</key> + <value>0</value> </param> <param> - <key>label5</key> + <key>ant8</key> <value></value> </param> <param> - <key>width5</key> - <value>1</value> - </param> - <param> - <key>color5</key> - <value>"cyan"</value> - </param> - <param> - <key>alpha5</key> - <value>1.0</value> - </param> - <param> - <key>label6</key> - <value></value> + <key>bw8</key> + <value>0</value> </param> <param> - <key>width6</key> - <value>1</value> + <key>center_freq8</key> + <value>0</value> </param> <param> - <key>color6</key> - <value>"magenta"</value> + <key>norm_gain8</key> + <value>False</value> </param> <param> - <key>alpha6</key> - <value>1.0</value> + <key>gain8</key> + <value>0</value> </param> <param> - <key>label7</key> + <key>ant9</key> <value></value> </param> <param> - <key>width7</key> - <value>1</value> - </param> - <param> - <key>color7</key> - <value>"yellow"</value> - </param> - <param> - <key>alpha7</key> - <value>1.0</value> + <key>bw9</key> + <value>0</value> </param> <param> - <key>label8</key> - <value></value> + <key>center_freq9</key> + <value>0</value> </param> <param> - <key>width8</key> - <value>1</value> + <key>norm_gain9</key> + <value>False</value> </param> <param> - <key>color8</key> - <value>"dark red"</value> + <key>gain9</key> + <value>0</value> </param> <param> - <key>alpha8</key> - <value>1.0</value> + <key>clock_rate</key> + <value>0.0</value> </param> <param> - <key>label9</key> + <key>comment</key> <value></value> </param> <param> - <key>width9</key> - <value>1</value> - </param> - <param> - <key>color9</key> - <value>"dark green"</value> - </param> - <param> - <key>alpha9</key> - <value>1.0</value> - </param> - <param> - <key>label10</key> + <key>affinity</key> <value></value> </param> <param> - <key>width10</key> - <value>1</value> + <key>dev_addr</key> + <value>""</value> </param> <param> - <key>color10</key> - <value>"dark blue"</value> + <key>dev_args</key> + <value>""</value> </param> <param> - <key>alpha10</key> - <value>1.0</value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>alias</key> - <value></value> + <key>_coordinate</key> + <value>(528, 123)</value> </param> <param> - <key>affinity</key> - <value></value> + <key>_rotation</key> + <value>0</value> </param> <param> - <key>minoutbuf</key> - <value>0</value> + <key>id</key> + <value>uhd_usrp_source_0</value> </param> <param> <key>maxoutbuf</key> <value>0</value> </param> <param> - <key>comment</key> + <key>clock_source0</key> <value></value> </param> <param> - <key>_coordinate</key> - <value>(344, 139)</value> - </param> - <param> - <key>_rotation</key> - <value>180</value> + <key>sd_spec0</key> + <value></value> </param> - </block> - <block> - <key>variable_qtgui_range</key> <param> - <key>id</key> - <value>gain</value> + <key>time_source0</key> + <value></value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>clock_source1</key> + <value></value> </param> <param> - <key>label</key> - <value>Gain</value> + <key>sd_spec1</key> + <value></value> </param> <param> - <key>rangeType</key> - <value>float</value> + <key>time_source1</key> + <value></value> </param> <param> - <key>value</key> - <value>.8</value> + <key>clock_source2</key> + <value></value> </param> <param> - <key>start</key> - <value>0</value> + <key>sd_spec2</key> + <value></value> </param> <param> - <key>stop</key> - <value>1</value> + <key>time_source2</key> + <value></value> </param> <param> - <key>step</key> - <value>.01</value> + <key>clock_source3</key> + <value></value> </param> <param> - <key>widget</key> - <value>counter_slider</value> + <key>sd_spec3</key> + <value></value> </param> <param> - <key>orient</key> - <value>Qt.Horizontal</value> + <key>time_source3</key> + <value></value> </param> <param> - <key>min_len</key> - <value>200</value> + <key>clock_source4</key> + <value></value> </param> <param> - <key>gui_hint</key> + <key>sd_spec4</key> <value></value> </param> <param> - <key>alias</key> + <key>time_source4</key> <value></value> </param> <param> - <key>comment</key> + <key>clock_source5</key> <value></value> </param> <param> - <key>_coordinate</key> - <value>(103, 99)</value> + <key>sd_spec5</key> + <value></value> </param> <param> - <key>_rotation</key> - <value>0</value> + <key>time_source5</key> + <value></value> </param> - </block> - <block> - <key>options</key> <param> - <key>id</key> - <value>uhd_tune_msg</value> + <key>clock_source6</key> + <value></value> </param> <param> - <key>_enabled</key> - <value>True</value> + <key>sd_spec6</key> + <value></value> </param> <param> - <key>title</key> - <value>UHD Message Tuner</value> + <key>time_source6</key> + <value></value> </param> <param> - <key>author</key> + <key>clock_source7</key> <value></value> </param> <param> - <key>description</key> - <value>Tune a UHD source from a QT sink via messages (double-click a frequency to tune)</value> + <key>sd_spec7</key> + <value></value> </param> <param> - <key>window_size</key> - <value>1280, 1024</value> + <key>time_source7</key> + <value></value> </param> <param> - <key>generate_options</key> - <value>qt_gui</value> + <key>minoutbuf</key> + <value>0</value> </param> <param> - <key>category</key> - <value>Custom</value> + <key>nchan</key> + <value>1</value> </param> <param> - <key>run_options</key> - <value>prompt</value> + <key>num_mboards</key> + <value>1</value> </param> <param> - <key>run</key> - <value>True</value> + <key>type</key> + <value>fc32</value> </param> <param> - <key>max_nouts</key> - <value>0</value> + <key>samp_rate</key> + <value>samp_rate</value> </param> <param> - <key>realtime_scheduling</key> + <key>stream_args</key> <value></value> </param> <param> - <key>thread_safe_setters</key> - <value></value> + <key>stream_chans</key> + <value>[]</value> </param> <param> - <key>alias</key> + <key>sync</key> <value></value> </param> <param> - <key>comment</key> + <key>otw</key> <value></value> </param> - <param> - <key>_coordinate</key> - <value>(-1, -2)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> </block> <connection> - <source_block_id>uhd_usrp_source_0</source_block_id> + <source_block_id>blocks_message_strobe_0</source_block_id> + <sink_block_id>uhd_usrp_source_0</sink_block_id> + <source_key>strobe</source_key> + <sink_key>command</sink_key> + </connection> + <connection> + <source_block_id>qtgui_freq_sink_x_0</source_block_id> <sink_block_id>qtgui_freq_sink_x_0</sink_block_id> - <source_key>0</source_key> - <sink_key>0</sink_key> + <source_key>freq</source_key> + <sink_key>freq</sink_key> </connection> <connection> <source_block_id>qtgui_freq_sink_x_0</source_block_id> @@ -1321,9 +1401,9 @@ <sink_key>command</sink_key> </connection> <connection> - <source_block_id>qtgui_freq_sink_x_0</source_block_id> + <source_block_id>uhd_usrp_source_0</source_block_id> <sink_block_id>qtgui_freq_sink_x_0</sink_block_id> - <source_key>freq</source_key> - <sink_key>freq</sink_key> + <source_key>0</source_key> + <sink_key>0</sink_key> </connection> </flow_graph> diff --git a/gr-uhd/lib/usrp_block_impl.cc b/gr-uhd/lib/usrp_block_impl.cc index be24c57c6e..2e73b10538 100644 --- a/gr-uhd/lib/usrp_block_impl.cc +++ b/gr-uhd/lib/usrp_block_impl.cc @@ -27,6 +27,20 @@ using namespace gr::uhd; const double usrp_block_impl::LOCK_TIMEOUT = 1.5; +const pmt::pmt_t CMD_CHAN_KEY = pmt::mp("chan"); +const pmt::pmt_t CMD_GAIN_KEY = pmt::mp("gain"); +const pmt::pmt_t CMD_FREQ_KEY = pmt::mp("freq"); +const pmt::pmt_t CMD_LO_OFFSET_KEY = pmt::mp("lo_offset"); +const pmt::pmt_t CMD_TUNE_KEY = pmt::mp("tune"); +const pmt::pmt_t CMD_LO_FREQ_KEY = pmt::mp("lo_freq"); +const pmt::pmt_t CMD_DSP_FREQ_KEY = pmt::mp("dsp_freq"); +const pmt::pmt_t CMD_RATE_KEY = pmt::mp("rate"); +const pmt::pmt_t CMD_BANDWIDTH_KEY = pmt::mp("bandwidth"); +const pmt::pmt_t CMD_TIME_KEY = pmt::mp("time"); +const pmt::pmt_t CMD_MBOARD_KEY = pmt::mp("mboard"); +const pmt::pmt_t CMD_ANTENNA_KEY = pmt::mp("antenna"); + + /********************************************************************** * Structors *********************************************************************/ @@ -47,11 +61,10 @@ usrp_block_impl::usrp_block_impl( _nchan(stream_args.channels.size()), _stream_now(_nchan == 1 and ts_tag_name.empty()), _start_time_set(false), - _curr_freq(stream_args.channels.size(), 0.0), - _curr_lo_offset(stream_args.channels.size(), 0.0), - _curr_gain(stream_args.channels.size(), 0.0), + _curr_tune_req(stream_args.channels.size(), ::uhd::tune_request_t()), _chans_to_tune(stream_args.channels.size()) { + // TODO remove this when we update UHD if(stream_args.cpu_format == "fc32") _type = boost::make_shared< ::uhd::io_type_t >(::uhd::io_type_t::COMPLEX_FLOAT32); if(stream_args.cpu_format == "sc16") @@ -66,6 +79,19 @@ usrp_block_impl::usrp_block_impl( pmt::mp("command"), boost::bind(&usrp_block_impl::msg_handler_command, this, _1) ); + +// cuz we lazy: +#define REGISTER_CMD_HANDLER(key, _handler) register_msg_cmd_handler(key, boost::bind(&usrp_block_impl::_handler, this, _1, _2, _3)) + // Register default command handlers: + REGISTER_CMD_HANDLER(CMD_FREQ_KEY, _cmd_handler_freq); + REGISTER_CMD_HANDLER(CMD_GAIN_KEY, _cmd_handler_gain); + REGISTER_CMD_HANDLER(CMD_LO_OFFSET_KEY, _cmd_handler_looffset); + REGISTER_CMD_HANDLER(CMD_TUNE_KEY, _cmd_handler_tune); + REGISTER_CMD_HANDLER(CMD_LO_FREQ_KEY, _cmd_handler_lofreq); + REGISTER_CMD_HANDLER(CMD_DSP_FREQ_KEY, _cmd_handler_dspfreq); + REGISTER_CMD_HANDLER(CMD_RATE_KEY, _cmd_handler_rate); + REGISTER_CMD_HANDLER(CMD_BANDWIDTH_KEY, _cmd_handler_bw); + REGISTER_CMD_HANDLER(CMD_ANTENNA_KEY, _cmd_handler_antenna); } usrp_block_impl::~usrp_block_impl() @@ -185,10 +211,9 @@ bool usrp_block_impl::_check_mboard_sensors_locked() void usrp_block_impl::_set_center_freq_from_internals_allchans() { - for (size_t chan = 0; chan < _nchan; chan++) { - if (_chans_to_tune[chan]) { - _set_center_freq_from_internals(chan); - } + while (_chans_to_tune.any()) { + // This resets() bits, so this loop should not run indefinitely + _set_center_freq_from_internals(_chans_to_tune.find_first()); } } @@ -389,40 +414,245 @@ usrp_block_impl::setup_rpc() void usrp_block_impl::msg_handler_command(pmt::pmt_t msg) { - std::string command; - pmt::pmt_t cmd_value; - int chan = -1; - if (not _unpack_chan_command(command, cmd_value, chan, msg)) { - GR_LOG_ALERT(d_logger, boost::format("Error while unpacking command PMT: %s") % msg); + // Legacy code back compat: If we receive a tuple, we convert + // it to a dict, and call the function again. Yep, this comes + // at a slight performance hit. Sometime in the future, we can + // hopefully remove this: + if (pmt::is_tuple(msg)) { + if (pmt::length(msg) != 2 && pmt::length(msg) != 3) { + GR_LOG_ALERT(d_logger, boost::format("Error while unpacking command PMT: %s") % msg); + return; + } + pmt::pmt_t new_msg = pmt::make_dict(); + new_msg = pmt::dict_add(new_msg, pmt::tuple_ref(msg, 0), pmt::tuple_ref(msg, 1)); + if (pmt::length(msg) == 3) { + new_msg = pmt::dict_add(new_msg, pmt::mp("chan"), pmt::tuple_ref(msg, 2)); + } + GR_LOG_WARN(d_debug_logger, boost::format("Using legacy message format (tuples): %s") % msg); + return msg_handler_command(new_msg); + } + // End of legacy backward compat code. + + // Turn pair into dict + if (!pmt::is_dict(msg)) { + GR_LOG_ERROR(d_logger, boost::format("Command message is neither dict nor pair: %s") % msg); return; } - GR_LOG_DEBUG(d_debug_logger, boost::format("Received command: %s") % command); + + // OK, here comes the horrible part. Pairs pass is_dict(), but they're not dicts. Such dicks. try { - if (command == "freq") { - _chans_to_tune = _update_vector_from_cmd_val<double>( - _curr_freq, chan, pmt::to_double(cmd_value), true - ); - _set_center_freq_from_internals_allchans(); - } else if (command == "lo_offset") { - _chans_to_tune = _update_vector_from_cmd_val<double>( - _curr_lo_offset, chan, pmt::to_double(cmd_value), true + // This will fail if msg is a pair: + pmt::pmt_t keys = pmt::dict_keys(msg); + } catch (const pmt::wrong_type &e) { + // So we fix it: + GR_LOG_DEBUG(d_debug_logger, boost::format("Converting pair to dict: %s") % msg); + msg = pmt::dict_add(pmt::make_dict(), pmt::car(msg), pmt::cdr(msg)); + } + + /*** Start the actual message processing *************************/ + /// 1) Check if there's a time stamp + if (pmt::dict_has_key(msg, CMD_TIME_KEY)) { + size_t mboard_index = pmt::to_long( + pmt::dict_ref( + msg, CMD_MBOARD_KEY, + pmt::from_long( ::uhd::usrp::multi_usrp::ALL_MBOARDS ) // Default to all mboards + ) + ); + pmt::pmt_t timespec_p = pmt::dict_ref(msg, CMD_TIME_KEY, pmt::PMT_NIL); + if (timespec_p == pmt::PMT_NIL) { + clear_command_time(mboard_index); + } else { + ::uhd::time_spec_t timespec( + time_t(pmt::to_uint64(pmt::car(timespec_p))), // Full secs + pmt::to_double(pmt::cdr(timespec_p)) // Frac secs ); - _set_center_freq_from_internals_allchans(); - } else if (command == "gain") { - boost::dynamic_bitset<> chans_to_change = _update_vector_from_cmd_val<double>( - _curr_gain, chan, pmt::to_double(cmd_value), true + GR_LOG_DEBUG(d_debug_logger, boost::format("Setting command time on mboard %d") % mboard_index); + set_command_time(timespec, mboard_index); + } + } + + /// 2) Read chan value + int chan = int(pmt::to_long( + pmt::dict_ref( + msg, CMD_CHAN_KEY, + pmt::from_long(-1) // Default to all chans + ) + )); + + /// 3) Loop through all the values + GR_LOG_DEBUG(d_debug_logger, boost::format("Processing command message %s") % msg); + pmt::pmt_t msg_items = pmt::dict_items(msg); + for (size_t i = 0; i < pmt::length(msg_items); i++) { + try { + dispatch_msg_cmd_handler( + pmt::car(pmt::nth(i, msg_items)), + pmt::cdr(pmt::nth(i, msg_items)), + chan, msg ); - if (chans_to_change.any()) { - for (size_t i = 0; i < chans_to_change.size(); i++) { - if (chans_to_change[i]) { - set_gain(_curr_gain[i], i); - } - } - } - } else { - GR_LOG_ALERT(d_logger, boost::format("Received unknown command: %s") % command); + } catch (pmt::wrong_type &e) { + GR_LOG_ALERT(d_logger, boost::format("Invalid command value for key %s: %s") % pmt::car(pmt::nth(i, msg_items)) % pmt::cdr(pmt::nth(i, msg_items))); + break; + } + } + + /// 4) Check if we need to re-tune + _set_center_freq_from_internals_allchans(); +} + + +void usrp_block_impl::dispatch_msg_cmd_handler(const pmt::pmt_t &cmd, const pmt::pmt_t &val, int chan, pmt::pmt_t &msg) +{ + if (_msg_cmd_handlers.has_key(cmd)) { + _msg_cmd_handlers[cmd](val, chan, msg); + } +} + +void usrp_block_impl::register_msg_cmd_handler(const pmt::pmt_t &cmd, cmd_handler_t handler) +{ + _msg_cmd_handlers[cmd] = handler; +} + +void usrp_block_impl::_update_curr_tune_req(::uhd::tune_request_t &tune_req, int chan) +{ + if (chan == -1) { + for (size_t i = 0; i < _nchan; i++) { + _update_curr_tune_req(tune_req, int(i)); + return; } - } catch (pmt::wrong_type &e) { - GR_LOG_ALERT(d_logger, boost::format("Received command '%s' with invalid command value: %s") % command % cmd_value); } + + if (tune_req.target_freq != _curr_tune_req[chan].target_freq || + tune_req.rf_freq_policy != _curr_tune_req[chan].rf_freq_policy || + tune_req.rf_freq != _curr_tune_req[chan].rf_freq || + tune_req.dsp_freq != _curr_tune_req[chan].dsp_freq || + tune_req.dsp_freq_policy != _curr_tune_req[chan].dsp_freq_policy + ) { + _curr_tune_req[chan] = tune_req; + _chans_to_tune.set(chan); + } +} + +// Default handlers: +void usrp_block_impl::_cmd_handler_freq(const pmt::pmt_t &freq_, int chan, const pmt::pmt_t &msg) +{ + double freq = pmt::to_double(freq_); + ::uhd::tune_request_t new_tune_reqest(freq); + if (pmt::dict_has_key(msg, CMD_LO_OFFSET_KEY)) { + double lo_offset = pmt::to_double(pmt::dict_ref(msg, CMD_LO_OFFSET_KEY, pmt::PMT_NIL)); + new_tune_reqest = ::uhd::tune_request_t(freq, lo_offset); + } + + _update_curr_tune_req(new_tune_reqest, chan); +} + +void usrp_block_impl::_cmd_handler_looffset(const pmt::pmt_t &lo_offset, int chan, const pmt::pmt_t &msg) +{ + if (pmt::dict_has_key(msg, CMD_FREQ_KEY)) { + // Then it's already taken care of + return; + } + + double lo_offs = pmt::to_double(lo_offset); + ::uhd::tune_request_t new_tune_request = _curr_tune_req[chan]; + new_tune_request.rf_freq = new_tune_request.target_freq + lo_offs; + new_tune_request.rf_freq_policy = ::uhd::tune_request_t::POLICY_MANUAL; + new_tune_request.dsp_freq_policy = ::uhd::tune_request_t::POLICY_AUTO; + + _update_curr_tune_req(new_tune_request, chan); } + +void usrp_block_impl::_cmd_handler_gain(const pmt::pmt_t &gain_, int chan, const pmt::pmt_t &msg) +{ + double gain = pmt::to_double(gain_); + if (chan == -1) { + for (size_t i = 0; i < _nchan; i++) { + set_gain(gain, i); + } + return; + } + + set_gain(gain, chan); +} + +void usrp_block_impl::_cmd_handler_antenna(const pmt::pmt_t &ant, int chan, const pmt::pmt_t &msg) +{ + const std::string antenna(pmt::symbol_to_string(ant)); + if (chan == -1) { + for (size_t i = 0; i < _nchan; i++) { + set_antenna(antenna, i); + } + return; + } + + set_antenna(antenna, chan); +} + +void usrp_block_impl::_cmd_handler_rate(const pmt::pmt_t &rate_, int, const pmt::pmt_t &) +{ + const double rate = pmt::to_double(rate_); + set_samp_rate(rate); +} + +void usrp_block_impl::_cmd_handler_tune(const pmt::pmt_t &tune, int chan, const pmt::pmt_t &msg) +{ + double freq = pmt::to_double(pmt::car(tune)); + double lo_offset = pmt::to_double(pmt::cdr(tune)); + ::uhd::tune_request_t new_tune_reqest(freq, lo_offset); + _update_curr_tune_req(new_tune_reqest, chan); +} + +void usrp_block_impl::_cmd_handler_bw(const pmt::pmt_t &bw, int chan, const pmt::pmt_t &msg) +{ + double bandwidth = pmt::to_double(bw); + if (chan == -1) { + for (size_t i = 0; i < _nchan; i++) { + set_bandwidth(bandwidth, i); + } + return; + } + + set_bandwidth(bandwidth, chan); +} + +void usrp_block_impl::_cmd_handler_lofreq(const pmt::pmt_t &lofreq, int chan, const pmt::pmt_t &msg) +{ + if (chan == -1) { + for (size_t i = 0; i < _nchan; i++) { + _cmd_handler_lofreq(lofreq, int(i), msg); + } + return; + } + + ::uhd::tune_request_t new_tune_request = _curr_tune_req[chan]; + new_tune_request.rf_freq = pmt::to_double(lofreq); + if (pmt::dict_has_key(msg, CMD_DSP_FREQ_KEY)) { + new_tune_request.dsp_freq = pmt::to_double(pmt::dict_ref(msg, CMD_DSP_FREQ_KEY, pmt::PMT_NIL)); + } + new_tune_request.rf_freq_policy = ::uhd::tune_request_t::POLICY_MANUAL; + new_tune_request.dsp_freq_policy = ::uhd::tune_request_t::POLICY_MANUAL; + + _update_curr_tune_req(new_tune_request, chan); +} + +void usrp_block_impl::_cmd_handler_dspfreq(const pmt::pmt_t &dspfreq, int chan, const pmt::pmt_t &msg) +{ + if (pmt::dict_has_key(msg, CMD_LO_FREQ_KEY)) { + // Then it's already dealt with + return; + } + + if (chan == -1) { + for (size_t i = 0; i < _nchan; i++) { + _cmd_handler_dspfreq(dspfreq, int(i), msg); + } + return; + } + + ::uhd::tune_request_t new_tune_request = _curr_tune_req[chan]; + new_tune_request.dsp_freq = pmt::to_double(dspfreq); + new_tune_request.rf_freq_policy = ::uhd::tune_request_t::POLICY_MANUAL; + new_tune_request.dsp_freq_policy = ::uhd::tune_request_t::POLICY_MANUAL; + + _update_curr_tune_req(new_tune_request, chan); +} + diff --git a/gr-uhd/lib/usrp_block_impl.h b/gr-uhd/lib/usrp_block_impl.h index 1ca613d1dc..5b38b51fa5 100644 --- a/gr-uhd/lib/usrp_block_impl.h +++ b/gr-uhd/lib/usrp_block_impl.h @@ -27,6 +27,15 @@ #include <pmt/pmt.h> #include <uhd/usrp/multi_usrp.hpp> #include <boost/dynamic_bitset.hpp> +#include <boost/bind.hpp> + +#define SET_CENTER_FREQ_FROM_INTERNALS(usrp_class, tune_method) \ + ::uhd::tune_result_t \ + usrp_class::_set_center_freq_from_internals(size_t chan) \ + { \ + _chans_to_tune.reset(chan); \ + return _dev->tune_method(_curr_tune_req[chan], _stream_args.channels[chan]); \ + } namespace gr { namespace uhd { @@ -35,6 +44,7 @@ namespace gr { { public: typedef boost::function< ::uhd::sensor_value_t (const std::string&)> get_sensor_fn_t; + typedef boost::function<void(const pmt::pmt_t &, int, const pmt::pmt_t &)> cmd_handler_t; static const double LOCK_TIMEOUT; @@ -91,6 +101,25 @@ namespace gr { //! Receives commands and handles them void msg_handler_command(pmt::pmt_t msg); + //! For a given argument, call the associated handler, or if none exists, + // show a warning through the logging interface. + void dispatch_msg_cmd_handler(const pmt::pmt_t &cmd, const pmt::pmt_t &val, int chan, pmt::pmt_t &msg); + + //! Register a new handler for command key \p cmd + void register_msg_cmd_handler(const pmt::pmt_t &cmd, cmd_handler_t handler); + + + // Default handlers + void _cmd_handler_freq(const pmt::pmt_t &freq, int chan, const pmt::pmt_t &msg); + void _cmd_handler_looffset(const pmt::pmt_t &lo_offset, int chan, const pmt::pmt_t &msg); + void _cmd_handler_gain(const pmt::pmt_t &gain, int chan, const pmt::pmt_t &msg); + void _cmd_handler_antenna(const pmt::pmt_t &ant, int chan, const pmt::pmt_t &msg); + void _cmd_handler_rate(const pmt::pmt_t &rate, int chan, const pmt::pmt_t &msg); + void _cmd_handler_tune(const pmt::pmt_t &tune, int chan, const pmt::pmt_t &msg); + void _cmd_handler_bw(const pmt::pmt_t &bw, int chan, const pmt::pmt_t &msg); + void _cmd_handler_lofreq(const pmt::pmt_t &lofreq, int chan, const pmt::pmt_t &msg); + void _cmd_handler_dspfreq(const pmt::pmt_t &dspfreq, int chan, const pmt::pmt_t &msg); + /********************************************************************** * Helpers **********************************************************************/ @@ -98,6 +127,9 @@ namespace gr { void _update_stream_args(const ::uhd::stream_args_t &stream_args_); + // should be const, doesn't work though 'cause missing operator=() for tune_request_t + void _update_curr_tune_req(::uhd::tune_request_t &tune_req, int chan); + /*! \brief Wait until a timeout or a sensor returns 'locked'. * * If a given sensor is not found, this still returns 'true', so we don't throw @@ -180,16 +212,13 @@ namespace gr { /****** Command interface related **********/ //! Stores a list of commands for later execution std::vector<pmt::pmt_t> _pending_cmds; - //! Stores the last value we told the USRP to tune to for every channel + //! Shadows the last value we told the USRP to tune to for every channel // (this is not necessarily the true value the USRP is currently tuned to!). - // We could theoretically ask the device, but during streaming, we want to minimize - // communication with the USRP. - std::vector<double> _curr_freq; - //! Stores the last value we told the USRP to have the LO offset for every channel. - std::vector<double> _curr_lo_offset; - //! Stores the last gain value we told the USRP to have for every channel. - std::vector<double> _curr_gain; + std::vector< ::uhd::tune_request_t > _curr_tune_req; boost::dynamic_bitset<> _chans_to_tune; + + //! Stores the individual command handlers + ::uhd::dict<pmt::pmt_t, cmd_handler_t> _msg_cmd_handlers; }; } /* namespace uhd */ diff --git a/gr-uhd/lib/usrp_sink_impl.cc b/gr-uhd/lib/usrp_sink_impl.cc index 98d54866fe..8f2d2ad4a3 100644 --- a/gr-uhd/lib/usrp_sink_impl.cc +++ b/gr-uhd/lib/usrp_sink_impl.cc @@ -132,29 +132,12 @@ namespace gr { usrp_sink_impl::set_center_freq(const ::uhd::tune_request_t tune_request, size_t chan) { - _curr_freq[chan] = tune_request.target_freq; - if (tune_request.rf_freq_policy == ::uhd::tune_request_t::POLICY_MANUAL) { - _curr_lo_offset[chan] = tune_request.rf_freq - tune_request.target_freq; - } else { - _curr_lo_offset[chan] = 0.0; - } + _curr_tune_req[chan] = tune_request; chan = _stream_args.channels[chan]; return _dev->set_tx_freq(tune_request, chan); } - ::uhd::tune_result_t - usrp_sink_impl::_set_center_freq_from_internals(size_t chan) - { - _chans_to_tune[chan] = false; - if (_curr_lo_offset[chan] == 0.0) { - return _dev->set_tx_freq(_curr_freq[chan], _stream_args.channels[chan]); - } else { - return _dev->set_tx_freq( - ::uhd::tune_request_t(_curr_freq[chan], _curr_lo_offset[chan]), - _stream_args.channels[chan] - ); - } - } + SET_CENTER_FREQ_FROM_INTERNALS(usrp_sink_impl, set_tx_freq); double usrp_sink_impl::get_center_freq(size_t chan) @@ -173,7 +156,6 @@ namespace gr { void usrp_sink_impl::set_gain(double gain, size_t chan) { - _curr_gain[chan] = gain; chan = _stream_args.channels[chan]; return _dev->set_tx_gain(gain, chan); } @@ -183,7 +165,6 @@ namespace gr { const std::string &name, size_t chan) { - _curr_gain[chan] = gain; chan = _stream_args.channels[chan]; return _dev->set_tx_gain(gain, name, chan); } @@ -433,7 +414,7 @@ namespace gr { // Go through tag list until something indicates the end of a burst. bool found_time_tag = false; bool found_eob = false; - // For commands that are in the middle in the burst: + // For commands that are in the middle of the burst: std::vector<pmt::pmt_t> commands_in_burst; // Store the command uint64_t in_burst_cmd_offset = 0; // Store its position BOOST_FOREACH(const tag_t &my_tag, _tags) { @@ -449,7 +430,7 @@ namespace gr { * * This includes: * - tx_time - * - tx_command + * - tx_command TODO should also work end-of-burst * - tx_sob * - length tags * @@ -461,6 +442,7 @@ namespace gr { max_count = my_tag_count; break; } + // TODO set the command time from the sample time msg_handler_command(value); } @@ -516,12 +498,16 @@ namespace gr { else if (pmt::equal(key, FREQ_KEY) && my_tag_count == samp0_count) { // If it's on the first sample, immediately do the tune: GR_LOG_DEBUG(d_debug_logger, boost::format("Received tx_freq on start of burst.")); - msg_handler_command(pmt::cons(pmt::mp("freq"), value)); + pmt::pmt_t freq_cmd = pmt::make_dict(); + freq_cmd = pmt::dict_add(freq_cmd, pmt::mp("freq"), value); + msg_handler_command(freq_cmd); } else if(pmt::equal(key, FREQ_KEY)) { // If it's not on the first sample, queue this command and only tx until here: GR_LOG_DEBUG(d_debug_logger, boost::format("Received tx_freq mid-burst.")); - commands_in_burst.push_back(pmt::cons(pmt::mp("freq"), value)); + pmt::pmt_t freq_cmd = pmt::make_dict(); + freq_cmd = pmt::dict_add(freq_cmd, pmt::mp("freq"), value); + commands_in_burst.push_back(freq_cmd); max_count = my_tag_count + 1; in_burst_cmd_offset = my_tag_count; } @@ -552,7 +538,7 @@ namespace gr { // until before the tag, so it will be on the first sample of the next run. if (not commands_in_burst.empty()) { if (not found_eob) { - // If it's in the middle of a burst, only send() until before the tag + // ...then it's in the middle of a burst, only send() until before the tag max_count = in_burst_cmd_offset; } else if (in_burst_cmd_offset < max_count) { BOOST_FOREACH(const pmt::pmt_t &cmd_pmt, commands_in_burst) { diff --git a/gr-uhd/lib/usrp_source_impl.cc b/gr-uhd/lib/usrp_source_impl.cc index d2d12c2eb1..6f0283e71f 100644 --- a/gr-uhd/lib/usrp_source_impl.cc +++ b/gr-uhd/lib/usrp_source_impl.cc @@ -145,19 +145,7 @@ namespace gr { return res; } - ::uhd::tune_result_t - usrp_source_impl::_set_center_freq_from_internals(size_t chan) - { - _chans_to_tune[chan] = false; - if (_curr_lo_offset[chan] == 0.0) { - return _dev->set_rx_freq(_curr_freq[chan], _stream_args.channels[chan]); - } else { - return _dev->set_rx_freq( - ::uhd::tune_request_t(_curr_freq[chan], _curr_lo_offset[chan]), - _stream_args.channels[chan] - ); - } - } + SET_CENTER_FREQ_FROM_INTERNALS(usrp_source_impl, set_rx_freq); double usrp_source_impl::get_center_freq(size_t chan) |