#include "pic16f628.h"

typedef unsigned int word;
word at 0x2007  __CONFIG = _CP_OFF & _WDT_ON & _BODEN_ON & _PWRTE_ON & _EXTCLK_OSC & _MCLRE_ON & _LVP_OFF ; 
#define HZ 1000
/* CLK is osc/4 */
#define CLK 1000000
#define HZ_T 65535-(CLK/HZ)
#define HZ_L (HZ_T % 255)
#define HZ_H (HZ_T / 256)
#define M0_SPEED_MIN 15
#define M0_SPEED_MAX 25
#define M1_SPEED_MIN 15
#define M1_SPEED_MAX 25
#define M0_DELTA_DELAY 100
#define M0_DELTA_T 1
#define M1_DELTA_DELAY 100
#define M1_DELTA_T 1

#define ClrWdt()        do { _asm clrwdt _endasm; } while(0)

	volatile unsigned short m0_speed=0; /* steps per second... */
	volatile unsigned short m0_spd_count=0; /* number of ticks since last pulse */
	volatile unsigned short m0_count=0; /* number of steps total */
	volatile unsigned short m0_togo=0; /* number of steps remaining */
	volatile unsigned char m0_direction=0; /* 0 or 1, just the pin output */
	volatile unsigned char m0_phase=0; /* 0 stopped;  1 ramp up, 2 stable 3, ramp down */
        volatile unsigned char m0_stepoff=0; /* should we shutoff the step */
	volatile unsigned short m0_speed_max=M0_SPEED_MAX;
	volatile unsigned short m0_speed_min=M0_SPEED_MIN;
	volatile unsigned short m0_rampup=0; /* number of pulses we used from speed min to max */
        volatile unsigned short m0_delta_delay=M0_DELTA_DELAY; /* number of Hz between changes */
	volatile unsigned short m0_delta_t=M0_DELTA_T; /* amount of change in steps per second */	
volatile unsigned short m0_delta_count=0;
        volatile unsigned char m0_move=0;

	volatile unsigned short m1_speed; /* steps per second... */
	volatile unsigned short m1_spd_count; /* number of ticks since last pulse */
	volatile unsigned short m1_count; /* number of steps total */
	volatile unsigned short m1_togo; /* number of steps remaining */
	volatile unsigned char m1_direction; /* 0 or 1, just the pin output */
	volatile unsigned char m1_phase; /* 0 stopped;  1 ramp up, 2 stable 3, ramp down */
        volatile unsigned char m1_stepoff; /* should we shutoff the step */
	volatile unsigned short m1_speed_max;
	volatile unsigned short m1_speed_min;
	volatile unsigned short m1_rampup; /* number of pulses we used from speed min to max */
        volatile unsigned short m1_delta_delay; /* number of Hz between changes */
	volatile unsigned short m1_delta_t; /* amount of change in steps per second */	
	volatile unsigned short m1_delta_count;
        volatile unsigned char m1_move;

static void set_step(unsigned char m, unsigned char i) {
  if (m== 0 ) {
    RA0=i;
  } else if (m == 1 ) {
    RB5 = i;
  };
}

static void set_dir(unsigned char m, unsigned char i) {
  if (m== 0 ) {
    RA1=i;
  } else if (m == 1 ) {
    RB6 = i;
  };
}

static void set_power(unsigned char m, unsigned char i) {
  if (m== 0 ) {
    RA2=i;
  } else if (m == 1 ) {
    RB7 = i;
  };
}



