#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Encoder.h>



#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// "UIC Logo", 128x64px
static const unsigned char PROGMEM logo_bmp [] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 
0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 
0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 
0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 
0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 
0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 
0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 
0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 
0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 
0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 
0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xf8, 
0x1f, 0xfc, 0x00, 0x1f, 0xfe, 0x00, 0x0f, 0xe0, 0x00, 0xff, 0xff, 0x00, 0x00, 0x07, 0xff, 0xf8, 
0x3f, 0xfc, 0x00, 0x1f, 0xfe, 0x00, 0x0f, 0xe0, 0x00, 0xff, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xfc, 
0x3f, 0xfc, 0x00, 0x1f, 0xfe, 0x00, 0x0f, 0xe0, 0x00, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x7f, 0xfc, 
0x3f, 0xfc, 0x00, 0x1f, 0xfe, 0x00, 0x0f, 0xe0, 0x00, 0xff, 0x80, 0x00, 0x00, 0x00, 0x1f, 0xfc, 
0x7f, 0xfc, 0x00, 0x1f, 0xfe, 0x00, 0x0f, 0xe0, 0x00, 0xff, 0x00, 0x01, 0xf8, 0x00, 0x0f, 0xfe, 
0x7f, 0xfc, 0x00, 0x1f, 0xfe, 0x00, 0x0f, 0xe0, 0x00, 0xfe, 0x00, 0x07, 0xff, 0x00, 0x3f, 0xfe, 
0x7f, 0xfc, 0x00, 0x1f, 0xfe, 0x00, 0x0f, 0xe0, 0x00, 0xfe, 0x00, 0x1f, 0xff, 0x87, 0xff, 0xfe, 
0x7f, 0xfc, 0x00, 0x1f, 0xfe, 0x00, 0x0f, 0xe0, 0x00, 0xfc, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xfe, 
0x7f, 0xfc, 0x00, 0x1f, 0xfe, 0x00, 0x0f, 0xe0, 0x00, 0xfc, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xfe, 
0x7f, 0xfc, 0x00, 0x1f, 0xfe, 0x00, 0x0f, 0xe0, 0x00, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfe, 
0x7f, 0xfc, 0x00, 0x1f, 0xfe, 0x00, 0x0f, 0xe0, 0x00, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfe, 
0x7f, 0xfc, 0x00, 0x1f, 0xfe, 0x00, 0x0f, 0xe0, 0x00, 0xfc, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xfe, 
0x7f, 0xfc, 0x00, 0x1f, 0xfe, 0x00, 0x0f, 0xe0, 0x00, 0xfc, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xfe, 
0x7f, 0xfc, 0x00, 0x1f, 0xfe, 0x00, 0x0f, 0xe0, 0x00, 0xfe, 0x00, 0x0f, 0xff, 0x9f, 0xff, 0xfe, 
0x3f, 0xfe, 0x00, 0x0f, 0xfc, 0x00, 0x1f, 0xe0, 0x00, 0xfe, 0x00, 0x07, 0xff, 0x00, 0x7f, 0xfc, 
0x3f, 0xfe, 0x00, 0x03, 0xf0, 0x00, 0x1f, 0xe0, 0x00, 0xff, 0x00, 0x00, 0xf8, 0x00, 0x0f, 0xfc, 
0x3f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0xff, 0x80, 0x00, 0x00, 0x00, 0x1f, 0xfc, 
0x1f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x3f, 0xf8, 
0x1f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0xff, 0xe0, 0x00, 0xff, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xf8, 
0x0f, 0xff, 0xf8, 0x00, 0x00, 0x07, 0xff, 0xe0, 0x00, 0xff, 0xff, 0x00, 0x00, 0x07, 0xff, 0xf0, 
0x07, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xe0, 
0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 
0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 
0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 
0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 
0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 
0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 
0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 
0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 
0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

// Encoder pins
#define CLK 2
#define DT 3
#define SW 4

const int travDirPin = 7; 
const int travStepPin = 6;

const int rotDirPin = 10; 
const int rotStepPin = 11;


Encoder myEnc(CLK, DT);
int lastPos = -999;
int pos;

int modeSelected = -1;  // No mode selected initially
boolean confirmed = false; 
int lastMode = -1; 

#define minTravDist 25                      //Defines minimum, maximum and increment of travel distance
#define maxTravDist 975
#define initialRotAng 180                   //Define rotation initial setting, minimum, maximum and increment
#define minRotAng 20
#define maxRotAng 360
#define rotAngInc 10

const float pulsesPerMM = 50;                     //Number of motor pulses for 1mm travel
const float pulsesPerDeg = 4.4444;                //Number of motor pulses for 1 degree of rotation
float currentAngle = 0; 

int travelDir = 0;


void setup() {
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.drawBitmap(0, 0, logo_bmp, 128, 64, WHITE);
  display.display();
  Serial.println("OLED Display Setup complete");

  pinMode(SW, INPUT_PULLUP); // Set the button pin as input with pull-up
  pinMode(travDirPin, OUTPUT);                            // Define the travel stepper motor pins
  pinMode(travStepPin, OUTPUT);

  delay(5000);                // Displays logo for 5 seconds 
  display.clearDisplay();
  display.display();
  Serial.println("Camera Slider");
  Serial.print("Enter mode: 0 = Pan, 1 = Rotate, 2 = Pan & Rotate or use encoder:\n");

}

