/******************** (C) COPYRIGHT 2006 STMicroelectronics ********************
* File Name          : waveplayer.c
* Author             : MCD Application Team
* Date First Issued  : 03/10/2006
* Description        : This file includes the wave player driver for the
*                      STR75x-EVAL demo.
********************************************************************************
* History:
* 07/17/2006 : V1.0
* 03/10/2006 : V0.1
********************************************************************************
* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private typedef -----------------------------------------------------------*/
typedef enum
{
  LittleEndian,
  BigEndian
}Endianness;

/* Private define ------------------------------------------------------------*/
#define  ChunkID             0x52494646  /* correspond to the letters 'RIFF' */
#define  FileFormat          0x57415645  /* correspond to the letters 'WAVE' */
#define  FormatID            0x666D7420  /* correspond to the letters 'fmt ' */
#define  DataID              0x64617461  /* correspond to the letters 'data' */
#define  FactID              0x66616374  /* correspond to the letters 'fact' */

#define  WAVE_FORMAT_PCM     0x01
#define  FormatChunkSize     0x10
#define  Channel_Mono        0x01

#define  SampleRate_8000     8000
#define  SampleRate_11025    11025
#define  SampleRate_22050    22050
#define  SampleRate_44100    44100
#define  Bits_Per_Sample_8   8

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/

  /* Wave details names table */
  WAVE_FormatTypeDef         WAVE_FormatPlaying;
  WAVE_FormatTypeDef         WAVE_PromoFormat;
  WAVE_FormatTypeDef         WAVE_OSIRISFormat;
  WAVE_FormatTypeDef         WAVE_Format;
  string WaveDetailsmsg[6]={"   Playing time   ",
                            "     File size    ",
                            "   Format Tag     ",
                            "    Channels      ",
                            "   Sample Rate    ",
                            " Bits per sample  "};


  /* Peripherals InitStructure define */
  extern GPIO_InitTypeDef    GPIO_InitStructure;
  extern EXTIT_InitTypeDef   EXTIT_InitStructure;
  TIM_InitTypeDef            TIM_InitStructure;
  extern  u8 STLogo61[];        /* ST Logo on 32*61 pixels */
  extern vu8  VoiceRecord;      /* Boardself test record or voice recordering select */
  vu8 SelectedWave = 1;         /* Loaded or recorded wave playing select */
  vu32 VoiceCounterRestore = 0; /* Voive recorder restore index */
  extern vu32 BoardSelfTestStatus;  /* Board Self Test starting status */
  extern vu32 RecordStatus;     /* Voice recorder global Status */
  extern vu32 AlarmStatus;      /* Alarm melody global status */
  extern vu32 SMIReadAddr;      /* SMI read address global index */
  extern vu32 WaveCounter;      /* Wave player and voice recorder global index */
  extern u32 WaveDataLength;    /* Wave player global data lenght*/
  extern u32 RecordDataLength;  /* Voice recorder global data lenght */
  extern vu32 ScreenStatus;  /* Screen saver global Status */
  extern vu32 WaveDataRead;     /* Played wave data length */
  volatile ErrorCode WaveFileStatus = Unvalid_RIFF_ID;       /* wave file load status */
  volatile ErrorCode WaveFileStatusPromo = Unvalid_RIFF_ID;  /*  Promo speech wave file load status */
  volatile ErrorCode WaveFileStatusOSIRIS = Unvalid_RIFF_ID; /* Osiris wave file load status */
  volatile ErrorCode WaveFileStatusAlarm = Unvalid_RIFF_ID;  /* Alarm wave file load status */
  vu32 FirstOne = 1;          /* wave file load variable */
  u16 PromoTIM0_OCR1_Value = 0;
  u16 OSIRISTIM0_OCR1_Value = 0;
  u16 TIM0_OCR1_Value = 0;
  u32 Offset = 0x00;
  u32 PromoOffset = 0;
  u32 OSIRISOffset = 0;


/* Private function prototypes -----------------------------------------------*/
static u32 ReadUnit(u8 NbrOfBytes, u32 ReadAddr, Endianness BytesFormat);

/* Private functions ---------------------------------------------------------*/

