/*

 +-------------------------------------+
 |                          Sig Vd Gnd |
 |  +---------+   5V O     PB0 [o o o] | 
 |  | 7805  O |   Vd O     PB1 [o o o] | 
 |  +---------+   V+ .     PB2 [o o o] | 
 |                         PB3 [o o o] | 
 |                         PB4 [o o o] | 
 |                         PB5 [o o o] | 
 |                         PB6 [o o o] | 
 |                         PB7 [o o o] | 
 |                         PA0 [o o o] | <- Limit 0 
 |                         PA1 [o o o] | <- Limit 1
 |        +----------+     PA2 [o o o] | <- Limit 2
 |        |O         |     PA3 [o o o] | <- Limit 3
 |        |          |     PA4 [o o o] | <- Limit 4
 |        |          |     PA5 [o o o] | <- Limit 5
 |        |          |     PA6 [o o o] | <- Limit 6
 |        |          |     PA7 [o o o] | <- Limit 7
 |        |          |     PC7 [o o o] | 
 |        |          |     PC6 [o o o] | 
 |        |          |     PC5 [o o o] | 
 |        | ATMEGA32 |     PC4 [o o o] | 
 |        |          |     PC3 [o o o] | 
 |        |          |     PC2 [o o o] | -> LS595 strobe
 |        |          |     PC1 [o o o] | -> LS595 data
 |        |          |     PC0 [o o o] | -> ls595 clock
 |        |          |     PD7 [o o o] | 
 |        |          |     PD2 [o o o] |
 |        |          |     PD3 [o o o] |
 |        |          |     PD4 [o o o] | 
 |        |          |     PD5 [o o o] | 
 |        +----------+     PD6 [o o o] | 
 |      E.D.S BABYBOARD III            |
 +-------------------------------------+



control motors on ports B and C, port A can be used for limit switch
inputs


Serial protocol:
115200 baud, 8N1

commands:
\n:   motor sync
A:   queue step 0 forward
a:   queue step 0 back  
B:   queue step 1 forward
b:   queue step 1 back
C:   queue step 2 forward
c:   queue step 2 back
D:   queue step 3 forward
d:   queue step 3 back
E:   queue step 4 forward
e:  queue step 4 back
F:  queue step 5 forward
f:  queue step 5 back
G:  queue step 6 forward
g:  queue step 6 back
H:  queue step 7 forward
h:  queue step 7 back
U:  echo, send 'u' when recieved 'U' (testing)
?: force input status update
s: start timer number entry (enter digits, . to stop)



replies:
'.': step complete
A: limit sw 1 went high
a: limit sw 1 went low
B: limit sw 2 went high
b: limit sw 2 went low
C: limit sw 3 went high
c: limit sw 3 went low
D: limit sw 4 went high
d: limit sw 4 went low
E: limit sw 5 went high
e: limit sw 5  went low
F: limit sw 6 went high
f: limit sw 6 went low
G: limit sw 7 went high
g: limit sw 7 went low
H: limit sw 8 went high
h: limit sw 8 went low



*/

#include "avrcommon.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include "usart.h"

// mind LS595settings.h
#include "74LS595.h"

#include "binary.h"

// misc

#define OUTPUT             1
#define INPUT              0

#define FOR 1
#define BAK -1

#define isDigit(C)    (((C)>='0') && ((C)<='9'))
#define setForward(m) (((m)->State) &= 0x03)
#define setReverse(m) (((m)->State) |= 0x04)
#define setStep(m)    (((m)->Step)   = 1)
#define clearStep(m)  (((m)->Step)   = 0)

typedef struct stepper4ph_t {    
      unsigned State :4;
      unsigned Step  :1;      
      unsigned Sleep :1;
} stepper4ph ;

unsigned char stateTable[] = {  
    (3)+(b0101<<4),                    
    (0)+(b0110<<4),
    (1)+(b1010<<4),
    (2)+(b1001<<4),
    (5)+(b0101<<4),                    
    (6)+(b0110<<4),
    (7)+(b1010<<4),
    (4)+(b1001<<4)      
};  

