capeMirror v. 2

The capeMirror Wiring

On the right can be seen the pin mapping.

The capeMirror Library

Now it’s just a question of combining the following libraries into one: Stepper_Aclr8_2, Stepper_Aclr8_i, Matrix_Steppers, and SerialParse.

/*
 * capeMirror v2a
 *
 * created by Ben @ Cape Ealing
 * 24 January 2010
 *
 */
 
//********************************************************************
// Initial Definitions
//********************************************************************
// include the libraries
// -------------------------------------------------------------------
#include "NewSoftSerial.h"
#include "CapeMirror.h"
 
// map all the pins
// -------------------------------------------------------------------
#define pReceiveBT 2
#define pTransmitBT 3
#define pAzStep1 4
#define pAzStep2 5
#define pAzStep3 6
#define pAzStep4 7
#define pAltStep1 8
#define pAltStep2 9
#define pAltStep3 10
#define pAltStep4 11
#define pKeypadCol1 12
#define pKeypadCol2 13
#define pKeypadCol3 14
#define pTransmitLCD 15
#define pKeypadRow1 16
#define pKeypadRow2 17
#define pKeypadRow3 18
#define pKeypadRow4 19
 
// the LCD constants and variables
// -------------------------------------------------------------------
#define lcdDataRate 9600
#define pLCDNoReceivePin 255
#define lcdLine1 1
#define lcdLine2 2
int lcdBright = 100;
 
// the bluetooth constants and variables
// -------------------------------------------------------------------
#define btDataRate 9600 
#define btHandshake1 1234567
#define btHandshake2 7654321
#define btNewCoords 1111112
#define btPark 2222222
#define btUnpark 333333
#define btSlew 4444444
 
// the keypad constants and variables
// -------------------------------------------------------------------
int keypadResult = 13;
 
 
// the stepper motors constants and variables
// -------------------------------------------------------------------
// Azimuth stepper
#define azSteps 200         
#define azMinSpeed 1     
#define azMaxSpeed 30
#define azAccSteps 400
#define azMoveSpeed 10
// Altitude stepper
#define altSteps 200         
#define altMinSpeed 1
#define altMaxSpeed 30
#define altAccSteps 100
#define altMoveSpeed 10
 
// ancillary set-up
// -------------------------------------------------------------------
boolean pcControl = false;  
int azStepsToDo = 0;  // variable to hold the 'az steps to take' data
int altStepsToDo = 0; // variable to hold the 'alt steps to take' data
// variables for the data
long azVal = 0;
long altVal = 0;
long cmdVal = 0;
// global variables for mount's azimuth and altitude (in arcseconds)
long azGlobal = 0;
long altGlobal = 187826;  
boolean initialised = false;

 
// initialise the classes
// -------------------------------------------------------------------
NewSoftSerial cmBlueTooth(pReceiveBT, pTransmitBT);
NewSoftSerial cmLCD(pLCDNoReceivePin, pTransmitLCD);
CapeMirror cmMount = CapeMirror(&azGlobal, &altGlobal); // DB change name
 
//********************************************************************
// Setup Procedure
//********************************************************************
void setup()
{
  // define the (lcd) serial communication
  cmMount.setLCDaddress(&cmLCD);
  cmMount.beginLCD(lcdDataRate);
  cmMount.lcdOn();
  cmMount.lcdClear();
  cmMount.lcdBacklight(100);
  cmMount.lcdDisplay(lcdLine1, 1, "   capeMirror");
  cmMount.lcdDisplay(lcdLine2, 1, " created by Ben");
  delay(3000);
 
  // define the (bluetooth) serial communication with the laptop  
  cmMount.setBTaddress(&cmBlueTooth);
  cmMount.beginBT(btDataRate);
 
  // define the keypad (fires columns, and reads rows)
  cmMount.setKeypadCols(pKeypadCol1, pKeypadCol2, pKeypadCol3);
  cmMount.setKeypadRows(pKeypadRow1, pKeypadRow2, pKeypadRow3, pKeypadRow4);
  cmMount.setInterruptPins(pKeypadCol2, pKeypadRow2);
 
  // define each stepper motor
  // (no of steps per rev, pin1, pin2, pin3, pin4)
  cmMount.azStepper(azSteps, pAzStep1, pAzStep3, pAzStep2, pAzStep4);
  cmMount.altStepper(altSteps, pAltStep1, pAltStep3, pAltStep2, pAltStep4);
 
  // define the rates of each motor: 
  // min, max, steps take to accelerate, and 'move speed' (when keypad pressed)
  cmMount.azStepperSpeeds(azMinSpeed, azMaxSpeed, azAccSteps, azMoveSpeed);
  cmMount.altStepperSpeeds(altMinSpeed, altMaxSpeed, altAccSteps, altMoveSpeed);
 
  // pass the address of the 'steps to take variables'
  cmMount.setStepsAddress(&azStepsToDo, &azStepsToDo);
 
  // run the startup routine
  do 
  {
  userStart(); 
  } while (initialised == false);

  cmMount.lcdDisplayCoords();  
  cmMount.lcdDisplayDegsMins();
  cmMount.lcdDisplaySecs();
  if (pcControl == true) {cmMount.lcdDisplayControlPC();} else {cmMount.lcdDisplayControlMT();}
  delay(2000);

} // End: setup
 
 
//********************************************************************
// Loop procedure (the main procedure)
//********************************************************************
void loop()
{


// read the keypad
keypadResult = cmMount.readKeypad();
if (keypadResult != 13){cmMount.move(keypadResult);}

if (keypadResult == 0){
  // wait until key no longer pressed
  do {keypadResult = cmMount.readKeypad();} while (keypadResult == 0);
  // vary the backlight
  cmMount.lcdBacklightShift();
}
 
  
  //SCENARIO A
            // read the serialcomm
            // if available...parse the data
                        // if under pcControl = true {}
                        // then 'switch case' the cmd value
                        // do as required: ie slew, or acceptnewcoords, or park
                        // need to be able to handle a 'move' command (ie slew can be interrupted by serial data)
                        
                        // else (not under pcControl                    
                        // then check pc wants to take control
                        // if not, error
                        // if does want to take control, then 
                        // toggle pcControl
            
            // read the keypad
            // if pressed then:
            // if pcControl = true, see if mount wants to take over.  if so, then park (same as park above?) otherwise ignore
            // if pcControl = false, then move as required, but if '#' pressed, then part (same as park above?)
            // always check for 0.  If 0 pressed then increase brightness by 20% (set to zero if result > 100).
            
            
            // NOTE: Whenever stepping on whatever instruction, need to 
            // 1. read the mount interrupt pin (*), to check user hasn't cancelled at that end
            //                      if cancelled by keypad, then 
            //                                  if under MT control just stop (coords will have been saved anyway)
            //                                  if under PC control then need to report to PC the interruption and the new coords
            //                                                                                                          and turn to MT control
            
            // 2. read the serial data, to check not cancelled by PC (eg a 'move')
            //    if cancelled by bluetooth, then 
            //                                  if under PC control then report to PC the interruption and the new coords
            //                                  if under MT control then report to PC the interruption and the new coords
            //                                                                                                          and turn to PC control
            
 
//SCENARIO B
            // if pcControl = true {
            // }
            // Either PC control: waiting for BlueTooth Data and reading '#' pin
            // hash says 'i want control': if hash pressed then the scope is 'parked'
            // if it's in the middle of a move routine, then can only interrupt by
            // pressing the 'abandon' key (*) 
            // That just means that the mount is interrupted, it sends its new position 
            // to the PC.  Waits for the PC to confirm that OK to proceed.
 
            // if pcControl = false {
            // }
            // Or Mount control: waiting for BlueTooth and reading keypad (possible)
            // scope is 'parked' as far as PC is concerned
            // read the keypad, move as necesssary, store alt and az position
            // if user presses '#' then unparks and goes over to pc control
            // also PC can regain control, so needs to read bluetooth too
 
            
            
  if (cmBlueTooth.available() > 0) 
  {    
    // the call parseData method
    cmMount.btParseData(&azVal, &altVal, &cmdVal);
    // the integers xVal, yVal, zVal now hold the values received
 
    cmBlueTooth.print("[");
    cmBlueTooth.print(azVal);
    cmBlueTooth.print(";");
    cmBlueTooth.print(altVal);
    cmBlueTooth.print(";");
    cmBlueTooth.print(cmdVal);
    cmBlueTooth.print("]");
  } // end if

}
 
 
 //********************************************************************
