#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#define TFT_DC 9
#define TFT_CS 10
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

//--------------- I/O ----------------
int UpButton               = 2;
int DownButton             = 3;
int Led1 =4;
int SensorValue            = A0;
//------------------------------------

//=============== Gauge =============
int GaugeCenter_Y         = 100; 
int GaugeStartPoint       = 150;
int GaugeOffSet           = 0;
float GaugeRange          = 0.2346;             // 250(Deg) / 1023(Bit)
float GaugeMaxPSI         = 0;
float GaugeMinPSI         = 0;
float PSI                 = 0.0782;             // 80(Max Pressuer) / 1023(Bits)
//===================================

float angle2, angle3;                       
float X1, X2, X3, X4, X5;
float Y1, Y2, Y3, Y4, Y5;                  
float oX1, oX2, oX3;               
float oY1, oY2, oY3;      
float Rad                 = 0;

int ScanCycle             = 50;                 //Program scan rate (50ms)
int TimerForMaxMin        = 4000 / ScanCycle;   //wait 5 sec to display Max Min
int MaxPSI                = 0;
int MinPSI                = 1023 * GaugeRange; // 
int NeedlePosition        = 0;
int NeedleAngle           = 0;
int count                 = 0;
int StepToMove            = 0;

// 320 x 240 
const int ScreenHeight      = 239;
const int ScreenLenght      = 319;
const int PlotScale         = 2; //Half Scale
const int PlotLenght        = 200;
const int PlotHeight        = 80 / PlotScale;
const float PlotRatio       = 0.078125;   // 80PSI scale devide by 1024 Bits
const int PlotScanRate      = 250;        // 0.5 Sec Scan Rate
const int PlotResalotion    = 2;          // Resalotion of scan

int MaxText_X_Position    = ScreenLenght - 50;
int MaxText_Y_Position    = 0;
int MinText_X_Position    = 0;
int MinText_Y_Position    = 0;
int GaugeCenter_X           = (ScreenLenght / 2); 
int PlotXLocation           = (ScreenLenght / 2) - (PlotLenght / 2);
int PlotYLocation           = (ScreenHeight - 4);
int GaugeRadis              = (ScreenHeight - PlotHeight) / 3;
int PlotX                   = 0;
int PlotY                   = 0;
int PlotY1                  = 0;
int PlotCounter             = 0;
int PlotOldValue            = 0;
int PlotValue               = 0;
int PlotScanCounter         = 0;
int PlotColor               = 0;





void setup() 
{
  pinMode(UpButton, INPUT);
  pinMode(DownButton, INPUT);
  pinMode(Led1, OUTPUT);
  tft.begin();
  tft.setRotation(45);
  Serial.begin(115200);

//------------ Drawing the smaller Lines ---------------------
  for (int Count = 0; Count < 251; Count = Count + 15)
    {
      Rad = (Count + GaugeStartPoint) / 57.29958; // 1 Rad = 57.2958 deg
      X1 = ((GaugeRadis + 10) * cos(Rad) + GaugeCenter_X);        
      Y1 = ((GaugeRadis + 10) * sin(Rad) + GaugeCenter_Y);
      tft.drawLine (GaugeCenter_X, GaugeCenter_Y, X1, Y1, ILI9341_WHITE); 
    }
  tft.fillCircle(GaugeCenter_X, GaugeCenter_Y, GaugeRadis - 10, ILI9341_BLACK);
//-----------------------------------------------------------
//----------------- Max and Min -----------------------------
  Call_Text_Display (ILI9341_RED, 2, MaxText_X_Position, MaxText_Y_Position, "max" );
  Call_Text_Display (ILI9341_RED, 2, MinText_X_Position, MinText_Y_Position, "min" );
  Call_Text_Display (ILI9341_WHITE, 2, 115, (GaugeCenter_Y + GaugeRadis), "Fuel psi" );
//-----------------------------------------------------------  
//---------------- Number on Gauge --------------------------       
  Call_Gauge_Text ( 0, (GaugeCenter_X -12), (GaugeCenter_Y - 9), 20, "0" );
  Call_Gauge_Text ( 30, (GaugeCenter_X -12), (GaugeCenter_Y - 7), 25, "10" );
  Call_Gauge_Text ( 60, (GaugeCenter_X - 20), (GaugeCenter_Y - 9), 19, "20" );
  Call_Gauge_Text ( 90, (GaugeCenter_X - 10), (GaugeCenter_Y - 12), 17, "30" );
  Call_Gauge_Text ( 120, (GaugeCenter_X - 9), (GaugeCenter_Y -17), 10, "40" );
  Call_Gauge_Text ( 150, (GaugeCenter_X - 7 ), (GaugeCenter_Y - 19), 10, "50" );
  Call_Gauge_Text ( 180, (GaugeCenter_X + 7), (GaugeCenter_Y - 9), 10, "60" );
  Call_Gauge_Text ( 210, (GaugeCenter_X + 7), (GaugeCenter_Y - 7), 10, "70" );
  Call_Gauge_Text ( 240, (GaugeCenter_X + 7), (GaugeCenter_Y - 5), 10, "80" );
//-----------------------------------------------------------

 Call_Gauge_Needle (0, (GaugeRadis * 0.9), GaugeCenter_X, GaugeCenter_Y, GaugeStartPoint, ILI9341_RED);

/*
for (int i=0; i<240;){ i=i+5;
Call_Gauge_Needle (i, (GaugeRadis * 0.9), GaugeCenter_X, GaugeCenter_Y, GaugeStartPoint, ILI9341_RED);
}
for (int i=240; i>0;){ i=i-5;
Call_Gauge_Needle (i, (GaugeRadis * 0.9), GaugeCenter_X, GaugeCenter_Y, GaugeStartPoint, ILI9341_RED);
}

delay(1000);
*/


//tft.fillCircle(GaugeCenter_X, GaugeCenter_Y, 9, ILI9341_RED);
//delay(5000);

}

