/* ECE 4760 Final Project
 * Spring 2010
 * Image Scan Using Phototransistor Array
 * Yunchi Luo yl477 Mengliang Yu my288
 *
 * Handles the entire scan routine on the MCU. This file
 * contains the control of the stepper motors as they
 * move the scanner head across the entire platform. Also
 * starts the ADC conversions for scanning light
 * intensity using the phototransistors and sends them to
 * MATLAB. Nothing is done until a start command is
 * received from MATLAB, in the form of the ASCII string
 * "start". The stop command is conversely, the ASCII
 * string "stop"
 */
//++++++++++++++++++++++++++++++++++++++++++

//Port A Phototransistor
//Port B Motor
//Port C
//Port D


#include <inttypes.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <string.h>
#include "uart.h"
#include "camera.h"


// UART file descriptor
// putchar and getchar are in uart.c
FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);

//custom putchar and getchar
//NO BACKSPACE OR ECHO implemented
//--- getchar ---
char shell_getchar(void) {
	loop_until_bit_is_set(UCSR0A, RXC0);
	return UDR0 ;
}

//--- putchar ---
void shell_putchar(char c) {
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = c ;
}

FILE shell_uart = FDEV_SETUP_STREAM(shell_putchar, shell_getchar, _FDEV_SETUP_RW);

//control motor movement
ISR (TIMER0_OVF_vect){
	count--;
	if (count==0){
		FLIP(PORTD,PORTD2);
		count = pulse_width;
		//Show which pins of the vertical motor are on. Lower bits
		// used for status indicators
		PORTC = ~PORTMOTOR;
		
		//state machine for motor. Runs if motor is
		// not at the desired position
		//Total 4 states, one for every quarter revolution
		//On every state change, num_turns is
		//decremented by 1
		//When state changes, set the output for the
		//corresponding PIN high, while setting all
		//other PINs low.
		if(posX==posXtarget&&posY==posYtarget) {
      moving = 0;
	  } else {
      moving = 1;
      
  		//Horizontal Motor State Machine
  		if(posX<posXtarget){ 
    		motorStateH++;
        posX++;
    		if(motorStateH > STEP4){
    			motorStateH = 0; //1 full rev
    		}
  		} else if(posX>posXtarget){
  		  motorStateH--;
        posX--;
    		if(motorStateH>>7){
    			motorStateH = STEP4; //1 full rev
    		}
  		}
		
  		//Vertical Motor State Machine
  		if(posY<posYtarget){ 
    		motorStateV++;
        posY++;
    		if(motorStateV > STEP4){
    			motorStateV = 0; //1 full rev
    		}
  		} else if(posY>posYtarget){
  		  motorStateV--;
        posY--;
    		if(motorStateV>>7){
    			motorStateV = STEP4; //1 full rev
    		}
  		}
	  }
		
		//horizontal motor output
		switch(motorStateH) {
			case STEP1:
        PORTMOTOR = (PORTMOTOR & 0xf0) | (1<<H1);
				break;
			case STEP2:
        PORTMOTOR = (PORTMOTOR & 0xf0) | (1<<H2);
				break;
			case STEP3:
        PORTMOTOR = (PORTMOTOR & 0xf0) | (1<<H3);
				break;
			case STEP4:
        PORTMOTOR = (PORTMOTOR & 0xf0) | (1<<H4);
				break;
		}
		
		//vertical motor output
		switch(motorStateV) {
			case STEP1:
        PORTMOTOR = (PORTMOTOR & 0x0f) | (1<<V1);
				break;
			case STEP2:
        PORTMOTOR = (PORTMOTOR & 0x0f) | (1<<V2);
				break;
			case STEP3:
        PORTMOTOR = (PORTMOTOR & 0x0f) | (1<<V3);
				break;
			case STEP4:
        PORTMOTOR = (PORTMOTOR & 0x0f) | (1<<V4);
				break;
		}
	}
}

