Sunday, 14 May 2017

controller_due.ino - Ardunio Due code incl hardware encoder counting

// see https://www.youtube.com/edit?o=U&video_id=7-xpBwuLIoI


#include <AccelStepper.h>
#include <LiquidCrystal.h>
#include <stdlib.h>

/* V 3.1 - incl acceleration and threading */
/* V 3.2 - incl cross slide power button
/* V 3.3 - change (Q)uiet to (S)erial feedback, add debug level 2 for feedback
/* V 3.4 - threading performance changes
/* V 3.5 - changed code order for performance and threading speed to 2200
/* V 3.6 - send back RPM
/* V 3.7 - add abort routine

/* blue wire is gnd */

// leadscrew

#define DIR_L_PIN 9 // to direction+ on DQ542MA green
#define STEP_L_PIN 10 // to pulse+ on DQ542MA orange

// crosslide

#define DIR_C_PIN 7 // to direction+ on DQ542MA green
#define STEP_C_PIN 6 // to pulse+ on DQ542MA orange

#define ENABLE_L_PIN 8 // to enable+ on DQ542MA white
#define ENABLE_C_PIN 16 // to enable+ on DQ542MA white

#define waitPin 11 //q to switch
#define joyLeft 12
#define joyRight 5
#define joyIn 3
#define joyOut 4

#define powerpin 14


/*
cross and lead directions - facing lathe

          +
          +
     ----- ++++++
          -
          -        
        
 Commands :
  Can use
  R                Query RPM
  M1, M0           Mains power on SSR on or off - controls stepper power supply and lathe power
  E1, E0           Enable/disable cross slide stepper (1 = enable)
  Lxxx;Syyy;       leadscrew xxx steps, at yyy per second  - positive is right, negative left
  Cxx;Syyy;        crosslide xxx steps, at yyy per second  - positive is in, negative out
  Dxxx;            at string start, repeat entire string xxx times (duplicate)
  Bxxx;Syyy;Szzz   go leadscrew left xxx steps at yyy per second, crossslide in at zzz per second (tied to leadscrew)
                   (if xxx is negative then right - if zzz is negative then out)
                 
  Tx;Pyyy;Lzzz;    x=0 means turn thread starting at left, 1=from right
                   yyy=length of one thread in mm (eg 8 per inch = 3.175) - tied to one turn of spindle as measured by encoder
                   zzz=distance in mm to thread

  K                cut motors
  Wxxx;            wait xxx milliseconds
  W0;              wait for button on waitPin to be pressed
 
  Xn.n;            Set X
  Zn.n;            Set Z
  Ax;Sy;           Acceleration : x1=leadscrew x2=crosslide y=factor to multiply speed by
                   B command will not use acceleration
                   S0 means do not use acceleration
  S                Serial feedback 0=disable 1=enable, 2=debug as well (0 means qonly sends response after full command string is consumed
  J                joystick 0=disable 1=enable
  #                end of command string
 
*/

AccelStepper stepper1(1,STEP_L_PIN, DIR_L_PIN); // leadscrew
AccelStepper stepper2(1,STEP_C_PIN, DIR_C_PIN); // crosslide

const int quad_A = 2;
const int quad_B = 13;
const unsigned int mask_quad_A = digitalPinToBitMask(quad_A);
const unsigned int mask_quad_B = digitalPinToBitMask(quad_B);
const int enc_z = 15;

char commandin[2550];
char rest[2550];
char str[2550];
char comm[2550];
float commVal[2550];
char floatval[2550];

char output1[100];
char output2[40];

int x;
unsigned long d;
int charreader;
int commandstringlength=0;
unsigned long timerStart;
unsigned long timerEnd;
float commVal1;
float commVal2;
float commVal3;
float LAccel=0.0F;
float CAccel=0.0F;

char currentProcess;
int currentCommand=0;
int numCommands=0;
int numDups=0;
int currentDup=0;

boolean processing=false;
boolean allDone=true;
boolean joystick=false;
int serialFeedback=0;

int globalLeadSteps=0;
int globalCrossSteps=0;

unsigned long currMillis=millis();
unsigned long prevMillis=millis();

unsigned long debugMillis=millis();

unsigned long prev_z_millis=millis();
unsigned long z_millis=millis();

int enc_at_z=0;
int waiting_first_z=1;
unsigned int partticks;

