#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#define TFT_DC 9
#define TFT_CS 10
#define TFT_RST 8
#define TFT_MOSI 11
#define TFT_SCK 13
#define TFT_MISO 12
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCK, TFT_MISO,TFT_RST);

#include <EEPROM.h>
#include <OneWire.h>
#include <DallasTemperature.h>
OneWire oneWire(4);
DallasTemperature sensor(&oneWire);

//void(*resetFunc)(void)=0;

const int buttonPin1 = 5;

const int buttonPin2 = 3;

const int fuel = A1;

const int GearSwitch = A0;
int sensorValue = 0;        
String Gear = "N"; 
void readSwitch () {                                  
  sensorValue = analogRead(GearSwitch); 
  sensorValue = map(sensorValue, 0, 1023, 0, 500);              
  if (sensorValue < 10 && sensorValue >= 0) {       
    Gear = "N";
    delay(100);                                       
  }
  if (sensorValue < 191 && sensorValue > 173) {       
    Gear = "D1";
    delay(100);                                      
  }
  if (sensorValue < 326 && sensorValue > 295) {       
    Gear = "D2";
    delay(100);      
  }
  if (sensorValue < 424 && sensorValue > 384) {        
    Gear = "D3";
    delay(100);                                       
  }
  if (sensorValue < 500 && sensorValue > 452) {        
    Gear = "D4";
    delay(100);                                       
  }
  delay(1);                                          
}



const int hallPin = 2; // Hall effect sensor connected to pin 2

// Constants
const unsigned long interval = 1000; // Interval to calculate speed (1 second)
const float wheelCircumference = 1.8; // Wheel circumference in meters (adjust based on your bike)
const int distanceEEPROMAddress = 0; // EEPROM address to store distance

// Variables
volatile unsigned long pulseCount = 0;
unsigned long previousMillis = 0;
float speed = 0.0;
float distance = 0.0;
float lastSavedDistance = 0.0;




void setup() {
  Serial.begin(115200);
  delay(2);
  sensor.begin();
  delay(20);

  pinMode(buttonPin1,INPUT_PULLUP);
  pinMode(buttonPin2,INPUT_PULLUP); 
  pinMode(GearSwitch, INPUT);
  pinMode(hallPin, INPUT_PULLUP); 

  //screen setting
  tft.begin();
  tft.setRotation(3);
  tft.fillScreen(tft.color565(149,142,105));

  //Bike start
  tft.setCursor(100,5);
  tft.setTextColor(tft.color565(255, 192, 0)); 
  tft.setTextSize(2);
  tft.println("BIKE START");
 

  //draw center brown box
  tft.drawRect(70,25,180,210,tft.color565(255,255, 255));
  tft.fillRect(70,25,180,210,tft.color565(102, 62, 17));


  //for Fuel box
  tft.drawRect(10,5,50,130,tft.color565(0, 0, 255));
  tft.fillRect(10,5,50,130,tft.color565(170, 230, 238));
  tft.setCursor(13,17);
  tft.setTextColor(tft.color565(0, 0, 0)); 
  tft.setTextSize(2);
  tft.println("Fuel"); 
 

  Display_Menu();  // Draw Start menu on screen

  attachInterrupt(digitalPinToInterrupt(hallPin), countPulse, FALLING);

  loadDistanceFromEEPROM();
}