/*******************************************************************************
* Function Name  : WavePlay_Init
* Description    : Wave player Initialization
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void WavePlayer_Init(void)
{
  /* Read the Promotion wave file status */
  WaveFileStatusPromo = WavePlayer_WaveParsing(IntroReadAddr);
  /* Store the promotion wave file properties to the WAVE_PromoFormat structure */
  WAVE_PromoFormat = WAVE_Format;
  /* Store the promotion wave file offset */
  PromoOffset = Offset;
  /* Store the promotion wave file sample rate */
  PromoTIM0_OCR1_Value = TIM0_OCR1_Value;
  /* Reset the Offset variable */
  Offset = 0;

  /* Read the OSIRIS wave file status */
  WaveFileStatusOSIRIS = WavePlayer_WaveParsing(OSIRISReadAddr);
  /* Store the OSIRIS wave file properties to the WAVE_OSIRISFormat structure */
  WAVE_OSIRISFormat = WAVE_Format;
  /* Store the OSIRIS wave file offset */
  OSIRISOffset = Offset;
  /* Store the OSIRIS wave file sample rate */
  OSIRISTIM0_OCR1_Value = TIM0_OCR1_Value;

  /* Read the Alarm wave file status */
  WaveFileStatusAlarm = WavePlayer_WaveParsing(AlarmReadAddr);

  if(WaveFileStatusPromo == Valid_WAVE_File) /* the .WAV file is valid */
  {
    /* Set WaveDataLenght to the Promotion wave length */
    WaveDataLength = WAVE_PromoFormat.DataSize;

    WaveFileStatus = Valid_WAVE_File;
  }
  else if(WaveFileStatusOSIRIS == Valid_WAVE_File) /* the .WAV file is valid */
  {
    /* Set WaveDataLenght to the Promotion wave length */
    WaveDataLength = WAVE_OSIRISFormat.DataSize;
  }

  /* Configure P1.2 as alternate function (TIM2_OC2) */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_Init(GPIO1, &GPIO_InitStructure);

  /* TIM2 configuration */
  TIM_InitStructure.TIM_Mode = TIM_Mode_PWM;
  TIM_InitStructure.TIM_Prescaler = 0x00;    /* TIM_CLK: 60 MHz */
  TIM_InitStructure.TIM_ClockSource = TIM_ClockSource_Internal;
  TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_InitStructure.TIM_Period = 0xFF;       /* PWM frequency : ~234KHz*/
  TIM_InitStructure.TIM_Channel = TIM_Channel_2;
  TIM_InitStructure.TIM_Pulse2 = 0x7F;       /* Duty cycle: 50%*/
  TIM_InitStructure.TIM_Polarity2 = TIM_Polarity2_Low;
  TIM_Init(TIM2, &TIM_InitStructure);

  /* TIM0 configuration */
  TIM_InitStructure.TIM_Mode = TIM_Mode_OCTiming;
  TIM_InitStructure.TIM_Prescaler = 0x5;   /* TIM_CLK: 10 MHz */
  TIM_InitStructure.TIM_ClockSource = TIM_ClockSource_Internal;
  TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_InitStructure.TIM_Period = 0x1C6;  /* TIM frequency : 22.05KHz*/
  TIM_InitStructure.TIM_Channel = TIM_Channel_1;
  TIM_Init(TIM0, &TIM_InitStructure);
}

