//======================================================================
// TR.h
//======================================================================

#ifndef __TR_h__
#define __TR_h__

#include <Bounce2.h>
#include "Debug.h"
#include "DSP.h"

#define UBITX_TR_OUT_PIN 2
#define UBITX_TR_PTT_PIN 3
#define UBITX_TR_VOX_PIN 4
#define UBITX_TR_KEY_PIN 5

const int uBitxTROutPin = UBITX_TR_OUT_PIN;
const int uBitxTRPttPin = UBITX_TR_PTT_PIN;
const int uBitxTRVoxPin = UBITX_TR_VOX_PIN;
const int uBitxTRKeyPin = UBITX_TR_KEY_PIN;

class UBitxTR {
  public:
  UBitxTR(UBitxDSP& d, int out = uBitxTROutPin, int p = uBitxTRPttPin, int v = uBitxTRVoxPin, int k = uBitxTRKeyPin):
  dsp(d), outPin(out), pttPin(p), voxPin(v), keyPin(k) {}

  void begin() {
    pinMode(outPin, OUTPUT);
    pinMode(voxPin, INPUT_PULLUP);
    pinMode(keyPin, INPUT_PULLUP);
    ptt.attach(pttPin, INPUT_PULLUP);
    ptt.interval(5);

    // default configuration: PTT, key, and CAT enabled; VOX disabled
    DBGCMD( enableMicPTT()  );
    DBGCMD( disableMicVOX() );
    DBGCMD( enableLinePTT()  );
    DBGCMD( enableCAT()  );

    DBGCMD( setRX() );
  }

  inline void enableMicPTT() { pttEnable = true; }
  inline void enableLinePTT() { keyEnable = true; }
  inline void enableMicVOX() { voxEnable = true; }
  inline void enableDataVOX() { dvoxEnable = true; }
  inline void enableCAT() { catEnable = true; }
  
  inline void disableMicPTT() { pttEnable = false; }
  inline void disableLinePTT() { keyEnable = false; }
  inline void disableMicVOX() { voxEnable = false; }
  inline void disableDataVOX() { dvoxEnable = false; }
  inline void disableCAT() { catEnable = false; }

  inline bool micPTTEnabled() const { return pttEnable; }
  inline bool linePTTEnabled() const { return keyEnable; }
  inline bool micVOXEnabled() const { return voxEnable; }
  inline bool dataVOXEnabled() const { return dvoxEnable; }
  inline bool catEnabled() const { return catEnable; }
  
  inline bool micPTTPressed() { return ptt.fell(); }
  inline bool micPTTReleased() { return ptt.rose(); }
  inline bool linePTTPressed() { return (L_keyDown != keyDown) && L_keyDown; }
  inline bool linePTTReleased() { return (L_keyDown != keyDown) && keyDown; }
  inline bool micVOXActivated() { return (L_voxActive != voxActive) && L_voxActive; }
  inline bool micVOXDeactivated() { return (L_voxActive != voxActive) && voxActive; }
  inline bool dataVOXActivated() { return (L_dvoxActive != dvoxActive) && L_dvoxActive; }
  inline bool dataVOXDeactivated() { return (L_dvoxActive != dvoxActive) && dvoxActive; }
  inline bool catActivated() { return (L_catActive != catActive) && L_catActive; }
  inline bool catDeactivated() { return (L_catActive != catActive) && catActive; }
  
  inline void catTX() {
    L_catActive = catActive;
    catActive = true;
  }

  inline void catRX() {
    L_catActive = catActive;
    catActive = false;
  }

//======================================================================

  inline bool transmitting() { return isTX;  }
  inline bool receiving() { return !isTX; }

  /*!
   *  @brief  Check if any of the PTT's have been pressed or released 
   *          since the last update.  Only one thing is allowed to occur
   *          based on an order of precedence.  The highest priority is
   *          to stop transmitting.
   *          
   *  @param  cw
   *          True if CW mode is currently active; false otherwise.  
   *          Different/faster logic is used in CW mode.
   *          
   *  @param  extKey
   *          True if an external keying signal (ie. CW keyer) is 
   *          currently active (ie. key down).
   */
  void update(bool cw = false, bool extKey = false);
  
  void end() {
  }
  
  private:

  inline void setTX() {
    digitalWrite(outPin, LOW);
    isTX = true;
  }

  inline void setRX() {
    isTX = false;
    digitalWrite(outPin, HIGH);
  }

  inline void updateMicPTT() {
    ptt.update();
  }

  inline void updateLinePTT() {
    L_keyDown = keyDown;
    keyDown = (digitalRead(keyPin) == LOW);
  }

  inline void updateMicVOX() {
    L_voxActive = voxActive;
    voxActive = (digitalRead(voxPin) == LOW);
  }

  inline void updateDataVOX() {
    L_dvoxActive = dvoxActive;
    if (dsp.getVoxLevel() > dvoxThreshold) {
      dvoxActive = true;
      dvoxElapsed = 0;
    } else if (dvoxActive && (dvoxElapsed > dvoxDelay)) {
      dvoxActive = false;
    }
  }

  UBitxDSP& dsp;

  Bounce ptt;
  
  int pttPin;
  int voxPin;
  int keyPin;
  int outPin;
  
  bool isTX = false;

  bool pttEnable = false;
  bool voxEnable = false;
  bool dvoxEnable = false;
  bool keyEnable = false;
  bool catEnable = false;

  bool voxActive = false;
  bool L_voxActive = false;
  bool dvoxActive = false;
  bool L_dvoxActive = false;
  bool keyDown = false;
  bool L_keyDown = false;
  bool catActive = false;
  bool L_catActive = false;

  elapsedMillis dvoxElapsed = 0;
  unsigned dvoxDelay = 250; // TODO: make dynamic
};

extern UBitxTR TR;

#endif

//======================================================================
// EOF
//======================================================================
