/**
*****************************************************************************
**
**  File        : main.c
**
**  Abstract    : main function.
**
**  Functions   : main
**
**  Environment : Atollic TrueSTUDIO/STM32
**                STMicroelectronics STM32F10x Standard Peripherals Library
**
**  Distribution: The file is distributed “as is,” without any warranty
**                of any kind.
**
**  (c)Copyright Atollic AB.
**  You may use this file as-is or modify it according to the needs of your
**  project. Distribution of this file (unmodified or modified) is not
**  permitted. Atollic AB permit registered Atollic TrueSTUDIO(R) users the
**  rights to distribute the assembled, compiled & linked contents of this
**  file as part of an application binary file, provided that it is built
**  using the Atollic TrueSTUDIO(R) toolchain.
**
**
*****************************************************************************
*/

/* Includes */


#include <stddef.h>
#include <string.h>
#include "stm32f10x.h"
#include "UART.h"
#include "pff.h"
#include "SPI.h"
#include "diskio.h"
#include "MAX9850.h"
#include "mp3dec.h"
#include "mp3common.h"



void system_startup(void);
void GPIO_Configuration(void);


static HMP3Decoder hMP3Decoder; // Content is the pointers to all buffers and information for the MP3 Library

#define MAX_FRAME_SIZE 4000
#define MP3_INVALID_FRAMEHEADER -6

int read_more(unsigned char *readBuf, unsigned char *readPtr, int bufSize, int bytesLeft)
{
    /* This function will move bytesLeft bytes from
     * readPtr to the top of readBuf. bufSize is the
     * size of readBuf. It then reads bufSize - bytesLeft bytes
     * from infile and appends these bytes to readBuf.
     * If readBuf is not full, then remaing bytes are
     * set to zero. The total number of bytes read from
     * infile is returned.
     */

    WORD nRead;

    /* move last, small chunk from end of buffer to start, then fill with new data */
    memmove(readBuf, readPtr, bytesLeft);
    pf_read( readBuf + bytesLeft, bufSize - bytesLeft, &nRead);
    /* zero-pad to avoid finding false sync word after last frame (from old data in readBuf) */
    if (nRead < bufSize - bytesLeft)
        memset(readBuf + bytesLeft + nRead, 0, bufSize - bytesLeft - nRead);

    return nRead;
}


/**
**===========================================================================
**
**  Abstract: main program
**
**===========================================================================
*/
int main(void)
{
	RCC_ClocksTypeDef RCC_ClocksStruct;
	FATFS fs;
	uint8_t resultat = 0;
	WORD br;
	char buff1[4000];
	unsigned char input[MAX_FRAME_SIZE];
	signed long offset = -1;
	int error;
	MP3FrameInfo frameInfo;
	DWORD bytes_read = 0;

	system_startup();
	GPIO_Configuration();
	lib_uart_init();
	MAX9850_init_Port();
	MAX9850_init_chip();
	MAX9850_SHDN(1);

	DMA_InitTypeDef    DMA_InitStructure;

	DMA_DeInit(DMA1_Channel5);  //SPI2_TX Channel
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0x4000380C;
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buff1;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
	DMA_InitStructure.DMA_BufferSize = (sizeof(buff1)/2);
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	DMA_Init(DMA1_Channel5, &DMA_InitStructure);



	SPI_I2S_DMACmd(SPI2,SPI_I2S_DMAReq_Tx, ENABLE); //SPI kann DMA benutzen



	/* Initilizes the MP3 Library */
	hMP3Decoder = MP3InitDecoder();


	resultat = disk_initialize();
	resultat = pf_mount(&fs);
	resultat = pf_open("myfile.mp3");

	if(resultat != 0)	//SD-Karten Probleme
	{
		while(1);
	}


	short output[2*1152];
	int bytesLeft = 0;
	int err;
	int nRead = 0;
	unsigned char *readPtr;

	bytesLeft = 0;
	readPtr = input;



	if(hMP3Decoder == 0)	//Prüfen ob Speicher allocation geklappt hat.
	{
		while(1);
	}
	else
	{
		offset = -1;
		while(offset<0)
		{
			pf_read(input,MAX_FRAME_SIZE,&br); //Lesen der anzahl Bytes aus max_frame_size in den Buffer input
			bytesLeft = br;
			offset = MP3FindSyncWord(readPtr,bytesLeft);
			if(offset < 0)
			{
				readPtr = input;
			}
		}
		readPtr += offset;
		bytesLeft -= offset;

		MP3GetNextFrameInfo(hMP3Decoder,&frameInfo,readPtr);
	}


	while(1)
	{
		err = MP3Decode(hMP3Decoder,&readPtr,&bytesLeft,output,1);
		if(err == -2)
		{
			nRead = read_more(input,readPtr,MAX_FRAME_SIZE,bytesLeft);
			bytesLeft += nRead; //Die anzahl gelesener Bytes zu der Anzahl noch nicht dekodierter hinzufügen
			readPtr = input; //Pointer neu setzen
		}
		if(err == -6)
		{
			offset = -1;
			while(offset<0)
			{
				pf_read(input,MAX_FRAME_SIZE,&br);
				bytesLeft = br;
				offset = MP3FindSyncWord(readPtr,bytesLeft);
				if(offset < 0)
				{
					readPtr = input;
				}
			}

			readPtr += offset;
			bytesLeft -= offset;

			MP3GetNextFrameInfo(hMP3Decoder,&frameInfo,readPtr);

		}
	}

	///////////////// Ab hier hat es nichts mehr mit dem MP3 decoder zu tun! //////////////////

	RCC_GetClocksFreq(&RCC_ClocksStruct);
	lib_spi_cs(0);
	lib_spi_cs(1);




	DMA_Cmd(DMA1_Channel5, ENABLE);

	for(;;)
	{

		while(!DMA_GetFlagStatus(DMA1_FLAG_HT5)); //Warte bis HALBER Transfer abgeschlossen
		resultat = pf_read(buff1, (sizeof(buff1)/2), &br); //untere 512bytes auffüllen
		DMA_ClearFlag(DMA1_FLAG_HT5);

		while(!DMA_GetFlagStatus(DMA1_FLAG_TC5)); //Warte bis gesamter Transfer abgeschlossen
		resultat = pf_read(&buff1[sizeof(buff1)/2], (sizeof(buff1)/2), &br); //obere 512bytes auffüllen
		DMA_ClearFlag(DMA1_FLAG_TC5);

	}

	MAX9850_SHDN(0);	//MAX deaktivieren





	uart_puts("--- Willkommen beim STM32 ---\n");
	uart_puts("SYSCLK: ");
	uart_send_var((RCC_ClocksStruct.SYSCLK_Frequency) / 1000000);
	uart_puts("MHz\n");
	uart_puts("HCLK: ");
	uart_send_var((RCC_ClocksStruct.HCLK_Frequency) / 1000000);
	uart_puts("MHz\n");
	uart_puts("PCLK1: ");
	uart_send_var((RCC_ClocksStruct.PCLK1_Frequency) / 1000000);
	uart_puts("MHz\n");
	uart_puts("PCLK2: ");
	uart_send_var((RCC_ClocksStruct.PCLK2_Frequency) / 1000000);
	uart_puts("MHz\n");
	uart_puts("------------ ADC ------------\n");





	while(1)
	{

	}
}


void GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	//////// SPI1 GPIO ////////////
	//PA4 CS
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	//PA5 SCK, PA7 MISO
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	//PA6 MOSI = Floating
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	//PB6 Alternate Function PushPull (SCL I2C1, WS, SCK, SD von I2S2)
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	//PB6 Alternate Function PushPull (SCL I2C1)
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	// MCLK PC6 von I2S2
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(GPIOC, &GPIO_InitStructure);




}


void system_startup(void)
{
	ErrorStatus HSEStartUpStatus;
	RCC_DeInit();

	/* Enable HSE */
	RCC_HSEConfig(RCC_HSE_ON);

	/* Wait till HSE is ready */
	HSEStartUpStatus = RCC_WaitForHSEStartUp();

	if (HSEStartUpStatus == SUCCESS)
	{
		/* Enable Prefetch Buffer */
		FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

		/* Flash 2 wait state */
		FLASH_SetLatency(FLASH_Latency_2);

		/* HCLK = SYSCLK */
		RCC_HCLKConfig(RCC_SYSCLK_Div1);

		/* PCLK2 = HCLK */
		RCC_PCLK2Config(RCC_HCLK_Div1);

		/* PCLK1 = HCLK/2 */
		RCC_PCLK1Config(RCC_HCLK_Div2);


		/* PLL configuration: PLLCLK = (HSE (8MHz) / 1) * 9 = 72 MHz */
		RCC_PREDIV1Config(RCC_PREDIV1_Source_HSE, RCC_PREDIV1_Div1);
		RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);

		/* Enable PLL */
		RCC_PLLCmd(ENABLE);

		/* Wait till PLL is ready */
		while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

		/* Select PLL as system clock source */
		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

		/* Wait till PLL is used as system clock source */
		while(RCC_GetSYSCLKSource() != 0x08);

		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);	//MCLK PC6

		RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

		RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);	//I2S2

		RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //DMA1 Aktivieren


	}

}






/*
 * Minimal __assert_func used by the assert() macro
 * */
void __assert_func(const char *file, int line, const char *func, const char *failedexpr)
{
  while(1)
  {}
}

/*
 * Minimal __assert() uses __assert__func()
 * */
void __assert(const char *file, int line, const char *failedexpr)
{
   __assert_func (file, line, NULL, failedexpr);
}