/*******************************************************************************
* Function Name  : WavePlayer_Start
* Description    : Start wave playing
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void WavePlayer_Start(void)
{
  /* Reset RecordStatus to FALSE to play wave */
  RecordStatus = 0;
  /* Reset WaveCounter value to play new wave */
  WaveCounter = 0;

  /* Configure P1.2 as alternate function (TIM2_OC2) */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_Init(GPIO1, &GPIO_InitStructure);

  /* If we select to play Recorded wave */
  if(SelectedWave == 0)
  {
    /* If no wave was recorded */
    if(RecordDataLength == 0)
    {
      /* Stop wave playing */
      WavePlayer_Stop();
      /* Display "No recorded wave " message */
      LCD_DisplayString(Line1, "No recorded wave ", BlackText);
      LCD_DisplayString(Line2, " Press UP / DOWN ", BlackText);
      /* Wait a press on "UP" or "DOWN" pushbuttons */
      while((ReadKey() & UP) != UP);
      /* Display the actual menu */
      DisplayMenu();
      /* Execute UpDownFunc function to display upper menu */
      UpDownFunc();
      return;
    }
    /* Set SMI start read address to the first recorded wave data */
    SMIReadAddr = RecordReadWritedAddr;
    /* Set WaveDataLenght to the recorded wave length */
    WaveDataLength = RecordDataLength;
    TIM_SetPeriod(TIM0, 0x1C6);
  }
  /* If we select to play wave files */
  else
  {
    if(WaveFileStatus == Valid_WAVE_File)
    {
      /* Set WaveDataLenght to the wave file length */
      WaveDataLength = WAVE_FormatPlaying.DataSize;
    }
    else
    {
      /* Display "No Loaded File   " message */
      LCD_DisplayString(Line1, "  No Loaded Wave ", BlackText);
      LCD_DisplayString(Line2, " Press UP / DOWN ", BlackText);
      /* Wait a press on "UP" or "DOWN" pushbuttons */
      while((ReadKey() & UP) != UP);
      /* Display the actual menu */
      DisplayMenu();
      if(FirstOne == 1)
      {
        LeftFunc();
        FirstOne = 0;
      }
      UpDownFunc();
      return;
    }
  }

  /* Start TIM2 */
  TIM_Cmd(TIM2, ENABLE);
  /* Enable TIM0 update interrupt */
  TIM_ITConfig(TIM0, TIM_IT_Update, ENABLE);
  /* Start TIM0 */
  TIM_Cmd(TIM0, ENABLE);

  /* In case we stop Alarm by "WavePlayer_Stop()" while playing other wave */
  /* Disable EXTIT for Key pushbutton */
  KeyButtonOff();
  /* Simulate Right push button action: to show "Stop" menu */
  RightFunc();
}

/*******************************************************************************
* Function Name  : WavePlayer_Stop
* Description    : Stop wave playing
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void WavePlayer_Stop(void)
{
  /* Disable TIM0 update interrupt */
  TIM_ITConfig(TIM0, TIM_IT_Update, DISABLE);
  /* Disable TIM0 */
  TIM_Cmd(TIM0, DISABLE);
  /* Disable TIM2 */
  TIM_Cmd(TIM2, DISABLE);

  /* Configure P1.2 as input floating */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_Init(GPIO1, &GPIO_InitStructure);

  /* In case the Alarm is just passed*/
  /* Disable EXTIT for Key pushbutton */
  EXTIT_InitStructure.EXTIT_ITLine = EXTIT_ITLine7;
  EXTIT_InitStructure.EXTIT_ITLineCmd = DISABLE;
  EXTIT_Init(&EXTIT_InitStructure);

  if(BoardSelfTestStatus == 0)
  {
    /* Simulate Left and Up/Down push buttons action */
    LeftFunc();
    UpDownFunc();
  }

  /* If played wave reach its end and screen saver is displayed */
  /* Redisplay screen saver skeleton */
  if(WAVE_FormatPlaying.DataSize != 0)
  {
    if((SelectedWave != 0) && (WaveDataRead == (WAVE_FormatPlaying.DataSize))
       && (ScreenStatus == 1))
    {
      /* Clear the LCD screen */
      LCD_Clear();
      /* Display ST Logo */
      LCD_DrawMasterGraphic(STLogo61);
      /* Display date separators */
      LCD_DisplayChar(Line1, 77, '/', BlackText);
      LCD_DisplayChar(Line1, 98, '/', BlackText);
      /* Display time separators */
      LCD_DisplayChar(Line2, 77, ':', BlackText);
      LCD_DisplayChar(Line2, 98, ':', BlackText);
    }
  }
  /* Reinitialize played wave data length value */
  WaveDataRead = 0;

  /* Set RecordStatus to TRUE to enable voice recording in TIM0 interrupt */
  RecordStatus = 1;

  TIM_SetPeriod(TIM0, PromoTIM0_OCR1_Value);
}