//receive commands from MATLAB
ISR (USART0_RX_vect) {
    fscanf(&shell_uart,"%s",in_buffer);
    if((!scanning) && (strcmp(in_buffer,"start")==0)) {
        scanning = 1;
    } else if((scanning) && (strcmp(in_buffer,"stop")==0)) {    
        scanning = 0;
        moveTo(0,0);
    }
}

/*
	Set the target motor position
*/
void moveTo(int x, int y) {
  posXtarget = x;
  posYtarget = y;
  //check bounds
  if(x<0) {
    posXtarget = 0;
  }
  if(y<0) {
    posYtarget = 0;
  }
  if(x>X_MAX) {
    posXtarget = X_MAX;
  }
  if(y>Y_MAX) {
    posYtarget = Y_MAX;
  }
  moving = 1;
}

void initialize(void){
	//Set PortB for Motor Control
	DDRB = 0xff;
	// timer 0 runs at clk/256, 62.5 cycle per second
	TCCR0B = 0b000000010;  
	//turn on timer 0 overflow ISR
	TIMSK0 = (1<<TOIE0) ;
	count = countMS;
	//motor state init
  moving = 0;
  motorStateH = motorStateV = STEP1;
  posX=0;
  posY=0;
  posXtarget=0;
  posYtarget=0;
  PORTMOTOR = 0x88;

  //LED
  DDRC = 0xff;
  PORTC = 0xff;
  DDRD = DDRD | 0x04;
  
  //init the A to D converter 
  //channel zero/ left adj /EXTERNAL Aref
  //!!!CONNECT Aref jumper!!!!
  ADMUX = (1<<ADLAR) | (1<<REFS1) | (1<<REFS0);//(1<<ADLAR) | (1<<REFS0);
  
  //enable ADC and set prescaler to 1/128*16MHz=125,000
  //and clear interupt enable
  ADCSRA = (1<<ADEN) | 0x07 ;
  
  //init the UART -- uart_init() is in uart.c
  uart_init();
  stdout = stdin = stderr = &uart_str;
  //fprintf(stdout,"Starting timers...\n\r");
  //fflush(stdout);
  SET(UCSR0B,RXCIE0);
  
  //enable interrupts
  sei();
}

void transistorScan(void){
	char i;
  char buffer;
	i = 0;

  //scan all phototransistors from PortA0 to PortA7
	while(i<=7){
		if(READ(ADCSRA,ADSC)==0){
		  //send previous conversion to MATLAB
    	if(i>0) {
        buffer = ADCH;
        uart_putchar(buffer,&uart_str);
    	}
			ADMUX = (ADMUX & 0xf8) | i; //PortA0 to PortA7 scan
			ADCSRA |= (1<<ADSC); //start the conversion
			i++;
		}
  }
  //send last conversion to MATLAB
	buffer = ADCH;
  uart_putchar(buffer,&uart_str);
}
  
int main(void) {
  initialize();
	char buffer[30];
  //run motor in forward then reverse and repeat indefinitely
  char xdir = LEFT;
  
  while(1) {
  	//Debugging =======
  	//fscanf(stdout,"%s",buffer);
	//fprintf(stdout,"you said %s\n",buffer);
	//============
    //scan control loop
  	if(!moving && scanning) {
      transistorScan();
      
      //if moving left and not at left end, then move left
      if(xdir == LEFT && (posX <= X_MAX-X_STEP)) {
        left(X_STEP);
      }
      //if moving right and not at right end, then move right
      else if(xdir == RIGHT && (posX >= X_STEP)) {
        right(X_STEP);
      } else {
        //if not at the bottom, move down and change X direction
        // otherwise stop
        if(posY <= Y_MAX-Y_STEP) {
          down(Y_STEP);
          xdir = xdir ^ 0x01;
        } else {
          scanning = 0;
          moveTo(0,0);
        }
      }
    } else if(!scanning) {
	   xdir = LEFT;
	}
  }
}
