/** \file midi.c:
 *  Handles receiving MIDI Transmissions and answering.
 */

/**
 * When receiving data from the Java Software, this function sends a reply for every 64 received bytes
 * \param reply
 * - 0=OK
 * - x=err-code
 *    x=1=received data corrupted
 *    x=2=no space left
 * - checksum of received datablock
 */
void sendReply(unsigned char reply,unsigned char checksum) __critical {
	MIOS_MIDI_BeginStream();
	MIOS_MIDI_TxBufferPut(0xF0);
	MIOS_MIDI_TxBufferPut(0x54);
	MIOS_MIDI_TxBufferPut(reply);
	MIOS_MIDI_TxBufferPut(checksum);
	MIOS_MIDI_TxBufferPut(0xF7);
	MIOS_MIDI_EndStream();
}

/**
 * This function is called by MIOS when a MIDI byte has been received
 * 
 * This function implements the reception of the Eprom data for programming the MIDIbox,
 * and also the reception of the editbuffer into the RAM
 * it also implements the tunnel function for data not determined for the MIDIbox
 */
void MPROC_NotifyReceivedByte(unsigned char byte) __wparam __critical
{
	unsigned long i;



	if (send_editbuffer)
		return;

	//active-sensing is swallowed

	if(byte==0xFE) {
		/*
		MIOS_MIDI_BeginStream();
		MIOS_MIDI_TxBufferPut (0xFE);
		MIOS_MIDI_EndStream();
		*/
		return;
	}
	//bytecount++;
	
	//If a SysEx Message starts it has to be checked if it is determined for the box.
	//If true the following large switchcase is a finite state machine that parses the arriving sysex messages
	//and writes it in the Bankstick or into editbuffer array in the RAM if it is a n editbuffer
	if (byte == 0xF0) {
		if(eb_request.active)
			sysex=0xFE;
		else
			sysex = 0x00;
		record_flag = 1;
	} /*else {
		if (byte == 0xF7) {
			if(sysex==0xFF) {
				MIOS_MIDI_BeginStream();
				MIOS_MIDI_TxBufferPut (0xF7);
		 	 	MIOS_MIDI_EndStream();
			} else {
				sysex = 0xFF;
				record_flag = 0;
				sendReply(0);
				MIOS_LCD_Clear();
				initDeviceModus();
			}
			return;
		}
	}*/

	switch (sysex) {									// still in Core-relevant Sysex-Message? no -> sysex = 0xFF -> Tunnel												//            	                            yes -> sysex = number of Byte
		case 0x00:
			if(byte == 0xF0) {							// Sysex?
				inc_buffer[0] = byte;					// keep recent byte in buffer
				sysex = 0x01;
			}
			break;

		case 0x01:
			if(byte == 0x55) {							// Manufacturer Code MIDIbox GLCD?
				inc_buffer[1] = byte;					//  keep recent byte in buffer
				sysex = 0x02;
			}
			else {
				MIOS_MIDI_BeginStream();
				MIOS_MIDI_TxBufferPut (inc_buffer[0]);		
				MIOS_MIDI_TxBufferPut (byte);			
				MIOS_MIDI_EndStream();
				sysex = 0xFF;							//exit Core-relevant - Sysex
			}
			break;

		case 0x02:
			if(byte == 0x4D) {							// M?
				inc_buffer[2] = byte;					//keep recent byte in buffer
				sysex = 0x03;
			}
			else {
				MIOS_MIDI_BeginStream();
				MIOS_MIDI_TxBufferPut (inc_buffer[0]);	//Falls nicht mehr in einer für Core relevanten Sysex Message,
				MIOS_MIDI_TxBufferPut (inc_buffer[1]);	//tunnele Buffer und aktuelles Byte an Ausgang
				MIOS_MIDI_TxBufferPut (byte);
				MIOS_MIDI_EndStream();
				sysex = 0xFF;							//exit Core-relevant - Sysex
			}
			break;

		case 0x03:
			if(byte == 0x42) {							// B?
				inc_buffer[3] = byte;
				sysex = 0x04;
			}
			else {
				MIOS_MIDI_BeginStream();
				MIOS_MIDI_TxBufferPut (inc_buffer[0]);	//Falls nicht mehr in einer für Core relevanten Sysex Message,
				MIOS_MIDI_TxBufferPut (inc_buffer[1]);	//tunnele Buffer und aktuelles Byte an Ausgang
				MIOS_MIDI_TxBufferPut (inc_buffer[2]);
				MIOS_MIDI_TxBufferPut (byte);
				MIOS_MIDI_EndStream();
				sysex = 0xFF;							//exit Core-relevant - Sysex
			}
			break;

		case 0x04:
			if(byte == CURENT_CORE) {					// CURRENT CORE?
				sysex = 0x05;
			}
			else {
				MIOS_MIDI_BeginStream();
				MIOS_MIDI_TxBufferPut (inc_buffer[0]);	//Falls nicht mehr in einer für Core relevanten Sysex Message,
				MIOS_MIDI_TxBufferPut (inc_buffer[1]);	//tunnele Buffer und aktuelles Byte an Ausgang
				MIOS_MIDI_TxBufferPut (inc_buffer[2]);
				MIOS_MIDI_TxBufferPut (inc_buffer[3]);
				MIOS_MIDI_TxBufferPut (byte);
				MIOS_MIDI_EndStream();
				sysex = 0xFF;							//exit Core-relevant - Sysex
			}
			break;

		case 0x05:
			received_func_flag = byte;
			sysex = 0x06;

			break;

		case 0x06:
			if(byte == MAJOR_VERSION) {
				sysex = 0x07;
			}
			break;

		case 0x07:
			if(byte == MINOR_VERSION) {
				sysex = 0x08;
				mem_adress = 0;
			}
			break;

		case 0x08:
			mem_adress |= byte;
			mem_adress <<= 8;
			sysex = 0x09;
			break;

		case 0x09:
			mem_adress |= byte;
			mem_adress |= (mem_adress>>7)&0x80;
			mem_adress <<= 8;
			sysex = 0x10;
			break;

		case 0x10:
			mem_adress |= byte;
			mem_adress |= (mem_adress>>14)&0x80;
			mem_adress &= 0x1fffff;
			sysex = 0x11;
			break;

		//writing to the Eprom with the Java data
		case 0x11:
			//debugb(0x0C);
			//debugc(get_userdata);
			if(byte==0xF7) {
				sysex = 0xFF;
				record_flag = 0;
				//init();
				transfer_counter=0;
				check_sum&=0x7F;
				sendReply(0,check_sum);
				check_sum=0;
				//initDeviceModus();
			} else if(received_func_flag==0x00) {
				 if(transfer_counter++>=64) {
					 transfer_counter=0;
					 sendReply(0,check_sum);
					 check_sum=0;
				 }
				 if(byte==0x60 && receive_escape<3) {
					receive_escape++;
				 	return;
				 }
				 if(receive_escape==1) {
				 	byte|=0x80;
				}
				 if(receive_escape==2) {
				 	writeStream (0x60);
				 	check_sum^=0x60;
				}
				 if(receive_escape==3) {
					 //byte|=0x60;
					 //byte|=0x80;
				 	 writeStream (0x60|0x80);
				 	 check_sum^=(0x60|0x80);
				}
				 receive_escape=0;
				 if (get_userdata==0)
				 	update=0x10;
				 eb_request.error=0;
				 get_userdata=0x08;

				 check_sum^=byte;
				 writeStream (byte);
			}
			//debugb(0x0D);
			//debugc(get_userdata);
			break;

		//receiving the editbuffer
		case 0xFE:
			if(byte==0xF0)
				return;
			if(eb_request.dump.wrong_header_length>eb_request.data_counter) {
				eb_request.data_counter++;
			}
			else {
				writeEditBuffer((eb_request.data_counter++)-eb_request.dump.wrong_header_length,byte);
				//debugc(eb_request.data_counter);
			}
			if(byte==0xF7) {
				unsigned char i;
				sysex=0xFF;
				record_flag = 0;
				for(i=0;i<8;i++) {
					if(parametersleft[i].edit&0x0FFF)
						potis[i]=eb_re_convert(parametersleft[i].value[0],parametersleft[i].edit&0x0FFF);
					if(parametersright[i].edit&0x0FFF)
						potis[i+8]=eb_re_convert(parametersright[i].value[0],parametersright[i].edit&0x0FFF);
				}
				//requestNextDump();
				eb_request.active=0;
				//get_userdata=0x00;
				update=0x03;
				//for(i=0;i<4;i++)
				//	MIOS_DOUT_PinSet(i,bank==i?1:0);
			}
			break;

		case 0xFF:										// Tunnel mode
			MIOS_MIDI_BeginStream();
			MIOS_MIDI_TxBufferPut (byte);				// send MIDI-Byte from input to output
			MIOS_MIDI_EndStream();
			break;
	}
}
