/* 	Speech Recorder Project For S.C.
   	Author: 	Mauro Grassi
	Date:		20 April, 2009.

	Important Note: if programming using PicKit2 use the programming executive!

	Preliminary Versions:

	0.10	: this is the first version with very rudimentary SD card drivers.
	0.11	: adding support for better initialization and detection of V1.0 or V2.0 SD cards via CMD8 response
	0.12	: added support for CID and CSD register fields automatically filled in...
	0.20	: this version has the correct initialisation procedure to detect ver 1 or 2 SD Cards and whether it is High Capacity or not!
			  it fills in the CARD_INFO Structure with CID, CSD, OCR registers and whether an error occured in the initialisation, say
		      if the inserted card was MMC instead of SD for eg.
	0.30	: this version adds support for SDHC cards from 2Gb to 32Gb capacity, there is support for ver1 and ver2 of CSD register, etc.
	0.40	: adds support for single block read and write functions as well as hardware assisted CRC16 on data blocks 
			  (even though CRC checking is disabled by default in SPI mode)
	0.50	: file tree structure cleaned up
	0.60	: added full support for MMC Cards as well, with date conversion to SD format for CID register and so on...
	0.64	: added support for multiple block read and write
	0.66	: transitional preliminary FATFs port version (changed the meaning of CARD_TYPE and removed SD_VERSION fields)
	0.67	: added ACMD13 response (MMC cards don't seem respond to this!)
	0.68	: preliminary version without ezlcd code for the sd.c routines...
	0.69	: transitional...
	0.70	: first version to incorporate FAT-FAT32 file system for MMC/SD/SDHC cards. Seems to work to open and read files as far as
			  the (limited) testing has uncovered so far...
	0.71	: changed system clock to external 10MHz crystal and PLL configured to 40MIPS operation (which is the maximum allowed).
	0.72	: transitional version for RTC module (real time clock)
	0.75	: full RTC support and FAT time updated to use the real time clock.
	0.76	: switch to OLED display from EzLCD module.
	0.77	: further OLED drivers
	0.78	: transitional version (good) with file write and read test and OLED test and RTC test
	0.79	: transitional DAC support version
	0.80	: first DAC preliminary version with DAC interrupts generating Sawtooth.
	0.81	: transitional version.
	0.82	: transitional version.
	0.83	: "Testing 1" wave file test version (good).
	0.84	: ping pong buffer transitional version!
	0.85	: transitional version...
	0.86	: first version with full wav playback from SD card @ 8kHz.
	0.87	: trial 16kHz?
	0.88	: this version we changed from using a 10Mhz crystal to a 24.576Mhz crystal. So the PLL settings are different. Slightly slower
			  resulting MIPS at 38.912MIPS but exact DAC frequencies for 8000Hz and 16000Hz sampling.
			  This version speeds up the SPI bus for SD cards to InitSPI(0x1E) for all types and can playback WAV files at 16kHz!
	0.89	: transitional version.
	0.90	: first version plays A-law compressed data from file mauro.alc at 8kHz.
	0.91	: transitional version
	0.92	: transitional version.
	0.93	: elvis 32000 version!
	0.94	: elvis 16000 version! - fixed the problem with primary oscillator was set to XT should be HS for the new 24.576MHz crystal!
	0.95	: smashing pumpkins at 22050 version...
	0.96	: transitional version
	0.97	: transitional preliminary ADC support version.
	0.98	: simple loop back version.
	0.99	: transitional version.
	0.991	: experimental transitional.
	0.992	: experimental transitional.
	0.993	: experimental transitional - some issues still.
	0.994	: experimental transitional (!!)
	0.995	: experimental transitional 
	0.9951  : experimental transitional
	0.9952  : experimental transitional
	0.996   : experimental transitional
	0.9961  : ditto
	0.9962  : ditto
	0.9963  : ditto
	0.9964  : ditto
	0.9965  : ditto
	0.997   : fixed disk_write for SDHC cards to convert sector address.
	0.9971	: transitional
	0.9972	: transitional
	0.998	: changed to 10Mhz crystal again.
	0.999	: experimental record version (good)
	0.9991	: experimental with record loop back...	
	0.9992	: experimental version
	0.9994	: experimental version...
	0.9995	: experimental version with electret!
	0.9996	: over sampling (up to 8 times) on ADC version
	0.9997	: first version with LCD 5453MM driver support
	0.9998	: good version with LCD 5453MM driver support.
	0.99991 : transitional
	0.99992	: last version with LCD 5453MM driver support
	1.0		: first version with LCD 16 x 2 support & first version with IR (infra red remote control) support
	1.01	: soft volume?
	1.02	: fast soft volume using fixed arithmetic and built in multiply instructions...
	1.10	: improved play WAV services through playrecord.c and callbacks, added disFLCD functions.
	1.12    : improved LCD routines.
	1.13    : improved LCD routines using SPI bus multiplexed with SD card bus (we save one pin)
	1.15	: transitional
	1.16	: changed to 8 bit mode for LCD.
	1.17	: transitional
	1.18	: added support for reading directory entries.
	1.20	: power saving features for battery back up of RTCC
	1.24	: dropped support for RTCC to gain pins. Now we have 8 push button switches...
	1.30	: with buttons on the PORTA4 pin
	1.40	: changed pin outs to be compatible with PC board
	1.44	: first version with flash memory support. EEPROM emulation using FLASH memory. Can store up to 512 (3 byte) longs in non-volatile (program) memory.
	1.46	: added some support for selecting File.
	1.48	: fuller support for select file.
	1.49	: transitional version.
	1.50	: select file support. Play and Pause display. etc.
	1.52	: improved navigation and record file name generation!
	1.56	: improved navigation with string.h support built in streamlined functions in playrecord.c
	1.60	: ditto
	1.64	: improved LCD and OLED information
	1.70	: works with stereo and mono streams...
	1.72	: minor improvements
	1.74	: enabled nested interrupts
	1.76	: first PC version
	1.78	: increased the buffer size to 5120 from 4096.
	1.79	: transitional
	1.80	: transitional
	1.90	: first version that you can select Line In or Microphone input. Use RECORD button to record Mic input or LINE button to record Line In input.
	1.92	: now responds to button presses...
	1.94	: first with delete a file option.
	1.96	: blinking LEDs
	1.97	: transitional
	1.98	: transitional
	1.99	: transitional
	2.00	: add support for Jaycar or Altronics LCD (can switch between LCDs by pressing BUTTON4 & BUTTON8 at startup) 
			: & added support for one touch recording and playback for BUTTONS config (selected if the file buttons.txt is present in root folder on boot up).
	2.10	: very much improved frizzle response by turning off DAC amplifiers when no audio is being played. Much improved from previous versions.
	2.12	: ameliorate amplifier turn on and speaker clip
	2.14	: added support for defining the remote control codes...
	2.16	: added random plays
	2.18	: minor improvements.
	2.20	: added on board button support for random shuffle play.
	2.30	: changed Mb to MB
	2.40	: stopped blinking of LEDS on play and record.
	2.51	: changed to start pointing to a file rather than root folder.
	2.52	: debug version & cleaned up OLED code.
	2.53	: debug version.
	2.60	: fixed 2Gb SD card peculiarity (2Gb cards report block length 1024 bytes which stuffs up the reads if you don't put a CMD12 after a single block read). Fixed problem with RND locking up with a directory in the 
			: root folder. Minor improvements to play wav file, we now check the file is a WAV file before playing it so the play LED does not light up momentarily when the file is not of type WAV.
    2.61    : added workaround for buggy SD card controllers (retry reads/writes up to three times upon error)
*/