void loop() 
{
  NeedleAngle = (analogRead(SensorValue) * GaugeRange);

Call_Plotting();

  if (NeedleAngle > NeedlePosition)  
    { 
      StepToMove = NeedleAngle - NeedlePosition;
      if (StepToMove > 10)  {count = 10;}   else {count = 1;}
    }

  if (NeedleAngle < NeedlePosition)  
    { 
      StepToMove = NeedlePosition - NeedleAngle;
      if (StepToMove > 10)  {count = -10;}  else {count = -1;}
    }

  if (NeedleAngle != NeedlePosition)
    {
      NeedlePosition = NeedlePosition + count;
      Call_Gauge_Needle (NeedlePosition, (GaugeRadis * 0.9), GaugeCenter_X, GaugeCenter_Y, GaugeStartPoint, ILI9341_RED);
      Call_Min_and_Max();
    }
//----- Delay timer for displaying the Max and Min PSI
  if (TimerForMaxMin > 0)     { TimerForMaxMin = TimerForMaxMin - 1; }
  else {digitalWrite(Led1,HIGH);} 

  delay(ScanCycle);

//tft.drawLine(0, 0, ScreenLenght, 0, ILI9341_RED);
//tft.drawLine(0, 0, 0, ScreenHeight, ILI9341_RED);
//tft.drawLine(0, ScreenHeight, ScreenLenght, ScreenHeight, ILI9341_RED);
//tft.drawLine(ScreenLenght, 0, ScreenLenght, ScreenHeight, ILI9341_RED);

//tft.drawLine(ScreenLenght / 2, 0, ScreenLenght / 2, ScreenHeight, ILI9341_RED);


 /* //testing center
tft.drawLine(22,0,22,255,ILI9341_BLUE);
tft.drawLine(297,0,297,255,ILI9341_BLUE);
  
tft.drawLine(0,0,0,319,ILI9341_WHITE);
tft.drawLine(319,0,319,239,ILI9341_RED);

tft.drawLine(0,0,319,0,ILI9341_YELLOW);
tft.drawLine(0,239,319,239,ILI9341_GREEN);

tft.drawLine(0,0,319,239,ILI9341_WHITE);
tft.drawLine(319,0,0,239,ILI9341_WHITE);

tft.drawLine(159,0,159,239,ILI9341_WHITE);

tft.drawLine(110,0,110,255,ILI9341_BLUE);
tft.drawLine(209,0,209,255,ILI9341_BLUE);
*/


}

