// Title: proximity_mine.ino
// Author: DAD_Projects
// Date: November 22, 2023
// Description: proximity mine project for Arduino Nano controls 4 LEDs 
// and uses the tone library to generate sound for a passive beeper

// Ardunio Pin Definitions
#define LED0 10
#define LED1 9
#define LED2 6
#define LED3 5
#define MOTION 12
#define SOUND 4

// 4*start_up_beep_period milliseconds for BEEP-BEEP-BEEP-PAUSE
#define start_up_beep_period 250 // milliseconds
#define start_up_beep_on_time 125 // milliseconds
#define start_up_beep_frequency 4097 // Hz
#define num_cycles 3// How many BEEP-BEEP-BEEP-PAUSE cycles

// How long each LED is on during the inital start up cycle
#define start_up_led_period 60

// Parameters for flashing and beeping effect when motion is detected
#define beep_on_time 25 // milliseconds
#define beep_period 50 // milliseconds
#define beep_frequency 4097 // Hz
#define flash_half_period 50 // milliseconds

// Parameters for the strobing effect when no motion is detected
#define strobe_period 4000 // milliseconds

// Variables for proximity mine monitoring mode
unsigned int ramp_value=0;
unsigned int strobe_value=0;
unsigned long current_time = 0;
unsigned long beep_time = 0;
unsigned long previous_time = 0;
bool is_motion=false;

// Variables for proximity mine start up mode
unsigned long start_up_beep_time=0;
unsigned long start_up_led_time=0;
unsigned int beep_count=0;
byte LED_state=0;
unsigned int cycles_completed=0;


void setup() {
  pinMode(LED0, OUTPUT);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(MOTION, INPUT);
  pinMode(SOUND, OUTPUT);

  // Set the initial state of the LEDs
  digitalWrite(LED0, LOW);
  digitalWrite(LED1, LOW);
  digitalWrite(LED2, LOW);
  digitalWrite(LED3, LOW);
  LED_state=0;

  while(1) {
    // Get current time
    current_time = millis();

    // BEEP-BEEP-BEEP-PAUSE
    // Test the time interval for the beeping
    if (current_time-start_up_beep_time >= start_up_beep_period) 
    {
      if (beep_count>=3) 
      {
        beep_count=0;
        cycles_completed++;
        if (cycles_completed >= num_cycles)
          break;
      }
      else
      {
        tone(SOUND, start_up_beep_frequency, start_up_beep_on_time);
        beep_count++;
      }
      start_up_beep_time = current_time;
    }

    // If a beep sequence just started and the LEDs are in the all off state
    if (beep_count==1 && LED_state==0)
    {
      digitalWrite(LED0, HIGH);
      start_up_led_time = current_time;      
      LED_state=1;
      continue;
    }

  // Test the time interval for light changing after the initial sequence start
  // Lights rotate clockwise
  if (current_time-start_up_led_time >= start_up_led_period) 
  {
      switch(LED_state){
        case 1:
          digitalWrite(LED0, LOW);
          digitalWrite(LED1, HIGH);
          LED_state = 2;
          break;
        case 2:
          digitalWrite(LED1, LOW);
          digitalWrite(LED2, HIGH);
          LED_state = 3;
          break;
        case 3:
          digitalWrite(LED2, LOW);
          digitalWrite(LED3, HIGH);
          LED_state = 4;
          break;
        case 4:
          digitalWrite(LED3, LOW);
          digitalWrite(LED0, LOW);
          LED_state = 0;
          break;
        default:
          LED_state = 0;
          break;          
      }
      start_up_led_time = current_time;
    }
  }
}

void loop() {
  is_motion=digitalRead(MOTION);

  // Rapidly flash the LEDs and the beeper while there is motion
  if (is_motion) {  
    current_time = millis();
    if (current_time-previous_time>flash_half_period) {
      LED_state=~LED_state;
      previous_time=current_time;
      digitalWrite(LED0, LED_state);
      digitalWrite(LED1, LED_state);
      digitalWrite(LED2, LED_state);
      digitalWrite(LED3, LED_state);
    }
    if (current_time-beep_time >= beep_period) {
      tone(SOUND, beep_frequency, beep_on_time);
      beep_time = current_time;
    }
  }

  // Synchrnonous glow effect for the LEDs when no motion
  else {
    ramp_value = (millis()*512/strobe_period) % 512;
      
    if (ramp_value > 255)
      strobe_value = (511 - ramp_value)/10; //Divide by 10 to limit brightness
    else
      strobe_value = ramp_value/10;
    analogWrite(LED0, strobe_value);
    analogWrite(LED1, strobe_value);
    analogWrite(LED2, strobe_value);
    analogWrite(LED3, strobe_value);
  }  
}
