//***************************(C) COPYRIGHT 2015 CZQ******************************
//*******************************************************************************
// File Name   	: jmdmp3lib.h
// Version		  : V0.0
// Compiler		  : GCCARM
// Target		    : E3RCU (STM32F103VET6)
// Author		    : CZQ
// Date			    : 2015/12/11
// Description  : 内置MP3库
//*******************************************************************************
//
//*******************************************************************************
/*****************************************************************************
MP3:上电初始化时间<=500ms,实测约300ms
播放曲目响应速度约50ms
芯片内部对串口的处理是 10MS 处理一次，所以连续的指令发送时，必须要间隔 20MS 的延时。
否则前面的指令将会被覆盖而得不到执行
******************************************************************************/
#ifndef _JMDMP3LIB_H_
#define _JMDMP3LIB_H_

#define _MP3LIB_EXT_H_
//#include "hw_config.h"

#define _MP3_PWR_ON_TIME_	500	//ms

typedef enum
{
	USB_DISK_ON=0,
	USB_MP3_OFF=0,
	USB_MP3_ON=1,
	
	MP3_SW_OFF=0,
	MP3_SW_ON=1,
	
	MP3_STOP=0,//停止
	MP3_PLAY=1,//播放
	MP3_SUSPEND=2,//暂停
	MP3_NXT=3,//下一首
	MP3_FWD=4,//上一首
	MP3_PLAYSONG=5//播放指定音频
}USB_SW_STATE;
#define EEP_MP3_SOUND 		192//MP3音量 最大声:0-30
#define EEP_MP3_PWR   		191//MP3电源开关
#define USB_SW_GPIO  			GPIOE
#define USB_SW_PIN   			GPIO_Pin_15
#define MP3_PWR_GPIO 			GPIOA
#define MP3_PWR_PIN  			GPIO_Pin_13
#define MP3_STATE_GPIO 		GPIOE
#define MP3_STATE_PIN  		GPIO_Pin_14
#define GET_MP3_STATE() 	GPIO_ReadInputDataBit(MP3_STATE_GPIO,MP3_STATE_PIN)
typedef enum
{//MP3数据包格式:0X7E+0XFF(保留字节)+0x06(长度)+CMD+FB+D0+D1+2Byte校验和+0XEF
 //长度:不包含字头字尾和校验和
 //检验和=0-(0XFF(保留字节)+0x06(长度)+CMD+FB+D0+D1)
 //CMD:操作指令
 //FB:反馈信息,1反馈,0不反馈
	MP3_FIRST_BYTE=0X7E,//数据包头
	MP3_END_BYTE=0XEF,//数据包未
	//控制指令
	MP3_PNXT_SCMD=0X01,//下一曲
	MP3_PFWD_SCMD=0X02,//上一曲
	MP3_PSONG_SCMD=0X03,//指定曲目(NUM)
	MP3_SOUNDP_SCMD=0X04,//音量+
	MP3_SOUNDN_SCMD=0X05,//音量-
	MP3_SOUND_SCMD=0X06,//指定音量0-30
	MP3_SCSTP_SCMD=0X08,//单曲循环指定曲目播放
	MP3_SPD_SCMD=0X09,//指定播放设备
	MP3_SLEEP_SCMD=0X0A,//进入睡眠 -- 低功耗
	MP3_WAKE_SCMD=0X0B,//唤醒睡眠
	MP3_RST_SCMD=0X0C,//芯片复位
	MP3_PLAY_SCMD=0X0D,//播放
	MP3_SUSPEND_SCMD=0X0E,//暂停
	MP3_PFNSF_SCMD=0X0F,//指定文件夹文件名播放
	MP3_PADVERT_SCMD=0X13,//插播广告
	MP3_SADVERT_SCMD=0X15,//停止插播播放背景音乐
	MP3_STOP_SCMD=0X16,//停止插播播放背景音乐
	MP3_PFLOOP_SCMD=0X17,//指定文件夹循环播放
	MP3_PRRAND_SCMD=0X18,//指定根目录随机播放
	MP3_PSSLOOP_SCMD=0X19,//对当前播放的曲目设置为循环播放
	MP3_DACOUT_SCMD=0X1A,//开启和关闭芯片的 DAC 输出
	MP3_COMBP_SCMD=0X21,//组合播放
	MP3_SSSF_SCMD=0X22,//指定音量同时指定文件播放
	MP3_PMF_SCMD=0X25,//多文件夹插播
	//查询指令
	MP3_ONLINE_CCMD=0X3F,//查询在线设备
	MP3_CURSTATE_CCMD=0X42,//查询当前状态
	MP3_CURSOUND_CCMD=0X43,//查询当前音量
	MP3_CTFILENUM_CCMD=0X49,//查询 FLASH 的总文件数,5个文件夹的总文件数
	MP3_CFSPOINT_CCMD=0X4D,//FLASH当前文件夹曲目指针
	MP3_FTNUM_CCMD=0X4E,//查询指定文件夹的曲目总数
	MP3_FOLDERNUM_CCMD=0X4F,//查询当前设备的总文件夹数
	MP3_CFILEPOINT_CCMD=0X61,//查询当前文件夹指针
}MP3_ENUM_DEFINED;

