#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/io.h>


#define BV(bit) (1<<(bit)) // Byte Value => converts bit into a byte value. One at bit location.
#define cbi(reg, bit) reg &= ~(BV(bit)) // Clears the corresponding bit in register reg
#define sbi(reg, bit) reg |= (BV(bit))              // Sets the corresponding bit in register reg

#define HEX__(n) 0x##n##UL

#define B8__(x) ((x&0x0000000FLU)?1:0)  \
  +((x&0x000000F0LU)?2:0)  \
  +((x&0x00000F00LU)?4:0)  \
  +((x&0x0000F000LU)?8:0)  \
  +((x&0x000F0000LU)?16:0) \
  +((x&0x00F00000LU)?32:0) \
  +((x&0x0F000000LU)?64:0) \
  +((x&0xF0000000LU)?128:0)

#define B8(d) ((unsigned char)B8__(HEX__(d)))


#ifndef F_CPU
#define F_CPU 			4000000       	// Mhz 
#endif
#define UART_BAUD_RATE0		9600      	// 9600 baud
#define UART_BAUD_RATE1		4800      	// 9600 baud

#define RX1_BUFF_LENGTH 128
#define RX0_BUFF_LENGTH 128

#define MAXXX 60000

char rx1_buff[RX1_BUFF_LENGTH];
uint8_t rx1_count;

char rx0_buff[RX0_BUFF_LENGTH];
uint8_t rx0_count=0;


ISR(USART1_RX_vect)
{
       uint8_t c;
  
//         while ( 0 != (UCSR1A & _BV(RXC)) ) {
             c = UDR1;
             if (bit_is_clear(UCSR1A, FE)) {
                   if ( rx1_count < RX1_BUFF_LENGTH ) {
	                 rx1_buff[rx1_count++] = c;
//	             }
               }
         }
	 }

 ISR(USART0_RX_vect)
{
       uint8_t c;
  
       //          while ( 0 != (UCSR0A & _BV(RXC)) ) {
             c = UDR0;
	     	          if (bit_is_clear(UCSR0A, FE)) {
                   if ( rx0_count < RX0_BUFF_LENGTH ) {
		     rx0_buff[rx0_count++] = c;
		     //   } 
			  }
         }
}


void uart_init(void);

int uart0_putchar(char c, FILE *stream);
int uart0_getchar(void);
int uart1_getchar(void);
int ADConvert(short Channel, short DivFactor);

void adc_init(void);

int uart0_putchar(char c, FILE *stream) {

  if (c == '\n') uart0_putchar('\r', stream);
  loop_until_bit_is_set(UCSR0A, UDRE);
  UDR0 = c;

  return 0;
}






void uart_init(void) {
  unsigned char baudrateDiv;

  baudrateDiv = (unsigned char)((F_CPU+(UART_BAUD_RATE0*8L))/(UART_BAUD_RATE0*16L)-1);
  	
  UBRR0H = baudrateDiv >> 8;	
  UBRR0L = baudrateDiv;
	
  UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);
  UCSR0C = (1 << USBS0) | (3 << UCSZ0);

  fdevopen(uart0_putchar, NULL);
  printf("\n\nuart0_init();\n");

  baudrateDiv = (unsigned char)((F_CPU+(UART_BAUD_RATE1*8L))/(UART_BAUD_RATE1*16L)-1);

  UBRR1H = baudrateDiv >> 8;	
  UBRR1L = baudrateDiv;
	
  UCSR1B = (1 << RXEN1) | (1 << TXEN1) | (1 << RXCIE1);
  UCSR1C = (1 << UCSZ0) | (3 << UCSZ1);

  printf("\n\nuart1_init();\n");

}

void enable_external_ram (void) __attribute__ ((naked)) __attribute__ ((section (".init1")));

void enable_external_ram(void)
{
  /* 
   * enable external memory, no wait states 
   */
  MCUCR |= _BV(SRE);
}