unsigned char stepmotor (stepper4ph * motor) ;   

unsigned char oPINA;

stepper4ph motors[6];

volatile char StepReady;
volatile char SendReady;
volatile unsigned int  tempTimer;
volatile unsigned int  timerTop;

void transmittchanges() ;
void sync() ;
void docmd(unsigned char command) ;
void initCompleteSignal() ;
void step(stepper4ph * motor, char dir) ;
void printNumber16(unsigned int n) ;
void inline printDigit(unsigned char n) ;


int main(void) {

  unsigned int inputsTimer;

 // set up directions 
  DDRA = (INPUT << PA0 | INPUT << PA1 |INPUT << PA2 |INPUT << PA3 |INPUT << PA4 |INPUT << PA5 |INPUT << PA6 |INPUT << PA7);
  DDRB = (INPUT << PB0 | INPUT << PB1 |INPUT << PB2 |INPUT << PB3 |INPUT << PB4 |INPUT << PB5 |INPUT << PB6 |INPUT << PB7);
  DDRC = (OUTPUT << PC0 | OUTPUT << PC1 |OUTPUT << PC2 |INPUT << PC3 |INPUT << PC4 |INPUT << PC5 |INPUT << PC6 |INPUT << PC7);
  DDRD = (INPUT << PD0 | INPUT << PD1 |INPUT << PD2 |INPUT << PD3 |INPUT << PD4 |INPUT << PD5 |INPUT << PD6 |INPUT << PD7);   

  PORTA = 0xFF;  // turn on port a pullups
  timerTop = 4000;
  
  StepReady   = 0;
  SendReady   = 0;
  inputsTimer = 90; // part of temp hack, to address comm saturation via input flapping
  USART_Init( 7 ); //115200 @ 14.74 Mhz
  
  motors[0].State = 0;
  motors[1].State = 0;
  motors[2].State = 0;
  motors[3].State = 0;
  motors[4].State = 0;
  motors[5].State = 0;
  
  // turn all steppers off
  LS595StrobeL();
  LS595Send (0x00);
  LS595Send (0x00);
  LS595Send (0x00);
  LS595StrobeH();

  while(1) {
  
    if (HAVEDATA) {
      docmd(USART_Receive());
    }
    
    if (SendReady) {
       USART_Transmit('.');
       SendReady = 0;
    }
    
    if ((inputsTimer -= 1) == 0 ) {
      transmittchanges();
      inputsTimer = 4000;
    }
    
    if (tempTimer) if ((tempTimer -= 1) == 0) SendReady = 1;        
    
    
  }

}




void transmittchanges() {

   unsigned char tPINA;
  
  tPINA = PINA;  // snapshot the ports
    if ((tPINA^oPINA) != 0) {
      if ((tPINA^oPINA) & 0x01) { USART_Transmit( ((tPINA&0x01)>0?'A':'a')); } 
      if ((tPINA^oPINA) & 0x02) { USART_Transmit( ((tPINA&0x02)>0?'B':'b')); } 
      if ((tPINA^oPINA) & 0x04) { USART_Transmit( ((tPINA&0x04)>0?'C':'c')); } 
      if ((tPINA^oPINA) & 0x08) { USART_Transmit( ((tPINA&0x08)>0?'D':'d')); } 
      if ((tPINA^oPINA) & 0x10) { USART_Transmit( ((tPINA&0x10)>0?'E':'e')); } 
      if ((tPINA^oPINA) & 0x20) { USART_Transmit( ((tPINA&0x20)>0?'F':'f')); } 
    }
  oPINA = tPINA;

}