void loop(void) {
  //Display Brake system
  int digitalVal1 = digitalRead(buttonPin1);
  if(digitalVal1 == HIGH)
  {
  //Serial.println("brake is proper working");
  //delay(1000);
  //tft.drawRect(5,150,60,80,tft.color565(0, 0, 255));
  tft.fillRect(5,150,60,80,tft.color565(149,142,105));
  tft.setCursor(15,170);
  tft.setTextColor(tft.color565(0, 0, 0)); 
  tft.setTextSize(1);
  tft.println("Change");
  tft.setCursor(6,185);
  tft.setTextColor(tft.color565(255, 192, 0)); 
  tft.setTextSize(2);
  tft.println("Brake");
  tft.println(" Shoe");   
  }
  else
  {
  //Serial.println("brake is not proper working");
  //delay(1000);
  tft.drawRect(5,150,60,80,tft.color565(0, 0, 255));
  tft.fillRect(5,150,60,80,tft.color565(255, 0, 0));
  tft.setCursor(15,170);
  tft.setTextColor(tft.color565(0, 0, 0)); 
  tft.setTextSize(1);
  tft.println("Change");
  tft.setCursor(6,185);
  tft.setTextColor(tft.color565(255, 255, 255)); 
  tft.setTextSize(2);
  tft.println("Brake");
  tft.println(" Shoe"); 
  }
  



  //Display side stand system
  int digitalVal2 = digitalRead(buttonPin2);
  if(digitalVal2 == HIGH)
  {
  //Serial.println("side stand lifted");
  //delay(1000);  
  //tft.drawRect(255,150,60,80,tft.color565(0, 0, 255));
  tft.fillRect(255,150,60,80,tft.color565(149,142,105));
  tft.setCursor(250,170);
  tft.setTextColor(tft.color565(255, 192, 0)); 
  tft.setTextSize(2);
  tft.println(" Side");
  tft.setCursor(256,185);
  tft.println("Stand");
  tft.setCursor(270,205);
  tft.setTextColor(tft.color565(0, 0, 0)); 
  tft.setTextSize(1);
  tft.println("Alert");
  }
  else
  {
  //Serial.println("side stand is not lifted");
  //delay(1000);
  tft.drawRect(255,150,60,80,tft.color565(0, 0, 255));
  tft.fillRect(255,150,60,80,tft.color565(255, 0, 0));
  tft.setCursor(250,170);
  tft.setTextColor(tft.color565(255, 255, 255)); 
  tft.setTextSize(2);
  tft.println(" Side");
  tft.setCursor(256,185);
  tft.println("Stand");
  tft.setCursor(270,205);
  tft.setTextColor(tft.color565(0, 0, 0)); 
  tft.setTextSize(1);
  tft.println("Alert");
  }




  //Temperature Measurement system
  sensor.requestTemperatures();
  //Serial.print("Temerature:");
  //Serial.println(sensor.getTempCByIndex(0));
  //delay(1000);
  tft.drawRect(255,5,60,100,tft.color565(0, 0, 255));
  tft.fillRect(255,5,60,100,tft.color565(170, 230, 238));
  tft.setCursor(260,15);
  tft.setTextColor(tft.color565(0, 0, 0)); 
  tft.setTextSize(2);
  tft.println("Temp");
  tft.setCursor(256,45);
  tft.setTextColor(tft.color565(255, 192, 0)); 
  tft.setTextSize(3);
  tft.println(round(sensor.getTempCByIndex(0)));
  tft.setCursor(256,70);
  tft.println(" C");




  // //Distance parameter
  // tft.drawRect(75,30,170,60,tft.color565(0, 0, 0));
  // tft.fillRect(75,30,170,60,tft.color565(170, 230, 238));
  // tft.setCursor(80,55);
  // tft.setTextColor(tft.color565(0, 0, 0)); 
  // tft.setTextSize(1.5);
  // tft.print("Distance:");
  // tft.setCursor(135,60);
  // tft.setTextColor(tft.color565(255, 192, 0)); 
  // tft.setTextSize(2);
  // tft.print("1000000");
  // tft.print("km");




  // //speed parameter
  // tft.drawRect(75,100,170,60,tft.color565(0, 0, 0));
  // tft.fillRect(75,100,170,60,tft.color565(170, 230, 238));
  // tft.setCursor(80,125);
  // tft.setTextColor(tft.color565(0, 0, 0)); 
  // tft.setTextSize(2);
  // tft.print("Speed:");
  // tft.setCursor(155,120);
  // tft.setTextColor(tft.color565(8, 143, 143)); 
  // tft.setTextSize(3);
  // tft.print("120");
  // tft.setCursor(210,130);
  // tft.setTextColor(tft.color565(8, 143, 143)); 
  // tft.setTextSize(1);
  // tft.print("km/h");
  

  

  
  //gear parameter
  delay (100);
  readSwitch();
  //Serial.print("Value = ");
  //Serial.print(sensorValue);
  //Serial.print("   Gear = ");
  //Serial.println(Gear);
  tft.drawRect(75,170,170,60,tft.color565(0, 0, 0));
  tft.fillRect(75,170,170,60,tft.color565(170, 230, 238));
  tft.setCursor(80,190);
  tft.setTextColor(tft.color565(0, 0, 0)); 
  tft.setTextSize(2);
  tft.print("Gear:");
  tft.setCursor(150,180);
  tft.setTextColor(tft.color565(2, 255, 32)); 
  tft.setTextSize(5);
  tft.print(Gear);
 

 // Print the sensor value and the stored value
  // Serial.print("Sensor Value: ");
  // Serial.println(sensorValue);
  // Serial.print("Stored Value: ");
  // Serial.println(storedValue);

  // Wait for a second before taking another reading
  // delay(1000);





  //Fuel levels
  int fuelval = analogRead(fuel); 
  fuelval = map(fuelval, 0, 1023, 0, 100); 
  //Serial.print("Fuel:");
  //Serial.println(fuelval);
  //delay(1000);
  if(fuelval==0){
  tft.drawRect(15,115,40,10,tft.color565(0, 0, 255));
  //tft.fillRect(15,115,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,98,40,10,tft.color565(0, 0, 255));
  //tft.fillRect(15,98,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,81,40,10,tft.color565(0, 0, 255));
  //tft.fillRect(15,81,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,64,40,10,tft.color565(0, 0, 255));
  //tft.fillRect(15,64,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,47,40,10,tft.color565(0, 0, 255));
  //tft.fillRect(15,47,40,10,tft.color565(178, 214, 49));
  }
  else if(fuelval>0 && fuelval<=20){
  tft.drawRect(15,115,40,10,tft.color565(0, 0, 255));
  tft.fillRect(15,115,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,98,40,10,tft.color565(0, 0, 255));
  //tft.fillRect(15,98,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,81,40,10,tft.color565(0, 0, 255));
  //tft.fillRect(15,81,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,64,40,10,tft.color565(0, 0, 255));
  //tft.fillRect(15,64,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,47,40,10,tft.color565(0, 0, 255));
  //tft.fillRect(15,47,40,10,tft.color565(178, 214, 49));
  }
  else if(fuelval>20 && fuelval<=40){
  tft.drawRect(15,115,40,10,tft.color565(0, 0, 255));
  tft.fillRect(15,115,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,98,40,10,tft.color565(0, 0, 255));
  tft.fillRect(15,98,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,81,40,10,tft.color565(0, 0, 255));
  //tft.fillRect(15,81,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,64,40,10,tft.color565(0, 0, 255));
  //tft.fillRect(15,64,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,47,40,10,tft.color565(0, 0, 255));
  //tft.fillRect(15,47,40,10,tft.color565(178, 214, 49));
  }
  else if(fuelval>40 && fuelval<=60){
  tft.drawRect(15,115,40,10,tft.color565(0, 0, 255));
  tft.fillRect(15,115,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,98,40,10,tft.color565(0, 0, 255));
  tft.fillRect(15,98,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,81,40,10,tft.color565(0, 0, 255));
  tft.fillRect(15,81,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,64,40,10,tft.color565(0, 0, 255));
  //tft.fillRect(15,64,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,47,40,10,tft.color565(0, 0, 255));
  //tft.fillRect(15,47,40,10,tft.color565(178, 214, 49));
  }
  else if(fuelval>60 && fuelval<=80){
  tft.drawRect(15,115,40,10,tft.color565(0, 0, 255));
  tft.fillRect(15,115,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,98,40,10,tft.color565(0, 0, 255));
  tft.fillRect(15,98,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,81,40,10,tft.color565(0, 0, 255));
  tft.fillRect(15,81,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,64,40,10,tft.color565(0, 0, 255));
  tft.fillRect(15,64,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,47,40,10,tft.color565(0, 0, 255));
  //tft.fillRect(15,47,40,10,tft.color565(178, 214, 49));
  }
  else if(fuelval>80 && fuelval<=100){
  tft.drawRect(15,115,40,10,tft.color565(0, 0, 255));
  tft.fillRect(15,115,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,98,40,10,tft.color565(0, 0, 255));
  tft.fillRect(15,98,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,81,40,10,tft.color565(0, 0, 255));
  tft.fillRect(15,81,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,64,40,10,tft.color565(0, 0, 255));
  tft.fillRect(15,64,40,10,tft.color565(178, 214, 49));
  tft.drawRect(15,47,40,10,tft.color565(0, 0, 255));
  tft.fillRect(15,47,40,10,tft.color565(178, 214, 49));
  }
//resetFunc();
  unsigned long currentMillis = millis();
  
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    calculateSpeed();
    updateDistance();

    // Print the speed and distance
    // Serial.print("Speed: ");
    // Serial.print(speed);
    // Serial.println(" km/h");

    // Serial.print("Distance: ");
    // Serial.print(distance);
    // Serial.println(" km");
    
    //Print Speed
    ShowSpeed();

    //Print Distance
    ShowMileage();
  }

}