#define MP3RX_MAX		    64
#define MP3SOUND_MAX	  28//30最大音量

#ifndef _MP3LIB_EXT_H_
extern u8 Mp3RXBuffer[MP3RX_MAX],Mp3RxNew,Mp3PowerState,Mp3Sound,Mp3Online,MP3DiskState;
extern u16 Mp3RxLen,Mp3NumSize,Mp3NumCnt;
extern u32 MP3SetCmdTime;
extern u8 MP3Version;
#else
//#ifdef _MP3LIB_EXT_H_
//#define _MP3LIB_EXT_H_
u8 Mp3RXBuffer[MP3RX_MAX],Mp3RxNew=0,Mp3PowerState=0,Mp3Sound=MP3SOUND_MAX,Mp3Online=0XFF;
u16 Mp3RxLen=0,Mp3NumSize=0,Mp3NumCnt=0;
u32 MP3SetCmdTime=0;//MP3播放时间间隔
u8 MP3Version=0;//MP3版本
u8 MP3DiskState=0;//MP3U盘版本
void ClearMP3Buffer(void)
{
	u16 i;
	Mp3RxLen=0;
	Mp3RxNew=0;
	for(i=0;i<MP3RX_MAX;i++)Mp3RXBuffer[i]=0;
}
void MP3_DELAY(u32 time){Delay1ms(time);}
u8 MP3_SetSetCmdTime(void){MP3SetCmdTime=GetSystemTime()+30;}//连续2次发送指令只是20ms时间间隔
u8 MP3_GetSetCmdTime(void)
{
	while(MP3SetCmdTime>GetSystemTime());//延时等待
	MP3_SetSetCmdTime();
	return 0;
}
u8 Usb_SwitchInit(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
	//USB切换
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Pin = USB_SW_PIN;   
  GPIO_Init(USB_SW_GPIO, &GPIO_InitStructure);
	SetUsbSwitch(USB_MP3_ON);
}
u8 MP3_BspPinInitFlag=0;
u8 MP3_BspPinInit(void)
{
	if(MP3_BspPinInitFlag)return;MP3_BspPinInitFlag=1;
  GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
	//由于复用JTAG的TDI需要关闭TDI功能
  //RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//必须开启复用时钟
  GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);//完全失能（JTAG+SW-DP）
	//GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//使能SWD 禁用JTAG 
	//电源引脚
	//GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	//GPIO_InitStructure.GPIO_Pin = MP3_PWR_PIN;
  //GPIO_Init(MP3_PWR_GPIO, &GPIO_InitStructure);
	//SetMP3PwrState(Mp3PowerState);
	//状态引脚同时用于MP3版本区分
	GPIO_InitStructure.GPIO_Pin = MP3_STATE_PIN;  
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//GPIO_Mode_IN_FLOATING;
  GPIO_Init(MP3_STATE_GPIO, &GPIO_InitStructure);
}
void SetUsbSwitch(u8 state)//USB切换
{
	if(state){GPIO_SetBits(USB_SW_GPIO,USB_SW_PIN);}	
	else	    {GPIO_ResetBits(USB_SW_GPIO,USB_SW_PIN);}
}
void SetMP3PwrState(u8 state)//MP3电源
{	
	if(state){GPIO_SetBits(MP3_PWR_GPIO,MP3_PWR_PIN);}
	else	{GPIO_ResetBits(MP3_PWR_GPIO,MP3_PWR_PIN);}	
}
u8 GetMP3State(void)
{
	return (GPIO_ReadInputDataBit(MP3_STATE_GPIO,MP3_STATE_PIN)>0?0:1);
}
//MP3电源开关
/*u16 ReadMP3PowerEEP(void)
{
	return ReadEEP(EEP_MP3_PWR);
}
u16 SetMP3PowerEEP(u16 state)
{
	WriteEEP(EEP_MP3_PWR,state);
}//*/
//MP3音量
u16 ReadMP3SoundEEP(void)
{
	u16 sound;
	sound=ReadEEP(EEP_MP3_SOUND);
	if(sound>MP3SOUND_MAX)sound=MP3SOUND_MAX;
	return sound;
}
u16 SetMP3SoundEEP(u16 state)
{
	if(state>MP3SOUND_MAX)state=MP3SOUND_MAX;
	WriteEEP(EEP_MP3_SOUND,state);
}

