//
//
// hello.echo.44.c
//
// 115200 baud serial echo hello-world program
//
// Neil Gershenfeld
// CBA MIT 9/12/09
//
// (c) Massachusetts Institute of Technology 2009
// Permission granted for experimental and personal use;
// license for commercial sale available from MIT.
//
//

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>

#define tx_pin PA6 // transmit pin
//#define rx_pin PA7 // receive pin
#define led_pin PB2 // LED pin
#define bit_delay_time 8.7 // bit delay, 1/115200 in usec at 20 MHZ
#define led_delay_time 10 // LED delay time, in ms
#define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay
#define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay
#define output_A(pin) (DDRA |= byte(pin)) // set PORTA pin for output
#define output_B(pin) (DDRB |= byte(pin)) // set PORTB pin for output
#define set_A(pin) (PORTA |= byte(pin)) // set pin in PORTA
#define clear_A(pin) (PORTA &= ~(byte(pin))) // clear pin in PORTA
#define set_B(pin) (PORTB |= byte(pin)) // set pin in PORTB
#define clear_B(pin) (PORTB &= ~(byte(pin))) // clear pin in PORTB
#define pin_test_A(bit) (PINA & (1 << bit)) // test for pin in PORTA
#define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
#define byte(bit) (1 << bit) // byte with bit set

#define midiout_pin PA3 //Midi Out pin
#define midi_bit_delay_time 32 // bit delay, 1/31250 at usec at 20 MHz
#define midi_bit_delay() _delay_us(midi_bit_delay_time) // RS232 bit delay
#define midi_half_bit_delay() _delay_us(midi_bit_delay_time/2) // RS232 half bit delay
//#define int_bit_delay(delayLength) _delay_us(delayLength) // delay by given length
//#define int_half_bit_delay(delayLength) _delay_us(delayLength/2) //delay by have given length

#define ADCMux ADMUX
#define ADCctrl ADCSRA
#define ADC_lowReg ADCL
#define ADC_highReg ADCH
#define ADC_readStat		((ADCSRA >> 6) & 0x01)
#define set_refVcc()		(ADMUX &= 0x3F) // set the ADC to compare to 
#define set_rightAdjust()	(ADCSRB &= ~(0x10)) // confirm the default of right adjust (bit 0 is 0 of ADLAR)
#define set_leftAdjust()	(ADCSRB |= (0x10)) // set left adjust
#define clr_MuxSelect()		(ADMUX &= 0xC0) //clear Mux
#define set_MuxSelect(pin)	(ADMUX |= (~0xC0 & pin)) // select mux pin
#define clr_ADCClockScalar() (ADCSRA &= 0xf8) //set clock scalar pins to zero
#define set_ADCClockScalar(ratio) (ADCSRA |= (~(0x07) | ratio))
#define clr_ADCEnable()		(ADCSRA &= ~0x80)
#define set_ADCEnable()		(ADCSRA |= 0x80 )
#define start_readADC()		(ADCSRA |= 0x40) //starts ADC to read

//int types
#define uint16 uint16_t
#define uint8 uint8_t	

enum ADC_ClockScalars {
	eADC_ClockDiv2 = 1,
	eADC_ClockDiv4 = 2,
	eADC_ClockDiv8 = 3,
	eADC_ClockDiv16 = 4,
	eADC_ClockDiv32 = 5,
	eADC_ClockDiv64 = 6,
	eADC_ClockDiv128 = 7
};

enum ADC_PinIns {
	eADC_FSRpin = 2,
	eADC_StepIn = 0,
};

enum Interface_Select {
	eInterfaceSel_MidiOut,
	eInterfaceSel_Serial
};

enum Midi_Ctrls {
	eMidi_NoteOn = 144,
	eMidi_NoteOff = 128,
	eMidi_FSRNote = 10,
	eThreshold = 25
};

