 }
 
 //Takes a key (text) value (int) pair and sends them as JSON over the serial interface
-void sendJson(const char key[], int value) {
-  StaticJsonBuffer<numChars> jsonBuffer;
+void sendJson(const char key[], byte value) {
+  StaticJsonBuffer<CHAR_ARRAY_SIZE> jsonBuffer;
   JsonObject& root = jsonBuffer.createObject();
   root[key] = value;
   Serial.print(startMarker);
   root.printTo(Serial);
   Serial.println(endMarker);
 }
+
+//Sends all calibrated receiver input max and min values as JSON over the serial interface
+void sendCalibrationJsonData() {
+  StaticJsonBuffer<CHAR_ARRAY_SIZE> jsonBuffer;
+  JsonObject& root = jsonBuffer.createObject();
+  JsonObject &calibrationData = jsonBuffer.createObject();;
+  calibrationData["aileronMin"] = aileronMin;
+  calibrationData["aileronMax"] = aileronMax;
+  calibrationData["elevatorMin"] = elevatorMin;
+  calibrationData["elevatorMax"] = elevatorMax;
+  calibrationData["rudderMin"] = rudderMin;
+  calibrationData["rudderMax"] = rudderMax;
+  calibrationData["throttleMin"] = throttleMin;
+  calibrationData["throttleMax"] = throttleMax;
+  calibrationData["cutoverMin"] = cutoverMin;
+  calibrationData["cutoverMax"] = cutoverMax;
+  root["calibrationData"] = calibrationData;
+  Serial.print(startMarker);
+  root.printTo(Serial);
+  Serial.println(endMarker);
+}
+
+//Checks if the receiver inputs have been calibrated
+//TODO use better verification method
+boolean calibrationComplete() {
+  if (aileronMax == RECEIVER_INPUT_DEFAULT) return false;
+  if (aileronMin == RECEIVER_INPUT_DEFAULT) return false;
+  if (elevatorMax == RECEIVER_INPUT_DEFAULT) return false;
+  if (elevatorMin == RECEIVER_INPUT_DEFAULT) return false;
+  if (rudderMax == RECEIVER_INPUT_DEFAULT) return false;
+  if (rudderMin == RECEIVER_INPUT_DEFAULT) return false;
+  if (throttleMax == RECEIVER_INPUT_DEFAULT) return false;
+  if (throttleMin == RECEIVER_INPUT_DEFAULT) return false;
+  if (cutoverMax == RECEIVER_INPUT_DEFAULT) return false;
+  if (cutoverMin == RECEIVER_INPUT_DEFAULT) return false;
+  return true;
+}
+
+//Reset all calibrated receiver input values to the default
+void resetCalibration() {
+  aileronMax = RECEIVER_INPUT_DEFAULT;
+  aileronMin = RECEIVER_INPUT_DEFAULT;
+  elevatorMax = RECEIVER_INPUT_DEFAULT;
+  elevatorMin = RECEIVER_INPUT_DEFAULT;
+  rudderMax = RECEIVER_INPUT_DEFAULT;
+  rudderMin = RECEIVER_INPUT_DEFAULT;
+  throttleMax = RECEIVER_INPUT_DEFAULT;
+  throttleMin = RECEIVER_INPUT_DEFAULT;
+  cutoverMax = RECEIVER_INPUT_DEFAULT;
+  cutoverMin = RECEIVER_INPUT_DEFAULT;
+}
+
+//Interrupt Service Routine (ISR) for aileron receiver input
+void listenForAileron() {
+  static uint32_t aileronInStart;
+  if (PCintPort::pinState) {
+    aileronInStart = micros();
+  } else {
+    aileronInValue = (uint16_t) (micros() - aileronInStart);
+    servoInputFlags |= FLAG_AILERON;
+  }
+}
+
+//Interrupt Service Routine (ISR) for cutover input
+void listenForCutover() {
+  static uint32_t cutoverInStart;
+  if (PCintPort::pinState) {
+    cutoverInStart = micros();
+  } else {
+    cutoverInValue = (uint16_t) (micros() - cutoverInStart);
+    servoInputFlags |= FLAG_CUTOVER;
+  }
+}
+
+//Interrupt Service Routine (ISR) for elevator receiver input
+void listenForElevator() {
+  static uint32_t elevatorInStart;
+  if (PCintPort::pinState) {
+    elevatorInStart = micros();
+  } else {
+    elevatorInValue = (uint16_t) (micros() - elevatorInStart);
+    servoInputFlags |= FLAG_ELEVATOR;
+  }
+}
+
+//Interrupt Service Routine (ISR) for rudder receiver input
+void listenForRudder() {
+  static uint32_t rudderInStart;
+  if (PCintPort::pinState) {
+    rudderInStart = micros();
+  } else {
+    rudderInValue = (uint16_t) (micros() - rudderInStart);
+    servoInputFlags |= FLAG_RUDDER;
+  }
+}
+
+//Interrupt Service Routine (ISR) for throttle receiver input
+void listenForThrottle() {
+  static uint32_t throttleInStart;
+  if (PCintPort::pinState) {
+    throttleInStart = micros();
+  } else {
+    throttleInValue = (uint16_t) (micros() - throttleInStart);
+    servoInputFlags |= FLAG_THROTTLE;
+  }
+}
+
+//Determines whether a given value is valid receiver input
+boolean isValidReceiverInput(uint16_t receiverInput) {
+  if (receiverInput < RECEIVER_INPUT_MAX && receiverInput > RECEIVER_INPUT_MIN) return true;
+  return false;
+}
+
+//Processes receiver input and writes the converted value out to the servo
+void processServoInput(Servo servo, int receiverInput, const char servoType[], const char servoError[]) {
+  if (servo.attached()) {
+    //The servoInValue (in microseconds) is mapped to the min and max of the Servo.write() function
+    byte convertedServoValue = map(receiverInput, getReceiverInputMin(servoType), getReceiverInputMax(servoType), SERVO_MIN, SERVO_MAX);
+    servo.write(convertedServoValue);
+    sendJson(servoType, convertedServoValue);
+  } else {
+    sendJson("error", servoError);
+  }
+}
+
+//Takes a servoType and returns the corresponding calibrated receiver input max value
+int getReceiverInputMax(const char servoType[]) {
+  if (strcmp(servoType, "aileron") == 0) return aileronMax;
+  if (strcmp(servoType, "elevator") == 0) return elevatorMax;
+  if (strcmp(servoType, "rudder") == 0) return rudderMax;
+  if (strcmp(servoType, "throttle") == 0) return throttleMax;
+}
+
+//Takes a servoType and returns the corresponding calibrated receiver input min value
+int getReceiverInputMin(const char servoType[]) {
+  if (strcmp(servoType, "aileron") == 0) return aileronMin;
+  if (strcmp(servoType, "elevator") == 0) return elevatorMin;
+  if (strcmp(servoType, "rudder") == 0) return rudderMin;
+  if (strcmp(servoType, "throttle") == 0) return throttleMin;
+}

//Created by Ryan Staatz

//Arduino JSON library: https://github.com/bblanchon/ArduinoJson
#include <ArduinoJson.h>
#include <Servo.h>

//Sets the baud rate of the Arduino
const long BAUD_RATE = 115200;

//Receiver input timeout in microseconds
const int PULSE_TIMEOUT = 44100;

//Pulse threshold values for receiver input for cutover between auto and manual control
const int CUTOVER_MIN = 900;
const int CUTOVER_MAX = 1500;

//Pulse threshold values for receiver input for servos and motor
const int RECEIVER_MIN = 750;
const int RECEIVER_MAX = 1800;

//Sets the character array (max) length for serial input
const int numChars = 300;

//This array stores Json characters read from serial input
char receivedJson[numChars];

//All valid input/output must start/end with the corresponding char
char startMarker = '@';  
char endMarker = '#';

//Determines if new Json data has been collected from serial input for processing
boolean newData = false;

//Determines if the plane is controlled manually (remote control) or via autopilot (phone)
boolean manualControl = false;

//All valid input/output must start/end with the corresponding chars below
char endMarker = '#';
char startMarker = '@';

//This array stores Json characters read from serial input
char receivedJson[CHAR_ARRAY_SIZE];

//Calibrated min and max for all receiver input (in microseconds)
uint16_t aileronMax = RECEIVER_INPUT_DEFAULT;
uint16_t aileronMin = RECEIVER_INPUT_DEFAULT;
uint16_t cutoverMax = RECEIVER_INPUT_DEFAULT;
uint16_t cutoverMin = RECEIVER_INPUT_DEFAULT;
uint16_t elevatorMax = RECEIVER_INPUT_DEFAULT;
uint16_t elevatorMin = RECEIVER_INPUT_DEFAULT;
uint16_t rudderMax = RECEIVER_INPUT_DEFAULT;
uint16_t rudderMin = RECEIVER_INPUT_DEFAULT;
uint16_t throttleMax = RECEIVER_INPUT_DEFAULT;
uint16_t throttleMin = RECEIVER_INPUT_DEFAULT;

//Servos
Servo aileron;
Servo elevator;
Servo rudder;
