Exemple #1
0
void nurbs_start (int p_seen) {
	reset_nurbs ();
	int tmp;
	if(code_seen('U')) du = code_value();
	if(code_seen('K')) {
		tmp = code_value();
		knot[0] = tmp;
		knot[1] = tmp;
		knot[2] = tmp;
	}
   if(code_seen('K')) knot[3] = code_value();
	p = p_seen;
}
Exemple #2
0
void nurbs_next () {

	float cx, cy, cw;
	if (code_seen('X')) cx = code_value ();
	if (code_seen('Y')) cy = code_value ();
	if (code_seen('W')) cw = code_value ();
	if (code_seen('K')) ck = code_value ();
	push_back (cx, cy, cw, ck);

	while (u < knot[3]) {
		nurbs_basis ();
		nurbs_curve ();
		nurbs_move ();
		u += du;
	}
	
}
void process_commands() // Routine to interpret commands sent over serial
{
  unsigned long codenum; // throwaway variable
  char *starpos = NULL;

  if (code_seen('G'))
  {
    switch ((int)code_value())
    {
    }
  }
}
void get_coordinates() {
    if (code_seen('X')) destination_x = (float)code_value() + relative_mode*current_x;
    else destination_x = current_x;                                                       //Are these else lines really needed?
    if (code_seen('Y')) destination_y = (float)code_value() + relative_mode*current_y;
    else destination_y = current_y;
    if (code_seen('Z')) destination_z = (float)code_value() + relative_mode*current_z;
    else destination_z = current_z;
    if (code_seen('E')) destination_e = (float)code_value() + (relative_mode_e || relative_mode)*current_e;
    else destination_e = current_e;
    if (code_seen('F')) {
        next_feedrate = code_value();
        if (next_feedrate > 0.0) feedrate = next_feedrate;
    }

    //Find direction
    if (destination_x >= current_x) direction_x=1;
    else direction_x=0;
    if (destination_y >= current_y) direction_y=1;
    else direction_y=0;
    if (destination_z >= current_z) direction_z=1;
    else direction_z=0;
    if (destination_e >= current_e) direction_e=1;
    else direction_e=0;


    if (min_software_endstops) {
        if (destination_x < 0) destination_x = 0.0;
        if (destination_y < 0) destination_y = 0.0;
        if (destination_z < 0) destination_z = 0.0;
    }

    if (max_software_endstops) {
        if (destination_x > X_MAX_LENGTH) destination_x = X_MAX_LENGTH;
        if (destination_y > Y_MAX_LENGTH) destination_y = Y_MAX_LENGTH;
        if (destination_z > Z_MAX_LENGTH) destination_z = Z_MAX_LENGTH;
    }

    if (feedrate > max_feedrate) feedrate = max_feedrate;
}
void gcode_M100() {
  static int m100_not_initialized = 1;
  unsigned char* sp, *ptr;
  int i, j, n;
  //
  // M100 D dumps the free memory block from __brkval to the stack pointer.
  // malloc() eats memory from the start of the block and the stack grows
  // up from the bottom of the block.    Solid 0xE5's indicate nothing has
  // used that memory yet.   There should not be anything but 0xE5's within
  // the block of 0xE5's.  If there is, that would indicate memory corruption
  // probably caused by bad pointers.  Any unexpected values will be flagged in
  // the right hand column to help spotting them.
  //
#if ENABLED(M100_FREE_MEMORY_DUMPER) // Disable to remove Dump sub-command
  if (code_seen('D')) {
    ptr = (unsigned char*) __brkval;
    //
    // We want to start and end the dump on a nice 16 byte boundry even though
    // the values we are using are not 16 byte aligned.
    //
    SERIAL_ECHOPGM("\n__brkval : ");
    prt_hex_word((unsigned int) ptr);
    ptr = (unsigned char*)((unsigned long) ptr & 0xfff0);
    sp = top_of_stack();
    SERIAL_ECHOPGM("\nStack Pointer : ");
    prt_hex_word((unsigned int) sp);
    SERIAL_ECHOPGM("\n");
    sp = (unsigned char*)((unsigned long) sp | 0x000f);
    n = sp - ptr;
    //
    // This is the main loop of the Dump command.
    //
    while (ptr < sp) {
      prt_hex_word((unsigned int) ptr); // Print the address
      SERIAL_ECHOPGM(":");
      for (i = 0; i < 16; i++) {      // and 16 data bytes
        prt_hex_byte(*(ptr + i));
        SERIAL_ECHOPGM(" ");
        delay(2);
      }
      SERIAL_ECHO("|");         // now show where non 0xE5's are
      for (i = 0; i < 16; i++) {
        delay(2);
        if (*(ptr + i) == 0xe5)
          SERIAL_ECHOPGM(" ");
        else
          SERIAL_ECHOPGM("?");
      }
      SERIAL_ECHO("\n");
      ptr += 16;
      delay(2);
    }
    SERIAL_ECHOLNPGM("Done.\n");
    return;
  }
#endif
  //
  // M100 F   requests the code to return the number of free bytes in the memory pool along with
  // other vital statistics that define the memory pool.
  //
  if (code_seen('F')) {
    int max_addr = (int) __brkval;
    int max_cnt = 0;
    int block_cnt = 0;
    ptr = (unsigned char*) __brkval;
    sp = top_of_stack();
    n = sp - ptr;
    // Scan through the range looking for the biggest block of 0xE5's we can find
    for (i = 0; i < n; i++) {
      if (*(ptr + i) == (unsigned char) 0xe5) {
        j = how_many_E5s_are_here((unsigned char*) ptr + i);
        if (j > 8) {
          SERIAL_ECHOPAIR("Found ", j);
          SERIAL_ECHOPGM(" bytes free at 0x");
          prt_hex_word((int) ptr + i);
          SERIAL_ECHOPGM("\n");
          i += j;
          block_cnt++;
        }
        if (j > max_cnt) {      // We don't do anything with this information yet
          max_cnt  = j;     // but we do know where the biggest free memory block is.
          max_addr = (int) ptr + i;
        }
      }
    }
    if (block_cnt > 1)
      SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.\n");
    SERIAL_ECHO("\nDone.\n");
    return;
  }
  //
  // M100 C x  Corrupts x locations in the free memory pool and reports the locations of the corruption.
  // This is useful to check the correctness of the M100 D and the M100 F commands.
  //
#if ENABLED(M100_FREE_MEMORY_CORRUPTOR)
  if (code_seen('C')) {
    int x;      // x gets the # of locations to corrupt within the memory pool
    x = code_value();
    SERIAL_ECHOLNPGM("Corrupting free memory block.\n");
    ptr = (unsigned char*) __brkval;
    SERIAL_ECHOPAIR("\n__brkval : ", (long) ptr);
    ptr += 8;
    sp = top_of_stack();
    SERIAL_ECHOPAIR("\nStack Pointer : ", (long) sp);
    SERIAL_ECHOLNPGM("\n");
    n = sp - ptr - 64;    // -64 just to keep us from finding interrupt activity that
    // has altered the stack.
    j = n / (x + 1);
    for (i = 1; i <= x; i++) {
      *(ptr + (i * j)) = i;
      SERIAL_ECHO("\nCorrupting address: 0x");
      prt_hex_word((unsigned int)(ptr + (i * j)));
    }
    SERIAL_ECHOLNPGM("\n");
    return;
  }
#endif
  //
  // M100 I    Initializes the free memory pool so it can be watched and prints vital
  // statistics that define the free memory pool.
  //
  if (m100_not_initialized || code_seen('I')) {       // If no sub-command is specified, the first time
    SERIAL_ECHOLNPGM("Initializing free memory block.\n");    // this happens, it will Initialize.
    ptr = (unsigned char*) __brkval;        // Repeated M100 with no sub-command will not destroy the
    SERIAL_ECHOPAIR("\n__brkval : ", (long) ptr);     // state of the initialized free memory pool.
    ptr += 8;
    sp = top_of_stack();
    SERIAL_ECHOPAIR("\nStack Pointer : ", (long) sp);
    SERIAL_ECHOLNPGM("\n");
    n = sp - ptr - 64;    // -64 just to keep us from finding interrupt activity that
    // has altered the stack.
    SERIAL_ECHO(n);
    SERIAL_ECHOLNPGM(" bytes of memory initialized.\n");
    for (i = 0; i < n; i++)
      *(ptr + i) = (unsigned char) 0xe5;
    for (i = 0; i < n; i++) {
      if (*(ptr + i) != (unsigned char) 0xe5) {
        SERIAL_ECHOPAIR("? address : ", (unsigned long) ptr + i);
        SERIAL_ECHOPAIR("=", *(ptr + i));
        SERIAL_ECHOLNPGM("\n");
      }
    }
    m100_not_initialized = 0;
    SERIAL_ECHOLNPGM("Done.\n");
    return;
  }
  return;
}
Exemple #6
0
void process_commands() {
    unsigned long codenum; //throw away variable
    //char *starpos = NULL;

    if (code_seen('G')) {
        switch ((int) code_value()) {
            case 0: // G0 -> G1
            case 1: // G1
                if (code_seen('Z')) {
                    codenum = code_value();
                    penup = codenum > 0;
                }

                if (relative_mode) {
                    double newx = 0;
                    double newy = 0;
                    if (code_seen('X')) {
                        newx = code_value();
                    }
                    if (code_seen('Y')) {
                        newy = code_value();
                    }
                    gcode_move(newx, newy, !penup, true);
                } else {
                    double newx = xpos;
                    double newy = ypos;
                    if (code_seen('X')) {
                        newx = code_value();
                    }
                    if (code_seen('Y')) {
                        newy = code_value();
                    }
                    gcode_move(newx, newy, !penup, false);
                }
                break;

            case 4: // G4 dwell
                codenum = 0;
                if (code_seen('P')) codenum = code_value(); // milliseconds to wait
                if (code_seen('S')) codenum = code_value() * 1000; // seconds to wait
                codenum = codenum / 10;
                while (codenum-- > 0) {
                    wdt_reset();
                    msleep(10);
                }
                break;

            case 28: //G28 Home all Axis one at a time
                stepper_move(0, 0);
                xoff = 0;
                yoff = 0;
                break;

            case 90: // G90
                relative_mode = false;
                break;

            case 91: // G91
                relative_mode = true;
                break;

            case 92: // G92 set coords
                if (code_seen('X')) {
                    xoff = -xpos + code_value();
                    xpos = 0;
                } else {
                    xoff = -xpos;
                    xpos = 0;
                }
                if (code_seen('Y')) {
                    yoff = -ypos + code_value();
                    ypos = 0;
                } else {
                    yoff = -ypos;
                    ypos = 0;
                }
                break;
        }
    } else
        if (code_seen('M')) {
        switch ((int) code_value()) {
            case 80://power on
                break;

            case 106://load paper
                stepper_load_paper();
                break;

            case 107://unload paper
                stepper_unload_paper();
                break;

            case 300://S30=down S50=up S255=off
                if (code_seen('S')) {
                    penup = code_value() > 40;
                }
                break;
        }
    }//M
    else {
        printf("Error:unknown commando\n");
    }

}
Exemple #7
0
 void Planner::autotemp_M109() {
   autotemp_enabled = code_seen('F');
   if (autotemp_enabled) autotemp_factor = code_value();
   if (code_seen('S')) autotemp_min = code_value();
   if (code_seen('B')) autotemp_max = code_value();
 }
