#include <Servo.h>
#include "Ramp.h"

#define ccwPBPin  2
#define cwPBPin   3
#define cwLED     4
#define ccwLED    5
#define enablePin 8

const uint8_t numberOfServo = 3;
const uint8_t servoPins[] = {11, 10, 9};
const uint8_t rampPins[] = {A0, A1, A2};


const float minTime = 0.5f;
const float maxTime = 5.0f;
const int maxdegreeAngle = 180;


Servo servo[numberOfServo];
bool stop[numberOfServo];
bool start[numberOfServo];
bool enable = false;
bool cwState = false;
bool ccwState = false;
bool directionState = false;

unsigned long startTime[numberOfServo];

int rawValue[numberOfServo];
float settingTime[numberOfServo];
float rate[numberOfServo];
float degreeAngle[numberOfServo];
float lastAngle[numberOfServo];

MicroBeaut_Ramp rampRate[numberOfServo];

void setup()
{
  Serial.begin(9600);
  // Input Mode
  pinMode(cwPBPin, INPUT);
  pinMode(ccwPBPin, INPUT);
  pinMode(enablePin, INPUT_PULLUP);

  // Output Mode
  pinMode(cwLED, OUTPUT);
  pinMode(ccwLED, OUTPUT);

  // Servo Pin
  for (uint8_t index = 0; index < numberOfServo; index++) {
    servo[index].attach(servoPins[index]);
  }
}

void loop()
{
  cwState = digitalRead(cwPBPin);   // Read CW PB State
  ccwState = digitalRead(ccwPBPin); // Read CCW PB State
  enable = digitalRead(enablePin);  // Read Enable Status

  directionState = (directionState & !ccwState) | cwState; // Selection: 0 = CCW, 1 = CW

  digitalWrite(cwLED, directionState);    // CW Status
  digitalWrite(ccwLED, !directionState);  // CCW Status

  for (uint8_t index = 0; index < numberOfServo; index++) {
    rawValue[index] = analogRead(rampPins[index]);
    settingTime[index] = Scale(rawValue[index], minTime, maxTime);
    rate[index] = (float)maxdegreeAngle / settingTime[index];
    if (enable) {
      if (directionState) {
        degreeAngle[index] = rampRate[index].rampControl(180.0f, rate[index], enable);  // CW Direction
      }
      else {
        degreeAngle[index] = rampRate[index].rampControl(0.0f, rate[index], enable);    // CCW Direction
      }
    }
    servo[index].write(degreeAngle[index]);
    stop[index] = (degreeAngle[index] == 0 && lastAngle[index] != 0);
    stop[index] |= (degreeAngle[index] == 180 && lastAngle[index] != 180);
    start[index] = lastAngle[index] == 0 && degreeAngle[index] != 0;
    start[index] |= lastAngle[index] == 180 && degreeAngle[index] != 180;
    if (start[index]) {
      startTime[index] = micros();
    }

    if (stop[index]) {
      Serial.print("Servo " + String(index + 1));
      Serial.print(directionState == true ? " CW" : " CCW");
      Serial.print(": Setting Time:" + String(settingTime[index]) + " s");
      Serial.print(": Speed:" + String(rate[index]) + " d/s Time:");
      Serial.print(String(float(micros() - startTime[index]) / 1000000.0));
      Serial.println(" s");
    }
    lastAngle[index] = degreeAngle[index];
  }
}

float Scale(int const inputValue, float const minEU, float const maxEU) {
  return ((float)inputValue / 1023.0) * (maxEU - minEU) + minEU;      // Return scaling value
}
uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
btn2:1.l
btn2:2.l
btn2:1.r
btn2:2.r
r1:1
r1:2
r2:1
r2:2
led1:A
led1:C
led4:A
led4:C
r3:1
r3:2
r9:1
r9:2
servo1:GND
servo1:V+
servo1:PWM
pot1:GND
pot1:SIG
pot1:VCC
sw1:1
sw1:2
sw1:3
pot2:GND
pot2:SIG
pot2:VCC
pot3:GND
pot3:SIG
pot3:VCC
servo2:GND
servo2:V+
servo2:PWM
servo3:GND
servo3:V+
servo3:PWM