/*******************************************************************************
* Function Name  : WavePlayerAlarm_Start
* Description    : Start wave alarm playing
* Input          : None
* Output         : None
* Return         : None.
*******************************************************************************/
void WavePlayerAlarm_Start(void)
{
  /* Set RecordStatus to FALSE to disable voice recording in TIM0 interrupt */
  RecordStatus = 0;
  /* Set AlarmStatus to TRUE to play Alarm wave in TIM0 interrupt */
  AlarmStatus = 1;
  /* Store voice recorder index when recording is interrupted by alarm */
  VoiceCounterRestore = WaveCounter;
  /* Reset wave player counter to play alarm wave */
  WaveCounter = 0;
  /* Set SMI start read address to first alarm wave data */
  SMIReadAddr = AlarmReadAddr;
  /* Set WaveDataLenght to alarm wave length */
  WaveDataLength = AlarmDataLength;

  /* Configure P1.2 as alternate function (TIM2_OC2) */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_Init(GPIO1, &GPIO_InitStructure);

  TIM_SetPeriod(TIM0, 0x1C6);
  /* Start TIM2 */
  TIM_Cmd(TIM2, ENABLE);
  /* Enable TIM0 update interrupt */
  TIM_ITConfig(TIM0, TIM_IT_Update, ENABLE);
  /* Start TIM0 */
  TIM_Cmd(TIM0, ENABLE);

  /* Clear the interrupt pending bit line 7 */
  EXTIT_ClearITPendingBit(EXTIT_ITLine7);
  /* Enable EXTIT for Key pushbutton on falling edge */
  EXTIT_InitStructure.EXTIT_ITLine = EXTIT_ITLine7;
  EXTIT_InitStructure.EXTIT_ITTrigger = EXTIT_ITTrigger_Falling;
  EXTIT_InitStructure.EXTIT_ITLineCmd = ENABLE;
  EXTIT_Init(&EXTIT_InitStructure);
}

/*******************************************************************************
* Function Name  : WavePlayerAlarm_Stop
* Description    : Stop wave alarm playing
* Input          : None
* Output         : None
* Return         : None.
*******************************************************************************/
void WavePlayerAlarm_Stop(void)
{
  /* Set RecordStatus to TRUE to enable voice recording in TIM0 interrupt */
  RecordStatus = 1;
  /* Set AlarmStatus to False to disable Alarm wave in TIM0 interrupt */
  AlarmStatus = 0;

  /* Configure P1.2 as input floating */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_Init(GPIO1, &GPIO_InitStructure);

  /* If current menu is different from "Voice Recorder" disable TIM0, TIM2 and EXTIT7 */
  /* else keep them enable for voice recording */
  if(VoiceRecord == 0)
  {
    /* Disable TIM0 update interrupt */
    TIM_ITConfig(TIM0, TIM_IT_Update, DISABLE);
    /* Disable TIM0 */
    TIM_Cmd(TIM0, DISABLE);
    /* Disable TIM2 */
    TIM_Cmd(TIM2, DISABLE);

    TIM_SetPeriod(TIM0, PromoTIM0_OCR1_Value);
    /* Disable EXTIT for Key pushbutton */
    EXTIT_InitStructure.EXTIT_ITLine = EXTIT_ITLine7;
    EXTIT_InitStructure.EXTIT_ITLineCmd = DISABLE;
    EXTIT_Init(&EXTIT_InitStructure);
  }

  /* Restore voice recorder index to continue recording if it is interrupted */
  WaveCounter = VoiceCounterRestore;
}

/*******************************************************************************
* Function Name  : WavePlayer_GlobalVarReset
* Description    : Resets the global variable SelectedWave.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void WavePlayer_GlobalVarReset(void)
{
  /* Reset SelectedWave for recorded wave playing */
  SelectedWave = 0;
  /* Reset VoiceRecord for recorded wave playing */
  VoiceRecord = 0;
}

/*******************************************************************************
* Function Name  : WavePlayer_GlobalVarSetPromo
* Description    : Select the promotion wave.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void WavePlayer_GlobalVarSetPromo(void)
{
  /* Set SelectedWave for Osiris wave playing */
  SelectedWave = 1;
  /* Reset VoiceRecord for Osiris wave playing */
  VoiceRecord = 0;

  TIM_SetPeriod(TIM0, PromoTIM0_OCR1_Value);

  WAVE_FormatPlaying = WAVE_PromoFormat;

  /* Set SMI start read address to the first Osiris wave data */
  SMIReadAddr = IntroReadAddr + PromoOffset;

  WaveFileStatus = WaveFileStatusPromo;

}

