 /*
-  Analog input, serial output
+  Laser Harp monitoring via Arduino.
+  
+  Monitors the inputs of 8 photoresistors that detect lasers, multiplexed via
+  a 74HC5067 IC and read by the Arduino analog input.
+  
+  Sends output via serial with the following format:
+    57600 baud, 8 data bits, 1 stop.
+    
+    Sends "~" to start, indicating that data follows.
+    While monitoring, sends "~" character every second as a heartbeat.
+    Sends character "A" - "H" when laser beam is interrupted.
+    Sends character "a" - "h" when laser beam is restored.
+    
+    Sends character "@" to indicate that debugging information is being output. After
+    "@" is received, all input should be ignored until a "~" is received.
  */
 
 // These constants won't change.  They're used to give names

    delayMicroseconds(10);  // delay 10 microseconds to allow multiplexer to stabilize.
    return analogRead(analogInPin);
}

// Pin for status LED.
const int ledPin = 9;

// Type of LED modes.
const byte LED_ON = 0; // on solid

  }
}

void setLasers(boolean on)
{
    digitalWrite(laserPin, on ? HIGH : LOW);
}

void gatherCalibrationData()
{
  long start = millis();
  
  for (int i = 0; i < inputCount; ++i) {
    calibrateMin[i] = 1023;
    calibrateMax[i] = 0;
  }
  
  while (millis() - start < 1500) {
    for (int i = 0; i < inputCount; ++i) {
      int value = multiplexedAnalogRead(i);
      if (value < calibrateMin[i])
        calibrateMin[i] = value;
      if (value > calibrateMax[i])
        calibrateMax[i] = value;
        
      delay(1);
    }
    
    updateLed();
  }
}

// Display the range of calibration data that was read.
void displayCalibrationData()
{
  for (int i = 0; i < inputCount; ++i) {
    Serial.print(i);
    Serial.print(": ");
    Serial.print(calibrateMin[i]);
    Serial.print(" to ");
    Serial.print(calibrateMax[i]);
    Serial.println();
  }
}

// If the gap in reading between on and off is less than this gap, signal an error.
const int minCalibrationGap = 60;

// Calibrate the photoresistor thresholds. Turn the lasers ON, and read
// the photoresistors, keeping the lowest values detected.
// Turn the lasers OFF, read the photoresistors, keeping the highest values detected.
// Put the threshold halfway between those values. If the gap between on and off is
// less than "minCalibrationGap", indicate an error by blinking the status LED the 
// number of the laser that is in error.
void calibrate()
{
  int minLasersOn[inputCount], maxLasersOff[inputCount];
  
  // Blink LED slowly to indicate calibration going on.
  setLedMode(LED_SLOW, 0);
  
  Serial.println("@"); // Indicate that debugging output follows; do not interpret as data.
  Serial.println("Calibrating light sensors...");
  
  setLasers(true);
  delay(400);  // let lasers get fully powered on.
  gatherCalibrationData();
  Serial.println("Lasers on:");
  displayCalibrationData();
  for (int i = 0; i < inputCount; ++i)
    minLasersOn[i] = calibrateMin[i];
    
  setLasers(false);
  delay(400);  // let lasers get fully powered off.
  gatherCalibrationData();
  Serial.println("Lasers off:");
  displayCalibrationData();
  for (int i = 0; i < inputCount; ++i)
    maxLasersOff[i] = calibrateMax[i];
 
  setLasers(true);
  
  Serial.println("Calibration complete; thresholds are:");
  int error = -1; // Set to first laser we can't calibrate.
  for (int i = 0; i < inputCount; ++i) {
    thresholds[i] = (minLasersOn[i] + maxLasersOff[i]) / 2;
    Serial.print(i);
    Serial.print(": ");
    Serial.print(thresholds[i]);
    
    if (minLasersOn[i] - maxLasersOff[i] < minCalibrationGap) {
      Serial.print("  CALIBRATION FAILED!");
      if (error == -1)
        error = i;
    }
    Serial.println();
  }  
  
  // If we had a calibration error, blink the status LED to show laser with problem.
  if (error >= 0)
    setLedMode(LED_NUMBER, error + 1);
  else
    setLedMode(LED_ON, 0);
  
  Serial.println("~");  // Transition back to output data.
}

void setup() {
  // initialize serial communications at 57600 bps:
  Serial.begin(57600); 
