#!/usr/bin/env python

from gnuradio import gr, gru, eng_notation
from gnuradio import audio
from gnuradio import usrp
from gnuradio import blks
from gnuradio import tv_rx
from gnuradio.eng_option import eng_option
from optparse import OptionParser
import sys
import math


"""
Reads from a file and generates PAL TV pictures in black and white
which can be displayed using ImageMagick


  # set the center freq of the TV RX tuner to 546 MHz somehow (center
  # of the 8 MHz PAL channel).  This works:

  $ tvrx_wfm_rcv_gui.py -f 546

  # adjust mux as required. This is for TV RX on B side.
  # hit Enter about 1 or 2 seconds after starting it...
  # Use a fast harddrive or ramdisk
  # -3.0 or -8.5
  # -3.75
  $ usrp_rx_cfile.py -d 8 -c -5.75M --mux=0xf0f0f0f2 -o foo.dat

  # -151.0 scale factor; 128 offset; 546  channel center freq
  $ tvrx_tv_rcv.py foo.dat 5.75 8 -151.0 128 546

  $ display -size 512x312 gray:pal_out_raw_char.gray

  # If you don't have a fast enough usb2 interface (like me)
  # You can get away with using a decimation factor of 16 like this  
  #
  $ usrp_rx_cfile.py -d 16 -c -3.75M --mux=0xf0f0f0f2 -o foo.dat
  $ tvrx_tv_rcv.py foo.dat 3.75 16 -151.0 128 546
  $ display -size 512x312 gray:pal_out_raw_char.gray
"""

#
# return a gr.flow_graph
#

