#include<Adafruit_GFX.h>
#include <SPI.h>
#include <Adafruit_ILI9341.h>
#define tftDC 49
#define tftCS 53
#define sygnal A0

#define BLACK    0x0000
#define BLUE     0x001F
#define RED      0xF800
#define GREEN    0x07E0
#define CYAN     0x07FF
#define MAGENTA  0xF81F
#define YELLOW   0xFFE0 
#define WHITE    0xFFFF

const double Pi = 3.14;

Adafruit_ILI9341 tft = Adafruit_ILI9341(tftCS, tftDC);

double nachyleniePoprzednie = 0;
int length;
int triangleWidth;
int triangleHeight;
int initialX;
int initialY;
double endXX;
double endYY;
double X1;
double Y1;
int endX;
int endY;
int X11;
int Y11;
int triangleX;
int triangleY;
double triangleXX;
double triangleYY;
unsigned long time;
unsigned long frameTime;
double pointerRadian = 0.00;
int maxCisnieniePsi = 500;                         //psi
int minCisnienie = 0;                           //psi
double maxCisnienie = 34.47; //psi na bary, ze względu na rozdzielczosc do dwoch miejsc po przecinku z zaokrągleniem
double odczytMinimalny = 1023 / 5 * 0.50;   //najmniejszy odczyt z czujnika - 0.5V, wartosc dodana aby program nie wariował kiedy będzie na granicy
double odczytMaksymalny = 1023 / 5 * 4.50;  // analogicznie jak wyżej
double prog = 5;
double cisnienie;
double cisnieniePoprzednie = maxCisnienie + 1;
bool alarm = 0;
bool alarM = 0;
int barWidth;
int kolor = WHITE;
int poprzedniKolor = 0;
int controlRadius;
void setup() {
  Serial.begin(9600);
  tft.begin();
  tft.setRotation(3);
  Serial.begin(9600);

  triangleWidth = 30;
  triangleHeight = 30;
  barWidth = 20;
  controlRadius = 100;
  length = tft.width() / 2 - barWidth;  // długość wskazówki
  initialX = tft.width() / 2;
  initialY = tft.height() - 10;
  screenSetUp();
  cisnienie = analogRead(sygnal);
}

void loop() {
  cisnienie = analogRead(sygnal);
  if((cisnienie < odczytMinimalny - prog) || (cisnienie > odczytMaksymalny + prog)) {
    if(alarm == 0)
    {
    alarmScreen();
    alarM = 1;
    alarm = 1;
    }
  }
  if((cisnienie >= odczytMinimalny) && (cisnienie <= odczytMaksymalny)) {
    if(alarm == 1)
    {
      screenSetUp();
      cisnieniePoprzednie = maxCisnienie + 1;
      poprzedniKolor = kolor +1;
      alarm = 0;
      alarM = 0;
    }
  }
  if(alarM == 0)
  {
  cisnienie = maxCisnienie / (1023 - odczytMinimalny - (1023 - odczytMaksymalny)) * (cisnienie - odczytMinimalny); //konwertowanie odczytu z adc na wartosc cisnienia
  //cisnienie = 15;
  double nachylenie = (cisnienie / 30) * Pi;
  displayPressure(cisnienie);
  movePointer(nachylenie);
  }
}
void setScreen(double radian) {

  //tft.drawLine(initialX, initialY, triangleX, triangleY, BLACK);
  tft.fillTriangle(triangleX - X11, triangleY - Y11, triangleX + X11, triangleY + Y11, endX, endY, BLACK);
  double sinus = sin(radian);
  double cosinus = cos(radian);
  endXX = length * cosinus;
  endYY = length * sinus;

  triangleXX = (length - triangleHeight) * cosinus;
  triangleYY = (length - triangleHeight) * sinus;
  triangleX = initialX - triangleXX + 0.5;
  triangleY = initialY - triangleYY + 0.5;
  X1 = (triangleWidth / 2) * cos(radian - Pi / 2);
  Y1 = (triangleWidth / 2) * sin(radian - Pi / 2);
  endX = initialX - endXX + 0.5;
  endY = initialY - endYY + 0.5;
  X11 = X1 + 0.5;
  Y11 = Y1 + 0.5;

  //tft.drawLine(initialX, initialY, triangleX, triangleY, WHITE);

  
  if(cisnienie >= 10)
  {
    kolor = YELLOW;
  }
  if(cisnienie >= 15)
  {
    kolor = RED;
  }
  if(cisnienie < 10)
  {
    kolor = GREEN;
  }
  if(kolor != poprzedniKolor)
  {
    tft.fillCircle(initialX, initialY, controlRadius, kolor);
    poprzedniKolor = kolor;
  }
  tft.fillTriangle(triangleX - X11, triangleY - Y11, triangleX + X11, triangleY + Y11, endX, endY, kolor);
}

void screenSetUp() {
  setScreen(0.00);
  tft.fillScreen(WHITE);

  tft.fillTriangle(initialX + 40, tft.height(), 0, initialY, 0, 0, GREEN);
  tft.fillTriangle(initialX + 40, tft.height(),  0, 0, initialX, 0, YELLOW);
  tft.fillTriangle(initialX, tft.height(), initialX, 0, tft.width(), 0, RED);
  tft.fillTriangle(initialX, tft.height(), tft.width(), 0, tft.width(), tft.height(), RED);
  tft.fillCircle(initialX, initialY, length, BLACK);
  tft.fillRect(0, initialY, tft.width(), tft.height() - initialY, BLACK);
  //tft.fillRect(initialX - 2, 0, 4, tft.height(), BLACK);

  for (int i = 0; i <= tft.width() / 2; i++) {
    int mylength = length + barWidth;
    int myX = initialX - i;
    double y = sqrt((mylength * mylength) - (myX * myX));
    int yy = y + 0.5;
    int myendY = yy + (tft.height() - initialY);
    tft.drawLine(i, 0, i, tft.height() - myendY, BLACK);
    tft.drawLine(tft.width() - i, 0, tft.width() - i, tft.height() - myendY, BLACK);
  }
  tft.setCursor(tft.width()/2, 10);
  tft.setTextSize(4);
  tft.print("/");
  tft.print(30);
  //tft.setCursor(tft.width()/2, 41);
  tft.print("bar");

  pointerRadian = 0.00;
  setScreen(pointerRadian);
}

void movePointer(double radian) {

  double x = abs(radian - pointerRadian);
  double speed = 1 / (x + 0.1);

  if (((unsigned long)(millis() - time) > speed) && (abs(radian - pointerRadian) >= 0.02)) {

    if (pointerRadian > radian) {
      pointerRadian -= 0.02;
    }
    if (pointerRadian < radian) {
      pointerRadian += 0.02;
    }
    setScreen(pointerRadian);
    time = millis();
  }
}

void alarmScreen() {
  tft.fillScreen(RED);
  tft.setTextSize(6);
  tft.setTextColor(WHITE);
  tft.setCursor(0, tft.height() / 3);
  tft.println("AWARIA");
  tft.print("CZUJNIKA");
}

void displayPressure(double cisnienie) {
  if (abs(cisnienie - cisnieniePoprzednie) > 0.34) {

    tft.fillRect(0, 0, tft.width()/2, tft.height() - (tft.height() - initialY) - length - barWidth, BLACK);
    tft.setCursor(10, 10);
    tft.setTextColor(WHITE);
    tft.setTextSize(4);
    tft.print(cisnienie);
    cisnieniePoprzednie = cisnienie;
  }
}