void Display_Menu (void) {
  // tft.fillScreen(tft.color565(149,142,105));
 
  // //========= Main windows ==========
  // tft.drawRect(123, 35, 234, 273, tft.color565(255, 255, 255));
  
  //========== Distance Window ========
  tft.fillRect(75,30,170,60,tft.color565(170, 230, 238));
  tft.setCursor(80,40);
  tft.setTextColor(tft.color565(0, 0, 0)); 
  tft.setTextSize(2);
  tft.print("Distance:");  
  tft.setCursor(220,60);
  tft.setTextSize(2);
  tft.setTextColor(tft.color565(0, 0, 0));
  tft.print("km");  
  
  //========= Speed Window ========
  tft.fillRect(75,100,170,60,tft.color565(170, 230, 238));
  tft.setCursor(80,110);
  tft.setTextColor(tft.color565(0, 0, 0)); 
  tft.setTextSize(2);
  tft.print("Speed:");
  tft.setCursor(210,135);
  tft.setTextColor(tft.color565(0, 0, 0)); 
  tft.setTextSize(1.5);
  tft.print("km/h");
}

//============= SHOW SPEED ========================
void ShowSpeed() {
  char buf_speed[9];
  dtostrf(speed, 7, 2, buf_speed);
  tft.setCursor(80,130);
  tft.setTextSize(3);
  tft.setTextColor(tft.color565(255, 0, 0), tft.color565(0, 255, 255));  
  tft.print(buf_speed);
}

