/* -*- c++ -*- */
/*
 * Copyright 2004,2007,2011,2012 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 3, 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., 51 Franklin Street,
 * Boston, MA 02110-1301, USA.
 */

#ifndef INCLUDED_DIGITAL_MPSK_RECEIVER_CC_H
#define	INCLUDED_DIGITAL_MPSK_RECEIVER_CC_H

#include <digital/api.h>
#include <gr_block.h>

namespace gr {
  namespace digital {

    /*!
     * \brief This block takes care of receiving M-PSK modulated
     * signals through phase, frequency, and symbol synchronization.
     * \ingroup sync_blk
     * \ingroup demod_blk
     * \ingroup digital
     *
     * This block takes care of receiving M-PSK modulated signals
     * through phase, frequency, and symbol synchronization. It
     * performs carrier frequency and phase locking as well as symbol
     * timing recovery.  It works with (D)BPSK, (D)QPSK, and (D)8PSK
     * as tested currently. It should also work for OQPSK and PI/4
     * DQPSK.
     *
     * The phase and frequency synchronization are based on a Costas
     * loop that finds the error of the incoming signal point compared
     * to its nearest constellation point. The frequency and phase of
     * the NCO are updated according to this error. There are
     * optimized phase error detectors for BPSK and QPSK, but 8PSK is
     * done using a brute-force computation of the constellation
     * points to find the minimum.
     *
     * The symbol synchronization is done using a modified Mueller and
     * Muller circuit from the paper:
     *
     * "G. R. Danesfahani, T. G. Jeans, "Optimisation of modified Mueller
     * and Muller algorithm," Electronics Letters, Vol. 31, no. 13, 22
     * June 1995, pp. 1032 - 1033."
     *
     * This circuit interpolates the downconverted sample (using the
     * NCO developed by the Costas loop) every mu samples, then it
     * finds the sampling error based on this and the past symbols and
     * the decision made on the samples. Like the phase error
     * detector, there are optimized decision algorithms for BPSK and
     * QPKS, but 8PSK uses another brute force computation against all
     * possible symbols. The modifications to the M&M used here reduce
     * self-noise.
     *
     */
    class DIGITAL_API mpsk_receiver_cc : virtual public gr_block
    {
    public:
      // gr::digital::mpsk_receiver_cc::sptr
      typedef boost::shared_ptr<mpsk_receiver_cc> sptr;

      /*!
       * \brief Buil M-PSK receiver block.
       *
       * \param M	    modulation order of the M-PSK modulation
       * \param theta	    any constant phase rotation from the real axis of the constellation
       * \param loop_bw	    Loop bandwidth to set gains of phase/freq tracking loop
       * \param fmin        minimum normalized frequency value the loop can achieve
       * \param fmax        maximum normalized frequency value the loop can achieve
       * \param mu          initial parameter for the interpolator [0,1]
       * \param gain_mu     gain parameter of the M&M error signal to adjust mu (~0.05)
       * \param omega       initial value for the number of symbols between samples (~number of samples/symbol)
       * \param gain_omega  gain parameter to adjust omega based on the error (~omega^2/4)
       * \param omega_rel   sets the maximum (omega*(1+omega_rel)) and minimum (omega*(1+omega_rel)) omega (~0.005)
       *
       * The constructor also chooses which phase detector and
       * decision maker to use in the work loop based on the value of
       * M.
       */
      static sptr make(unsigned int M, float theta, 
		       float loop_bw,
		       float fmin, float fmax,
		       float mu, float gain_mu, 
		       float omega, float gain_omega, float omega_rel);
      
      //! Returns the modulation order (M) currently set
      virtual float modulation_order() const = 0;

      //! Returns current value of theta
      virtual float theta() const = 0;

      //! Returns current value of mu
      virtual float mu() const = 0;

      //! Returns current value of omega
      virtual float omega() const = 0;

      //! Returns mu gain factor
      virtual float gain_mu() const = 0;

      //! Returns omega gain factor
      virtual float gain_omega() const = 0;

      //! Returns the relative omega limit
      virtual float gain_omega_rel() const = 0;

      //! Sets the modulation order (M) currently
      virtual void set_modulation_order(unsigned int M) = 0;

      //! Sets value of theta
      virtual void set_theta(float theta) = 0;

      //! Sets value of mu
      virtual void set_mu(float mu) = 0;
  
      //! Sets value of omega and its min and max values 
      virtual void set_omega(float omega) = 0;

      //! Sets value for mu gain factor
      virtual void set_gain_mu(float gain_mu) = 0;

      //! Sets value for omega gain factor
      virtual void set_gain_omega(float gain_omega) = 0;

      //! Sets the relative omega limit and resets omega min/max values
      virtual void set_gain_omega_rel(float omega_rel) = 0;
    };

  } /* namespace digital */
} /* namespace gr */

#endif /* INCLUDED_DIGITAL_MPSK_RECEIVER_CC_H */