/**

Benjamin Roll
Spool Splitter Code
2/6/2023

**/

#include <Adafruit_GFX.h>    // Core graphics library
#include <SPI.h>       // this is needed for display
#include <Adafruit_ILI9341.h>
#include <Wire.h>      // this is needed for FT6206
// not for this board      #include <Adafruit_FT6206.h>
#include <Stepper.h>
#include <XPT2046_Touchscreen.h>
#include "pitches.h"

const int stepsPerRevolution = 200;  // number of steps per revolution
const int tStepsPerRev = 200;

// initialize the stepper library on pins 8 through 11:
Stepper spool(stepsPerRevolution, 27, 29, 31, 33);
Stepper traverse(tStepsPerRev, 26, 28, 30, 32);

long Number;                             // input desired length of wire
int stepCount = 0;                        // # of steps for the spool to take
int layerCount = 0;                       // counter for # of wire layers
int SRCount = 0;                          //
int tCount = 0;                           //
long spoolDia = 11;
long ratio = spoolDia/0.5;                 // drive ratio
long revCount = 0;                         // # of spool stepper revs
int steps = ratio*stepsPerRevolution;     // # of steps for 1 spool rotaion
long tSteps = 18.4;                        // # of steps traverse needs to move
long wireLength;                // desired wire length in inches
long reqRevs;   // # of revs to get needed wire length
int X=0;
int Y=0;
int stepperRPM = 200;
int brakeVal = 20;

bool butPress = false;
bool complete = false;
bool result = false;
bool entered = false;
bool startPressed = false;

#define TonePin 13
#define BrakePin 3

// The display/touchscreen also uses hardware SPI, plus CS=53, DC=48, MOSI=51, MISO=50, SCK=52
#define TFT_CS 53
#define TFT_DC 48
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// The XPT2046 uses hardware I2C (SCL/SDA)
#define CS_PIN 22
XPT2046_Touchscreen ts(CS_PIN);
//#define TIRQ_PIN  2
//XPT2046_Touchscreen ts(CS_PIN);  // Param 2 - NULL - No interrupts
//XPT2046_Touchscreen ts(CS_PIN, 255);  // Param 2 - 255 - No interrupts
//XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN);  // Param 2 - Touch IRQ Pin - interrupt enabled polling

#define FRAME_X 80
#define FRAME_Y 180
#define FRAME_W 100
#define FRAME_H 50

#define TS_MINX 365
#define TS_MINY 250
#define TS_MAXX 3850
#define TS_MAXY 3850

String symbol[4][3] = {

  { "7", "8", "9"},

  { "4", "5", "6",},

  { "1", "2", "3",},

  { "C", "0", "GO", }

};

int melody[] = {
  NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, 0, NOTE_B3, NOTE_C4
};

// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {
  4, 8, 8, 4, 4, 4, 4, 4
};

void setup(void) {
 //while (!Serial);     // used for leonardo debugging
  pinMode(BrakePin, OUTPUT);
/*  pinMode(5, OUTPUT);
  digitalWrite(5, HIGH);
    pinMode(6, OUTPUT);
  digitalWrite(6, HIGH);
  pinMode(7, OUTPUT);
  digitalWrite(7, HIGH);
  pinMode(8, OUTPUT);
  digitalWrite(8, HIGH);
  pinMode(9, OUTPUT);
  digitalWrite(9, HIGH);
    pinMode(37, OUTPUT);
  digitalWrite(37, HIGH);
    pinMode(35, OUTPUT);
  digitalWrite(35, HIGH);
    pinMode(33, OUTPUT);
  digitalWrite(33, HIGH);
    pinMode(31, OUTPUT);
  digitalWrite(31, HIGH);*/
  
  spool.setSpeed(stepperRPM);

  Serial.begin(38400);
  Serial.println(F("Cap Touch Paint!"));
  
  tft.begin();
  ts.begin();
  
  tft.setRotation(0);
  ts.setRotation(2);

  tft.fillScreen(ILI9341_BLACK);
  
  // Draw Start Button
  tft.fillRect(FRAME_X, FRAME_Y, FRAME_W, FRAME_H, ILI9341_GREEN);
  tft.setCursor(FRAME_X + 6 , FRAME_Y + (FRAME_H/2));
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(3);
  tft.println("START");    
  
  //Write PWM to brake pin
    analogWrite(BrakePin, brakeVal);
}