/*******************************************************************************
* Function Name  : WavePlayer_GlobalVarSetOSIRIS
* Description    : Select the OSIRIS wave.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void WavePlayer_GlobalVarSetOSIRIS(void)
{
  /* Set SelectedWave for Osiris wave playing */
  SelectedWave = 1;
  /* Reset VoiceRecord for Osiris wave playing */
  VoiceRecord = 0;

  TIM_SetPeriod(TIM0, OSIRISTIM0_OCR1_Value);

  WAVE_FormatPlaying = WAVE_OSIRISFormat;

  /* Set SMI start read address to the first Osiris wave data */
  SMIReadAddr = OSIRISReadAddr + OSIRISOffset;

  WaveFileStatus = WaveFileStatusOSIRIS;

}

/*******************************************************************************
* Function Name  : WavePlayer_WaveParsing
* Description    : Checks the format of the .WAV file and gets information about
*                  the audio format. This is done by reading the value of a
*                  number of parameters stored in the file header and comparing
*                  these to the values expected authenticates the format of a
*                  standard .WAV  file (44 bytes will be read). If  it is a valid
*                  .WAV file format, it continues reading the header to determine
*                  the  audio format such as the sample rate and the sampled data
*                  size. If the audio format is supported by this application,
*                  it retrieves the audio format in WAVE_Format structure and
*                  returns a zero value. Otherwise the function fails and the
*                  return value is nonzero.In this case, the return value specifies
*                  the cause of  the function fails. The error codes that can be
*                  returned by this function are declared in the header file.
* Input          : None
* Output         : None
* Return         : Zero value if the function succeed, otherwise it return
*                  a nonzero value which specifies the error code.
*******************************************************************************/
ErrorCode WavePlayer_WaveParsing(u32 ReadAddress)
{
  u32 Temp = 0x00;
  u32 ExtraFormatBytes = 0;
	
/* Read chunkID, must be 'RIFF'	----------------------------------------------*/
  Temp = ReadUnit(4, ReadAddress, BigEndian);
  if(Temp != ChunkID)
  {
    return(Unvalid_RIFF_ID);
  }
  	
  /* Read the file length ----------------------------------------------------*/
  WAVE_Format.RIFFchunksize = SMI_ReadWord(ReadAddress + 4);
	
  /* Read the file format, must be 'WAVE' ------------------------------------*/
  Temp = ReadUnit(4, ReadAddress + 8, BigEndian);
  if(Temp != FileFormat)
  {
    return(Unvalid_WAVE_Format);
  }
	
/* Read the format chunk, must be'fmt ' --------------------------------------*/
  Temp = ReadUnit(4, ReadAddress + 12, BigEndian);
  if(Temp != FormatID)
  {
    return(Unvalid_FormatChunk_ID);
  }

  /* Read the length of the 'fmt' data, must be 0x10 -------------------------*/
  Temp = SMI_ReadWord(ReadAddress + 16);
  if(Temp != 0x10)
  {
    ExtraFormatBytes = 1;
  }

  /* Read the audio format, must be 0x01 (PCM) -------------------------------*/
  WAVE_Format.FormatTag = SMI_ReadHalfWord(ReadAddress + 20);
  if(WAVE_Format.FormatTag != WAVE_FORMAT_PCM)
  {
    return(Unsupporetd_FormatTag);	
  }
	
  /* Read the number of channels, must be 0x01 (Mono) ------------------------*/
  WAVE_Format.NumChannels = SMI_ReadHalfWord(ReadAddress + 22);
  if(WAVE_Format.NumChannels != Channel_Mono)
  {
    return(Unsupporetd_Number_Of_Channel);	
  }
	
  /* Read the Sample Rate ----------------------------------------------------*/
  WAVE_Format.SampleRate = SMI_ReadWord(ReadAddress + 24);

  /* Update the OCA value according to the .WAV file Sample Rate */
  switch(WAVE_Format.SampleRate)
  {
    case SampleRate_8000 : TIM0_OCR1_Value = 0x4E2; break; /* 8KHz = 10MHz /1250 */
    case SampleRate_11025: TIM0_OCR1_Value = 0x38B; break; /* 11.025KHz = 10MHz /907 */
    case SampleRate_22050: TIM0_OCR1_Value = 0x1C6; break; /* 22.05KHz = 10MHz /454 */	
    case SampleRate_44100: TIM0_OCR1_Value = 0xE2; break;  /* 44.1KHz = 10MHz /226 */		
    default: return(Unsupporetd_Sample_Rate);
  }
	
  /* Read the Byte Rate ------------------------------------------------------*/
  WAVE_Format.ByteRate = SMI_ReadWord(ReadAddress + 28);
	
  /* Read the block alignment ------------------------------------------------*/
  WAVE_Format.BlockAlign = SMI_ReadHalfWord(ReadAddress + 32);
	
  /* Read the number of bits per sample --------------------------------------*/
  WAVE_Format.BitsPerSample = SMI_ReadHalfWord(ReadAddress + 34);
  if(WAVE_Format.BitsPerSample != Bits_Per_Sample_8)
  {
    return(Unsupporetd_Bits_Per_Sample);	
  }

  Offset = 36;

/* If there is Extra format bytes, these bytes will be defined in "Fact Chunk" */
  if(ExtraFormatBytes == 1)
  {
    /* Read th Extra format bytes, must be 0x00 ------------------------------*/
    Temp = SMI_ReadHalfWord(ReadAddress + 36);
    if(Temp != 0x00)
    {
      return(Unsupporetd_ExtraFormatBytes);
    }

    /* Read the Fact chunk, must be 'fact' -----------------------------------*/
    Temp = ReadUnit(4, ReadAddress + 38, BigEndian);
    if(Temp != FactID)
    {
      return(Unvalid_FactChunk_ID);
    }

    /* Read Fact chunk data Size ---------------------------------------------*/
    Temp = ReadUnit(4, ReadAddress + 42, LittleEndian);

    Offset += 10 + Temp;

  }

/* Read the Data chunk, must be 'data' ---------------------------------------*/
  Temp = ReadUnit(4, ReadAddress + Offset, BigEndian);
  if(Temp != DataID)
  {
    return(Unvalid_DataChunk_ID);
  }
	
  /* Read the number of sample data ------------------------------------------*/
  WAVE_Format.DataSize = ReadUnit(4, ReadAddress + Offset + 4, LittleEndian);


  return(Valid_WAVE_File);	
}


