 	configure();
 	
 	// Start the serial port.
-	Serial.begin(9600);
+	Serial.begin(115200);
 	
 	// Wait two seconds.
-	Serial.println("hello world");
+	Serial.println("Boot v2.0");
 	
 	// Select a default clip mode from the set of possible modes, if one is not set.
 	eClipMode = EEPROM.read(EEMODEADDR);
-	if (eClipMode != EEMODE_SYNCPULSE && eClipMode != EEMODE_HEIGHTONLY)
-	{
-		EEPROM.write(EEMODEADDR, EEMODE_HEIGHTONLY);
-		eClipMode = EEMODE_HEIGHTONLY;
-	}
-	
+        switch( eClipMode )
+        {
+          case EEMODE_SYNCPULSE:
+            break;
+          case EEMODE_HEIGHTONLY:
+            break;
+          case EEMODE_SERIAL:
+            break;
+          default:
+            eClipMode = EEMODE_HEIGHTONLY;
+            EEPROM.write(EEMODEADDR, EEMODE_HEIGHTONLY);
+        }
+	
+        // Debug Mode
+        eClipMode = EEMODE_SERIAL;
+
 	// Wait for a random time so that not all clips zero their motor at the same time.
 	randomSeed(analogRead(PIN_RND));
 	uint16_t randomWait = random(1000);


#define EEMODEADDR 0			// The address of the mode stored in EEPROM.
#define EEMODE_CHANGETIME 5000  // The number of ms to hold the switch before the clip mode is changed.
#define EEMODE_SYNCPULSE 45		// The Clip looks for a sync pulse on one of the LDRs.
#define EEMODE_HEIGHTONLY 37	// The Clip uses both LDRs to estimate height, no colour involved.

#define PULSE_STATE__NOT_CHECKED  -1	// The sync-pulse routine did not bother checking, too soon since previous check.
#define PULSE_STATE__NO_PULSE      0	// The sync-pulse check returned no pulse.. Probably off a screen.

	if (!cycleCheck(&tmrModeCheck, 10U))
		return;
	
        if( digitalRead(PIN_SWBOT) == HIGH )
          return;

        while( digitalRead(PIN_SWBOT) == LOW )
        {
          switch( eClipMode )
          {
            case EEMODE_HEIGHTONLY:
              pRGB.setPixelColor(0,  0, 255, 0);
            
              eRGBMode  = RGBMODE_SCREEN;
              eClipMode = EEMODE_SYNCPULSE;
              break;
              
            case EEMODE_SYNCPULSE:
              pRGB.setPixelColor(0,  0, 0, 255);
              
              eRGBMode  = RGBMODE_NONE;
              eClipMode = EEMODE_SERIAL;
              break;
            
            case EEMODE_SERIAL:
              pRGB.setPixelColor(0,  255, 0, 0);
              
              eRGBMode  = RGBMODE_NONE;
              eClipMode = EEMODE_HEIGHTONLY;
              break;
            
            default:
              pRGB.setPixelColor(0,  255, 0, 0);
              eRGBMode  = RGBMODE_NONE;
              eClipMode = EEMODE_HEIGHTONLY;
          }
          
          pRGB.show();
          delay( 1000 );
        }
        
        for( int i=0; i<3; i++ )
        {
          switch( eClipMode )
          {
            case EEMODE_HEIGHTONLY:
              pRGB.setPixelColor(0,  255, 0, 0);
              break;
            case EEMODE_SYNCPULSE:
              pRGB.setPixelColor(0,  0, 255, 0);
              break;
            case EEMODE_SERIAL:
              pRGB.setPixelColor(0,  0, 0, 255);
              break;
          }
          pRGB.show();
          delay( 100 );
          pRGB.setPixelColor(0,  0, 0, 0);
          pRGB.show();
          delay( 100 );
        }
        
        EEPROM.write( EEMODEADDR, eClipMode );
}

/**
 * @brief Check the sync pulse and update relevant global variables.
 * This is automatically rate limited to 5ms samples.
 * It will update the iTargetR,G,B, iLDR1Max and iLDR1Min values if valid pulses are detected.
 * @return -1 if check not performed, 1 if we received an active pulse, 0 if we did not.
 */