void loop() {
  while (complete==false){
    
  // Wait for a touch
  if (! ts.touched() && result==false) {
    return;
  }

  // Retrieve a point 
  delay (200); 
  TS_Point p = ts.getPoint();
  
/*
  // Print out raw data from screen touch controller
  Serial.print("X = "); Serial.print(p.x);
  Serial.print("\tY = "); Serial.print(p.y);
  Serial.print(" -> ");
 */

  // flip it around to match the screen.
  p.x = map(p.x, TS_MINX, TS_MAXX, 0, 240);

  p.y = map(p.y, TS_MINY, TS_MAXY, 0, 320);

  X=p.x;
  Y=p.y;
  

 // Print out the remapped (rotated) coordinates
  Serial.print("("); Serial.print(p.x);
  Serial.print(", "); Serial.print(p.y);
  Serial.println(")");
  
  if (startPressed == false){
    if ((p.y < (FRAME_Y + FRAME_H)) && (p.y > FRAME_Y)) {
      if ((p.x > FRAME_X) && (p.x < (FRAME_X + FRAME_W))){
        butPress = true;
        startPressed = true;
      }
    }
  }

  if(butPress == true){
    drawInput();
    butPress = false;
    return;
  
  }
  
  if(result == false && startPressed==true){
    DetectButtons();
    DisplayResult();
    return;
  }
  if(result==true){
    sSplit();
    return;
  }
  }
  splitComplete();

}

// Draw the input screen
void drawInput(){
  tft.fillScreen(ILI9341_BLACK);
  
  //Draw the Result Box
  tft.fillRect(0, 0, 240, 70, ILI9341_CYAN);

 //Draw First Column
  tft.fillRect  (0,260,80,65,ILI9341_RED);
  tft.fillRect  (0,200,80,65,ILI9341_BLACK);
  tft.fillRect  (0,140,80,65,ILI9341_BLACK);
  tft.fillRect  (0,80,80,65,ILI9341_BLACK);

 //Draw Second Column
  tft.fillRect  (80,260,80,65,ILI9341_BLACK);
  tft.fillRect  (80,200,80,65,ILI9341_BLACK);
  tft.fillRect  (80,140,80,65,ILI9341_BLACK);
  tft.fillRect  (80,80,80,65,ILI9341_BLACK);

 //Draw Third Column 
  tft.fillRect  (160,260,80,65,ILI9341_GREEN);
  tft.fillRect  (160,200,80,65,ILI9341_BLACK);
  tft.fillRect  (160,140,80,65,ILI9341_BLACK);
  tft.fillRect  (160,80,80,65,ILI9341_BLACK);

  //Draw Horizontal Lines
  for (int h=70; h<=320; h+=65)
  tft.drawFastHLine(0, h, 240, ILI9341_WHITE);

  //Draw Vertical Lines
  for (int v=0; v<=240; v+=80)
  tft.drawFastVLine(v, 80, 240, ILI9341_WHITE);

  //Display keypad lables
  for (int j=0;j<4;j++) {
    for (int i=0;i<3;i++) {
      tft.setCursor(22 + (80*i), 100 + (65*j));
      tft.setTextSize(3);
      tft.setTextColor(ILI9341_WHITE);
      tft.println(symbol[j][i]);
}
  }
  butPress = false;

  return butPress;
  }

