#include <mechButton.h>
#include <timeObj.h>
#include <serialStr.h>

#define  IN_PIN_NUM     2
#define  DEF_DELAY_MS   25
#define  DEF_PERIOD_MS  1000    // 50 for real version.
#define  OUT_PIN_NUM    13
#define  PULSE_WIDTH    100     // 10 foe real version.

// *************************
// Q & D signal generator.
// Loose this for the "real" version.

#include <blinker.h>
blinker inSignal(4,PULSE_WIDTH,2000,true);

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


mechButton     inSig(IN_PIN_NUM);                  // Manager & debouncer for input pin.
timeObj        delayTimer(DEF_DELAY_MS,false);     // How long we drag our feet before starting next signal.
timeObj        pulseTimer(PULSE_WIDTH,false);      // How long to lupses last?
timeObj        periodTimer(DEF_PERIOD_MS,false);   // How long between the double pulses?
serialStr      comStr;                             // Manager of input serial port.
unsigned long  startMicros;                        // When we saw the last pulse start.
float          outputDelayMs;                      // Amount in Ms we delay the first output pulse.


void setup(void) {

   Serial.begin(57600);             // Fire up serial.
   Serial.println();
   Serial.println("Type a number between 1 & 50 to set delay ms");
   startMicros = 0;                 // We're relying on we'll never see a zero here.
   inSig.setCallback(inputChange);  // See a state change? Call this.
   outputDelayMs = DEF_DELAY_MS;    // We'll start the delay at this defualt.
   pinMode(OUT_PIN_NUM,OUTPUT);     // Set up our ouput pin.
   comStr.setCallback(handleStr);   // If a string comes in the serial port? Call this.
   
   // *************************     // Loose this bit for the "real" one.
   inSignal.setOnOff(true);         // Fire up the signal.
   // *************************

}


void inputChange(void) {

   unsigned long now;
   float         measuredPeriod;

   now = micros();                                        // Grab the time.
   if (!inSig.getState()) {                               // If it was a high to low..                         
      delayTimer.setTime(outputDelayMs,true);             // Update and fire off the delayTimer.
      if (startMicros) {                                  // If we have a non zero startMicros..
         measuredPeriod = (now - startMicros)/1000.0;     // Do the calculation for the period.
         periodTimer.setTime(measuredPeriod/2.0,false);   // Set period timer to 1/2 this value.
      } else {                                            // Else this is first pulse..
         periodTimer.setTime(DEF_PERIOD_MS,false);        // Set the period timer to the defualt.
      }
      startMicros = now;                                  // Set the start time to when this began.
   }
}


void handleStr(char* theStr) {

   float inDelay;
  
   inDelay = atof(theStr);
   if (inDelay<1) outputDelayMs = 1;
   if (inDelay>50) outputDelayMs = 50;
   else outputDelayMs = inDelay;
}


void loop(void) {

   idle();                             // Run the magic behind the scenes.
   if (delayTimer.ding()) {            // If the delay timer dings..
      digitalWrite(OUT_PIN_NUM,HIGH);  // Time to output the first High.
      pulseTimer.start();              // We start the pulse timer.
      periodTimer.start();             // Also start the period timer.
      delayTimer.reset();              // Reset, turn off, the delayTimer.
   }
   if (pulseTimer.ding()) {            // If the pulse timer dings..
      digitalWrite(OUT_PIN_NUM,LOW);   // Shut off the current pulse.
      pulseTimer.reset();              // And reset the pulse timer.
   }
   if (periodTimer.ding()) {           // If the periodTimer dings..
      digitalWrite(OUT_PIN_NUM,HIGH);  // Start the second pulse.
      pulseTimer.start();              // And start the pulse timer.
      periodTimer.reset();             // Reset the period timer.
   }
}