#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include "libsys.h"

#define	PI				3.1415926535897932384626433832795
#define	SAMPLE_RATE		48000
#define	BUF_SIZE		(2*4800)
#define	REC_BUF_SIZE	(5*60*2*SAMPLE_RATE)

INT32 *buffer;
INT32 *rec_buffer;
UINT32 buf_size;

INT32 * volatile pPtr_r;
INT32 * volatile pPtr_w;
UINT32 gcnt, led_cnt;
volatile INT32 sample_left, sample_right;

#define	AC97_REG_RESET		0x00
#define	AC97_REG_VOLO_MST	0x02
#define	AC97_REG_VOLO_HP	0x04
#define	AC97_REG_VOLO_MONO	0x06
#define	AC97_REG_VOLI_BEEP	0x0A
#define	AC97_REG_VOLI_PHONE	0x0C
#define	AC97_REG_VOLI_MIC	0x0E
#define	AC97_REG_VOLI_LINE	0x10
#define	AC97_REG_VOLI_CD	0x12
#define	AC97_REG_VOLI_VIDEO	0x14
#define	AC97_REG_VOLI_AUX	0x16
#define	AC97_REG_VOLI_PCM	0x18
#define	AC97_REG_REC_SRC	0x1A
#define	AC97_REG_REC_GAIN	0x1C
#define	AC97_REG_EXTCTRL	0x2A
#define	AC97_REG_RATE_DAC	0x2C
#define	AC97_REG_RATE_ADC	0x32

UINT32 ac97_status(UINT32 reg)
{
	UINT32 offset;
	volatile UINT32 *pAC_stat = (UINT32*)SYS_AC97_STAT;
	volatile UINT32 *pAC_stat_ac = (UINT32*)SYS_AC97_ACSTAT;

	offset = (reg & 0x7E);

	// Wait if previous command is still pending
	while(*pAC_stat & 1);

	*(pAC_stat_ac + offset) = 0;

	// Wait for data valid
	while(!(*pAC_stat & 2));

	return *pAC_stat_ac;
}

void ac97_ctrl(UINT32 reg, UINT16 value)
{
	UINT32 offset;
	volatile UINT32 *pAC_stat = (UINT32*)SYS_AC97_STAT;
	volatile UINT32 *pAC_ctrl_ac = (UINT32*)SYS_AC97_ACCTRL;

	offset = (reg & 0x7E);

	// Wait if previous command is still pending
	while(*pAC_stat & 1);

	*(pAC_ctrl_ac + offset) = value;

}

void ac97_isr_rec(void)
{
	int i, size;
	volatile UINT32 *pReg = (UINT32*)SYS_LED_PORT;
	volatile UINT32 *pAC_stat = (UINT32*)SYS_AC97_STAT;
	volatile INT32 *pAC_pcm = (INT32*)SYS_AC97_PCM;

	if (!gcnt)
	{
		gcnt = SAMPLE_RATE;
		*pReg = led_cnt++;
	}
	gcnt--;

	*pPtr_w++ = pAC_pcm[3];
	if (pPtr_w == &buffer[buf_size])
		pPtr_w = buffer;

	*pPtr_w++ = pAC_pcm[4];
	if (pPtr_w == &buffer[buf_size])
		pPtr_w = buffer;

	CP0_TR_write(pAC_pcm[3]);
	CP0_TR_write(pAC_pcm[4]);

}

void ac97_isr_play(void)
{
	int i, size;
	volatile UINT32 *pReg = (UINT32*)SYS_LED_PORT;
	volatile UINT32 *pAC_stat = (UINT32*)SYS_AC97_STAT;
	volatile INT32 *pAC_pcm = (INT32*)SYS_AC97_PCM;

	if (!gcnt)
	{
		gcnt = SAMPLE_RATE;
		*pReg = led_cnt++;
	}
	gcnt--;

	*pAC_pcm = *pPtr_r++;
	if (pPtr_r == &buffer[buf_size])
		pPtr_r = buffer;
}

void ac97_isr_pass(void)
{
	int i, size;
	volatile UINT32 *pReg = (UINT32*)SYS_LED_PORT;
	volatile UINT32 *pAC_stat = (UINT32*)SYS_AC97_STAT;
	volatile INT32 *pAC_pcm = (INT32*)SYS_AC97_PCM;

	if (!gcnt)
	{
		gcnt = SAMPLE_RATE;
		*pReg = led_cnt++;
	}
	gcnt--;

	if (*pAC_stat & 0x08)
	{

//		CP0_TR_write(pAC_pcm[3]);
//		CP0_TR_write(pAC_pcm[4]);

		*pPtr_w++ = pAC_pcm[3];
		if (pPtr_w == &buffer[buf_size])
			pPtr_w = buffer;

		*pPtr_w++ = pAC_pcm[4];
		if (pPtr_w == &buffer[buf_size])
			pPtr_w = buffer;
	}

	if (pPtr_r != pPtr_w)
	{
		*pAC_pcm = *pPtr_r++;
		if (pPtr_r == &buffer[buf_size])
			pPtr_r = buffer;
	}

}