/*******************************************************************************
* Function Name  : ReadUnit
* Description    : Reads a number of bytes from the SPI Flash and reorder them
*                  in Big endian.
* Input          : - NbrOfBytes : number of bytes to read.
*                    This parameter must be a number between 1 and 4.
*                  - ReadAddr : external memory address to read from.
*                  - Endians : specifies the bytes endianness.
*                    This parameter can be one of the following values:
*                          - LittleEndian
*                          - BigEndian
* Output         : None
* Return         : Bytes read from the SPI Flash.
*******************************************************************************/
static u32 ReadUnit(u8 NbrOfBytes, u32 ReadAddr, Endianness BytesFormat)
{
  u32 index = 0;
  u32 Temp = 0;

  if(BytesFormat == LittleEndian)
  {
    for(index = 0; index < NbrOfBytes; index++)
    {
      Temp |= SMI_ReadByte(ReadAddr++) << (index * 8);
    }
  }
  else
  {
    for(index = NbrOfBytes; index != 0; index--)
    {
      Temp |= SMI_ReadByte(ReadAddr++) << ((index-1) * 8);
    }
  }

  return Temp;
}

/*******************************************************************************
* Function Name  : WavePlayer_WaveProperties
* Description    : Display the wave file properties.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void WavePlayer_WaveProperties(void)
{
  u8 MyKey = 0, Count = 0;
  u32 Tmp = 0, Tmp1 = 10;


  LCD_Clear();

  if(WaveFileStatus == Valid_WAVE_File)
  {
    /* Loop until any press on "UP" or "DOWN" pushbuttons */
    while(1)
    {
      /* Check which key is pressed */
      MyKey = ReadKey();
      /* If "RIGHT" pushbutton is pressed */
      if(MyKey == RIGHT)
      {
        /* Select the next failed board test index */
        if(Count >= (5))
        {
          Count = 0;
        }
        else
        {
          Count++;
        }
      }
      /* If "RIGHT" pushbutton is pressed */
      else if(MyKey == LEFT)
      {
        /* Select the previous failed board test index */
        if(Count >0)
        {
          Count--;
        }
        else
        {
          Count = 5;
        }
      }
      /* If one of "UP" or "DOWN" pushbuttons is pressed */
      else if((MyKey == UP) || (MyKey == DOWN))
      {
        /* Execute UpDownFunc function to dispaly the upper menu */
        DisplayMenu();
        /* Exit the loop */
        return;
      }
      /* Display the failed test board name corresponding to the current index */
      LCD_DisplayString(Line1, WaveDetailsmsg[Count], WhiteText);

      if(Tmp1 != Count)
      {
        Tmp1 = Count;
        switch(Count)
        {
          case 0:
            LCD_ClearLine(Line2);
            Tmp = (u32)((WAVE_FormatPlaying.DataSize)/(WAVE_FormatPlaying.SampleRate));
            LCD_DisplayChar(Line2, 42, ((Tmp/600) + 0x30), BlackText);
            LCD_DisplayChar(Line2, 49, (((Tmp%600)/60) + 0x30), BlackText);
            LCD_DisplayChar(Line2, 56, ':', BlackText);
            LCD_DisplayChar(Line2, 63, (((Tmp%600)%60)/10 + 0x30), BlackText);
            LCD_DisplayChar(Line2, 70, (((Tmp%600)%60)%10 + 0x30), BlackText);
            break;

          case 1:
            LCD_ClearLine(Line2);
            Tmp = WAVE_FormatPlaying.RIFFchunksize;
            LCD_DisplayChar(Line2, 14, ((Tmp/1000000) + 0x30), BlackText);
            LCD_DisplayChar(Line2, 21, (((Tmp%1000000)/100000) + 0x30), BlackText);
            LCD_DisplayChar(Line2, 28, (((Tmp%1000000)%100000)/10000 + 0x30), BlackText);
            LCD_DisplayChar(Line2, 35, (((((Tmp%1000000)%100000)%10000)/1000) + 0x30), BlackText);
            LCD_DisplayChar(Line2, 42, ((((((Tmp%1000000)%100000)%10000)%1000)/100) + 0x30), BlackText);
            LCD_DisplayChar(Line2, 49, (((((((Tmp%1000000)%100000)%10000)%1000)%100)/10) + 0x30), BlackText);
            LCD_DisplayChar(Line2, 56, (((((((Tmp%1000000)%100000)%10000)%1000)%100)%10) + 0x30), BlackText);
            LCD_DisplayChar(Line2, 63, ' ', BlackText);
            LCD_DisplayChar(Line2, 70, 'B', BlackText);
            LCD_DisplayChar(Line2, 77, 'y', BlackText);
            LCD_DisplayChar(Line2, 84, 't', BlackText);
            LCD_DisplayChar(Line2, 91, 'e', BlackText);
            LCD_DisplayChar(Line2, 98, 's', BlackText);
            break;

          case 2:
            LCD_ClearLine(Line2);
            Tmp = WAVE_FormatPlaying.FormatTag;
            if(Tmp == 1)
            {
              LCD_DisplayChar(Line2, 49, 'P', BlackText);
              LCD_DisplayChar(Line2, 56, 'C', BlackText);
              LCD_DisplayChar(Line2, 63, 'M', BlackText);
            }
            else
            {
              LCD_DisplayChar(Line2, 35, ((Tmp/10000) + 0x30), BlackText);
              LCD_DisplayChar(Line2, 42, (((Tmp%10000)/1000) + 0x30), BlackText);
              LCD_DisplayChar(Line2, 49, (((Tmp%10000)%1000)/100 + 0x30), BlackText);
              LCD_DisplayChar(Line2, 56, (((((Tmp%10000)%1000)%100)/10) + 0x30), BlackText);
              LCD_DisplayChar(Line2, 63, (((((Tmp%10000)%1000)%100)%10) + 0x30), BlackText);
            }
            break;

          case 3:
            LCD_ClearLine(Line2);
            Tmp = WAVE_FormatPlaying.NumChannels;
            if(Tmp == 1)
            {
              LCD_DisplayChar(Line2, 42, 'M', BlackText);
              LCD_DisplayChar(Line2, 49, 'O', BlackText);
              LCD_DisplayChar(Line2, 56, 'N', BlackText);
              LCD_DisplayChar(Line2, 63, 'O', BlackText);
            }
            else if(Tmp == 2)
            {
              LCD_DisplayChar(Line2, 35, 'S', BlackText);
              LCD_DisplayChar(Line2, 42, 'T', BlackText);
              LCD_DisplayChar(Line2, 49, 'E', BlackText);
              LCD_DisplayChar(Line2, 56, 'R', BlackText);
              LCD_DisplayChar(Line2, 63, 'E', BlackText);
              LCD_DisplayChar(Line2, 70, 'O', BlackText);
            }
            break;

          case 4:
            LCD_ClearLine(Line2);
            Tmp = WAVE_FormatPlaying.SampleRate;
            LCD_DisplayChar(Line2, 28, ((Tmp/10000) + 0x30), BlackText);
            LCD_DisplayChar(Line2, 35, (((Tmp%10000)/1000) + 0x30), BlackText);
            LCD_DisplayChar(Line2, 42, (((Tmp%10000)%1000)/100 + 0x30), BlackText);
            LCD_DisplayChar(Line2, 49, (((((Tmp%10000)%1000)%100)/10) + 0x30), BlackText);
            LCD_DisplayChar(Line2, 56, (((((Tmp%10000)%1000)%100)%10) + 0x30), BlackText);
            LCD_DisplayChar(Line2, 63, ' ', BlackText);
            LCD_DisplayChar(Line2, 70, 'H', BlackText);
            LCD_DisplayChar(Line2, 77, 'z', BlackText);
            break;

          case 5:
            LCD_ClearLine(Line2);
            Tmp = WAVE_FormatPlaying.BitsPerSample;
            if(Tmp == 8)
            {
              LCD_DisplayChar(Line2, 35, '8', BlackText);
              LCD_DisplayChar(Line2, 42, ' ', BlackText);
              LCD_DisplayChar(Line2, 49, 'B', BlackText);
              LCD_DisplayChar(Line2, 56, 'i', BlackText);
              LCD_DisplayChar(Line2, 63, 't', BlackText);
              LCD_DisplayChar(Line2, 70, 's', BlackText);
            }
            else if(Tmp == 16)
            {
              LCD_DisplayChar(Line2, 35, '1', BlackText);
              LCD_DisplayChar(Line2, 42, '6', BlackText);
              LCD_DisplayChar(Line2, 49, ' ', BlackText);
              LCD_DisplayChar(Line2, 56, 'B', BlackText);
              LCD_DisplayChar(Line2, 63, 'i', BlackText);
              LCD_DisplayChar(Line2, 70, 't', BlackText);
              LCD_DisplayChar(Line2, 77, 's', BlackText);
            }
            break;

        }/* End of Switch loop */
      }/* End of if loop (if(Tmp1 != Count) */
    }/* End of while (1) */
  }/* End of if loop (VALID_WAVE_FILE) */
  else
  {
    LCD_DisplayString(Line1, " Wave corrupted", BlackText);
    switch(WaveFileStatus)
    {
      case Unvalid_RIFF_ID:
        LCD_DisplayString(Line2, " Unvalid RIFF ID ", BlackText);
        break;
      case Unvalid_WAVE_Format:
        LCD_DisplayString(Line2, "Unvalid WAVE Fmt ", BlackText);
        break;
      case Unvalid_FormatChunk_ID:
        LCD_DisplayString(Line2, " Unvalid ChunkID ", BlackText);
        break;
      case Unsupporetd_FormatTag:
        LCD_DisplayString(Line2, " Unsupporetd Tag ", BlackText);
        break;
      case Unsupporetd_Number_Of_Channel:
        LCD_DisplayString(Line2, "Number Of Channel", BlackText);
        break;
      case Unsupporetd_Sample_Rate:
        LCD_DisplayString(Line2, "   Sample Rate   ", BlackText);
        break;
      case Unsupporetd_Bits_Per_Sample:
        LCD_DisplayString(Line2, " Bits Per Sample", BlackText);
        break;
      case Unvalid_DataChunk_ID:
        LCD_DisplayString(Line2, "  DataChunk ID  ", BlackText);
        break;
      case Unsupporetd_ExtraFormatBytes:
        LCD_DisplayString(Line2, "ExtraFormatBytes", BlackText);
        break;
      case Unvalid_FactChunk_ID:
        LCD_DisplayString(Line2, "  FactChunk ID  ", BlackText);
        break;
    default:
       break;
    }/* End of switch loop */
  }/* End of else loop */
}

/******************* (C) COPYRIGHT 2006 STMicroelectronics *****END OF FILE****/