int main(void)
{
  unsigned char * xram_ptr; 
  unsigned char chard,x, maske;
  unsigned int i,j,grr,kk;
  unsigned int counter, counter2;

  uint8_t my_rx1_count, my_rx0_count,myc;
  char my_rx1_buff[RX1_BUFF_LENGTH];
  char my_rx0_buff[RX0_BUFF_LENGTH];  
  char command_buff[RX0_BUFF_LENGTH];  

  uart_init();
  adc_init();
  sei();
  TCCR3A = 0x00;
  
  kk=i=0;

  //	    printf("\nprompt:\n");

  while (1) {

    //       printf("zzz %d\n",rx0_count);
    //1] log adc0 into RAM//paging
    counter2++;
    if (counter2==10) {counter++;counter2=0;}
    if (i<(MAXXX-2) && counter==30000){    
      maske=0;counter=0;
    //    DDRE=0xff;
        PORTE=PORTE&(maske<<5);
    PORTE=0xff;
    //    xram_ptr = (unsigned char *)(0x1100+i);
    grr=ADConvert(0,2);
    xram_ptr = (unsigned char *)(0x1100+i); //lsb
    *xram_ptr = (unsigned char) grr;
    xram_ptr = (unsigned char *)(0x1101+i); //msb
        *xram_ptr = (int) grr>>8;

	i+=2;kk++;
    }
    
    
    //2] check for log command on uart0 - interrupt

    //3] if so then output length

    // toggle bank -- PE7/6/5 - otherwise memory is from 1100->FFFF // 8 pages of 60K

       
    if ( rx0_count > 0 ) {
     
            cli();
      my_rx0_count = rx0_count;
      memcpy( my_rx0_buff, rx0_buff, rx0_count );
      rx0_count = 0;
            sei();
      
      for ( j = 0; j < my_rx0_count; j++ ) {
	printf("%c",my_rx0_buff[j]);
	command_buff[myc++]=my_rx0_buff[j];	
      }
      if (rx0_buff[my_rx0_count-1]==13){
	command_buff[myc-1]=0;
	myc=0;
	rx0_buff[rx0_count-1]=0;
	//    rx0_count = 0;

	if (strcmp(command_buff,"log")==0) {
	  //printf("zzzz"); // dump log
	  for (j=0; j<i; j+=2){
	    //	    xram_ptr = (unsigned char *)(0x1100+j);
	    //	    chard=*xram_ptr;
	    xram_ptr = (unsigned char *)(0x1100+j);
	    grr=*xram_ptr;
	    xram_ptr = (unsigned char *)(0x1101+j);
	    grr |= ((int)(*xram_ptr))<<8;  
	    printf("%d\n", grr);    
	   
	  }}

if (strcmp(command_buff,"live")==0) {
  printf("\n%d\n", ADConvert(0,128));    
 }

if (strcmp(command_buff,"num")==0) {
  printf("\n%d\n", kk);    
 }

if (strcmp(command_buff,"reset")==0) {
  kk=i=0;
  printf("\n%d\n", kk);    
 }


	printf("\nxxxxx:");
	
      }
    }
  }
}



void adc_init(void)
{
  /*
  sbi(ADCSRA,ADEN); // enables ADC by setting bit 7 (ADEN) in the ADCSRA
  sbi(ADCSRA,ADFR); // single sample conversion by clearing bit 5 (ADFR) in the ADCSRA
  ADCSRA = ((ADCSRA & B8(11111000)) | B8(00000111)); // selects div by 64 clock prescaler
  ADMUX = ((ADMUX & B8(00111111)) | B8(01000000));         // selects AVCC as Vref
  cbi(ADMUX,ADLAR);       // selects right adjust of ADC result
  ADMUX &= B8(11100000); // selects single-ended conversion on PF0*/
  

  ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescalar to 128 - 125KHz sample rate @ 16MHz

  ADMUX |= (1 << REFS0); // Set ADC reference to AVCC
  //  ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading

  // No MUX values needed to be changed to use ADC0

  ADCSRA |= (1 << ADFR);  // Set ADC to Free-Running Mode

  ADCSRA |= (1 << ADEN);  // Enable ADC 

  DDRF = 0x00; // configure a2d port (PORTF) as input so we can receive analog signals
  PORTF = 0x00; // make sure pull-up resistors are turned off (else we’ll just read 0xCFF)


}

	int ADConvert(short Channel, short DivFactor)
{	
		int ADresult;                                                   
		        int DivMask = 0;
			int i;
			ADMUX = 0xC0 | (Channel & 0x07);                
			for (i = 0; i < 8; i++)
			  {
			    if (DivFactor & 0x01)
			      DivMask = i;
			    DivFactor >>= 1;
			  }
			ADCSRA = (0x90 | DivMask);

			for (i = 0; i < 400; i++)
			  {
			    asm volatile ("nop");
			  }

			sbi(ADCSRA, ADSC);                              /* Start ADC    */
			loop_until_bit_is_set(ADCSRA, ADIF);  
			ADresult = ADCL;                 
			ADresult |= ((int)ADCH) << 8;           
			ADCSRA = 0x10;
			
			return(ADresult);
}




