/*******************************************************************************
 * C H A M E L E O N   ColdFire C file                                         *
 *******************************************************************************
 * Programmed by Aleix Riera                                                   *
 * www.fjarre.com/~aleix                                                       *
 * aleix@fjarre.com                                                            *
 *******************************************************************************
 * www.soundart-hot.com                                                        *
 * support@soundart-hot.com                                                    *
 ******************************************************************************
 * Sounth Pole was conceived by:                                               *
 * Jordi Trujillo (LlunaSol)                                                   *
 * Thanks for all, Jordi!                                                      *
 *******************************************************************************
 * SOUTH POLE ONLINE:                                                          *
 * www.fjarre.com/~aleix/southpole                                             *
 ******************************************************************************/
	
#include <stdlib.h>
#include <stdio.h>
#include <rtems.h>
#include <math.h>
#include <string.h>
#include <chameleon.h>
#include "spole.h"

#include "dsp/dsp_code.h"
	
/******************************************************************************/
#define WORKSPACE_SIZE	128*1024
rtems_unsigned32 rtems_workspace_size = WORKSPACE_SIZE;
rtems_unsigned32 rtems_workspace_start[WORKSPACE_SIZE];
/******************************************************************************/

TSouthPoleVariables		Actual;
TSouthPoleFactoryPresets	SP_Presets[MAX_PRESETS_SIZE];

rtems_unsigned8		Volume;		//global volume

rtems_unsigned8		pot;		//wich potentiometer?
rtems_unsigned8		value;		//of potentiometer
rtems_unsigned8		encoder;	//wich encoder?
rtems_signed8		inc;		//wich increment?
rtems_unsigned32	key;		//wich key?
rtems_unsigned32	led_bits;	//leds.c

//handlers
int			panel;
int			dsp;
int			flash;

int			flash_preset;		//indexing flash
int			menu_index_part,	//indexing menu
			menu_index_group,
			menu_index_page,
			menu_index_param;

char			text0[PANEL_LCD_MAX_LINE_LEN+1],//[17]
			text1[PANEL_LCD_MAX_LINE_LEN+1];

static char		menu[OPTIONS][PANEL_LCD_MAX_LINE_LEN+1];//contains the options strings

static rtems_signed32	log_table[TABLE_LEN];		//[0..1] LOG
static rtems_signed32	nolog_table[TABLE_LEN];		//[0..1] LIN
static rtems_signed32	delaytime_table[TABLE_LEN];	//DELAY TIME
static rtems_signed32	amp_table[TABLE_LEN];		//AMPLITUDES
static rtems_signed32	ifreq_table_LFO[TABLE_LEN];
static rtems_signed32	ffreq_table_LFO[TABLE_LEN];	//LFO'S INCREMENTS (see osc.asm)
static float		period[TABLE_LEN];		//LFO range period in mseconds (for led_task)
static rtems_signed32	offset_table[TABLE_LEN];	//OFFSETS
static rtems_signed32	offset_table_cutoff[TABLE_LEN];	//OFFSETS(only for cutoff)
static rtems_signed32	dspData[DSP_DATA_LEN];		//sent to dsp with all parameters
static rtems_unsigned8	dspData_flash[DSP_DATA_LEN];	//exactly the same of 'dspData', to be saved in flash

