/*
 *  Copyright (c) 2008  Swedish Institute of Computer Science
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of the copyright holders nor the names of
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
/**
 * \file
 *
 * \brief
 *      This file implements a beep function to emit a beep sound from Raven's
 *      speaker. Also polyphonic ringtones.
 *
 * \author
 *      Mike Vidales mavida404@gmail.com
 *      David Kopf dak664@embarqmail.com
 *
 */


#include "beep.h"
#include "key.h"
#include <stdlib.h>
#include "util/delay.h"

/**
 *  \addtogroup lcd
 *  \{
*/
/*---------------------------------------------------------------------------*/

/**
 *  \brief Emits a beep from the Raven's buzzer.  This routine simply toggles a port pin
 *  at an audio frequency, which causes a tone to be emitted from the Raven's speaker.
 *  The beep consists of two tones at two different frequencies.  At the end, the beeper
 *  port pin is kept low, which causes the speaker amplifier to shut down.
*/
void
beep(void)
{
    uint8_t i;
    volatile uint8_t j;

    /* Turn on the power to the speaker. */
    ENTER_DDR |= (1 << PE7);
    ENTER_PUR |= (1 << PE7);

    /* Setup port pin */
    BEEP_DDR |= (1 << BEEP_BIT);

    for (i=0;i<100;i++){
        /* Toggle port pin */
        BEEP_PIN |= (1 << BEEP_BIT);
        /* Delay loop */
        for (j=0;j<0xff;j++)
            ;
    }

    for (i=0;i<100;i++){
        /* Toggle port pin */
        BEEP_PIN |= (1 << BEEP_BIT);
        /* Delay loop */
        for (j=0;j<0xa0;j++)
            ;
    }

    /* Turn off speaker */
    BEEP_PORT &= ~(1 << BEEP_BIT);
    ENTER_PUR &= ~(1 << PE7);
}

/*---------------------------------------------------------------------------*/
/**
 *  \brief Play polyphonic tune using buzzer.  An 8 bit timer generates interrupts
 *  that flip the BEEP pin at the selected frequencies.
 *  On exit the beeper port pin is set low to shut down the speaker amplifier.
*/
/* Base interrupts per second, and interrupts for each note */
//#define BASE 31250
#define BASE 31250/2  //up one octave
#define NONE 0
#define C4   BASE/262
#define CS4  BASE/277
#define D4   BASE/294
#define DS4  BASE/311
#define E4   BASE/330
#define F4   BASE/349
#define FS4  BASE/370
#define G4   BASE/392
#define GS4  BASE/415
#define A4   BASE/440
#define AS4  BASE/466
#define B4   BASE/494
#define C5   BASE/523
#define CS5  BASE/554
#define D5   BASE/587
#define DS5  BASE/622
#define E5   BASE/659
#define F5   BASE/698
#define FS5  BASE/740
#define G5   BASE/784
#define GS5  BASE/831
#define A5   BASE/880
#define AS5  BASE/932

/* Tone reference length and internote gap, milliseconds */
#define TONE_LENGTH 60
#define TONE_GAP    20


static uint8_t tuneindex=0;
static uint8_t pictures[] PROGMEM = {G4,4, F4,4, AS4,4, C5,2, F5,2, D5,4, C5,2, F5,2, D5,4, AS4,4, C5,4, G4,4, F4,4, 0xff};
static uint8_t     axel[] PROGMEM = {FS4,2, NONE,2, A4,3, FS4,2, FS4,1, B4,2, FS4,2, E4,2, FS4,2, NONE,2, CS5,3, FS4,2, FS4,1, D5,2, CS5,2, A4,2, FS4,2, CS5,2, FS5,2, FS4,1, E4,2, E4,1, CS4,2, GS4,2, FS4,6, 0xff};
static uint8_t sandman1[] PROGMEM = {F4,2, G4,2, B4,4, A4,10, B4,2, B4,2, A4,2, B4,12, 0xff};
static uint8_t sandman2[] PROGMEM = {C4,2, E4,2, G4,2, B4,2, A4,2, G4,2, E4,2, C4,2, D4,2, F4,2, A4,2, C5,2, B4,8, 0xff};
static uint8_t furelise[] PROGMEM = {E5,1, DS5,1, E5,1, DS5,1, E5,1, B4,1, D5,1, E5,1, A4,2, NONE,1, C4,1, E4,1, A4,1, B4,2, NONE,1, E4,1, GS4,1, B4,1, C5,2, 0xff};

static volatile uint8_t icnt,tone;

#include <avr/interrupt.h>
ISR(TIMER0_OVF_vect)
{
    if (tone == NONE) icnt = 0;
    else if (icnt++ >= tone)
    {
        BEEP_PIN |= (1 << BEEP_BIT);
        icnt = 0;
    }
}

void play_ringtone(void)
{
uint8_t i,*noteptr;

    /* What's next on the playlist? */
    switch (tuneindex++) {
    case 1 :beep();return;
    case 2 :noteptr=sandman1;break;
    case 3 :noteptr=furelise;break;
    case 4 :noteptr=sandman2;break;
    case 5 :noteptr=axel;break;
    default:noteptr=pictures;tuneindex=1;break;
    }
    
    /* Turn on the power to the speaker. */
    ENTER_DDR |= (1 << PE7);
    ENTER_PUR |= (1 << PE7);

    /* Setup port pin */
    BEEP_DDR |= (1 << BEEP_BIT);

    /* Start with no tone */
    icnt = 0;
    tone = NONE;
    
    /* Clock 8 bit timer at maximum frequency (CS0=1), interrupt overflow */
    /* 8MHz / 256 = 31250 interrupts per second */
    TCCR0A |= _BV(CS00);
    TCNT0 = 0;
    TIMSK0 |= _BV(TOIE0);

    /* Play all the notes */
    for (;;) {
        tone=pgm_read_byte(noteptr++);
        if (tone==0xff) break;
        for (i = pgm_read_byte(noteptr++);i > 0; i--) _delay_us(1000UL*TONE_LENGTH);
        tone = NONE;_delay_us(1000UL*TONE_GAP);
    }
    
    /* Turn off interrupts and speaker */
    TIMSK0 &= ~_BV(TOIE0);
    BEEP_PORT &= ~(1 << BEEP_BIT);
    ENTER_PUR &= ~(1 << PE7);
}
/** \}   */