/** \file func.c:
 *  Contains a collection of functions that is meant to be expanded by the
 *  commited user of the "MIDI Plank". Here you find a collection of standard
 *  functions that are implemented differently in every synthesizer and thus have
 *  to be custom made for every device. These functions include tasks like
 *  converting the formats between edit buffers and the parameter values of the
 *  "MIDI Plank", readying Sysex Strings to be sent by putting in single values at
 *  the right position in the right format, and calculating checksums for the edit
 *  buffers.
 */

/**
 * convert functions put a converted 'value' at 'value_position' into a
 * sysex string ('z_input_sysex') that is being sent
 * \param z_input_sysex pointer to the sysex string that is being manipulated
 * \param value value which is being put into sysex string
 * \param value_position position in sysex string, where value is being put in
 */
void empty_convert(unsigned char *z_input_sysex,int value,unsigned char value_position) {
}

/**
 *  EB_convert functions put a converted 'value' at 'value_position' into the
 *  Edit Buffer that is stored in the RAM
 *  \param value_position position in Edit buffer where value is being put in
 *  \param value value which is being put into Edit Buffer
 */
void empty_EB_convert(int value_position, int value) {
}

/**
 *  EB_re_convert functions gets an int value from 'value_position' from the
 *  Edit Buffer that is stored in the RAM
 *	\param value_position position in Edit Buffer, where return value is being read from
 *  \return value which was read from the edit buffer and was then converted
 */
int empty_EB_re_convert(int value_position) {
	return 0;
}

/**
 * checksum functions calculate checksums (to be used for Edit Buffer
 * transmissions)
 * \return checksum after calculation
 */
unsigned char empty_checksum() {
	return ' ';
}

void EB_convert_Matrix1000(int value_position, int value) {
	writeEditBuffer(value_position*2,value&0x0F);
	writeEditBuffer(value_position*2+1,(value>>4)&0x0F);				//first two bytes reserved for length of buffer
}

int EB_re_convert_Matrix1000(int value_position) {
	char value;
	value=readEditBuffer(value_position*2+1)<<4|readEditBuffer(value_position*2);
	return value;
}



void EB_convert_UltraProteus(int value_position, int value) {
	writeEditBuffer(value_position*2+2,value&0x7F);
	writeEditBuffer(value_position*2+1+2,(value>>7)&0x7F);				//first two bytes reserved for length of buffer
}

int EB_re_convert_UltraProteus(int value_position) {
	int value;
	value=readEditBuffer(value_position*2+1+2)<<7|readEditBuffer(value_position*2+2);
	return value;
}

void Single_Byte_Sysex_Input (unsigned char *z_input_sysex,int value,unsigned char value_position) {
	*(z_input_sysex + value_position) =value&0x7F;
}

void Double_Byte_Sysex_Input_BigEndian (unsigned char *z_input_sysex,int value,unsigned char value_position) {
	z_input_sysex[value_position]=(value>>7)&0x7F;
	z_input_sysex[value_position+1]=value&0x7F;
}

void Double_Byte_Sysex_Input_LittleEndian (unsigned char *z_input_sysex,int value,unsigned char value_position) {
	z_input_sysex[value_position]=value&0x7F;
	z_input_sysex[value_position+1]=(value>>7)&0x7F;
}

unsigned char checksum_Matrix1000() {
	int i,EB_Length;
	char checksum;
	checksum=0;
	//EB_Length=edit_buffer0[0]<<8|edit_buffer0[1];
	EB_Length=eb_request.dump.edit_buffer_length;
	for(i=0;i<=EB_Length-1;i++)
		checksum=(checksum+(readEditBuffer(i*2+1+2)<<4|readEditBuffer(i*2+2)))&0x7F;
	return checksum;
}

unsigned char checksum_UltraProteus() {
	int i,EB_Length;
	char checksum;
	checksum=0;
	EB_Length=edit_buffer0[0]<<8|edit_buffer0[1];
	for(i=0;i<=EB_Length-1;i++)								//-1 for checksum byte
		checksum=(checksum+readEditBuffer(i+2))&0x7F;		//+2 for Length bytes at beginning
	return checksum;
}

//static void (*convert[4])(unsigned char*,int,unsigned char) = {empty_convert,Single_Byte_Sysex_Input,Double_Byte_Sysex_Input_BigEndian,Double_Byte_Sysex_Input_LittleEndian};

//static void (*eb_convert[3])(int,int) = {empty_EB_convert,EB_convert_Matrix1000,EB_convert_UltraProteus};
//static int (*eb_re_convert[3])(int) = {empty_EB_re_convert,EB_re_convert_Matrix1000,EB_re_convert_UltraProteus};

//static unsigned char (*checksum[3])() = {empty_checksum,checksum_Matrix1000,checksum_UltraProteus};

void convert(unsigned char func,unsigned char *z_input_sysex,int value,unsigned char value_position) {
	switch(func) {
		case 1: Single_Byte_Sysex_Input(z_input_sysex,value,value_position);
			break;
		case 2: Double_Byte_Sysex_Input_BigEndian(z_input_sysex,value,value_position);
			break;
		case 3: Double_Byte_Sysex_Input_LittleEndian(z_input_sysex,value,value_position);
			break;
		default: empty_convert(z_input_sysex,value,value_position);
			break;
	}
}

void eb_convert(unsigned char func, int value_position, int value) {
	switch(func) {
		case 1: EB_convert_Matrix1000(value_position, value);
			break;
		case 2: EB_convert_UltraProteus(value_position, value);
			break;
		default: empty_EB_convert(value_position, value);
			break;
	}
}

int eb_re_convert(unsigned char func, int value_position) {
	switch(func) {
		case 1:
			return EB_re_convert_Matrix1000(value_position);
		case 2:
			return EB_re_convert_UltraProteus(value_position);
		default:
			return empty_EB_re_convert(value_position);
	}
}

unsigned char checksum(unsigned char func) {
	switch(func) {
		case 1:
			return checksum_Matrix1000();
		case 2:
			return checksum_UltraProteus();
		default:
			return empty_checksum();
	}
}