def build_graph(input_filename, iffreq,decimation,rffreq,sfactor,black_level):
    global plot
    adc_rate = 64e6
    decim = decimation #int(adc_rate/8e6)
    IF_freq = iffreq #use decim 16 and IF_freq 3.75e6 for slow usb systems
                     #use decim 8 and IF_freq 5.75e6 for fast systems which can capture the full tv-bandwidth
    carrier_freq=(5.75e6 -iffreq) -2.75e6
    do_accurate=False      
    use_pll=False
    use_agc=False

    video_rate = adc_rate / decim               # 8 Mhz

    fg = gr.flow_graph ()
    
    if input_filename:
        src = gr.file_source(gr.sizeof_gr_complex, input_filename)
        #src = gr.sig_source_c(video_rate, gr.GR_SIN_WAVE, 
        #                 +0.75e6*1.15, 1.0) #+2.75e6
    else:
        # usrp is data source
        src = usrp.source_c (0, decim)
        which_side = 1
        if which_side == 0:
            src.set_mux(gru.hexint(0xf0f0f0f0))
        else:
            src.set_mux(gru.hexint(0xf0f0f0f2))
    
        dboard = tv_rx.tv_rx (src, which_side)
        RF_freq = rffreq #freq1 * 1e6
        (success, baseband_freq) = dboard.set_freq(RF_freq)
        assert success
        #dboard.set_gain(57)
        #IF_freq = 3.75e6 #RF_freq - baseband_freq
        src.set_rx_freq (0, -IF_freq)
    
    itaps = gr.firdes.low_pass(2,   # gain
                               1,   # sample rate
                               0.2,#.2,
                               0.1,#.1,  # should be 0.05
                               gr.firdes.WIN_HAMMING)

    #plot = gru.gnuplot_freqz (gru.freqz (itaps, 1), 1)
    #if 1:
    #    interp = gr.interp_fir_filter_ccf(3, itaps)
    if use_pll:
        interpolate_factor=3
        demod_rate = video_rate*interpolate_factor
        interp = gr.interp_fir_filter_ccf(interpolate_factor, itaps)
        pll=gr.pll_cc (demod_rate,carrier_freq,1.0, 0.25e-6, False)
        fg.connect(src, interp)
        fg.connect(interp, pll)
    else: 
     if do_accurate:
        interp = gr.interp_fir_filter_ccf(3, itaps)

        lo = gr.sig_source_c(video_rate*3, gr.GR_SIN_WAVE, 
                         carrier_freq, 1.0) #+2.75e6
        mixer = gr.multiply_cc()

        fg.connect(src, interp)
        fg.connect(interp, (mixer, 0))
        fg.connect(lo, (mixer, 1))
        demod_rate = video_rate*3
        stage1=mixer
     else:
      if 0:
        # Tune to the desired frequency.
        ddc = gr.freq_xlating_fir_filter_ccf (1, itaps, carrier_freq, video_rate) #-2.75e6
        fg.connect(src, ddc)
        demod_rate = video_rate
        stage1=ddc
      else:
        stage1=src
        demod_rate=video_rate


    #fg.connect(interp, gr.file_sink(gr.sizeof_gr_complex, "interp.cmplx"))
    #fg.connect(mixer, gr.file_sink(gr.sizeof_gr_complex, "mixer.cmplx"))
    
    am_demod = gr.complex_to_mag () #gr.complex_to_mag ()
        
    dc_restore = gr.add_const_ff(black_level) 

    scale = gr.multiply_const_ff (sfactor)

    #video_lp_coeffs = gr.firdes.low_pass (
    #        1, video_rate, 1e6, 6e6, 
    #        gr.firdes.WIN_HAMMING )
    #
    #video_lp = gr.fir_filter_fff (int(video_rate/demod_rate), video_lp_coeffs )

    #float_to_char=gr.float_to_char()
    #dst = gr.file_sink (gr.sizeof_char, "pal_out_raw_char.gray")#raw file with short image data, not synchronized yet

    float_to_char=gr.float_to_uchar()
    dst = gr.file_sink (gr.sizeof_char, "pal_out_raw_char.gray")#raw file with unsigned char image data, not synchronized yet
    # agc
    integrator_agc = gr.single_pole_iir_filter_ff (0.000001) #gr.iir_filter_ffd ( [.004, 0], [0, .999] )
    offset_agc = gr.add_const_ff(1)
    divide_agc = gr.divide_ff()
    # now wire it all together
    
    if use_agc:
        fg.connect (stage1, am_demod)
        fg.connect (am_demod, integrator_agc)
        fg.connect (am_demod, (divide_agc, 0))
        fg.connect (integrator_agc, (divide_agc, 1))
        fg.connect (divide_agc,scale, dc_restore, float_to_char, dst)
    else:
      if use_pll:
        ctor=gr.complex_to_real() #gr.complex_to_mag()
        fg.connect (pll,ctor,scale, dc_restore, float_to_char, dst)
      else:
        fg.connect (stage1, am_demod, scale, dc_restore, float_to_char, dst)

    #fg.connect (mixer, am_demod, scale, dc_restore, float_to_char, dst)
 
    #demod_rate=sampling_freq/cfir_decimation
    pixels_in_line_pal=demod_rate/(25*625*2)
    pixels_in_line_ntsc=demod_rate/(30*525*2)

    print "You can use the imagemagick display tool to show the resulting imagesequence"
    print "use the following line to show a PAL signal:"
    print "display -size " +str(int(pixels_in_line_pal))+ "x312  gray:pal_out_raw_char.gray"
    print "use the following line to show a NTSC signal:"
    print "display -size " +str(int(pixels_in_line_ntsc))+ "x262  gray:ntsc_out_raw_char.gray"

    return fg
    

def main (args):
    nargs = len (args)
    input_filename =  sys.argv[1]   # FIXME
    rffreq=0.0
    if nargs == 4:
                rffreq=float (args[3])* 1e6
    if ((nargs == 3) | (nargs==4)):
                iffreq=float (args[1])* 1e6
                decimation = int(args[1])
                sfactor=float (args[2]) #-302
                black_level=float(args[3]) # 255
    else:
                sys.stderr.write ('usage: ntsc_demod.py iffreq  scale black_levelcorrection [rffreq]\n')
                sys.stderr.write ('frequencies in Mhz\n')
                sys.stderr.write ('Using an 8 bit ADC and an iffreq of 38.9 Mhz (folded back to 11.0625 when using 50 Mhz sampling_freq), a scale factor of -20.0 and a blacklevelcorrection of -22 gave me a reasonable picture for a PAL signal\n')
                sys.stderr.write ('For NTSC I think you need to use a positive scale factor\n')
                sys.exit (1)
    print 'input_filename',input_filename
    print 'rffreq',rffreq
    print 'iffreq' ,iffreq
    print 'decimation',rffreq
    print 'sfactor',sfactor
    print ' black_level',black_level

    fg = build_graph(input_filename, iffreq,decimation,rffreq,sfactor,black_level)
    if input_filename:
        fg.run()
    else:
        fg.start()
        raw_input ('Press Enter to quit')
        fg.stop()
    
if __name__ == '__main__':
    main (sys.argv[1:])