int main (void)
{
	int result, i, j;
	volatile UINT32 *pReg = (UINT32*)SYS_LED_PORT;
	volatile UINT32 *pGPIO1 = (UINT32*)SYS_GPIO1;
	volatile UINT32 *pAC_ctrl = (UINT32*)SYS_AC97_CTRL;
	volatile UINT32 *pAC_stat = (UINT32*)SYS_AC97_STAT;
	volatile UINT32 *pAC_ctrl_ac = (UINT32*)SYS_AC97_ACCTRL;
	volatile UINT32 *pAC_stat_ac = (UINT32*)SYS_AC97_ACSTAT;
	volatile UINT32 *pAC_pcm = (UINT32*)SYS_AC97_PCM;
	double phi, dphi, y, mean;
	char sel, cmd;
	char buf[1024];
	FILE *pFile = stdout;

//	setbuf(stderr, NULL);
//
	fprintf(pFile, "AC-97 Test\n");
	fprintf(pFile, "Status         : %8.8X\n", *pAC_ctrl);

	ac97_ctrl(AC97_REG_VOLO_MST, 0);
	ac97_ctrl(AC97_REG_VOLO_HP, 0);
	ac97_ctrl(AC97_REG_VOLI_LINE, 0x8808);
	ac97_ctrl(AC97_REG_VOLI_PCM, 0x0808);
	ac97_ctrl(AC97_REG_REC_SRC, 0x0404);
	ac97_ctrl(AC97_REG_REC_GAIN, 0);
	ac97_ctrl(AC97_REG_EXTCTRL, 1);

	ac97_ctrl(AC97_REG_RATE_DAC, SAMPLE_RATE);
	ac97_ctrl(AC97_REG_RATE_ADC, SAMPLE_RATE);

	led_cnt = 0;
	gcnt = SAMPLE_RATE;

	fprintf(pFile, "DAC-Rate       : %d\n", ac97_status(AC97_REG_RATE_DAC));
	fprintf(pFile, "ADC-Rate       : %d\n", ac97_status(AC97_REG_RATE_ADC));

	*pGPIO1	= 0x04;

	while(1)
	{
		fprintf(pFile, "Aufnehmen und Abspielen (1)\n");
		fprintf(pFile, "Sinus Ton               (2)\n");
		fprintf(pFile, "Pass through            (3)\n");
		fprintf(pFile, "Eingabe: ");

		scanf("%c", &sel);
//		sel = 0x31;

		if (sel == 0x31)
		{
			buf_size = REC_BUF_SIZE;
			buffer = (INT32*)malloc(REC_BUF_SIZE*sizeof(INT32));
//			memset(buffer, 0, sizeof(REC_BUF_SIZE*sizeof(INT32)));
			pPtr_r = buffer;
			pPtr_w = buffer;

			ac97_ctrl(AC97_REG_VOLI_LINE, 0x0808);

			cmd = 0;
			while(1)
			{
				switch (cmd)
				{
					case 'r':
					ac97_ctrl(AC97_REG_VOLI_LINE, 0x0808);
					pPtr_w = buffer;
					fprintf(pFile, "Aufnahme\n");
					interrupt_register(5, ac97_isr_rec);
					interrupt_enable(5);
					*pAC_ctrl = 0x24;
					break;

					case 'p':
					ac97_ctrl(AC97_REG_VOLI_LINE, 0x8808);
					pPtr_r = buffer;
					fprintf(pFile, "Wiedergabe\n");
					interrupt_register(5, ac97_isr_play);
					interrupt_enable(5);
					*pAC_ctrl = 0x12;
					break;

					case ' ':
					ac97_ctrl(AC97_REG_VOLI_LINE, 0x0808);
					fprintf(pFile, "Stop\n");
					memset(buffer, 0, sizeof(REC_BUF_SIZE*sizeof(INT32)));
					*pAC_ctrl = 0x00;
					pPtr_r = buffer;
					pPtr_w = buffer;
					break;

					default:
						fprintf(pFile, "Aufnahme   (R)\n");
						fprintf(pFile, "Wiedergabe (P)\n");
						fprintf(pFile, "Stop       (Space)\n");
					break;
				}
				cmd = readchar(0);
			}
		}
		if (sel == 0x32)
		{
			buf_size = BUF_SIZE;
			buffer = (INT32*)malloc(REC_BUF_SIZE*sizeof(INT32));
			memset(buffer, 0, sizeof(REC_BUF_SIZE*sizeof(INT32)));
			pPtr_r = buffer;
			pPtr_w = buffer;

			dphi = 120*2*PI/BUF_SIZE;
			phi = 0;
			for (i=0; i < BUF_SIZE/2; i++)
			{
				y = cos(phi);
				buffer[2*i+0] = (INT32)(32000*y);
				buffer[2*i+1] = (INT32)(32000*y);
				phi = fmod((phi + dphi), 2.0*PI);
			}

			fprintf(stderr, "Status         : %8.8X\n", *pAC_ctrl);

			interrupt_register(5, ac97_isr_play);
			interrupt_enable(5);
			*pAC_ctrl = 0x12;

			fprintf(stderr, "Status         : %8.8X\n", *pAC_ctrl);

			while(1)
			{
				fprintf(stderr, "Status         : %8.8X\n", *pAC_ctrl);
			}
		}
		if (sel == 0x33)
		{

			buf_size = BUF_SIZE;
			buffer = (INT32*)malloc(BUF_SIZE*sizeof(INT32));
			memset(buffer, 0, sizeof(BUF_SIZE*sizeof(INT32)));
			pPtr_r = buffer;
			pPtr_w = buffer;
			*pAC_ctrl = 0x32;
			interrupt_register(5, ac97_isr_pass);
			interrupt_enable(5);

			fprintf(stdout, "Status         : %8.8X\n", *pAC_ctrl);

			while(1);
		}
	}

	return 0;

}