//============= SHOW DISTANCE ========================
void ShowMileage() {
  char buf_mileage[9];
  dtostrf(distance, 7, 2, buf_mileage);
  tft.setCursor(90,60);
  tft.setTextSize(3);
  tft.setTextColor(tft.color565(255, 0, 0), tft.color565(0, 255, 255));  
  tft.print(buf_mileage);
}

void countPulse() {
  pulseCount++;
}

void loadDistanceFromEEPROM() {
  EEPROM.get(distanceEEPROMAddress, distance);
  if (isnan(distance)) {
    distance = 0.0;
  }
  lastSavedDistance = distance;
}

void calculateSpeed() {
  // Temporarily disable interrupts to avoid race conditions
  noInterrupts();
  
  float speedMps = (pulseCount * wheelCircumference) / (interval / 1000.0);
  speed = speedMps * 3.6;

  // Re-enable interrupts after calculation
  interrupts();
}

void updateDistance() {
  // Temporarily disable interrupts to avoid race conditions
  noInterrupts();
  
  distance += (pulseCount * wheelCircumference) / 1000.0;
  pulseCount = 0;

  // Re-enable interrupts after calculation
  interrupts();

  if (distance - lastSavedDistance >= 1.0) {
    saveDistanceToEEPROM();
  }
}

void saveDistanceToEEPROM() {
  EEPROM.put(distanceEEPROMAddress, distance);
  lastSavedDistance = distance;
}