// All subsidiary procedures
//********************************************************************
// start up routine
// -------------------------------------------------------------------
void userStart()
{
  // 1.  Ask if making a PC connection
  cmMount.lcdClear();
  cmMount.lcdDisplay(lcdLine1, 1, "Control by PC?");
  cmMount.lcdDisplay(lcdLine2, 1, "1 = Yes, 2 = No");
  // loop through until a result is obtained
  do 
  {
  keypadResult = cmMount.readKeypad();
  } 
  while (keypadResult != 1 && keypadResult != 2);

  if (keypadResult ==1)
  {
    cmMount.lcdDisplay(lcdLine2, 1, "    Yes        ");   
    do {keypadResult = cmMount.readKeypad();} while (keypadResult != 13);
    keypadResult = 1;
  }
  else
  {
    cmMount.lcdDisplay(lcdLine2, 1, "             No");
    do {keypadResult = cmMount.readKeypad();} while (keypadResult != 13);
    keypadResult = 2;
  }
  delay(1000);
  
  if (keypadResult ==1){
    // PC control
    cmMount.lcdClear();
    cmMount.lcdDisplay(lcdLine1, 1, "Run PC software,");   
    cmMount.lcdDisplay(lcdLine2, 1, "waiting...    s");
    
    // wait for bluetooth commands (or max 5 mins)
    int waiting=90;
    while ((cmMount.btAvailable() == 0) && waiting > 0)
    {
      if (waiting > 9) 
      {
        cmMount.lcdDisplay(lcdLine2, 13, waiting);
      }
      else
      {
        cmMount.lcdDisplay(lcdLine2, 13, " ");
        cmMount.lcdDisplay(lcdLine2, 14, waiting);
      }
      waiting--;
      cmMount.btAvailable(); // needed with NewSoftSerial library
      delay(1000);
    }
    
     // if timed out, start the loop within setup again    
    if (waiting==0)
    {
      cmMount.lcdClear();
      cmMount.lcdDisplay(lcdLine1, 1, "Error: timed out");   
      delay(5000);
      keypadResult = 3;
    }
    // or got serial data, so handshake
    else
    {
      pcHandShaking();
    }
  }
  
  // Mount control
  if (keypadResult ==2){
    mtCoordObtaining();
  }
  
} // end userStart
 
 
// pcHandshaking procedure
// -------------------------------------------------------------------
void pcHandShaking()
{
  // parse the data received  
  cmMount.btParseData(&azVal, &altVal, &cmdVal);
  if (azVal == btHandshake1 && altVal == btHandshake1 && cmdVal == btHandshake1)
  {
    // report that 'good data' has been recieved
    cmMount.lcdClear();
    cmMount.lcdDisplay(lcdLine1, 1, "Data received,");
    cmMount.lcdDisplay(lcdLine2, 1, "handshaking...");
    cmMount.btAvailable(); // needed with NewSoftSerial library
    delay(2000);  
    // write data back to the laptop
    cmMount.btWrite("[");
    cmMount.btWrite(btHandshake2);
    cmMount.btWrite(";");
    cmMount.btWrite(btHandshake2);
    cmMount.btWrite(";");
    cmMount.btWrite(btHandshake2);
    cmMount.btWrite("]");
  }
  else
  {
    cmMount.lcdClear();
    cmMount.lcdDisplay(lcdLine1, 1, "Error:");   
    cmMount.lcdDisplay(lcdLine2, 1, "Bad data recd");   
    keypadResult = 3;   // loop round startup procedures again
    delay(2000);  
  }
  
  // if PC control proceeding successully
  if (keypadResult == 1)
  {
  cmMount.lcdDisplay(lcdLine1, 1, "Now, polar align");   
  cmMount.lcdDisplay(lcdLine2, 1, "#=Done; *=Cancel");   
  do 
  {
  keypadResult = cmMount.readKeypad();

  //move using keypad until press # or cancel
  
  } 
  while (keypadResult != 10 && keypadResult != 11);
  
 
  // HERE NEED TO PUT IN POLAR ALIGN ROUTINE
  // HAVING SENT THE DATA OUT
  // JUST GO INTO KEYPAD READING / MOVING ROUTINE
  // CARRY ON UNTIL PRESSSES # AT THIS END.
  // THEN MOUNT WAITS FOR PC RESPONSE
  // PC ONLY RESPONDS WHEN USER PRESSES 'OK' ON PC
  // (AMEND PC INSTRUCTIONS SO IT SAYS, POLAR ALIGN MOUNT, 
  // THEN PRESS '#' ON MOUNT.
  // AFTER PRESSSING '#', CLICK OK HERE. 
  
  // ON PC: 
  // IF PC RECEIVES GOOD DATA, THEN WILL POP UP QUESTION (ABOVE) 
  // IF PC RECEIVES BAD DATA, THEN WILL NOT POP UP.
  
  // SO NEED TO BE ABLE CANCEL POLAR ALIGN ON THE MOUNT
  // WOULD SUGGEST THAT * ON THE KEYPAD ABANDONS POLAR ALIGN
  // THEN STARTS AT BEGINNING OF START UP ROUTINE AGAIN
  
  // on 'OK' on PC, the PC sends through the mounts coords
  // assuming that the cmdVal is correct (ie new coords 
  // - which will be used as 'synch' later too.
  // then store the new coords.
  // Display the new coords as (need routine for this):
  // cmMount.lcdDisplay(lcdLine1, 1, "Az: 359.59'59" P");   
  // cmMount.lcdDisplay(lcdLine2, 1, "Alt: 89.59'59" C");   
  // display routines:
  // 1.  Initialise for coords (ie put in Az:, Alt: etc)
  // 2.  just display coords
  // 3.  PC control
  // 4.  MT control
  
  // if good data received then wait for more data back
  // this contains the az and alt coords
  // if good data received back then store it and 
  // successfully connected
  pcControl = true;
  initialised = true;
  }   
} // end pcHandShaking