void docmd(unsigned char command) {

  static char mode = 0;
  static unsigned int number = 0;

  if (mode == 0) {
    switch(command) {
      case '\r': sync();        break;    // motor sync
      case 'A':  step(&motors[0], FOR);  break;    // step 0 forward
      case 'a':  step(&motors[0], BAK);  break;    // step 0 back  
      case 'B':  step(&motors[1], FOR);  break;    // step 1 forward
      case 'b':  step(&motors[1], BAK);  break;    // step 1 back
      case 'C':  step(&motors[2], FOR);  break;    // step 2 forward
      case 'c':  step(&motors[2], BAK);  break;    // step 2 back
      case 'D':  step(&motors[3], FOR);  break;    // step 3 forward
      case 'd':  step(&motors[3], BAK);  break;    // step 3 back
      case 'E':  step(&motors[4], FOR);  break;    // step 4 forward
      case 'e':  step(&motors[4], BAK);  break;    // step 4 back
      case 'F':  step(&motors[5], FOR);  break;    // step 5 forward
      case 'f':  step(&motors[5], BAK);  break;    // step 5 back

      case 'U':  USART_Transmit(117);    break;  // echo

      case '?':  oPINA = ~oPINA;         break;  // force status update

      case 's':  number = 0; mode = 1;   break;  // switch to number mode for timer

    }
  } else {
    if (0) {    
    } else if (isDigit(command)) {        
      number *= 10;
      number += (command - '0');
    } else if (command == '.') { // apply value and switch back
      timerTop = number;
      mode = 0;
    }
    
  }
}

unsigned char stepMotor (stepper4ph * motor) {         
   unsigned char index;
   
   index = stateTable[motor->State];
   
   motor->State  = (index & 0x0F);      // calc next state      
   return          (index & 0xF0) /*>> 4*/; // calc motor bits   
  
}


void step(stepper4ph * motor, char dir) {
  
  if  (dir == FOR) setForward(motor);
  else             setReverse(motor);     
  setStep(motor);   
  
}


void sync() {
 // set up outputs
 static unsigned char out1, out2, out3 = 0;
 
 // in 3.3ms send done (0x00) 109 clocks at 32.768khz, 13 * 32768/8
 initCompleteSignal();
 
  if (motors[0].Step != 0) {
   out1 &= 0x0F;
   out1 |= stepMotor(&motors[0]);
   clearStep(&motors[0]);
  }
  
  if (motors[1].Step != 0) {
   out1 &= 0xF0;
   out1 |= (stepMotor(&motors[1]) >> 4);
   clearStep(&motors[1]);
  }
  
  if (motors[2].Step != 0) {
   out2 &= 0x0F;
   out2 |= stepMotor(&motors[2]);
   clearStep(&motors[2]);
  }
  
  if (motors[3].Step != 0) {
   out2 &= 0xF0;
   out2 |= (stepMotor(&motors[3]) >> 4);
   clearStep(&motors[3]);
  }
  
  if (motors[4].Step != 0) {
   out3 &= 0x0F;
   out3 |= stepMotor(&motors[4]);
   clearStep(&motors[4]);
  }
  
  if (motors[5].Step != 0) {
   out3 &= 0xF0;
   out3 |= (stepMotor(&motors[5]) >> 4);
   clearStep(&motors[5]);
  }
 
  // output them
  LS595StrobeL();
  LS595Send (out1);
  LS595Send (out2);
  LS595Send (out3);
  LS595StrobeH();
  
 // in 3.3ms send done (0x00) 109 clocks at 32.768khz, 13 * 32768/8
 initCompleteSignal();
  
}




void initCompleteSignal() {

 StepReady = 0;
 tempTimer = timerTop;
 
 // setup timer to trigger send of 0x00
 
}


void inline printDigit(unsigned char n) {
  USART_Transmit( (n & 0x0F) | 0x30 );
}


void printNumber16(unsigned int n) {
  unsigned int d;
  
  d = n/10000;
  printDigit(d);
  n -= d * 10000;
  
  d = n/1000;
  printDigit(d);
  n -= d * 1000;

  d = n/100;
  printDigit(d);
  n -= d * 100;
  
  d = n/10;
  printDigit(d);
  n -= d * 10;
  
  printDigit(n);

}



