diff options
29 files changed, 2741 insertions, 249 deletions
| diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 6b342c2d3..1559bd6bf 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -70,6 +70,8 @@ SET(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING "")  IF(CMAKE_COMPILER_IS_GNUCXX)      ADD_DEFINITIONS(-Wall)      ADD_DEFINITIONS(-Wextra) +    ADD_DEFINITIONS(-Wsign-compare) +    #ADD_DEFINITIONS(-Wconversion)      #ADD_DEFINITIONS(-pedantic)      #ADD_DEFINITIONS(-ansi)      IF(NOT WIN32) diff --git a/host/README.txt b/host/README.txt index 64d0307ed..cc7a501b4 100644 --- a/host/README.txt +++ b/host/README.txt @@ -25,6 +25,7 @@ WBX + Simple GDB  DBSRX  DBSRX2  TVRX +TVRX2  SBX  ############################################### diff --git a/host/docs/dboards.rst b/host/docs/dboards.rst index 42965b32f..959a1b300 100644 --- a/host/docs/dboards.rst +++ b/host/docs/dboards.rst @@ -258,6 +258,31 @@ Receive Gains:  Bandwidth: 6MHz +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +TVRX2 +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The TVRX2 board has 2 real-mode subdevices. +It is operated at a low IF. + +Receive Subdevices: +* **Subdevice RX1:** real signal on antenna J100 +* **Subdevice RX2:** real signal on antenna J140 + +Note: The TVRX2 has always-on AGC, the software controllable gain is the +final gain stage which controls the AGC set-point for output to ADC. + +Receive Gains: + +* **IF**, Range: 0.0-30.0dB + +Bandwidth: 1.7MHz, 6MHz, 7MHz, 8MHz, 10MHz + +Sensors: + +* **lo_locked**: boolean for LO lock state +* **rssi**: float for measured RSSI in dBm +* **temperature**: float for measured temperature in degC +  ------------------------------------------------------------------------  Daughterboard Modifications  ------------------------------------------------------------------------ diff --git a/host/docs/usrp_e1xx.rst b/host/docs/usrp_e1xx.rst index 036d2c02c..fcaa57716 100644 --- a/host/docs/usrp_e1xx.rst +++ b/host/docs/usrp_e1xx.rst @@ -35,12 +35,7 @@ To use the 61.44MHz clock rate, the USRP embedded will require two jumpers to be  * J16 is a two pin header, remove the jumper (or leave it on pin1 only)  * J15 is a three pin header, move the jumper to (pin1, pin2) -Then run the following commands to record the setting into the EEPROM: -:: - -    cd <install-path>/share/uhd/utils -    ./usrp_burn_mb_eeprom --key=mcr --val=61.44e6 - +**Note:** See instructions below to communicate the desired clock rate into the UHD.  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  Set other rates - uses internal VCO @@ -50,11 +45,13 @@ To use other clock rates, the jumpers will need to be in the default position.  * J16 is a two pin header, move the jumper to (pin1, pin2)  * J15 is a three pin header, move the jumper to (pin2, pin3) -Then run the following commands to record the setting into the EEPROM: +To communicate the desired clock rate into the UHD, +specify the a special device address argument, +where the key is "master_clock_rate" and the value is a rate in Hz. +Example:  :: -    cd <install-path>/share/uhd/utils -    ./usrp_burn_mb_eeprom --key=mcr --val=<rate> +    uhd_usrp_probe --args="master_clock_rate=52e6"  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  Clock rate recovery - unbricking diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index 092028d09..f80c738aa 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -21,9 +21,16 @@  #include <uhd/config.hpp>  #include <boost/utility.hpp>  #include <boost/shared_ptr.hpp> +#include <boost/intrusive_ptr.hpp>  namespace uhd{ namespace transport{ +    //! Create smart pointer to a reusable managed buffer +    template <typename T> UHD_INLINE boost::intrusive_ptr<T> make_managed_buffer(T *p){ +        p->_ref_count = 1; //reset the count to 1 reference +        return boost::intrusive_ptr<T>(p, false); +    } +      /*!       * A managed receive buffer:       * Contains a reference to transport-managed memory, @@ -31,7 +38,7 @@ namespace uhd{ namespace transport{       */      class UHD_API managed_recv_buffer{      public: -        typedef boost::shared_ptr<managed_recv_buffer> sptr; +        typedef boost::intrusive_ptr<managed_recv_buffer> sptr;          /*!           * Signal to the transport that we are done with the buffer. @@ -59,8 +66,18 @@ namespace uhd{ namespace transport{      private:          virtual const void *get_buff(void) const = 0;          virtual size_t get_size(void) const = 0; + +    public: int _ref_count;      }; +    UHD_INLINE void intrusive_ptr_add_ref(managed_recv_buffer *p){ +        ++(p->_ref_count); +    } + +    UHD_INLINE void intrusive_ptr_release(managed_recv_buffer *p){ +        if (--(p->_ref_count) == 0) p->release(); +    } +      /*!       * A managed send buffer:       * Contains a reference to transport-managed memory, @@ -68,7 +85,7 @@ namespace uhd{ namespace transport{       */      class UHD_API managed_send_buffer{      public: -        typedef boost::shared_ptr<managed_send_buffer> sptr; +        typedef boost::intrusive_ptr<managed_send_buffer> sptr;          /*!           * Signal to the transport that we are done with the buffer. @@ -97,8 +114,18 @@ namespace uhd{ namespace transport{      private:          virtual void *get_buff(void) const = 0;          virtual size_t get_size(void) const = 0; + +    public: int _ref_count;      }; +    UHD_INLINE void intrusive_ptr_add_ref(managed_send_buffer *p){ +        ++(p->_ref_count); +    } + +    UHD_INLINE void intrusive_ptr_release(managed_send_buffer *p){ +        if (--(p->_ref_count) == 0) p->commit(0); +    } +      /*!       * A zero-copy interface for transport objects.       * Provides a way to get send and receive buffers diff --git a/host/include/uhd/utils/log.hpp b/host/include/uhd/utils/log.hpp index 8d8f42fd0..7f83fd2a9 100644 --- a/host/include/uhd/utils/log.hpp +++ b/host/include/uhd/utils/log.hpp @@ -38,7 +38,7 @@   * (in other words, as often or less often than the current log level)   * are recorded into the log file. All other messages are sent to null.   * - * The default log level is "regular", but can be overridden: + * The default log level is "never", but can be overridden:   *  - at compile time by setting the pre-processor define UHD_LOG_LEVEL.   *  - at runtime by setting the environment variable UHD_LOG_LEVEL.   * diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index fca4730d8..ebb211566 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -15,10 +15,6 @@  # along with this program.  If not, see <http://www.gnu.org/licenses/>.  # -#Creating a shared pointer itself has allocation overhead. -#Define the quick allocator to reduce fast-path overhead. -ADD_DEFINITIONS(-DBOOST_SP_USE_QUICK_ALLOCATOR) -  ########################################################################  # Helpful Macros  ######################################################################## diff --git a/host/lib/ic_reg_maps/CMakeLists.txt b/host/lib/ic_reg_maps/CMakeLists.txt index 9e1f4705e..46cf5a06a 100644 --- a/host/lib/ic_reg_maps/CMakeLists.txt +++ b/host/lib/ic_reg_maps/CMakeLists.txt @@ -92,4 +92,9 @@ LIBUHD_PYTHON_GEN_SOURCE(      ${CMAKE_CURRENT_BINARY_DIR}/tuner_4937di5_regs.hpp  ) +LIBUHD_PYTHON_GEN_SOURCE( +    ${CMAKE_CURRENT_SOURCE_DIR}/gen_tda18272hnm_regs.py +    ${CMAKE_CURRENT_BINARY_DIR}/tda18272hnm_regs.hpp +) +  UNSET(LIBUHD_PYTHON_GEN_SOURCE_DEPS) diff --git a/host/lib/ic_reg_maps/gen_tda18272hnm_regs.py b/host/lib/ic_reg_maps/gen_tda18272hnm_regs.py new file mode 100755 index 000000000..677a201de --- /dev/null +++ b/host/lib/ic_reg_maps/gen_tda18272hnm_regs.py @@ -0,0 +1,521 @@ +#!/usr/bin/env python +# +# Copyright 2010 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +######################################################################## +# Template for raw text data describing write registers +# name addr[bit range inclusive] default optional enums +######################################################################## +REGS_TMPL="""\ +######################################################################## +## Note: offsets given from perspective of data bits (excludes address) +######################################################################## +## +######################################################################## +##  ID_byte_1 (0x00) Read +######################################################################## +##reserved as 1       0x00[7]       1 +ident_14_8            0x00[0:6]     0 +######################################################################## +##  ID_byte_2 (0x01) Read +######################################################################## +ident_7_0             0x01[0:7]     0 +##~ident                ident_7_0, ident_14_8 +######################################################################## +##  ID_byte_3 (0x02) Read +######################################################################## +major_rev             0x02[4:7]     0 +minor_rev             0x02[0:3]     0 +######################################################################## +##  Thermo_byte_1 (0x03) Read +######################################################################## +##reserved            0x03[7]       0 +tm_d                  0x03[0:6]     0   ## 22-127deg C junction temp +######################################################################## +##  Thermo_byte_2 (0x04) Write +######################################################################## +##reserved            0x04[1:7]     0 +tm_on                 0x04[0]       0   sensor_off, sensor_on +######################################################################## +##  Power_state_byte_1 (0x05) Read +######################################################################## +##reserved            0x05[2:7]     0 +por                   0x05[1]       0   read, reset +lo_lock               0x05[0]       0   unlocked, locked +######################################################################## +##  Power_state_byte_2 (0x06) Read/Write ## Standby modes +######################################################################## +##reserved            0x06[4:7]     0 +sm                    0x06[3]       0   normal, standby +sm_pll                0x06[2]       0   on, off +sm_lna                0x06[1]       0   on, off +##resevered as 0      0x06[0]       0 +## (sm, sm_pll, sm_lna) only valid values are 000, 100, 110, and 111 +######################################################################## +##  Input_Power_Level_byte (0x07) Read +######################################################################## +##reserved            0x07[7]       0 +power_level           0x07[0:6]     0   ## 40dB_Vrms to 110dB_Vrms +## Trigger power level calculation with MSM_byte_1 and MSM_byte_2 +######################################################################## +##  IRQ_status (0x08) Read/Write +######################################################################## +irq_status            0x08[7]       0   cleared, set +##reserved            0x08[6]       0 +irq_xtalcal_end       0x08[5]       0   false, true +irq_rssi_end          0x08[4]       0   false, true +irq_localc_end        0x08[3]       0   false, true +irq_rfcal_end         0x08[2]       0   false, true +irq_ircal_end         0x08[1]       0   false, true +irq_rccal_end         0x08[0]       0   false, true +######################################################################## +##  IRQ_enable (0x09) Read/Write +######################################################################## +irq_enable            0x09[7]       1   false, true +##reserved            0x09[6]       0 +irq_xtalcal_enable    0x09[5]       0   false, true +irq_rssi_enable       0x09[4]       0   false, true +irq_localc_enable     0x09[3]       0   false, true +irq_rfcal_enable      0x09[2]       0   false, true +irq_ircal_enable      0x09[1]       0   false, true +irq_rccal_enable      0x09[0]       0   false, true +######################################################################## +##  IRQ_clear (0x0a) Read/Write +######################################################################## +irq_clear             0x0a[7]       0   false, true +##reserved            0x0a[6]       0 +irq_xtalcal_clear     0x0a[5]       0   false, true +irq_rssi_clear        0x0a[4]       0   false, true +irq_localc_clear      0x0a[3]       0   false, true +irq_rfcal_clear       0x0a[2]       0   false, true +irq_ircal_clear       0x0a[1]       0   false, true +irq_rccal_clear       0x0a[0]       0   false, true +######################################################################## +##  IRQ_set (0x0b) Read +######################################################################## +irq_set               0x0b[7]       0   false, true +##reserved            0x0b[6]       0 +irq_xtalcal_set       0x0b[5]       0   false, true +irq_rssi_set          0x0b[4]       0   false, true +irq_localc_set        0x0b[3]       0   false, true +irq_rfcal_set         0x0b[2]       0   false, true +irq_ircal_set         0x0b[1]       0   false, true +irq_rccal_set         0x0b[0]       0   false, true +######################################################################## +##  AGC1_byte_1 (0x0c) Read/Write +######################################################################## +lt_enable             0x0c[7]       0 +agc1_6_15db           0x0c[6]       1 +##reserved            0x0c[4:5]     0 +agc1_top              0x0c[0:3]     0 +######################################################################## +##  AGC2_byte_1 (0x0d) Read +######################################################################## +##reserved            0x0d[5:7]     0 +agc2_top              0x0d[0:4]     0xf +######################################################################## +##  AGCK_byte_1 (0x0e) Read/Write +######################################################################## +agcs_up_step_assym    0x0e[6:7]     3 +agcs_up_step          0x0e[5]       1 +pulse_shaper_disable  0x0e[4]       0   vsync_pulse, 500us_pulse +agck_step             0x0e[2:3]     0 +agck_mode             0x0e[0:1]     1   analog_tv=1, digital_tv=2 +######################################################################## +##  RF_AGC_byte_1 (0x0f) Read/Write +######################################################################## +pd_rfagc_adapt        0x0f[7]       0   on, off +rfagc_adapt_top       0x0f[5:6]     0 +rfagc_low_bw          0x0f[4]       1 +rf_atten_3db          0x0f[3]       0   0db, 3db ## FIXME +agc3_top              0x0f[0:2]     1 +######################################################################## +##  IR_MIXER_byte_1 (0x10) Read/Write +######################################################################## +##reserved            0x10[4:7]     0 +agc4_top              0x10[0:3]     1 +######################################################################## +##  AGC5_byte_1 (0x11) Read/Write +######################################################################## +##reserved            0x11[7]       0 +agcs_do_step_assym    0x11[5:6]     2 +agc5_hpf              0x11[4]       1   off, on +agc5_top              0x11[0:3]     1 +######################################################################## +##  IF_AGC_byte (0x12) Read/Write +######################################################################## +##reserved            0x12[3:7]     0 +if_level              0x12[0:2]     0   0_5vpp=7, 0_6vpp=6, 0_7vpp=5, 0_85vpp=4, 0_8vpp=3, 1_0vpp=2, 1_25vpp=1, 2_0vpp=0 +######################################################################## +##  IF_byte_1 (0x13) Read/Write +######################################################################## +if_hp_fc              0x13[6:7]     0   0_4mhz, 0_85mhz, 1_0mhz, 1_5mhz +if_atsc_notch         0x13[5]       0   off, on +lp_fc_offset          0x13[3:4]     0   0_percent, m4_percent, m8_percent, forbidden +lp_fc                 0x13[0:2]     3   1_7mhz=4, 6_0mhz=0, 7_0mhz=1, 8_0mhz=2, 10_0mhz=3 +######################################################################## +##  Reference_byte (0x14) Read/Write +######################################################################## +i2c_clock_mode        0x14[7]       0 +digital_clock         0x14[6]       1   spread_off, spread_on +##reserved            0x14[5]       0 +xtalosc_anareg_en     0x14[4]       0 +##reserved            0x14[2:3]     0 +xtout                 0x14[0:1]     0   no=0, 16mhz=3 +######################################################################## +##  IF_Frequency_byte (0x15) Read/Write +######################################################################## +if_freq               0x15[0:7]     0   ## IF frequency = if_freq*50 (kHz) +######################################################################## +##  RF_Frequency_byte_1 (0x16) Read/Write +######################################################################## +##reserved            0x16[4:7]     0 +rf_freq_19_16         0x16[0:3]     0 +######################################################################## +##  RF_Frequency_byte_2 (0x17) Read/Write +######################################################################## +rf_freq_15_8          0x17[0:7]     0 +######################################################################## +##  RF_Frequency_byte_3 (0x18) Read/Write +######################################################################## +rf_freq_7_0           0x18[0:7]     0 +~rf_freq              rf_freq_7_0, rf_freq_15_8, rf_freq_19_16 +## RF Frequency = rf_freq (kHz) +######################################################################## +##  MSM_byte_1 (0x19) Read/Write +######################################################################## +rssi_meas             0x19[7]       0 +rf_cal_av             0x19[6]       0 +rf_cal                0x19[5]       0 +ir_cal_loop           0x19[4]       0 +ir_cal_image          0x19[3]       0 +ir_cal_wanted         0x19[2]       0 +rc_cal                0x19[1]       0 +calc_pll              0x19[0]       0 +######################################################################## +##  MSM_byte_2 (0x1a) Read +######################################################################## +##reserved            0x1a[2:7]     0 +xtalcal_launch        0x1a[1]       0 +msm_launch            0x1a[0]       0 +######################################################################## +##  PSM_byte_1 (0x1b) Read +######################################################################## +psm_agc1              0x1b[6:7]     0 +psm_stob              0x1b[5]       0 +psmrfpoly             0x1b[4]       0 +psm_mixer             0x1b[3]       0 +psm_ifpoly            0x1b[2]       0 +psm_lodriver          0x1b[0:1]     0 +######################################################################## +##  DCC_byte_1 (0x1c) Read +######################################################################## +dcc_bypass            0x1c[7]       0 +dcc_slow              0x1c[6]       0 +dcc_psm               0x1c[5]       0 +##reserved            0x1c[0:4]     0 +######################################################################## +##  FLO_Max_byte (0x1d) Read +######################################################################## +##reserved            0x1d[6:7]     0 +fmax_lo               0x1d[0:5]     0xA +######################################################################## +##  IR_Cal_byte_1 (0x1e) Read +######################################################################## +ir_loop               0x1e[6:7]     0 +ir_target             0x1e[3:5]     0 +ir_gstep              0x1e[0:2]     0 +######################################################################## +##  IR_Cal_byte_2 (0x1f) Read +######################################################################## +ir_corr_boost         0x1f[7]       0 +ir_freqlow_sel        0x1f[6]       0 +ir_mode_ram_store     0x1f[5]       0 +ir_freqlow            0x1f[0:4]     0 +######################################################################## +##  IR_Cal_byte_3 (0x20) Read +######################################################################## +##reserved            0x20[5:7]     0 +ir_freqmid            0x20[0:4]     0 +######################################################################## +##  IR_Cal_byte_4 (0x21) Read +######################################################################## +##reserved            0x21[5:7]     0 +coarse_ir_freqhigh    0x21[4]       0 +ir_freqhigh           0x21[0:3]     0 +######################################################################## +##  Vsync_Mgt_byte (0x22) Read +######################################################################## +pd_vsync_mgt          0x22[7]       0 +pd_ovld               0x22[6]       0 +pd_udld               0x22[5]       0 +agc_ovld_top          0x22[2:4]     0 +agc_ovld_timer        0x22[0:1]     0 +######################################################################## +##  IR_MIXER_byte_2 (0x23) Read/Write +######################################################################## +ir_mixer_loop_off     0x23[7]       0 +ir_mixer_do_step      0x23[5:6]     0 +##reserved            0x23[2:4]     0 +hi_pass               0x23[1]       0   disable, enable ## FIXME Logic Unclear +if_notch              0x23[0]       1   on, off +######################################################################## +##  AGC1_byte_2 (0x24) Read +######################################################################## +agc1_loop_off         0x24[7]       0 +agc1_do_step          0x24[5:6]     2 +force_agc1_gain       0x24[4]       0 +agc1_gain             0x24[0:3]     8 +######################################################################## +##  AGC5_byte_2 (0x25) Read +######################################################################## +agc5_loop_off         0x25[7]       0 +agc5_do_step          0x25[5:6]     0 +##reserved            0x25[4]       0 +force_agc5_gain       0x25[3]       0 +##reserved            0x25[2]       0 +agc5_gain             0x25[0:1]     2 +######################################################################## +##  RF_Cal_byte_1 (0x26) Read +######################################################################## +rfcal_offset_cprog0   0x26[6:7]     0 +rfcal_freq0           0x26[4:5]     0 +rfcal_offset_cprog1   0x26[2:3]     0 +rfcal_freq1           0x26[0:1]     0 +######################################################################## +##  RF_Cal_byte_2 (0x27) Read +######################################################################## +rfcal_offset_cprog2   0x27[6:7]     0 +rfcal_freq2           0x27[4:5]     0 +rfcal_offset_cprog3   0x27[2:3]     0 +rfcal_freq3           0x27[0:1]     0 +######################################################################## +##  RF_Cal_byte_3 (0x28) Read +######################################################################## +rfcal_offset_cprog4   0x28[6:7]     0 +rfcal_freq4           0x28[4:5]     0 +rfcal_offset_cprog5   0x28[2:3]     0 +rfcal_freq5           0x28[0:1]     0 +######################################################################## +##  RF_Cal_byte_4 (0x29) Read +######################################################################## +rfcal_offset_cprog6   0x29[6:7]     0 +rfcal_freq6           0x29[4:5]     0 +rfcal_offset_cprog7   0x29[2:3]     0 +rfcal_freq7           0x29[0:1]     0 +######################################################################## +##  RF_Cal_byte_5 (0x2a) Read +######################################################################## +rfcal_offset_cprog8   0x2a[6:7]     0 +rfcal_freq8           0x2a[4:5]     0 +rfcal_offset_cprog9   0x2a[2:3]     0 +rfcal_freq9           0x2a[0:1]     0 +######################################################################## +##  RF_Cal_byte_6 (0x2b) Read +######################################################################## +rfcal_offset_cprog10  0x2b[6:7]     0 +rfcal_freq10          0x2b[4:5]     0 +rfcal_offset_cprog11  0x2b[2:3]     0 +rfcal_freq11          0x2b[0:1]     0 +######################################################################## +##  RF_Filter_byte_1 (0x2c) Read +######################################################################## +rf_filter_bypass      0x2c[7]       0 +##reserved as 0       0x2c[6]       0 +agc2_loop_off         0x2c[5]       0 +force_agc2_gain       0x2c[4]       0 +rf_filter_gv          0x2c[2:3]     2 +rf_filter_band        0x2c[0:1]     0 +######################################################################## +##  RF_Filter_byte_2 (0x2d) Read +######################################################################## +rf_filter_cap         0x2d[0:7]     0 +######################################################################## +##  RF_Filter_byte_3 (0x2e) Read +######################################################################## +agc2_do_step          0x2e[6:7]     2 +gain_taper            0x2e[0:5]     0 +######################################################################## +##  RF_Band_Pass_Filter_byte (0x2f) Read +######################################################################## +rf_bpf_bypass         0x2f[7]       0 +##reserved            0x2f[3:6]     0 +rf_bpf                0x2f[0:2]     0 +######################################################################## +##  CP_Current_byte (0x30) Read +######################################################################## +##reserved            0x30[7]       0 +n_cp_current          0x30[0:6]     0x68 +######################################################################## +##  AGC_Det_Out_byte (0x31) Read +######################################################################## +up_agc5               0x31[7]       0 +do_agc5               0x31[6]       0 +up_agc4               0x31[5]       0 +do_agc4               0x31[4]       0 +up_agc2               0x31[3]       0 +do_agc2               0x31[2]       0 +up_agc1               0x31[1]       0 +do_agc1               0x31[0]       0 +######################################################################## +##  RF_AGC_Gain_byte_1 (0x32) Read +######################################################################## +#set $lna_gain_names = ', '.join(map(lambda x: {0: '', 1: 'm'}[3*x-12 < 0] + str(abs(3*x-12)) + 'db=' + str(x), range(0,10))) +##reserved            0x32[6:7]     0 +agc2_gain_read        0x32[4:5]     3   m11db, m8db, m5db, m2db +agc1_gain_read        0x32[0:3]     9   $lna_gain_names +######################################################################## +##  RF_AGC_Gain_byte_2 (0x33) Read +######################################################################## +#set $top_agc3_read_names = ', '.join(map(lambda x: str(int(round(1.92*x+94))) + 'dbuvrms=' + str(x), range(0,8))) +##reserved            0x33[3:7]     0 +top_agc3_read         0x33[0:2]     0   $top_agc3_read_names +######################################################################## +##  IF_AGC_Gain_byte (0x34) Read +######################################################################## +#set $lpf_gain_names = ', '.join(map(lambda x: str(3*x) + 'db=' + str(x), range(0,4))) +#set $ir_mixer_names = ', '.join(map(lambda x: str(3*x+2) + 'db=' + str(x), range(0,5))) +##reserved            0x34[5:7]     0 +agc5_gain_read        0x34[3:4]     3   $lpf_gain_names +agc4_gain_read        0x34[0:2]     4   $ir_mixer_names +######################################################################## +##  Power_byte_1 (0x35) Read +######################################################################## +rssi                  0x35[0:7]     0 +######################################################################## +##  Power_byte_2 (0x36) Read +######################################################################## +##reserved            0x36[6:7]     0 +rssi_av               0x36[5]       0 +##reserved            0x36[4]       0 +rssi_cap_reset_en     0x36[3]       1 +rssi_cap_val          0x36[2]       1 +rssi_ck_speed         0x36[1]       0 +rssi_dicho_not        0x36[0]       1 +######################################################################## +##  Misc_byte_1 (0x37) Read/Write +######################################################################## +rfcal_phi2            0x37[6:7]     1 +dds_polarity          0x37[5]       0 +rfcal_deltagain       0x37[1:4]     1 +irq_polarity          0x37[0]       0   raised_vcc, raised_low +######################################################################## +##  rfcal_log_1 (0x38) Read +######################################################################## +rfcal_log_1           0x38[0:7]     0 +######################################################################## +##  rfcal_log_2 (0x39) Read +######################################################################## +rfcal_log_2           0x39[0:7]     0 +######################################################################## +##  rfcal_log_3 (0x3a) Read +######################################################################## +rfcal_log_3           0x3a[0:7]     0 +######################################################################## +##  rfcal_log_4 (0x3b) Read +######################################################################## +rfcal_log_4           0x3b[0:7]     0 +######################################################################## +##  rfcal_log_5 (0x3c) Read +######################################################################## +rfcal_log_5           0x3c[0:7]     0 +######################################################################## +##  rfcal_log_6 (0x3d) Read +######################################################################## +rfcal_log_6           0x3d[0:7]     0 +######################################################################## +##  rfcal_log_7 (0x3e) Read +######################################################################## +rfcal_log_7           0x3e[0:7]     0 +######################################################################## +##  rfcal_log_8 (0x3f) Read +######################################################################## +rfcal_log_8           0x3f[0:7]     0 +######################################################################## +##  rfcal_log_9 (0x40) Read +######################################################################## +rfcal_log_9           0x40[0:7]     0 +######################################################################## +##  rfcal_log_10 (0x41) Read +######################################################################## +rfcal_log_10          0x41[0:7]     0 +######################################################################## +##  rfcal_log_11 (0x42) Read +######################################################################## +rfcal_log_11          0x42[0:7]     0 +######################################################################## +##  rfcal_log_12 (0x43) Read +######################################################################## +rfcal_log_12          0x43[0:7]     0 +## +## +######################################################################## +## FORBIDDEN ACCESS to 0x50-0x67 and 0xFE-0xFF +######################################################################## +######################################################################## +##  xtal_cal_dac (0x65) Write +######################################################################## +magic                 0x43[7]       1   untouched, xtal_cal_dac +""" + +######################################################################## +# Template for methods in the body of the struct +######################################################################## +BODY_TMPL="""\ +boost::uint8_t get_reg(boost::uint8_t addr){ +    boost::uint8_t reg = 0; +    switch(addr){ +    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) +    case $addr: +        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) +        reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); +        #end for +        break; +    #end for +    } +    return boost::uint8_t(reg); +} + +void set_reg(boost::uint8_t addr, boost::uint8_t reg){ +    switch(addr){ +    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) +    case $addr: +        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) +        $reg.get_name() = $(reg.get_type())((reg >> $reg.get_shift()) & $reg.get_mask()); +        #end for +        break; +    #end for +    } +} +""" + +SPLIT_REGS_HELPER_TMPL="""\ +#for $divname in ['n','f'] +void set_$(divname)_divider(boost::uint32_t $divname){ +    #for $regname in sorted(map(lambda r: r.get_name(), filter(lambda r: r.get_name().find(divname + '_divider') == 0, $regs))) +    #end for +} +#end for +""" + +if __name__ == '__main__': +    import common; common.generate( +        name='tda18272hnm_regs', +        regs_tmpl=REGS_TMPL, +        body_tmpl=BODY_TMPL, +        file=__file__, +    ) diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index d4cfab422..28bea978b 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -73,14 +73,10 @@ public:      sptr get_new(void){          _expired = false; -        return sptr(this, &libusb_zero_copy_mrb::fake_deleter); +        return make_managed_buffer(this);      }  private: -    static void fake_deleter(void *obj){ -        static_cast<libusb_zero_copy_mrb *>(obj)->release(); -    } -      const void *get_buff(void) const{return _lut->buffer;}      size_t get_size(void) const{return _lut->actual_length;} @@ -108,14 +104,10 @@ public:      sptr get_new(void){          _expired = false; -        return sptr(this, &libusb_zero_copy_msb::fake_deleter); +        return make_managed_buffer(this);      }  private: -    static void fake_deleter(void *obj){ -        static_cast<libusb_zero_copy_msb *>(obj)->commit(0); -    } -      void *get_buff(void) const{return _lut->buffer;}      size_t get_size(void) const{return _lut->length;} diff --git a/host/lib/transport/udp_zero_copy.cpp b/host/lib/transport/udp_zero_copy.cpp index c3ba085bf..8c97e1e99 100644 --- a/host/lib/transport/udp_zero_copy.cpp +++ b/host/lib/transport/udp_zero_copy.cpp @@ -52,16 +52,12 @@ public:      sptr get_new(size_t len){          _len = len; -        return sptr(this, &udp_zero_copy_asio_mrb::fake_deleter); +        return make_managed_buffer(this);      }      template <class T> T cast(void) const{return static_cast<T>(_mem);}  private: -    static void fake_deleter(void *obj){ -        static_cast<udp_zero_copy_asio_mrb *>(obj)->release(); -    } -      const void *get_buff(void) const{return _mem;}      size_t get_size(void) const{return _len;} @@ -90,14 +86,10 @@ public:      sptr get_new(size_t len){          _len = len; -        return sptr(this, &udp_zero_copy_asio_msb::fake_deleter); +        return make_managed_buffer(this);      }  private: -    static void fake_deleter(void *obj){ -        static_cast<udp_zero_copy_asio_msb *>(obj)->commit(0); -    } -      void *get_buff(void) const{return _mem;}      size_t get_size(void) const{return _len;} diff --git a/host/lib/usrp/dboard/CMakeLists.txt b/host/lib/usrp/dboard/CMakeLists.txt index 0eff5c4bd..c7b46e7c4 100644 --- a/host/lib/usrp/dboard/CMakeLists.txt +++ b/host/lib/usrp/dboard/CMakeLists.txt @@ -30,5 +30,6 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_CURRENT_SOURCE_DIR}/db_unknown.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/db_tvrx.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/db_dbsrx2.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/db_tvrx2.cpp  ) diff --git a/host/lib/usrp/dboard/db_tvrx2.cpp b/host/lib/usrp/dboard/db_tvrx2.cpp new file mode 100644 index 000000000..fe07a70a5 --- /dev/null +++ b/host/lib/usrp/dboard/db_tvrx2.cpp @@ -0,0 +1,1911 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +// Common IO Pins +#define REFCLOCK_DIV_MASK    ((1 << 8)|(1 << 9)|(1 << 10))    // Three GPIO lines to CPLD for Clock Divisor Selection +#define REFCLOCK_DIV8        ((1 << 8)|(1 << 9)|(1 << 10))    // GPIO to set clock div8 mode +#define REFCLOCK_DIV7        ((0 << 8)|(1 << 9)|(1 << 10))    // GPIO to set clock div7 mode +#define REFCLOCK_DIV6        ((1 << 8)|(0 << 9)|(1 << 10))    // GPIO to set clock div6 mode +#define REFCLOCK_DIV5        ((0 << 8)|(0 << 9)|(1 << 10))    // GPIO to set clock div5 mode +#define REFCLOCK_DIV4        ((1 << 8)|(1 <<9))               // GPIO to set clock div4 mode +#define REFCLOCK_DIV3        (1 <<9)                          // GPIO to set clock div3 mode +#define REFCLOCK_DIV2        (1 <<8)                          // GPIO to set clock div2 mode +#define REFCLOCK_DIV1        ((0 << 8)|(0 << 9)|(0 << 10))    // GPIO to set clock div1 mode + +// RX1 IO Pins +#define RX1_MASTERSYNC  (1 << 3)                // MASTERSYNC Signal for Slave Tuner Coordination +#define RX1_FREEZE      (1 << 2)                // FREEZE Signal for Slave Tuner Coordination +#define RX1_IRQ         (1 << 1)                // IRQ Signals TDA18272HNM State Machine Completion +#define RX1_VSYNC       (1 << 0)                // VSYNC Pulse for AGC Holdoff + +// RX2 IO Pins +#define RX2_MASTERSYNC  (1 << 7)                // MASTERSYNC Signal for Slave Tuner Coordination +#define RX2_FREEZE      (1 << 6)                // FREEZE Signal for Slave Tuner Coordination +#define RX2_IRQ         (1 << 5)                // IRQ Signals TDA18272HNM State Machine Completion +#define RX2_VSYNC       (1 << 4)                // VSYNC Pulse for AGC Holdoff + +// Pin functions +#define RX1_OUTPUT_MASK (0) +#define RX1_INPUT_MASK  (RX1_VSYNC|RX1_MASTERSYNC|RX1_FREEZE|RX1_IRQ) + +#define RX2_OUTPUT_MASK (0) +#define RX2_INPUT_MASK  (RX2_VSYNC|RX2_MASTERSYNC|RX2_FREEZE|RX2_IRQ) + +#define OUTPUT_MASK     (RX1_OUTPUT_MASK|RX2_OUTPUT_MASK|REFCLOCK_DIV_MASK) +#define INPUT_MASK      (RX1_INPUT_MASK|RX2_INPUT_MASK) + + +#include "tda18272hnm_regs.hpp" +#include <uhd/utils/static.hpp> +#include <uhd/utils/log.hpp> +#include <uhd/utils/msg.hpp> +#include <uhd/utils/assert_has.hpp> +#include <uhd/utils/algorithm.hpp> +#include <uhd/types/ranges.hpp> +#include <uhd/types/sensors.hpp> +#include <uhd/types/dict.hpp> +#include <uhd/usrp/subdev_props.hpp> +#include <uhd/usrp/dboard_base.hpp> +#include <uhd/usrp/dboard_manager.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/format.hpp> +#include <boost/thread.hpp> +#include <boost/array.hpp> +#include <boost/math/special_functions/round.hpp> +#include <utility> +#include <cmath> + +using namespace uhd; +using namespace uhd::usrp; +using namespace boost::assign; + +/*********************************************************************** + * The TVRX2 types + **********************************************************************/ +struct tvrx2_tda18272_rfcal_result_t { +    boost::int8_t    delta_c; +    boost::int8_t    c_offset; +    tvrx2_tda18272_rfcal_result_t(void): delta_c(0), c_offset(0){} +}; + +struct tvrx2_tda18272_rfcal_coeffs_t  { +    boost::uint8_t   cal_number; +    boost::int32_t   RF_A1; +    boost::int32_t   RF_B1; +    tvrx2_tda18272_rfcal_coeffs_t(void): cal_number(0), RF_A1(0), RF_B1(0) {} +    tvrx2_tda18272_rfcal_coeffs_t(boost::uint32_t num): RF_A1(0), RF_B1(0) { cal_number = num; } +}; + +struct tvrx2_tda18272_cal_map_t { +    boost::array<boost::uint32_t, 4>  cal_freq; +    boost::array<boost::uint8_t, 4>   c_offset; +    tvrx2_tda18272_cal_map_t(boost::array<boost::uint32_t, 4> freqs, boost::array<boost::uint8_t, 4> offsets) +        { cal_freq = freqs; c_offset = offsets; } +}; + +struct tvrx2_tda18272_freq_map_t { +    boost::uint32_t  rf_max; +    boost::uint8_t   c_prog; +    boost::uint8_t   gain_taper; +    boost::uint8_t   rf_band; +    tvrx2_tda18272_freq_map_t( boost::uint32_t max, boost::uint8_t c, boost::uint8_t taper, boost::uint8_t band) +        { rf_max = max; c_prog = c; gain_taper = taper; rf_band = band; } +}; + +/*********************************************************************** + * The TVRX2 constants + **********************************************************************/ + +static const boost::array<freq_range_t, 4> tvrx2_tda18272_rf_bands = list_of +    ( freq_range_t(  44.056e6, 144.408e6) ) +    ( freq_range_t( 145.432e6, 361.496e6) ) +    ( freq_range_t( 365.592e6, 618.520e6) ) +    ( freq_range_t( 619.544e6, 865.304e6) ) +; + +#define TVRX2_TDA18272_FREQ_MAP_ENTRIES (565) + +static const uhd::dict<boost::uint32_t, tvrx2_tda18272_cal_map_t> tvrx2_tda18272_cal_map = map_list_of +    (  0, tvrx2_tda18272_cal_map_t( list_of( 44032000)( 48128000)( 52224000)( 56320000), list_of(15)( 0)(10)(17) ) ) +    (  1, tvrx2_tda18272_cal_map_t( list_of( 84992000)( 89088000)( 93184000)( 97280000), list_of( 1)( 0)(-2)( 3) ) ) +    (  2, tvrx2_tda18272_cal_map_t( list_of(106496000)(111616000)(115712000)(123904000), list_of( 0)(-1)( 1)( 2) ) ) +    (  3, tvrx2_tda18272_cal_map_t( list_of(161792000)(165888000)(169984000)(174080000), list_of( 3)( 0)( 1)( 2) ) ) +    (  4, tvrx2_tda18272_cal_map_t( list_of(224256000)(228352000)(232448000)(235520000), list_of( 3)( 0)( 1)( 2) ) ) +    (  5, tvrx2_tda18272_cal_map_t( list_of(301056000)(312320000)(322560000)(335872000), list_of( 0)(-1)( 1)( 2) ) ) +    (  6, tvrx2_tda18272_cal_map_t( list_of(389120000)(393216000)(397312000)(401408000), list_of(-2)( 0)(-1)( 1) ) ) +    (  7, tvrx2_tda18272_cal_map_t( list_of(455680000)(460800000)(465920000)(471040000), list_of( 0)(-2)(-3)( 1) ) ) +    (  8, tvrx2_tda18272_cal_map_t( list_of(555008000)(563200000)(570368000)(577536000), list_of(-1)( 0)(-3)(-2) ) ) +    (  9, tvrx2_tda18272_cal_map_t( list_of(647168000)(652288000)(658432000)(662528000), list_of(-6)(-3)( 0)(-5) ) ) +    ( 10, tvrx2_tda18272_cal_map_t( list_of(748544000)(755712000)(762880000)(770048000), list_of(-6)(-3)( 0)(-5) ) ) +    ( 11, tvrx2_tda18272_cal_map_t( list_of(792576000)(801792000)(809984000)(818176000), list_of(-5)(-2)( 0)(-4) ) ) +; + +static const std::vector<tvrx2_tda18272_freq_map_t> tvrx2_tda18272_freq_map = list_of +    ( tvrx2_tda18272_freq_map_t( 39936000, 0xFF, 0x17, 0) ) +    ( tvrx2_tda18272_freq_map_t( 40960000, 0xFD, 0x17, 0) ) +    ( tvrx2_tda18272_freq_map_t( 41984000, 0xF1, 0x15, 0) ) +    ( tvrx2_tda18272_freq_map_t( 43008000, 0xE5, 0x13, 0) ) +    ( tvrx2_tda18272_freq_map_t( 44032000, 0xDB, 0x13, 0) ) +    ( tvrx2_tda18272_freq_map_t( 45056000, 0xD1, 0x12, 0) ) +    ( tvrx2_tda18272_freq_map_t( 46080000, 0xC7, 0x10, 0) ) +    ( tvrx2_tda18272_freq_map_t( 47104000, 0xBE, 0x0F, 0) ) +    ( tvrx2_tda18272_freq_map_t( 48128000, 0xB5, 0x0F, 0) ) +    ( tvrx2_tda18272_freq_map_t( 49152000, 0xAD, 0x0F, 0) ) +    ( tvrx2_tda18272_freq_map_t( 50176000, 0xA6, 0x0F, 0) ) +    ( tvrx2_tda18272_freq_map_t( 51200000, 0x9F, 0x0F, 0) ) +    ( tvrx2_tda18272_freq_map_t( 52224000, 0x98, 0x0F, 0) ) +    ( tvrx2_tda18272_freq_map_t( 53248000, 0x91, 0x0F, 0) ) +    ( tvrx2_tda18272_freq_map_t( 54272000, 0x8B, 0x0F, 0) ) +    ( tvrx2_tda18272_freq_map_t( 55296000, 0x86, 0x0F, 0) ) +    ( tvrx2_tda18272_freq_map_t( 56320000, 0x80, 0x0F, 0) ) +    ( tvrx2_tda18272_freq_map_t( 57344000, 0x7B, 0x0E, 0) ) +    ( tvrx2_tda18272_freq_map_t( 58368000, 0x76, 0x0E, 0) ) +    ( tvrx2_tda18272_freq_map_t( 59392000, 0x72, 0x0D, 0) ) +    ( tvrx2_tda18272_freq_map_t( 60416000, 0x6D, 0x0D, 0) ) +    ( tvrx2_tda18272_freq_map_t( 61440000, 0x69, 0x0C, 0) ) +    ( tvrx2_tda18272_freq_map_t( 62464000, 0x65, 0x0C, 0) ) +    ( tvrx2_tda18272_freq_map_t( 63488000, 0x61, 0x0B, 0) ) +    ( tvrx2_tda18272_freq_map_t( 64512000, 0x5E, 0x0B, 0) ) +    ( tvrx2_tda18272_freq_map_t( 64512000, 0x5A, 0x0B, 0) ) +    ( tvrx2_tda18272_freq_map_t( 65536000, 0x57, 0x0A, 0) ) +    ( tvrx2_tda18272_freq_map_t( 66560000, 0x54, 0x0A, 0) ) +    ( tvrx2_tda18272_freq_map_t( 67584000, 0x51, 0x09, 0) ) +    ( tvrx2_tda18272_freq_map_t( 68608000, 0x4E, 0x09, 0) ) +    ( tvrx2_tda18272_freq_map_t( 69632000, 0x4B, 0x09, 0) ) +    ( tvrx2_tda18272_freq_map_t( 70656000, 0x49, 0x08, 0) ) +    ( tvrx2_tda18272_freq_map_t( 71680000, 0x46, 0x08, 0) ) +    ( tvrx2_tda18272_freq_map_t( 72704000, 0x44, 0x08, 0) ) +    ( tvrx2_tda18272_freq_map_t( 73728000, 0x41, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t( 74752000, 0x3F, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t( 75776000, 0x3D, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t( 76800000, 0x3B, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t( 77824000, 0x39, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t( 78848000, 0x37, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t( 79872000, 0x35, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t( 80896000, 0x33, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t( 81920000, 0x32, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t( 82944000, 0x30, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t( 83968000, 0x2F, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t( 84992000, 0x2D, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t( 86016000, 0x2C, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t( 87040000, 0x2A, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t( 88064000, 0x29, 0x06, 0) ) +    ( tvrx2_tda18272_freq_map_t( 89088000, 0x27, 0x06, 0) ) +    ( tvrx2_tda18272_freq_map_t( 90112000, 0x26, 0x06, 0) ) +    ( tvrx2_tda18272_freq_map_t( 91136000, 0x25, 0x06, 0) ) +    ( tvrx2_tda18272_freq_map_t( 92160000, 0x24, 0x06, 0) ) +    ( tvrx2_tda18272_freq_map_t( 93184000, 0x22, 0x05, 0) ) +    ( tvrx2_tda18272_freq_map_t( 94208000, 0x21, 0x05, 0) ) +    ( tvrx2_tda18272_freq_map_t( 95232000, 0x20, 0x05, 0) ) +    ( tvrx2_tda18272_freq_map_t( 96256000, 0x1F, 0x05, 0) ) +    ( tvrx2_tda18272_freq_map_t( 97280000, 0x1E, 0x05, 0) ) +    ( tvrx2_tda18272_freq_map_t( 98304000, 0x1D, 0x05, 0) ) +    ( tvrx2_tda18272_freq_map_t( 99328000, 0x1C, 0x04, 0) ) +    ( tvrx2_tda18272_freq_map_t(100352000, 0x1B, 0x04, 0) ) +    ( tvrx2_tda18272_freq_map_t(101376000, 0x1A, 0x04, 0) ) +    ( tvrx2_tda18272_freq_map_t(103424000, 0x19, 0x04, 0) ) +    ( tvrx2_tda18272_freq_map_t(104448000, 0x18, 0x04, 0) ) +    ( tvrx2_tda18272_freq_map_t(105472000, 0x17, 0x04, 0) ) +    ( tvrx2_tda18272_freq_map_t(106496000, 0x16, 0x03, 0) ) +    ( tvrx2_tda18272_freq_map_t(106496000, 0x15, 0x03, 0) ) +    ( tvrx2_tda18272_freq_map_t(108544000, 0x14, 0x03, 0) ) +    ( tvrx2_tda18272_freq_map_t(109568000, 0x13, 0x03, 0) ) +    ( tvrx2_tda18272_freq_map_t(111616000, 0x12, 0x03, 0) ) +    ( tvrx2_tda18272_freq_map_t(112640000, 0x11, 0x03, 0) ) +    ( tvrx2_tda18272_freq_map_t(113664000, 0x11, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t(114688000, 0x10, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t(115712000, 0x0F, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t(117760000, 0x0E, 0x07, 0) ) +    ( tvrx2_tda18272_freq_map_t(119808000, 0x0D, 0x06, 0) ) +    ( tvrx2_tda18272_freq_map_t(121856000, 0x0C, 0x06, 0) ) +    ( tvrx2_tda18272_freq_map_t(123904000, 0x0B, 0x06, 0) ) +    ( tvrx2_tda18272_freq_map_t(125952000, 0x0A, 0x05, 0) ) +    ( tvrx2_tda18272_freq_map_t(128000000, 0x09, 0x05, 0) ) +    ( tvrx2_tda18272_freq_map_t(130048000, 0x08, 0x05, 0) ) +    ( tvrx2_tda18272_freq_map_t(133120000, 0x07, 0x04, 0) ) +    ( tvrx2_tda18272_freq_map_t(135168000, 0x06, 0x04, 0) ) +    ( tvrx2_tda18272_freq_map_t(138240000, 0x05, 0x04, 0) ) +    ( tvrx2_tda18272_freq_map_t(141312000, 0x04, 0x04, 0) ) +    ( tvrx2_tda18272_freq_map_t(144384000, 0x03, 0x03, 0) ) +    ( tvrx2_tda18272_freq_map_t(145408000, 0xE0, 0x3F, 1) ) +    ( tvrx2_tda18272_freq_map_t(147456000, 0xDC, 0x37, 1) ) +    ( tvrx2_tda18272_freq_map_t(148480000, 0xD9, 0x32, 1) ) +    ( tvrx2_tda18272_freq_map_t(149504000, 0xD6, 0x2F, 1) ) +    ( tvrx2_tda18272_freq_map_t(149504000, 0xD2, 0x2F, 1) ) +    ( tvrx2_tda18272_freq_map_t(150528000, 0xCF, 0x2F, 1) ) +    ( tvrx2_tda18272_freq_map_t(151552000, 0xCC, 0x2B, 1) ) +    ( tvrx2_tda18272_freq_map_t(152576000, 0xC9, 0x27, 1) ) +    ( tvrx2_tda18272_freq_map_t(153600000, 0xC5, 0x27, 1) ) +    ( tvrx2_tda18272_freq_map_t(154624000, 0xC2, 0x25, 1) ) +    ( tvrx2_tda18272_freq_map_t(155648000, 0xBF, 0x23, 1) ) +    ( tvrx2_tda18272_freq_map_t(156672000, 0xBD, 0x20, 1) ) +    ( tvrx2_tda18272_freq_map_t(157696000, 0xBA, 0x1F, 1) ) +    ( tvrx2_tda18272_freq_map_t(158720000, 0xB7, 0x1F, 1) ) +    ( tvrx2_tda18272_freq_map_t(159744000, 0xB4, 0x1F, 1) ) +    ( tvrx2_tda18272_freq_map_t(160768000, 0xB1, 0x1F, 1) ) +    ( tvrx2_tda18272_freq_map_t(161792000, 0xAF, 0x1F, 1) ) +    ( tvrx2_tda18272_freq_map_t(162816000, 0xAC, 0x1F, 1) ) +    ( tvrx2_tda18272_freq_map_t(163840000, 0xAA, 0x1F, 1) ) +    ( tvrx2_tda18272_freq_map_t(164864000, 0xA7, 0x1F, 1) ) +    ( tvrx2_tda18272_freq_map_t(165888000, 0xA5, 0x1F, 1) ) +    ( tvrx2_tda18272_freq_map_t(166912000, 0xA2, 0x1F, 1) ) +    ( tvrx2_tda18272_freq_map_t(167936000, 0xA0, 0x1F, 1) ) +    ( tvrx2_tda18272_freq_map_t(168960000, 0x9D, 0x1F, 1) ) +    ( tvrx2_tda18272_freq_map_t(169984000, 0x9B, 0x1F, 1) ) +    ( tvrx2_tda18272_freq_map_t(171008000, 0x99, 0x1F, 1) ) +    ( tvrx2_tda18272_freq_map_t(172032000, 0x97, 0x1E, 1) ) +    ( tvrx2_tda18272_freq_map_t(173056000, 0x95, 0x1D, 1) ) +    ( tvrx2_tda18272_freq_map_t(174080000, 0x92, 0x1C, 1) ) +    ( tvrx2_tda18272_freq_map_t(175104000, 0x90, 0x1B, 1) ) +    ( tvrx2_tda18272_freq_map_t(176128000, 0x8E, 0x1A, 1) ) +    ( tvrx2_tda18272_freq_map_t(177152000, 0x8C, 0x19, 1) ) +    ( tvrx2_tda18272_freq_map_t(178176000, 0x8A, 0x18, 1) ) +    ( tvrx2_tda18272_freq_map_t(179200000, 0x88, 0x17, 1) ) +    ( tvrx2_tda18272_freq_map_t(180224000, 0x86, 0x17, 1) ) +    ( tvrx2_tda18272_freq_map_t(181248000, 0x84, 0x17, 1) ) +    ( tvrx2_tda18272_freq_map_t(182272000, 0x82, 0x17, 1) ) +    ( tvrx2_tda18272_freq_map_t(183296000, 0x81, 0x17, 1) ) +    ( tvrx2_tda18272_freq_map_t(184320000, 0x7F, 0x17, 1) ) +    ( tvrx2_tda18272_freq_map_t(185344000, 0x7D, 0x16, 1) ) +    ( tvrx2_tda18272_freq_map_t(186368000, 0x7B, 0x15, 1) ) +    ( tvrx2_tda18272_freq_map_t(187392000, 0x7A, 0x14, 1) ) +    ( tvrx2_tda18272_freq_map_t(188416000, 0x78, 0x14, 1) ) +    ( tvrx2_tda18272_freq_map_t(189440000, 0x76, 0x13, 1) ) +    ( tvrx2_tda18272_freq_map_t(190464000, 0x75, 0x13, 1) ) +    ( tvrx2_tda18272_freq_map_t(191488000, 0x73, 0x13, 1) ) +    ( tvrx2_tda18272_freq_map_t(192512000, 0x71, 0x12, 1) ) +    ( tvrx2_tda18272_freq_map_t(192512000, 0x70, 0x11, 1) ) +    ( tvrx2_tda18272_freq_map_t(193536000, 0x6E, 0x11, 1) ) +    ( tvrx2_tda18272_freq_map_t(194560000, 0x6D, 0x10, 1) ) +    ( tvrx2_tda18272_freq_map_t(195584000, 0x6B, 0x10, 1) ) +    ( tvrx2_tda18272_freq_map_t(196608000, 0x6A, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(197632000, 0x68, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(198656000, 0x67, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(199680000, 0x65, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(200704000, 0x64, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(201728000, 0x63, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(202752000, 0x61, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(203776000, 0x60, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(204800000, 0x5F, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(205824000, 0x5D, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(206848000, 0x5C, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(207872000, 0x5B, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(208896000, 0x5A, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(209920000, 0x58, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(210944000, 0x57, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(211968000, 0x56, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(212992000, 0x55, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(214016000, 0x54, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(215040000, 0x53, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(216064000, 0x52, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(217088000, 0x50, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(218112000, 0x4F, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(219136000, 0x4E, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(220160000, 0x4D, 0x0E, 1) ) +    ( tvrx2_tda18272_freq_map_t(221184000, 0x4C, 0x0E, 1) ) +    ( tvrx2_tda18272_freq_map_t(222208000, 0x4B, 0x0E, 1) ) +    ( tvrx2_tda18272_freq_map_t(223232000, 0x4A, 0x0E, 1) ) +    ( tvrx2_tda18272_freq_map_t(224256000, 0x49, 0x0D, 1) ) +    ( tvrx2_tda18272_freq_map_t(225280000, 0x48, 0x0D, 1) ) +    ( tvrx2_tda18272_freq_map_t(226304000, 0x47, 0x0D, 1) ) +    ( tvrx2_tda18272_freq_map_t(227328000, 0x46, 0x0D, 1) ) +    ( tvrx2_tda18272_freq_map_t(228352000, 0x45, 0x0C, 1) ) +    ( tvrx2_tda18272_freq_map_t(229376000, 0x44, 0x0C, 1) ) +    ( tvrx2_tda18272_freq_map_t(230400000, 0x43, 0x0C, 1) ) +    ( tvrx2_tda18272_freq_map_t(231424000, 0x42, 0x0C, 1) ) +    ( tvrx2_tda18272_freq_map_t(232448000, 0x42, 0x0B, 1) ) +    ( tvrx2_tda18272_freq_map_t(233472000, 0x41, 0x0B, 1) ) +    ( tvrx2_tda18272_freq_map_t(234496000, 0x40, 0x0B, 1) ) +    ( tvrx2_tda18272_freq_map_t(234496000, 0x3F, 0x0B, 1) ) +    ( tvrx2_tda18272_freq_map_t(235520000, 0x3E, 0x0B, 1) ) +    ( tvrx2_tda18272_freq_map_t(236544000, 0x3D, 0x0B, 1) ) +    ( tvrx2_tda18272_freq_map_t(237568000, 0x3C, 0x0B, 1) ) +    ( tvrx2_tda18272_freq_map_t(239616000, 0x3B, 0x0A, 1) ) +    ( tvrx2_tda18272_freq_map_t(240640000, 0x3A, 0x0A, 1) ) +    ( tvrx2_tda18272_freq_map_t(241664000, 0x39, 0x0A, 1) ) +    ( tvrx2_tda18272_freq_map_t(242688000, 0x38, 0x0A, 1) ) +    ( tvrx2_tda18272_freq_map_t(244736000, 0x37, 0x09, 1) ) +    ( tvrx2_tda18272_freq_map_t(245760000, 0x36, 0x09, 1) ) +    ( tvrx2_tda18272_freq_map_t(246784000, 0x35, 0x09, 1) ) +    ( tvrx2_tda18272_freq_map_t(248832000, 0x34, 0x09, 1) ) +    ( tvrx2_tda18272_freq_map_t(249856000, 0x33, 0x09, 1) ) +    ( tvrx2_tda18272_freq_map_t(250880000, 0x32, 0x08, 1) ) +    ( tvrx2_tda18272_freq_map_t(252928000, 0x31, 0x08, 1) ) +    ( tvrx2_tda18272_freq_map_t(253952000, 0x30, 0x08, 1) ) +    ( tvrx2_tda18272_freq_map_t(256000000, 0x2F, 0x08, 1) ) +    ( tvrx2_tda18272_freq_map_t(257024000, 0x2E, 0x08, 1) ) +    ( tvrx2_tda18272_freq_map_t(259072000, 0x2D, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(260096000, 0x2C, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(262144000, 0x2B, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(264192000, 0x2A, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(265216000, 0x29, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(267264000, 0x28, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(269312000, 0x27, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(270336000, 0x26, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(272384000, 0x25, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(274432000, 0x24, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(276480000, 0x23, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(277504000, 0x22, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(279552000, 0x21, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(281600000, 0x20, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(283648000, 0x1F, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(285696000, 0x1E, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(287744000, 0x1D, 0x0F, 1) ) +    ( tvrx2_tda18272_freq_map_t(289792000, 0x1C, 0x0E, 1) ) +    ( tvrx2_tda18272_freq_map_t(291840000, 0x1B, 0x0E, 1) ) +    ( tvrx2_tda18272_freq_map_t(293888000, 0x1A, 0x0D, 1) ) +    ( tvrx2_tda18272_freq_map_t(296960000, 0x19, 0x0D, 1) ) +    ( tvrx2_tda18272_freq_map_t(299008000, 0x18, 0x0C, 1) ) +    ( tvrx2_tda18272_freq_map_t(301056000, 0x17, 0x0C, 1) ) +    ( tvrx2_tda18272_freq_map_t(304128000, 0x16, 0x0C, 1) ) +    ( tvrx2_tda18272_freq_map_t(306176000, 0x15, 0x0B, 1) ) +    ( tvrx2_tda18272_freq_map_t(309248000, 0x14, 0x0B, 1) ) +    ( tvrx2_tda18272_freq_map_t(312320000, 0x13, 0x0B, 1) ) +    ( tvrx2_tda18272_freq_map_t(314368000, 0x12, 0x0B, 1) ) +    ( tvrx2_tda18272_freq_map_t(317440000, 0x11, 0x0A, 1) ) +    ( tvrx2_tda18272_freq_map_t(320512000, 0x10, 0x0A, 1) ) +    ( tvrx2_tda18272_freq_map_t(322560000, 0x0F, 0x0A, 1) ) +    ( tvrx2_tda18272_freq_map_t(325632000, 0x0E, 0x09, 1) ) +    ( tvrx2_tda18272_freq_map_t(328704000, 0x0D, 0x09, 1) ) +    ( tvrx2_tda18272_freq_map_t(331776000, 0x0C, 0x08, 1) ) +    ( tvrx2_tda18272_freq_map_t(335872000, 0x0B, 0x08, 1) ) +    ( tvrx2_tda18272_freq_map_t(338944000, 0x0A, 0x08, 1) ) +    ( tvrx2_tda18272_freq_map_t(343040000, 0x09, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(346112000, 0x08, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(350208000, 0x07, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(354304000, 0x06, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(358400000, 0x05, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(362496000, 0x04, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(365568000, 0x04, 0x07, 1) ) +    ( tvrx2_tda18272_freq_map_t(367616000, 0xDA, 0x2A, 2) ) +    ( tvrx2_tda18272_freq_map_t(367616000, 0xD9, 0x27, 2) ) +    ( tvrx2_tda18272_freq_map_t(368640000, 0xD8, 0x27, 2) ) +    ( tvrx2_tda18272_freq_map_t(369664000, 0xD6, 0x27, 2) ) +    ( tvrx2_tda18272_freq_map_t(370688000, 0xD5, 0x27, 2) ) +    ( tvrx2_tda18272_freq_map_t(371712000, 0xD3, 0x25, 2) ) +    ( tvrx2_tda18272_freq_map_t(372736000, 0xD2, 0x23, 2) ) +    ( tvrx2_tda18272_freq_map_t(373760000, 0xD0, 0x23, 2) ) +    ( tvrx2_tda18272_freq_map_t(374784000, 0xCF, 0x21, 2) ) +    ( tvrx2_tda18272_freq_map_t(375808000, 0xCD, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(376832000, 0xCC, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(377856000, 0xCA, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(378880000, 0xC9, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(379904000, 0xC7, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(380928000, 0xC6, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(381952000, 0xC4, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(382976000, 0xC3, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(384000000, 0xC1, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(385024000, 0xC0, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(386048000, 0xBF, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(387072000, 0xBD, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(388096000, 0xBC, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(389120000, 0xBB, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(390144000, 0xB9, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(391168000, 0xB8, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(392192000, 0xB7, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(393216000, 0xB5, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(394240000, 0xB4, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(395264000, 0xB3, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(396288000, 0xB1, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(397312000, 0xB0, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(398336000, 0xAF, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(399360000, 0xAD, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(400384000, 0xAC, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(401408000, 0xAB, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(402432000, 0xAA, 0x1F, 2) ) +    ( tvrx2_tda18272_freq_map_t(403456000, 0xA8, 0x1E, 2) ) +    ( tvrx2_tda18272_freq_map_t(404480000, 0xA7, 0x1D, 2) ) +    ( tvrx2_tda18272_freq_map_t(405504000, 0xA6, 0x1D, 2) ) +    ( tvrx2_tda18272_freq_map_t(405504000, 0xA5, 0x1C, 2) ) +    ( tvrx2_tda18272_freq_map_t(406528000, 0xA3, 0x1C, 2) ) +    ( tvrx2_tda18272_freq_map_t(407552000, 0xA2, 0x1B, 2) ) +    ( tvrx2_tda18272_freq_map_t(408576000, 0xA1, 0x1B, 2) ) +    ( tvrx2_tda18272_freq_map_t(409600000, 0xA0, 0x1B, 2) ) +    ( tvrx2_tda18272_freq_map_t(410624000, 0x9F, 0x1A, 2) ) +    ( tvrx2_tda18272_freq_map_t(411648000, 0x9D, 0x1A, 2) ) +    ( tvrx2_tda18272_freq_map_t(412672000, 0x9C, 0x19, 2) ) +    ( tvrx2_tda18272_freq_map_t(413696000, 0x9B, 0x18, 2) ) +    ( tvrx2_tda18272_freq_map_t(414720000, 0x9A, 0x18, 2) ) +    ( tvrx2_tda18272_freq_map_t(415744000, 0x99, 0x17, 2) ) +    ( tvrx2_tda18272_freq_map_t(416768000, 0x98, 0x17, 2) ) +    ( tvrx2_tda18272_freq_map_t(417792000, 0x97, 0x17, 2) ) +    ( tvrx2_tda18272_freq_map_t(418816000, 0x95, 0x17, 2) ) +    ( tvrx2_tda18272_freq_map_t(419840000, 0x94, 0x17, 2) ) +    ( tvrx2_tda18272_freq_map_t(420864000, 0x93, 0x17, 2) ) +    ( tvrx2_tda18272_freq_map_t(421888000, 0x92, 0x17, 2) ) +    ( tvrx2_tda18272_freq_map_t(422912000, 0x91, 0x17, 2) ) +    ( tvrx2_tda18272_freq_map_t(423936000, 0x90, 0x17, 2) ) +    ( tvrx2_tda18272_freq_map_t(424960000, 0x8F, 0x17, 2) ) +    ( tvrx2_tda18272_freq_map_t(425984000, 0x8E, 0x16, 2) ) +    ( tvrx2_tda18272_freq_map_t(427008000, 0x8D, 0x16, 2) ) +    ( tvrx2_tda18272_freq_map_t(428032000, 0x8C, 0x15, 2) ) +    ( tvrx2_tda18272_freq_map_t(429056000, 0x8B, 0x15, 2) ) +    ( tvrx2_tda18272_freq_map_t(430080000, 0x8A, 0x15, 2) ) +    ( tvrx2_tda18272_freq_map_t(431104000, 0x88, 0x14, 2) ) +    ( tvrx2_tda18272_freq_map_t(432128000, 0x87, 0x14, 2) ) +    ( tvrx2_tda18272_freq_map_t(433152000, 0x86, 0x14, 2) ) +    ( tvrx2_tda18272_freq_map_t(434176000, 0x85, 0x13, 2) ) +    ( tvrx2_tda18272_freq_map_t(435200000, 0x84, 0x13, 2) ) +    ( tvrx2_tda18272_freq_map_t(436224000, 0x83, 0x13, 2) ) +    ( tvrx2_tda18272_freq_map_t(437248000, 0x82, 0x13, 2) ) +    ( tvrx2_tda18272_freq_map_t(438272000, 0x81, 0x13, 2) ) +    ( tvrx2_tda18272_freq_map_t(439296000, 0x80, 0x12, 2) ) +    ( tvrx2_tda18272_freq_map_t(440320000, 0x7F, 0x12, 2) ) +    ( tvrx2_tda18272_freq_map_t(441344000, 0x7E, 0x12, 2) ) +    ( tvrx2_tda18272_freq_map_t(442368000, 0x7D, 0x11, 2) ) +    ( tvrx2_tda18272_freq_map_t(444416000, 0x7C, 0x11, 2) ) +    ( tvrx2_tda18272_freq_map_t(445440000, 0x7B, 0x10, 2) ) +    ( tvrx2_tda18272_freq_map_t(446464000, 0x7A, 0x10, 2) ) +    ( tvrx2_tda18272_freq_map_t(447488000, 0x79, 0x10, 2) ) +    ( tvrx2_tda18272_freq_map_t(448512000, 0x78, 0x10, 2) ) +    ( tvrx2_tda18272_freq_map_t(448512000, 0x77, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(449536000, 0x76, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(450560000, 0x75, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(451584000, 0x74, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(452608000, 0x73, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(453632000, 0x72, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(454656000, 0x71, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(455680000, 0x70, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(457728000, 0x6F, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(458752000, 0x6E, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(459776000, 0x6D, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(460800000, 0x6C, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(461824000, 0x6B, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(462848000, 0x6A, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(464896000, 0x69, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(465920000, 0x68, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(466944000, 0x67, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(467968000, 0x66, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(468992000, 0x65, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(471040000, 0x64, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(472064000, 0x63, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(473088000, 0x62, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(474112000, 0x61, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(476160000, 0x60, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(477184000, 0x5F, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(478208000, 0x5E, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(479232000, 0x5D, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(481280000, 0x5C, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(482304000, 0x5B, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(483328000, 0x5A, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(485376000, 0x59, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(486400000, 0x58, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(487424000, 0x57, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(489472000, 0x56, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(490496000, 0x55, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(490496000, 0x54, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(492544000, 0x53, 0x0E, 2) ) +    ( tvrx2_tda18272_freq_map_t(493568000, 0x52, 0x0E, 2) ) +    ( tvrx2_tda18272_freq_map_t(495616000, 0x51, 0x0E, 2) ) +    ( tvrx2_tda18272_freq_map_t(496640000, 0x50, 0x0E, 2) ) +    ( tvrx2_tda18272_freq_map_t(497664000, 0x4F, 0x0E, 2) ) +    ( tvrx2_tda18272_freq_map_t(499712000, 0x4E, 0x0D, 2) ) +    ( tvrx2_tda18272_freq_map_t(500736000, 0x4D, 0x0D, 2) ) +    ( tvrx2_tda18272_freq_map_t(502784000, 0x4C, 0x0D, 2) ) +    ( tvrx2_tda18272_freq_map_t(503808000, 0x4B, 0x0D, 2) ) +    ( tvrx2_tda18272_freq_map_t(505856000, 0x4A, 0x0C, 2) ) +    ( tvrx2_tda18272_freq_map_t(506880000, 0x49, 0x0C, 2) ) +    ( tvrx2_tda18272_freq_map_t(508928000, 0x48, 0x0C, 2) ) +    ( tvrx2_tda18272_freq_map_t(509952000, 0x47, 0x0C, 2) ) +    ( tvrx2_tda18272_freq_map_t(512000000, 0x46, 0x0C, 2) ) +    ( tvrx2_tda18272_freq_map_t(513024000, 0x45, 0x0B, 2) ) +    ( tvrx2_tda18272_freq_map_t(515072000, 0x44, 0x0B, 2) ) +    ( tvrx2_tda18272_freq_map_t(517120000, 0x43, 0x0B, 2) ) +    ( tvrx2_tda18272_freq_map_t(518144000, 0x42, 0x0B, 2) ) +    ( tvrx2_tda18272_freq_map_t(520192000, 0x41, 0x0B, 2) ) +    ( tvrx2_tda18272_freq_map_t(521216000, 0x40, 0x0B, 2) ) +    ( tvrx2_tda18272_freq_map_t(523264000, 0x3F, 0x0B, 2) ) +    ( tvrx2_tda18272_freq_map_t(525312000, 0x3E, 0x0B, 2) ) +    ( tvrx2_tda18272_freq_map_t(526336000, 0x3D, 0x0B, 2) ) +    ( tvrx2_tda18272_freq_map_t(528384000, 0x3C, 0x0A, 2) ) +    ( tvrx2_tda18272_freq_map_t(530432000, 0x3B, 0x0A, 2) ) +    ( tvrx2_tda18272_freq_map_t(531456000, 0x3A, 0x0A, 2) ) +    ( tvrx2_tda18272_freq_map_t(533504000, 0x39, 0x0A, 2) ) +    ( tvrx2_tda18272_freq_map_t(534528000, 0x38, 0x0A, 2) ) +    ( tvrx2_tda18272_freq_map_t(536576000, 0x37, 0x0A, 2) ) +    ( tvrx2_tda18272_freq_map_t(537600000, 0x36, 0x09, 2) ) +    ( tvrx2_tda18272_freq_map_t(539648000, 0x35, 0x09, 2) ) +    ( tvrx2_tda18272_freq_map_t(541696000, 0x34, 0x09, 2) ) +    ( tvrx2_tda18272_freq_map_t(543744000, 0x33, 0x09, 2) ) +    ( tvrx2_tda18272_freq_map_t(544768000, 0x32, 0x09, 2) ) +    ( tvrx2_tda18272_freq_map_t(546816000, 0x31, 0x09, 2) ) +    ( tvrx2_tda18272_freq_map_t(548864000, 0x30, 0x08, 2) ) +    ( tvrx2_tda18272_freq_map_t(550912000, 0x2F, 0x08, 2) ) +    ( tvrx2_tda18272_freq_map_t(552960000, 0x2E, 0x08, 2) ) +    ( tvrx2_tda18272_freq_map_t(555008000, 0x2D, 0x08, 2) ) +    ( tvrx2_tda18272_freq_map_t(557056000, 0x2C, 0x08, 2) ) +    ( tvrx2_tda18272_freq_map_t(559104000, 0x2B, 0x08, 2) ) +    ( tvrx2_tda18272_freq_map_t(561152000, 0x2A, 0x07, 2) ) +    ( tvrx2_tda18272_freq_map_t(563200000, 0x29, 0x07, 2) ) +    ( tvrx2_tda18272_freq_map_t(565248000, 0x28, 0x07, 2) ) +    ( tvrx2_tda18272_freq_map_t(567296000, 0x27, 0x07, 2) ) +    ( tvrx2_tda18272_freq_map_t(569344000, 0x26, 0x07, 2) ) +    ( tvrx2_tda18272_freq_map_t(570368000, 0x26, 0x07, 2) ) +    ( tvrx2_tda18272_freq_map_t(571392000, 0x25, 0x07, 2) ) +    ( tvrx2_tda18272_freq_map_t(573440000, 0x24, 0x07, 2) ) +    ( tvrx2_tda18272_freq_map_t(575488000, 0x23, 0x07, 2) ) +    ( tvrx2_tda18272_freq_map_t(577536000, 0x22, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(578560000, 0x21, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(580608000, 0x20, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(583680000, 0x1F, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(585728000, 0x1E, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(587776000, 0x1D, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(589824000, 0x1C, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(592896000, 0x1B, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(594944000, 0x1A, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(596992000, 0x19, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(600064000, 0x18, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(602112000, 0x17, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(604160000, 0x16, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(607232000, 0x15, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(609280000, 0x14, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(612352000, 0x13, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(615424000, 0x12, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(617472000, 0x11, 0x0F, 2) ) +    ( tvrx2_tda18272_freq_map_t(619520000, 0x10, 0x0E, 2) ) +    ( tvrx2_tda18272_freq_map_t(621568000, 0x0F, 0x0E, 2) ) +    ( tvrx2_tda18272_freq_map_t(623616000, 0x0F, 0x0E, 2) ) +    ( tvrx2_tda18272_freq_map_t(624640000, 0xA3, 0x1F, 3) ) +    ( tvrx2_tda18272_freq_map_t(625664000, 0xA2, 0x1F, 3) ) +    ( tvrx2_tda18272_freq_map_t(626688000, 0xA1, 0x1F, 3) ) +    ( tvrx2_tda18272_freq_map_t(627712000, 0xA0, 0x1F, 3) ) +    ( tvrx2_tda18272_freq_map_t(628736000, 0x9F, 0x1F, 3) ) +    ( tvrx2_tda18272_freq_map_t(630784000, 0x9E, 0x1F, 3) ) +    ( tvrx2_tda18272_freq_map_t(631808000, 0x9D, 0x1F, 3) ) +    ( tvrx2_tda18272_freq_map_t(632832000, 0x9C, 0x1F, 3) ) +    ( tvrx2_tda18272_freq_map_t(633856000, 0x9B, 0x1F, 3) ) +    ( tvrx2_tda18272_freq_map_t(635904000, 0x9A, 0x1F, 3) ) +    ( tvrx2_tda18272_freq_map_t(636928000, 0x99, 0x1F, 3) ) +    ( tvrx2_tda18272_freq_map_t(637952000, 0x98, 0x1F, 3) ) +    ( tvrx2_tda18272_freq_map_t(638976000, 0x97, 0x1F, 3) ) +    ( tvrx2_tda18272_freq_map_t(641024000, 0x96, 0x1E, 3) ) +    ( tvrx2_tda18272_freq_map_t(642048000, 0x95, 0x1E, 3) ) +    ( tvrx2_tda18272_freq_map_t(643072000, 0x94, 0x1E, 3) ) +    ( tvrx2_tda18272_freq_map_t(644096000, 0x93, 0x1D, 3) ) +    ( tvrx2_tda18272_freq_map_t(646144000, 0x92, 0x1D, 3) ) +    ( tvrx2_tda18272_freq_map_t(647168000, 0x91, 0x1C, 3) ) +    ( tvrx2_tda18272_freq_map_t(648192000, 0x90, 0x1C, 3) ) +    ( tvrx2_tda18272_freq_map_t(650240000, 0x8F, 0x1B, 3) ) +    ( tvrx2_tda18272_freq_map_t(651264000, 0x8E, 0x1B, 3) ) +    ( tvrx2_tda18272_freq_map_t(652288000, 0x8D, 0x1B, 3) ) +    ( tvrx2_tda18272_freq_map_t(654336000, 0x8C, 0x1B, 3) ) +    ( tvrx2_tda18272_freq_map_t(655360000, 0x8B, 0x1B, 3) ) +    ( tvrx2_tda18272_freq_map_t(656384000, 0x8A, 0x1B, 3) ) +    ( tvrx2_tda18272_freq_map_t(658432000, 0x89, 0x1A, 3) ) +    ( tvrx2_tda18272_freq_map_t(659456000, 0x88, 0x1A, 3) ) +    ( tvrx2_tda18272_freq_map_t(660480000, 0x87, 0x1A, 3) ) +    ( tvrx2_tda18272_freq_map_t(661504000, 0x86, 0x19, 3) ) +    ( tvrx2_tda18272_freq_map_t(662528000, 0x85, 0x19, 3) ) +    ( tvrx2_tda18272_freq_map_t(664576000, 0x84, 0x18, 3) ) +    ( tvrx2_tda18272_freq_map_t(665600000, 0x83, 0x18, 3) ) +    ( tvrx2_tda18272_freq_map_t(666624000, 0x82, 0x18, 3) ) +    ( tvrx2_tda18272_freq_map_t(668672000, 0x81, 0x18, 3) ) +    ( tvrx2_tda18272_freq_map_t(669696000, 0x80, 0x17, 3) ) +    ( tvrx2_tda18272_freq_map_t(671744000, 0x7F, 0x17, 3) ) +    ( tvrx2_tda18272_freq_map_t(672768000, 0x7E, 0x17, 3) ) +    ( tvrx2_tda18272_freq_map_t(674816000, 0x7D, 0x17, 3) ) +    ( tvrx2_tda18272_freq_map_t(675840000, 0x7C, 0x17, 3) ) +    ( tvrx2_tda18272_freq_map_t(676864000, 0x7B, 0x17, 3) ) +    ( tvrx2_tda18272_freq_map_t(678912000, 0x7A, 0x17, 3) ) +    ( tvrx2_tda18272_freq_map_t(679936000, 0x79, 0x17, 3) ) +    ( tvrx2_tda18272_freq_map_t(681984000, 0x78, 0x17, 3) ) +    ( tvrx2_tda18272_freq_map_t(683008000, 0x77, 0x17, 3) ) +    ( tvrx2_tda18272_freq_map_t(685056000, 0x76, 0x17, 3) ) +    ( tvrx2_tda18272_freq_map_t(686080000, 0x75, 0x17, 3) ) +    ( tvrx2_tda18272_freq_map_t(688128000, 0x74, 0x17, 3) ) +    ( tvrx2_tda18272_freq_map_t(689152000, 0x73, 0x17, 3) ) +    ( tvrx2_tda18272_freq_map_t(691200000, 0x72, 0x16, 3) ) +    ( tvrx2_tda18272_freq_map_t(693248000, 0x71, 0x16, 3) ) +    ( tvrx2_tda18272_freq_map_t(694272000, 0x70, 0x16, 3) ) +    ( tvrx2_tda18272_freq_map_t(696320000, 0x6F, 0x15, 3) ) +    ( tvrx2_tda18272_freq_map_t(697344000, 0x6E, 0x15, 3) ) +    ( tvrx2_tda18272_freq_map_t(699392000, 0x6D, 0x15, 3) ) +    ( tvrx2_tda18272_freq_map_t(700416000, 0x6C, 0x15, 3) ) +    ( tvrx2_tda18272_freq_map_t(702464000, 0x6B, 0x14, 3) ) +    ( tvrx2_tda18272_freq_map_t(704512000, 0x6A, 0x14, 3) ) +    ( tvrx2_tda18272_freq_map_t(704512000, 0x69, 0x14, 3) ) +    ( tvrx2_tda18272_freq_map_t(706560000, 0x68, 0x14, 3) ) +    ( tvrx2_tda18272_freq_map_t(707584000, 0x67, 0x13, 3) ) +    ( tvrx2_tda18272_freq_map_t(709632000, 0x66, 0x13, 3) ) +    ( tvrx2_tda18272_freq_map_t(711680000, 0x65, 0x13, 3) ) +    ( tvrx2_tda18272_freq_map_t(712704000, 0x64, 0x13, 3) ) +    ( tvrx2_tda18272_freq_map_t(714752000, 0x63, 0x13, 3) ) +    ( tvrx2_tda18272_freq_map_t(716800000, 0x62, 0x13, 3) ) +    ( tvrx2_tda18272_freq_map_t(717824000, 0x61, 0x13, 3) ) +    ( tvrx2_tda18272_freq_map_t(719872000, 0x60, 0x13, 3) ) +    ( tvrx2_tda18272_freq_map_t(721920000, 0x5F, 0x12, 3) ) +    ( tvrx2_tda18272_freq_map_t(723968000, 0x5E, 0x12, 3) ) +    ( tvrx2_tda18272_freq_map_t(724992000, 0x5D, 0x12, 3) ) +    ( tvrx2_tda18272_freq_map_t(727040000, 0x5C, 0x12, 3) ) +    ( tvrx2_tda18272_freq_map_t(729088000, 0x5B, 0x11, 3) ) +    ( tvrx2_tda18272_freq_map_t(731136000, 0x5A, 0x11, 3) ) +    ( tvrx2_tda18272_freq_map_t(732160000, 0x59, 0x11, 3) ) +    ( tvrx2_tda18272_freq_map_t(734208000, 0x58, 0x11, 3) ) +    ( tvrx2_tda18272_freq_map_t(736256000, 0x57, 0x10, 3) ) +    ( tvrx2_tda18272_freq_map_t(738304000, 0x56, 0x10, 3) ) +    ( tvrx2_tda18272_freq_map_t(740352000, 0x55, 0x10, 3) ) +    ( tvrx2_tda18272_freq_map_t(741376000, 0x54, 0x10, 3) ) +    ( tvrx2_tda18272_freq_map_t(743424000, 0x53, 0x10, 3) ) +    ( tvrx2_tda18272_freq_map_t(745472000, 0x52, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(746496000, 0x51, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(748544000, 0x50, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(750592000, 0x4F, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(752640000, 0x4E, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(753664000, 0x4D, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(755712000, 0x4C, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(757760000, 0x4B, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(759808000, 0x4A, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(761856000, 0x49, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(762880000, 0x49, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(763904000, 0x48, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(765952000, 0x47, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(768000000, 0x46, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(770048000, 0x45, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(772096000, 0x44, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(774144000, 0x43, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(776192000, 0x42, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(778240000, 0x41, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(780288000, 0x40, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(783360000, 0x3F, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(785408000, 0x3E, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(787456000, 0x3D, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(789504000, 0x3C, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(790528000, 0x3B, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(792576000, 0x3A, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(794624000, 0x39, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(797696000, 0x38, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(799744000, 0x37, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(801792000, 0x36, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(803840000, 0x35, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(806912000, 0x34, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(808960000, 0x33, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(809984000, 0x33, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(811008000, 0x32, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(813056000, 0x31, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(816128000, 0x30, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(818176000, 0x2F, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(820224000, 0x2E, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(823296000, 0x2D, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(825344000, 0x2C, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(828416000, 0x2B, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(830464000, 0x2A, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(832512000, 0x29, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(834560000, 0x28, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(836608000, 0x27, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(839680000, 0x26, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(841728000, 0x25, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(844800000, 0x24, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(847872000, 0x23, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(849920000, 0x22, 0x0F, 3) ) +    ( tvrx2_tda18272_freq_map_t(852992000, 0x21, 0x0E, 3) ) +    ( tvrx2_tda18272_freq_map_t(855040000, 0x20, 0x0E, 3) ) +    ( tvrx2_tda18272_freq_map_t(858112000, 0x1F, 0x0E, 3) ) +    ( tvrx2_tda18272_freq_map_t(861184000, 0x1E, 0x0E, 3) ) +    ( tvrx2_tda18272_freq_map_t(863232000, 0x1D, 0x0E, 3) ) +    ( tvrx2_tda18272_freq_map_t(866304000, 0x1C, 0x0E, 3) ) +    ( tvrx2_tda18272_freq_map_t(900096000, 0x10, 0x0C, 3) ) +    ( tvrx2_tda18272_freq_map_t(929792000, 0x07, 0x0B, 3) ) +    ( tvrx2_tda18272_freq_map_t(969728000, 0x00, 0x0A, 3) ) +; + +static const freq_range_t tvrx2_freq_range(42e6, 870e6); + +static const uhd::dict<std::string, std::string> tvrx2_sd_name_to_antennas = map_list_of +    ("RX1", "J100") +    ("RX2", "J140") +; + +static const uhd::dict<std::string, subdev_conn_t> tvrx2_sd_name_to_conn = map_list_of +    ("RX1",  SUBDEV_CONN_REAL_Q) +    ("RX2",  SUBDEV_CONN_REAL_I) +; + +static const uhd::dict<std::string, boost::uint8_t> tvrx2_sd_name_to_i2c_addr = map_list_of +    ("RX1", 0x63) +    ("RX2", 0x60) +; + +static const uhd::dict<std::string, boost::uint8_t> tvrx2_sd_name_to_irq_io = map_list_of +    ("RX1", (RX1_IRQ)) +    ("RX2", (RX2_IRQ)) +; + +static const uhd::dict<std::string, dboard_iface::aux_dac_t> tvrx2_sd_name_to_dac = map_list_of +    ("RX1", dboard_iface::AUX_DAC_A) +    ("RX2", dboard_iface::AUX_DAC_B) +; + +static const uhd::dict<std::string, gain_range_t> tvrx2_gain_ranges = map_list_of +//    ("LNA", gain_range_t(-12, 15, 3)) +//    ("RF_FILTER", gain_range_t(-11, -2, 3)) +//    ("IR_MIXER", gain_range_t(2, 14, 3)) +//    ("LPF", gain_range_t(0, 9, 3)) +    ("IF", gain_range_t(0, 30, 0.5)) +; + +/*********************************************************************** + * The TVRX2 dboard class + **********************************************************************/ +class tvrx2 : public rx_dboard_base{ +public: +    tvrx2(ctor_args_t args); +    ~tvrx2(void); + +    void rx_get(const wax::obj &key, wax::obj &val); +    void rx_set(const wax::obj &key, const wax::obj &val); + +private: +    double _freq_scalar; +    double _lo_freq; +    double _if_freq; +    double _bandwidth; +    uhd::dict<std::string, double> _gains; +    tda18272hnm_regs_t _tda18272hnm_regs; +    uhd::dict<boost::uint32_t, tvrx2_tda18272_rfcal_result_t> _rfcal_results; +    uhd::dict<boost::uint32_t, tvrx2_tda18272_rfcal_coeffs_t> _rfcal_coeffs; + +    bool _enabled; + +    void set_enabled(void); +    void set_disabled(void); + +    void set_lo_freq(double target_freq); +    void set_gain(double gain, const std::string &name); +    void set_bandwidth(double bandwidth); + +    void set_scaled_rf_freq(double rf_freq); +    double get_scaled_rf_freq(void); +    void set_scaled_if_freq(double if_freq); +    double get_scaled_if_freq(void); +    void send_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg); +    void read_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg); + +    freq_range_t get_tda18272_rfcal_result_freq_range(boost::uint32_t result); +    void tvrx2_tda18272_init_rfcal(void); +    void tvrx2_tda18272_tune_rf_filter(boost::uint32_t uRF); +    void soft_calibration(void); +    void transition_0(void); +    void transition_1(void); +    void transition_2(int rf_freq); +    void transition_3(void); +    void transition_4(int rf_freq); +    void wait_irq(void); +    void test_rf_filter_robustness(void); + +/*********************************************************************** + * The TVRX2 class helper functions + **********************************************************************/ +    /*! +     * Is the IRQ set or cleared? +     * \return true for set +     */ +    bool get_irq(void){ +        read_reg(0x8, 0x8); + +        //return irq status +        bool irq = _tda18272hnm_regs.irq_status == tda18272hnm_regs_t::IRQ_STATUS_SET; + +        UHD_LOGV(often) << boost::format( +            "TVRX2 (%s): IRQ %d" +        ) % (get_subdev_name()) % irq << std::endl; + +        return irq; +    } + +    /*! +     * In Power-On Reset State? +     *      Check POR logic for reset state (causes POR to clear) +     * \return true for reset +     */ +    bool get_power_reset(void){ +        read_reg(0x5, 0x5); + +        //return POR state +        bool por = _tda18272hnm_regs.por == tda18272hnm_regs_t::POR_RESET; + +        UHD_LOGV(often) << boost::format( +            "TVRX2 (%s): POR %d" +        ) % (get_subdev_name()) % int(_tda18272hnm_regs.por) << std::endl; + +        return por; +    } + +    /*! +     * Is the LO locked? +     * \return true for locked +     */ +    bool get_locked(void){ +        read_reg(0x5, 0x5); + +        //return lock detect +        bool locked = _tda18272hnm_regs.lo_lock == tda18272hnm_regs_t::LO_LOCK_LOCKED; + +        UHD_LOGV(often) << boost::format( +            "TVRX2 (%s): locked %d" +        ) % (get_subdev_name()) % locked << std::endl; + +        return locked; +    } + +    /*! +     * Read the RSSI from the registers +     * \return the rssi in dB(m?) FIXME +     */ +    double get_rssi(void){ +        //Launch RSSI calculation with MSM statemachine +        _tda18272hnm_regs.set_reg(0x19, 0x80); //set MSM_byte_1 for rssi calculation +        _tda18272hnm_regs.set_reg(0x1A, 0x01); //set MSM_byte_2 for launching rssi calculation + +        send_reg(0x19, 0x1A); + +        wait_irq(); + +        //read rssi in dBuV +        read_reg(0x7, 0x7); + +        //calculate the rssi from the voltage +        double rssi_dBuV = 40.0 + double(((110.0 - 40.0)/128.0) * _tda18272hnm_regs.get_reg(0x7)); +        return rssi_dBuV - 107.0; //convert to dBm in 50ohm environment ( -108.8 if 75ohm ) FIXME +    } + +    /*! +     * Read the Temperature from the registers +     * \return the temp in degC +     */ +    double get_temp(void){ +        //Enable Temperature reading +        _tda18272hnm_regs.tm_on = tda18272hnm_regs_t::TM_ON_SENSOR_ON; +        send_reg(0x4, 0x4); + +        //read temp in degC +        read_reg(0x3, 0x3); + +        UHD_LOGV(often) << boost::format( +            "TVRX2 (%s): Temperature %f C" +        ) % (get_subdev_name()) % (double(_tda18272hnm_regs.tm_d)) << std::endl; + +        //Disable Temperature reading +        _tda18272hnm_regs.tm_on = tda18272hnm_regs_t::TM_ON_SENSOR_OFF; +        send_reg(0x4, 0x4); + +        return (double(_tda18272hnm_regs.tm_d)); +    } +}; + +/*********************************************************************** + * Register the TVRX2 dboard + **********************************************************************/ +static dboard_base::sptr make_tvrx2(dboard_base::ctor_args_t args){ +    return dboard_base::sptr(new tvrx2(args)); +} + +UHD_STATIC_BLOCK(reg_tvrx2_dboard){ +    //register the factory function for the rx dbid +    dboard_manager::register_dboard(0x0046, &make_tvrx2, "TVRX2", tvrx2_sd_name_to_conn.keys()); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +tvrx2::tvrx2(ctor_args_t args) : rx_dboard_base(args){ +    //FIXME for USRP1, we can only support one TVRX2 installed + +    _rfcal_results = map_list_of +        (  0, tvrx2_tda18272_rfcal_result_t() ) +        (  1, tvrx2_tda18272_rfcal_result_t() ) +        (  2, tvrx2_tda18272_rfcal_result_t() ) +        (  3, tvrx2_tda18272_rfcal_result_t() ) +        (  4, tvrx2_tda18272_rfcal_result_t() ) +        (  5, tvrx2_tda18272_rfcal_result_t() ) +        (  6, tvrx2_tda18272_rfcal_result_t() ) +        (  7, tvrx2_tda18272_rfcal_result_t() ) +        (  8, tvrx2_tda18272_rfcal_result_t() ) +        (  9, tvrx2_tda18272_rfcal_result_t() ) +        ( 10, tvrx2_tda18272_rfcal_result_t() ) +        ( 11, tvrx2_tda18272_rfcal_result_t() ) +    ; + +    _rfcal_coeffs = map_list_of +        ( 0, tvrx2_tda18272_rfcal_coeffs_t(0) ) +        ( 1, tvrx2_tda18272_rfcal_coeffs_t(1) ) +        ( 2, tvrx2_tda18272_rfcal_coeffs_t(3) ) +        ( 3, tvrx2_tda18272_rfcal_coeffs_t(4) ) +        ( 4, tvrx2_tda18272_rfcal_coeffs_t(6) ) +        ( 5, tvrx2_tda18272_rfcal_coeffs_t(7) ) +        ( 6, tvrx2_tda18272_rfcal_coeffs_t(9) ) +        ( 7, tvrx2_tda18272_rfcal_coeffs_t(10) ) +    ; + +    //set the gpio directions and atr controls (identically) +    this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, 0); // All unused in atr +    this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, OUTPUT_MASK); // Set outputs + +    double ref_clock=0.0; + +    //configure ref_clock + +    /* +    std::vector<double> clock_rates = this->get_iface()->get_clock_rates(dboard_iface::UNIT_RX); +    BOOST_FOREACH(ref_clock, uhd::sorted(clock_rates)){ +        if (ref_clock < 16.0e6) continue;  +        if (ref_clock >= 16.0e6) break;  +    } +    this->get_iface()->set_clock_rate(dboard_iface::UNIT_RX, ref_clock); +    */ + +    ref_clock = this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX); + +    if (ref_clock == 64.0e6) { +        this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, REFCLOCK_DIV4); + +        UHD_LOGV(often) << boost::format( +            "TVRX2 (%s): Dividing Refclock by 4" +        ) % (get_subdev_name()) << std::endl; + +        _freq_scalar = (4*16.0e6)/(this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX)); +    } else if (ref_clock == 100e6) { +        this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, REFCLOCK_DIV6); + +        UHD_LOGV(often) << boost::format( +            "TVRX2 (%s): Dividing Refclock by 6" +        ) % (get_subdev_name()) << std::endl; + +        _freq_scalar = (6*16.0e6)/this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX); +    } else { +        this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, REFCLOCK_DIV6); +        UHD_MSG(warning) << boost::format("Unsupported ref_clock %0.2f, valid options 64e6 and 100e6") % ref_clock << std::endl; +        _freq_scalar = 1.0; +    } + +    //enable only the clocks we need +    this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true); + +    UHD_LOGV(often) << boost::format( +        "TVRX2 (%s): Refclock %f Hz, scalar = %f" +    ) % (get_subdev_name()) % (this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX)) % _freq_scalar << std::endl; + +    //set defaults for LO, gains, and filter bandwidth +    _bandwidth = 10e6; + +    _if_freq = 12.5e6; + +    _lo_freq = tvrx2_freq_range.start(); + +    _enabled = false; + +    //send initial register settings +    //this->read_reg(0x0, 0x43); +    //this->send_reg(0x0, 0x43); + +    //send magic xtal_cal_dac setting +    send_reg(0x65, 0x65); + +    _tda18272hnm_regs.irq_polarity = tda18272hnm_regs_t::IRQ_POLARITY_RAISED_VCC; +    _tda18272hnm_regs.irq_clear = tda18272hnm_regs_t::IRQ_CLEAR_TRUE; +    send_reg(0x37, 0x37); +    send_reg(0xA, 0xA); + +    send_reg(0x31, 0x31); //N_CP_Current +    send_reg(0x36, 0x36); //RSSI_Clock +    send_reg(0x24, 0x25); //AGC1_Do_step +    send_reg(0x2C, 0x2C); //AGC1_Do_step +    send_reg(0x2E, 0x2E); //AGC2_Do_step +    send_reg(0x0E, 0x0E); //AGCs_Up_step_assym +    send_reg(0x11, 0x11); //AGCs_Do_step_assym + +    //intialize i2c +    //soft_calibration(); +    //tvrx2_tda18272_init_rfcal(); +    transition_0(); +} + +void tvrx2::set_enabled(void){ +    //setup tuner parameters +    transition_1(); + +    transition_2(int(tvrx2_freq_range.start())); + +    test_rf_filter_robustness(); + +    BOOST_FOREACH(const std::string &name, tvrx2_gain_ranges.keys()){ +        set_gain(tvrx2_gain_ranges[name].start(), name); +    } + +    set_bandwidth(_bandwidth); // default bandwidth from datasheet + +    //transition_2 equivalent +    set_lo_freq(tvrx2_freq_range.start()); + +    //enter standby mode +    transition_3(); +    _enabled = true; +} + +tvrx2::~tvrx2(void){ +    UHD_LOGV(often) << boost::format( +        "TVRX2 (%s): Called Destructor" +    ) % (get_subdev_name()) << std::endl; +    if (_enabled) set_disabled(); +} + +void tvrx2::set_disabled(void){ +    //enter standby mode +    transition_3(); +    _enabled = false; +} + + +/*********************************************************************** + * TDA18272 Register IO Functions + **********************************************************************/ +void tvrx2::set_scaled_rf_freq(double rf_freq){ +    _tda18272hnm_regs.set_rf_freq(_freq_scalar*rf_freq/1e3); +} + +double tvrx2::get_scaled_rf_freq(void){ +    return _tda18272hnm_regs.get_rf_freq()*1e3/_freq_scalar; +} + +void tvrx2::set_scaled_if_freq(double if_freq){ +    _tda18272hnm_regs.if_freq = int(_freq_scalar*if_freq/(50e3)); //max 12.8MHz?? +} + +double tvrx2::get_scaled_if_freq(void){ +    return _tda18272hnm_regs.if_freq*50e3/_freq_scalar; +} + +void tvrx2::send_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg){ +    start_reg = boost::uint8_t(uhd::clip(int(start_reg), 0x0, 0x43)); +    stop_reg = boost::uint8_t(uhd::clip(int(stop_reg), 0x0, 0x43)); + +    for(boost::uint8_t start_addr=start_reg; start_addr <= stop_reg; start_addr += sizeof(boost::uint32_t) - 1){ +        int num_bytes = int(stop_reg - start_addr + 1) > int(sizeof(boost::uint32_t)) - 1 ? sizeof(boost::uint32_t) - 1 : stop_reg - start_addr + 1; + +        //create buffer for register data (+1 for start address) +        byte_vector_t regs_vector(num_bytes + 1); + +        //first byte is the address of first register +        regs_vector[0] = start_addr; + +        //get the register data +        for(int i=0; i<num_bytes; i++){ +            regs_vector[1+i] = _tda18272hnm_regs.get_reg(start_addr+i); +            UHD_LOGV(often) << boost::format( +                "TVRX2 (%s, 0x%02x): send reg 0x%02x, value 0x%04x, start_addr = 0x%04x, num_bytes %d" +            ) % (get_subdev_name()) % int(tvrx2_sd_name_to_i2c_addr[get_subdev_name()]) % int(start_addr+i) % int(regs_vector[1+i]) % int(start_addr) % num_bytes << std::endl; +        } + +        //send the data +        this->get_iface()->write_i2c( +            tvrx2_sd_name_to_i2c_addr[get_subdev_name()], regs_vector +        ); +    } +} + +void tvrx2::read_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg){ +    static const boost::uint8_t status_addr = 0x0; +    start_reg = boost::uint8_t(uhd::clip(int(start_reg), 0x0, 0x43)); +    stop_reg = boost::uint8_t(uhd::clip(int(stop_reg), 0x0, 0x43)); + +    for(boost::uint8_t start_addr=start_reg; start_addr <= stop_reg; start_addr += sizeof(boost::uint32_t)){ +        int num_bytes = int(stop_reg - start_addr + 1) > int(sizeof(boost::uint32_t)) ? sizeof(boost::uint32_t) : stop_reg - start_addr + 1; + +        //create buffer for starting address +        byte_vector_t start_address_vector(1); + +        //first byte is the address of first register +        start_address_vector[0] = start_addr; + +        //send the start address +        this->get_iface()->write_i2c( +            tvrx2_sd_name_to_i2c_addr[get_subdev_name()], start_address_vector +        ); + +        //create buffer for register data +        byte_vector_t regs_vector(num_bytes); + +        //read from i2c +        regs_vector = this->get_iface()->read_i2c( +            tvrx2_sd_name_to_i2c_addr[get_subdev_name()], num_bytes +        ); + +        for(boost::uint8_t i=0; i < num_bytes; i++){ +            if (i + start_addr >= status_addr){ +                _tda18272hnm_regs.set_reg(i + start_addr, regs_vector[i]); +            } +            UHD_LOGV(often) << boost::format( +                "TVRX2 (%s, 0x%02x): read reg 0x%02x, value 0x%04x, start_addr = 0x%04x, num_bytes %d" +            ) % (get_subdev_name()) % int(tvrx2_sd_name_to_i2c_addr[get_subdev_name()]) % int(start_addr+i) % int(regs_vector[i]) % int(start_addr) % num_bytes << std::endl; +        } +    } +} + + +/*********************************************************************** + * TDA18272 Calibration Functions + **********************************************************************/ +freq_range_t tvrx2::get_tda18272_rfcal_result_freq_range(boost::uint32_t result) +{ + +    uhd::dict<boost::uint32_t, freq_range_t> result_to_cal_freq_ranges_map = map_list_of +        ( 0, freq_range_t( +                 (double) tvrx2_tda18272_cal_map[0].cal_freq[_tda18272hnm_regs.rfcal_freq0] * _freq_scalar, +                 (double) tvrx2_tda18272_cal_map[1].cal_freq[_tda18272hnm_regs.rfcal_freq1] * _freq_scalar +                 ) ) +        ( 1, freq_range_t( +                 (double) tvrx2_tda18272_cal_map[1].cal_freq[_tda18272hnm_regs.rfcal_freq1] * _freq_scalar, +                 (double) tvrx2_tda18272_cal_map[2].cal_freq[_tda18272hnm_regs.rfcal_freq2] * _freq_scalar +                 ) ) +        ( 2, freq_range_t( +                 (double) tvrx2_tda18272_cal_map[2].cal_freq[_tda18272hnm_regs.rfcal_freq2] * _freq_scalar, +                 (double) tvrx2_tda18272_cal_map[3].cal_freq[_tda18272hnm_regs.rfcal_freq3] * _freq_scalar +                 ) ) +        ( 3, freq_range_t( +                 (double) tvrx2_tda18272_cal_map[3].cal_freq[_tda18272hnm_regs.rfcal_freq3] * _freq_scalar, +                 (double) tvrx2_tda18272_cal_map[4].cal_freq[_tda18272hnm_regs.rfcal_freq4] * _freq_scalar +                 ) ) +        ( 4, freq_range_t( +                 (double) tvrx2_tda18272_cal_map[4].cal_freq[_tda18272hnm_regs.rfcal_freq4] * _freq_scalar, +                 (double) tvrx2_tda18272_cal_map[5].cal_freq[_tda18272hnm_regs.rfcal_freq5] * _freq_scalar +                 ) ) +        ( 5, freq_range_t( +                 (double) tvrx2_tda18272_cal_map[5].cal_freq[_tda18272hnm_regs.rfcal_freq5] * _freq_scalar, +                 (double) tvrx2_tda18272_cal_map[6].cal_freq[_tda18272hnm_regs.rfcal_freq6] * _freq_scalar +                 ) ) +        ( 6, freq_range_t( +                 (double) tvrx2_tda18272_cal_map[6].cal_freq[_tda18272hnm_regs.rfcal_freq6] * _freq_scalar, +                 (double) tvrx2_tda18272_cal_map[7].cal_freq[_tda18272hnm_regs.rfcal_freq7] * _freq_scalar +                 ) ) +        ( 7, freq_range_t( +                 (double) tvrx2_tda18272_cal_map[7].cal_freq[_tda18272hnm_regs.rfcal_freq7] * _freq_scalar, +                 (double) tvrx2_tda18272_cal_map[8].cal_freq[_tda18272hnm_regs.rfcal_freq8] * _freq_scalar +                 ) ) +        ( 8, freq_range_t( +                 (double) tvrx2_tda18272_cal_map[8].cal_freq[_tda18272hnm_regs.rfcal_freq8] * _freq_scalar, +                 (double) tvrx2_tda18272_cal_map[9].cal_freq[_tda18272hnm_regs.rfcal_freq9] * _freq_scalar +                 ) ) +        ( 9, freq_range_t( +                 (double) tvrx2_tda18272_cal_map[9].cal_freq[_tda18272hnm_regs.rfcal_freq9] * _freq_scalar, +                 (double) tvrx2_tda18272_cal_map[10].cal_freq[_tda18272hnm_regs.rfcal_freq10] * _freq_scalar +                 ) ) +        (10, freq_range_t( +                 (double) tvrx2_tda18272_cal_map[10].cal_freq[_tda18272hnm_regs.rfcal_freq10] * _freq_scalar, +                 (double) tvrx2_tda18272_cal_map[11].cal_freq[_tda18272hnm_regs.rfcal_freq11] * _freq_scalar +                 ) ) +    ; + +    if (result < 11) +        return result_to_cal_freq_ranges_map[result];  +    else +        return freq_range_t(0.0, 0.0); +} + + +/* + * Initialize the RF Filter calibration maps after hardware init + */ +void tvrx2::tvrx2_tda18272_init_rfcal(void) +{ + +    /* read byte 0x38-0x43 */ +    read_reg(0x38, 0x43); + +    uhd::dict<boost::uint32_t, boost::uint8_t> result_to_cal_regs = map_list_of +        ( 0, _tda18272hnm_regs.rfcal_log_1) +        ( 1, _tda18272hnm_regs.rfcal_log_2) +        ( 2, _tda18272hnm_regs.rfcal_log_3) +        ( 3, _tda18272hnm_regs.rfcal_log_4) +        ( 4, _tda18272hnm_regs.rfcal_log_5) +        ( 5, _tda18272hnm_regs.rfcal_log_6) +        ( 6, _tda18272hnm_regs.rfcal_log_7) +        ( 7, _tda18272hnm_regs.rfcal_log_8) +        ( 8, _tda18272hnm_regs.rfcal_log_9) +        ( 9, _tda18272hnm_regs.rfcal_log_10) +        (10, _tda18272hnm_regs.rfcal_log_11) +        (11, _tda18272hnm_regs.rfcal_log_12) +    ; + + +    // Loop through rfcal_log_* registers, initialize _rfcal_results +    BOOST_FOREACH(const boost::uint32_t &result, result_to_cal_regs.keys()) +        _rfcal_results[result].delta_c = result_to_cal_regs[result] > 63 ? result_to_cal_regs[result] - 128 : result_to_cal_regs[result]; + +    /* read byte 0x26-0x2B */ +    read_reg(0x26, 0x2B); + +    // Loop through rfcal_byte_* registers, initialize _rfcal_coeffs +    BOOST_FOREACH(const boost::uint32_t &subband, _rfcal_coeffs.keys()) +    { +        freq_range_t subband_freqs; + +        boost::uint32_t result = _rfcal_coeffs[subband].cal_number; + +        subband_freqs = get_tda18272_rfcal_result_freq_range(result); + +        _rfcal_coeffs[subband].RF_B1 = _rfcal_results[result].delta_c + tvrx2_tda18272_cal_map[result].c_offset[_rfcal_results[result].c_offset]; + +        boost::uint32_t quotient = (((_rfcal_results[result+1].delta_c + tvrx2_tda18272_cal_map[result+1].c_offset[_rfcal_results[result].c_offset]) +                                        - (_rfcal_results[result].delta_c + tvrx2_tda18272_cal_map[result].c_offset[_rfcal_results[result].c_offset])) * 1000000); + +        boost::uint32_t divisor = ((boost::int32_t)(subband_freqs.stop() - subband_freqs.start())/1000); + +        _rfcal_coeffs[subband].RF_A1 = quotient / divisor; + +    } + +} + +/* + * Apply calibration coefficients to RF Filter tuning + */ +void tvrx2::tvrx2_tda18272_tune_rf_filter(boost::uint32_t uRF) +{ +    boost::uint32_t                  uCounter = 0; +    boost::uint8_t                   cal_result = 0; +    boost::uint32_t                  uRFCal0 = 0; +    boost::uint32_t                  uRFCal1 = 0; +    boost::uint8_t                   subband = 0; +    boost::int32_t                   cProg = 0; +    boost::uint8_t                   gain_taper = 0; +    boost::uint8_t                   RFBand = 0; +    boost::int32_t                   RF_A1 = 0; +    boost::int32_t                   RF_B1 = 0; +    freq_range_t                     subband_freqs; + +    /* read byte 0x26-0x2B */ +    read_reg(0x26, 0x2B); + +    subband_freqs = get_tda18272_rfcal_result_freq_range(1); +    uRFCal0 = subband_freqs.start(); +    subband_freqs = get_tda18272_rfcal_result_freq_range(4); +    uRFCal1 = subband_freqs.start(); + +    if(uRF < uRFCal0) +        subband = 0; +    else if(uRF < 145700000) +        subband = 1; +    else if(uRF < uRFCal1) +        subband = 2; +    else if(uRF < 367400000) +        subband = 3; +    else +    { +        subband_freqs = get_tda18272_rfcal_result_freq_range(7); +        uRFCal0 = subband_freqs.start(); +        subband_freqs = get_tda18272_rfcal_result_freq_range(10); +        uRFCal1 = subband_freqs.start(); + +        if(uRF < uRFCal0) +            subband = 4; +        else if(uRF < 625000000) +            subband = 5; +        else if(uRF < uRFCal1) +            subband = 6; +        else +            subband = 7; +    } + +    cal_result = _rfcal_coeffs[subband].cal_number; +    subband_freqs = get_tda18272_rfcal_result_freq_range(cal_result); +    uRFCal0 = subband_freqs.start(); + +    RF_A1 = _rfcal_coeffs[subband].RF_A1; +    RF_B1 = _rfcal_coeffs[subband].RF_B1; + +    uCounter = 0; +    do uCounter ++; +    while (uRF >= tvrx2_tda18272_freq_map[uCounter].rf_max && uCounter < TVRX2_TDA18272_FREQ_MAP_ENTRIES); + +    cProg = tvrx2_tda18272_freq_map[uCounter - 1].c_prog; +    gain_taper = tvrx2_tda18272_freq_map[uCounter - 1].gain_taper; +    RFBand = tvrx2_tda18272_freq_map[uCounter - 1].rf_band; + +    cProg = (boost::int32_t)(cProg + RF_B1 + (RF_A1*((boost::int32_t)(uRF - uRFCal0)/1000))/1000000); + +    if(cProg>255)   cProg = 255; +    if(cProg<0)     cProg = 0; + +    _tda18272hnm_regs.rf_filter_bypass = 1; +    _tda18272hnm_regs.rf_filter_cap = (boost::uint8_t) cProg; +    _tda18272hnm_regs.gain_taper = gain_taper; +    _tda18272hnm_regs.rf_filter_band = RFBand; + +    UHD_LOGV(often) << boost::format( +        "\nTVRX2 (%s): Software Calibration:\n" +        "\tRF Filter Bypass = %d\n" +        "\tRF Filter Cap    = %d\n" +        "\tRF Filter Band   = %d\n" +        "\tGain Taper       = %d\n")  +        % (get_subdev_name()) +        % int(_tda18272hnm_regs.rf_filter_bypass) +        % int(_tda18272hnm_regs.rf_filter_cap) +        % int(_tda18272hnm_regs.rf_filter_band)  +        % int(_tda18272hnm_regs.gain_taper) +        << std::endl; + +    send_reg(0x2c, 0x2f); +} + +void tvrx2::soft_calibration(void){ +    UHD_LOGV(often) << boost::format( +        "\nTVRX2 (%s): Software Calibration: Initialize Tuner, Calibrate and Standby\n") % (get_subdev_name()) << std::endl; + +    _tda18272hnm_regs.sm = tda18272hnm_regs_t::SM_NORMAL; +    _tda18272hnm_regs.sm_lna = tda18272hnm_regs_t::SM_LNA_ON; +    _tda18272hnm_regs.sm_pll = tda18272hnm_regs_t::SM_PLL_ON; + +    send_reg(0x6, 0x6); +    read_reg(0x6, 0x6); + +    read_reg(0x19, 0x1A); +    read_reg(0x26, 0x2B); + +    _tda18272hnm_regs.rfcal_freq0  = 0x2; +    _tda18272hnm_regs.rfcal_freq1  = 0x2; +    _tda18272hnm_regs.rfcal_freq2  = 0x2; +    _tda18272hnm_regs.rfcal_freq3  = 0x2; +    _tda18272hnm_regs.rfcal_freq4  = 0x2; +    _tda18272hnm_regs.rfcal_freq5  = 0x2; +    _tda18272hnm_regs.rfcal_freq6  = 0x2; +    _tda18272hnm_regs.rfcal_freq7  = 0x2; +    _tda18272hnm_regs.rfcal_freq8  = 0x2; +    _tda18272hnm_regs.rfcal_freq9  = 0x2; +    _tda18272hnm_regs.rfcal_freq10 = 0x2; +    _tda18272hnm_regs.rfcal_freq11 = 0x2; + +    send_reg(0x26, 0x2B); + +    _tda18272hnm_regs.set_reg(0x19, 0x3B); //set MSM_byte_1 for calibration per datasheet +    _tda18272hnm_regs.set_reg(0x1A, 0x01); //set MSM_byte_2 for launching calibration + +    send_reg(0x19, 0x1A); + +    wait_irq(); + +    send_reg(0x1D, 0x1D); //Fmax_LO +    send_reg(0x0C, 0x0C); //LT_Enable +    send_reg(0x1B, 0x1B); //PSM_AGC1 +    send_reg(0x0C, 0x0C); //AGC1_6_15dB + +    //set spread spectrum for clock  +    //FIXME: NXP turns clock spread on and off  +    //   based on where clock spurs would be relative to RF frequency +    //   we should do this also +    _tda18272hnm_regs.digital_clock = tda18272hnm_regs_t::DIGITAL_CLOCK_SPREAD_OFF; +    if (get_subdev_name() == "RX1") +        //_tda18272hnm_regs.xtout = tda18272hnm_regs_t::XTOUT_NO; +        _tda18272hnm_regs.xtout = tda18272hnm_regs_t::XTOUT_16MHZ; +    else +        //_tda18272hnm_regs.xtout = tda18272hnm_regs_t::XTOUT_NO; +        _tda18272hnm_regs.xtout = tda18272hnm_regs_t::XTOUT_16MHZ; +     +    send_reg(0x14, 0x14); + +    _tda18272hnm_regs.set_reg(0x36, 0x0E); //sets clock mode +    send_reg(0x36, 0x36); + +    //go to standby mode +    _tda18272hnm_regs.sm = tda18272hnm_regs_t::SM_STANDBY; +    send_reg(0x6, 0x6); +} + +void tvrx2::test_rf_filter_robustness(void){ +    typedef uhd::dict<std::string, std::string> tvrx2_filter_ratings_t; +    typedef uhd::dict<std::string, double> tvrx2_filter_margins_t; + +    tvrx2_filter_margins_t _filter_margins; +    tvrx2_filter_ratings_t _filter_ratings; + +    read_reg(0x38, 0x43); + +    uhd::dict<std::string, boost::uint8_t> filter_cal_regs = map_list_of +        ("VHFLow_0", 0x38) +        ("VHFLow_1", 0x3a) +        ("VHFHigh_0", 0x3b) +        ("VHFHigh_1", 0x3d) +        ("UHFLow_0", 0x3e) +        ("UHFLow_1", 0x40) +        ("UHFHigh_0", 0x41) +        ("UHFHigh_1", 0x43) +    ; + +    BOOST_FOREACH(const std::string &name, filter_cal_regs.keys()){ +        boost::uint8_t cal_result = _tda18272hnm_regs.get_reg(filter_cal_regs[name]); +        if (cal_result & 0x80) { +            _filter_ratings.set(name, "E"); +            _filter_margins.set(name, 0.0); +        } +        else { +            double partial; + +            if (name == "VHFLow_0") +                partial = 100 * (45 - 39.8225 * (1 + (0.31 * (cal_result < 64 ? cal_result : cal_result - 128)) / 1.0 / 100.0)) / 45.0; + +            else if (name == "VHFLow_1") +                partial = 100 * (152.1828 * (1 + (1.53 * (cal_result < 64 ? cal_result : cal_result - 128)) / 1.0 / 100.0) - (144.896 - 6)) / (144.896 - 6);  + +            else if (name == "VHFHigh_0") +                partial = 100 * ((144.896 + 6) - 135.4063 * (1 + (0.27 * (cal_result < 64 ? cal_result : cal_result - 128)) / 1.0 / 100.0)) / (144.896 + 6); + +            else if (name == "VHFHigh_1") +                partial = 100 * (383.1455 * (1 + (0.91 * (cal_result < 64 ? cal_result : cal_result - 128)) / 1.0 / 100.0) - (367.104 - 8)) / (367.104 - 8); + +            else if (name == "UHFLow_0") +                partial = 100 * ((367.104 + 8) - 342.6224 * (1 + (0.21 * (cal_result < 64 ? cal_result : cal_result - 128)) / 1.0 / 100.0)) / (367.104 + 8); + +            else if (name == "UHFLow_1") +                partial = 100 * (662.5595 * (1 + (0.33 * (cal_result < 64 ? cal_result : cal_result - 128)) / 1.0 / 100.0) - (624.128 - 2)) / (624.128 - 2); + +            else if (name == "UHFHigh_0") +                partial = 100 * ((624.128 + 2) - 508.2747 * (1 + (0.23 * (cal_result < 64 ? cal_result : cal_result - 128)) / 1.0 / 100.0)) / (624.128 + 2); + +            else if (name == "UHFHigh_1") +                partial = 100 * (947.8913 * (1 + (0.3 * (cal_result < 64 ? cal_result : cal_result - 128)) / 1.0 / 100.0) - (866 - 14)) / (866 - 14); + +            else +                UHD_THROW_INVALID_CODE_PATH(); + +            _filter_margins.set(name, 0.0024 * partial * partial * partial - 0.101 * partial * partial + 1.629 * partial + 1.8266); +            _filter_ratings.set(name, _filter_margins[name] >= 0.0 ? "H" : "L"); +        } +    } + +    std::stringstream robustness_message; +    robustness_message << boost::format("TVRX2 (%s): RF Filter Robustness Results:") % (get_subdev_name()) << std::endl; +    BOOST_FOREACH(const std::string &name, uhd::sorted(_filter_ratings.keys())){ +        robustness_message << boost::format("\t%s:\tMargin = %0.2f,\tRobustness = %c") % name % (_filter_margins[name]) % (_filter_ratings[name]) << std::endl; +    } + +    UHD_LOGV(often) << robustness_message.str(); +} + +/*********************************************************************** + * TDA18272 State Functions + **********************************************************************/ +void tvrx2::transition_0(void){ +    //Transition 0: Initialize Tuner and place in standby +    UHD_LOGV(often) << boost::format( +        "\nTVRX2 (%s): Transistion 0: Initialize Tuner, Calibrate and Standby\n") % (get_subdev_name()) << std::endl; + +    //Check for Power-On Reset, if reset, initialze tuner +    if (get_power_reset()) { +        _tda18272hnm_regs.sm = tda18272hnm_regs_t::SM_NORMAL; +        _tda18272hnm_regs.sm_lna = tda18272hnm_regs_t::SM_LNA_ON; +        _tda18272hnm_regs.sm_pll = tda18272hnm_regs_t::SM_PLL_ON; + +        send_reg(0x6, 0x6); +        read_reg(0x6, 0x6); + +        read_reg(0x19, 0x1A); + +        _tda18272hnm_regs.set_reg(0x19, 0x3B); //set MSM_byte_1 for calibration per datasheet +        _tda18272hnm_regs.set_reg(0x1A, 0x01); //set MSM_byte_2 for launching calibration + +        send_reg(0x19, 0x1A); + +        wait_irq(); +    } + +    //send magic xtal_cal_dac setting +    send_reg(0x65, 0x65); + +    send_reg(0x1D, 0x1D); //Fmax_LO +    send_reg(0x0C, 0x0C); //LT_Enable +    send_reg(0x1B, 0x1B); //PSM_AGC1 +    send_reg(0x0C, 0x0C); //AGC1_6_15dB + +    //set spread spectrum for clock  +    //FIXME: NXP turns clock spread on and off  +    //   based on where clock spurs would be relative to RF frequency +    //   we should do this also +    _tda18272hnm_regs.digital_clock = tda18272hnm_regs_t::DIGITAL_CLOCK_SPREAD_OFF; +    if (get_subdev_name() == "RX1") +        //_tda18272hnm_regs.xtout = tda18272hnm_regs_t::XTOUT_NO; +        _tda18272hnm_regs.xtout = tda18272hnm_regs_t::XTOUT_16MHZ; +    else +        //_tda18272hnm_regs.xtout = tda18272hnm_regs_t::XTOUT_NO; +        _tda18272hnm_regs.xtout = tda18272hnm_regs_t::XTOUT_16MHZ; +     +    send_reg(0x14, 0x14); + +    _tda18272hnm_regs.set_reg(0x36, 0x0E); //sets clock mode +    send_reg(0x36, 0x36); + +    //go to standby mode +    _tda18272hnm_regs.sm = tda18272hnm_regs_t::SM_STANDBY; +    send_reg(0x6, 0x6); +} + +void tvrx2::transition_1(void){ +    //Transition 1: Select TV Standard +    UHD_LOGV(often) << boost::format( +        "\nTVRX2 (%s): Transistion 1: Select TV Standard\n") % (get_subdev_name()) << std::endl; + +    //send magic xtal_cal_dac setting +    send_reg(0x65, 0x65); + +    //Choose IF Byte 1 Setting +    //_tda18272hnm_regs.if_hp_fc = tda18272hnm_regs_t::IF_HP_FC_0_4MHZ; +    //_tda18272hnm_regs.if_notch = tda18272hnm_regs_t::IF_NOTCH_OFF; +    //_tda18272hnm_regs.lp_fc_offset = tda18272hnm_regs_t::LP_FC_OFFSET_0_PERCENT; +    //_tda18272hnm_regs.lp_fc = tda18272hnm_regs_t::LP_FC_10_0MHZ; +    //send_reg(0x13, 0x13); + +    //Choose IR Mixer Byte 2 Setting +    //_tda18272hnm_regs.hi_pass = tda18272hnm_regs_t::HI_PASS_DISABLE; +    //_tda18272hnm_regs.dc_notch = tda18272hnm_regs_t::DC_NOTCH_OFF; +    send_reg(0x23, 0x23); + +    //Set AGC TOP Bytes +    send_reg(0x0C, 0x13); + +    //Set PSM Byt1 +    send_reg(0x1B, 0x1B); + +    //Choose IF Frequency, setting is 50KHz steps +    set_scaled_if_freq(_if_freq); +    send_reg(0x15, 0x15); +} + +void tvrx2::transition_2(int rf_freq){ +    //Transition 2: Select RF Frequency after changing TV Standard +    UHD_LOGV(often) << boost::format( +        "\nTVRX2 (%s): Transistion 2: Select RF Frequency after changing TV Standard\n") % (get_subdev_name()) << std::endl; + +    //send magic xtal_cal_dac setting +    send_reg(0x65, 0x65); + +    //Wake up from Standby +    _tda18272hnm_regs.sm = tda18272hnm_regs_t::SM_NORMAL; +    _tda18272hnm_regs.sm_lna = tda18272hnm_regs_t::SM_LNA_ON; +    _tda18272hnm_regs.sm_pll = tda18272hnm_regs_t::SM_PLL_ON; +     +    send_reg(0x6, 0x6); +     +    //Set Clock Mode +    _tda18272hnm_regs.set_reg(0x36, 0x00); +    send_reg(0x36, 0x36); +     +    //Set desired RF Frequency +    set_scaled_rf_freq(rf_freq); +    send_reg(0x16, 0x18); +     +    //Lock PLL and tune RF Filters +    _tda18272hnm_regs.set_reg(0x19, 0x41); //set MSM_byte_1 for RF Filters Tuning, PLL Locking +    _tda18272hnm_regs.set_reg(0x1A, 0x01); //set MSM_byte_2 for launching calibration +     +    send_reg(0x19, 0x1A); +     +    wait_irq(); + +    tvrx2_tda18272_tune_rf_filter(rf_freq); + +    ////LO Lock state in Reg 0x5 LSB +    //read_reg(0x6, 0x6); + +} + +void tvrx2::transition_3(void){ +    //Transition 3: Standby Mode +    UHD_LOGV(often) << boost::format( +        "\nTVRX2 (%s): Transistion 3: Standby Mode\n") % (get_subdev_name()) << std::endl; + +    //send magic xtal_cal_dac setting +    send_reg(0x65, 0x65); + +    //Set clock mode +    _tda18272hnm_regs.set_reg(0x36, 0x0E); +    send_reg(0x36, 0x36); + +    //go to standby mode +    _tda18272hnm_regs.sm = tda18272hnm_regs_t::SM_STANDBY; +    _tda18272hnm_regs.sm_lna = tda18272hnm_regs_t::SM_LNA_OFF; +    _tda18272hnm_regs.sm_pll = tda18272hnm_regs_t::SM_PLL_OFF; +    send_reg(0x6, 0x6); +} + +void tvrx2::transition_4(int rf_freq){ +    //Transition 4: Change RF Frequency without changing TV Standard +    UHD_LOGV(often) << boost::format( +        "\nTVRX2 (%s): Transistion 4: Change RF Frequency without changing TV Standard\n") % (get_subdev_name()) << std::endl; + +    //send magic xtal_cal_dac setting +    send_reg(0x65, 0x65); + +    //Set desired RF Frequency +    set_scaled_rf_freq(rf_freq); +    send_reg(0x16, 0x18); +     +    //Lock PLL and tune RF Filters +    _tda18272hnm_regs.set_reg(0x19, 0x41); //set MSM_byte_1 for RF Filters Tuning, PLL Locking +    _tda18272hnm_regs.set_reg(0x1A, 0x01); //set MSM_byte_2 for launching calibration +     +    send_reg(0x19, 0x1A); +     +    wait_irq(); + +    tvrx2_tda18272_tune_rf_filter(rf_freq); + +    ////LO Lock state in Reg 0x5 LSB +    //read_reg(0x5, 0x6); + +} + +void tvrx2::wait_irq(void){ +    int timeout = 20; //irq waiting timeout in milliseconds +    //int irq = (this->get_iface()->read_gpio(dboard_iface::UNIT_RX) & int(tvrx2_sd_name_to_irq_io[get_subdev_name()])); +    bool irq = get_irq(); +    UHD_LOGV(often) << boost::format( +        "\nTVRX2 (%s): Waiting on IRQ, subdev = %d, mask = 0x%x, Status: 0x%x\n") % (get_subdev_name()) % get_subdev_name() % (int(tvrx2_sd_name_to_irq_io[get_subdev_name()])) % irq << std::endl; + +    while (not irq and timeout > 0) { +        //irq = (this->get_iface()->read_gpio(dboard_iface::UNIT_RX) & tvrx2_sd_name_to_irq_io[get_subdev_name()]); +        irq = get_irq(); +        boost::this_thread::sleep(boost::posix_time::milliseconds(10)); +        timeout -= 1; +    } + +    UHD_LOGV(often) << boost::format( +        "\nTVRX2 (%s): IRQ Raised, subdev = %d, mask = 0x%x, Status: 0x%x, Timeout: %d\n") % (get_subdev_name()) % get_subdev_name() % (int(tvrx2_sd_name_to_irq_io[get_subdev_name()])) % irq % timeout << std::endl; + +    read_reg(0xA, 0xB); +    //UHD_ASSERT_THROW(timeout > 0); +    if(timeout <= 0) UHD_MSG(warning) << boost::format( +        "\nTVRX2 (%s): Timeout waiting on IRQ\n") % (get_subdev_name()) << std::endl; + +    _tda18272hnm_regs.irq_clear = tda18272hnm_regs_t::IRQ_CLEAR_TRUE; +    send_reg(0xA, 0xA); +    read_reg(0xA, 0xB); + +    irq = (this->get_iface()->read_gpio(dboard_iface::UNIT_RX) & tvrx2_sd_name_to_irq_io[get_subdev_name()]); + +    UHD_LOGV(often) << boost::format( +        "\nTVRX2 (%s): Cleared IRQ, subdev = %d, mask = 0x%x, Status: 0x%x\n") % (get_subdev_name()) % get_subdev_name() % (int(tvrx2_sd_name_to_irq_io[get_subdev_name()])) % irq << std::endl; +} + + + +/*********************************************************************** + * Tuning + **********************************************************************/ +void tvrx2::set_lo_freq(double target_freq){ +    //target_freq = std::clip(target_freq, tvrx2_freq_range.min, tvrx2_freq_range.max); + +    read_reg(0x6, 0x6); + +    if (_tda18272hnm_regs.sm == tda18272hnm_regs_t::SM_STANDBY) { +        transition_2(int(target_freq + _bandwidth/2 - get_scaled_if_freq())); +    } else { +        transition_4(int(target_freq + _bandwidth/2 - get_scaled_if_freq())); +    } +    read_reg(0x16, 0x18); + +    //compute actual tuned frequency +    _lo_freq = get_scaled_rf_freq() + get_scaled_if_freq(); // - _bandwidth/2; + +    //debug output of calculated variables +    UHD_LOGV(often) << boost::format( +        "\nTVRX2 (%s): LO Frequency\n" +        "\tRequested: \t%f\n" +        "\tComputed: \t%f\n" +        "\tReadback: \t%f\n" +        "\tIF Frequency: \t%f\n") % (get_subdev_name()) % target_freq % double(int(target_freq/1e3)*1e3) % get_scaled_rf_freq() % get_scaled_if_freq() << std::endl; + +    get_locked(); + +    test_rf_filter_robustness(); + +    UHD_LOGV(often) << boost::format( +        "\nTVRX2 (%s): RSSI = %f dBm\n" +    ) % (get_subdev_name()) % (get_rssi()) << std::endl; +} + +/*********************************************************************** + * Gain Handling + **********************************************************************/ +/* + * Convert the requested gain into a dac voltage + */ +static double gain_to_if_gain_dac(double &gain){ +    //clip the input +    gain = tvrx2_gain_ranges["IF"].clip(gain); + +    //voltage level constants +    static const double max_volts = double(1.7), min_volts = double(0.5); +    static const double slope = (max_volts-min_volts)/tvrx2_gain_ranges["IF"].stop(); + +    //calculate the voltage for the aux dac +    double dac_volts = gain*slope + min_volts; + +    UHD_LOGV(often) << boost::format( +        "TVRX2 IF Gain: %f dB, dac_volts: %f V" +    ) % gain % dac_volts << std::endl; + +    //the actual gain setting +    gain = (dac_volts - min_volts)/slope; + +    return dac_volts; +} + +void tvrx2::set_gain(double gain, const std::string &name){ +    assert_has(tvrx2_gain_ranges.keys(), name, "tvrx2 gain name"); + +    if (name == "IF"){ +        //write voltage to aux_dac +        this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, tvrx2_sd_name_to_dac[get_subdev_name()], gain_to_if_gain_dac(gain)); +    } +    else UHD_THROW_INVALID_CODE_PATH(); + +    //shadow gain setting +    _gains[name] = gain; +} + +/*********************************************************************** + * Bandwidth Handling + **********************************************************************/ +static tda18272hnm_regs_t::lp_fc_t bandwidth_to_lp_fc_reg(double &bandwidth){ +    int reg = uhd::clip(boost::math::iround((bandwidth-5.0e6)/1.0e6), 0, 4); + +    switch(reg){ +    case 0: +        bandwidth = 1.7e6; +        return tda18272hnm_regs_t::LP_FC_1_7MHZ; +    case 1: +        bandwidth = 6e6; +        return tda18272hnm_regs_t::LP_FC_6_0MHZ; +    case 2: +        bandwidth = 7e6; +        return tda18272hnm_regs_t::LP_FC_7_0MHZ; +    case 3: +        bandwidth = 8e6; +        return tda18272hnm_regs_t::LP_FC_8_0MHZ; +    case 4: +        bandwidth = 10e6; +        return tda18272hnm_regs_t::LP_FC_10_0MHZ; +    } +    UHD_THROW_INVALID_CODE_PATH(); +} + +void tvrx2::set_bandwidth(double bandwidth){ +    //compute low pass cutoff frequency setting +    _tda18272hnm_regs.lp_fc = bandwidth_to_lp_fc_reg(bandwidth); + +    //shadow bandwidth setting +    _bandwidth = bandwidth; + +    //update register +    send_reg(0x13, 0x13); + +    UHD_LOGV(often) << boost::format( +        "TVRX2 (%s) Bandwidth (lp_fc): %f Hz, reg: %d" +    ) % (get_subdev_name()) % _bandwidth % (int(_tda18272hnm_regs.lp_fc)) << std::endl; +} + +/*********************************************************************** + * RX Get and Set + **********************************************************************/ +void tvrx2::rx_get(const wax::obj &key_, wax::obj &val){ +    named_prop_t key = named_prop_t::extract(key_); + +    //handle the get request conditioned on the key +    switch(key.as<subdev_prop_t>()){ +    case SUBDEV_PROP_NAME: +        val = get_rx_id().to_pp_string(); +        return; + +    case SUBDEV_PROP_OTHERS: +        val = prop_names_t(); //empty +        return; + +    case SUBDEV_PROP_GAIN: +        assert_has(_gains.keys(), key.name, "tvrx2 gain name"); +        val = _gains[key.name]; +        return; + +    case SUBDEV_PROP_GAIN_RANGE: +        assert_has(tvrx2_gain_ranges.keys(), key.name, "tvrx2 gain name"); +        val = tvrx2_gain_ranges[key.name]; +        return; + +    case SUBDEV_PROP_GAIN_NAMES: +        val = prop_names_t(tvrx2_gain_ranges.keys()); +        return; + +    case SUBDEV_PROP_FREQ: +        val = _lo_freq; +        return; + +    case SUBDEV_PROP_FREQ_RANGE: +        val = tvrx2_freq_range; +        return; + +    case SUBDEV_PROP_ANTENNA: +        val = tvrx2_sd_name_to_antennas[get_subdev_name()]; +        return; + +    case SUBDEV_PROP_ANTENNA_NAMES: +        val = prop_names_t(1, tvrx2_sd_name_to_antennas[get_subdev_name()]); +        return; + +    case SUBDEV_PROP_CONNECTION: +        val = tvrx2_sd_name_to_conn[get_subdev_name()]; +        return; + +    case SUBDEV_PROP_ENABLED: +        val = _enabled; +        return; + +    case SUBDEV_PROP_USE_LO_OFFSET: +        val = false; +        return; + +    case SUBDEV_PROP_SENSOR: +        if (key.name == "lo_locked") +            val = sensor_value_t("LO", this->get_locked(), "locked", "unlocked"); +        else if (key.name == "rssi") +            val = sensor_value_t("RSSI", this->get_rssi(), "dBm"); +        else if (key.name == "temperature") +            val = sensor_value_t("TEMP", this->get_temp(), "degC"); +        else +            UHD_THROW_INVALID_CODE_PATH(); +        return; + +    case SUBDEV_PROP_SENSOR_NAMES:{ +            prop_names_t names = list_of("lo_locked")("rssi")("temperature"); +            val = names; +        } +        return; + +    case SUBDEV_PROP_BANDWIDTH: +        val = _bandwidth; +        return; + +    default: UHD_THROW_PROP_GET_ERROR(); +    } +} + +void tvrx2::rx_set(const wax::obj &key_, const wax::obj &val){ +    named_prop_t key = named_prop_t::extract(key_); + +    //handle the get request conditioned on the key +    switch(key.as<subdev_prop_t>()){ + +    case SUBDEV_PROP_FREQ: +        this->set_lo_freq(val.as<double>()); +        return; + +    case SUBDEV_PROP_GAIN: +        this->set_gain( val.as<double>(), key.name); +        return; + +    case SUBDEV_PROP_ANTENNA: +        return; + +    case SUBDEV_PROP_ENABLED: +        if ((val.as<bool>())) this->set_enabled(); +        else if (not (val.as<bool>())) this->set_disabled(); + +        return; + +    case SUBDEV_PROP_BANDWIDTH: +        this->set_bandwidth(val.as<double>()); +        return; + +    default: UHD_THROW_PROP_SET_ERROR(); +    } +} + diff --git a/host/lib/usrp/mboard_eeprom.cpp b/host/lib/usrp/mboard_eeprom.cpp index 297de990f..2ee4a9284 100644 --- a/host/lib/usrp/mboard_eeprom.cpp +++ b/host/lib/usrp/mboard_eeprom.cpp @@ -252,8 +252,7 @@ struct e100_eeprom_map{      unsigned char env_var[16];      unsigned char env_setting[64];      unsigned char serial[10]; -    unsigned char name[16]; -    unsigned char mcr[sizeof(float)]; +    unsigned char name[NAME_MAX_LEN];  };  template <typename T> static const byte_vector_t to_bytes(const T &item){ @@ -285,20 +284,6 @@ static void load_e100(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){      load_e100_string_xx(env_setting);      load_e100_string_xx(serial);      load_e100_string_xx(name); - -    //extract the master clock rate -    float master_clock_rate = 0; -    const byte_vector_t rate_bytes = iface.read_eeprom( -        E100_EEPROM_ADDR, offsetof(e100_eeprom_map, mcr), sizeof(master_clock_rate) -    ); -    std::copy( -        rate_bytes.begin(), rate_bytes.end(), //source -        reinterpret_cast<boost::uint8_t *>(&master_clock_rate) //destination -    ); -    if (master_clock_rate > 1e6 and master_clock_rate < 1e9){ -        mb_eeprom["mcr"] = boost::lexical_cast<std::string>(master_clock_rate); -    } -    else mb_eeprom["mcr"] = "";  }  static void store_e100(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){ @@ -333,18 +318,6 @@ static void store_e100(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){      store_e100_string_xx(env_setting);      store_e100_string_xx(serial);      store_e100_string_xx(name); - -    //store the master clock rate -    if (mb_eeprom.has_key("mcr")){ -        const float master_clock_rate = float(boost::lexical_cast<double>(mb_eeprom["mcr"])); -        const byte_vector_t rate_bytes( -            reinterpret_cast<const boost::uint8_t *>(&master_clock_rate), -            reinterpret_cast<const boost::uint8_t *>(&master_clock_rate) + sizeof(master_clock_rate) -        ); -        iface.write_eeprom( -            E100_EEPROM_ADDR, offsetof(e100_eeprom_map, mcr), rate_bytes -        ); -    }  }  /*********************************************************************** diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp index 9f1e4975a..66b11b989 100644 --- a/host/lib/usrp/usrp1/dsp_impl.cpp +++ b/host/lib/usrp/usrp1/dsp_impl.cpp @@ -103,17 +103,16 @@ void usrp1_impl::rx_dsp_set(const wax::obj &key_, const wax::obj &val, size_t wh          {              size_t rate = size_t(_clock_ctrl->get_master_clock_freq() / val.as<double>()); -            if ((rate & 0x01) || (rate < 4) || (rate > 256)) { -                UHD_MSG(error) << "Decimation must be even and between 4 and 256" -                          << std::endl; -                return; -            } +            //clip the rate to something in range: +            rate = std::min<size_t>(std::max<size_t>(rate, 4), 256);              _rx_dsp_decim = rate;              //TODO Poll every 100ms. Make it selectable?              _rx_samps_per_poll_interval = size_t(0.1 * _clock_ctrl->get_master_clock_freq() / rate); +            bool s = this->disable_rx();              _iface->poke32(FR_DECIM_RATE, _rx_dsp_decim/2 - 1); +            this->restore_rx(s);          }          return; @@ -164,11 +163,11 @@ void usrp1_impl::tx_dsp_get(const wax::obj &key_, wax::obj &val, size_t which_ds          return;      case DSP_PROP_CODEC_RATE: -        val = _clock_ctrl->get_master_clock_freq() * 2; +        val = _clock_ctrl->get_master_clock_freq();          return;      case DSP_PROP_HOST_RATE: -        val = _clock_ctrl->get_master_clock_freq() * 2 / _tx_dsp_interp; +        val = _clock_ctrl->get_master_clock_freq() / _tx_dsp_interp;          return;      default: UHD_THROW_PROP_GET_ERROR(); @@ -199,20 +198,19 @@ void usrp1_impl::tx_dsp_set(const wax::obj &key_, const wax::obj &val, size_t wh      case DSP_PROP_HOST_RATE:          if (which_dsp != 0) return; //only for dsp[0] as this is vectorized          { -            size_t rate = size_t(_clock_ctrl->get_master_clock_freq() * 2 / val.as<double>()); +            size_t rate = size_t(_clock_ctrl->get_master_clock_freq() / val.as<double>()); -            if ((rate & 0x01) || (rate < 8) || (rate > 512)) { -                UHD_MSG(error) << "Interpolation rate must be even and between 8 and 512" -                          << std::endl; -                return; -            } +            //clip the rate to something in range: +            rate = std::min<size_t>(std::max<size_t>(rate, 4), 256);              _tx_dsp_interp = rate;              //TODO Poll every 100ms. Make it selectable?  -            _tx_samps_per_poll_interval = size_t(0.1 * _clock_ctrl->get_master_clock_freq() * 2 / rate); +            _tx_samps_per_poll_interval = size_t(0.1 * _clock_ctrl->get_master_clock_freq() / rate); -            _iface->poke32(FR_INTERP_RATE, _tx_dsp_interp / 4 - 1); +            bool s = this->disable_tx(); +            _iface->poke32(FR_INTERP_RATE, _tx_dsp_interp/2 - 1); +            this->restore_tx(s);              return;          }      default: UHD_THROW_PROP_SET_ERROR(); diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 22d078e70..8ac2696eb 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -61,39 +61,28 @@ class offset_managed_send_buffer : public managed_send_buffer{  public:      typedef boost::function<void(offset_send_buffer&, offset_send_buffer&, size_t)> commit_cb_type;      offset_managed_send_buffer(const commit_cb_type &commit_cb): -        _expired(true), _commit_cb(commit_cb) +        _commit_cb(commit_cb)      {          /* NOP */      } -    bool expired(void){return _expired;} -      void commit(size_t size){ -        if (_expired) return; -        this->_commit_cb(_curr_buff, _next_buff, size); -        _expired = true; +        if (size != 0) this->_commit_cb(_curr_buff, _next_buff, size);      }      sptr get_new(          offset_send_buffer &curr_buff,          offset_send_buffer &next_buff      ){ -        _expired = false;          _curr_buff = curr_buff;          _next_buff = next_buff; -        return sptr(this, &offset_managed_send_buffer::fake_deleter); +        return make_managed_buffer(this);      }  private: -    static void fake_deleter(void *){ -        //dont do anything and assume the bastard committed it -        //static_cast<offset_managed_send_buffer *>(obj)->commit(0); -    } -      void  *get_buff(void) const{return _curr_buff.buff->cast<char *>() + _curr_buff.offset;}      size_t get_size(void) const{return _curr_buff.buff->size()         - _curr_buff.offset;} -    bool _expired;      offset_send_buffer _curr_buff, _next_buff;      commit_cb_type _commit_cb;  }; @@ -210,7 +199,7 @@ void usrp1_impl::io_impl::flush_send_buff(void){  bool usrp1_impl::io_impl::get_send_buffs(      vrt_packet_handler::managed_send_buffs_t &buffs  ){ -    UHD_ASSERT_THROW(omsb.expired() and buffs.size() == 1); +    UHD_ASSERT_THROW(buffs.size() == 1);      //try to get a new managed buffer with timeout      offset_send_buffer next_buff(data_transport->get_send_buff(send_timeout)); @@ -240,12 +229,13 @@ void usrp1_impl::io_init(void){          boost::bind(&usrp1_impl::rx_stream_on_off, this, _1)      ); +    this->enable_tx(true); //always enabled      rx_stream_on_off(false);      _io_impl->flush_send_buff();  }  void usrp1_impl::rx_stream_on_off(bool enb){ -    return _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, enb, 0, 0, 0); +    this->enable_rx(enb);      //drain any junk in the receive transport after stop streaming command      while(not enb and _data_transport->get_recv_buff().get() != NULL){          /* NOP */ diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index cd04e7351..e9108e4f1 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -214,8 +214,8 @@ void usrp1_impl::mboard_init(void)      // Normal mode with no loopback or Rx counting      _iface->poke32(FR_MODE, 0x00000000);      _iface->poke32(FR_DEBUG_EN, 0x00000000); -    _iface->poke32(FR_RX_SAMPLE_RATE_DIV, 0x00000001); -    _iface->poke32(FR_TX_SAMPLE_RATE_DIV, 0x00000003); +    _iface->poke32(FR_RX_SAMPLE_RATE_DIV, 0x00000001); //divide by 2 +    _iface->poke32(FR_TX_SAMPLE_RATE_DIV, 0x00000001); //divide by 2      _iface->poke32(FR_DC_OFFSET_CL_EN, 0x0000000f);      // Reset offset correction registers @@ -339,7 +339,7 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val)      //handle the get request conditioned on the key      switch(key.as<mboard_prop_t>()){ -    case MBOARD_PROP_RX_SUBDEV_SPEC: +    case MBOARD_PROP_RX_SUBDEV_SPEC:{          _rx_subdev_spec = val.as<subdev_spec_t>();          if (_rx_subdev_spec.size() > this->get_num_ddcs()){              throw uhd::value_error(str(boost::format( @@ -349,10 +349,12 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val)          }          verify_rx_subdev_spec(_rx_subdev_spec, _mboard_proxy->get_link());          //set the mux and set the number of rx channels +        bool s = this->disable_rx();          _iface->poke32(FR_RX_MUX, calc_rx_mux(_rx_subdev_spec, _mboard_proxy->get_link())); -        return; +        this->restore_rx(s); +    }return; -    case MBOARD_PROP_TX_SUBDEV_SPEC: +    case MBOARD_PROP_TX_SUBDEV_SPEC:{          _tx_subdev_spec = val.as<subdev_spec_t>();          if (_tx_subdev_spec.size() > this->get_num_ducs()){              throw uhd::value_error(str(boost::format( @@ -362,8 +364,10 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val)          }          verify_tx_subdev_spec(_tx_subdev_spec, _mboard_proxy->get_link());          //set the mux and set the number of tx channels +        bool s = this->disable_tx();          _iface->poke32(FR_TX_MUX, calc_tx_mux(_tx_subdev_spec, _mboard_proxy->get_link())); -        return; +        this->restore_tx(s); +    }return;      case MBOARD_PROP_EEPROM_MAP:          // Step1: commit the map, writing only those values set. diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp index 96dc5d80c..2e6f6e014 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp @@ -210,10 +210,6 @@ public:          usrp_tx_reset(true);          usrp_rx_reset(false);          usrp_tx_reset(false); - -        //enable -        //usrp_rx_enable(true); //dont enable, enable means dont work -        //usrp_tx_enable(true);      }      void usrp_load_fpga(std::string filestring) diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.hpp b/host/lib/usrp/usrp1/usrp1_ctrl.hpp index 970ca2951..a6e4ffba7 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.hpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.hpp @@ -108,6 +108,11 @@ public:                                 unsigned char *buf,                                  boost::uint16_t len) = 0; +    //! enable/disable the rx path +    virtual void usrp_rx_enable(bool on) = 0; + +    //! enable/disable the tx path +    virtual void usrp_tx_enable(bool on) = 0;  };  #endif /* INCLUDED_USRP_CTRL_HPP */ diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 57aae1b58..b1fa986d1 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -209,6 +209,8 @@ usrp1_impl::usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport,  }  usrp1_impl::~usrp1_impl(void){ +    UHD_SAFE_CALL(this->enable_rx(false);) +    UHD_SAFE_CALL(this->enable_tx(false);)      //Safely destruct all RAII objects in a device.      //This prevents the mboard deconstructor from throwing,      //which allows the device to be safely deconstructed. diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index f53894b29..69ad9b0a0 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -205,6 +205,45 @@ private:      size_t get_num_ddcs(void);      bool has_rx_halfband(void);      bool has_tx_halfband(void); + +    //handle the enables +    bool _rx_enabled, _tx_enabled; +    void enable_rx(bool enb){ +        _rx_enabled = enb; +        _ctrl_transport->usrp_rx_enable(enb); +    } +    void enable_tx(bool enb){ +        _tx_enabled = enb; +        _ctrl_transport->usrp_tx_enable(enb); +    } + +    //conditionally disable and enable rx +    bool disable_rx(void){ +        if (_rx_enabled){ +            enable_rx(false); +            return true; +        } +        return false; +    } +    void restore_rx(bool last){ +        if (last != _rx_enabled){ +            enable_rx(last); +        } +    } + +    //conditionally disable and enable tx +    bool disable_tx(void){ +        if (_tx_enabled){ +            enable_tx(false); +            return true; +        } +        return false; +    } +    void restore_tx(bool last){ +        if (last != _tx_enabled){ +            enable_tx(last); +        } +    }  };  #endif /* INCLUDED_USRP1_IMPL_HPP */ diff --git a/host/lib/usrp/usrp_e100/clock_ctrl.cpp b/host/lib/usrp/usrp_e100/clock_ctrl.cpp index 65162dbeb..49ce0c742 100644 --- a/host/lib/usrp/usrp_e100/clock_ctrl.cpp +++ b/host/lib/usrp/usrp_e100/clock_ctrl.cpp @@ -37,7 +37,6 @@ using namespace uhd;   **********************************************************************/  static const bool ENABLE_THE_TEST_OUT = true;  static const double REFERENCE_INPUT_RATE = 10e6; -static const double DEFAULT_OUTPUT_RATE = 64e6;  /***********************************************************************   * Helpers @@ -168,7 +167,7 @@ static clock_settings_type get_clock_settings(double rate){   **********************************************************************/  class usrp_e100_clock_ctrl_impl : public usrp_e100_clock_ctrl{  public: -    usrp_e100_clock_ctrl_impl(usrp_e100_iface::sptr iface){ +    usrp_e100_clock_ctrl_impl(usrp_e100_iface::sptr iface, double master_clock_rate){          _iface = iface;          _chan_rate = 0.0;          _out_rate = 0.0; @@ -181,27 +180,13 @@ public:          _ad9522_regs.ld_pin_control = 0x00; //dld          _ad9522_regs.refmon_pin_control = 0x12; //show ref2          _ad9522_regs.lock_detect_counter = ad9522_regs_t::LOCK_DETECT_COUNTER_16CYC; +        _ad9522_regs.divider0_ignore_sync = 1; // master FPGA clock ignores sync (always on, cannot be disabled by sync pulse)          this->use_internal_ref(); -        //initialize the FPGA clock to something -        bool fpga_clock_initialized = false; -        try{ -            if (not _iface->mb_eeprom["mcr"].empty()){ -                UHD_MSG(status) << "Read FPGA clock rate from EEPROM setting." << std::endl; -                const double master_clock_rate = boost::lexical_cast<double>(_iface->mb_eeprom["mcr"]); -                UHD_MSG(status) << boost::format("Initializing FPGA clock to %fMHz...") % (master_clock_rate/1e6) << std::endl; -                this->set_fpga_clock_rate(master_clock_rate); -                fpga_clock_initialized = true; -            } -        } -        catch(const std::exception &e){ -            UHD_MSG(error) << "Error setting FPGA clock rate from EEPROM: " << e.what() << std::endl; -        } -        if (not fpga_clock_initialized){ //was not set... use the default rate -            UHD_MSG(status) << boost::format("Initializing FPGA clock to %fMHz...") % (DEFAULT_OUTPUT_RATE/1e6) << std::endl; -            this->set_fpga_clock_rate(DEFAULT_OUTPUT_RATE); -        } +        //initialize the FPGA clock rate +        UHD_MSG(status) << boost::format("Initializing FPGA clock to %fMHz...") % (master_clock_rate/1e6) << std::endl; +        this->set_fpga_clock_rate(master_clock_rate);          this->enable_test_clock(ENABLE_THE_TEST_OUT);          this->enable_rx_dboard_clock(false); @@ -358,7 +343,7 @@ public:          );          this->send_reg(0x199);          this->send_reg(0x19a); -        this->latch_regs(); +        this->soft_sync();      }      double get_rx_clock_rate(void){ @@ -393,7 +378,7 @@ public:          );          this->send_reg(0x196);          this->send_reg(0x197); -        this->latch_regs(); +        this->soft_sync();      }      double get_tx_clock_rate(void){ @@ -409,6 +394,7 @@ public:          _ad9522_regs.select_ref = ad9522_regs_t::SELECT_REF_REF2;          _ad9522_regs.enb_auto_ref_switchover = ad9522_regs_t::ENB_AUTO_REF_SWITCHOVER_MANUAL;          this->send_reg(0x01C); +        this->latch_regs();      }      void use_external_ref(void) { @@ -417,6 +403,7 @@ public:          _ad9522_regs.select_ref = ad9522_regs_t::SELECT_REF_REF1;          _ad9522_regs.enb_auto_ref_switchover = ad9522_regs_t::ENB_AUTO_REF_SWITCHOVER_MANUAL;          this->send_reg(0x01C); +        this->latch_regs();      }      void use_auto_ref(void) { @@ -424,6 +411,8 @@ public:          _ad9522_regs.enable_ref1 = 1;          _ad9522_regs.select_ref = ad9522_regs_t::SELECT_REF_REF1;          _ad9522_regs.enb_auto_ref_switchover = ad9522_regs_t::ENB_AUTO_REF_SWITCHOVER_AUTO; +        this->send_reg(0x01C); +        this->latch_regs();      }  private: @@ -459,15 +448,36 @@ private:          //wait for calibration done:          static const boost::uint8_t addr = 0x01F;          for (size_t ms10 = 0; ms10 < 100; ms10++){ +            boost::this_thread::sleep(boost::posix_time::milliseconds(10));              boost::uint32_t reg = _iface->read_spi(                  UE_SPI_SS_AD9522, spi_config_t::EDGE_RISE,                  _ad9522_regs.get_read_reg(addr), 24              );              _ad9522_regs.set_reg(addr, reg); -            if (_ad9522_regs.vco_calibration_finished) return; -            boost::this_thread::sleep(boost::posix_time::milliseconds(10)); +            if (_ad9522_regs.vco_calibration_finished) goto wait_for_ld;          }          UHD_MSG(error) << "USRP-E100 clock control: VCO calibration timeout" << std::endl; +        wait_for_ld: +        //wait for digital lock detect: +        for (size_t ms10 = 0; ms10 < 100; ms10++){ +            boost::this_thread::sleep(boost::posix_time::milliseconds(10)); +            boost::uint32_t reg = _iface->read_spi( +                UE_SPI_SS_AD9522, spi_config_t::EDGE_RISE, +                _ad9522_regs.get_read_reg(addr), 24 +            ); +            _ad9522_regs.set_reg(addr, reg); +            if (_ad9522_regs.digital_lock_detect) return; +        } +        UHD_MSG(error) << "USRP-E100 clock control: lock detection timeout" << std::endl; +    } + +    void soft_sync(void){ +        _ad9522_regs.soft_sync = 1; +        this->send_reg(0x230); +        this->latch_regs(); +        _ad9522_regs.soft_sync = 0; +        this->send_reg(0x230); +        this->latch_regs();      }      void send_all_regs(void){ @@ -492,6 +502,6 @@ private:  /***********************************************************************   * Clock Control Make   **********************************************************************/ -usrp_e100_clock_ctrl::sptr usrp_e100_clock_ctrl::make(usrp_e100_iface::sptr iface){ -    return sptr(new usrp_e100_clock_ctrl_impl(iface)); +usrp_e100_clock_ctrl::sptr usrp_e100_clock_ctrl::make(usrp_e100_iface::sptr iface, double master_clock_rate){ +    return sptr(new usrp_e100_clock_ctrl_impl(iface, master_clock_rate));  } diff --git a/host/lib/usrp/usrp_e100/clock_ctrl.hpp b/host/lib/usrp/usrp_e100/clock_ctrl.hpp index 507f914f3..6f16bc6ed 100644 --- a/host/lib/usrp/usrp_e100/clock_ctrl.hpp +++ b/host/lib/usrp/usrp_e100/clock_ctrl.hpp @@ -35,9 +35,10 @@ public:      /*!       * Make a new clock control object.       * \param iface the usrp_e100 iface object +     * \param master clock rate the FPGA rate       * \return the clock control object       */ -    static sptr make(usrp_e100_iface::sptr iface); +    static sptr make(usrp_e100_iface::sptr iface, double master_clock_rate);      /*!       * Set the rate of the fpga clock line. diff --git a/host/lib/usrp/usrp_e100/mboard_impl.cpp b/host/lib/usrp/usrp_e100/mboard_impl.cpp index d31662eb5..b2533e7ee 100644 --- a/host/lib/usrp/usrp_e100/mboard_impl.cpp +++ b/host/lib/usrp/usrp_e100/mboard_impl.cpp @@ -209,7 +209,8 @@ void usrp_e100_impl::mboard_set(const wax::obj &key, const wax::obj &val){      case MBOARD_PROP_CLOCK_RATE:          UHD_MSG(warning)              << "I see that you are setting the master clock rate from the API.\n" -            << "You may find it more convenient to burn this setting into the EEPROM.\n" +            << "You may want to pass this into the device address as mcr=<rate>.\n" +            << "This way, the clock rate is guaranteed to be initialized first.\n"              << "See the application notes for USRP-E1XX for further instructions.\n"          ;          _clock_ctrl->set_fpga_clock_rate(val.as<double>()); diff --git a/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp b/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp index 4247746ab..e9e9b6e20 100644 --- a/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp +++ b/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp @@ -76,6 +76,15 @@ static device_addrs_t usrp_e100_find(const device_addr_t &hint){  /***********************************************************************   * Make   **********************************************************************/ +static size_t hash_fpga_file(const std::string &file_path){ +    size_t hash = 0; +    std::ifstream file(file_path.c_str()); +    if (not file.good()) throw uhd::io_error("cannot open fpga file for read: " + file_path); +    while (file.good()) boost::hash_combine(hash, file.get()); +    file.close(); +    return hash; +} +  static device::sptr usrp_e100_make(const device_addr_t &device_addr){      //setup the main interface into fpga @@ -83,55 +92,44 @@ static device::sptr usrp_e100_make(const device_addr_t &device_addr){      UHD_MSG(status) << boost::format("Opening USRP-E on %s") % node << std::endl;      usrp_e100_iface::sptr iface = usrp_e100_iface::make(node); -    //------------------------------------------------------------------ -    //-- Handle the FPGA loading... -    //-- The image can be confimed as already loaded when: -    //--   1) The compatibility number matches. -    //--   2) The hash in the hash-file matches. -    //------------------------------------------------------------------ -    static const char *hash_file_path = "/tmp/usrp_e100_hash"; -      //extract the fpga path for usrp-e -    std::string usrp_e100_fpga_image = find_image_path( -        device_addr.has_key("fpga")? device_addr["fpga"] : "usrp_e100_fpga.bin" -    ); - -    //calculate a hash of the fpga file -    size_t fpga_hash = 0; -    { -        std::ifstream file(usrp_e100_fpga_image.c_str()); -        if (not file.good()) throw uhd::io_error( -            "cannot open fpga file for read: " + usrp_e100_fpga_image -        ); -        do{ -            boost::hash_combine(fpga_hash, file.get()); -        } while (file.good()); -        file.close(); -    } +    std::string usrp_e100_fpga_image = find_image_path(device_addr.get("fpga", "usrp_e100_fpga.bin")); -    //read the compatibility number -    boost::uint16_t fpga_compat_num = iface->peek16(UE_REG_MISC_COMPAT); +    //compute a hash of the fpga file +    const boost::uint32_t file_hash = boost::uint32_t(hash_fpga_file(usrp_e100_fpga_image)); -    //read the hash in the hash-file -    size_t loaded_hash = 0; -    try{std::ifstream(hash_file_path) >> loaded_hash;}catch(...){} - -    //if not loaded: load the fpga image and write the hash-file -    if (fpga_compat_num != USRP_E_FPGA_COMPAT_NUM or loaded_hash != fpga_hash){ +    //When the hash does not match: +    // - unload the iface to free the node +    // - load the fpga configuration file +    // - re-open the iface on the node +    if (iface->peek32(UE_REG_RB_MISC_TEST32) != file_hash){          iface.reset();          usrp_e100_load_fpga(usrp_e100_fpga_image);          sleep(1); ///\todo do this better one day.          UHD_MSG(status) << boost::format("re-Opening USRP-E on %s") % node << std::endl;          iface = usrp_e100_iface::make(node); -        try{std::ofstream(hash_file_path) << fpga_hash;}catch(...){} +    } + +    //store the hash into the FPGA register +    iface->poke32(UE_REG_SR_MISC_TEST32, file_hash); + +    //check that the hash can be readback correctly +    if (iface->peek32(UE_REG_RB_MISC_TEST32) != file_hash){ +        UHD_MSG(error) << boost::format( +            "The FPGA hash readback failed!\n" +            "The FPGA is either clocked improperly\n" +            "or the FPGA build is not compatible.\n" +        );      }      //check that the compatibility is correct -    fpga_compat_num = iface->peek16(UE_REG_MISC_COMPAT); +    const boost::uint16_t fpga_compat_num = iface->peek16(UE_REG_MISC_COMPAT);      if (fpga_compat_num != USRP_E_FPGA_COMPAT_NUM){          throw uhd::runtime_error(str(boost::format( -            "Expected fpga compatibility number 0x%x, but got 0x%x:\n" -            "The fpga build is not compatible with the host code build." +            "\nPlease update the FPGA image for your device.\n" +            "See the application notes for USRP E-Series for instructions.\n" +            "Expected FPGA compatibility number 0x%x, but got 0x%x:\n" +            "The FPGA build is not compatible with the host code build."          ) % USRP_E_FPGA_COMPAT_NUM % fpga_compat_num));      } @@ -156,7 +154,8 @@ usrp_e100_impl::usrp_e100_impl(  {      //setup interfaces into hardware -    _clock_ctrl = usrp_e100_clock_ctrl::make(_iface); +    const double master_clock_rate = device_addr.cast<double>("master_clock_rate", 64e6); +    _clock_ctrl = usrp_e100_clock_ctrl::make(_iface, master_clock_rate);      _codec_ctrl = usrp_e100_codec_ctrl::make(_iface);      //initialize the mboard diff --git a/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp b/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp index 26774aeda..bb421507a 100644 --- a/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp +++ b/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp @@ -51,14 +51,10 @@ public:      sptr get_new(void){          if (fp_verbose) UHD_LOGV(always) << "  make_recv_buff: " << get_size() << std::endl;          _info->flags = RB_USER_PROCESS; //claim the frame -        return sptr(this, &usrp_e100_mmap_zero_copy_mrb::fake_deleter); +        return make_managed_buffer(this);      }  private: -    static void fake_deleter(void *obj){ -        static_cast<usrp_e100_mmap_zero_copy_mrb *>(obj)->release(); -    } -      const void *get_buff(void) const{return _mem;}      size_t get_size(void) const{return _info->len;} @@ -90,14 +86,10 @@ public:      sptr get_new(void){          if (fp_verbose) UHD_LOGV(always) << "  make_send_buff: " << get_size() << std::endl;          _info->flags = RB_USER_PROCESS; //claim the frame -        return sptr(this, &usrp_e100_mmap_zero_copy_msb::fake_deleter); +        return make_managed_buffer(this);      }  private: -    static void fake_deleter(void *obj){ -        static_cast<usrp_e100_mmap_zero_copy_msb *>(obj)->commit(0); -    } -      void *get_buff(void) const{return _mem;}      size_t get_size(void) const{return _len;} diff --git a/host/lib/utils/log.cpp b/host/lib/utils/log.cpp index 8b270af6b..7d11877a1 100644 --- a/host/lib/utils/log.cpp +++ b/host/lib/utils/log.cpp @@ -16,6 +16,7 @@  //  #include <uhd/utils/log.hpp> +#include <uhd/utils/msg.hpp>  #include <uhd/utils/static.hpp>  #include <boost/filesystem.hpp>  #include <boost/format.hpp> @@ -41,6 +42,7 @@ namespace boost{ namespace interprocess{  #include <stdio.h> //P_tmpdir  #include <cstdlib> //getenv  #include <fstream> +#include <sstream>  #include <cctype>  namespace fs = boost::filesystem; @@ -84,22 +86,21 @@ static fs::path get_temp_path(void){  }  /*********************************************************************** - * The library's streamer resource (static initialization) + * Global resources for the logger   **********************************************************************/ -class null_streambuf_class : public std::streambuf{ -    int overflow(int c) { return c; } -}; -UHD_SINGLETON_FCN(null_streambuf_class, null_streambuf); - -class uhd_logger_stream_resource_class{ +class log_resource_type{  public: -    uhd_logger_stream_resource_class(void) : _null_stream(&null_streambuf()){ -        const std::string log_path = (get_temp_path() / "uhd.log").string(); -        _file_stream.open(log_path.c_str(), std::fstream::out | std::fstream::app); -        _file_lock = ip::file_lock(log_path.c_str()); +    boost::mutex mutex; +    std::ostringstream ss; +    uhd::_log::verbosity_t verbosity, level; + +    log_resource_type(void){ + +        //file lock pointer must be null +        _file_lock = NULL;          //set the default log level -        _log_level = uhd::_log::regularly; +        level = uhd::_log::never;          //allow override from macro definition          #ifdef UHD_LOG_LEVEL @@ -109,41 +110,34 @@ public:          //allow override from environment variable          const char * log_level_env = std::getenv("UHD_LOG_LEVEL");          if (log_level_env != NULL) _set_log_level(log_level_env); -      } -    ~uhd_logger_stream_resource_class(void){ +    ~log_resource_type(void){          _file_stream.close(); +        if (_file_lock != NULL) delete _file_lock;      } -    std::ostream &get(void){ -        if (_verbosity >= _log_level) return _file_stream; -        return _null_stream; -    } - -    void aquire(bool lock){ -        if (lock){ -            _mutex.lock(); -            _file_lock.lock(); +    void log_to_file(void){ +        if (verbosity < level) return; +        if (_file_lock == NULL){ +            const std::string log_path = (get_temp_path() / "uhd.log").string(); +            _file_stream.open(log_path.c_str(), std::fstream::out | std::fstream::app); +            _file_lock = new ip::file_lock(log_path.c_str());          } -        else{ -            _file_lock.unlock(); -            _mutex.unlock(); -        } -    } - -    void set_verbosity(uhd::_log::verbosity_t verbosity){ -        _verbosity = verbosity; +        _file_lock->lock(); +        _file_stream << ss.str() << std::flush; +        _file_lock->unlock();      }  private:      //! set the log level from a string that is either a digit or an enum name      void _set_log_level(const std::string &log_level_str){ -        const uhd::_log::verbosity_t log_level = uhd::_log::verbosity_t(log_level_str[0]-'0'); -        if (std::isdigit(log_level_str[0]) and log_level >= uhd::_log::always and log_level <= uhd::_log::never){ -            _log_level = log_level; +        const uhd::_log::verbosity_t log_level_num = uhd::_log::verbosity_t(log_level_str[0]-'0'); +        if (std::isdigit(log_level_str[0]) and log_level_num >= uhd::_log::always and log_level_num <= uhd::_log::never){ +            this->level = log_level_num; +            return;          } -        #define if_lls_equal(name) else if(log_level_str == #name) _log_level = uhd::_log::name +        #define if_lls_equal(name) else if(log_level_str == #name) this->level = uhd::_log::name          if_lls_equal(always);          if_lls_equal(often);          if_lls_equal(regularly); @@ -152,20 +146,12 @@ private:          if_lls_equal(never);      } -    //available stream objects +    //file stream and lock:      std::ofstream _file_stream; -    std::ostream _null_stream; - -    //synchronization mechanisms -    boost::mutex _mutex; //process-level -    ip::file_lock _file_lock; //system-level - -    //log-level settings -    uhd::_log::verbosity_t _verbosity; -    uhd::_log::verbosity_t _log_level; +    ip::file_lock *_file_lock;  }; -UHD_SINGLETON_FCN(uhd_logger_stream_resource_class, uhd_logger_stream_resource); +UHD_SINGLETON_FCN(log_resource_type, log_rs);  /***********************************************************************   * The logger object implementation @@ -187,14 +173,14 @@ uhd::_log::log::log(      const unsigned int line,      const std::string &function  ){ -    uhd_logger_stream_resource().aquire(true); -    uhd_logger_stream_resource().set_verbosity(verbosity); +    log_rs().mutex.lock(); +    log_rs().verbosity = verbosity;      const std::string time = pt::to_simple_string(pt::microsec_clock::local_time());      const std::string header1 = str(boost::format("-- %s - level %d") % time % int(verbosity));      const std::string header2 = str(boost::format("-- %s") % function).substr(0, 80);      const std::string header3 = str(boost::format("-- %s:%u") % get_rel_file_path(file) % line);      const std::string border = std::string(std::max(std::max(header1.size(), header2.size()), header3.size()), '-'); -    uhd_logger_stream_resource().get() +    log_rs().ss          << std::endl          << border << std::endl          << header1 << std::endl @@ -205,10 +191,35 @@ uhd::_log::log::log(  }  uhd::_log::log::~log(void){ -    uhd_logger_stream_resource().get() << std::endl; -    uhd_logger_stream_resource().aquire(false); +    log_rs().ss << std::endl; +    try{ +        log_rs().log_to_file(); +    } +    catch(const std::exception &e){ +        /*! +         * Critical behavior below. +         * The following steps must happen in order to avoid a lock-up condition. +         * This is because the message facility will call into the logging facility. +         * Therefore we must disable the logger (level = never) and unlock the mutex. +         * +         * 1) Set logging level to never. +         * 2) Unlock the mutex. +         * 3) Send the error message. +         * 4) Return. +         */ +        log_rs().level = never; +        log_rs().ss.str(""); //clear for next call +        log_rs().mutex.unlock(); +        UHD_MSG(error) +            << "Logging failed: " << e.what() << std::endl +            << "Logging has been disabled for this process" << std::endl +        ; +        return; +    } +    log_rs().ss.str(""); //clear for next call +    log_rs().mutex.unlock();  }  std::ostream & uhd::_log::log::operator()(void){ -    return uhd_logger_stream_resource().get(); +    return log_rs().ss;  } diff --git a/host/lib/utils/msg.cpp b/host/lib/utils/msg.cpp index e850b5a6d..0fd62bfc1 100644 --- a/host/lib/utils/msg.cpp +++ b/host/lib/utils/msg.cpp @@ -61,20 +61,24 @@ static void msg_to_cerr(const std::string &title, const std::string &msg){  }  /*********************************************************************** - * Global settings for the messenger + * Global resources for the messenger   **********************************************************************/ -static boost::mutex msg_mutex; -static std::ostringstream msg_ss; -static uhd::msg::type_t msg_type; -static uhd::msg::handler_t msg_handler; +struct msg_resource_type{ +    boost::mutex mutex; +    std::ostringstream ss; +    uhd::msg::type_t type; +    uhd::msg::handler_t handler; +}; + +UHD_SINGLETON_FCN(msg_resource_type, msg_rs);  /***********************************************************************   * Setup the message handlers   **********************************************************************/  void uhd::msg::register_handler(const handler_t &handler){ -    msg_mutex.lock(); -    msg_handler = handler; -    msg_mutex.unlock(); +    msg_rs().mutex.lock(); +    msg_rs().handler = handler; +    msg_rs().mutex.unlock();  }  static void default_msg_handler(uhd::msg::type_t type, const std::string &msg){ @@ -108,16 +112,16 @@ UHD_STATIC_BLOCK(msg_register_default_handler){   * The message object implementation   **********************************************************************/  uhd::msg::_msg::_msg(const type_t type){ -    msg_mutex.lock(); -    msg_type = type; +    msg_rs().mutex.lock(); +    msg_rs().type = type;  }  uhd::msg::_msg::~_msg(void){ -    msg_handler(msg_type, msg_ss.str()); -    msg_ss.str(""); //clear for next call -    msg_mutex.unlock(); +    msg_rs().handler(msg_rs().type, msg_rs().ss.str()); +    msg_rs().ss.str(""); //clear for next call +    msg_rs().mutex.unlock();  }  std::ostream & uhd::msg::_msg::operator()(void){ -    return msg_ss; +    return msg_rs().ss;  } diff --git a/host/usrp_e_utils/usrp-e-utility.cpp b/host/usrp_e_utils/usrp-e-utility.cpp index b926cf49d..47a2c0900 100644 --- a/host/usrp_e_utils/usrp-e-utility.cpp +++ b/host/usrp_e_utils/usrp-e-utility.cpp @@ -64,9 +64,6 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){              "  usrp-e-utility --reclk --fpga=/usr/share/uhd/images/usrp_e1xx_pt_fpga.bin"          );          clock_genconfig_main(); -        if (std::system("rm /tmp/usrp*hash") != 0){ //clear hash so driver must reload -            std::cerr << "No hash to remove! Don't worry, its not a problem." << std::endl; -        }      }      std::cout << "Done!" << std::endl; | 
