#ifndef __HamFuncs_h__
#define __HamFuncs_h__

/**********************************************************************/

#ifndef HF_PWR_DEFAULT_LOAD
#define HF_PWR_DEFAULT_LOAD 50.0
#endif

#ifndef HF_VSWR_MAX_REPORTED
#define HF_VSWR_MAX_REPORTED 9.9
#endif

#ifndef HF_BRIDGE_FWD_VRECT
#define HF_BRIDGE_FWD_VRECT 0.25
#endif

#ifndef HF_BRIDGE_FWD_TURNS
#define HF_BRIDGE_FWD_TURNS 10.0
#endif

#ifndef HF_BRIDGE_REV_VRECT
#define HF_BRIDGE_REV_VRECT 0.25
#endif

#ifndef HF_BRIDGE_REV_TURNS
#define HF_BRIDGE_REV_TURNS 10.0
#endif

#ifndef HF_ADC_DEFAULT_BITS
#define HF_ADC_DEFAULT_BITS 10
#endif

#ifndef HF_ADC_DEFAULT_VREF
#define HF_ADC_DEFAULT_VREF 3.3
#endif

/**********************************************************************/

namespace HF {

  const float    pwrDefaultLoad  = HF_PWR_DEFAULT_LOAD;
  const float    vswrMaxReported = HF_VSWR_MAX_REPORTED;
  const float    bridgeFwdVrect  = HF_BRIDGE_FWD_VRECT;
  const float    bridgeFwdTurns  = HF_BRIDGE_FWD_TURNS;
  const float    bridgeRevVrect  = HF_BRIDGE_REV_VRECT;
  const float    bridgeRevTurns  = HF_BRIDGE_REV_TURNS;
  const unsigned adcDefaultBits  = HF_ADC_DEFAULT_BITS;
  const float    adcDefaultVref  = HF_ADC_DEFAULT_VREF;

  const float rms = sqrt(2.0) / 2.0;   
  
  /********************************************************************/

  /*!
   *  @brief  Calculate the output voltage of a resistive divider 
   *          network, given the input voltage and the values of the 
   *          resistors. The input voltage is applied to R1, the output
   *          voltage is taken from the junction of R1 and R2, and R2 is
   *          connected to ground.
   *  @param  Vin
   *          Input voltage.
   *  @param  R1
   *          Input resistor (ohms). Input voltage is measured between
   *          the top of this resistor and ground.
   *  @param  R2
   *          Output resistor (ohms). Output voltage is measured
   *          between the top of this resistor and ground.
   *  @return Output voltage.
   */
  inline float divOut(float Vin, float R1, float R2) {
    return Vin * R2 / (R1 + R2);
  }

  /*!
   *  @brief  Calculate the input voltage of a resistive divider 
   *          network, given the output voltage and the values of the 
   *          resistors. The input voltage is applied to R1, the output 
   *          voltage is taken from the junction of R1 and R2, and R2 is
   *          connected to ground.
   *  @param  Vout
   *          Output voltage.
   *  @param  R1
   *          Input resistor (ohms). Input voltage is measured between 
   *          the top of this resistor and ground.
   *  @param  R2
   *          Output resistor (ohms). Output voltage is measured between
   *          the top of this resistor and ground.
   *  @return Input voltage.
   */
  inline float divIn(float Vout, float R1, float R2) {
    return Vout * (R1 + R2) / R2;
  }

  /*!
   *  @brief  Calculate and return the power in watts, given a
   *          resistance and the voltage across the resistance.
   *  @param  V
   *          Voltage across the load.
   *  @param  R
   *          (optional) Resistance of the load (ohms).  If not provided,
   *          a default is used (HF_PWR_DEFAULT_LOAD).
   *  @return Power dissipated (watts).  This is calculated as
   *          P = V^2/R.
   */
  inline float P(float V, float R = pwrDefaultLoad) {
    return (V * V) / R;
  }

  /*!
   *  @brief  Calculate and return the Voltage Standing Wave Ratio
   *          (VSWR) based on the given forward and reverse voltages.
   *  @param  Vfwd
   *          Measured forward voltage.
   *  @param  Vrev
   *          Measured reverse voltage.
   *  @param  VSWRmax
   *          (optional) Maximum reported VSWR.  The output will be
   *          clamped to this value if necessary (HF_VSWR_MAX_REPORTED).
   *  @return Voltage Standing Wave Ratio (VSWR).  This is calculated 
   *          as VSWR = (Vfwd + Vrev) / (Vfwd - Vrev).
   */
  inline float VSWR(float Vfwd, float Vrev, float VSWRmax = vswrMaxReported) {
    if (Vfwd - Vrev == 0.0) {
      return VSWRmax;
    } else {
      float swr = (Vfwd + Vrev) / (Vfwd - Vrev);
      return (swr > VSWRmax ? VSWRmax : swr);
    }
  }

  /*!
   *  @brief  Calculate and return the forward RMS input voltage across
   *          a Stockton bridge.
   *  @param  Vout
   *          Rectified output voltage (e.g. read via an ADC).
   *  @param  Vrect
   *          (optional) Voltage drop across the rectifier diode.  If
   *          not provided, a default is used (HF_BRIDGE_FWD_VRECT).
   *  @param  turns
   *          (optional) Coupling transformer turns ratio. If not 
   *          provided, a default is used (HF_BRIDGE_FWD_TURNS).
   *  @return Input voltage (i.e. the actual forward voltage).
   */
  inline float bridgeFwd(float Vout, float Vrect = bridgeFwdVrect, float turns = bridgeFwdTurns) {
    return (Vout + Vrect) * turns * rms;
  }

  /*!
   *  @brief  Calculate and return the reverse RMS input voltage across
   *          a Stockton bridge.
   *  @param  Vout
   *          Rectified output voltage (e.g. read via an ADC).
   *  @param  Vrect
   *          (optional) Voltage drop across the rectifier diode.  If
   *          not provided, a default is used (HF_BRIDGE_REV_VRECT).
   *  @param  turns
   *          (optional) Coupling transformer turns ratio. If not 
   *          provided, a default is used (HF_BRIDGE_REV_TURNS).
   *  @return Input voltage (i.e. the actual reverse voltage).
   */
  inline float bridgeRev(float Vout, float Vrect = bridgeRevVrect, float turns = bridgeRevTurns) {
    return (Vout + Vrect) * turns * rms;
  }

  /*!
   *  @brief  Calculate and return the input voltage to an Analog-to-
   *          Digital Converter (ADC) given the resolution (number of
   *          bits) and the voltage reference of the ADC.
   *  @param  counts
   *          Value of the ADC measurement (in unitless counts).
   *  @param  res
   *          (optional) Resolution (in bits) of the ADC.  If not
   *          provided, the default is used (HF_ADC_DEFAULT_BITS).
   *  @param  Vref
   *          (optional) Voltage reference of the ADC.  If not
   *          provided, the default is used (HF_ADC_DEFAULT_VREF).
   *  @return Input voltage to the ADC.
   */
  inline float adcIn(unsigned counts, unsigned res = adcDefaultBits, float Vref = adcDefaultVref) {
    return float(counts) * Vref / float(1 << res);
  }

};

#endif
