#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 16000000UL
#include <util/delay.h>
#include <math.h>

#define LED PD5
#define EN1 PB3
#define EN2 PB4

#define A1  PB2
#define A2  PB1
#define B1  PB0
#define B2  PD6

#define ENPIN PB5
#define DIRPIN PB7
#define STEPPIN PD3

#define read_pin(port, pin) port & (1<<pin)
#define output_low(port,pin) port &= ~(1<<pin)
#define output_high(port,pin) port |= (1<<pin)
#define set_input(portdir,pin) portdir &= ~(1<<pin)
#define set_output(portdir,pin) portdir |= (1<<pin)


int step_number = 0;
const int number_of_steps = 48;

volatile uint8_t chip_enabled = 0;
volatile uint8_t step_direction = 0;
uint8_t step_cmd = 0;


void enable(){
        output_high(PORTB, EN1);
        output_high(PORTB, EN2);
}

void disable(){
        output_low(PORTB, EN1);
        output_low(PORTB, EN2);
}

void step_full(uint8_t microstep) {
//takes next_step in the half step sequence
        uint8_t quadrant = microstep % 4;
        switch (quadrant){
                case 0: //0110
                        output_low (PORTB, A1);
                        output_high (PORTB, A2);
                        output_high (PORTB, B1);
                        output_low (PORTD, B2);
                break;
                case 1: //0101
                        output_low (PORTB, A1);
                        output_high (PORTB, A2);
                        output_low (PORTB, B1);
                        output_high (PORTD, B2);
                break;
                case 2: //1001
                        output_high (PORTB, A1);
                        output_low (PORTB, A2);
                        output_low (PORTB, B1);
                        output_high (PORTD, B2);
                break;
                case 3: //1010
                        output_high (PORTB, A1);
                        output_low (PORTB, A2);
                        output_high (PORTB, B1);
                        output_low (PORTD, B2);
                break;
        }
}


void step(uint8_t direction)
{
  // decrement the number of steps, moving one step each time:
          // move only if the appropriate delay has passed:
           if (direction == 1)
                {
                step_number++;
                if (step_number == number_of_steps)
                        {
                          step_number = 0;
                        }
                }
           else {
                if (step_number == 0) {
                        step_number = number_of_steps;
                }
         step_number--;
        }
        step_full (step_number);
}

ISR(INT1_vect){
        if (step_cmd==0){
                step_cmd=1;
        }
}


int main(void) {

// initialize outputs
set_output(DDRD, LED);
set_output(DDRB, EN1);
set_output(DDRB, EN2);
set_output(DDRB, A1);
set_output(DDRB, A2);
set_output(DDRB, B1);
set_output(DDRD, B2);

set_input(DDRB, ENPIN);
set_input(DDRB, DIRPIN);
set_input(DDRD, STEPPIN);

//blink once to see init
output_high(PORTD, LED);
_delay_ms(250);
output_low(PORTD, LED);
_delay_ms(250);
cli();

PCMSK |= (1<<PIND3);
MCUCR = (1<<ISC11) | (0<<ISC10);
GIMSK  |= (1<<INT1);

//enable interrupts*/
sei();

/*init_pwm();*/

while (1) {
        if (!(read_pin(PINB, ENPIN)) ){
        //      output_high(PORTD, LED);
                enable();
        }
        else{
        //      output_low(PORTD, LED);
                disable();
        }
        if (step_cmd){
                if ((read_pin(PINB,DIRPIN))){
                        output_high(PORTD, LED);
                        step(1);
                }
                else{
                        step(0);
                        output_high(PORTD, LED);
                }
                step_cmd=0;
        }
        output_low(PORTD, LED);
}
}

