/* Events module */
/* By: Benjie Nelson, Nora Levinson, David Sirkin */
/* Dr. Von Sirlevson's Automated Locomotive Computation Engine */

/**************************************************/
/* Includes                                       */
/**************************************************/

#include <timers12.h>

#include "ME218_E128.h"
#include "S12eVec.h"
#include "ADS12e.H"

#include "Events.h"
#include "GameDefs.h"
		    
/**************************************************/
/* Module Variables                               */
/**************************************************/

/* Store the current beacon DC and completed runs */

static unsigned int beaconDC;
static char completedRuns;

/* Possible & current states for the tape sensors */

typedef enum {
  black, red, green, white

} TapeState;

static TapeState tapeB = white, tapeR = white,

                 tapeC = white, tapeL = white;

/**************************************************/
/* Getter Functions for Static Variables          */
/**************************************************/

TapeState GetTapeB(void) {
  return tapeB;
}

TapeState GetTapeL(void) {

  return tapeL;
}

TapeState GetTapeR(void) {
  return tapeR;
}

/**************************************************/
/* Check Events Functions                         */
/**************************************************/

/* Pretty straight-forward, poll the flash pin T1 */

char SeeFlash(void) {
  return((PTT & BIT1HI) != 0);
}

/* Poll port AD pin 4 for beacon signal amplitude */

int BeaconStr(void) {
  return ADS12_ReadADPin(4);  
}

/* Poll the IC-found DC or clear if expired first */
/* Compare that with expected DC range for goal 3 */
/* & dispenser. Set static states 'last' for each */

char CheckBeacon(void) {
  static int cnt50, cnt90, cntBad;

  static char duty, lastBeaconEvent;
  
  if(!Expired(BEACON))

    duty = beaconDC;
  else
    duty = 0;

  if(duty > ABOUT_40 && duty < ABOUT_60)
    cnt50++;

  else
    if(duty > ABOUT_80 && duty < ABOUT_100)
      cnt90++;

    else
      cntBad++;  

  // If see dispenser, reset counts and return event
  if(cnt50 > ACCEPT_BEACON) { 
    if(cnt90 + cntBad <= REJECT_BEACON) {

      cnt50 = cnt90 = cntBad = 0;
      if(lastBeaconEvent != SEE_DISPENSER)

        return(lastBeaconEvent = SEE_DISPENSER);
      else
        return(NO_EVENT); 
    }
    else {

      cnt50 = cnt90 = cntBad = 0;
      if(lastBeaconEvent != LOST_BEACON)

        return(lastBeaconEvent = LOST_BEACON);
      else
        return(NO_EVENT);    
    }
  }
  // If see goal #3, reset counts and return event

  if(cnt90 > ACCEPT_GOAL) { 
    if(cnt50 + cntBad <= REJECT_BEACON) {

      cnt50 = cnt90 = cntBad = 0;
      if(lastBeaconEvent != SEE_GOAL)

        return(lastBeaconEvent = SEE_GOAL);
      else
        return(NO_EVENT); 
    }
    else {

      cnt50 = cnt90 = cntBad = 0;
      if(lastBeaconEvent != LOST_BEACON)

        return(lastBeaconEvent = LOST_BEACON);
      else
        return(NO_EVENT);    
    }
  }
  // Don't believe the last reading, so reset counts  

  if(cntBad > REJECT_BEACON) { 
    cnt50 = cnt90 = cntBad = 0;

    if(lastBeaconEvent != LOST_BEACON)
      return(lastBeaconEvent = LOST_BEACON);

    else
      return(NO_EVENT);
  }
  return(NO_EVENT);  
}

/* Poll the tape pins AD0-3 and set static states */

char CheckTapeB(void) {

  static unsigned int cntBlack;

  if(ADS12_ReadADPin(0) > BLACK) {

    if(++cntBlack > ACCEPT_TAPE) {
	  // Found the black tape. Set tapeB to be black
      cntBlack = ACCEPT_TAPE;

      if(tapeB != black) {        
        tapeB = black;

        return(TRUE);
      }
    }
  }
  else {
	// Lost the black tape. Re-set tapeB to be white
    cntBlack = 0;

    if(tapeB != white) {
      tapeB = white;

      return(TRUE);
    }
  }
  return(FALSE);
}
  
