/* -----------------------------------------------------------------------
 * Title:    Simple photoresistor-based motion detector
 * Author:   Sofian Audry (info@sofianaudry.com) and Samuel St-Aubin (samuel.st-aubin@sympatico.ca)
 * Date:     12.12.2007
 * Hardware: ATtiny13v
 * Software: WinAVR 20060421
 * -----------------------------------------------------------------------*/
 
#include <avr/io.h>
 
#define PIEZZO PB4                     // Define PIEZZO ext output pin on PB2

int i;                              // 8 bits integer

#define output_low(port,pin) port &= ~(1<<pin)
#define output_high(port,pin) port |= (1<<pin)
#define set_input(portdir,pin) portdir &= ~(1<<pin)
#define set_output(portdir,pin) portdir |= (1<<pin)
 
// this is just a program that 'kills time' in a calibrated method
void delay_ms(uint8_t ms) {
  uint16_t delay_count = F_CPU / 17500;
  volatile uint16_t i;
  
  while (ms != 0) {
    for (i=0; i != delay_count; i++);
    ms--;
  }
}
//void delay_ms(uint8_t ms) {
//  uint16_t delay_count = F_CPU / 17500;
//  volatile uint16_t i;
//  
//  while (ms != 0) {
//    for (i=0; i != delay_count; i++);
//    ms--;
//  }
//}

unsigned int analogRead() {
  unsigned int low, high;
  
  ADCSRA |= (1 << ADEN);          // Analog-Digital enable bit
  ADCSRA |= (1 << ADSC);          // Discard first conversion

  while (ADCSRA & (1 << ADSC));  // wait until conversion is done

  ADCSRA |= (1 << ADSC);         // start single conversion

  while (ADCSRA & (1 << ADSC))  // wait until conversion is done

  ADCSRA &= ~(1<<ADEN);             // shut down the ADC
  
  //----------Show ADCH Byte in PIEZZO variable brightness indicator---------
	low = ADCL;
  high = ADCH;
  
  return (high << 8) | low;
}

int value;
int last_value;

#define THRESHOLD 3

unsigned int motion() {
  int motion;
  value = analogRead();
  motion = value - last_value;
  if (motion < 0)
    motion = -motion;
  last_value = value;
  return (unsigned int) motion;
}

void analogInit() {
  // Analog read initialization.
  ADCSRA |= (1 << ADEN) |          // Analog-Digital enable bit
            (1 << ADPS1) |         // set prescaler to 8    (clock / 8)
            (1 << ADPS0);          // set prescaler to 8    (clock / 8)

  ADMUX |= // (1 << ADLAR) |         // AD result store in (more significant bit in ADCH)
            (1 << MUX1) | (1 << MUX0);           // Choose AD input ADC3 (BP 3)
}

#define TIME_STEP 100

void playSquare(unsigned int period, unsigned int times)
{
  period /= 2;
  while (times--) {
    output_high(PORTB, PIEZZO);
    delay_ms(period);
    output_low(PORTB, PIEZZO);
    delay_ms(period);
  }
}

int main(void)
{
  unsigned int m;
  analogInit();

  set_output(DDRB, PIEZZO);              // Set output direction on PIEZZO
    
  output_low(PORTB, PIEZZO);
  
  motion(); // call one time to initialize the values
  
  for (;;)
  {
      if (TIME_STEP)
        delay_ms(TIME_STEP);
      
      m = motion();
      if (m > THRESHOLD) {
        playSquare(10, 10);
      }
  }
  
  return 0;
}