void DetectButtons(){
  //Detecting Buttons on Column 1
  if (X<80 && X>0) {
    if (Y>255 && Y<320) //If cancel Button is pressed
    {
      Serial.println ("Button Cancel"); 
      Number=0; 
      result=false;
      Serial.println (Number);
    }

    if (Y>190 && Y<255) //If Button 1 is pressed
    {
      Serial.println ("Button 1"); 
      if (Number==0)
      Number=1;
      else
      Number = (Number*10) + 1; //Pressed twice
      Serial.println (Number);
    }

    if (Y>125 && Y<190) //If Button 4 is pressed
    {
      Serial.println ("Button 4"); 
      if (Number==0)
      Number=4;
      else
      Number = (Number*10) + 4; //Pressed twice
    Serial.println (Number);
    }

    if (Y>60 && Y<125) //If Button 7 is pressed
    {
      Serial.println ("Button 7");
      if (Number==0)
      Number=7;
      else
      Number = (Number*10) + 7; //Pressed twice
    Serial.println (Number);
    } 
  }
  //Detecting Buttons on Column 2
  if (X<160 && X>80) {
    if (Y>255 && Y<320)
    {
      Serial.println ("Button 0"); //Button 0 is Pressed
      if (Number==0)
      Number=0;
      else
      Number = (Number*10) + 0; //Pressed twice
    Serial.println (Number);
    }
    
    if (Y>190 && Y<255)
    {
      Serial.println ("Button 2"); 
      if (Number==0)
      Number=2;
      else
      Number = (Number*10) + 2; //Pressed twice
    Serial.println (Number);
    }

    if (Y>125 && Y<190)
    {
      Serial.println ("Button 5"); 
      if (Number==0)
      Number=5;
      else
      Number = (Number*10) + 5; //Pressed twice
    Serial.println (Number);
    }

    if (Y>60 && Y<125)
    {
      Serial.println ("Button 8"); 
      if (Number==0)
      Number=8;
      else
      Number = (Number*10) + 8; //Pressed twic
    Serial.println (Number);
    }   
  }

  //Detecting Buttons on Column 3
  if (X<240 && X>160) {
    if (Y>255 && Y<320)
    {Serial.println ("Button Equal"); 
    Number=Number;
    tone(13,NOTE_A3,1000/2);
    result = true;
    Serial.println (Number);
    }

    if (Y>190 && Y<255)
    {Serial.println ("Button 3"); 
      if (Number==0)
      Number=3;
      else
      Number = (Number*10) + 3; //Pressed twice
    Serial.println (Number);
    }

    if (Y>125 && Y<190)
    {Serial.println ("Button 6"); 
    if (Number==0)
      Number=6;
      else
      Number = (Number*10) + 6; //Pressed twice
    Serial.println (Number);
    }

    if (Y>60 && Y<125)
    {Serial.println ("Button 9");
    if (Number==0)
    Number=9;
    else
    Number = (Number*10) + 9; //Pressed twice
    Serial.println (Number);
    }   
    return result;
  }
}

void DisplayResult(){
    tft.fillRect(0, 0, 240, 80, ILI9341_CYAN);  //clear result box
    tft.setCursor(10, 20);
    tft.setTextSize(4);
    tft.setTextColor(ILI9341_BLACK);
    tft.println(Number); //update new value
}

//Spool split script
void sSplit(){

  wireLength = Number*12;
  reqRevs = wireLength/(2*PI*(spoolDia/2));
  Serial.print("number:");
  Serial.println(Number);
  Serial.print("wire length:");
  Serial.println(wireLength);
  Serial.print("Required Revs:");
  Serial.println(reqRevs);

  if(revCount < reqRevs){
  
  // step one step:
    spool.step(steps);
    Serial.print("spoolRev:");
    Serial.println(SRCount);
    SRCount++;
   revCount++;

    traverse.step(tSteps);
    Serial.print("steps:");
    Serial.println(tCount);
    tCount++;

      if (SRCount > 10){
          layerCount++;
          SRCount = 0;
          tSteps = -tSteps;
     }


    }else{
      Serial.print("COMPLETE");
      complete = true;
      return complete;
    
     }
}

void splitComplete(){
  tft.fillScreen(ILI9341_BLACK);
  
  // Draw Start Button
  tft.setCursor(20 , 160);
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(4);
  tft.println("COMPLETE!");
  //delay(500);
  
  playSong();
  for (int thisNote = 0; thisNote < 8; thisNote++) {

    // to calculate the note duration, take one second divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    int noteDuration = 1000 / noteDurations[thisNote];
    tone(TonePin, melody[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(TonePin);
  }

  return;
}

void playSong(){

  int size = sizeof(noteDurations) / sizeof(int);

  for (int thisNote = 0; thisNote < size; thisNote++) {

    // to calculate the note duration, take one second divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    int noteDuration = 1000 / noteDurations[thisNote];
    tone(TonePin, melody[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(TonePin);
  }
}