#!/usr/bin/env python
#
#
# Copyright 2005 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
# GNU Radio 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 2, or (at your option)
# any later version.
#
# GNU Radio 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 GNU Radio; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
# =====================================================================
#                    Weaver SSB demodulation
#
#
#                                          af_loi
#                                            |
#                               --[lpf2i]---(X)---|
#                               |         af_mixi |
#                               |                 |
# signal --[freq xlating]--[split]               (+)----- ssb_demod
#          [fir filter  ]       |                 |  + USB
#                               |         af_mixq |  - LSB
#                               --[lpf2q]---(X)---|
#                                            |
#                                          af_loq
#
# This version uses TWO branches of the above, one for LSB and one for USB
# and feeds to the right & left audio out for 'stereo' independant side band

from gnuradio import gr
from gnuradio import audio

def build_graph (freq,scale,usrp_center,tune_offset):

    usrp_decim = 100
    rf_sample_rate = 64000000 / usrp_decim
    af_sample_rate = 32000
    fir_decimation = rf_sample_rate / af_sample_rate

    rf_LO_L = usrp_center - ( freq - tune_offset ) + 1.8e3 
    rf_LO_U = usrp_center - ( freq - tune_offset ) - 1.82e3
    af_LO = 1.8e3

    fg = gr.flow_graph ()
    
    src = gr.file_source (gr.sizeof_gr_complex,"/root/radio/ssb_data-3.8e6-c-d100_3-6-2005_6-35pm",1)

    xlate_taps = gr.firdes.low_pass ( \
        1.0, rf_sample_rate, 20e3, 10e3, gr.firdes.WIN_HAMMING )

# LSB branch
    xlate_L = gr.freq_xlating_fir_filter_ccf ( \
        fir_decimation, xlate_taps, rf_LO_L, rf_sample_rate )

    split_L = gr.complex_to_float ()

    af_loi_L = gr.sig_source_f (af_sample_rate,gr.GR_COS_WAVE,af_LO,1,0)
    af_loq_L = gr.sig_source_f (af_sample_rate,gr.GR_SIN_WAVE,af_LO,1,0)

    lpf2_taps = gr.firdes.low_pass ( \
           1.0, af_sample_rate, 2e3, 600, gr.firdes.WIN_HAMMING)
    lpf2i_L = gr.fir_filter_fff (1, lpf2_taps)
    lpf2q_L = gr.fir_filter_fff (1, lpf2_taps)

    af_mixi_L = gr.multiply_ff ()
    af_mixq_L = gr.multiply_ff ()

    sum_L = gr.add_ff ()    # sub for USB,  add for LSB

    audio_lpf_coeffs = gr.firdes.low_pass ( \
           1.0,af_sample_rate,3000,600,gr.firdes.WIN_HAMMING)
    audio_lpf_L = gr.fir_filter_fff (1, audio_lpf_coeffs)

    scale_L = gr.multiply_const_ff(scale)

# USB branch
    xlate_U = gr.freq_xlating_fir_filter_ccf ( \
        fir_decimation, xlate_taps, rf_LO_U, rf_sample_rate )

    split_U = gr.complex_to_float ()

    af_loi_U = gr.sig_source_f (af_sample_rate,gr.GR_COS_WAVE,af_LO,1,0)
    af_loq_U = gr.sig_source_f (af_sample_rate,gr.GR_SIN_WAVE,af_LO,1,0)

    lpf2i_U = gr.fir_filter_fff (1, lpf2_taps)
    lpf2q_U = gr.fir_filter_fff (1, lpf2_taps)

    af_mixi_U = gr.multiply_ff ()
    af_mixq_U = gr.multiply_ff ()

    sum_U = gr.sub_ff ()    # sub for USB,  add for LSB

    audio_lpf_U = gr.fir_filter_fff (1, audio_lpf_coeffs)

    scale_U = gr.multiply_const_ff(scale)

# AGC lsb
    sqr1_L = gr.multiply_ff()
    int_L = gr.iir_filter_ffd ( [.004, 0], [0, .999] )
    offset_L = gr.add_const_ff(1)
    agc_L = gr.divide_ff()

# AGC usb
    sqr1_U = gr.multiply_ff()
    int_U = gr.iir_filter_ffd ( [.004, 0], [0, .999] )
    offset_U = gr.add_const_ff(1)
    agc_U = gr.divide_ff()

# sideband selection
    sel_lsb_0 = gr.multiply_const_ff(1)
    sel_lsb_1 = gr.multiply_const_ff(1)
    sel_usb_0 = gr.multiply_const_ff(0)
    sel_usb_1 = gr.multiply_const_ff(0)
    select0 = gr.add_ff()
    select1 = gr.add_ff()

#    out = gr.file_sink (gr.sizeof_float, "ssb_demod")
    out = audio.sink (long(af_sample_rate))

    fg.connect (src, xlate_L)
    fg.connect (src, xlate_U)
    fg.connect (xlate_L, split_L)
    fg.connect (xlate_U, split_U)

    fg.connect ((split_L, 0), lpf2i_L)
    fg.connect ((split_U, 0), lpf2i_U)
    fg.connect (lpf2i_L, (af_mixi_L, 0))
    fg.connect (lpf2i_U, (af_mixi_U, 0))
    fg.connect (af_loi_L, (af_mixi_L, 1))
    fg.connect (af_loi_U, (af_mixi_U, 1))
    fg.connect (af_mixi_L, (sum_L, 0))
    fg.connect (af_mixi_U, (sum_U, 0))

    fg.connect ((split_L, 1), lpf2q_L)
    fg.connect ((split_U, 1), lpf2q_U)
    fg.connect (lpf2q_L, (af_mixq_L, 0))
    fg.connect (lpf2q_U, (af_mixq_U, 0))
    fg.connect (af_loq_L, (af_mixq_L, 1))
    fg.connect (af_loq_U, (af_mixq_U, 1))
    fg.connect (af_mixq_L, (sum_L, 1))
    fg.connect (af_mixq_U, (sum_U, 1))

    fg.connect (sum_L, audio_lpf_L)
    fg.connect (sum_U, audio_lpf_U)
    fg.connect (audio_lpf_L, scale_L)
    fg.connect (audio_lpf_U, scale_U)
# wire AGC
    fg.connect (scale_L, (sqr1_L, 0))
    fg.connect (scale_U, (sqr1_U, 0))
    fg.connect (scale_L, (sqr1_L, 1))
    fg.connect (scale_U, (sqr1_U, 1))
    fg.connect (sqr1_L, int_L)
    fg.connect (sqr1_U, int_U)
    fg.connect (int_L, offset_L)
    fg.connect (int_U, offset_U)
    fg.connect (offset_L, (agc_L, 1))
    fg.connect (offset_U, (agc_U, 1))
    fg.connect (scale_L, (agc_L, 0))
    fg.connect (scale_U, (agc_U, 0))
# wire sideband selection
    fg.connect (agc_L, sel_lsb_0)
    fg.connect (agc_U, sel_usb_0)
    fg.connect (agc_L, sel_lsb_1)
    fg.connect (agc_U, sel_usb_1)
    fg.connect (sel_lsb_0, (select0, 0))
    fg.connect (sel_usb_0, (select0, 1))
    fg.connect (sel_lsb_1, (select1, 0))
    fg.connect (sel_usb_1, (select1, 1))
    fg.connect (select0, (out, 0))
    fg.connect (select1, (out, 1))

    fg.start()

    return fg, xlate_L, xlate_U, scale_L, scale_U, src, audio_lpf_L, audio_lpf_U, sel_lsb_0, sel_lsb_1, sel_usb_0, sel_usb_1