char CheckTapeL(void) {

  static unsigned int cntBlack;

  if(ADS12_ReadADPin(1) > BLACK) {

    if(++cntBlack > ACCEPT_TAPE) {
	  // Found the black tape. Set tapeL to be black
      cntBlack = ACCEPT_TAPE;

      if(tapeL != black) {        
        tapeL = black;

        return(TRUE);
      }
    }
  }
  else {
	// Lost the black tape. Re-set tapeL to be white
    cntBlack = 0;

    if(tapeL != white) {
      tapeL = white;

      return(TRUE);
    }
  }
  return(FALSE);
}
   
char CheckTapeC(void) {

  static unsigned int cntBlack;

  if(ADS12_ReadADPin(2) > BLACK) {

    if(++cntBlack > ACCEPT_TAPE) {
	  // Found the black tape. Set tapeC to be black
      cntBlack = ACCEPT_TAPE;

      if(tapeC != black) {        
        tapeC = black;

        return(TRUE);
      }
    }
  }
  else {
	// Lost the black tape. Re-set tapeC to be white
    cntBlack = 0;

    if(tapeC != white) {
      tapeC = white;

      return(TRUE);
    }
  }
  return(FALSE);
}

char CheckTapeR(void) {

  static unsigned int cntBlack;

  if(ADS12_ReadADPin(3) > BLACK) {

    if(++cntBlack > ACCEPT_TAPE) {
	  // Found the black tape. Set tapeR to be black
      cntBlack = ACCEPT_TAPE;

      if(tapeR != black) {      
        tapeR = black;

        return(TRUE);
      }
    }
  }
  else {
	// Lost the black tape. Re-set tapeR to be white
    cntBlack = 0;

    if(tapeR != white) {
      tapeR = white;

      return(TRUE);
    }
  }
  return(FALSE);
}

/* Poll the bumper pins P0-2 & S2-3, set HI or LO */

char BumpIntoFT(void) {
  return(!((PTP & BIT0HI) != 0));
}

   
char BumpIntoFB(void) {
  return(!((PTP & BIT2HI) != 0));
}

    							
char BumpIntoBL(void) {
  return((PTS & BIT2HI) != 0);
}

char BumpIntoBR(void) {
  return((PTS & BIT3HI) != 0);
}

/* Main check events function calls each of those */
/* checker routines in turn and returns the state */

char CheckEvents(void) {
  static char lastBeaconEvent,

              lastBumpFTEvent, lastBumpFBEvent,
              lastBumpBREvent, lastBumpBLEvent;

  // Flash detector occurs once, so no need to track

  if(SeeFlash())
    return(SEE_FLASH);

  // Beacon event is assigned within the conditional
  if(lastBeaconEvent = CheckBeacon())

    return(lastBeaconEvent);
 
  // Tape is on B, L C or R, but no history to reset
  if(CheckTapeB() || CheckTapeL() ||

     CheckTapeC() || CheckTapeR())
       return(TAPE_CHANGE);

  // Bumpers are on FT, FB, BL or BR, so reset event
  if(BumpIntoFT()) {

    if(lastBumpFTEvent != BUMP_FT)
      return(lastBumpFTEvent = BUMP_FT);
  }

  else
    if(lastBumpFTEvent != LOST_FT)
      return(lastBumpFTEvent = LOST_FT);

       
  if(BumpIntoFB()) {
    if(lastBumpFBEvent != BUMP_FB)
      return(lastBumpFBEvent = BUMP_FB);  
  }

  else
    if(lastBumpFBEvent != LOST_FB)
      return(lastBumpFBEvent = LOST_FB);

    
  if(BumpIntoBL()) {
    if(lastBumpBLEvent != BUMP_BL)
      return(lastBumpBLEvent = BUMP_BL);
  }

  else
    if(lastBumpBLEvent != LOST_BL)
      return(lastBumpBLEvent = LOST_BL);

	      
  if(BumpIntoBR()) {
    if(lastBumpBREvent != BUMP_BR)
      return(lastBumpBREvent = BUMP_BR);
  }

  else
    if(lastBumpBREvent != LOST_BR)
      return(lastBumpBREvent = LOST_BR);

 
  // Lost if SM timer expires, so clear flag, return
  if(Expired(SM_TMR)) {
    TMRS12_ClearTimerExpired(SM_TMR);
    return(SM_TMR_XPD); 
  }

  return(NO_EVENT);
}