void mtCoordObtaining()
{

  // Get the Coords  
  boolean azCoordsOK = false;
  boolean altCoordsOK = false;
  char azCoordsInput[10] = {0,0,0,0,0,0,0,0,0,0};
  char altCoordsInput[10] = {0,0,5,2,0,1,0,0,2,6};

  do
  {
    cmMount.lcdClear();
    cmMount.lcdDisplay(lcdLine1, 1, "Enter Az:  #=OK");
    cmMount.lcdDisplay(2, 1, "000");
    cmMount.lcdDisplay(2, 4, (char)223);
    cmMount.lcdDisplay(2, 5, "00");
    cmMount.lcdDisplay(2, 7, (char)39);
    cmMount.lcdDisplay(2, 8, "00");
    cmMount.lcdDisplay(2, 10, (char)34);
    cmMount.lcdDisplay(2, 11, " *=Del");
    cmMount.lcdPosition(2,1);
    cmMount.lcdBlockCursor();

    // Az input loop
    int entrypos = 1;
    do 
      {
        // wait until get a response
        do {keypadResult = cmMount.readKeypad();} while (keypadResult == 13);
  
        // check the result
        switch  (keypadResult){
          case 10:    // *
          entrypos -=1;
          if (entrypos==0){entrypos=1;}
          if (entrypos==4 || entrypos==7) {entrypos -=1;}
          cmMount.lcdPosition(2,entrypos);
          break;
          case 11:    // #
          entrypos = 13;
          break;  
          default:
          azCoordsInput[entrypos] = char(keypadResult);
          cmMount.lcdDisplay(2,entrypos, keypadResult);
          entrypos +=1;
          if (entrypos==4 || entrypos==7) {entrypos +=1;}
          if (entrypos==10){entrypos=9;}
          cmMount.lcdPosition(2,entrypos);
        } // end: switxh
        
        do {keypadResult = cmMount.readKeypad();} while (keypadResult != 13);
          
     } while (entrypos != 13); // end: do Az input loop

   // Az coords have been entered
   long azDegs =  (int(azCoordsInput[1]) * 100) + (int(azCoordsInput[2]) * 10) + (int(azCoordsInput[3]));
   azDegs =  azDegs * 3600;
   long azMins = (int(azCoordsInput[5]) * 10) + (int(azCoordsInput[6]));
   if (azMins>59) {azDegs=400;} // throw an error if over 59 mins
   azMins = azMins * 60;
   long azSecs = (int(azCoordsInput[8]) * 10) + (int(azCoordsInput[9]));
   if (azSecs>59) {azDegs=400;} // throw an error if over 59 secs
   azSecs = azSecs + azMins + azDegs;
   
   // Az coords: check within 2 degrees of zero degrees
   if (azSecs == 1296000){azSecs = 0;} // change to zero if 360 degrees entered
   if ((azSecs <= 7200) || ((azSecs >= 1288800) && (azSecs < 1296000)))
   {
     azCoordsOK = true; 
     cmMount.lcdNoCursor();
     cmMount.lcdClear();
     azGlobal = azSecs;
   }
   else
   {
     cmMount.lcdNoCursor();
     cmMount.lcdClear();     
     cmMount.lcdDisplay(lcdLine1, 1, "Error");
     cmMount.lcdDisplay(lcdLine2, 1, "Bad Az data");
     delay(2000);
   }
 
 } while (azCoordsOK == false);  // End: Get the Az Coords

  // Get the Az Coords
  do
  {
    // clear the screen
    cmMount.lcdDisplay(lcdLine1, 1, "Enter Alt:  #=OK");
    cmMount.lcdDisplay(2, 1, " 52");
    cmMount.lcdDisplay(2, 4, (char)223);
    cmMount.lcdDisplay(2, 5, "10");
    cmMount.lcdDisplay(2, 7, (char)39);
    cmMount.lcdDisplay(2, 8, "26");
    cmMount.lcdDisplay(2, 10, (char)34);
    cmMount.lcdDisplay(2, 11, " *=Del");
    cmMount.lcdPosition(2,2);
    cmMount.lcdBlockCursor();

    // Alt input loop
    int entrypos = 2;
    do 
      {
        // wait until get a response
        do {keypadResult = cmMount.readKeypad();} while (keypadResult == 13);
  
        // check the result
        switch  (keypadResult){
          case 10:    // *
          entrypos -=1;
          if (entrypos==1){entrypos=2;}
          if (entrypos==4 || entrypos==7) {entrypos -=1;}
          cmMount.lcdPosition(2,entrypos);
          break;
          case 11:    // #
          entrypos = 13;
          break;  
          default:
          altCoordsInput[entrypos] = char(keypadResult);
          cmMount.lcdDisplay(2,entrypos, keypadResult);
          entrypos +=1;
          if (entrypos==4 || entrypos==7) {entrypos +=1;}
          if (entrypos==10){entrypos=9;}
          cmMount.lcdPosition(2,entrypos);
        } // end: switch

        do {keypadResult = cmMount.readKeypad();} while (keypadResult != 13);

     } while (entrypos != 13); // end: do Az input loop

   // Alt coords have been entered
   long altDegs =  (int(altCoordsInput[2]) * 10) + (int(altCoordsInput[3]));
   altDegs =  altDegs * 3600;
   long altMins = (int(altCoordsInput[5]) * 10) + (int(altCoordsInput[6]));
   if (altMins>59) {altDegs=400;} // throw an error if over 59 mins
   altMins = altMins * 60;
   long altSecs = (int(altCoordsInput[8]) * 10) + (int(altCoordsInput[9]));
   if (altSecs>60) {altDegs=400;} // throw an error if over 59 secs
   altSecs = altSecs + altMins + altDegs;
   
   // Alt coords: check over 20 degrees and less then 90 degrees
   if ((altSecs >= 72000) && (altSecs < 324000))
   {
     altCoordsOK = true; 
     cmMount.lcdNoCursor();
     cmMount.lcdClear();
     altGlobal = altSecs;
   }
   else
   {
     cmMount.lcdNoCursor();
     cmMount.lcdClear();     
     cmMount.lcdDisplay(lcdLine1, 1, "Error");
     cmMount.lcdDisplay(lcdLine2, 1, "Bad Alt data");
     delay(2000);
   }
 
 } while (altCoordsOK == false);  // End: Get the Alt Coords

  // report successful 
  cmMount.lcdDisplay(lcdLine1, 1, "Startup complete");
  cmMount.lcdDisplay(lcdLine2, 1, "Mount control");
  delay(2000);  
  initialised = true;
}

this is the test

/*
	CapeMirror.h
	v. 2a
	by Ben @ Cape Ealing
*/

// ensure this library description is only included once
#ifndef CapeMirror_h
#define CapeMirror_h

#define moveStep 1
#define slewStep 2

// create shorthand refs for "[" and "]" and ";"
#define leftbracket 0x5b    
#define rightbracket 0x5d   
#define semicolon 0x3b 
#define dataLength 8