unsigned int enc_ticks;
unsigned int enc_steps;
unsigned int enc_steps_req;
unsigned int enc_total_steps_req;
unsigned int enc_ticks_to_steps_x_10000;
// lcd pins are    4   6  11  12  13  14
// connected to the following pins on the Due
LiquidCrystal lcd(45, 43, 53, 51, 49, 47);

void setup() {

pinMode(powerpin,OUTPUT);
digitalWrite(powerpin, LOW);  
 
Serial.begin(115200);
 // lcd.begin(20, 4);
//lcdprint1("12345678901234567890");
 // lcdprint1("Initialising        ");

pinMode(ENABLE_L_PIN,OUTPUT);
digitalWrite(ENABLE_L_PIN, LOW);
pinMode(ENABLE_C_PIN,OUTPUT);
digitalWrite(ENABLE_C_PIN, LOW);

pinMode(waitPin,INPUT);
digitalWrite(waitPin, HIGH); // enable internal resistor

pinMode(joyLeft,INPUT);
digitalWrite(joyLeft, HIGH);
pinMode(joyRight,INPUT);
digitalWrite(joyRight, HIGH);
pinMode(joyIn,INPUT);
digitalWrite(joyIn, HIGH);
pinMode(joyOut,INPUT);
digitalWrite(joyOut, HIGH);

stepper1.setMaxSpeed(3000);
stepper2.setMaxSpeed(3000);
stepper1.setAcceleration(0);
stepper2.setAcceleration(0);
// encoder
// activate peripheral functions for quad pins
REG_PIOB_PDR = mask_quad_A;     // activate peripheral function (disables all PIO functionality)
REG_PIOB_ABSR |= mask_quad_A;   // choose peripheral option B  
REG_PIOB_PDR = mask_quad_B;     // activate peripheral function (disables all PIO functionality)
REG_PIOB_ABSR |= mask_quad_B;   // choose peripheral option B
// activate clock for TC0
REG_PMC_PCER0 = (1<<27);
// select XC0 as clock source and set capture mode
REG_TC0_CMR0 = 5;
// activate quadrature encoder and position measure mode, no filters
REG_TC0_BMR = (1<<9)|(1<<8)|(1<<12);
// enable the clock (CLKEN=1) and reset the counter (SWTRG=1)
// SWTRG = 1 necessary to start the clock!!
REG_TC0_CCR0 = 5;  
pinMode(enc_z, INPUT);     
attachInterrupt(enc_z, enc_zrising, RISING);
 enc_at_z=0;
// end encoder
delay(1000);
lcd.clear();
//lcdprint1("12345678901234567890");
  lcdprint1("Ready               ");


void loop() {
currMillis=millis();
if(Serial.available()>0) {
   charreader = Serial.read();   
   switch (char(charreader)) {
      case 'K':         
         stepper1.stop();   
         stepper2.stop();   
         sendXZImmediate();       
         Serial.write("PC #"); // command sequence completed        
       //lcdprint1("12345678901234567890");
         lcdprint1("Killed              ");
         commandstringlength=0; 
         currentCommand=0;
         numDups=0;
         currentDup=0;       
         allDone=true;
         processing=false;  
         break;
      case '#':
         commandin[commandstringlength] = charreader;        
         parse();         
         commandstringlength=0;                             
         break;
      default :
         commandin[commandstringlength] = charreader;
         commandstringlength++;
         break;         
     }  // switch
  } // Serial.available

 // -------------------------------------------------------------------------------------------------

if (processing) { 
 
   if (currentProcess=='T') {    
       enc_ticks=REG_TC0_CV0; /// swap with next line after debugging
       // enc_ticks=millis() - debugMillis;
       if (waiting_first_z==0) {
          enc_steps_req=((enc_ticks-partticks)*10000) / enc_ticks_to_steps_x_10000;
          if (enc_steps>=enc_total_steps_req) {
             respond_to_pc ("CC #");                                     
             incrementCommands();
             return;
             } // threading completed

          if (enc_steps<enc_steps_req) {
              if ((enc_steps_req-enc_steps)>1) {
                Serial.print("Aborting - threading step backlog>1, steps required=");
                Serial.print(enc_steps_req);
                Serial.print(" Steps made=");
                Serial.println(enc_steps);              
                abort();
              }        
              stepLeadScrew(commVal1);
              return;
              } // need to step
           } // waiting_first_z==0

       if (waiting_first_z==1) {       
          // enc_at_z=1; /////////////////// take out after debugging
          if (enc_at_z==1) {                
              waiting_first_z=0;
              partticks=enc_ticks; // partticks will be a partial revolution until z was reached
              } // at z
           } // waiting first z, still not arrived
      return;
      } // currentProcess=='T'
 
   if (currentProcess=='L') {
       if (commVal1==0 || (stepper1.distanceToGo()<=0 && commVal1>0) || (stepper1.distanceToGo()>=0 && commVal1<0)) {
         respond_to_pc ("CC #");                     
         incrementCommands();
          return;
          } // done
       runMotor(1);
       return;     
      }  // L
    
   if (currentProcess=='C') {
       if (commVal1==0 || (stepper2.distanceToGo()<=0 && commVal1>0) || (stepper2.distanceToGo()>=0 && commVal1<0)) {
          respond_to_pc ("CC #");
          incrementCommands();
          return;
          } // done               
       runMotor(2);
       return;
      }  // C

   if (currentProcess=='B') {
       if (commVal1==0 || (stepper1.distanceToGo()<=0 && commVal1>0) || (stepper1.distanceToGo()>=0 && commVal1<0)) {
          respond_to_pc("CC #");        
          incrementCommands();
          return;
          } // done
       runMotor(1);
       runMotor(2);
       return;
       } // B
 
     if (currentProcess=='S')  {  
       serialFeedback=commVal1;
       respond_to_pc("CC #");    
       incrementCommands();
       return;      
   }

   if (currentProcess=='R') {
       numCommands=0;
       return; 
       }
 
   if (currentProcess=='M')  {  
       if (commVal1==1) {
          digitalWrite(powerpin,HIGH);
          }
       else {
          digitalWrite(powerpin,LOW);
          }
       respond_to_pc("CC #");    
       incrementCommands();
       return;      
   } 
 
   if (currentProcess=='E')  {  
       if (commVal1==1) {
          digitalWrite(ENABLE_C_PIN,HIGH);
          }
       else {
          digitalWrite(ENABLE_C_PIN,LOW);
          }
       respond_to_pc("CC #");    
       incrementCommands();
       return;      
   } 
 
   if (currentProcess=='X')  {  
       respond_to_pc("CC #");        
        incrementCommands();
        return;      
   }
   if (currentProcess=='Z')  {  
       respond_to_pc("CC #");        
        incrementCommands();                    
        return;      
   }
   if (currentProcess=='J')  {  
       respond_to_pc("CC #");        
       incrementCommands();                    
       return;      
   } 

   if (currentProcess=='A')  {  
       respond_to_pc("CC #");        
       incrementCommands();                    
       return;      
   } 

   if (currentProcess=='W')  {
      if (commVal1==0) {
         if (digitalRead(waitPin)==LOW) {
            respond_to_pc("CC #");        
            incrementCommands();                
         } // LOW
         return;
       } // Val1=0
      timerEnd=millis();
      if ((timerEnd-timerStart)>=commVal1) {     
         respond_to_pc("CC #");        
         incrementCommands();
          return;       
         } // done
      } // W                                                 
     
   } // processing    

// -------------------------------------------------------------------------------------------------

if (!processing) { 
  if (joystick==true) {
  if (digitalRead(joyLeft)==LOW) {
     stepper1.move(-99999999L);     
     if (digitalRead(waitPin)==LOW) {
        stepper1.setSpeed(-1500);
        stepper1.setAcceleration(-1500*LAccel);         
        }
      else {
        stepper1.setSpeed(-120);    
        stepper1.setAcceleration(-120*LAccel);      
      }  
     runMotor(1);
   }
 
  else if (digitalRead(joyRight)==LOW) {
     stepper1.move(99999999L);     
     if (digitalRead(waitPin)==LOW) {
        stepper1.setSpeed(1500);
        stepper1.setAcceleration(1500*LAccel);      
        }
     else {
        stepper1.setSpeed(120);
        stepper1.setAcceleration(120*LAccel);      
      }  
     runMotor(1);
   } 
  else if (digitalRead(joyIn)==LOW) {
     stepper2.move(99999999L);     
     if (digitalRead(waitPin)==LOW) {
        stepper2.setSpeed(2000);
        stepper2.setAcceleration(2000*CAccel);      
        }
     else {
        stepper2.setSpeed(100);
        stepper2.setAcceleration(100*CAccel);              
      }  
     runMotor(2);
        
   } 
  else if (digitalRead(joyOut)==LOW) {
     stepper2.move(-99999999L);     
     if (digitalRead(waitPin)==LOW) {   
       stepper2.setSpeed(-2000);
        stepper2.setAcceleration(-2000*CAccel);             
        }
     else {
        stepper2.setSpeed(-100);    
        stepper2.setAcceleration(-100*CAccel);                     
      }  
     runMotor(2);   
   }
   else {
   //digitalWrite(13, HIGH);
  // sendXZJoystick();  
   }
   } // joystick enabled
//   else
 //  digitalWrite(13, LOW);
   
   if (allDone) {
     return;
   }  // allDone 

// -------------------------------------------------------------------------------------------------
 
   processing=true; // not allDone, and not processing - so process next command
 
   currentProcess=comm[currentCommand];    
   //Serial.println(currentProcess);
 
     
   if (currentProcess=='W') {
       commVal1=commVal[currentCommand];
       if (commVal1>0) {
          if (serialFeedback>0) {
          //lcdprint1("12345678901234567890");
            lcdprint1("Wait time           ");
            Serial.write("WT ");
            Serial.print(commVal1,0);
            Serial.write(" #");
            }
          timerStart=millis();
          }
       else {
          if (serialFeedback>0) {     
           //lcdprint1("12345678901234567890");
             lcdprint1("Wait button         ");
             Serial.write("WB ");
             Serial.write("#");
          }
       } 
       return;    
       } // W

   if (currentProcess=='R') {
       Serial.write("R ");
       Serial.print(z_millis - prev_z_millis);
       Serial.write(" ");
       Serial.print(prev_z_millis);
       Serial.write(" ");     
       Serial.print(z_millis);            
       Serial.write  (" #");
       processing=false;
       currentProcess=' ';
       numCommands=0;
       allDone=true;
       return;
     } // rpm
     
   if (currentProcess=='S') {
      commVal1=commVal[currentCommand]; 
      respond_to_pc("S #"); 
      return;       
   } // set X     

   if (currentProcess=='M') {
      commVal1=commVal[currentCommand];
      globalLeadSteps=commVal1;
      if (commVal1==0)
        Serial.write("M0 #"); 
      else
        Serial.write("M1 #"); 
      return; 
   } // set mains
 
   if (currentProcess=='E') {
      commVal1=commVal[currentCommand];
      globalLeadSteps=commVal1;
      if (commVal1==0)
        Serial.write("E0 #"); 
      else
        Serial.write("E1 #"); 
      return; 
   } // set cross slide enabled
    
   if (currentProcess=='Z') {
      commVal1=commVal[currentCommand];
      globalLeadSteps=commVal1;
      respond_to_pc("Z #"); 
      return; 
   } // set Z

   if (currentProcess=='X') {
      commVal1=commVal[currentCommand];   
      globalCrossSteps=commVal1;
      respond_to_pc("X #"); 
      return;       
   } // set X
 
   if (currentProcess=='J') {
      commVal1=commVal[currentCommand];
      if (commVal1==1) {
     joystick=true;
      }
      else {   
         joystick=false;
      }       
      Serial.write("J ");
      Serial.write("#");
      Serial.flush();       
      return; 
   } // set joystick on/off

   if (currentProcess=='A') {
       if (commVal[currentCommand]==1) {
          currentCommand++;              
          LAccel=commVal[currentCommand];    
       }
       if (commVal[currentCommand]==2) {
          currentCommand++;              
          CAccel=commVal[currentCommand];    
       }
      respond_to_pc("A #"); 
      }

   if (currentProcess=='T') {
       commVal1=commVal[currentCommand];
       currentCommand++;              
       commVal2=commVal[currentCommand];          
       currentCommand++;              
       commVal3=commVal[currentCommand];
       // ?Multiply encoding factor by 10000, to use integer instead of float for performance
       // ?It is divided again when calculating whether a step is needed
       enc_total_steps_req=commVal3*214.1732;
 
       // Ticks to steps conversion is calculated as follows:
       // 680 = steps per mm (214.1732) x 3.175 mm (1/8 inch or one rev) - so 680 = steps for 1 leadscrew rev
       // 2.1176 = ticks per rev (1440 / 680 )
       // 21176 is 10000 x conversion factor from ticks to steps
       // commVal2 is pitch in mm (3.175=1/8 inch) - larger pitch needs fewer ticks - so dividing by this gives a faster step rate for coarser pitches

       enc_ticks_to_steps_x_10000=21176 / commVal2;
       sprintf(output1,"Threading enc_ticks_to_steps_x_10000 is %u , total steps required is %u #",enc_ticks_to_steps_x_10000,enc_total_steps_req);
       Serial.println(output1);
       enc_steps=0;     
       waiting_first_z=1;
       if (commVal1==1) {
       digitalWrite(DIR_L_PIN,LOW);
       }
       else {
       digitalWrite(DIR_L_PIN,HIGH);
       }    
      debugMillis=millis();
       enc_at_z=0;
   } // T
          
   if (currentProcess=='L') {
       commVal1=commVal[currentCommand];
       currentCommand++;              
       commVal2=commVal[currentCommand];          
       stepper1.setCurrentPosition(0);
       stepper1.move(commVal1);
       stepper1.setSpeed(commVal2);
       stepper1.setAcceleration(commVal2*LAccel);                           
       if (commVal1 >0.0) {
          //lcdprint1("12345678901234567890");
            lcdprint1("Right               ");
          if (serialFeedback>1) {
              sprintf(output1,"LR %0.0f %0.0f #",commVal1,commVal2);
              Serial.print(output1);
             }
          }
       else {
            //lcdprint1("12345678901234567890");
              lcdprint1("Left                ");
          if (serialFeedback>1) {
              sprintf(output1,"LL %0.0f %0.0f #",commVal1*-1.0,commVal2*-1.0);
              Serial.print(output1);
              }
          }      
       } // L

   if (currentProcess=='C') {
       commVal1=commVal[currentCommand];
       currentCommand++;              
       commVal2=commVal[currentCommand];          
       stepper2.setCurrentPosition(0);
       stepper2.move(commVal1);
       stepper2.setSpeed(commVal2);            
       stepper2.setAcceleration(commVal2*CAccel);                           
       if (commVal1 >0.0) {
        //lcdprint1("12345678901234567890");
          lcdprint1("In                  ");
          if (serialFeedback>1) {
              sprintf(output1,"CI %0.0f %0.0f #",commVal1,commVal2);
              Serial.print(output1);
          }
         }
       else {
         //lcdprint1("12345678901234567890");
           lcdprint1("Out                 ");
       if (serialFeedback>1) {
              sprintf(output1,"CO %0.0f %0.0f #",commVal1*-1.0,commVal2*-1.0);
              Serial.print(output1);
          }
         }
       } // C

   if (currentProcess=='B') { // both, leadscrew controls the stop
       commVal1=commVal[currentCommand];
       currentCommand++;              
       commVal2=commVal[currentCommand];          
       currentCommand++;              
       commVal3=commVal[currentCommand];                 
       stepper1.setCurrentPosition(0);     
       stepper2.setCurrentPosition(0);
       stepper1.move(commVal1);
       stepper1.setSpeed(commVal2);            
       stepper1.setAcceleration(0);                                  
       if (commVal3>0) {
          stepper2.move(99999999L);
          }
       else {
          stepper2.move(-99999999L);                
          }         
       stepper2.setSpeed(commVal3);                 
       stepper2.setAcceleration(0);                                         
       if (commVal2 >0.0 && commVal3 >0.0) {
          //lcdprint1("12345678901234567890");
            lcdprint1("In right            ");
       if (serialFeedback>1) {
              sprintf(output1,"BRI %0.0f %0.0f %0.0f#",commVal1,commVal2,commVal3);
              Serial.print(output1);
              lcdprint2(output1);
          }
         } // BRI
       
       if (commVal2 >=0.0 && commVal3 <0.0) {
          //lcdprint1("12345678901234567890");
            lcdprint1("Out right           ");
       if (serialFeedback>1) {
              sprintf(output1,"BRO %0.0f %0.0f %0.0f#",commVal1,commVal2,commVal3*-1.0);
              Serial.print(output1);
              lcdprint2(output1);            
          }       
          } // BRO
       
       if (commVal2 <0.0 && commVal3 >=0.0) {
          //lcdprint1("12345678901234567890");
            lcdprint1("In left             ");
       if (serialFeedback>1) {
              sprintf(output1,"BLI %0.0f %0.0f %0.0f#",commVal1*-1.0,commVal2*-1.0,commVal3);
              Serial.print(output1);
              lcdprint2(output1);            
          }       
          } // BLI
       
       if (commVal2 <0.0 && commVal3 <0.0) {
          //lcdprint1("12345678901234567890");
            lcdprint1("Out left            ");
       if (serialFeedback>1) {
              sprintf(output1,"BLO %0.0f %0.0f %0.0f#",commVal1*-1.0,commVal2*-1.0,commVal3*-1.0);
              Serial.print(output1);
              lcdprint2(output1);            
          }                
          }  // BLO    
      } // B  
 
   }  // !processing
 
// -----------------------------------------------------------------------------------------------------------------

} // loop

void parse() {
numCommands=0;
currentDup=1;
allDone=false;
processing=false;
while (char(commandin[0])!='#') {
   sscanf(commandin,"%[^';']%[^\n]",str,rest);
     x=sscanf(str,"%c%s",&comm[numCommands],floatval);
  commVal[numCommands]=atof(floatval); 
   numCommands++;
   strcpy(commandin,rest+1);
   }  
if (comm[0]=='D') {
 //  Serial.println("Received D");
   currentCommand=1; 
   numDups=commVal[0]; 
   if (numDups==0) {
      numDups=1;
      }
   Serial.write("D 1 #");       
   }
else {
   currentCommand=0;
   numDups=1;
   } 
//   Serial.print("numDups=");
//   Serial.println(numDups);    
//   Serial.print("numCommands="); 
//   Serial.println(numCommands);       
} // parse

void incrementCommands() {
processing=false;
currentProcess=' ';

//   Serial.print("currentCommand="); 
//   Serial.println(currentCommand);       
//   Serial.print("numCommands="); 
//   Serial.println(numCommands);       
if (currentCommand<numCommands) {
   currentCommand++;
   }
if (currentCommand==numCommands) {
//   Serial.print("currentDup="); 
//   Serial.println(currentDup); 
//   Serial.print("numDups="); 
//   Serial.println(numDups);    
    if (currentDup==numDups) {
       allDone=true;
       //lcdprint1("12345678901234567890");
       //  lcdprint1("Ready               ");
       //  lcdprint2(" ");

         Serial.write("PC "); // command completed               
         Serial.print(globalCrossSteps);
         Serial.write(" ");        
         Serial.print(globalLeadSteps);       
         Serial.write(" #");        
         return;
         }
    currentDup++;
    if (serialFeedback>0) {
       Serial.write("D ");
       Serial.print(currentDup);  
       Serial.write(" #");
       }
    if (comm[0]=='D') {
       currentCommand=1; 
       }
    else {
       currentCommand=0;
       }
   }     
}

void lcdprint1(char * msg) {
lcd.setCursor(0,0);
lcd.print(msg);
}

void lcdprint2(char * msg) {
lcd.setCursor(0,1);
lcd.print("                    ");
lcd.setCursor(0,1);
lcd.print(msg);
}

void stepLeadScrew(int dir) {
  digitalWrite(STEP_L_PIN,HIGH);
  delayMicroseconds(1);
  digitalWrite(STEP_L_PIN,LOW);
  enc_steps++;
  if (dir==1) {
    globalLeadSteps--;
  }
  else {
    globalLeadSteps++;
  }       
}

void runMotor(int motor) {
if (motor==1) {
   if (stepper1.runSpeed()) {     
       if (stepper1.speed()>=0) {
          globalLeadSteps++;
           enc_steps++;          }
       else {
          globalLeadSteps--;
          enc_steps++;
          }       
      }
   }
if (motor==2) {
   if (stepper2.runSpeed()) {
       if (stepper2.speed()>=0) {
          globalCrossSteps++;
          }
       else {
          globalCrossSteps--;
          }      
 
      }
   } 
}

void respond_to_pc (char * msg) {
  if (serialFeedback>0) {
   Serial.write(msg); 
  }
}

void respond_to_pc_debug (char * msg) {
  if (serialFeedback==2) {
   Serial.write(msg); 
  }
}  
void sendXZJoystick() {
   if ((currMillis-prevMillis)>100) {
       prevMillis=currMillis;     
       Serial.write("P ");
       Serial.print(globalCrossSteps);
       Serial.write(" ");        
       Serial.print(globalLeadSteps);
       Serial.write(" #");    
       }
}
     
void sendXZImmediate() {
       Serial.write("P ");
       Serial.print(globalCrossSteps);
       Serial.write(" ");        
       Serial.print(globalLeadSteps);
       Serial.write(" #");    
       }
       
 void enc_zrising() {
  enc_at_z=1;
  prev_z_millis=z_millis;
  z_millis=currMillis;
  respond_to_pc_debug ("Z");                     
}

  void abort () {       
    stepper1.stop();   
    stepper2.stop();   
    sendXZImmediate();       
    Serial.write("PC #"); // command sequence completed        
    commandstringlength=0; 
    currentCommand=0;
    numDups=0;
    currentDup=0;       
    allDone=true;
    processing=false;  

  }