// musicbox1.c
// for NerdKits with ATtiny26L
// mrobbins@mit.edu

// F_CPU defined for delay.c
#define F_CPU 8000000UL	// 8MHz

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <inttypes.h>
#include <stdlib.h>

#include "delay.h"
#include "lcd.h"

// PIN DEFINITIONS:
//
// PA0 -- temperature sensor analog input
// PA1 -- piezo buzzer
// PA4 -- LCD RS (pin 4)
// PA5 -- LCD E (pin 6)
// PA7 -- button (pullup high)
// PB3-6 -- LCD DB4-7 (pins 11-14)

void lcd_blank_line() {
  lcd_write_string(PSTR("                        "));
}

void lcd_quick_clear_and_home() {
    lcd_home();
    lcd_blank_line();
    lcd_line_two();
    lcd_blank_line();
    lcd_home();
}

void play_tone(uint16_t delay, uint8_t duration) {
  // delay is half-period in microseconds
  // duration is in 10ms increments
  
  // example: 440Hz --> delay=1136
  
  
  // duration = 2*delay * cycles (all in same units)
  // cycles = 10000 * duration / delay / 2
  // cycles = 100 * duration / (delay/50)
  uint16_t tmp = 100 * duration;
  uint16_t delaysm = delay / 50;
  uint16_t cycles = tmp / delaysm;
  
  while(cycles > 0) {
    PORTA |= (1<<PA1);
    delay_us(delay);
    PORTA &= ~(1<<PA1);
    delay_us(delay);
    cycles--;
  }
}

// define some notes
// Frequencies from http://www.phy.mtu.edu/~suits/notefreqs.html
// converted to half-periods (us) by calculating
// 	1000000/2/frequency
// where frequency is in Hz
#define D5 851
#define E5 758
#define Fsh5 675
#define G5 637
#define A5 568
#define B5 506
#define C6 477
#define D6 425
#define DUR 40

int main() {
  // internal RC oscillator calibration for 8MHz.
  OSCCAL = 176;

  // enable the piezo as output
  DDRA |= (1<<PA1);
  
  // enable internal pullup on PA7 (the button)
  PORTA |= (1<<PA7);

  // fire up the LCD
  lcd_init();
  lcd_home();

  // loop forever!
  while(1) {
    lcd_quick_clear_and_home();
    lcd_write_string(PSTR("Press to play a song..."));
  
    // wait for button press...
    while(PINA & (1<<PA7)) {
      // do nothing
    }
  
    lcd_quick_clear_and_home();
    lcd_write_string(PSTR("  Happy "));	play_tone(D5, DUR);
    lcd_write_string(PSTR("birth"));	play_tone(E5, DUR);
    lcd_write_string(PSTR("day "));	play_tone(D5, DUR);
    lcd_write_string(PSTR("to "));	play_tone(G5, DUR);
    lcd_write_string(PSTR("you "));	play_tone(Fsh5, 2*DUR);

    lcd_line_two();
    lcd_write_string(PSTR("  Happy "));	play_tone(D5, DUR);
    lcd_write_string(PSTR("birth"));	play_tone(E5, DUR);
    lcd_write_string(PSTR("day "));	play_tone(D5, DUR);
    lcd_write_string(PSTR("to "));	play_tone(A5, DUR);
    lcd_write_string(PSTR("you "));	play_tone(G5, 2*DUR);

    lcd_quick_clear_and_home();

    lcd_write_string(PSTR("Happy "));	play_tone(D5, DUR);
    lcd_write_string(PSTR("birth"));	play_tone(D6, DUR);
    lcd_write_string(PSTR("day "));	play_tone(B5, DUR);
    lcd_write_string(PSTR("dear "));	play_tone(G5, DUR);
    lcd_write_string(PSTR("__"));	play_tone(Fsh5, DUR);
    lcd_write_string(PSTR("__"));	play_tone(E5, DUR);
    
    lcd_line_two();
    lcd_write_string(PSTR(" Happy "));	play_tone(C6, DUR);
    lcd_write_string(PSTR("birth"));	play_tone(B5, DUR);
    lcd_write_string(PSTR("day "));	play_tone(G5, DUR);
    lcd_write_string(PSTR("to "));	play_tone(A5, DUR);
    lcd_write_string(PSTR("you! "));	play_tone(G5, 2*DUR);
  
    // delay a bit
    delay_ms(500);
  }
  
  return 0;
}