void put_char(char txchar) {
   //
   // print the character in txchar
   // assumes no line driver (doesn't invert bits)
   //
   // start bit
   //
   set_A(tx_pin);
   bit_delay();
   //
   // unrolled loop to write data bits
   //
   if bit_test(txchar,0)
      clear_A(tx_pin);
   else
      set_A(tx_pin);
   bit_delay();
   if bit_test(txchar,1)
      clear_A(tx_pin);
   else
      set_A(tx_pin);
   bit_delay();
   if bit_test(txchar,2)
      clear_A(tx_pin);
   else
      set_A(tx_pin);
   bit_delay();
   if bit_test(txchar,3)
      clear_A(tx_pin);
   else
      set_A(tx_pin);
   bit_delay();
   if bit_test(txchar,4)
      clear_A(tx_pin);
   else
      set_A(tx_pin);
   bit_delay();
   if bit_test(txchar,5)
      clear_A(tx_pin);
   else
      set_A(tx_pin);
   bit_delay();
   if bit_test(txchar,6)
      clear_A(tx_pin);
   else
      set_A(tx_pin);
   bit_delay();
   if bit_test(txchar,7)
      clear_A(tx_pin);
   else
      set_A(tx_pin);
   bit_delay();
   //
   // stop bit
   //
   clear_A(tx_pin);
   bit_delay();
   }

/*
void put_midi(char txchar) {

	set_A(midiout_pin);
   midi_bit_delay();
   //
   // unrolled loop to write data bits
   //
   if bit_test(txchar,0)
      clear_A(midiout_pin);
   else
      set_A(midiout_pin);
   midi_bit_delay();
   if bit_test(txchar,1)
      clear_A(midiout_pin);
   else
      set_A(midiout_pin);
   midi_bit_delay();
   if bit_test(txchar,2)
      clear_A(midiout_pin);
   else
      set_A(midiout_pin);
   midi_bit_delay();
   if bit_test(txchar,3)
      clear_A(midiout_pin);
   else
      set_A(midiout_pin);
   midi_bit_delay();
   if bit_test(txchar,4)
      clear_A(midiout_pin);
   else
      set_A(midiout_pin);
   midi_bit_delay();
   if bit_test(txchar,5)
      clear_A(midiout_pin);
   else
      set_A(midiout_pin);
   midi_bit_delay();
   if bit_test(txchar,6)
      clear_A(midiout_pin);
   else
      set_A(midiout_pin);
   midi_bit_delay();
   if bit_test(txchar,7)
      clear_A(midiout_pin);
   else
      set_A(midiout_pin);
   midi_bit_delay();
   //
   // stop bit
   //
   clear_A(midiout_pin);
   midi_bit_delay();
}
*/

void put_midi(char txchar) {

   clear_A(midiout_pin);
   midi_bit_delay();
   //
   // unrolled loop to write data bits
   //
   if bit_test(txchar,0)
      set_A(midiout_pin);
   else
      clear_A(midiout_pin);
   midi_bit_delay();
   if bit_test(txchar,1)
      set_A(midiout_pin);
   else
      clear_A(midiout_pin);
   midi_bit_delay();
   if bit_test(txchar,2)
      set_A(midiout_pin);
   else
      clear_A(midiout_pin);
   midi_bit_delay();
   if bit_test(txchar,3)
      set_A(midiout_pin);
   else
      clear_A(midiout_pin);
   midi_bit_delay();
   if bit_test(txchar,4)
      set_A(midiout_pin);
   else
      clear_A(midiout_pin);
   midi_bit_delay();
   if bit_test(txchar,5)
      set_A(midiout_pin);
   else
      clear_A(midiout_pin);
   midi_bit_delay();
   if bit_test(txchar,6)
      set_A(midiout_pin);
   else
      clear_A(midiout_pin);
   midi_bit_delay();
   if bit_test(txchar,7)
      set_A(midiout_pin);
   else
      clear_A(midiout_pin);
   midi_bit_delay();
   //
   // stop bit
   //
   set_A(midiout_pin);
   midi_bit_delay();
}

