/* -*- c++ -*- */
/*
 * Copyright 2004 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.
 */

/*
 * config.h is generated by configure.  It contains the results
 * of probing for features, options etc.  It should be the first
 * file included in your .cc file.
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gr_rds_biphase_decoder.h>
#include <gr_io_signature.h>

//#define BIPHASE_VERBOSE

/*
 * Create a new instance of gr_rds_biphase_decoder and return
 * a boost shared_ptr.  This is effectively the public constructor.
 */
gr_rds_biphase_decoder_sptr 
gr_rds_make_biphase_decoder (double sampling_rate)
        
{
  return gr_rds_biphase_decoder_sptr (new gr_rds_biphase_decoder (sampling_rate));
}

/*
 * Specify constraints on number of input and output streams.
 * This info is used to construct the input and output signatures
 * (2nd & 3rd args to gr_block's constructor).  The input and
 * output signatures are used by the runtime system to
 * check that a valid number and type of inputs and outputs
 * are connected to this block.  In this case, we accept
 * only 1 input and 1 output.
 */
static const int MIN_IN = 2;	// mininum number of input streams
static const int MAX_IN = 2;	// maximum number of input streams
static const int MIN_OUT = 1;	// minimum number of output streams
static const int MAX_OUT = 8;	// maximum number of output streams



/*
 * The private constructor
 */
gr_rds_biphase_decoder::gr_rds_biphase_decoder (double input_sampling_rate)
  : gr_block("gr_rds_biphase_decoder",
              gr_make_io_signature (MIN_IN, MAX_IN, sizeof (float)),
              gr_make_io_signature (MIN_OUT, MAX_OUT, sizeof (bool)) )
{

        SYMBOL_LENGTH = (int)(input_sampling_rate/57000*48.0);

//	printf("SYMBOL_LENGHT= %d,\n", SYMBOL_LENGTH);

        d_zc = 0;
        d_last_zc=0;
        d_sign_last = 0;

        set_relative_rate((input_sampling_rate/57e3/48));
        
        enter_looking();
        
}

/*
 * Our virtual destructor.
 */
gr_rds_biphase_decoder::~gr_rds_biphase_decoder ()
{
  // nothing else required in this example
}


void gr_rds_biphase_decoder::enter_looking ()
{
        printf (">>> biphase decoder enter_looking\n");
        
          d_state = ST_LOOKING;
}

void  gr_rds_biphase_decoder::enter_locked ()
{
         printf(">>> biphase decoder enter_locked\n");
         
         d_state = ST_LOCKED;
         d_symbol_integrator = 0;
         d_sign_last = 0;
}

int gr_rds_biphase_decoder::general_work (int noutput_items,
                               gr_vector_int &ninput_items,
                               gr_vector_const_void_star &input_items,
                               gr_vector_void_star &output_items)
{
  const float *in = (const float *) input_items[0];
  const float *clk  =  (const float *) input_items [1];
  
  bool *out = (bool *) output_items[0];
  //float *out = (float *) output_items[0];
          
  int n_in = ninput_items[0];
  int n_clk_in = ninput_items[1];
  int i = 0;
  int n = 0;
  int cons;
  int sign_current = 0;

  #ifdef BIPHASE_VERBOSE
  printf("Biphase decoder at work: n_in = %d, n_clk_in = %d\n", n_in, n_clk_in);
  #endif
        
  switch (d_state){

    case ST_LOCKED:

        if(d_sign_last == 0) { d_sign_last = (clk[0] > 0 ? 1: -1);}

        for( i = 0; (i < n_in) && (i < n_clk_in); i++) {

                sign_current = (clk[i] > 0 ? 1: -1);
                
                if(sign_current != d_sign_last) {
                        // a zero cross in clk
                        d_zc++;
                }
                d_sign_last = sign_current;
                
                d_symbol_integrator += (in[i] * clk[i]);
//		out[n] = d_symbol_integrator;
//		n++;
                if(d_zc >=  2) {
                        // Two zc in clock.. that's a symbol
                        // Integration over one symbol finished..
                        if(d_symbol_integrator > 0) {
                                #ifdef BIPHASE_VERBOSE  
                                        printf("1");
                                #endif
                                out[n] = 1;
                        } else  {
                                #ifdef BIPHASE_VERBOSE 
                                        printf("0");
                                #endif
                                out[n] = 0;
                        }

                        n++; // created one more symbol...
                        d_symbol_integrator = 0;
                        d_zc = 0;
                }
                
        } 
            
        fflush(stdout);
        consume_each (i);
        return n; // Tell the runtime system how many output items we created..
        
    case ST_LOOKING:

        // adjust clock and signal
        // 
        // if fine: go locked 

        
        if(d_sign_last == 0) { d_sign_last = (in[0] > 0 ? 1 : -1); }

        for( i = 0; i < n_in; i++) {

                sign_current = (in[i] > 0 ? 1 : -1);
                if(sign_current != d_sign_last) {
                        
                        // Remeber the zc and check next time if it was  a half or a hole symbol...
                        #ifdef BIPHASE_VERBOSE
                                printf("ZC at i = %d\n", i);
                        #endif
                        if(d_last_zc != 0) {
                                int delta = i - d_last_zc;
                                #ifdef BIPHASE_VERBOSE
                                        printf("delta of zc = %d\n", delta);
                                #endif
                                if((delta  >= SYMBOL_LENGTH - 5)) {
                                        // That was a 1, 0 or 0, 1 in signal...
                                        // i indexes the middle of a symbol
                                        //
                                        //
                                        #ifdef BIPHASE_VERBOSE
                                                printf("sync ... consume: %d",  (i-(delta/2)) );
                                        #endif
                                        consume(0, i-(delta/2));

                                        // From this point sync clk
                                        //
                                        d_sign_last = (clk[0] > 0 ? 1: -1);
                                        for (i = 0; i < n_clk_in ; i++) {
                                                sign_current = (clk[i] > 0 ? 1: -1);
                                                if(sign_current != d_sign_last) {
                                                        // zc in clock
                                                               consume(1, i);
                                                        break;
                                                }
                                                d_sign_last = sign_current;
                                        }

                                        enter_locked();
                                        return 0;	// No output produced, but now sync...

                                }
                                                
                        }
                        d_last_zc = i;
                }
                d_sign_last = sign_current;
                
        }
        
        d_last_zc = d_last_zc - n_in;

        cons = (n_in > n_clk_in ? n_clk_in : n_in );
        
        consume(0, cons);
        consume(1, cons);
        
        return 0;	 

    default:
        // Strange state setting
      enter_looking();
      consume_each(0);
      return 0;
    }
     
    
}