void process_commands() {
    unsigned long codenum; //throw away variable

    if (code_seen('N')) {
        gcode_N = code_value_long();
        if (gcode_N != gcode_LastN+1 && (strstr(cmdbuffer, "M110") == NULL) ) {
            gcode_LastN=0;
            pc.printf("ok");
            //if(gcode_N != gcode_LastN+1 && !code_seen("M110") ) {   //Hmm, compile size is different between using this vs the line above even though it should be the same thing. Keeping old method.
            //pc.printf("Serial Error: Line Number is not Last Line Number+1, Last Line:");
            //pc.printf("%d\n",gcode_LastN);
            //FlushSerialRequestResend();
            return;
        }

        if (code_seen('*')) {
            int checksum = 0;
            int count=0;
            while (cmdbuffer[count] != '*') checksum = checksum^cmdbuffer[count++];

            if ( (int)code_value() != checksum) {
                //pc.printf("Error: checksum mismatch, Last Line:");
                //pc.printf("%d\n",gcode_LastN);
                //FlushSerialRequestResend();
                return;
            }
            //if no errors, continue parsing
        } else {
            //pc.printf("Error: No Checksum with line number, Last Line:");
            //pc.printf("%d\n",gcode_LastN);
            //FlushSerialRequestResend();
            return;
        }

        gcode_LastN = gcode_N;
        //if no errors, continue parsing
    } else { // if we don't receive 'N' but still see '*'
        if (code_seen('*')) {
            //pc.printf("Error: No Line Number with checksum, Last Line:");
            //pc.printf("%d\n",gcode_LastN);
            return;
        }
    }

    //continues parsing only if we don't receive any 'N' or '*' or no errors if we do. :)

    if (code_seen('G')) {
        switch ((int)code_value()) {
            case 0: // G0 -> G1
            case 1: // G1
                reset_timers();//avoid timer overflow after 30 seconds
                get_coordinates(); // For X Y Z E F
                x_steps_to_take = abs(destination_x - current_x)*x_steps_per_unit;
                y_steps_to_take = abs(destination_y - current_y)*y_steps_per_unit;
                z_steps_to_take = abs(destination_z - current_z)*z_steps_per_unit;
                e_steps_to_take = abs(destination_e - current_e)*e_steps_per_unit;
                //printf(" x_steps_to_take:%d\n", x_steps_to_take);


                time_for_move = max(X_TIME_FOR_MOVE,Y_TIME_FOR_MOVE);
                time_for_move = max(time_for_move,Z_TIME_FOR_MOVE);
                time_for_move = max(time_for_move,E_TIME_FOR_MOVE);

                if (x_steps_to_take) x_interval = time_for_move/x_steps_to_take;
                if (y_steps_to_take) y_interval = time_for_move/y_steps_to_take;
                if (z_steps_to_take) z_interval = time_for_move/z_steps_to_take;
                if (e_steps_to_take) e_interval = time_for_move/e_steps_to_take;


                x_steps_remaining = x_steps_to_take;
                y_steps_remaining = y_steps_to_take;
                z_steps_remaining = z_steps_to_take;
                e_steps_remaining = e_steps_to_take;


                if (DEBUGGING) {
                    pc.printf("destination_x: %f\n",destination_x);
                    pc.printf("current_x: %f\n",current_x);
                    pc.printf("x_steps_to_take: %d\n",x_steps_to_take);
                    pc.printf("X_TIME_FOR_MOVE: %f\n",X_TIME_FOR_MOVE);
                    pc.printf("x_interval: %f\n\n",x_interval);

                    pc.printf("destination_y: %f\n",destination_y);
                    pc.printf("current_y: %f\n",current_y);
                    pc.printf("y_steps_to_take: %d\n",y_steps_to_take);
                    pc.printf("Y_TIME_FOR_MOVE: %f\n",Y_TIME_FOR_MOVE);
                    pc.printf("y_interval: %f\n\n",y_interval);

                    pc.printf("destination_z: %f\n",destination_z);
                    pc.printf("current_z: %f\n",current_z);
                    pc.printf("z_steps_to_take: %d\n",z_steps_to_take);
                    pc.printf("Z_TIME_FOR_MOVE: %f\n",Z_TIME_FOR_MOVE);
                    pc.printf("z_interval: %f\n\n",z_interval);

                    pc.printf("destination_e: %f\n",destination_e);
                    pc.printf("current_e: %f\n",current_e);
                    pc.printf("e_steps_to_take: %d\n",e_steps_to_take);
                    pc.printf("E_TIME_FOR_MOVE: %f\n",E_TIME_FOR_MOVE);
                    pc.printf("e_interval: %f\n\n",e_interval);
                }

                linear_move(); // make the move
                ClearToSend();
                return;
            case 4: // G4 dwell
                codenum = 0;
                if (code_seen('P')) codenum = code_value(); // milliseconds to wait
                if (code_seen('S')) codenum = code_value()*1000; // seconds to wait
                previous_millis_heater = millis();  // keep track of when we started waiting
                while ((millis() - previous_millis_heater) < codenum ) manage_heater(); //manage heater until time is up
                break;
            case 90: // G90
                relative_mode = false;
                break;
            case 91: // G91
                relative_mode = true;
                break;
            case 92: // G92
                if (code_seen('X')) current_x = code_value();
                if (code_seen('Y')) current_y = code_value();
                if (code_seen('Z')) current_z = code_value();
                if (code_seen('E')) current_e = code_value();
                break;
           case 93: // G93
                pc.printf("previous_micros:%d\n", previous_micros);
                pc.printf("previous_micros_x:%d\n", previous_micros_x);
                pc.printf("previous_micros_y:%d\n", previous_micros_y);
                pc.printf("previous_micros_z:%d\n", previous_micros_z);
                break;

        }
    }

    if (code_seen('M')) {

        switch ( (int)code_value() ) {
            case 104: // M104 - set hot-end temp
                
                if (code_seen('S'))
                {
                     
                    target_raw = temp2analog(code_value());
                    //pc.printf("target_raw: %d\n ", target_raw);
                }
                break;
        case 140: // M140 - set heated-printbed temp
                if (code_seen('S'))
                {
                     
                    target_raw1 = temp2analog(code_value());
                    //pc.printf("target_raw1: %d\n ", target_raw);
                }
                break;                
                
            case 105: // M105
                pc.printf("ok T:");
                if (TEMP_0_PIN != NC) {
                    pc.printf("%f\n", analog2temp( (p_temp0.read_u16())  ));
                } else {
                    pc.printf("0.0\n");
                }
                if (!code_seen('N')) return; // If M105 is sent from generated gcode, then it needs a response.
                break;
            case 109: // M109 - Wait for heater to reach target.
                if (code_seen('S')) target_raw = temp2analog(code_value());
                previous_millis_heater = millis();
                while (current_raw < target_raw) {
                    if ( (millis()-previous_millis_heater) > 1000 ) { //Print Temp Reading every 1 second while heating up.
                        pc.printf("ok T:");
                        if (TEMP_0_PIN != NC) {
                            pc.printf("%f\n", analog2temp(p_temp0.read_u16()));
                        } else {
                            pc.printf("0.0\n");
                        }
                        previous_millis_heater = millis();
                    }
                    manage_heater();
                }
                break;
            case 106: //M106 Fan On
                p_fan = 1;
                break;
            case 107: //M107 Fan Off
                p_fan = 0;
                break;
            case 80: // M81 - ATX Power On
                //if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,OUTPUT); //GND
                break;
            case 81: // M81 - ATX Power Off
                //if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); //Floating
                break;
            case 82:
                relative_mode_e = false;
                break;
            case 83:
                relative_mode_e = true;
                break;
            case 84:
                disable_x();
                disable_y();
                disable_z();
                disable_e();
                break;
            case 85: // M85
                code_seen('S');
                max_inactive_time = code_value()*1000;
                break;
            case 86: // M86 If Endstop is Not Activated then Abort Print
                if (code_seen('X')) {
                    if (X_MIN_PIN != NC) {
                        if ( p_X_min == ENDSTOPS_INVERTING ) {
                            kill(3);
                        }
                    }
                }
                if (code_seen('Y')) {
                    if (Y_MIN_PIN != NC) {
                        if ( p_Y_min == ENDSTOPS_INVERTING ) {
                            kill(4);
                        }
                    }
                }
                break;
            case 92: // M92
                if (code_seen('X')) x_steps_per_unit = code_value();
                if (code_seen('Y')) y_steps_per_unit = code_value();
                if (code_seen('Z')) z_steps_per_unit = code_value();
                if (code_seen('E')) e_steps_per_unit = code_value();
                break;
        }

    }

    ClearToSend();
}
/*----------------------------------------
*
* Start the massive Gcode processing loop
*-----------------------------------------
*/
void process_commands()
{
  int result;
  int motorChannel, motorPower;
  unsigned long codenum;
  char *starpos = NULL;
  
  if(code_seen('G'))
  {
    switch((int)code_value())
    {
    case 0: // G0 -> G1
    case 1: // G1
      break;
	  
    case 2:
	  break;
	  
    case 3:
	  break;
	  
    case 4: // G4 dwell
      //LCD_MESSAGEPGM(MSG_DWELL);
      codenum = 0;
      if(code_seen('P')) codenum = code_value(); // milliseconds to wait
      if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait

      //codenum += millis();  // keep track of when we started waiting
      previous_millis_cmd = 0;//millis();
      while(++previous_millis_cmd  < codenum ){
        manage_inactivity();
		_delay_ms(1);
      }
      break;
	  
	case 5: // G5 - Absolute command motor C<Channel> P<motor power -1000 to 1000>
	     if(!Stopped) {
		     if(code_seen('C')) {
				motorChannel = code_value(); // motor channel 1,2
				if(code_seen('P')) {
					motorPower = code_value(); // motor power -1000,1000
					fault = 0; // clear fault flag
					motorControl->commandMotorPower(motorChannel, motorPower);
				} // code P
			 } // code C
	     } // stopped
	     break;
		 
    case 28:
      previous_millis_cmd = 0;
      break;
	  
    case 90: // G90
      break;
	  
    case 91: // G91
      break;
	  
    case 92: // G92
      break;
	  
	case 99: // G99 start watchdog timer. G99 T<time_in_millis> values are 15,30,60,120,250,500,1000,4000,8000 default 4000
		if( code_seen('T') ) {
			int time_val = code_value();
			watchdog_timer = new WatchdogTimer();
			watchdog_timer->watchdog_init(time_val);
		}
		break;
		
	case 100: // G100 reset watchog timer before time interval is expired, otherwise a reset occurs
		if( watchdog_timer != NULL )
			watchdog_timer->watchdog_reset();
		break;
		
    } // switch
  } // if code
  /*-------------------------------------
  * M Code processing
  *--------------------------------------
  */
  else if(code_seen('M'))
  {
    switch( (int)code_value() )
    {
	case 0: // M0 Set real time output off
		realtime_output = 0;
		break;
		
	case 1: // M1 Set real time output on
		realtime_output = 1;
		break;
		
	case 2: // M2 [C<channel> E<encoder pin>] set smart controller (default) with optional encoder pin per channel
		motor_status = 0;
		motorControl = &roboteqDevice;
		if(code_seen('C')) {
			channel = code_value();
			if(code_seen('E')) {
				pin_number = code_value();
				motorControl->createEncoder(channel, pin_number);
			}
		}
		break;
		
	//Set PWM motor driver, map pin to channel, this will check to prevent free running motors during inactivity
	//For a PWM motor control subsequent G5 commands are affected here. 	
	case 3: // M3 P<pin> C<channel> D<direction pin> E<default dir> W<encoder pin> [T<timer mode 0-3>] [R<resolution 8,9,10 bits>] [X<prescale 0-7>]
	  motor_status = 1;
	  pin_number = -1;
	  encode_pin = 0;
	  motorControl = (AbstractMotorControl*)&hBridgeDriver;
	  ((HBridgeDriver*)motorControl)->setMotors((PWM**)&ppwms);
	  ((HBridgeDriver*)motorControl)->setDirectionPins((Digital**)&pdigitals);
	  if(code_seen('P'))
          pin_number = code_value();
	  else
		 break;
      if(code_seen('C')) {
        channel = code_value();
		if( code_seen('D'))
			dir_pin = code_value();
		else 
			break;
		if( code_seen('E'))
			dir_default = code_value();
		else
			break;
		if( code_seen('W')) 
			encode_pin = code_value(); 
		((HBridgeDriver*)motorControl)->createPWM(channel, pin_number, dir_pin, dir_default, timer_pre, timer_res);
		if(encode_pin)
			motorControl->createEncoder(channel, encode_pin);
      } // code C
	  break;
	
	case 4:
		// BLDC motor
		// BLDC: lo1,lo2,lo3,hi1,hi2,hi3,hall1,hall2,hall3,enable
		// hall sensors hall1:bit0,hall2:bit1,hall2:bit2 of commu array offset
		// BLDC3PhaseSensor* tmotor1 = new BLDC3PhaseSensor(29,31,33,8,9,10,64,65,66);
		// tmotor2 = new BLDC3PhaseSensor(35,37,39,11,12,13,67,68,69,30);
		// tmotor1->motor_init();
		// tmotor2->Motor_init();
		break;
		
	case 11: // M11 C<channel> D<duration> Set maximum motor cycle duration for given channel.
		if( code_seen('C') ) {
			channel = code_value();
			if( code_seen('D') )
				motorControl->setDuration(channel, code_value());
		}
	break;
	
	case 12: // M12 C<channel> P<offset> set amount to add to G5 for min motor power
		if( code_seen('C') ) {
			channel = code_value();
			if( code_seen('P'))
				motorControl->setMinMotorPower(channel, code_value());
		}
		break;
			 	
    case 17:
      break;
	  
	case 18: //M18
	  break;
	  
	case 31: //M31 take time since the start of the SD print or an M109 command
      stoptime=0;//millis();
      char time[30];
      t =(stoptime-starttime)/1000;
      int sec,min;
      min=t/60;
      sec=t%60;
      sprintf_P(time, PSTR("%i min, %i sec"), min, sec);
      SERIAL_PGMLN(timeCntrlHdr);
	  SERIAL_PGM("1 ");
      SERIAL_PORT.println(time);
	  SERIAL_PORT.flush();
      //lcd_setstatus(time);
      //autotempShutdown();
      break;
	  
	case 33: // M33 P<ultrasonic pin> D<min. distance in cm> [E<direction 1- forward facing, 0 - reverse facing sensor>] 
	// link Motor controller to ultrasonic sensor, the sensor must exist via M301
	  motor_status = 1;
	  pin_number = 0;
	  if(code_seen('P')) {
        pin_number = code_value();
		if( code_seen('D'))
			dist = code_value();
		else 
			break;
		dir_face = 1; // default forward
		if( code_seen('E'))
			dir_face = code_value(); // optional
		motorControl->linkDistanceSensor((Ultrasonic**)psonics, pin_number, dist, dir_face);
	  } // code_seen = 'P'
	  break;
	  
	  case 35: //M35 - Clear all digital pins
		for(int i = 0; i < 10; i++) {
			 if(pdigitals[i]) {
				unassignPin(pdigitals[i]->pin);
				delete pdigitals[i];
				pdigitals[i] = 0;
			 }
		}
	  break;
		  
	  case 36: //M36 - Clear all analog pins
		  	 for(int i = 0; i < 10; i++) {
			  	  if(panalogs[i]) {
					unassignPin(panalogs[i]->pin);
				  	delete panalogs[i];
					panalogs[i] = 0;
			  	  }
		  	 }
	  break;
	  
	  case 37: //M36 - Clear all PWM pins
	  for(int i = 0; i < 10; i++) {
		  if(ppwms[i]) {
			  unassignPin(ppwms[i]->pin);
			  delete ppwms[i];
			  ppwms[i] = 0;
		  }
	  }
	  break;
	  
	  case 38: //M38 - Remove PWM pin P<pin>
	  	  pin_number = -1;
	  	  if (code_seen('P')) {
		  	  pin_number = code_value();
		  	  if(unassignPin(pin_number) ) {
			  	  for(int i = 0; i < 10; i++) {
				  	  if(ppwms[i] && ppwms[i]->pin == pin_number) {
					  	  delete ppwms[i];
						  ppwms[i] = 0;
				  	  } // pwms == pin_number
			  	  } // i iterate pwm array
		  	  } // unassign pin
	  	  } // code P
	  break;
	  
	  case 39: //M39 - Remove Persistent Analog pin P<pin>
	  	  pin_number = -1;
	  	  if (code_seen('P')) {
		  	  pin_number = code_value();
		  	  if(unassignPin(pin_number) ) {
			  	  for(int i = 0; i < 10; i++) {
				  	  if(panalogs[i] && panalogs[i]->pin == pin_number) {
					  	delete panalogs[i];
						panalogs[i] = 0;
					    break;
				  	  }
			  	  }
		  	  }
	  	  }
	  break;
			
	  case 40: //M40 - Remove persistent digital pin P<pin>
	       pin_number = -1;
	       if (code_seen('P')) {
		       pin_number = code_value();
		       if(unassignPin(pin_number) ) {
			       for(int i = 0; i < 10; i++) {
				       if(pdigitals[i] && pdigitals[i] == pin_number) {
					       delete pdigitals[i];
						   pdigitals[i] = 0;
					       break;
				       }
			       }
			   }
		   }
	  break;
		
	  case 41: //M41 - Create persistent digital pin, Write digital pin HIGH P<pin> (this gives you a 5v source on pin)
	     pin_number = -1;
	     if (code_seen('P')) {
		     pin_number = code_value();
		     if( assignPin(pin_number) ) {
			     dpin = new Digital(pin_number);
				 dpin->setPin(pin_number);
			     dpin->pinMode(OUTPUT);
			     dpin->digitalWrite(HIGH);
			     for(int i = 0; i < 10; i++) {
				     if(!pdigitals[i]) {
					     pdigitals[i] = dpin;
					     break;
				     }
			     }
			 } else {
			     for(int i = 0; i < 10; i++) {
				     if(pdigitals[i] && pdigitals[i]->pin == pin_number) {
						 pdigitals[i]->setPin(pin_number);
						 pdigitals[i]->pinMode(OUTPUT);
					     pdigitals[i]->digitalWrite(HIGH);
					     break;
				     }
			     }
		     }
	     }
	break;
	     
    case 42: //M42 - Create persistent digital pin, Write digital pin LOW P<pin> (This gives you a grounded pin)
	  pin_number = -1;
	  if (code_seen('P')) {
        pin_number = code_value();
		if( assignPin(pin_number) ) {
			dpin = new Digital(pin_number);
			dpin->pinMode(OUTPUT);
			dpin->digitalWrite(LOW);
			for(int i = 0; i < 10; i++) {
				if(!pdigitals[i]) {
					pdigitals[i] = dpin;
					break;
				}
			}
		} else {
			for(int i = 0; i < 10; i++) {
				if(pdigitals[i] && pdigitals[i]->pin == pin_number) {
					pdigitals[i]->setPin(pin_number);
					pdigitals[i]->pinMode(OUTPUT);
					pdigitals[i]->digitalWrite(LOW);
					break;
				}
			}
		}
	  }
     break;
	 
	case 43: // M43 Read from digital pin P<pin>
        pin_number = -1;
        if (code_seen('P'))
          pin_number = code_value();
   		if( assignPin(pin_number) ) {
			dpin = new Digital(pin_number);
			dpin->pinMode(INPUT);
			int res = dpin->digitalRead();
			delete &dpin;
			unassignPin(pin_number); // reset it since this is a one-shot
			SERIAL_PGMLN(digitalPinHdr);
			SERIAL_PGM("1 ");
			SERIAL_PORT.println(pin_number);
			SERIAL_PGM("2 ");
			SERIAL_PORT.println(res);
			SERIAL_PORT.println();
			SERIAL_PORT.flush();
		}
		break;
	
	case 44: // M44 -Read digital pin with pullup P<pin>
        pin_number = -1;
        if (code_seen('P'))
          pin_number = code_value();
    	if( assignPin(pin_number) ) {
			dpin = new Digital(pin_number);
			dpin->pinMode(INPUT_PULLUP);
			int res = dpin->digitalRead();
			delete &dpin;
			unassignPin(pin_number); // reset it since this is a one-shot
			SERIAL_PGMLN(digitalPinHdr);
			SERIAL_PGM("1 ");
			SERIAL_PORT.println(pin_number);
			SERIAL_PGM("2 ");
			SERIAL_PORT.println(res);
			SERIAL_PORT.flush();
		}
		break;
		
	 // PWM value between 0 and 255, default timer mode is 2; clear on match, default resolution is 8 bits, default prescale is 1
	 // Prescale: 1,2,4,6,7,8,9 = none, 8, 64, 256, 1024, external falling, external rising
	 // Use M445 to disable pin permanently or use timer more 0 to stop pulse without removing pin assignment
     case 45: // M45 - set up PWM P<pin> S<power val 0-255> [T<timer mode 0-3>] [R<resolution 8,9,10 bits>] [X<prescale 0-7>]
	  pin_number = -1;
	  if(code_seen('P') )
          pin_number = code_value();
	  else
		 break;
      if (code_seen('S')) {
        int pin_status = code_value();
		int timer_mode = 2;
		int timer_res = 8;
		int timer_pre = 1;
		
		if( pin_status < 0 || pin_status > 255)
			pin_status = 0;
		// this is a semi-permanent pin assignment so dont add if its already assigned
		if( assignPin(pin_number) ) {
			// timer mode 0-3: 0 stop, 1 toggle on compare match, 2 clear on match, 3 set on match (see HardwareTimer)
			if( code_seen('T') ) {
				timer_mode = code_value();
				if( timer_mode < 0 || timer_mode > 3 )
					timer_mode = 0;
			}
			// timer bit resolution 8,9, or 10 bits
			if( code_seen('R')) {
				timer_res = code_value();
				if( timer_res < 8 || timer_res > 10 )
					timer_res = 8;
			}
			// X - prescale 0-7 for power of 2
			if( code_seen('X') ) {
				timer_pre = code_value();
				if( timer_pre < 0 || timer_pre > 7 )
					timer_pre = 0;
			}
			for(int i = 0; i < 10; i++) {
				if(ppwms[i] == NULL) {
					ppin = new PWM(pin_number);
					ppin->init(pin_number);
					ppin->setPWMPrescale(timer_pre);
					ppin->setPWMResolution(timer_res);
					ppin->pwmWrite(pin_status,timer_mode); // default is 2, clear on match. to turn off, use 0
					ppwms[i] = ppin;
					break;
				}
			}
		 } else { // reassign pin with new mode and value
			 for(int i = 0; i < 10; i++) {
				 if(ppwms[i] && ppwms[i]->pin == pin_number) {
					 // timer mode 0-3: 0 stop, 1 toggle on compare match, 2 clear on match, 3 set on match (see HardwareTimer)
					 if( code_seen('T') ) {
						 timer_mode = code_value();
						 if( timer_mode < 0 || timer_mode > 3 )
							timer_mode = 2; // mess up the code get clear on match default
					 }
					 //ppwms[i]->init();
					 ppwms[i]->pwmWrite(pin_status, timer_mode);
					 break;
				 }
			 }
		 }
      }
	  break;
	  
	  case 46: // M46 -Read analog pin P<pin>
        pin_number = -1;
        if (code_seen('P'))
          pin_number = code_value();
		if( assignPin(pin_number) ) {
			apin = new Analog(pin_number);
			int res = apin->analogRead();
			res = apin->analogRead(); // de-jitter
			delete &apin;
			unassignPin(pin_number);
			SERIAL_PGMLN(analogPinHdr);
			SERIAL_PGM("1 ");
			SERIAL_PORT.println(pin_number);
			SERIAL_PGM("2 ");
			SERIAL_PORT.println(res);
			SERIAL_PORT.flush();
		}
     break;
	 
     case 80: // M80 - Turn on Power Supply
	  #if defined(PS_ON_PIN) && PS_ON_PIN > -1
        SET_OUTPUT(PS_ON_PIN); //GND
        WRITE(PS_ON_PIN, PS_ON_AWAKE);
        // If you have a switch on suicide pin, this is useful
        #if defined(SUICIDE_PIN) && SUICIDE_PIN > -1
            SET_OUTPUT(SUICIDE_PIN);
            WRITE(SUICIDE_PIN, HIGH);
        #endif
      #endif
	  break;

     case 81: // M81 - Turn off Power
      if( motorControl->isConnected())
		motorControl->commandEmergencyStop();
      #if defined(SUICIDE_PIN) && SUICIDE_PIN > -1
        suicide();
      #elif defined(PS_ON_PIN) && PS_ON_PIN > -1
        SET_OUTPUT(PS_ON_PIN);
        WRITE(PS_ON_PIN, PS_ON_ASLEEP);
      #endif
	    _delay_ms(1000); // Wait 1 sec before switch off
	  break;

    case 82:
      break;
	  
    case 83:
      break;
	  
    case 84: // M84
      break;
	  
    case 85: // M85
      break;
	  
    case 92: // M92
      break;
	  
	case 104: // M104
      break;
	  
    case 105 : // M105
      SERIAL_PORT.println();
      break; 
	   
    case 106: //M106
        break;
		
    case 107: //M107
        break;
	
    case 109: // M109 
      break;
	  
    case 115: // M115
      SERIAL_PGMLN(MSG_M115_REPORT);
      break;
	  
    case 117: 
      break;
	  
    case 114: // M114
      break;
	  
    case 120: // M120
      break;
	  
    case 121: // M121
      break;
	  
    case 119: // M119
      break; 
	  
	case 140: // M140 
      break;
	  
    case 150: // M150 - set an RGB value
        byte red;
        byte grn;
        byte blu;
        if(code_seen('R')) red = code_value();
        if(code_seen('U')) grn = code_value();
        if(code_seen('B')) blu = code_value();
        //SendColors(red,grn,blu);
      break;
	  
	case 190: // M190
      break;
	  
    case 200:
      break;
	  
    case 201: // M201
      //reset_acceleration_rates();
      break;
	  
    case 202: // M202
      break;
	  
    case 203:
      break;
	  
    case 204: // M204 acceleration T
      if(code_seen('T')) ;//max_acceleration = code_value();
      break;
	  
    case 205: //M205 advanced settings:  maximum travel speed T=travel
      if(code_seen('T')) ;//maxtravelspeed = code_value();
	  break;
	
    case 206: 
      break;
	  
    case 207:
	  break;
	  
    case 208:
      break;
	  
    case 209: 
	  break;
	  
    case 218:
	  break;
	  
    case 220: 
      if(code_seen('S'))
      {
        
      }
    break;
	
    case 221: 
      if(code_seen('S'))
      {
        
      }
    break;

	case 226: // M226 P<pin number> S<pin state>- Wait until the specified pin reaches the state required, default is opposite current state
      if(code_seen('P')) {
        int pin_number = code_value(); // pin number
        int pin_state = -1; // required pin state - default is inverted
        if(code_seen('S')) 
			pin_state = code_value(); // required pin state
		if( assignPin(pin_number) ) {
			Digital pn = new Digital(pin_number);
            pn.pinMode(INPUT);
            int target;
            switch(pin_state){
				case 1:
					target = HIGH;
					break;
				case 0:
					target = LOW;
					break;
				default:
					target = !pn.digitalRead(); // opposite of current state
					break;
            } // switch
            while(pn.digitalRead() != target) {
              manage_inactivity();
            } // while
			delete &pn;
			unassignPin(pin_number);
          } // if pin_number
      } // code seen p
    break;

	case 227: // M227 P<pin number> S<pin state>- INPUT_PULLUP Wait until the specified pin reaches the state required, default is opposite current state
	if(code_seen('P')) {
		int pin_number = code_value(); // pin number
		int pin_state = -1; // required pin state - default is inverted
		if(code_seen('S'))
		pin_state = code_value(); // required pin state
		if( assignPin(pin_number) ) {
			Digital pn = new Digital(pin_number);
			pn.pinMode(INPUT_PULLUP);
			int target;
			switch(pin_state){
				case 1:
				target = HIGH;
				break;
				case 0:
				target = LOW;
				break;
				default:
				target = !pn.digitalRead(); // opposite of current state
				break;
			} // switch
			while(pn.digitalRead() != target) {
				manage_inactivity();
			} // while
			delete &pn;
			unassignPin(pin_number);
		} // if pin_number
	} // code seen p
	break;
		
	case 240: // M240  Triggers a camera by emulating a Canon RC-1 : http://www.doc-diy.net/photo/rc-1_hacked/
	/*
      #if defined(PHOTOGRAPH_PIN) && PHOTOGRAPH_PIN > -1
        const uint8_t NUM_PULSES=16;
        const float PULSE_LENGTH=0.01524;
        for(int i=0; i < NUM_PULSES; i++) {
          WRITE(PHOTOGRAPH_PIN, HIGH);
          _delay_ms(PULSE_LENGTH);
          WRITE(PHOTOGRAPH_PIN, LOW);
          _delay_ms(PULSE_LENGTH);
        }
        delay(7.33);
        for(int i=0; i < NUM_PULSES; i++) {
          WRITE(PHOTOGRAPH_PIN, HIGH);
          _delay_ms(PULSE_LENGTH);
          WRITE(PHOTOGRAPH_PIN, LOW);
          _delay_ms(PULSE_LENGTH);
        }
      #endif
	  */
    break;
	
	case 250: 
      break;
	
    case 280: 
      break;

    case 300: // M300 - emit ultrasonic pulse on given pin and return duration P<pin number>
      uspin = code_seen('P') ? code_value() : 0;
      if (uspin > 0) {
		Ultrasonic* upin = new Ultrasonic(uspin);
		pin_number = upin->getPin();
		SERIAL_PGMLN(sonicCntrlHdr);
		SERIAL_PGM("1 "); // pin
		SERIAL_PORT.println(pin_number);
		SERIAL_PGM("2 "); // sequence
		SERIAL_PORT.println(upin->getRange()); // range
		delete upin;
      }
    break;
		
    case 301: // M301 - toggle ultrasonic during inactivity P<pin>
		// wont assign pin 0 as its sensitive
		uspin = code_seen('P') ? code_value() : 0;
		// this is a permanent pin assignment so dont add if its already assigned
		if( assignPin(uspin) ) {
			for(int i = 0; i < 10; i++) {
				if(!psonics[i]) {
					psonics[i] = new Ultrasonic(uspin);
					break;
				}
			}
		}
		break;
	
	case 302: // M302 - disable ultrasonic during inactivity P<pin>
		uspin = code_seen('P') ? code_value() : 0;
		unassignPin(uspin);
		for(int i = 0; i < 10; i++) {
				if(psonics[i] && psonics[i] == uspin) {
					delete psonics[i];
					psonics[i] = 0;
					break;
				}
		}
      break;
	
	case 303: // M303 - toggle analog read during inactivity P<pin> with exclusion range 0-1024 via L<min> H<max> if present
		// wont assign pin 0 as its sensitive
		// if optional L and H values exclude readings in that range
		uspin = code_seen('P') ? code_value() : 0;
		// this is a permanent pin assignment so dont add if its already assigned
		if( assignPin(uspin) ) {
			for(int i = 0; i < 10; i++) {
				if(!panalogs[i]) {
					analogRanges[0][i] = code_seen('L') ? code_value() : 0;
					analogRanges[1][i] = code_seen('H') ? code_value() : 0;
					panalogs[i] = new Analog(uspin);
					panalogs[i]->pinMode(INPUT);
					break;
				}
			}
		} else { // reassign values for assigned pin
			for(int i = 0; i < 10; i++) {
				if(panalogs[i] && panalogs[i]->pin == uspin) {
					analogRanges[0][i] = code_seen('L') ? code_value() : 0;
					analogRanges[1][i] = code_seen('H') ? code_value() : 0;
					break;
				}
			}
		}
      break;
	  
	case 304:// M304 - toggle analog read INPUT_PULLUP during inactivity P<pin> with exclusion range 0-1024 via L<min> H<max> if present
		// if optional L and H values exclude readings in that range
		uspin = code_seen('P') ? code_value() : 0;
		// this is a permanent pin assignment so dont add if its already assigned
		if( assignPin(uspin) ) {
			for(int i = 0; i < 10; i++) {
				if(!panalogs[i]) {
					analogRanges[0][i] = code_seen('L') ? code_value() : 0;
					analogRanges[1][i] = code_seen('H') ? code_value() : 0;
					panalogs[i] = new Analog(uspin);
					panalogs[i]->pinMode(INPUT_PULLUP);
					break;
				}
			}
		} else { // reassign values for assigned pin
			for(int i = 0; i < 10; i++) {
				if(panalogs[i] && panalogs[i]->pin == uspin) {
					analogRanges[0][i] = code_seen('L') ? code_value() : 0;
					analogRanges[1][i] = code_seen('H') ? code_value() : 0;
					break;
				}
			}
		}
      break;
	
	case 305: // M305 - toggle digital read during inactivity M305 P<pin> T<target> 0 or 1 for target value, default 0
		// wont assign pin 0 as its sensitive
		// Looks for target value for pin during inactive, if so publish with <digitalpin> header and 1 - pin, 2 - value
		uspin = code_seen('P') ? code_value() : 0;
		digitarg = code_seen('T') ? code_value() : 0;
		// this is a permanent pin assignment so dont add if its already assigned
		if( assignPin(uspin) ) {
			for(int i = 0; i < 10; i++) {
				if(!pdigitals[i]) {
					pdigitals[i] = new Digital(uspin);
					pdigitals[i]->pinMode(INPUT);
					digitalTarget[i] = digitarg;
					break;
				}
			}
		} else {
			for(int i = 0; i < 10; i++) {
				if(pdigitals[i] && pdigitals[i]->pin == uspin) {
					digitalTarget[i] = digitarg;
					break;
				}
			}
		}
      break;
	
	case 306:// M306 - INPUT_PULLUP toggle digital read during inactivity M306 P<pin> T<target> 0 or 1 for target value, default 0
		// Looks for target value for pin during inactive, if so publish with <digitalpin> header and 1 - pin 2 - value
		uspin = code_seen('P') ? code_value() : 0;
		digitarg = code_seen('T') ? code_value() : 0;
		// this is a permanent pin assignment so dont add if its already assigned
		if( assignPin(uspin) ) {
			for(int i = 0; i < 10; i++) {
				if(!pdigitals[i]) {
					pdigitals[i] = new Digital(uspin);
					pdigitals[i]->pinMode(INPUT_PULLUP);
					digitalTarget[i] = digitarg;
					break;
				}
			}
		} else {
			for(int i = 0; i < 10; i++) {
				if(pdigitals[i] && pdigitals[i]->pin == uspin) {
					digitalTarget[i] = digitarg;
					break;
				}
			}
		}
		break;
	
    case 349: // M349
	/*
        if(code_seen('P')) bedKp = code_value();
        if(code_seen('I')) bedKi = scalePID_i(code_value());
        if(code_seen('D')) bedKd = scalePID_d(code_value());

        updatePID();
        SERIAL_PROTOCOL(MSG_OK);
        SERIAL_PROTOCOL(" p:");
        SERIAL_PROTOCOL(bedKp);
        SERIAL_PROTOCOL(" i:");
        SERIAL_PROTOCOL(unscalePID_i(bedKi));
        SERIAL_PROTOCOL(" d:");
        SERIAL_PROTOCOL(unscalePID_d(bedKd));
        SERIAL_PROTOCOLLN("");
		*/
      break;
	  
   case 350:
    break;
	
   case 351: 
      break;
	  
    case 400:
      
    break;
	
    case 401:
        
    break;
	
    case 402:
        
    break;
	
	case 444: // M444 - set battery warning threshold V<volts*10>!!!!!!!!!!!!!!!!!! REMEMBER ITS TIMES 10 !!!!!!!!!!!!!!!!!!
	    if(code_seen('V')) {
			BatteryThreshold = code_value(); // times 10!!!
		}
		break;
		
	case 445: // M445 - Turn off pulsed write pin - disable PWM P<pin>
      pin_number = -1;
      if (code_seen('P'))
          pin_number = code_value();
	  unassignPin(pin_number);
	  for(int i = 0; i < 10; i++) {
			if(ppwms[i] && ppwms[i] == pin_number) {
				ppwms[i]->pwmWrite(0,0); // default is 2, clear on match. to turn off, use 0 
				delete ppwms[i];
				ppwms[i] = 0;
				break;
			}
	  }
	  break;
	  
    case 500: // M500 Store settings in EEPROM
        Config_StoreSettings();
    break;
	
    case 501: // M501 Read settings from EEPROM
        Config_RetrieveSettings();
    break;
	
    case 502: // M502 Revert to default settings
        Config_ResetDefault();
    break;
	
    case 503: // M503 print settings currently in memory
        Config_PrintSettings();
    break;
	
    case 540:
        //if(code_seen('S')) abort_on_endstop_hit = code_value() > 0;
    break;
	
    case 600: 
    break;
	
    case 605: 
    break;
	
	case 666:
    break;
	  
	case 700: // return stats
	  // Check startup - does nothing if bootloader sets MCUSR to 0
	  mcu = MCUSR;
	  if(mcu & 1) SERIAL_PGMLN(MSG_POWERUP);
	  if(mcu & 2) SERIAL_PGMLN(MSG_EXTERNAL_RESET);
	  if(mcu & 4) SERIAL_PGMLN(MSG_BROWNOUT_RESET);
	  if(mcu & 8) SERIAL_PGMLN(MSG_WATCHDOG_RESET);
	  if(mcu & 32) SERIAL_PGMLN(MSG_SOFTWARE_RESET);
	  MCUSR=0;
	  SERIAL_PGM(VERSION_STRING);
	  #ifdef STRING_VERSION_CONFIG_H
	  #ifdef STRING_CONFIG_H_AUTHOR
	  SERIAL_PGM(MSG_CONFIGURATION_VER);
	  SERIAL_PGM(STRING_VERSION_CONFIG_H);
	  SERIAL_PGM(MSG_AUTHOR);
	  SERIAL_PGMLN(STRING_CONFIG_H_AUTHOR);
	  SERIAL_PGM("Compiled: ");
	  SERIAL_PGM(__DATE__);
	  #endif
	  #endif
	  SERIAL_PGM(MSG_FREE_MEMORY);
	  SERIAL_PORT.println(freeMemory());
	  SERIAL_PORT.flush();
	  break; 
	  
	case 701: // Report digital pins in use
		SERIAL_PGMLN("Digital Pins:");
		for(int i = 0; i < 10; i++) {
			if( pdigitals[i] ) {
				SERIAL_PORT.print(pdigitals[i]->pin);
				switch(pdigitals[i]->mode) {
					case INPUT:
						SERIAL_PGMLN(" INPUT");
						break;
					case INPUT_PULLUP:
						SERIAL_PGMLN(" INPUT_PULLUP");
						break;
					case OUTPUT:
						SERIAL_PGMLN(" OUTPUT");
						break;
				}
			}
		}
		SERIAL_PORT.println();
		SERIAL_PORT.flush();
		break;
		
	case 702: // Report analog pins in use
		SERIAL_PGMLN("Analog Pins:");
		for(int i = 0; i < 10; i++) {
			if( panalogs[i]  ) {
				SERIAL_PORT.print(panalogs[i]->pin);
				switch(panalogs[i]->mode) {
					case INPUT:
					SERIAL_PGMLN(" INPUT");
					break;
					case INPUT_PULLUP:
					SERIAL_PGMLN(" INPUT_PULLUP");
					break;
					case OUTPUT:
					SERIAL_PGMLN(" OUTPUT");
					break;
				}
			}
		}
		SERIAL_PORT.println();
		SERIAL_PORT.flush();
		break;
		
	case 703: // Report ultrasonic pins in use
		SERIAL_PGMLN("Ultrasonic Pins:");
		for(int i = 0; i < 10; i++) {
			if( psonics[i] ) {
				SERIAL_PGM("Pin:");
				SERIAL_PORT.println(psonics[i]->getPin());
			}
		}
		SERIAL_PORT.flush();
		break;
		
	case 704: // Report PWM pins in use
		SERIAL_PGMLN("PWM Pins:");
		for(int i = 0; i < 10; i++) {
			if( ppwms[i] ) {
				SERIAL_PGM("Pin:");
				SERIAL_PORT.print(ppwms[i]->pin);
				SERIAL_PGM(" Timer channel:");
				SERIAL_PORT.print(ppwms[i]->channel);
				switch(ppwms[i]->mode) {
					case INPUT:
						SERIAL_PGM(" INPUT");
						break;
					case INPUT_PULLUP:
						SERIAL_PGM(" INPUT_PULLUP");
						break;
					case OUTPUT:
						SERIAL_PGM(" OUTPUT");
						break;
				}
				SERIAL_PORT.println();
			}
			SERIAL_PORT.flush();
		}
		break;
		
	case 705:
			// see if it has propulsion attributes declared with M3 as interrupt serviced
			switch(motor_status) {
				case 0:
					SERIAL_PGMLN("Multi Channel Motor Controller:");
					break;
				case 1:
					SERIAL_PGMLN("H-Bridge Brushed DC Motor Driver(s):");
					break;
				case 2:
					SERIAL_PGMLN("Brushless DC Motor Driver(s):");
					break;
			}
			for(int i = 0 ; i < motorControl->getChannels(); i++) { //per channel
					SERIAL_PGM("Motor channel:");
					SERIAL_PORT.print(i+1);
					SERIAL_PGM(" Min Power:");
					SERIAL_PORT.print(motorControl->getMinMotorPower(i+1));
					SERIAL_PGM(" Speed:");
					SERIAL_PORT.print(motorControl->getMotorSpeed(i+1));
					SERIAL_PGM(" Curr. Dir:");
					SERIAL_PORT.print(motorControl->getCurrentDirection(i+1));
					SERIAL_PGM(" Default. Dir:");
					SERIAL_PORT.println(motorControl->getDefaultDirection(i+1));
					SERIAL_PGM(" Encoder Pin:");
					if(motorControl->getWheelEncoder(i+1)) {
						SERIAL_PORT.print(motorControl->getWheelEncoder(i+1)->pin);
						SERIAL_PGM(" Count:");
						SERIAL_PORT.print(motorControl->getEncoderCount(i+1));
						SERIAL_PGM(" Duration:");
						SERIAL_PORT.println(motorControl->getMaxMotorDuration(i+1));
					} else {
						SERIAL_PGMLN("None.");
					}
			}
			SERIAL_PGM("Ultrasonic pins:");
			if( motorControl->totalUltrasonics() ) {
				SERIAL_PORT.println(motorControl->totalUltrasonics());
				for(int j = 0; j < motorControl->totalUltrasonics(); j++) {
					SERIAL_PGM("Pin:");
					SERIAL_PORT.print(psonics[motorControl->getUltrasonicIndex(i+1)]->getPin());
					SERIAL_PGM(" Facing:");
					SERIAL_PORT.print(motorControl->getUltrasonicFacing(i+1));
					SERIAL_PGM(" Shutdown cm:");
					SERIAL_PORT.println(motorControl->getMinMotorDist(i+1));
				}
			} else {
						SERIAL_PGMLN("None.");
			}
			SERIAL_PORT.flush();
			break;
			
	case 706: // Report all pins in use
		for(int i = 0; i < 100; i++) {
			if( pinAssignment(i) == PIN_ASSIGNED ) {
				SERIAL_PORT.print(i);
				SERIAL_PORT.print(',');
			}
		}
		SERIAL_PORT.println();
		SERIAL_PORT.flush();
		break;
		
	case 797:
		break;
		
	case 798: // Report controller status
		//SERIAL_PGMLN(motorCntrlHdr);
		if( motorControl->isConnected() ) {
			for(int i = 0; i < motorControl->getChannels() ; i++ ) {
				SERIAL_PGM("Motor Channel:");
				SERIAL_PORT.println(i+1);
				char* buf = motorControl->getDriverInfo(i+1);
				while(*buf) {
					SERIAL_PORT.print(*buf);
					buf++;
				}
			}
		}
		SERIAL_PORT.println();
		SERIAL_PORT.flush();
		break;	
		
	case 799: // Reset Motor controller
		motorControl->commandEmergencyStop();
		break;		
		
	case 800: 
		break;
		
	case 801: // IMU
		prh = new PitchRollHeading();
		orient = prh->getPitchRollHeading();
		SERIAL_PGMLN(posCntrlHdr);
		SERIAL_PGM("1 ");
		SERIAL_PORT.println(orient.pitch);
		SERIAL_PGM("2 ");
		SERIAL_PORT.println(orient.roll);
		SERIAL_PGM("3 ");
		SERIAL_PORT.println(orient.heading);
		break;	
			
	case 802: // Acquire analog pin data M802 Pnn Sxxx Mxxx P=Pin number, S=number readings, M=microseconds per reading. X - pullup.
		// Publish <dataset> 1 - pin, 2 - reading
		if( code_seen('P')) {
			apin = new Analog((uint8_t)code_value());
			if( code_seen('X') )
				apin->pinMode(INPUT_PULLUP);
			else
				apin->pinMode(INPUT);
		}
		nread = 0;
		if( code_seen('S') ) {
			nread = code_value();
		}
		micros = 0;
		if( code_seen('M')) {
			micros = (uint32_t)code_value();
		}
		values = new int(nread);
		for(int i = 0; i < nread; i++) {
			*(values+i) = apin->analogRead();
			for(int j = 0; j < micros; j++) _delay_us(1);
		}
		SERIAL_PGMLN(datasetHdr);
		SERIAL_PORT.println();
		for(int i = 0; i < nread; i++) {
			SERIAL_PORT.print(i+1); // sequence
			SERIAL_PORT.print(' ');
			// 0 element is pin number
			if( i == 0 )
				SERIAL_PORT.println(apin->pin);
			else
				SERIAL_PORT.println(*(values+i)); // value
		}
		delete values;
		SERIAL_PORT.println();
		SERIAL_PORT.flush();
		break;	
		
	case 803:
		break;	
		
	case 907: 
		break; 
		 
	case 908: // M908 Control digital trimpot directly.
		uint8_t current;
		if(code_seen('P')) channel=code_value();
		if(code_seen('S')) current=code_value();
		digitalPotWrite(channel, current);
		break;
		
    case 999: // M999: Reset
		Stopped = false;
		//lcd_reset_alert_level();
		gcode_LastN = Stopped_gcode_LastN;
		//FlushSerialRequestResend();
		if( watchdog_timer != NULL )
			delete watchdog_timer;
		watchdog_timer = new WatchdogTimer();
		watchdog_timer->watchdog_init(15); // 15 ms
	
  } // switch m code

  } else { // if M code
    SERIAL_PGMLN(MSG_UNKNOWN_COMMAND);
    //SERIAL_PORT.println(cmdbuffer[bufindr]);
  }

}
  /**
   * This function used to be inline code in G26. But there are so many
   * parameters it made sense to turn them into static globals and get
   * this code out of sight of the main routine.
   */
  bool parse_G26_parameters() {

    extrusion_multiplier  = EXTRUSION_MULTIPLIER;
    retraction_multiplier = RETRACTION_MULTIPLIER;
    nozzle                = NOZZLE;
    filament_diameter     = FILAMENT;
    layer_height          = LAYER_HEIGHT;
    prime_length          = PRIME_LENGTH;
    bed_temp              = BED_TEMP;
    hotend_temp           = HOTEND_TEMP;
    ooze_amount           = OOZE_AMOUNT;
    prime_flag            = 0;
    keep_heaters_on       = false;

    if (code_seen('B')) {
      bed_temp = code_value_temp_abs();
      if (!WITHIN(bed_temp, 15, 140)) {
        SERIAL_PROTOCOLLNPGM("?Specified bed temperature not plausible.");
        return UBL_ERR;
      }
    }

    if (code_seen('C')) continue_with_closest++;

    if (code_seen('L')) {
      layer_height = code_value_linear_units();
      if (!WITHIN(layer_height, 0.0, 2.0)) {
        SERIAL_PROTOCOLLNPGM("?Specified layer height not plausible.");
        return UBL_ERR;
      }
    }

    if (code_seen('Q')) {
      if (code_has_value()) {
        retraction_multiplier = code_value_float();
        if (!WITHIN(retraction_multiplier, 0.05, 15.0)) {
          SERIAL_PROTOCOLLNPGM("?Specified Retraction Multiplier not plausible.");
          return UBL_ERR;
        }
      }
      else {
        SERIAL_PROTOCOLLNPGM("?Retraction Multiplier must be specified.");
        return UBL_ERR;
      }
    }

    if (code_seen('N') || code_seen('n')) {
      nozzle = code_value_float();
      if (!WITHIN(nozzle, 0.1, 1.0)) {
        SERIAL_PROTOCOLLNPGM("?Specified nozzle size not plausible.");
        return UBL_ERR;
      }
    }

    if (code_seen('K')) keep_heaters_on++;

    if (code_seen('O') && code_has_value())
      ooze_amount = code_value_linear_units();

    if (code_seen('P')) {
      if (!code_has_value())
        prime_flag = -1;
      else {
        prime_flag++;
        prime_length = code_value_linear_units();
        if (!WITHIN(prime_length, 0.0, 25.0)) {
          SERIAL_PROTOCOLLNPGM("?Specified prime length not plausible.");
          return UBL_ERR;
        }
      }
    }

    if (code_seen('F')) {
      filament_diameter = code_value_linear_units();
      if (!WITHIN(filament_diameter, 1.0, 4.0)) {
        SERIAL_PROTOCOLLNPGM("?Specified filament size not plausible.");
        return UBL_ERR;
      }
    }
    extrusion_multiplier *= sq(1.75) / sq(filament_diameter);         // If we aren't using 1.75mm filament, we need to
                                                                      // scale up or down the length needed to get the
                                                                      // same volume of filament

    extrusion_multiplier *= filament_diameter * sq(nozzle) / sq(0.3); // Scale up by nozzle size

    if (code_seen('H')) {
      hotend_temp = code_value_temp_abs();
      if (!WITHIN(hotend_temp, 165, 280)) {
        SERIAL_PROTOCOLLNPGM("?Specified nozzle temperature not plausible.");
        return UBL_ERR;
      }
    }

    if (code_seen('R')) {
      randomSeed(millis());
      random_deviation = code_has_value() ? code_value_float() : 50.0;
    }

    x_pos = current_position[X_AXIS];
    y_pos = current_position[Y_AXIS];

    if (code_seen('X')) {
      x_pos = code_value_axis_units(X_AXIS);
      if (!WITHIN(x_pos, X_MIN_POS, X_MAX_POS)) {
        SERIAL_PROTOCOLLNPGM("?Specified X coordinate not plausible.");
        return UBL_ERR;
      }
    }
    else

    if (code_seen('Y')) {
      y_pos = code_value_axis_units(Y_AXIS);
      if (!WITHIN(y_pos, Y_MIN_POS, Y_MAX_POS)) {
        SERIAL_PROTOCOLLNPGM("?Specified Y coordinate not plausible.");
        return UBL_ERR;
      }
    }

    /**
     * We save the question of what to do with the Unified Bed Leveling System's Activation until the very
     * end.  The reason is, if one of the parameters specified up above is incorrect, we don't want to
     * alter the system's status.  We wait until we know everything is correct before altering the state
     * of the system.
     */
    ubl.state.active = !code_seen('D');

    return UBL_OK;
  }