u8 MP3_BspInitFlag=0;
u8 MP3_BspInit(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  SysMP3ISRFunInit();//先初始化中断函数
	if(MP3_BspInitFlag)return 0;MP3_BspInitFlag=1;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
	
  Mp3Sound=ReadMP3SoundEEP();//读取MP3声音
	//由于复用JTAG的TDI需要关闭TDI功能
  //RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//必须开启复用时钟
  GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);//完全失能（JTAG+SW-DP）
	//GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//使能SWD 禁用JTAG 
	
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

  //Usb_SwitchInit();
	//SetUsbSwitch(USB_MP3_OFF);
	//MP3_BspPinInit();
	//SetMP3PwrState(Mp3PowerState);
	
  //Configure USART3 Tx (PB.10) as alternate function push-pull //
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  // Configure USART3 Rx (PB.11) as input floating //
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

//初始化串口
  USART_InitTypeDef USART_InitStructure;
  USART_InitStructure.USART_BaudRate = 9600;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No ;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(USART3, &USART_InitStructure);

  //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	NVIC_InitTypeDef NVIC_InitStructure;
  NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =9;   //抢占优先级0
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
//配置中断
  USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
//使能串口
  USART_Cmd(USART3, ENABLE);

  MP3_SetSound(Mp3Sound);
  MP3_DELAY(20);
	return 1;
}
u8 MP3_BspDeInit(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, DISABLE);
	USART_ITConfig(USART3, USART_IT_RXNE, DISABLE);
	USART_Cmd(USART3, DISABLE);
}
void MP3_SendByte(u8 byte)
{
  USART_SendData(USART3, byte);
  while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
}
void MP3_SendPacket(u8 *Data,u16 len)
{
  u16 i;
  for(i=0;i<len;i++)
  {
		MP3_SendByte(*Data++);
  }
}
//MP3数据包格式:0X7E+0XFF(保留字节)+0x06(长度)+CMD+FB+D0+D1+2Byte校验和+0XEF
void MP3_SendCmd( u8 *Data,//放送指令
                   u16 len,//长度,去掉字头字尾和检验和
									 u8 check)//0不校验,1校验
{
	u16 sum=0,i;
	MP3_GetSetCmdTime();//等待上次处理完毕
	MP3_SendByte(MP3_FIRST_BYTE);
	MP3_SendPacket(Data,len);
	if(check)//发送校验和
	{
		for(i=0;i<len;i++){sum+=*(Data+i);}
		sum=0-sum;
		MP3_SendByte((sum>>8)&0xFF);
		MP3_SendByte((sum)&0xFF);
	}
	MP3_SendByte(MP3_END_BYTE);
}
//发送MP3指令
void MP3_Send(u8 cmd,//控制指令
               u8 feedback,//1有反馈,0无反馈
							 u8 *Data,//控制指令包含的参数
							 u16 len)//参数*Data长度
{
	u8 mData[100];
	u16 i=0;
	mData[i++]=0xFF;    //0 保留位
	mData[i++]=len+4;   //1 长度
	mData[i++]=cmd;     //2 控制指令
	mData[i++]=feedback;//3 反馈
	for(i;i<mData[1];i++)mData[i]=*Data++;
	MP3_SendCmd(mData,mData[1],1);
}
//发送MP3指令
void MP3_SendString(u8 cmd,//控制指令
											u8 feedback,//1有反馈,0无反馈
											u8 *Data)//控制指令包含的参数
{
	u8 mData[100];
	u16 i=0,len=0;
	mData[i++]=0xFF;    //0 保留位
	i++;//mData[i++]=len+4;   //1 长度
	mData[i++]=cmd;     //2 控制指令
	mData[i++]=feedback;//3 反馈
	for(i;*Data;i++)mData[i]=*Data++;
	mData[1]=i;//len+4;
	MP3_SendCmd(mData,mData[1],1);
}
//发送MP3指令
void MP3_Cmd(u8 cmd,//控制指令
               u8 feedback,//1有反馈,0无反馈
							 u16 Data)//控制指令包含的参数

