/*
MIDI/Kaossilator message translator for ATTiny2313 (12MHz), see schematic for pin descriptions.
MIDI implementation code sucks because it's the result of trying to get rid of a problem which wasn't caused by it. I apologize.
CC furrtek 2010.
*/

#include <avr/io.h>
#include <util/delay.h>
#include <inttypes.h>
#include <avr/interrupt.h>

#define NOTE_ON	1
#define NOTE_OFF 2
#define CONTROL_CHG 3
#define NRPNL 4
#define NRPNM 5
#define CHANGE 6

volatile uint8_t t=0,cmpt=0,sens=0,note=0,cmd=0,MIDI=0;
uint8_t NRPN_nl=0,NRPN_nm=0;

// OCR0B = mod
// OCR0A = note
ISR(USART_RX_vect) {
	MIDI = UDR;
		if (MIDI & 0x80) {				// bit7=1 of MIDI byte: command
			// Commande 
			if (MIDI==0x93) {				// Note ON, MIDI channel 4
				cmd = NOTE_ON;
			} else if (MIDI==0x83) {		// Note OFF, MIDI channel 4
				cmd = NOTE_OFF;
			} else if (MIDI==0xB3) {		// Param change, MIDI channel 4
				cmd = CONTROL_CHG;
			} else {
				cmd = 0;
			}
		} else {
			if (cmd == NOTE_ON) {
				note = MIDI;
				OCR0A = 255-(note*8);		// No mapping... Need a LUT, Velocity isn't supported
				cmd = 0;
			} else if (cmd == NOTE_OFF) {
				note = 0;
				cmd = 0;
			} else if (cmd == NRPNL) {
				NRPN_nl = MIDI;
				cmd = 0;
			} else if (cmd == NRPNM) {
				NRPN_nm = MIDI;
				cmd = 0;
			} else if (cmd == CHANGE) {
				OCR0B = MIDI*2;			// Pot value is 0~127: make it 0~254
				NRPN_nm=0;
				cmd = 0;
			} else if (cmd == CONTROL_CHG) {
				if (MIDI==0x62) {
					cmd = NRPNL;
				} else if (MIDI==0x63) {
					cmd = NRPNM;
				} else if (MIDI==0x06) {
					if ((NRPN_nm == 0x03) && (NRPN_nl == 0x08)) {	// NRPN values for cutoff pot on the EA-1
						cmd = CHANGE;
					}
					NRPN_nm=0;
				}
			}
		}
}

ISR(INT0_vect) {
	GIMSK = 0b00000000;			// INT0 off

	PORTB = 0b00000001;			// Discharge touchpad for 5 us, prevents the CD4066 from "sticking" to ~2V
	_delay_us(5);
	DDRB = 0b11011110;			// Hi-Z on line 2

	PORTB = 0b10000001;			// Out DAC H on line 4
	_delay_us(55);

	PORTB = 0b01000001;			// Out DAC V in line 2
	_delay_us(55);

	PORTB = 0b00100001;			// Simulates a push until the next reading
	DDRB =  0b11111110;

	_delay_us(100);

	EIFR = 0x00;				// Probably useless
	GIMSK = 0b01000000;			// INT0 on
}

int main(void) {
	WDTCSR |= (1<<WDCE) | (1<<WDE);
	WDTCSR = 0x00;				// Watchdog off

	PORTB = 0b00000000;
	DDRB = 0b11111111;

	PORTD = 0b00000000;
	DDRD = 0b11111011;			// PD2 is an input (INT0)

	#define BAUD 31250			// Init UART for MIDI
	#include <util/setbaud.h>
	UBRRH = UBRRH_VALUE;
	UBRRL = UBRRL_VALUE;
	#if USE_2X
	UCSRA |= (1 << U2X);
	#else
	UCSRA &= ~(1 << U2X);
	#endif

	UCSRC = (3<<UCSZ0);
	UCSRB = (1<<RXEN)|(1<<RXCIE); 	// RX interrupt on

	_delay_ms(100);

	TCCR0A = 0b10100011;			// Fast PWM mode 3, OC0A and OC0B
	TCCR0B = 0b00000001;			// No prescaler (max freq)
	OCR0A = 0x40;				// Horizontal init value (can be 0)
	OCR0B = 0x80;				// Vertical init value (can be 0)

	MCUCR = 0b00000010;			// INT0 on falling edge of PD2
	GIMSK = 0b01000000;			// INT0 on

	sei();

	for (;;) {
		if (note) {
			GIMSK = 0b01000000;	// INT0 on
			PORTD |= _BV(PD6);	// Debug LED
		} else {
			GIMSK = 0;			// INT0 off
			PORTB = 0b00000001;	// "Release" touch pad
			PORTD &= ~_BV(PD6);	// Debug LED
		}
	}

    return 0;
}