void print_string(char *str) {
   //
   // print the null-terminated program memory string str
   //
   char chr;
   chr = pgm_read_byte(str++);
   while (chr != 0x00) {
      put_char(chr);
      chr = pgm_read_byte(str++);
      }
};
   
//bool isADCDone(void)
//{
//	uint8 result = ((ADCSRA >> 6) & 0x01);
	
//	return result;
//}

/*
void readADC(uint8* lowByte, uint8* highByte)
{
	start_readADC();
	while(!ADC_readStat); //wait for ADC to finish converting
	*lowByte = (uint8) ADC_lowReg; 
	*highByte = (uint8) ADC_highReg;

	return ;
}
*/

void readADCeight(uint8* highByte)
{
	start_readADC();
	while(!ADC_readStat); //wait for ADC to finish converting
	*highByte = (uint8) ADC_highReg;

	return ;
}

char message[] PROGMEM = "Running.  Hello!";
char message2[] PROGMEM = "ADC Configured.";
char messageRef[] PROGMEM = "ADC Ref Value: ";
char messageRead[] PROGMEM = "RV: ";

int main(void) 
{
   //
   // set clock divider to /1
   //
   CLKPR = (1 << CLKPCE);
   CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
   //
   // initialize output pins
   //
   output_A(tx_pin);
   output_A(midiout_pin);
   clear_A(tx_pin);
//   clear_A(midiout_pin);
	set_A(midiout_pin);  //inverse version
   //
   // main loop
   //
    print_string(message);
	put_char('\n');
	_delay_ms(500);
	
	ADCMux = 0x00; //clear settings
	set_refVcc(); // set the ADC to compare to 
	set_leftAdjust(); // confirm the default of right adjust (bit 0 is 0 of ADLAR)
	clr_MuxSelect();
	set_MuxSelect(eADC_FSRpin); // set mux pin to read pin 2
	clr_ADCClockScalar();
	set_ADCClockScalar(eADC_ClockDiv64);
	set_ADCEnable();
	
	print_string(message2);
	put_char('\n');
	
//	uint8 maxVoltLowByte;
	uint8 maxVoltHighByte;
//	readADC(&maxVoltLowByte, &maxVoltHighByte);
	readADCeight(&maxVoltHighByte);
//	uint16 maxVolt = maxVoltHighByte << 8 + maxVoltLowByte;
	print_string(messageRef);
	char outchar = (char) (maxVoltHighByte>>1);
	put_char(outchar);
//	outchar = (char) (maxVoltLowByte);
//	put_char(outchar );

	_delay_ms(500);
 
//	uint8 lowByte;
	uint8 highByte;
	uint8 strike = 0;
	while (1) 
	{
//	  readADC(&lowByte, &highByte);
	  readADCeight(&highByte);
//	  print_string(messageRead);
/*	  if (strike && ((highByte + eThreshold) >= maxVoltHighByte))
	  {
	  		put_midi(eMidi_NoteOff);
			put_midi(eMidi_FSRNote);
			outchar = (char) (highByte>>1);
			put_midi(outchar);
	//	  outchar = (char) (lowByte);	  
	//	  put_char(outchar );
//		put_char(':');
//		put_char('\n');
			strike = 0;
	  }
	  else 
	  if (!strike && ((highByte + eThreshold) < maxVoltHighByte)
	  {*/
		put_char(eMidi_NoteOn);
		put_char(eMidi_FSRNote);
		outchar = (char) (highByte>>1);
		put_char(outchar);
		put_midi(eMidi_NoteOn);
		put_midi(eMidi_FSRNote);
		put_midi(outchar);
	//	  outchar = (char) (lowByte);	  
	//	  put_char(outchar );
		put_char(':');
		put_char('\n');
//		strike = 1;
//	   }
		_delay_ms(500);
	}
	  
	  return 1;
}
