/******************************************************************************
文 件 名：Buzzer.c
功能描述：蜂鸣器驱动库文件
作    者：张暄
版    本：V1.0
日    期：2016.5.18
******************************************************************************/

#include "Buzzer.h"

#include "TimerB.h"

#include "Sound_Tracks.h"

#define BUZZER_PWM_CHANNEL TIMERB_0_CH11

BuzzerPlayCtrlStruct BuzzerPlayCtrl;

/******************************************************************************
函数名：Buzzer_Start_Up
功  能：启动并初始化蜂鸣器
        蜂鸣器PWM使用CLKSA/CLKSB时钟源,推荐的时钟源频率为50kHz~100kHz
参  数：无
返回值：无
******************************************************************************/
void Buzzer_Start_Up(void)
{
    BuzzerPlayCtrl.Mode = BUZZER_MODE_IDLE;

    BuzzerPlayCtrl.Track = 0;
    BuzzerPlayCtrl.Note = 0;
    BuzzerPlayCtrl.Timer = 0;
    BuzzerPlayCtrl.Fade = 0;

    BUZZER_CTRL = 0;
    TimerB_PWM_Channel_Stop(BUZZER_PWM_CHANNEL);
    TimerB_PWM_Channel_Init(BUZZER_PWM_CHANNEL, TIMERB_CLOCK_0, TIMERB_HIGH);
}

/******************************************************************************
函数名：Buzzer_Shutdown
功  能：关闭蜂鸣器
参  数：无
返回值：无
******************************************************************************/
void Buzzer_Shutdown(void)
{
    BuzzerPlayCtrl.Mode = BUZZER_MODE_IDLE;

    BuzzerPlayCtrl.Track = 0;
    BuzzerPlayCtrl.Note = 0;
    BuzzerPlayCtrl.Timer = 0;
    BuzzerPlayCtrl.Fade = 0;

    BUZZER_CTRL = 0;
    TimerB_PWM_Channel_Stop(BUZZER_PWM_CHANNEL);
}

/******************************************************************************
函数名：Buzzer_Play_Track
功  能：单次播放指定音轨
参  数：TrackID - 音轨编号
返回值：无
******************************************************************************/
void Buzzer_Play_Track(uint8_t TrackID)
{
    if (BuzzerPlayCtrl.Mode)
        return;

    if (TrackID >= SND_TRACK_TOTAL_NUM)
        return;

    BUZZER_CTRL = 1;

    BuzzerPlayCtrl.Track = TrackID;
    BuzzerPlayCtrl.Note = 0;
    BuzzerPlayCtrl.Timer = (uint16_t)SndTracks[TrackID].PreCharge * 20;
    BuzzerPlayCtrl.Fade = 0;

    BuzzerPlayCtrl.Mode = BUZZER_MODE_SINGLE;
}

/******************************************************************************
函数名：Buzzer_Play_Track
功  能：循环播放指定音轨
参  数：TrackID - 音轨编号
返回值：无
******************************************************************************/
void Buzzer_Repeat_Play_Track(uint8_t TrackID)
{
    if (BuzzerPlayCtrl.Mode)
        return;

    if (TrackID >= SND_TRACK_TOTAL_NUM)
        return;

    BUZZER_CTRL = 1;

    BuzzerPlayCtrl.Track = TrackID;
    BuzzerPlayCtrl.Note = 0;
    BuzzerPlayCtrl.Timer = (uint16_t)SndTracks[TrackID].PreCharge * 20;
    BuzzerPlayCtrl.Fade = 0;

    BuzzerPlayCtrl.Mode = BUZZER_MODE_LOOP;
}

/******************************************************************************
函数名：Buzzer_Stop_Play
功  能：停止播放音轨
参  数：无
返回值：无
******************************************************************************/
void Buzzer_Stop_Play(void)
{
    BuzzerPlayCtrl.Mode = BUZZER_MODE_IDLE;

    BuzzerPlayCtrl.Track = 0;
    BuzzerPlayCtrl.Note = 0;
    BuzzerPlayCtrl.Timer = 0;
    BuzzerPlayCtrl.Fade = 0;

    BUZZER_CTRL = 0;
    TimerB_PWM_Channel_Stop(BUZZER_PWM_CHANNEL);
}

/******************************************************************************
函数名：Buzzer_Play_ISR
功  能：蜂鸣器播放中断服务函数
参  数：无
返回值：无
******************************************************************************
注  意：该服务函数必须嵌入到50us定时中断内
******************************************************************************/
void Buzzer_Play_ISR(void)
{
    if (BuzzerPlayCtrl.Mode)
    {
        if (BuzzerPlayCtrl.Timer)
            BuzzerPlayCtrl.Timer--;

        if (BuzzerPlayCtrl.Timer == 0)
        {
            if (BuzzerPlayCtrl.Note < SndTracks[BuzzerPlayCtrl.Track].NoteNum)
            {
                BUZZER_CTRL = 1;

                if (SndTracks[BuzzerPlayCtrl.Track].Note[BuzzerPlayCtrl.Note].Freq)
                {
                    TimerB_PWM_Channel_Fre_Set(BUZZER_PWM_CHANNEL, SndTracks[BuzzerPlayCtrl.Track].Note[BuzzerPlayCtrl.Note].Freq, SndTracks[BuzzerPlayCtrl.Track].Note[BuzzerPlayCtrl.Note].Duty);
                    // TimerB_PWM_Channel_Duty_Set(BUZZER_PWM_CHANNEL, SndTracks[BuzzerPlayCtrl.Track].Note[BuzzerPlayCtrl.Note].Duty);
                    TimerB_PWM_Channel_Start(BUZZER_PWM_CHANNEL);
                }
                else
                    TimerB_PWM_Channel_Stop(BUZZER_PWM_CHANNEL);

                BuzzerPlayCtrl.Timer = SndTracks[BuzzerPlayCtrl.Track].Note[BuzzerPlayCtrl.Note].Interval * 20;
                BuzzerPlayCtrl.Fade = SndTracks[BuzzerPlayCtrl.Track].Note[BuzzerPlayCtrl.Note].Fade * 20;
                BuzzerPlayCtrl.Note++;
            }
            else
            {
                if (BuzzerPlayCtrl.Mode == BUZZER_MODE_LOOP)
                    BuzzerPlayCtrl.Note = 0;
                else
                {
                    BUZZER_CTRL = 0;
                    TimerB_PWM_Channel_Stop(BUZZER_PWM_CHANNEL);
                    BuzzerPlayCtrl.Mode = BUZZER_MODE_IDLE;
                }
            }
        }
        else if (BuzzerPlayCtrl.Timer < BuzzerPlayCtrl.Fade)
            BUZZER_CTRL = 0;
    }
}