void intr () interrupt 0  {
	if (TMR1IF) {
	  /* tmr1 has overflowed, first we reset it */
	  TMR1ON=0;
	  TMR1L=HZ_L;
	  TMR1H=HZ_H;
	  TMR1ON=1;
	  TMR1IF=0;
	  /* now we handle the post processing */
	    if (m0_stepoff) {
	      set_step(0,0);
	      m0_stepoff=0;
	      if (m0_phase == 0 ) {
		set_power(0,0);
	      };
	    };
	    /* are we running */
	      if (m0_phase != 0 ) {
	      /* first handle any speed change */
	      if (m0_phase == 1 && m0_togo < m0_count/2 ) {
		m0_phase=3;
	      };
	      if (m0_phase == 1 ) {
		if (m0_delta_count > m0_delta_delay) {
		  m0_delta_count =0;
		  m0_speed = m0_speed + m0_delta_t;
		  if (m0_speed >= m0_speed_max) { 
		    m0_phase = 2;
		    m0_rampup = m0_count - m0_togo;
		    m0_speed = m0_speed_max;
		  };
		};
		m0_delta_count++;
	      };
	      
	      if (m0_phase == 2 && m0_togo < m0_rampup ) {
		m0_phase=3;
		m0_delta_count = 0;
	      };
	      if (m0_phase == 3 ) {
		if (m0_delta_count > m0_delta_delay ) {
		  m0_delta_count = 0;
		  m0_speed = m0_speed - m0_delta_t;
		  if (m0_speed <= m0_speed_min) {
		    /* don't change phase,
		       only do that when we run out of pulses */
		    m0_speed=m0_speed_min;
		  }; 
		};
		m0_delta_count++;
	      };
	      /* phases are handled.
		 determine if it's time to step the motor. */
	      m0_spd_count++;
	      if (m0_speed == 0 ) {
		m0_phase = 0; /* odd, shouldn't see this */
	      } else if (m0_spd_count > (HZ / m0_speed)) { 
		m0_spd_count=0;
		/* steptime */
		set_step(0,1);
		m0_stepoff=1;
		m0_togo--;
		if (m0_togo == 0 ) {
		  /* no more moving */
		  m0_move = 2 ; /* send ok */
		  m0_speed = 0;
		  m0_phase = 0;
		};
		
	      };
	      };
	  
	};
	
}
static void varset(unsigned char m, unsigned short val, unsigned char var) {
  if (m == 0 ) {
    switch (var) {
  case 2:
    m0_speed_min=val;
    break;
  case 3:
    m0_speed_max=val;
    break;
  case 4:
    m0_delta_delay = val;
    break;
  case 5:
    m0_delta_t = val;
    break;
    };
  };
}
    
static void move(unsigned char m, unsigned short steps, unsigned char dir) {
  if (m==0) {
	m0_phase=0;
	m0_spd_count=0;
	m0_rampup=0;
	m0_delta_count=0;

	if (steps != 0 ) {
	  m0_speed = m0_speed_min;
	  m0_count= steps;
	  m0_togo = steps;
	  m0_direction = dir;
	  /* set to full power here */
	  set_power(0,1);
	  set_dir(0,dir);
	  m0_phase= 1;
	  m0_move = 1; /* flag move started */
	} else {
	  m0_speed=0;
	  m0_count=0;
	  m0_togo=0;
	  m0_move = 0;
	};
  };
	/*  } else if (m == 1 ) {
	m1_phase=0;
	m1_spd_count=0;
	m1_rampup=0;
	m1_delta_count=0;

	if (steps > 0 ) {
	  m1_speed = m1_speed_min;
	  m1_count=steps;
	  m1_togo = steps;
	  m1_direction = dir;
	  m1_phase=1;
	
	  set_power(m,1);
	  m1_move = 1;
	} else {
	  m1_speed=0;
	  m1_count=0;
	  m1_togo=0;
	  m1_move = 0;
	};
  };
*/

}



