/* File: robotics7opt.c
   Implementation file for OPTIONS Version of basic controller routines for Version 7
   of the UE controller board  (delay, motors, A to D, and sound only)

   Keil C headers are not guarded.  If robotics library is used, its header
   file should be the only included file unless KEIL_C_H is defined first.
*/

#include "robotics7opt.h"
#include <stdlib.h>

/* ------------------------------------------------------------------------
DELAY ROUTINE.  With count = 1 this routine provides a delay 
of about 50 msec.
---------------------------------------------------------------------------*/
void Delay(unsigned char count)
{
   unsigned char i,j;

   while(count > 0)
   {
      for(j=0;j<255;j++)
         for(i=0;i<130;i++);
      count--;
   } /* end while */
}  /* end Delay */

/* ------------------------------------------------------------------------
MOTOR ROUTINES
Speed is -255 to 255, however |speed| needs to be > 190 to be effective
for most vehicle designs.
Direction is based on sign of speed:
                   < 0 for left/reverse
                   = 0 for stop
                   > 0 for right/forward
Port bits control direction:
                   00 - stop (but motor still on, used for dynamic braking)
                   01 - "left"
                   10 - "right"
                   11 - not used
Port bits assigned: M11 M12 M21 M22 M31 M32 M41 M42
(LSB is not used and set to one to turn on the IR sensors)
Chip select for enabling motors in Port 1 of processor:
                   P1.4 - M1 select
                   P1.3 - M2 select
                   P1.6 - M3 select
                   P1.5 - M4 select
1 for off, 0 for on
Version 7 selects automatically power to off; PWM takes care of
turning them on and off.
PWM modules:
                   Module 1 - M1
                   Module 0 - M2
                   Module 3 - M3
                   Module 2 - M4
---------------------------------------------------------------------------*/

// Interrupt 6 is the PCA interrupt.  We are using register bank 2 for the 
// interrupt as a matter of form.  This code does not actually use any
// registers.
void PWMInterrupt(void) interrupt 6 using 2
{
   // Clear bit 7 - counter overflow flag
   // bit 6 is the counter run flag and must be left at 1
   // bit 5 is not used
   // Clear all pwm module interrup flags - bits 0 to 4.
   CCON = CCON & 0x40;  //Clear all motor interrupt flags
}  /* PWMInterrupt */

void InitializeMotors (void)
{
   /* Turn off all motors */
   AllStop();

   /* Enable PWM */
   CMOD   = 0x01;    // Clock freq/12, enable interrupt on overflow, (all motors)
   CCON   = 0x40;    // Enable PCA to run.
   // IPx and IPHx set the interrupt priority as 1 of 4 levels.  Setting bit 6
   // in IP and IPH sets the priority level to 3 (highest)
   IP = 0x40;        //Set PCA to high priority.  All others are low
   IPH = 0x40;       //Set PCA to high priority.  All others are low

   IE = 0xC0;        //Bit 7 is global enable.  Bit 6 is PCA enable.
}  /* InitializeMotors */   

sbit M1select = 0x94;  /* Port 1 Bit 4 */
sbit M2select = 0x93;  /* Port 1 Bit 3 */
sbit M3select = 0x96;  /* Port 1 Bit 6 */
sbit M4select = 0x95;  /* Port 1 Bit 5 */

void AllStop(void)
{
   M4select = 0; /* leave motor 4 select on for IR power, bit 5 */

   motors = ALLMOTORSOFF;
   XBYTE[MOTOR_IDX] = motors;
}  /* end AllStop */