void loop() {
  static long oldPosition  = -999;
  long newPosition = myEnc.read() / 4; // Encoder position

  // Handle encoder input
  if (!confirmed) {
    if (newPosition != oldPosition) {
      oldPosition = newPosition;
      if (newPosition < 0) newPosition = 2; // Wrap around logic
      if (newPosition > 2) newPosition = 0;
      updateDisplay(newPosition);
    }

    if (digitalRead(SW) == LOW) {
      modeSelected = newPosition;
      confirmed = true;
      Serial.print("Mode selected via Encoder: ");
      Serial.println(modeSelected);
      displayModeSelection(modeSelected);
    }
  }

  if (!confirmed && Serial.available() > 0) {          // Handle serial input
    int serialInput = Serial.parseInt();
    if (serialInput >= 0 && serialInput <= 2) {
      modeSelected = serialInput;
      confirmed = true;
      Serial.print("Mode selected via Serial: ");
      Serial.println(modeSelected);
      displayModeSelection(serialInput);
    } else {
      Serial.println("Invalid input. Please enter a value between 0 and 2");      // displays this. Maybe add a stop motors
      
    }
  }
  // Execute the selected mode
  if (confirmed && modeSelected != lastMode) {
    lastMode = modeSelected;
    executeMode(modeSelected);
  }
}

void updateDisplay(int pos) {
  display.clearDisplay();
  display.setTextSize(1);

  display.setCursor(28, 4);
  display.print(F("Camera Slider"));

  display.setCursor(25, 20);
  if (pos == 0) {
    display.print(F("> "));
  } else {
    display.print(F("  "));
  }
  display.print(F("Pan"));

  display.setCursor(25, 30);
  if (pos == 1) {
    display.print(F("> "));
  } else {
    display.print(F("  "));
  }
  display.print(F("Rotate"));

  display.setCursor(25, 40);
  if (pos == 2) {
    display.print(F("> "));
  } else {
    display.print(F("  "));
  }
  display.print(F("Pan & Rotate"));

  display.display();
}

const char* getModeName(int pos) {
  switch (pos) {
    case 0: return "Pan";
    case 1: return "Rotate";
    case 2: return "Pan & Rotate";
    default: return "";
  }
}

void displayModeSelection(int mode) {
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(10, 30);
  display.print(F("Mode selected: \n"));
  display.print(getModeName(mode));
  display.display();
}

void executeMode(int mode) {
  switch (mode) {
    case 0:
      runPan();
      break;
    case 1:
      runRotate();
      break;
    case 2:
      runPanAndRotate();
      break;
  }
}

// Function to get user input for travel distance
float inputPanData() {

  // works but randomly chooses 0mm as distance
  // user needs to type distance really fast 

  int startTime = millis();
  int duration = 5000;

  // Wait for user input
  while (true) {
    int pause = millis(); 
    if (pause - startTime >= duration){
      Serial.println("Took too long to respond");
      break; 
    } 
    if (Serial.available()){
      break; 
    }
  }

  delay(500);
  // Serial.println("Enter travel distance: ");      // Doesnt work with simulator

  delay(50);  // Small delay to ensure input is processed
  float currentDist = Serial.parseFloat();
  delay(5000);  // Reduced delay
  
  return currentDist; 
}

float inputRotData(){
  // works but randomly chooses 0mm as distance
  // user needs to type distance really fast 

  int startTime = millis();
  int duration = 5000;

  // Wait for user input
  while (true) {
    int pause = millis(); 
    if (pause - startTime >= duration){
      Serial.println("Took too long to respond");
      break; 
    } 
    if (Serial.available()){
      break; 
    }
  }

  delay(500);
  

  delay(50);  // Small delay to ensure input is processed
  float currentDist = Serial.parseFloat();
  delay(5000);  // Reduced delay
  
  return currentDist; 

}


// Main function to run the pan operation
void runPan() {

  //inputPanData();
  Serial.println("Enter travel distance: ");      // Doesnt work with simulator
  float value = inputPanData(); 

  delay(2000);

  float travP = value*pulsesPerMM;

  Serial.print("Travel Pulses: ");
  Serial.print(travP);
  Serial.println("mm");

  delay(500);

  digitalWrite(travDirPin, HIGH);         // Sets Direction High = clockwise LOW = Counter Clockwise
  for(int i = 0; i < travP; i++) {  // Pulses the motor to move the required distance in the required time
    digitalWrite(travStepPin, HIGH);
    delay(50);                          // Wait to 
    digitalWrite(travStepPin, LOW);
    delay(100);    
  }

}

void runRotate() {
  // Code to run Rotate mode
  Serial.println("Running Rotate");
}

void runPanAndRotate() {
  // Code to run Pan & Rotate mode
  Serial.println("Running Pan and Rotate");
}
$abcdeabcde151015202530fghijfghij
A4988
A4988