// LCD definitions
#define _line1 127
#define _line2 191
#define _cmd 254
#define _cmdSp 124
#define _clear 1
#define _on 12
#define _off 8
#define _nocursor 12
#define _block 13
#define _line 14
#define _lcddelay 50
//#define _blightshiftdelay 500

// stepper motor definitions
// azimuth resolution: 0.045 degrees (162 arcsecs)
// altitude resolution: 0.09 degrees (324 arcsecs)
#define _azRes 162
#define _altRes 324
#define _azMax 1296000
#define _altMax 324000
#define _altMin 72000

/*
	CapeMirror library
*/ 
class CapeMirror {
	
	// public methods and variables 
	// ----------------------------
	public:
 
	// Initialise the class
	CapeMirror(long* gAz, long* gAlt);

	// define the 'address' for the bluetooth serial connection
	void setBTaddress(NewSoftSerial *btAddress);

	// define the 'address' for the LCD serial connection
	void setLCDaddress(NewSoftSerial *lcdAddress);

	// wrappers for the NewSoftSerial begin method
	void beginBT(int btBaudRate);
	void beginLCD(int lcdBaudRate);

	// Create the parse method
	void btParseData(long *azVal, long *altVal, long *cmdVal);

	// bluetooth write methods
	void btWrite (char msg);
	void btWrite (const char msg[]);
	void btWrite (uint8_t msg);
	void btWrite (int msg);
	void btWrite (unsigned int msg);
	void btWrite (long msg);
	void btWrite (unsigned long msg);

	// wrapper for NewSoftSerial available method
	uint8_t btAvailable(void);

	// serLCD
	// ----------------
	// selection of methods from the serLCD library
	void lcdOn();
	void lcdOff();
	void lcdClear();
	void lcdBlockCursor();
	void lcdLineCursor();
	void lcdNoCursor();
	void lcdBacklight(int blight);
	void lcdBacklightShift();
	void lcdPosition (int line, int character);
	void lcdDisplay ( int line, int character, char );
	void lcdDisplay ( int line, int character, const char[] );
	void lcdDisplay ( int line, int character, uint8_t );
	void lcdDisplay ( int line, int character, int );
	void lcdDisplay ( int line, int character, unsigned int );
	void lcdDisplay ( int line, int character, long );
	void lcdDisplay ( int line, int character, unsigned long );
	void lcdDisplay ( int line, int character, long, int );

	void lcdDisplayCoords();
	void lcdDisplayDegsMins();
	void lcdDisplaySecs();
	void lcdDisplayAzSecs();
	void lcdDisplayAltSecs();
	void lcdDisplayControlMT();
	void lcdDisplayControlPC();
	
	// ----------------
	// Matrix_Steppers 
	// ----------------
	// define the rows and columns
    void setKeypadRows(int row1, int row2, int row3, int row4);
    void setKeypadCols(int col1, int col2, int col3);

	// read the keypad
	int readKeypad(void);

	// ----------------
	// The movement methods (slew and move)
	// ----------------

	void slew (int steps_to_move1, int steps_to_move2);
	void move (int keyResult);

	// ----------------
	// Stepper_Aclr8_2
	// ----------------

	// Stepper constructors: 4 wire stepper motors only
	void azStepper(int number_of_steps1, int motor1_pin_1, \
		int motor1_pin_2, int motor1_pin_3, int motor1_pin_4);
	void altStepper(int number_of_steps2, int motor2_pin_1, \
		int motor2_pin_2, int motor2_pin_3, int motor2_pin_4);

	// Define each stepper's rates (min speed, max speed, acceleration)
    void azStepperSpeeds(long minSpeed1, long maxSpeed1, double Accel1, long moveSpeed1);
    void altStepperSpeeds(long minSpeed2, long maxSpeed2, double Accel2, long moveSpeed2);


	// ----------------
	// Stepper_Aclr8_i 
	// ----------------

	// define interupt pins method:
	void setInterruptPins(int firePin, int readPin);
	void setStepsAddress(int* azStepsAddress, int* altStepsAddress);


	// return the version if asked
	int version(void);

	// ********************************************************
	// private methods and variables 
	// ********************************************************
	private:

	// variable to hold a references to the serial connections
    NewSoftSerial* cmBlueToothRef;
	NewSoftSerial* cmLCDRef;
	long* gAzimuth;
	long* gAltitude;


	// ----------------
	// The keypad
	// ----------------
	int col1;
	int col2;
	int col3;
	int row1;
	int row2;
	int row3;
	int row4;
	int keyResult;  

	// ----------------
	// Stepper_Aclr8_2
	// ----------------

	// setup the motors
    void takeSteps(int steps_to_move1, int steps_to_move2, int step_type);
    void stepMotor1(int thisStep1);
    void stepMotor2(int thisStep2);
	
	// Direction of rotation
	int direction1;        
	int direction2;
    
	// Speed in RPMs
	int speed1;          
	int speed2;          
    
	// delay between steps, in ms, based on speed1
    double step_delay1;    
    double step_delay2;    
	double move_step_delay1;
	double move_step_delay2;

	// total number of steps this motor can take
	int number_of_steps1;      
	int number_of_steps2;      
    
	// delay at 1 rev per minute
    double delay_1revpermin1;
    double delay_1revpermin2;
	
	// which step the motor is on
	int step_number1;        
	int step_number2;        
	
	//steps left
	int steps_left1;    
	int steps_left2;    

	// motor pin numbers:
    int motor1_pin_1;
    int motor2_pin_1;

    int motor1_pin_2;
    int motor2_pin_2;

    int motor1_pin_3;
	int motor2_pin_3;

	int motor1_pin_4;
    int motor2_pin_4;
    
	// time stamp in ms of when the last step was taken
	long last_step_time1;      
	long last_step_time2;      

	//motor speeds
	long motorMinSpeed1;
	long motorMinSpeed2;
	
	long motorMaxSpeed1;
	long motorMaxSpeed2;
	
	long motorAccSteps1;
	long motorAccSteps2;
	
	double motorAccelVal1;
	double motorAccelVal2;

	long minSpeed1;
	long minSpeed2;

	// which step number of steps to take
	int steps_no1;
	int steps_no2;

	// total steps for both motors
	int total_steps_left;	

	// interupt pins
	int firePin;
	int readPin;

	// references to variables in sketch
    //NewSoftSerial* theSerial;
	int* azStepsToDoAddress;
	int* altStepsToDoAddress;

	// counter for number of bytes read
	int btByteIndex;		
	// whether all data has been read
	int btAllComplete;	
	// arrays for each of the three values received
	char azData[dataLength], altData[dataLength], cmdData[dataLength];
	// the character being read
	char thisChar;
	// variable to hold whether any partic value is complete
	int azComplete, altComplete, cmdComplete;

	long azDegLCD;
	long azMinLCD;
	long azSecLCD;
	long altDegLCD;
	long altMinLCD;
	long altSecLCD;
	int blightShift;

	bool moveSingleStep;
	void moveSingleStepToggle();
	int t;
};

#endif
/*
  CapeMirror.cpp
  v. 2a
  by Ben @ Cape Ealing
*/

#include "WProgram.h"
#include "NewSoftSerial.h"
#include "CapeMirror.h"

/*
 *   Initialise the class
 */