int8_t checkPulse() {

	// Only allow this function to be called once every 5ms.
	static unsigned long tmr1 = 0;
	if (!cycleCheck(&tmr1, 5U))
		return PULSE_STATE__NOT_CHECKED;

	// Define static variables.
	static WindowVariance* pEstimatedMin = new WindowVariance(5);	// Running 
	static WindowVariance* pEstimatedMax = new WindowVariance(5);
	static int r=0; static int g=0; static int b=0;
	static float x1,x2,y1,y2 = 0;	// Required for slope differentials.
	static float fSlope = 0.0f;		// Required for slope differentials.
	static long iLastMinima = 0;	// The time of the last minimal (ms).

	// Read the LDR and reset the serial debug colour values.
	int iLDRValue = analogRead(PIN_LDR1);
	r=0; g=0; b=0;

	// Compute the slope (dLDR/dTime) by comparing it to the previous data.
	long iCurrentTime = millis();
	x1 = x2; y1 = y2;
	x2 = (float)iCurrentTime; y2 = (float)iLDRValue;
	fSlope = (y1-y2) / (x1-x2);

	// If we are hitting a big dip AND it has been over 50ms since the last one.
	int iDeltaTime = iCurrentTime - iLastMinima;
	boolean bSlopeDetected = fSlope < -SYNC_SIGNAL_DROP_THRESHOLD;
	boolean bWithinPulseRange = iDeltaTime > (DATA_WIDTH - DATA_WIDTH_ERR); // &&  delta < (DATA_WIDTH + DATA_WIDTH_ERR + PULSE_WIDTH + PULSE_WIDTH_ERR);

	// TODO: Reject pulses after a recent slope detection.
	if (bSlopeDetected && bWithinPulseRange)
	{
		// Log the start of the second pulse of the data-frame.
		iLastMinima = iCurrentTime;

		// If another minma happened BEFORE 500ms  (i.e. the amount of time between a high and a red/green)
		//  then we know that it is likely attached to the wrong pulse.
	}

	// Determine if this device has a sync pulse.
	boolean bActive = iDeltaTime < ( DATA_WIDTH + DATA_WIDTH_ERR ) ;

	// If an active sync pulse, sample the data.
	if (bActive)
	{
		// Make it relative to the start of the minima spike.
		int iRelativeDelta = iCurrentTime - iLastMinima;

		// Sample the min and max.  Min = immediately after the spike, Max = 4th pulse after the spike.
		if (checkSample(iRelativeDelta, (PULSE_WIDTH * 0) + SAMPLE_OFFSET, SAMPLE_WINDOW)) {		// Min.
			pEstimatedMin->push(iLDRValue);
			iLDR1Min = pEstimatedMin->mean();
			ldr2.updateMin(iLDR1Min);
		}
		if (checkSample(iRelativeDelta, (PULSE_WIDTH * 4) + SAMPLE_OFFSET, SAMPLE_WINDOW)) {		// Max.
			pEstimatedMax->push(iLDRValue);
			iLDR1Max = pEstimatedMax->mean();
			ldr2.updateMax(iLDR1Max);
		}

		// Sample the RGB pulses. R = 1st pulse after the spike, B = 3rd pulse after the spike.
		if (checkSample(iRelativeDelta, (PULSE_WIDTH * 1) + SAMPLE_OFFSET, SAMPLE_WINDOW)) {		// Red.
			r = iLDRValue;
			iTargetR = constrain(map(iLDRValue, iLDR1Min, iLDR1Max, 0, 255), 0, 255);
		}
		if (checkSample(iRelativeDelta, (PULSE_WIDTH * 2) + SAMPLE_OFFSET, SAMPLE_WINDOW)) {		// Green.
			g = iLDRValue;
			iTargetG = constrain(map(iLDRValue, iLDR1Min, iLDR1Max, 0, 255), 0, 255);
		}
		if (checkSample(iRelativeDelta, (PULSE_WIDTH * 3) + SAMPLE_OFFSET, SAMPLE_WINDOW)) {		// Blue.
			b = iLDRValue;
			iTargetB = constrain(map(iLDRValue, iLDR1Min, iLDR1Max, 0, 255), 0, 255);
		}

		// Ensure we are in a mode that displays a screen colour.
		//changeMode(SCREEN);
	}
	else
	{
		// Turn the LED blue (not on screen).
		//changeMode(NO_SCREEN);
	}

	// Debug graph. Used with SerialChart. 
	#ifdef SERIAL_SYNC_DEBUG
	Serial.print(millis()); Serial.print(","); 		// ms
	Serial.print(iTargetR); Serial.print(","); 		// Red
	Serial.print(iTargetG); Serial.print(","); 		// Green
	Serial.print(iTargetB); Serial.print("\n"); 	// Blue
	#endif
	
	#ifdef SERIAL_SYNC_DEBUG2
	// Print out the verbose serial debug as csv.
	Serial.print(millis()); Serial.print(","); 		// ms
	Serial.print(fSlope); Serial.print(","); 		// slope
	Serial.print(iLDR1Max); Serial.print(","); 		// Estimated maximum (white + backlight).
	Serial.print(r); Serial.print(","); 			// Red (estimated)
	Serial.print(g); Serial.print(","); 			// Green (estimated) 
	Serial.print(b); Serial.print(","); 			// Blue (estimated)
	Serial.print(iLDR1Min); Serial.print(","); 		// Estimated minimum (black + backlight).
	Serial.println(iLDRValue);						// ldr raw
	#endif

	// Return if we are active or not.
	return bActive ? PULSE_STATE__ACTIVE_PULSE : PULSE_STATE__NO_PULSE;
}

/**
 * @brief Handle the clip behaviour for sync pulse mode.