{
	u8 mData[2];
	mData[0]=(Data>>8)&0xff;
	mData[1]=Data&0xff;
  MP3_Send(cmd,//控制指令
            feedback,//1有反馈,0无反馈
						mData,//控制指令包含的参数
						0x02);//参数*Data长度	
}
void MP3_GetSound(u8 *sound)//读取音量
{
	u16 msound;
	msound=ReadMP3SoundEEP();
	if(msound>MP3SOUND_MAX)msound=MP3SOUND_MAX;
	*sound=msound;
}
void MP3_SetSound(u8 sound)//设置音量
{
	if(sound>30)sound=30;
	MP3_Cmd(MP3_SOUND_SCMD,//控制指令
          0x00,//1有反馈,0无反馈
					sound);//控制指令包含的参数	
	//if(Mp3Sound!=sound)	// 保存到eeprom ReadMP3SoundEEP()
	//{
		//SetMP3SoundEEP(sound);
		//Mp3Sound=sound;
	//}
}
u16 Mp3SoundOut=0xffff;
void MP3_SetSoundOut(void)//设置音量
{
	if(Mp3SoundOut==Mp3Sound)return;
	MP3_Cmd(MP3_SOUND_SCMD,//控制指令
          0x00,//1有反馈,0无反馈
          Mp3Sound);//控制指令包含的参数
	Mp3SoundOut=Mp3Sound;
	//MP3_DELAY(25);//需要时间设置
}
void MP3_SetDACOut(u8 mode)//设置输出,1开0关
{
	u8 state=0;
	if(mode==0)state=1;//关闭DAC
	MP3_Cmd(MP3_DACOUT_SCMD,//控制指令
          0x01,//1有反馈,0无反馈
					state);//控制指令包含的参数	
}
void MP3_PlaySong(u8 mode,u16 data)
{
	MP3_BspInit();
	MP3_SetSoundOut();//先设置MP3播放时间
	switch(mode)
	{
		case MP3_STOP://停止
		{
			MP3_Cmd(MP3_STOP_SCMD,//控制指令
              0x01,//1有反馈,0无反馈
							0x00);//控制指令包含的参数
		}break;
		case MP3_PLAY://播放
		{
			MP3_Cmd(MP3_PLAY_SCMD,//控制指令
              0x01,//1有反馈,0无反馈
							0x00);//控制指令包含的参数
		}break;
		case MP3_SUSPEND://暂停
		{
			MP3_Cmd(MP3_SUSPEND_SCMD,//控制指令
              0x01,//1有反馈,0无反馈
							0x00);//控制指令包含的参数
		}break;
		case MP3_NXT://下一首
		{
			MP3_Cmd(MP3_PNXT_SCMD,//控制指令
              0x01,//1有反馈,0无反馈
							0x00);//控制指令包含的参数
		}break;
		case MP3_FWD://上一首
		{
			MP3_Cmd(MP3_PFWD_SCMD,//控制指令
              0x01,//1有反馈,0无反馈
							0x00);//控制指令包含的参数
		}break;
		case MP3_PLAYSONG:
		{//7E FF 06 0F 00 01 01 FE EA EF//指定为"01"的文件夹，曲目为"001"
			MP3_Cmd(MP3_PFNSF_SCMD,//MP3_PSONG_SCMD,//控制指令
              0x01,//1有反馈,0无反馈
							data);//控制指令包含的参数
		}break;
	}
}
//u8 iiii=0;
u8 CheckMP3OnlineState(void)
{
	ClearMP3Buffer();
	MP3_Cmd(MP3_ONLINE_CCMD,//控制指令
          0x00,//1有反馈,0无反馈
					0x00);//控制指令包含的参数
	MP3_DELAY(50);
	if(Mp3RxNew)
	{
		if(Mp3RXBuffer[3]==0X3F&&Mp3RXBuffer[6]==0x0C)
		{
			ClearMP3Buffer();
			return 1;//在线
		}
		ClearMP3Buffer();
	}
	return 0;
}
u8 CheckCurronOnlineState(void)
{
	if(MP3DiskState==1){MP3DiskState=0;return 1;}
	else if(MP3DiskState==2){MP3DiskState=0;return 0;}
	if(Mp3RxNew)
	{
	#if _MP3_DEBUG_EN_>0
		MP3_Debug();
	#endif	
		if(Mp3RXBuffer[3]==0X3A||(Mp3RXBuffer[3]==0X3F&&Mp3RXBuffer[6]==0x0C))//接入电脑
		{
			ClearMP3Buffer();
			return 1;//在线
		}
		ClearMP3Buffer();
	}
	return 0;
}
u16 ReadMP3SongNum(u16 *SongSize)//读曲目总数
{
	u16 t=3;//,i;
	ClearMP3Buffer();//清缓存
	do
	{
		MP3_Cmd(MP3_CTFILENUM_CCMD,//控制指令
						0x00,//1有反馈,0无反馈
						0x00);//控制指令包含的参数			
		MP3_DELAY(20);//延时20ms等待接收完毕
		if(Mp3RxNew&&Mp3RXBuffer[3]==MP3_CTFILENUM_CCMD)
		{
			t=0;
			*SongSize=(Mp3RXBuffer[5]<<8)|Mp3RXBuffer[6];//保存音频数量
			return 1;
		}
		else if(Mp3RxNew)ClearMP3Buffer();
	}while(t--);
	*SongSize=0;
//	for(i=0;i<Mp3RxLen;i++)print("%X ",Mp3RXBuffer[i]);
	return 0;
}