/*----------------------------------------------------------------------
Version 7 of the controller board has PWM speed control numbers
1 (fastest) to 255 (slowest).  The routine turns the scale around
so that the numbers input to the routine are 1 (slowest) to 255
(fastest).
------------------------------------------------------------------------*/
void SetMotor(unsigned char motorID, int speed)
{
   unsigned char shift = 2 * (4 - motorID);
   unsigned char realSpeed = abs(speed);

   if (motorID > MAXMOTORID || motorID == 0)  /* error in usage, turn everything off */
   {
      AllStop();
      return;
   }  /* motor number out of range */

   if (realSpeed > 255)   /* cap speed number at 255 */
       realSpeed = 255;

   /* set direction */
   motors = motors & ~(MOTOROFF << shift);       /* Turn motor num off */
   if (speed < 0)                                /* Turn motor num on left/reverse */
      motors = motors | (MOTORLEFT << shift);
   else if (speed > 0)                           /* Turn motor num on right/forward */
      motors = motors | (MOTORRIGHT << shift);

   /* set PWM control */
   if (realSpeed != 0)  /* Enable motor pwm module, set speed */
   {
      switch (motorID)
      {
         case 1:                            // Motor 1 uses module 1
            CCAPM1 = PWM_ENABLE;            // Enable Motor 1 PWM for 8-bit PWM
            CCAP1H = realSpeed;             // Set speed  
            break;
         case 2:                            // Motor 2 uses module 0
            CCAPM0 = PWM_ENABLE;            // Enable Motor 2 PWM for 8-bit PWM
            CCAP0H = realSpeed;             // Set speed
            break;
         case 3:                            // Motor 3 uses module 3
            CCAPM3 = PWM_ENABLE;            // Enable Motor 3 PWM for 8-bit PWM
            CCAP3H = realSpeed;             // Set speed 
            break;
         case 4:                            // Motor 4 uses module 2
            CCAPM2 = PWM_ENABLE;            // Enable Motor 4 PWM for 8-bit PWM
            CCAP2H = realSpeed;             // Set speed
            break;
	  }
   }  /* end enable PWM, set speed */
   else  /* speed = 0, disable PWM */
   {
      switch (motorID)
      {
         case 1:
            CCAPM1 = 0;         // Disable Motor 1 PWM
            break;
         case 2:
            CCAPM0 = 0;         // Disable Motor 2 PWM
            break;
         case 3:
            CCAPM3 = 0;         // Disable Motor 3 PWM
            break;
         case 4:
            CCAPM2 = 0;         // Disable Motor 2 PWM
            break;
      }
   }  /* end set speed */         
   XBYTE[MOTOR_IDX] = motors;  /* set direction control */
}  /* SetMotor */

/* ------------------------------------------------------------------------
A TO D CONVERTER ROUTINES
Channels are numbered 0-7
---------------------------------------------------------------------------*/
sbit notDone = 0xB5;  /* Port 3 Bit 5 */

unsigned char GetAtoD (unsigned char channel)
{
   /* OR 8 with channel for single ended entry */
   XBYTE[ATOD_IDX] = (channel | 8); 

   /* Delay to allow conversion to finish       */
   /* Interrupt sets P3.5 to 0 when finished */
   notDone = 1;
   while (notDone);  /* just waiting for change in state */
   
   /* Get the data and return it */
   return XBYTE[ATOD_IDX];
}  /* end GetAtoD */

/* ------------------------------------------------------------------------
SOUND ROUTINES
The buzzer is on port 1 at pin 0.  Set to 0 for on, 1 for off
state = 1 turns buzzer on; state = 0 turns buzzer off
---------------------------------------------------------------------------*/
sbit P1_0 = 0x90;  /* Port 1 Pin 0 */

void Sound(unsigned char state)
{
   if (state == OFF)  /* Turn buzzer off */
   { 
      /* Set P1.0 to 1 */
      P1_0 = 1;            
   }  /* end if */
   else   /* Turn buzzer on */
   {
      /* Set P1.0 to 0 */
      P1_0 = 0;
   }  /* end else */
}  /* end Sound */

/* Beep drives buzzer as a beeper at approximately .25 seconds on, */
/* .25 seconds off for duration number of cycles.  E.g., Beep(5)   */
/* beeps 5 times.                                                  */
void Beep(unsigned char duration)
{
   unsigned char j;
   for(j = 0; j <duration; j++)
   {
      Sound (ON);
      Delay (5);     /* Approx. .25 seconds */
      Sound (OFF);
      Delay (5);
   }  /* end for */
}  /* end Beep */