CapeMirror::CapeMirror(long* gAz, long* gAlt)
{
gAzimuth = gAz;
gAltitude = gAlt;
}


// define the 'address' for the bluetooth serial connection
void CapeMirror::setBTaddress(NewSoftSerial* btAddress)
{
cmBlueToothRef = btAddress;
}

// start the bluetooth connection
void CapeMirror::beginBT(int btBaudRate)
{
cmBlueToothRef->begin(btBaudRate);
}

uint8_t CapeMirror::btAvailable(void) 
{
	return cmBlueToothRef->available();
}



// define the 'address' for the LCD serial connection
void CapeMirror::setLCDaddress(NewSoftSerial* lcdAddress)
{
cmLCDRef = lcdAddress;
}

// start the lcd connection
void CapeMirror::beginLCD(int lcdBaudRate)
{
blightShift = 5;
cmLCDRef->begin(lcdBaudRate);
}

void CapeMirror::lcdOn()
{
	cmLCDRef->print(_cmd, BYTE);  // instruction
	cmLCDRef->print(_on, BYTE);  // turn on
	delay(_lcddelay);
}

void CapeMirror::lcdOff()
{
	cmLCDRef->print(_cmd, BYTE);  // instruction
	cmLCDRef->print(_off, BYTE);  // turn off
	delay(_lcddelay);
}

void CapeMirror::lcdClear()
{
	cmLCDRef->print(_cmd, BYTE);  // instruction
	cmLCDRef->print(_clear, BYTE);  // clear the LCD 0x01 or 1
	delay(_lcddelay);
}

void CapeMirror::lcdBlockCursor()
{
	cmLCDRef->print(_cmd, BYTE);  // instruction
	cmLCDRef->print(_block, BYTE);  // block cursor: 0X0D or 13
	delay(_lcddelay);
}

void CapeMirror::lcdLineCursor()
{
	cmLCDRef->print(_cmd, BYTE);  // instruction
	cmLCDRef->print(_line, BYTE);  // block cursor: 0X0D or 13
	delay(_lcddelay);
}

void CapeMirror::lcdNoCursor()
{
	cmLCDRef->print(_cmd, BYTE);  // instruction
	cmLCDRef->print(_nocursor, BYTE);  // block cursor: 0X0D or 13
	delay(_lcddelay);
}


void CapeMirror::lcdBacklight(int blight)
{
	blight = int((blight*30)/100);
	blight = (blight<3)?3:blight;
	blight = (blight>30)?30:blight;
	blight += 127;
    cmLCDRef->print(_cmdSp, BYTE);  // instruction coming
    cmLCDRef->print(blight, BYTE);  // backlight instruction
	delay(_lcddelay);
}


void CapeMirror::lcdBacklightShift()
{
	blightShift -= 1;
	if (blightShift == -1){blightShift = 5;}
	lcdBacklight ((blightShift*20));
//	delay(_blightshiftdelay);
}

void CapeMirror::lcdPosition (int line, int character)
{
	int pos = 0;
	if(line==2)
	{
		pos = _line2;
	}
	else
	{
		pos = _line1;
	}

	pos = pos + character;

	cmLCDRef->print(_cmd, BYTE);			// command
	cmLCDRef->print(pos, BYTE);	// set the position
}

void CapeMirror::lcdDisplay ( int line, int character, char v )			{ lcdPosition (line,character); cmLCDRef->print(v); }
void CapeMirror::lcdDisplay ( int line, int character, const char v[] )	{ lcdPosition (line,character); cmLCDRef->print(v); }
void CapeMirror::lcdDisplay ( int line, int character, uint8_t v )			{ lcdPosition (line,character); cmLCDRef->print(v); }
void CapeMirror::lcdDisplay ( int line, int character, int v )				{ lcdPosition (line,character); cmLCDRef->print(v); }
void CapeMirror::lcdDisplay ( int line, int character, unsigned int v )	{ lcdPosition (line,character); cmLCDRef->print(v); }
void CapeMirror::lcdDisplay ( int line, int character, long v )			{ lcdPosition (line,character); cmLCDRef->print(v); }
void CapeMirror::lcdDisplay ( int line, int character, unsigned long v )	{ lcdPosition (line,character); cmLCDRef->print(v); }
void CapeMirror::lcdDisplay ( int line, int character, long v, int t )		{ lcdPosition (line,character); cmLCDRef->print(v,t); }

void CapeMirror::btWrite (char msg) {cmBlueToothRef->print(msg);}
void CapeMirror::btWrite (const char msg[]) {cmBlueToothRef->print(msg);}
void CapeMirror::btWrite (uint8_t msg) {cmBlueToothRef->print(msg);}
void CapeMirror::btWrite (int msg) {cmBlueToothRef->print(msg);}
void CapeMirror::btWrite (unsigned int msg) {cmBlueToothRef->print(msg);}
void CapeMirror::btWrite (long msg) {cmBlueToothRef->print(msg);}
void CapeMirror::btWrite (unsigned long msg) {cmBlueToothRef->print(msg);}

void CapeMirror::lcdDisplayControlMT() {lcdDisplay(1,16,"M"); lcdDisplay(2,16,"T");}

void CapeMirror::lcdDisplayControlPC() {
	lcdDisplay(1,16,"P"); 
	lcdDisplay(2,16,"C");
}