//------------------ Subroutines ---------------------
void Call_Gauge_Needle (float angle, float radis, float centerPointx, float centerPointy, float StartPoint, int Color)
  { 
    Rad = (angle + StartPoint) / 57.29958; // 1 Rad = 57.2958 deg
    X1 = (radis * cos(Rad) + centerPointx);        
    Y1 = (radis * sin(Rad) + centerPointy);

    if (angle > 270)    { angle2 = angle - 90; }
    else                { angle2 = angle + 90; }

    Rad = (angle2 + StartPoint) / 57.29958;
    X2 = ((radis * 0.1) * cos(Rad) + centerPointx );        
    Y2 = ((radis * 0.1) * sin(Rad) + centerPointy );

    if (angle2 > 180)   { angle3 = angle2 - 180; }
    else                { angle3 = angle2 + 180; }

    Rad = (angle3 + StartPoint) / 57.29958;
    X3 = ((radis * 0.1) * cos(Rad) + centerPointx );        
    Y3 = ((radis * 0.1) * sin(Rad) + centerPointy );

// Clear needle on the way up
    Rad = (angle - 20 + StartPoint) / 57.29958;
    X5 = ((radis + 6) * cos(Rad) + centerPointx );        
    Y5 = ((radis + 6) * sin(Rad) + centerPointy );
    tft.fillTriangle(X5, Y5, X3, Y3, X1, Y1, ILI9341_BLACK);

// Clear needle on the way down
    Rad = (angle + 20 + StartPoint) / 57.29958;
    X5 = ((radis + 6) * cos(Rad) + centerPointx );        
    Y5 = ((radis + 6) * sin(Rad) + centerPointy );
    tft.fillTriangle(X5, Y5, X1, Y1, X2, Y2, ILI9341_BLACK);

    tft.fillTriangle(X1, Y1, X2, Y2, X3, Y3, Color);
    tft.fillCircle(GaugeCenter_X, GaugeCenter_Y, 13, ILI9341_WHITE);

    oX1 = X1; oY1 = Y1; 
    oX2 = X2; oY2 = Y2;
    oX3 = X3; oY3 = Y3;
  }

void Call_Text_Display (int COLOR, int SIZE, int X, int Y, char TEXT[] )
  {
    tft.setTextColor(COLOR);      tft.setTextSize(SIZE);
    tft.setCursor(X, Y);          tft.print(TEXT);
  }

void Call_Number_Display (int COLOR, int SIZE, int X, int Y, float TEXT )
  {
    tft.setTextColor(COLOR);      tft.setTextSize(SIZE);
    tft.setCursor(X, Y);          tft.print((float)TEXT,1);
  }

void Call_Gauge_Text (int Position, float centerPointx, float centerPointy, float StartPoint, char Text[])
  {
    Rad = (Position + GaugeStartPoint) / 57.29958; // 1 Rad = 57.2958 deg
    X1 = ((GaugeRadis + StartPoint) * cos(Rad) + centerPointx);        
    Y1 = ((GaugeRadis + StartPoint) * sin(Rad) + centerPointy);
    Call_Text_Display(ILI9341_WHITE, 2, X1, Y1, Text);
  }

void Call_Min_and_Max()
  {
    if (TimerForMaxMin < 1)
      {
        if (MaxPSI < NeedleAngle) {MaxPSI = NeedleAngle;}
        if (MinPSI > NeedleAngle) {MinPSI = NeedleAngle;}
        
        tft.fillRect(MaxText_X_Position, MaxText_Y_Position, 60, 15, ILI9341_BLACK);
        Call_Number_Display (ILI9341_RED, 2, MaxText_X_Position, MaxText_Y_Position, ((MaxPSI / GaugeRange)  * PSI));
        tft.fillRect(MinText_X_Position, MinText_Y_Position, 60, 15, ILI9341_BLACK);
        Call_Number_Display (ILI9341_RED, 2, MinText_X_Position, MinText_Y_Position, ((MinPSI / GaugeRange)  * PSI));
      }
  }




void Call_Plotting()
  {
    if (PlotScanCounter >= (PlotScanRate / ScanCycle))
      {
        if (PlotCounter > PlotLenght)  { PlotCounter = 0;  PlotColor = !PlotColor; }  
        PlotValue = (analogRead(SensorValue) * PlotRatio / PlotScale);
        tft.drawRect(PlotXLocation - 1, PlotYLocation + 3, PlotLenght + 5, - PlotHeight - 3, ILI9341_BLUE);
        PlotX = PlotXLocation + PlotCounter;        PlotY = - PlotHeight;
        tft.fillRect(PlotX, PlotYLocation, PlotResalotion, PlotY, ILI9341_BLACK); //Block to clear         
        if (PlotX > PlotXLocation)
          { 
            PlotX = PlotXLocation + PlotCounter;    PlotY = PlotYLocation - PlotOldValue;
            PlotY1 = PlotYLocation - PlotValue;
            if (PlotColor)          { tft.drawLine(PlotX - PlotResalotion , PlotY, PlotX, PlotY1, ILI9341_WHITE); }
            else                    { tft.drawLine(PlotX - PlotResalotion , PlotY, PlotX, PlotY1, ILI9341_RED); }
          }
        PlotCounter = PlotCounter +  PlotResalotion;
        PlotOldValue = PlotValue;
        PlotScanCounter = 0;
      }
    else {PlotScanCounter = PlotScanCounter + 1;}
  }
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
lcd1:VCC
lcd1:GND
lcd1:CS
lcd1:RST
lcd1:D/C
lcd1:MOSI
lcd1:SCK
lcd1:LED
lcd1:MISO
pot1:GND
pot1:SIG
pot1:VCC
led1:A
led1:C