#define VERSION 2.61

#include "h/p33FJ64GP802.h"
#include "h/types.h"
#include "h/common.h"
#include "h/i2c.h"
#include "h/spi.h"
#include "h/sd.h"
#include "h/show.h"
#include "h/crc.h"
#include "h/ff.h"
#include "h/pll.h"
#include "h/oled.h"
#include "h/dac.h"
#include "h/g711.h"
#include "h/adc.h"
#include "h/wav.h"
#include "h/lcd16x2.h"
#include "h/ir.h"
#include "h/playrecord.h"
#include "h/clock.h"
#include "h/buttons.h"
#include "h/flashmem.h"
#include "h/string.h"

_FICD(BKBUG_ON & COE_ON & JTAGEN_OFF & ICS_PGD1);
_FBS(RBS_NO_RAM & BSS_NO_FLASH & BWRP_WRPROTECT_OFF);
_FSS(RSS_NO_RAM & SSS_NO_FLASH & SWRP_WRPROTECT_OFF);
_FGS(GSS_OFF & GCP_OFF & GWRP_OFF);
_FOSCSEL(FNOSC_PRIPLL & IESO_OFF);
_FOSC(FCKSM_CSECMD & OSCIOFNC_OFF & POSCMD_HS);
_FWDT(FWDTEN_OFF & WDTPOST_PS1024 & WDTPRE_PR32);