void CapeMirror::btParseData(long* azVal, long* altVal, long* cmdVal)
{

	// reset the variables
	*azVal = 0;
	*altVal = 0;
	*cmdVal = 0;

	azComplete = false;
    altComplete = false;
    cmdComplete = false;

	for (int i=0;iread();

	if (thisChar == leftbracket)
	{
		// read all first data section 
		while (azComplete == false && cmBlueToothRef->available() > 0)
		{
    		char thisChar = cmBlueToothRef->read();
				if (thisChar == semicolon)
				{
  					azComplete = true;
					break; 
				}
				else 
				{
					azData[btByteIndex] = thisChar;
					btByteIndex++;
				}
		}
		btByteIndex = 0;

		// read the second data section
		while (altComplete == false && cmBlueToothRef->available() > 0)
		{
			char thisChar = cmBlueToothRef->read();
				if (thisChar == semicolon)
				{
					altComplete = true;
					break;
				}
				else 
				{
					altData[btByteIndex] = thisChar;
					btByteIndex++;
				}
		}
		btByteIndex= 0;

		// read the third data section
		while (cmdComplete == false && cmBlueToothRef->available() > 0)
		{
			char thisChar = cmBlueToothRef->read();
   				if (thisChar == rightbracket)
				{
					cmdComplete = true;
					break;
				}
				else 
				{
					cmdData[btByteIndex] = thisChar;
					btByteIndex++;
				}
		}
		btByteIndex= 0;
	
	// report back the values
	*azVal = atol(azData);
	*altVal = atol(altData);
	*cmdVal = atol(cmdData);
	}
}


/*
 *   Set up the keypad
 */

// define the rows
void CapeMirror::setKeypadRows(int row1, int row2, int row3, int row4)
{
  this->row1 = row1;
  this->row2 = row2;
  this->row3 = row3;
  this->row4 = row4;
  
  moveSingleStep = false;
}

// define the columns
void CapeMirror::setKeypadCols(int col1, int col2, int col3)
{
  this->col1 = col1;
  this->col2 = col2;
  this->col3 = col3;

  // set them as outputs
  pinMode(this->col1, OUTPUT);
  pinMode(this->col2, OUTPUT);
  pinMode(this->col3, OUTPUT);
}


/*
 *   Read the keypad
 */
int CapeMirror::readKeypad(void)
{
  keyResult = 13;
  
  // Read the 1st column
  digitalWrite(col1, HIGH);  
  if (digitalRead(row1) == HIGH){keyResult = 1;}
  if (digitalRead(row2) == HIGH){keyResult = 4;}
  if (digitalRead(row3) == HIGH){keyResult = 7;}
  if (digitalRead(row4) == HIGH){keyResult = 10;}
  digitalWrite(col1, LOW);  
  if (keyResult<12){return keyResult;}

  // Read the 2nd column 
  digitalWrite(col2, HIGH);  
  if (digitalRead(row1) == HIGH){keyResult = 2;}
  if (digitalRead(row2) == HIGH){keyResult = 5;}
  if (digitalRead(row3) == HIGH){keyResult = 8;}
  if (digitalRead(row4) == HIGH){keyResult = 0;}
  digitalWrite(col2, LOW);  
  if (keyResult<12){return keyResult;}

  // Read the 3rd column 
  digitalWrite(col3, HIGH);  
  if (digitalRead(row1) == HIGH){keyResult = 3;}
  if (digitalRead(row2) == HIGH){keyResult = 6;}
  if (digitalRead(row3) == HIGH){keyResult = 9;}
  if (digitalRead(row4) == HIGH){keyResult = 11;}
  digitalWrite(col3, LOW);

  return keyResult;
}


/*	 First motor
 *   Constructor for four-pin stepper motor
 *   Sets which wires should control the motor and
 *   primary variables used by motor.
 */
void CapeMirror::azStepper(int number_of_steps1, \
						   int motor1_pin_1, int motor1_pin_2, \
						   int motor1_pin_3, int motor1_pin_4)
{
  // which step the motor is on
  this->step_number1 = 0;
  // the motor speed1, in revolutions per minute
  this->speed1 = 0;
  // motor direction1
  this->direction1 = 0;
  // time stamp in ms of the last step taken
  this->last_step_time1 = 0;
  // total number of steps for this motor
  this->number_of_steps1 = number_of_steps1;
  // find the delay nec at 1 rev per min
  this->delay_1revpermin1 = 60L * 1000L  / number_of_steps1;

  // Arduino pins for the motor control connection
  this->motor1_pin_1 = motor1_pin_1;
  this->motor1_pin_2 = motor1_pin_2;
  this->motor1_pin_3 = motor1_pin_3;
  this->motor1_pin_4 = motor1_pin_4;

  // setup the pins on the microcontroller
  pinMode(this->motor1_pin_1, OUTPUT);
  pinMode(this->motor1_pin_2, OUTPUT);
  pinMode(this->motor1_pin_3, OUTPUT);
  pinMode(this->motor1_pin_4, OUTPUT);
}

/*	 Second motor
 *   Constructor for four-pin stepper motor
 *   Sets which wires should control the motor and
 *   primary variables used by motor.
 */
void CapeMirror::altStepper(int number_of_steps2, \
						   int motor2_pin_1, int motor2_pin_2, \
						   int motor2_pin_3, int motor2_pin_4)
{
  // which step the motor is on
  this->step_number2 = 0;
  // the motor speed, in revolutions per minute
  this->speed2 = 0;
  // motor direction
  this->direction2 = 0;
  // time stamp in ms of the last step taken
  this->last_step_time2 = 0;
  // total number of steps for this motor
  this->number_of_steps2 = number_of_steps2;
  // find the delay nec at 1 rev per min
  this->delay_1revpermin2 = 60L * 1000L  / number_of_steps2;

  // Arduino pins for the motor control connection
  this->motor2_pin_1 = motor2_pin_1;
  this->motor2_pin_2 = motor2_pin_2;
  this->motor2_pin_3 = motor2_pin_3;
  this->motor2_pin_4 = motor2_pin_4;

  // setup the pins on the microcontroller
  pinMode(this->motor2_pin_1, OUTPUT);
  pinMode(this->motor2_pin_2, OUTPUT);
  pinMode(this->motor2_pin_3, OUTPUT);
  pinMode(this->motor2_pin_4, OUTPUT);
}

/*	First motor
	Set the min speed, max speed, and steps taken to accelerate
*/
void CapeMirror::azStepperSpeeds(long minSpeed1, long maxSpeed1, double Accel1, long moveSpeed1)
{
	this->motorMinSpeed1 = minSpeed1;
	this->motorMaxSpeed1 = maxSpeed1;
	// Number of steps to accelerate over
	this->motorAccSteps1 = Accel1;
	// Change in speed1 needed per step
	this->motorAccelVal1 = (this->motorMaxSpeed1 -this->motorMinSpeed1) / (Accel1-1);
	// Set the move speed (ie the speed when 'moving' in response to keypad press
	this->move_step_delay1 = 60L * 1000L / this->number_of_steps1 / moveSpeed1;
}

/*	Second motor
	Set the min speed, max speed, and steps taken to accelerate
*/
void CapeMirror::altStepperSpeeds(long minSpeed2, long maxSpeed2, double Accel2, long moveSpeed2)
{
	this->motorMinSpeed2 = minSpeed2;
	this->motorMaxSpeed2 = maxSpeed2;
	// Number of steps to accelerate over
	this->motorAccSteps2 = Accel2;
	// Change in speed1 needed per step
	this->motorAccelVal2 = (this->motorMaxSpeed2 -this->motorMinSpeed2) / (Accel2-1);
	// Set the move speed (ie the speed when 'moving' in response to keypad press
	this->move_step_delay2 = 60L * 1000L / this->number_of_steps2 / moveSpeed2;
}

/*
	Set the interrupt pins
 */
void CapeMirror::setInterruptPins(int firePin, int readPin)
{
	// Pin to fire as an output pin (here a keypad column)
	this->firePin = firePin;
	// Pin to read (here a keypad row)
	this->readPin = readPin;
}


/*
	Get the address of the 'steps to do' variables
 */

void CapeMirror::setStepsAddress(int* azStepsAddress, int* altStepsAddress)
	{
		azStepsToDoAddress = azStepsAddress;
		altStepsToDoAddress = altStepsAddress;
	}


void CapeMirror::slew (int steps_to_move1, int steps_to_move2)
	{
	takeSteps(steps_to_move1, steps_to_move2, slewStep);
	}

void CapeMirror::move(int keyResult)
{
     switch (keyResult) {
      case 0:
      break;
      case 1: // up and left
	  takeSteps(-1,1, moveStep);
      break;
      case 2: // up 
	  takeSteps(0, 1, moveStep);
      break;
      case 3: // up and right
	  takeSteps(1, 1, moveStep);
      break;
      case 4: // left
	  takeSteps(-1, 0, moveStep);
      break;
      case 5: 
		  // toggle whether only moving in single steps
		  do {t = readKeypad();} while (t != 13);
		  moveSingleStepToggle();
      break;
      case 6: // right
	  takeSteps(1, 0, moveStep);
      break;      
      case 7: // left and down
	  takeSteps(-1, -1, moveStep);
      break;      
      case 8: // down
	  takeSteps(0, -1, moveStep);
      break;      
      case 9: // right and down
	  takeSteps(1, -1, moveStep);
      break;      
    }
	delay(move_step_delay1);
	
	if (moveSingleStep == true)
	{
		do {t = readKeypad();} while (t != 13);
	}
}


void CapeMirror::moveSingleStepToggle()
{
moveSingleStep = (moveSingleStep==false)?true:false;
}

/*	
	Step method for both motors
*/
void CapeMirror::takeSteps(int steps_to_move1, int steps_to_move2, int step_type)
{
	if (step_type == slewStep){
		// if slewing, set the interrupt 'fire' pin high
		digitalWrite(this->firePin, HIGH);	
	}

	// steps taken
	int steps_no1= 1;
	int steps_no2= 1;

	// Steps for each motor to complete, and the total
	// how many steps to take for the motor
	int steps_left1 = abs(steps_to_move1);
	int steps_left2 = abs(steps_to_move2);
	int total_steps_left = steps_left1 + steps_left2;

	// determine direction1 based on whether steps_to_mode is + or -:
	if (steps_to_move1 > 0) {this->direction1 = 1;}
	else {this->direction1 = 0;}
	if (steps_to_move2 > 0) {this->direction2 = 1;}
	else {this->direction2 = 0;}

	// if a slew, reset the motor speed 
	if (step_type == slewStep)
	{
		this->speed1 = this->motorMinSpeed1;
		this->speed2 = this->motorMinSpeed2;
	}

	// this is the loop for both motor
	while(total_steps_left > 0) {

    // set new values for the StepsToTake address (ie StepsToTake variable)
	*azStepsToDoAddress = steps_left1;
	*altStepsToDoAddress = steps_left2;

	// if a slew, read the interrupt pin
	if (step_type == slewStep)
	{
		int readVal = digitalRead(this->readPin);
		// if high then exit
		if (readVal==HIGH){
		break;
		}
	}

	//First motor
	//If the motor steps not completed it's steps then
    if (steps_left1 > 0) {

		//if a slew, work out the speed
		if (step_type == slewStep)
		{

			//1.a. if in the first third of total steps AND
			if ((steps_left1 > abs(steps_to_move1/3)) && \
				(steps_left1 > (abs(steps_to_move1/3)*2))) {
				
					// 1.b if not yet at max speed1
					if (this->speed1 < this->motorMaxSpeed1){
						// get the new speed1
						this->speed1 = ((steps_no1 -1) * this->motorAccelVal1) + this->motorMinSpeed1; 
						// get the new delay
						step_delay1 = (this->delay_1revpermin1 / this->speed1); 
					} // i.b.  end if: not yet max speed1
			
			} //1.a. end if: first third of total steps
			  
			//2. if in middle third of steps do nothing

			//3.a. if in the last third of total steps AND
			if (steps_left1 <= (abs(steps_to_move1)/3)) {
			
				//3.b. if within deceleration zone
				if (steps_left1 <= this->motorAccSteps1) {
					// get the new speed1
					this->speed1 = ((steps_left1-1) * this->motorAccelVal1) + this->motorMinSpeed1; 
					// get the new delay
					step_delay1 = (this->delay_1revpermin1 / this->speed1); 
				} //3.b. end if: within deceleration zone
			
			} //3.a. end if: last third of total steps
		} // end: if this is a 'slew'
		
		else // if this is a 'move' not a 'slew'
		{
			step_delay1 = move_step_delay1;
		}


      // move only if the appropriate delay has passed:
      if (millis() - this->last_step_time1 >= this->step_delay1) {
        // get the timeStamp of when you stepped:
        this->last_step_time1 = millis();
          // increment or decrement the step number,
          // depending on direction1:
          if (this->direction1 == 1) {
            this->step_number1++;
            if (this->step_number1 == this->number_of_steps1) {
            this->step_number1 = 0;
            }
          }
          else
		  {
            if (this->step_number1 == 0) {
            this->step_number1 = this->number_of_steps1;
            }
          this->step_number1--;
          }
      // in/decrement the steps left:
      steps_no1++;
      steps_left1--;
	  total_steps_left--;
	  
	  // Adjust the Azimuth variable
	  if (this->direction1 >0) { *gAzimuth += _azRes;}
	  else {*gAzimuth -= _azRes;}
	  if (*gAzimuth >= _azMax) { *gAzimuth -= _azMax; }
	  if (*gAzimuth < 0) { *gAzimuth +=  _azMax; }
	  
	  // only report the arcseconds at the end of the slew
	  if (steps_left1 == 0) {lcdDisplayAzSecs();}

	  // step the motor to step number 0, 1, 2, or 3:
      stepMotor1(this->step_number1 % 4);
      
	  } // End: if suitable delay passed
	  	
	} //End: if (steps_left1 > 0)

	//Second motor  
	//If the motor steps not completed it's steps then
    if (steps_left2 > 0) {

		//if a slew, work out the speed
		if (step_type == slewStep)
		{
	
			//1.a. if in the first third of total steps AND
			if ((steps_left2 > abs(steps_to_move2/3)) && \
			(steps_left2 > (abs(steps_to_move2/3)*2))) {
				// 1.b if not yet at max speed1
				if (this->speed2 < this->motorMaxSpeed2){
					// get the new speed1
					this->speed2 = ((steps_no2 -1) * this->motorAccelVal2) + this->motorMinSpeed2; 
					// get the new delay
					step_delay2 = (this->delay_1revpermin2 / this->speed2); 
				} // i.b.  end if: not yet max speed1
	  
			} //1.a. end if: first third of total steps
			  
		//2. if in middle third of steps do nothing

		//3.a. if in the last third of total steps AND
		if (steps_left2 <= (abs(steps_to_move2)/3)) {
		
			//3.b. if within deceleration zone
			if (steps_left2 <= this->motorAccSteps2) {
				// get the new speed1
				this->speed2 = ((steps_left2-1) * this->motorAccelVal2) + this->motorMinSpeed2; 
				// get the new delay
				step_delay2 = (this->delay_1revpermin2 / this->speed2); 
			} //end if: within deceleration zone
		
		} //3.a. end if: last third of total steps
		} // end: if this is a 'slew'
		
		else // if this is a 'move' not a 'slew'
		{
			step_delay2 = move_step_delay2;
		}

      // move only if the appropriate delay has passed:
      if (millis() - this->last_step_time2 >= this->step_delay2) {
        // get the timeStamp of when you stepped:
        this->last_step_time2 = millis();
          // increment or decrement the step number,
          // depending on direction1:
          if (this->direction2 == 1) {
            this->step_number2++;
            if (this->step_number2 == this->number_of_steps2) {
            this->step_number2 = 0;
            }
          }
          else
		  {
            if (this->step_number2 == 0) {
            this->step_number2 = this->number_of_steps2;
            }
          this->step_number2--;
          }

	  // in/decrement the steps left:
      steps_no2++;
      steps_left2--;
	  total_steps_left--;
      
	  // Adjust the Altitude variable
	  if (this->direction2 >0) { *gAltitude += _altRes;}
	  else {*gAltitude -= _altRes;}
	  if (*gAltitude >= _altMax) {
		// gone too high, end stepping
		*gAltitude -= _altRes;
		steps_left2=0;
		if (step_type == slewStep) {digitalWrite(this->firePin, LOW);}
		lcdDisplayDegsMins();
		lcdDisplaySecs();
		break;
	  }

	  if (*gAltitude < _altMin) { 
		// gone too low, end stepping
		*gAltitude += _altRes;
		steps_left2=0;
		if (step_type == slewStep) {digitalWrite(this->firePin, LOW);}
		lcdDisplayDegsMins();
		lcdDisplaySecs();
		break;
	  }
	  
	  // only report the arcseconds at the end of the slew
	  if (steps_left2 == 0) { lcdDisplayAltSecs(); }

	  // step the motor to step number 0, 1, 2, or 3:
      stepMotor2(this->step_number2 % 4);
      
	  } // end: if suitable delay passed
	} //End: if (steps_left1 > 0)

	  // Display the results
	  lcdDisplayDegsMins();

  } //End: WHILE statement

	// if a 'slew', set the interrupt 'fire' pin low
	if (step_type == slewStep) {digitalWrite(this->firePin, LOW);}

} //End: void step()


/* First motor
 * Moves the motor forward or backwards
 */
void CapeMirror::stepMotor1(int thisStep1)
{
    switch (thisStep1) {
      case 0:    // 1010
      digitalWrite(motor1_pin_1, HIGH);
      digitalWrite(motor1_pin_2, LOW);
      digitalWrite(motor1_pin_3, HIGH);
      digitalWrite(motor1_pin_4, LOW);
      break;
      case 1:    // 0110
      digitalWrite(motor1_pin_1, LOW);
      digitalWrite(motor1_pin_2, HIGH);
      digitalWrite(motor1_pin_3, HIGH);
      digitalWrite(motor1_pin_4, LOW);
      break;
      case 2:    //0101
      digitalWrite(motor1_pin_1, LOW);
      digitalWrite(motor1_pin_2, HIGH);
      digitalWrite(motor1_pin_3, LOW);
      digitalWrite(motor1_pin_4, HIGH);
      break;
      case 3:    //1001
      digitalWrite(motor1_pin_1, HIGH);
      digitalWrite(motor1_pin_2, LOW);
      digitalWrite(motor1_pin_3, LOW);
      digitalWrite(motor1_pin_4, HIGH);
      break;
    }
}


/* Second motor
 * Moves the motor forward or backwards
 */
void CapeMirror::stepMotor2(int thisStep2)
{
    switch (thisStep2) {
      case 0:    // 1010
      digitalWrite(motor2_pin_1, HIGH);
      digitalWrite(motor2_pin_2, LOW);
      digitalWrite(motor2_pin_3, HIGH);
      digitalWrite(motor2_pin_4, LOW);
      break;
      case 1:    // 0110
      digitalWrite(motor2_pin_1, LOW);
      digitalWrite(motor2_pin_2, HIGH);
      digitalWrite(motor2_pin_3, HIGH);
      digitalWrite(motor2_pin_4, LOW);
      break;
      case 2:    //0101
      digitalWrite(motor2_pin_1, LOW);
      digitalWrite(motor2_pin_2, HIGH);
      digitalWrite(motor2_pin_3, LOW);
      digitalWrite(motor2_pin_4, HIGH);
      break;
      case 3:    //1001
      digitalWrite(motor2_pin_1, HIGH);
      digitalWrite(motor2_pin_2, LOW);
      digitalWrite(motor2_pin_3, LOW);
      digitalWrite(motor2_pin_4, HIGH);
      break;
    }
}

void CapeMirror::lcdDisplayCoords()
{
	lcdClear();

	lcdDisplay(1, 1, "Az:    ");
	lcdDisplay(1, 8, (char)223);
	lcdDisplay(1, 9, "  ");
	lcdDisplay(1, 11, (char)39);
	lcdDisplay(1, 12, "  ");
	lcdDisplay(1, 14, (char)34);
	lcdDisplay(1, 15, " ");

	lcdDisplay(2, 1, "Alt:   ");
	lcdDisplay(2, 8, (char)223);
	lcdDisplay(2, 9, "  ");
	lcdDisplay(2, 11, (char)39);
	lcdDisplay(2, 12, "  ");
	lcdDisplay(2, 14, (char)34);
	lcdDisplay(2, 15, " ");
}

void CapeMirror::lcdDisplayDegsMins()
{
	//Azimuth
	azDegLCD = int(*gAzimuth/3600);
	azMinLCD = int((*gAzimuth-(azDegLCD*3600))/60);	
	if (azDegLCD > 99){lcdDisplay(1, 5, azDegLCD);}	
	else if (azDegLCD < 10) {lcdDisplay(1, 5, "  "); lcdDisplay(1, 7, azDegLCD);}
	else {lcdDisplay(1, 5, " "); lcdDisplay(1, 6, azDegLCD);}
	if (azMinLCD < 10) {lcdDisplay(1, 9, " "); lcdDisplay(1, 10, azMinLCD);}
	else {lcdDisplay(1, 9, azMinLCD);}

	//Altitude
	altDegLCD = int(*gAltitude/3600);
	altMinLCD = int((*gAltitude-(altDegLCD*3600))/60);
	if (altDegLCD < 10) {lcdDisplay(2, 6, " "); lcdDisplay(2, 7, altDegLCD);}
	else {lcdDisplay(2, 6, altDegLCD);}
	if (altMinLCD < 10) {lcdDisplay(2, 9, " "); lcdDisplay(2, 10, altMinLCD);}
	else {lcdDisplay(2, 9, altMinLCD);}
}

void CapeMirror::lcdDisplaySecs()
{
lcdDisplayAzSecs();
lcdDisplayAltSecs();
}

void CapeMirror::lcdDisplayAzSecs()
{
	//Azimuth
	azDegLCD = int(*gAzimuth/3600);
	azMinLCD = int((*gAzimuth-(azDegLCD*3600))/60);	
	azSecLCD = int(*gAzimuth-((azDegLCD*3600)+(azMinLCD*60)));
	if (azSecLCD < 10) {lcdDisplay(1, 12, " "); lcdDisplay(1, 13, azSecLCD);}
	else {lcdDisplay(1, 12, azSecLCD);}
}

void CapeMirror::lcdDisplayAltSecs()
{
	//Altitude
	altDegLCD = int(*gAltitude/3600);
	altMinLCD = int((*gAltitude-(altDegLCD*3600))/60);
	altSecLCD = int(*gAltitude-((altDegLCD*3600)+(altMinLCD*60)));
	if (altSecLCD < 10) {lcdDisplay(2, 12, " "); lcdDisplay(2, 13, altSecLCD);}
	else {lcdDisplay(2, 12, altSecLCD);}
}

/*
  version() returns the version of the library:
*/
int CapeMirror::version(void)
{
  return 2;
}

post a comment...

you must be logged in to post a comment.