#define CLK_PIN 15
#define DT_PIN 4
#define LED_PIN 13

const float WHEEL_CIRCUMFERENCE = 2.0; // Wheel circumference in meters
const unsigned long INACTIVITY_TIMEOUT = 2000; // Inactivity timeout before turning off the LED (in milliseconds)

const float MAX_SPEED_KMH = 20; // Maximum speed in kilometers per hour
const float SPEED_OVER_LIMIT = 20.0; // Speed over limit in kilometers per hour

volatile unsigned long lastMillis = 0;
volatile unsigned long interval = 0;
volatile unsigned long lastInterruptTime = 0;
volatile unsigned long currentMillis = 0;
volatile float rps = 0;
float maxRPS; // Allowed revolutions per second
float limitRPS; // Allowed revolutions per second with additional speed
unsigned long lastChangeTime = 0; // Time of the last change in speed

void IRAM_ATTR handleEncoder() 
{
  currentMillis = millis();
  if (currentMillis - lastInterruptTime > 1000) { // Every second
    interval = currentMillis - lastMillis;
    lastMillis = currentMillis;
    rps = 1000.0 / interval; // Calculate RPS
    lastInterruptTime = currentMillis;
    lastChangeTime = currentMillis; // Update the last change time
  }
}

void setup() 
{
  Serial.begin(115200);
  
  pinMode(CLK_PIN, INPUT);
  pinMode(DT_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);

  // Calculate the maximum allowed RPS
  float rpm = (MAX_SPEED_KMH * 1000.0) / (WHEEL_CIRCUMFERENCE * 60.0); // RPM
  maxRPS = rpm / 60.0; // RPS

  // Calculate the RPS limit with additional speed
  float rpmOverLimit = ((MAX_SPEED_KMH + SPEED_OVER_LIMIT) * 1000.0) / (WHEEL_CIRCUMFERENCE * 60.0); // RPM
  limitRPS = rpmOverLimit / 60.0; // RPS

  // Print the allowed RPS values
  Serial.print("Max allowed RPS is set to: ");
  Serial.println(maxRPS);
  Serial.print("RPS limit with 20 km/h over speed is set to: ");
  Serial.println(limitRPS);
  
  attachInterrupt(digitalPinToInterrupt(CLK_PIN), handleEncoder, RISING);
}

void loop()
{
  currentMillis = millis();

  // Check if there has been no change in speed in the last second
  if ((currentMillis - lastChangeTime) > INACTIVITY_TIMEOUT) 
     digitalWrite(LED_PIN, LOW); // Turn off the LED if no change
  else if (rps > maxRPS) { // Condition for high speed
        digitalWrite(LED_PIN, HIGH); // Turn on the LED
    if (rps > limitRPS) // Condition for exceeding the limit by 20 km/h
      Serial.println("Speed exceeds the limit by 20 km/h!");
  } else {
    digitalWrite(LED_PIN, LOW); // Turn off the LED
  }
  
  delay(100); // Short delay before the next check
}