//******************************************************************************
//   DOA_Stepper.C
//
// part of the PHCC (PIC HomeCockpit Controller) Project
//
// This is the 4x Stepper motor controller that consists
// of a PIC, 4 stepper motors and 4 L293D drivers.
//
// Copyright (c) 2008 by Danny Faber <danny.faber AT online.nl>
//
//  The full text of the legal notices is contained in the file called
//  COPYING, included with this distribution.
//
//  This program is free software; you can redistribute it and/or
//  modify it under the terms of the GNU General Public License
//  as published by the Free Software Foundation; either version 2
//  of the License, or (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.                                                                          *
//
//******************************************************************************

#define DOA_CLK PORTB.f0
#define DOA_DATA PORTB.f1
#define DOA_CLK_TRIS TRISB, 0
#define DOA_DATA_TRIS TRISB, 1

#define STATE_ADDR 0x0
#define STATE_SUBADDR 0x1
#define STATE_DATA 0x2

#define MOTOR1A		PORTA.f1
#define MOTOR1B		PORTA.f0
#define MOTOR1C		PORTA.f4
#define MOTOR1D		PORTA.f3
#define MOTOR1EN	PORTA.f2

#define MOTOR2A		PORTC.f0
#define MOTOR2B		PORTA.f5
#define MOTOR2C		PORTC.f3
#define MOTOR2D		PORTC.f2
#define MOTOR2EN	PORTC.f1

#define MOTOR3A		PORTC.f5
#define MOTOR3B		PORTC.f4
#define MOTOR3C		PORTB.f2
#define MOTOR3D		PORTC.f7
#define MOTOR3EN	PORTC.f6

#define MOTOR4A		PORTB.f4
#define MOTOR4B		PORTB.f3
#define MOTOR4C		PORTB.f6
#define MOTOR4D		PORTB.f7
#define MOTOR4EN	PORTB.f5


#define DEVADDR 0x70

unsigned short bitcounter;
unsigned short ap2pp_state, ap2pp_addr, ap2pp_subaddr, ap2pp_data;
unsigned int stepper[4];
unsigned short step[4];
unsigned short stepTable[8] = { 0x1, 0x3, 0x2, 0x6, 0x4, 0xC, 0x8, 0x9 };
unsigned int i;

void setupAp2pp();
void doaInt();
void ap2ppRecv();

void interrupt()
{
   if (INTCON.INT0IF)
      doaInt();
}

void initialize()
{
   PORTA = 0x0;
   PORTB = 0x0;
   PORTC = 0x0;

   TRISA = 0x0;
   TRISB = 0x3;
   TRISC = 0x0;

   ADCON1 = 0x7;

   setupAp2pp();
   
   stepper[0] = 0;
   stepper[1] = 0;
   stepper[2] = 0;
   stepper[3] = 0;

   RCON.IPEN = 0;
   INTCON.GIE = 1;
   INTCON.PEIE = 1;

}

void setupAp2pp()
{
    INTCON2.INTEDG0 = 1;
    INTCON.INT0IF = 0;
    INTCON.INT0IE = 1;

    ap2pp_state = 0;
    ap2pp_addr = 0;
    ap2pp_subaddr = 0;
    ap2pp_data = 0;
    bitcounter = 7;
}

void doaInt()
{
    ap2ppRecv();
    INTCON.INT0IF = 0;
    INTCON.INT0IE = 1;
}

void ap2ppRecv()
{
    switch (ap2pp_state)
    {
       case 0:
          if (DOA_DATA)
             ap2pp_addr += 128;
          if (bitcounter-- != 0)
             ap2pp_addr = ap2pp_addr >> 1;
          else
          {
             ap2pp_state = 1;
             bitcounter = 5;
          }
          break;
       case 1:
          if (DOA_DATA)
             ap2pp_subaddr += 128;
          if (bitcounter-- != 0)
             ap2pp_subaddr = ap2pp_subaddr >> 1;
          else
          {
             ap2pp_state = 2;
             ap2pp_subaddr = ap2pp_subaddr>> 2;
             bitcounter = 7;
          }
          break;
       case 2:
          if (DOA_DATA)
             ap2pp_data += 128;
          if (bitcounter-- != 0)
             ap2pp_data = ap2pp_data >> 1;
          else
          {
             ap2pp_state = 0;
             bitcounter = 7;
             
             if (ap2pp_addr == DEVADDR)
             {
                if ((ap2pp_data & 0x80) == 0x80)
                   stepper[ap2pp_subaddr] -= (ap2pp_data & 0x7F);
                else
                   stepper[ap2pp_subaddr] += ap2pp_data;
             }
             ap2pp_addr = 0;
             ap2pp_subaddr = 0;
             ap2pp_data = 0;
          }
          break;
    }
}

void delay(int duration)
{
    while (duration > 0)
       duration--;
}

void main()
{
   initialize();

   while(1)
   {
      for (i = 0; i < 4; i++)                       // 4 motors
      {
         if ((stepper[i] & 0x7FFF) > 0)               // if more then 0 steps required
         {
             if ((stepper[i] & 0x8000) == 0x8000)       // if direction = CCW
             {
                 if (stepper[i] < 0xFFFD)             // if more then 3 steps required = full step
                 {
                    stepper[i] += 2;
                    step[i] -= 2;
                 }
                 else                                // else halfstep
                 {
                    stepper[i]++;
                    step[i]--;
                 }
             }
             else                                    // else direction = CW
             {
                 if (stepper[i] > 0x3)
                 {
                    stepper[i] -= 2;
                    step[i] += 2;
                 }
                 else
                 {
                    stepper[i]--;
                    step[i]++;
                 }
             }

             switch (i)
             {
                case 0:
                   MOTOR1EN = 0;
                   MOTOR1A = stepTable[step[0] & 0x7].f0;
                   MOTOR1B = stepTable[step[0] & 0x7].f1;
                   MOTOR1C = stepTable[step[0] & 0x7].f2;
                   MOTOR1D = stepTable[step[0] & 0x7].f3;
                   MOTOR1EN = 1;
                   break;
               case 1:
                   MOTOR2EN = 0;
                   MOTOR2A = stepTable[step[1] & 0x7].f0;
                   MOTOR2B = stepTable[step[1] & 0x7].f1;
                   MOTOR2C = stepTable[step[1] & 0x7].f2;
                   MOTOR2D = stepTable[step[1] & 0x7].f3;
                   MOTOR2EN = 1;
                   break;
               case 2:
                   MOTOR3EN = 0;
                   MOTOR3A = stepTable[step[2] & 0x7].f0;
                   MOTOR3B = stepTable[step[2] & 0x7].f1;
                   MOTOR3C = stepTable[step[2] & 0x7].f2;
                   MOTOR3D = stepTable[step[2] & 0x7].f3;
                   MOTOR3EN = 1;
                   break;
               case 3:
                   MOTOR4EN = 0;
                   MOTOR4A = stepTable[step[3] & 0x7].f0;
                   MOTOR4B = stepTable[step[3] & 0x7].f1;
                   MOTOR4C = stepTable[step[3] & 0x7].f2;
                   MOTOR4D = stepTable[step[3] & 0x7].f3;
                   MOTOR4EN = 1;
                   break;
            }
         }
      }
      delay(5000);              // Adjust value to optimize stepping speed. Shorter delay will result in faster stepping
   }
}