void main() {
  unsigned char m=0;
  unsigned char rx_phase=0;
  unsigned char rx_motor=0;
  unsigned char work_dir=0;
  unsigned short work_count=0;
  unsigned char work_char=0;
  unsigned char tx_phase=0;

  ClrWdt();

  /* set motors to off, this will be done by the C init of the 
   global variables */

  /* setup port config */
  PORTA=0;
  PORTB=0;
  CMCON = 7; /* Comparator off, pins to I/O */
  /* no interrupts for now */
  PIE1=0;
  INTCON = 0;
  OPTION_REG=128; /* prescaler on Timer0, pull-ups on B disabled */

  /* set port direction bits */
  /* we use port A for our 2 motors */
  TRISA=0;
  /* Setup USART pins */
  TRISB=0;
  TRISB1=1;
  TRISB2=1;

  for (m=0; m++; m<2) {
    set_power(m,0);
    set_step(m,0);
  };
  /* setup USART */
  SYNC = 0;
  BRGH = 1;
  SPBRG = 25;
  RX9 = 0;
  SPEN = 1;
  TXIE = 0 ;
  RCIE = 0 ;
  TXEN = 1;
  CREN = 1;



    /* Setup timer1 */
    TMR1ON=0;
    TMR1IF=0;
    T1CKPS0=0;
    T1CKPS1=0;
    T1OSCEN=0;
    TMR1CS=0;
    TMR1L=HZ_L;
    TMR1H=HZ_H;
    /* enable the timer, start interrupts */
    TMR1IF=0;
    TMR1ON=1;
    TMR1IE=1;
    /* set variables  */

/* main loop, wait for input, process, control motor and send responses */
	GIE=1;
	PEIE = 1;
    while(1) {
      ClrWdt();
      //      if (m0_phase == 0 ) {
      //	work_dir++; if (work_dir > 1) {work_dir = 0;};
      //	move(0,120,work_dir);
      //      };



      /* first process any incoming data */
	 if (RCIF) {
	   work_char = RCREG ; 
	   switch(rx_phase) {
	   case(0): 
	     if (work_char == 'x' ) { rx_motor=0 ; rx_phase++;} 
	     else 
	       if (work_char == 'y' ) {rx_motor=1; rx_phase++;};
	     break;
	   case(1):
	     /* direction */ 
	     if (work_char == '+' ) { work_dir=0 ; rx_phase++;} 
	     else 
	       if (work_char == '-' ) {work_dir=1; rx_phase++;} 
	     else 
	       if (work_char == 'a' ) {work_dir=2; rx_phase++;} 
	     else 
	       if (work_char == 'b' ) {work_dir=3; rx_phase++;} 
	     else 
	       if (work_char == 'c' ) {work_dir=4; rx_phase++;} 
	     else 
	       if (work_char == 'd' ) {work_dir=5; rx_phase++;} 

	       else rx_phase = 0;
	     break;
	   case(2):
	     work_count=0;
	     rx_phase++;
	   case(3):
	     if (work_char == 13 || work_char == 10 || work_char == ',' ) {
	       if (work_dir > 1 ) {
		 varset(rx_motor,work_count,work_dir);
	       } else {
	       move(rx_motor,work_count,work_dir);
	       };
	       work_count=0;
	       
	       rx_phase=0;
	     } else if (work_char >= '0' && work_char <= '9' ) {
	       work_count = (work_count * 10 ) + (work_char - '0');
	     } else {
	       /* invalid character */
	       rx_phase = 0 ;
	     };
	     break;
	   };
	 };
	 /* do we want to send anything */
	 /* first, ok to send... */
	 if (TXIF) {
	   switch (tx_phase) {
	   case(0):
	     /* see if anything is pending */
	     if (m0_move== 1 ) {
	       m0_move = 0;
	       /* send xgo\n */
	       tx_phase = 1;
	       break;
	     };
	     if (m0_move== 2 ) {
	       m0_move = 0;
	       /* send xok\n */
	       tx_phase = 5;
	       break;
	     };
	     if (m1_move== 1 ) {
	       m1_move = 0;
	       /* send ygo\n */
	       tx_phase = 9;
	       break;
	     };
	     if (m1_move== 2 ) {
	       m1_move = 0;
	       /* send yok\n */
	       tx_phase = 10;
	       break;
	     };
	     //	     tx_phase=0;
	     break;
	   case(1):
	     TXREG='x';
	     tx_phase++;
	     break;
	   case(2):
	     TXREG='g';
	     tx_phase++;
	     break;
	   case(3):
	     TXREG='o';
	     tx_phase++;
	     break;
	   case(4):
	     TXREG=10;
	     tx_phase=0;
	     break;
	   case(5):
	     TXREG='x';
	     tx_phase++;
	     break;
	   case(6):
	     TXREG='o';
	     tx_phase++;
	     break;
	   case(7):
	     TXREG='k';
	     tx_phase++;
	     break;
	   case(8):
	     TXREG=10;
	     tx_phase=0;
	     break;
	   case(9):
	     TXREG='y';
	     tx_phase=2;
	     break;
	   case(10):
	     TXREG='y';
	     tx_phase=6;
	     break;
	   case(11):
	     TXREG='.';
	     tx_phase=0;
	     break;
	   };
	 };


	     
    };

}
    