rtems_boolean work(void){
	int		i;
	rtems_id	led_task1_id,led_task2_id,led_task3_id;
	
	//ONLY FOR EASTER EGGS
	int		egg1_counter=0;
	rtems_boolean	eggrnd_first=TRUE;//to catch the seed with potentiometer
	rtems_unsigned8	egg_val1=0,egg_val2=0,egg_val3=0; //although it's no necessary,
							//we initialize them to avoid warnings
	////
	
	TRACE("******************************************************************************\n");
	TRACE("Chameleon's South Pole. Programmed by Aleix Riera (aleix@fjarre.com)\n");
	TRACE("******************************************************************************\n\n");
	TRACE("INITIALIZING ...\n\n");

	init_panel_and_dsp();
	print_title(1);
	init_flash();
	init_panel_redefines();
	init_menu();
	fill_tables();
	init_southpole_presets();
	init_variables();
	leds_and_wait();
	panel_out_lcd_clear(panel);
	print_LCD();

	if(LEDS){
		led_task1_id = create_led_task1(panel);
		if (!led_task1_id)	TRACE("ERROR: cannot create led_task 1.\n");
		led_task2_id = create_led_task2(panel);
		if (!led_task2_id)	TRACE("ERROR: cannot create led_task 2.\n");
		led_task3_id = create_led_task3(panel);
		if (!led_task3_id)	TRACE("ERROR: cannot create led_task 3.\n");
	}

	TRACE(" ### SouthPole Signal Processing Started . ###\n");

	//There are INIT_EVENTS initial and automatic 'new_events'.
	//We want catch the Volume event, of course.
	for(i=0;i<INIT_EVENTS;i++){
		panel_in_new_event(panel,TRUE);
		if(panel_in_potentiometer(panel,&pot,&value))
			if(pot==PANEL01_POT_VOLUME) Volume=value;
	}

	prepare_and_send_DSP();		//init the DSP with first preset
	dsp_write_flag0(dsp,TRUE);	//SYNC

	while(TRUE)
//////////////////////////////////////////////////////////////////////
//	ENDLESS LOOP BEGINS
//////////////////////////////////////////////////////////////////////
		if(panel_in_new_event(panel,TRUE)){
			if(panel_in_potentiometer(panel,&pot,&value)){
				switch(pot){
					case PANEL01_POT_VOLUME:
						Volume=value;
						break;
					case PANEL01_POT_CTRL1:
						//EGG SEED
						if(eggrnd_first){
							srand(value);
							eggrnd_first=FALSE;
						}
						////
						egg_val1=value;
						switch(menu_index_page){
							case MAX_OPTIONS_PER_SECTION:	//Constants
								Actual.Line[menu_index_part].K[0]=value;
								break;
							case MAX_OPTIONS_PER_SECTION+1:	//Freq
								Actual.Line[menu_index_part].Freq[0]=value;
								break;
							/* ENCODER
							case MAX_OPTIONS_PER_SECTION+2:	//Send
								Actual.Send[1]=value;
								break;*/
							/* ENCODER
							case MAX_OPTIONS_PER_SECTION+3:	//Saturation
								Actual.D[0]=value;
								break;*/
							case MAX_OPTIONS_PER_SECTION+4:	//Amp
								Actual.Line[menu_index_part].Amp[0]=value;
								break;
							case MAX_OPTIONS_PER_SECTION+5:	//FilterLevels: LPF
								Actual.Line[menu_index_part].Filtlvl[0]=value;
								break;
							/* ENCODER
							case MAX_OPTIONS_PER_SECTION+6:	//Line vol
								Actual.Line[menu_index_part].Filtlvl[0]=value;
								break;*/
							/*ENCODER
							case MAX_OPTIONS_PER_SECTION+7:	//Delay
								Actual.Line[menu_index_part].Filtlvl[0]=value;
								break;*/
							case MAX_OPTIONS_PER_SECTION+8:	//Globalmix: thru
								Actual.Mix[0]=value;
								break;
						}
						break;
					case PANEL01_POT_CTRL2:
						egg_val2=value;
						switch(menu_index_page){
							case MAX_OPTIONS_PER_SECTION:	//Constants
								Actual.Line[menu_index_part].K[1]=value;
								break;
							case MAX_OPTIONS_PER_SECTION+1:	//Freq
								Actual.Line[menu_index_part].Freq[1]=value;
								break;
							case MAX_OPTIONS_PER_SECTION+4:	//Amp
								Actual.Line[menu_index_part].Amp[1]=value;
								break;
							case MAX_OPTIONS_PER_SECTION+5:	//FilterLevels: BPF
								Actual.Line[menu_index_part].Filtlvl[1]=value;
								break;
							case MAX_OPTIONS_PER_SECTION+8:	//Globalmix: Lines
								Actual.Mix[1]=value;
								break;
						}
						break;
					case PANEL01_POT_CTRL3:
						egg_val3=value;
						switch(menu_index_page){
							case MAX_OPTIONS_PER_SECTION:	//Constants
								Actual.Line[menu_index_part].K[2]=value;
								break;
							case MAX_OPTIONS_PER_SECTION+1:	//Freq
								Actual.Line[menu_index_part].Freq[2]=value;
								break;
							case MAX_OPTIONS_PER_SECTION+4:	//Amp
								Actual.Line[menu_index_part].Amp[2]=value;
								break;
							case MAX_OPTIONS_PER_SECTION+5:	//FilterLevels: HPF
								Actual.Line[menu_index_part].Filtlvl[2]=value;
								break;
							case MAX_OPTIONS_PER_SECTION+8:	//Globalmix: Delay
								Actual.Mix[2]=value;
								break;
						}
						break;
				}
				print_LCD_param();
				//EGG2
				if(egg_val1==EGG2_VAL1&&
					egg_val2==EGG2_VAL2&&
					egg_val3==EGG2_VAL3)
					print_egg(EGG2);
				//EGG3
				if(egg_val1==EGG3_VAL1&&
					egg_val2==EGG3_VAL2&&
					egg_val3==EGG3_VAL3)
					print_egg(EGG3);
			}
			else if(panel_in_encoder(panel,&encoder,&inc)){
				switch(menu_index_page){
					case MAX_OPTIONS_PER_SECTION+2:	//Send
						i=Actual.Line[menu_index_part].Send+inc;
						if(i>=0&&i<TABLE_LEN) Actual.Line[menu_index_part].Send=i;
						break;
					case MAX_OPTIONS_PER_SECTION+3:	//Saturation
						i=Actual.Line[menu_index_part].Sat+inc;
						if(i>=0&&i<TABLE_LEN) Actual.Line[menu_index_part].Sat=i;
						break;
					case MAX_OPTIONS_PER_SECTION+6:	//Line vol
						i=Actual.Line[menu_index_part].Vol+inc;
						if(i>=0&&i<TABLE_LEN) Actual.Line[menu_index_part].Vol=i;
						break;
					case MAX_OPTIONS_PER_SECTION+7:	//Delay
						switch(menu_index_param){
							case 2*MAX_OPTIONS_PER_SECTION+3:	//Time
								i=Actual.D[0]+inc;
								if(i>=0&&i<TABLE_LEN) Actual.D[0]=i;
								break;
							case 2*MAX_OPTIONS_PER_SECTION+4:	//Feedback
								i=Actual.D[1]+inc;
								if(i>=0&&i<TABLE_LEN) Actual.D[1]=i;
								break;
							case 2*MAX_OPTIONS_PER_SECTION+5:	//Random
								i=Actual.D[2]+inc;
								if(i>=0&&i<TABLE_LEN) Actual.D[2]=i;
								break;
						}
						break;
				}
				print_LCD_param();
			}
			else if(panel_in_keypad(panel,&key)){
				switch(key){
					case PANEL01_KEY_EDIT:
						panel_out_lcd_clear(panel);
						access_flash(TRUE);
						panel_out_lcd_clear(panel);
						print_LCD();
						break;
					case PANEL01_KEY_SHIFT:
						panel_out_lcd_clear(panel);
						access_flash(FALSE);
						panel_out_lcd_clear(panel);
						print_LCD();
						break;
					case PANEL01_KEY_PART_UP:
						if(menu_index_part!=MENU_PART-1)
							menu_index_part++;
						panel_out_lcd_clear(panel);
						print_LCD();
						break;
					case PANEL01_KEY_PART_DOWN:
						if(menu_index_part!=0)
							menu_index_part--;
						panel_out_lcd_clear(panel);
						print_LCD();
						break;
					case PANEL01_KEY_GROUP_UP:
						if(menu_index_group!=3*MAX_OPTIONS_PER_SECTION+MENU_GROUP-1)
							menu_index_group++;
						Actual.Line[menu_index_part].Active=1;
						panel_out_lcd_clear(panel);
						print_LCD();
						break;
					case PANEL01_KEY_GROUP_DOWN:
						if(menu_index_group!=3*MAX_OPTIONS_PER_SECTION)
							menu_index_group--;
						Actual.Line[menu_index_part].Active=0;
						panel_out_lcd_clear(panel);
						print_LCD();
						break;
					case PANEL01_KEY_PAGE_UP:
						if(menu_index_page!=MAX_OPTIONS_PER_SECTION+MENU_PAGE-1){
							menu_index_page++;
							switch(menu_index_page){
								case MAX_OPTIONS_PER_SECTION+2:	//Send
									menu_index_param=2*MAX_OPTIONS_PER_SECTION;
									break;
								case MAX_OPTIONS_PER_SECTION+3:	//Saturation
									menu_index_param=2*MAX_OPTIONS_PER_SECTION+1;
									break;
								case MAX_OPTIONS_PER_SECTION+6:	//LineVol
									menu_index_param=2*MAX_OPTIONS_PER_SECTION+2;
									break;
								case MAX_OPTIONS_PER_SECTION+7:	//Delay
									menu_index_param=2*MAX_OPTIONS_PER_SECTION+3;
									break;
							}
							panel_out_lcd_clear(panel);
							print_LCD();
						}
						break;
					case PANEL01_KEY_PAGE_DOWN:
						if(menu_index_page!=MAX_OPTIONS_PER_SECTION){
							menu_index_page--;
							switch(menu_index_page){
								case MAX_OPTIONS_PER_SECTION+2:	//Send
									menu_index_param=2*MAX_OPTIONS_PER_SECTION;
									break;
								case MAX_OPTIONS_PER_SECTION+3:	//Saturation
									menu_index_param=2*MAX_OPTIONS_PER_SECTION+1;
									break;
								case MAX_OPTIONS_PER_SECTION+6:	//LineVol
									menu_index_param=2*MAX_OPTIONS_PER_SECTION+2;
									break;
								case MAX_OPTIONS_PER_SECTION+7:	//Delay
									menu_index_param=2*MAX_OPTIONS_PER_SECTION+3;
									break;
							}
							panel_out_lcd_clear(panel);
							print_LCD();
						}
						break;
					case PANEL01_KEY_PARAM_UP:
						switch(menu_index_param){
							case 2*MAX_OPTIONS_PER_SECTION+3:	//Delay Time
								menu_index_param++;
								break;
							case 2*MAX_OPTIONS_PER_SECTION+4:	//Delay	FeedBack
								menu_index_param++;
								break;
						}
						panel_out_lcd_clear(panel);
						print_LCD();
						break;
					case PANEL01_KEY_PARAM_DOWN:
						switch(menu_index_param){
							case 2*MAX_OPTIONS_PER_SECTION+4:	//Delay Feedback
								menu_index_param--;
								break;
							case 2*MAX_OPTIONS_PER_SECTION+5:	//Delay	Random
								menu_index_param--;
								break;
						}
						panel_out_lcd_clear(panel);
						print_LCD();
						break;
					//VALUE: The Same functions as the Encoder ones
					case PANEL01_KEY_VALUE_UP:
						switch(menu_index_page){
							case MAX_OPTIONS_PER_SECTION+2:	//Send
								i=Actual.Line[menu_index_part].Send+1;
								if(i<TABLE_LEN) Actual.Line[menu_index_part].Send=i;
								break;
							case MAX_OPTIONS_PER_SECTION+3:	//Saturation
								i=Actual.Line[menu_index_part].Sat+1;
								if(i<TABLE_LEN) Actual.Line[menu_index_part].Sat=i;
								break;
							case MAX_OPTIONS_PER_SECTION+6:	//Line vol
								i=Actual.Line[menu_index_part].Vol+1;
								if(i<TABLE_LEN) Actual.Line[menu_index_part].Vol=i;
								break;
							case MAX_OPTIONS_PER_SECTION+7:	//Delay
								switch(menu_index_param){
									case 2*MAX_OPTIONS_PER_SECTION+3:	//Time
										i=Actual.D[0]+1;
										if(i<TABLE_LEN) Actual.D[0]=i;
										break;
									case 2*MAX_OPTIONS_PER_SECTION+4:	//Feedback
										i=Actual.D[1]+1;
										if(i<TABLE_LEN) Actual.D[1]=i;
										break;
									case 2*MAX_OPTIONS_PER_SECTION+5:	//Random
										i=Actual.D[2]+1;
										if(i<TABLE_LEN) Actual.D[2]=i;
										break;
								}
								break;
						}
						print_LCD_param();
						break;
					case PANEL01_KEY_VALUE_DOWN:
						//ONLY WHEN SAVING FACTORY PRESETS
						//trace_variables();
						////
						switch(menu_index_page){
							case MAX_OPTIONS_PER_SECTION+2:	//Send
								i=Actual.Line[menu_index_part].Send-1;
								if(i>=0) Actual.Line[menu_index_part].Send=i;
								break;
							case MAX_OPTIONS_PER_SECTION+3:	//Saturation
								i=Actual.Line[menu_index_part].Sat-1;
								if(i>=0) Actual.Line[menu_index_part].Sat=i;
								break;
							case MAX_OPTIONS_PER_SECTION+6:	//Line vol
								i=Actual.Line[menu_index_part].Vol-1;
								if(i>=0) Actual.Line[menu_index_part].Vol=i;
								break;
							case MAX_OPTIONS_PER_SECTION+7:	//Delay
								switch(menu_index_param){
									case 2*MAX_OPTIONS_PER_SECTION+3:	//Time
										i=Actual.D[0]-1;
										if(i>=0) Actual.D[0]=i;
										break;
									case 2*MAX_OPTIONS_PER_SECTION+4:	//Feedback
										i=Actual.D[1]-1;
										if(i>=0) Actual.D[1]=i;
										break;
									case 2*MAX_OPTIONS_PER_SECTION+5:	//Random
										i=Actual.D[2]-1;
										if(i>=0) Actual.D[2]=i;
										break;
								}
								break;
						}
						print_LCD_param();
						break;
					case EGGRND_KEYS:
						print_egg(RANDOM);
						break;
				}
				if(egg1_counter<EGG1_NKEYS)
					egg1_counter++;
				else if(egg1_counter==EGG1_NKEYS){
					print_egg(EGG1);
					egg1_counter=0;	//if>EGG1_NKEYS then does not occur nevermore (thus quoth the raven!)
				}
			}
			prepare_and_send_DSP();			
//////////////////////////////////////////////////////////////////////
//	ENDLESS LOOP ENDS (hehe)
//////////////////////////////////////////////////////////////////////
		}
}

#include "inc\dsp.c"
#include "inc\flash.c"
#include "inc\init.c"
#include "inc\presets.c"
#include "inc\print.c"
#include "inc\leds.c"

rtems_task rtems_main(rtems_task_argument ignored)
{
	work();
	rtems_task_delete(RTEMS_SELF);
}