void MP3_RX_ISR(void)
{
	if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
	{ 
		USART_ClearFlag(USART3, USART_FLAG_RXNE);
		Mp3RXBuffer[Mp3RxLen++]=USART_ReceiveData(USART3);//读数据自动清除中断标志
		if(Mp3RxLen>=MP3RX_MAX){	Mp3RxLen=0;}
		switch(Mp3RxNew)
		{
			case 0:
			{
				if(Mp3RxLen>4&&Mp3RxLen>=(Mp3RXBuffer[2]+4))//接收完1个数据包
				{
					if(Mp3RXBuffer[0]==MP3_FIRST_BYTE&&Mp3RXBuffer[Mp3RxLen-1]==MP3_END_BYTE)
					{
						Mp3RxNew=1;//接收完1个数据包
					}
					else 
					{
						Mp3RxNew=0;
						Mp3RxLen=0;
					}
				}
			}break;
			default:
			{
			}break;
		}
		//以下用于检测是否接入PC
		if(Mp3RxLen>=10)
		{
			if(Mp3RXBuffer[Mp3RxLen-10]==MP3_FIRST_BYTE&&
			    Mp3RXBuffer[Mp3RxLen-1]==MP3_END_BYTE&&
					Mp3RXBuffer[Mp3RxLen-8]==0X06&&
					Mp3RXBuffer[Mp3RxLen-4]==0X04)//PC
			{
				if(Mp3RXBuffer[Mp3RxLen-7]==0X3A)
				{//7E FF 06 3A 00 00 04 FE BD EF
					MP3DiskState=1;//接入PC
				}
				else if(Mp3RXBuffer[Mp3RxLen-7]==0X3B)
				{//7E FF 06 3B 00 00 04 FE BD EF
					MP3DiskState=2;//拔出PC
				}
			}
		}//if(Mp3RxLen>=10)
	}
}
#endif//_MP3LIB_EXT_H_
#endif//_MP3_H_
