#!/usr/bin/python2
#
# Copyright 2004, 2013 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.
#
# This module starts the atsc processing chain taking the captured
# off-air signal created with:
#
#  uhd_rx_cfile.py  --samp-rate=6.4e6
#                   -f <center of tv signal channel freq>
#                   -g <appropriate gain for best signal / noise>
#                   -s output shorts
#
# This python script converts from interleaved shorts to the complex data type,
# then multiplies the sample rate by 3, from 6.4e6 to 19.2e6
# complex samples / sec, then lowpass filters with a cutoff of 3.2MHz
# and a transition band width of .5MHz.  Center of the tv channels is
# now at 0 with edges at -3.2MHz and 3.2MHz. This puts the pilot at
# -3MHz + 309KHz. Next a root raised cosine filter is aplied to match the one
# in the transmitter and thus reduce ISI. The phased locked loop then locks to
# the pilot and outputs just the real part of the signal ( as information is
# not stored in the phase with atsc ), this is then feed to the bit lock
# loop, this looks for the bit sync marker put at the beginning of every segment
# field, this then adjusts the timing so the amplitude will be sampled at the
# correct sample ( sub-sample is used in this case ).
#
# Output is float.

from gnuradio import gr, analog, atsc
from gnuradio import blocks
from gnuradio import filter
import sys, math, os

def graph (args):

	print os.getpid()

	nargs = len(args)
    	if nargs == 2:
		infile = args[0]
        	outfile = args[1]
    	else:
        	raise ValueError('usage: interp.py input_file output_file.ts\n')

	input_rate = 19.2e6
	IF_freq = 5.75e6

	tb = gr.top_block()

	# Read from input file
	srcf = blocks.file_source(gr.sizeof_short, infile)

	# Convert interleaved shorts (I,Q,I,Q) to complex
	is2c = blocks.interleaved_short_to_complex()

	# 1/2 as wide because we're designing lp filter
	symbol_rate = atsc.ATSC_SYMBOL_RATE/2.
	NTAPS = 279
	tt = filter.firdes.root_raised_cosine (1.0, input_rate / 3, symbol_rate, .1152, NTAPS)
	rrc = filter.fir_filter_ccf(1, tt)

	# Interpolate Filter our 6MHz wide signal centered at 0
	ilp_coeffs = filter.firdes.low_pass(1, input_rate, 3.2e6, .5e6, filter.firdes.WIN_HAMMING)
	ilp = filter.interp_fir_filter_ccf(3, ilp_coeffs)

	# Move the center frequency to 5.75MHz ( this wont be needed soon )
	duc_coeffs = filter.firdes.low_pass ( 1, 19.2e6, 9e6, 1e6, filter.firdes.WIN_HAMMING )
    	duc = filter.freq_xlating_fir_filter_ccf ( 1, duc_coeffs, -5.75e6, 19.2e6 )

	# fpll input is float
	c2f = blocks.complex_to_float()

	# Phase locked loop
	fpll = atsc.fpll()

	# Clean fpll output
	lp_coeffs2 = filter.firdes.low_pass (1.0,
			   input_rate,
			   5.75e6,
                           120e3,
                           filter.firdes.WIN_HAMMING);
	lp_filter = filter.fir_filter_fff (1, lp_coeffs2)

	# Remove pilot ( at DC now )
	iir = filter.single_pole_iir_filter_ff(1e-5)
	remove_dc = blocks.sub_ff()

	# Bit Timing Loop, Field Sync Checker and Equalizer
	btl = atsc.bit_timing_loop()
	fsc = atsc.fs_checker()
	eq = atsc.equalizer()
	fsd = atsc.field_sync_demux()

	# Viterbi
	viterbi = atsc.viterbi_decoder()
        deinter = atsc.deinterleaver()
        rs_dec = atsc.rs_decoder()
        derand = atsc.derandomizer()
	depad = atsc.depad()

	# Write to output file
	outf = blocks.file_sink(gr.sizeof_char,outfile)

	# Connect it all together
	tb.connect( srcf, is2c, rrc, ilp, duc, c2f, fpll, lp_filter)
	tb.connect( lp_filter, iir )
	tb.connect( lp_filter, (remove_dc, 0) )
	tb.connect( iir, (remove_dc, 1) )
	tb.connect( remove_dc, btl )
	tb.connect( (btl, 0), (fsc, 0), (eq, 0), (fsd,0) )
	tb.connect( (btl, 1), (fsc, 1), (eq, 1), (fsd,1) )
	tb.connect( fsd, viterbi, deinter, rs_dec, derand, depad, outf )

	tb.run()

if __name__ == '__main__':
	graph (sys.argv[1:])