// Global Variables
int jaycarLCD;

void delayMs(int x)
{
	int i;
	while(x>0)
	{
		for(i=0; i<8000; i++)
		{
		asm("nop");
		}
		x--;
	}
}

void __attribute__((interrupt, no_auto_psv))_OscillatorFail(void)
{
    INTCON1bits.OSCFAIL=0;
}    

void __attribute__((interrupt, no_auto_psv))_MathError(void)
{
    INTCON1bits.MATHERR=0;
}    

void __attribute__((interrupt, no_auto_psv))_StackError(void)
{
    INTCON1bits.STKERR=0;
}    

int confirm(void)
{
	int k;

#if (USE_LCD)
	writeStringLCD(0,    "Are You Sure?   ", 16);
	writeStringLCD(0x40, "STOP: Yes       ", 16);
#endif

#if (USE_OLED)
	writeStringAtOLED(0, 0, "Are You Sure?");
	
#endif

	while(checkButtons()!=0);
	k=0;
	while((keyFull==0)&&(k==0))
	{
	k=checkButtons();
	}
	if((k==BUTTON4)||(getKey()==KEYSTOP))return 1;
	else return 0;
}

int randomPlay;

int main(void)
{
	unsigned int 	i;
	unsigned long 	x;
	char* 			selectedFileName;
	int 			key;
	int 			index;
	FRESULT			result;
	int 			mode;
	int 			k;

	PORTB=0xFFFF;
	TRISB=0xF020;
	TRISA=0xFFFF;
	initPLL();
	//INTCON1bits.NSTDIS=1;
	initRC5();
	initTime();
	initButtons();
	initDAC();
	startPlay(13,1);
	endPlay();
	initADC();
	initKeys();
	initFF();
	jaycarLCD=readFlashMemory(JAYCARLCD_ADDR);
	InitSPI(0x00);
	mode=0;
	k=checkButtons();	
	if(k==(BUTTON4 | BUTTON8))
	{
	jaycarLCD&=1;
	jaycarLCD^=1;
	writeFlashMemory(JAYCARLCD_ADDR, jaycarLCD);
	} else
	if(k==(BUTTON2 | BUTTON6))
	{
	mode=1;
	}
	LED1=0;
	initLCD();
#if (USE_OLED)
	initOLED();
#endif
	
#if (USE_LCD)
	writeStringLCD(0, "Speech Recorder", 16);
	writeStringLCD(0x40, "Version: ", 16);
	disFUnsignedLCD(0x49, VERSION, 2, 0, 0);
#endif

#if (USE_OLED)
	clsOLED();

	setColourOLED(COLOUR0);
	writeStringAtOLED(0, 0, "Speech Recorder");
	writeStringAtOLED(0, 1, "Version: ");
	disFUnsignedOLED(9, 1, VERSION, 2, 0, 2);
#endif
	delayMs(1500);

	if(mode)
	{
#if (USE_LCD)
	writeStringLCD(0,    " Define Remote  ", 16);
	writeStringLCD(0x40, "    Control     ", 16);
	delayMs(1500);
	reDefineRemoteControlCodes();
#endif
	}

	LED1=1;
	LED2=0;
	
#if (USE_DEBUG)
	initUART();
#endif

	if(InitSDMMCCardSPI(&cardInfo))
	{
#if (USE_LCD)
	writeStringLCD(0, 		"Size(MB): ", 16);
	disFUnsignedLCD(10, cardInfo.SIZE/1000.0, 1, 0, 0);
	writeStringLCD(0x40, 	"Free(MB):  ", 16);
	disFUnsignedLCD(0x4A, getFreeKiloBytes()/1000.0, 1, 0, 0);
#endif

#if (USE_OLED)
	setColourOLED(COLOUR1);
	writeStringAtOLED(0, 0, "Size(Mb): ");
	disFUnsignedOLED(10, 0, cardInfo.SIZE/1000.0, 1, 0, 6);
	writeStringAtOLED(0, 1, "Free(Mb): ");
	disFUnsignedOLED(10, 1, getFreeKiloBytes()/1000.0, 1, 0, 6);
#endif

	} else
	{
#if (USE_LCD)
	writeStringLCD(0, 	 "    No  Card    ", 16);
	writeStringLCD(0x40, "    Detected    ", 16);
#endif
#if (USE_OLED)
	writeStringAtOLED(0, 1, "No Card Present");
#endif

	LED2=1;
	LED1=1;
	while(1)
	{
		LED2=0;
		LED1=1;
		delayMs(500);
		LED2=1;
		LED1=0;
		delayMs(500);
	}

	}
	delayMs(1500);

/*
	while(1)
	{
	i=checkButtons();
	disaLCD(0x40, i>>8);
	disaLCD(0x42, i);
	delayMs(100);
	}
*/

	randomPlay=0;

#if (USE_LCD)
	writeStringLCD(0, 		"     Reading    ", 16);
	writeStringLCD(0x40, 	"     Config.    ", 16);
	delayMs(1000);
#endif
	mode=0;
	result=f_open(&fsrc, "trigger.txt", FA_OPEN_EXISTING | FA_READ);
	if(result==0)
	{
#if (USE_LCD)
	writeStringLCD(0, 		"     Trigger    ", 16);
	writeStringLCD(0x40, 	"     Config.    ", 16);
	delayMs(1000);
#endif
	mode=1;
	} else
	{
#if (USE_LCD)
	writeStringLCD(0, 		"     Normal     ", 16);
	writeStringLCD(0x40, 	"     Config.    ", 16);
	delayMs(1000);
#endif
	}
	f_close(&fsrc);

	if(mode==0)
	{
	LED2=1;
	pathName[0]='\0';
	selectedFileName=&pathName[0];
	index=1;
	while(1)
	{

	if(randomPlay==1)
	{
		i=countEntries("");
		getRandomTrack("", i);
		if(isWAVFile(pathName))
		{
		LED2=0;
		playWAVFile(pathName, playCallBack,0);
		LED2=1;
		}
		k=checkButtons();
		if(k==BUTTON4)randomPlay=0;
		if(randomPlay==0)
		{
		pathName[0]='\0';
		selectedFileName=&pathName[0];
		index=1;
		}	
	} else
	{

#if (USE_LCD)
 	selectedFileName=selectFile(selectedFileName, &key, &index, 2, displayCallBackLCD);
#elif (USE_OLED)
	selectedFileName=selectFile(selectedFileName, &key, &index, 4, displayCallBackOLED);
#endif

		if(key==KEYFF)
		{
			randomPlay=1;
		} else
		if((key==KEYPLAY)||(key==KEYOK))
 		{
			if(isWAVFile(selectedFileName))
			{
			LED2=0;
			playWAVFile(selectedFileName, playCallBack,0);
			LED2=1;
			}
		} 
		else
		if((key==KEYRECORD)||(key==KEYLINE))
		{
		LED1=0;
		if(key==KEYRECORD)adcCh=0; else adcCh=1;
		if((*selectedFileName)!='\0')
		 {
		 selectedFileName=stripFileName(selectedFileName); 		
 		 *selectedFileName='/';
		 selectedFileName++;
		 x=1;
		 while(x<999)
		 {		 
		 fileName1[0]='r';
		 fileName1[1]='e';
		 fileName1[2]='c';
		 i=iitoa(x,&fileName2[0],10,0);
		 fileName1[3]=fileName2[i-4];
		 fileName1[4]=fileName2[i-3];
		 fileName1[5]=fileName2[i-2];
		 fileName1[6]='.';
		 fileName1[7]='w';
		 fileName1[8]='a';
		 fileName1[9]='v';
		 fileName1[10]='\0';
		 copyString(selectedFileName, fileName1);
		 result=f_open(&fsrc, &pathName[0], FA_OPEN_EXISTING | FA_READ );
		 if(result!=0)break; 
		 f_close(&fsrc);
		 x++;
		 }
		 
		 i=recordWAVFile(&pathName[0], recordCallBack, 0);
		 LED1=1;
		 writeStringLCD(0, "Recorded:", 16);
		 writeStringLCD(0x40, fileName1, 16);
		 delayMs(2000);
		 } else LED1=1;
		} else
		if(key==KEYMENU)
		{
#if (USE_LCD)
		writeStringLCD(0, 	 "    Deleting    ", 16);
		writeStringLCD(0x40, "      File      ", 16);
		delayMs(1000);
#endif

#if (USE_OLED)

#endif
		if(confirm())
			{
				f_unlink(selectedFileName);
#if (USE_LCD)
				writeStringLCD(0, 	 "      File      ", 16);
				writeStringLCD(0x40, "     Deleted    ", 16);  
				delayMs(2000);
#endif	

#if (USE_OLED)

#endif
			} 
		}
		stripFileName(selectedFileName);
	 }
	}
	} 
	else
	{
		LED2=1;
		while(1)
		{
			k=0;
			while((k==0)&&(keyFull==0))k=checkButtons();
			key=getKey();
			fileName1[0]='r';
			fileName1[1]='e';
			fileName1[2]='c';
			fileName1[3]='0';
			fileName1[4]='0';
			fileName1[5]='0';
			fileName1[6]='.';
			fileName1[7]='w';
			fileName1[8]='a';
			fileName1[9]='v';
			fileName1[10]='\0';
			if((k==BUTTON1)||(key==KEYONE))
			{
			fileName1[5]='1';
			} else
			if((k==BUTTON2)||(key==KEYTWO))
			{
			fileName1[5]='2';
			} else
			if((k==BUTTON3)||(key==KEYTHREE))
			{
			fileName1[5]='3';
			} else
			if((k==BUTTON4)||(key==KEYFOUR))
			{
			fileName1[5]='4';
			}
			else
			if((k==BUTTON5)||(key==KEYFIVE))
			{
			fileName1[5]='5';
			} else
			if((k==BUTTON6)||(key==KEYSIX))
			{
			fileName1[5]='6';
			} else
			if((k==BUTTON7)||(key==KEYSEVEN))
			{
			fileName1[5]='7';
			} else
			if((k==BUTTON8)||(key==KEYEIGHT))
			{
			fileName1[5]='8';
			} else
			if(key==KEYNINE)
			{
			fileName1[5]='9';
			}
			LED2=0;
			i=playWAVFile(fileName1, playMinimalCallBack, 0);
			LED2=1;
#if (USE_LCD)
				writeStringLCD(0, 	 "Played:", 16);
				writeStringLCD(0x40, fileName1, 16);
#endif	
		}
	}
}
