Example #1
0
void lcd_loading_filament(){

  
    lcd_implementation_clear();
      
      lcd.setCursor(0, 0);
     
      lcd.print(MSG_LOADING_FILAMENT);
      lcd.setCursor(0, 2);
      lcd.print(MSG_PLEASE_WAIT);

  
  for(int i = 0; i<20; i++){
    
    lcd.setCursor(i, 3);
    lcd.print(".");
    for(int j = 0;j<10 ; j++){
        manage_heater();
    manage_inactivity(true);
        delay(110);
    
    }
    
     
  }

}
void loop() {
    get_command();
    
    manage_heater();
    
    manage_inactivity(1); //shutdown if not receiving any new commands
}
Example #3
0
/*-------------------------------------------------
* And the primary command parser loop
*/
void loop()
{
  if(buflen < (BUFSIZE-1))
    get_command();

  if(buflen)
  {
    process_commands();
    buflen = (buflen-1);
    bufindr = (bufindr + 1)%BUFSIZE;
  } else {
	manage_inactivity();
  }
}
Example #4
0
// Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in 
// mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration
// calculation the caller must also provide the physical length of the line in millimeters.
void plan_buffer_line(const float &x, const float &y, const float &z, const float &e, float feed_rate, const uint8_t &extruder)
{
  // Calculate the buffer head after we push this byte
  int next_buffer_head = next_block_index(block_buffer_head);

  // If the buffer is full: good! That means we are well ahead of the robot. 
  // Rest here until there is room in the buffer.
  while(block_buffer_tail == next_buffer_head)
  {
    manage_heater(); 
    manage_inactivity(); 
    lcd_update();
  }

  // The target position of the tool in absolute steps
  // Calculate target position in absolute steps
  //this should be done after the wait, because otherwise a M92 code within the gcode disrupts this calculation somehow
  long target[4];
  target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]);
  target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]);
  target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]);     
  target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]);

  #ifdef PREVENT_DANGEROUS_EXTRUDE
  if(target[E_AXIS]!=position[E_AXIS])
  {
    if(degHotend(active_extruder)<extrude_min_temp)
    {
      position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part
      SERIAL_ECHO_START;
      SERIAL_ECHOLNPGM(MSG_ERR_COLD_EXTRUDE_STOP);
    }
        #ifdef PREVENT_LENGTHY_EXTRUDE
    if(labs(target[E_AXIS]-position[E_AXIS])>axis_steps_per_unit[E_AXIS]*EXTRUDE_MAXLENGTH)
    {
#ifdef EASY_LOAD
	  if (!allow_lengthy_extrude_once) {
#endif
        position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part
        SERIAL_ECHO_START;
        SERIAL_ECHOLNPGM(MSG_ERR_LONG_EXTRUDE_STOP);
#ifdef EASY_LOAD
	  }
	  allow_lengthy_extrude_once = false;
#endif
    }
    #endif  // PREVENT_LENGTHY_EXTRUDE
  }
  #endif

  // Prepare to set up new block
  block_t *block = &block_buffer[block_buffer_head];

  // Mark block as not busy (Not executed by the stepper interrupt)
  block->busy = false;

  // Number of steps for each axis
#ifndef COREXY
// default non-h-bot planning
block->steps_x = labs(target[X_AXIS]-position[X_AXIS]);
block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]);
#else
// corexy planning
// these equations follow the form of the dA and dB equations on http://www.corexy.com/theory.html
block->steps_x = labs((target[X_AXIS]-position[X_AXIS]) + (target[Y_AXIS]-position[Y_AXIS]));
block->steps_y = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-position[Y_AXIS]));
#endif
  block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]);
  block->steps_e = labs(target[E_AXIS]-position[E_AXIS]);
  block->steps_e *= extrudemultiply;
  block->steps_e /= 100;
  block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e)));

  // Bail if this is a zero-length block
  if (block->step_event_count <= dropsegments)
  { 
    return; 
  }

  block->fan_speed = fanSpeed;
  #ifdef BARICUDA
  block->valve_pressure = ValvePressure;
  block->e_to_p_pressure = EtoPPressure;
  #endif

  // Compute direction bits for this block 
  block->direction_bits = 0;
#ifndef COREXY
  if (target[X_AXIS] < position[X_AXIS])
  {
    block->direction_bits |= (1<<X_AXIS); 
  }
  if (target[Y_AXIS] < position[Y_AXIS])
  {
    block->direction_bits |= (1<<Y_AXIS); 
  }
#else
  if ((target[X_AXIS]-position[X_AXIS]) + (target[Y_AXIS]-position[Y_AXIS]) < 0)
  {
    block->direction_bits |= (1<<X_AXIS); 
  }
  if ((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-position[Y_AXIS]) < 0)
  {
    block->direction_bits |= (1<<Y_AXIS); 
  }
#endif
  if (target[Z_AXIS] < position[Z_AXIS])
  {
    block->direction_bits |= (1<<Z_AXIS); 
  }
  if (target[E_AXIS] < position[E_AXIS])
  {
    block->direction_bits |= (1<<E_AXIS); 
  }

  block->active_extruder = extruder;

  //enable active axes
  #ifdef COREXY
  if((block->steps_x != 0) || (block->steps_y != 0))
  {
    enable_x();
    enable_y();
  }
  #else
  if(block->steps_x != 0) enable_x();
  if(block->steps_y != 0) enable_y();
  #endif
#ifndef Z_LATE_ENABLE
  if(block->steps_z != 0) enable_z();
#endif

  // Enable all
  if(block->steps_e != 0)
  {
    enable_e0();
    enable_e1();
    enable_e2(); 
  }

  if (block->steps_e == 0)
  {
    if(feed_rate<mintravelfeedrate) feed_rate=mintravelfeedrate;
  }
  else
  {
    if(feed_rate<minimumfeedrate) feed_rate=minimumfeedrate;
  } 

  float delta_mm[4];
  #ifndef COREXY
    delta_mm[X_AXIS] = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS];
    delta_mm[Y_AXIS] = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS];
  #else
    delta_mm[X_AXIS] = ((target[X_AXIS]-position[X_AXIS]) + (target[Y_AXIS]-position[Y_AXIS]))/axis_steps_per_unit[X_AXIS];
    delta_mm[Y_AXIS] = ((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-position[Y_AXIS]))/axis_steps_per_unit[Y_AXIS];
  #endif
  delta_mm[Z_AXIS] = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS];
  delta_mm[E_AXIS] = ((target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS])*extrudemultiply/100.0;
  if ( block->steps_x <=dropsegments && block->steps_y <=dropsegments && block->steps_z <=dropsegments )
  {
    block->millimeters = fabs(delta_mm[E_AXIS]);
  } 
  else
  {
    block->millimeters = sqrt(square(delta_mm[X_AXIS]) + square(delta_mm[Y_AXIS]) + square(delta_mm[Z_AXIS]));
  }
  float inverse_millimeters = 1.0/block->millimeters;  // Inverse millimeters to remove multiple divides 

    // Calculate speed in mm/second for each axis. No divide by zero due to previous checks.
  float inverse_second = feed_rate * inverse_millimeters;

  int moves_queued=(block_buffer_head-block_buffer_tail + BLOCK_BUFFER_SIZE) & (BLOCK_BUFFER_SIZE - 1);

  // slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill
#ifdef OLD_SLOWDOWN
  if(moves_queued < (BLOCK_BUFFER_SIZE * 0.5) && moves_queued > 1)
    feed_rate = feed_rate*moves_queued / (BLOCK_BUFFER_SIZE * 0.5); 
#endif

#ifdef SLOWDOWN
  //  segment time im micro seconds
  unsigned long segment_time = lround(1000000.0/inverse_second);
  if ((moves_queued > 1) && (moves_queued < (BLOCK_BUFFER_SIZE * 0.5)))
  {
    if (segment_time < minsegmenttime)
    { // buffer is draining, add extra time.  The amount of time added increases if the buffer is still emptied more.
      inverse_second=1000000.0/(segment_time+lround(2*(minsegmenttime-segment_time)/moves_queued));
      #ifdef XY_FREQUENCY_LIMIT
         segment_time = lround(1000000.0/inverse_second);
      #endif
    }
  }
#endif
  //  END OF SLOW DOWN SECTION    


  block->nominal_speed = block->millimeters * inverse_second; // (mm/sec) Always > 0
  block->nominal_rate = ceil(block->step_event_count * inverse_second); // (step/sec) Always > 0

  // Calculate and limit speed in mm/sec for each axis
  float current_speed[4];
  float speed_factor = 1.0; //factor <=1 do decrease speed
  for(int i=0; i < 4; i++)
  {
    current_speed[i] = delta_mm[i] * inverse_second;
    if(fabs(current_speed[i]) > max_feedrate[i])
      speed_factor = min(speed_factor, max_feedrate[i] / fabs(current_speed[i]));
  }

  // Max segement time in us.
#ifdef XY_FREQUENCY_LIMIT
#define MAX_FREQ_TIME (1000000.0/XY_FREQUENCY_LIMIT)
  // Check and limit the xy direction change frequency
  unsigned char direction_change = block->direction_bits ^ old_direction_bits;
  old_direction_bits = block->direction_bits;
  segment_time = lround((float)segment_time / speed_factor);
  
  if((direction_change & (1<<X_AXIS)) == 0)
  {
    x_segment_time[0] += segment_time;
  }
  else
  {
    x_segment_time[2] = x_segment_time[1];
    x_segment_time[1] = x_segment_time[0];
    x_segment_time[0] = segment_time;
  }
  if((direction_change & (1<<Y_AXIS)) == 0)
  {
    y_segment_time[0] += segment_time;
  }
  else
  {
    y_segment_time[2] = y_segment_time[1];
    y_segment_time[1] = y_segment_time[0];
    y_segment_time[0] = segment_time;
  }
  long max_x_segment_time = max(x_segment_time[0], max(x_segment_time[1], x_segment_time[2]));
  long max_y_segment_time = max(y_segment_time[0], max(y_segment_time[1], y_segment_time[2]));
  long min_xy_segment_time =min(max_x_segment_time, max_y_segment_time);
  if(min_xy_segment_time < MAX_FREQ_TIME)
    speed_factor = min(speed_factor, speed_factor * (float)min_xy_segment_time / (float)MAX_FREQ_TIME);
#endif

  // Correct the speed  
  if( speed_factor < 1.0)
  {
    for(unsigned char i=0; i < 4; i++)
    {
      current_speed[i] *= speed_factor;
    }
    block->nominal_speed *= speed_factor;
    block->nominal_rate *= speed_factor;
  }

  // Compute and limit the acceleration rate for the trapezoid generator.  
  float steps_per_mm = block->step_event_count/block->millimeters;
  if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)
  {
    block->acceleration_st = ceil(retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
  }
  else
  {
    block->acceleration_st = ceil(acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
    // Limit acceleration per axis
    if(((float)block->acceleration_st * (float)block->steps_x / (float)block->step_event_count) > axis_steps_per_sqr_second[X_AXIS])
      block->acceleration_st = axis_steps_per_sqr_second[X_AXIS];
    if(((float)block->acceleration_st * (float)block->steps_y / (float)block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS])
      block->acceleration_st = axis_steps_per_sqr_second[Y_AXIS];
    if(((float)block->acceleration_st * (float)block->steps_e / (float)block->step_event_count) > axis_steps_per_sqr_second[E_AXIS])
      block->acceleration_st = axis_steps_per_sqr_second[E_AXIS];
    if(((float)block->acceleration_st * (float)block->steps_z / (float)block->step_event_count ) > axis_steps_per_sqr_second[Z_AXIS])
      block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS];
  }
  block->acceleration = block->acceleration_st / steps_per_mm;
  block->acceleration_rate = (long)((float)block->acceleration_st * (16777216.0 / (F_CPU / 8.0)));

#if 0  // Use old jerk for now
  // Compute path unit vector
  double unit_vec[3];

  unit_vec[X_AXIS] = delta_mm[X_AXIS]*inverse_millimeters;
  unit_vec[Y_AXIS] = delta_mm[Y_AXIS]*inverse_millimeters;
  unit_vec[Z_AXIS] = delta_mm[Z_AXIS]*inverse_millimeters;

  // Compute maximum allowable entry speed at junction by centripetal acceleration approximation.
  // Let a circle be tangent to both previous and current path line segments, where the junction
  // deviation is defined as the distance from the junction to the closest edge of the circle,
  // colinear with the circle center. The circular segment joining the two paths represents the
  // path of centripetal acceleration. Solve for max velocity based on max acceleration about the
  // radius of the circle, defined indirectly by junction deviation. This may be also viewed as
  // path width or max_jerk in the previous grbl version. This approach does not actually deviate
  // from path, but used as a robust way to compute cornering speeds, as it takes into account the
  // nonlinearities of both the junction angle and junction velocity.
  double vmax_junction = MINIMUM_PLANNER_SPEED; // Set default max junction speed

  // Skip first block or when previous_nominal_speed is used as a flag for homing and offset cycles.
  if ((block_buffer_head != block_buffer_tail) && (previous_nominal_speed > 0.0)) {
    // Compute cosine of angle between previous and current path. (prev_unit_vec is negative)
    // NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity.
    double cos_theta = - previous_unit_vec[X_AXIS] * unit_vec[X_AXIS]
      - previous_unit_vec[Y_AXIS] * unit_vec[Y_AXIS]
      - previous_unit_vec[Z_AXIS] * unit_vec[Z_AXIS] ;

    // Skip and use default max junction speed for 0 degree acute junction.
    if (cos_theta < 0.95) {
      vmax_junction = min(previous_nominal_speed,block->nominal_speed);
      // Skip and avoid divide by zero for straight junctions at 180 degrees. Limit to min() of nominal speeds.
      if (cos_theta > -0.95) {
        // Compute maximum junction velocity based on maximum acceleration and junction deviation
        double sin_theta_d2 = sqrt(0.5*(1.0-cos_theta)); // Trig half angle identity. Always positive.
        vmax_junction = min(vmax_junction,
        sqrt(block->acceleration * junction_deviation * sin_theta_d2/(1.0-sin_theta_d2)) );
      }
    }
  }
#endif
  // Start with a safe speed
  float vmax_junction = max_xy_jerk/2; 
  float vmax_junction_factor = 1.0; 
  if(fabs(current_speed[Z_AXIS]) > max_z_jerk/2) 
    vmax_junction = min(vmax_junction, max_z_jerk/2);
  if(fabs(current_speed[E_AXIS]) > max_e_jerk/2) 
    vmax_junction = min(vmax_junction, max_e_jerk/2);
  vmax_junction = min(vmax_junction, block->nominal_speed);
  float safe_speed = vmax_junction;

  if ((moves_queued > 1) && (previous_nominal_speed > 0.0001)) {
    float jerk = sqrt(pow((current_speed[X_AXIS]-previous_speed[X_AXIS]), 2)+pow((current_speed[Y_AXIS]-previous_speed[Y_AXIS]), 2));
    //    if((fabs(previous_speed[X_AXIS]) > 0.0001) || (fabs(previous_speed[Y_AXIS]) > 0.0001)) {
    vmax_junction = block->nominal_speed;
    //    }
    if (jerk > max_xy_jerk) {
      vmax_junction_factor = (max_xy_jerk/jerk);
    } 
    if(fabs(current_speed[Z_AXIS] - previous_speed[Z_AXIS]) > max_z_jerk) {
      vmax_junction_factor= min(vmax_junction_factor, (max_z_jerk/fabs(current_speed[Z_AXIS] - previous_speed[Z_AXIS])));
    } 
    if(fabs(current_speed[E_AXIS] - previous_speed[E_AXIS]) > max_e_jerk) {
      vmax_junction_factor = min(vmax_junction_factor, (max_e_jerk/fabs(current_speed[E_AXIS] - previous_speed[E_AXIS])));
    } 
    vmax_junction = min(previous_nominal_speed, vmax_junction * vmax_junction_factor); // Limit speed to max previous speed
  }
  block->max_entry_speed = vmax_junction;

  // Initialize block entry speed. Compute based on deceleration to user-defined MINIMUM_PLANNER_SPEED.
  double v_allowable = max_allowable_speed(-block->acceleration,MINIMUM_PLANNER_SPEED,block->millimeters);
  block->entry_speed = min(vmax_junction, v_allowable);

  // Initialize planner efficiency flags
  // Set flag if block will always reach maximum junction speed regardless of entry/exit speeds.
  // If a block can de/ac-celerate from nominal speed to zero within the length of the block, then
  // the current block and next block junction speeds are guaranteed to always be at their maximum
  // junction speeds in deceleration and acceleration, respectively. This is due to how the current
  // block nominal speed limits both the current and next maximum junction speeds. Hence, in both
  // the reverse and forward planners, the corresponding block junction speed will always be at the
  // the maximum junction speed and may always be ignored for any speed reduction checks.
  if (block->nominal_speed <= v_allowable) { 
    block->nominal_length_flag = true; 
  }
  else { 
    block->nominal_length_flag = false; 
  }
  block->recalculate_flag = true; // Always calculate trapezoid for new block

  // Update previous path unit_vector and nominal speed
  memcpy(previous_speed, current_speed, sizeof(previous_speed)); // previous_speed[] = current_speed[]
  previous_nominal_speed = block->nominal_speed;


#ifdef ADVANCE
  // Calculate advance rate
  if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) {
    block->advance_rate = 0;
    block->advance = 0;
  }
  else {
    long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration_st);
    float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * 
      (current_speed[E_AXIS] * current_speed[E_AXIS] * EXTRUTION_AREA * EXTRUTION_AREA)*256;
    block->advance = advance;
    if(acc_dist == 0) {
      block->advance_rate = 0;
    } 
    else {
      block->advance_rate = advance / (float)acc_dist;
    }
  }
  /*
    SERIAL_ECHO_START;
   SERIAL_ECHOPGM("advance :");
   SERIAL_ECHO(block->advance/256.0);
   SERIAL_ECHOPGM("advance rate :");
   SERIAL_ECHOLN(block->advance_rate/256.0);
   */
#endif // ADVANCE

  calculate_trapezoid_for_block(block, block->entry_speed/block->nominal_speed,
  safe_speed/block->nominal_speed);

  // Move buffer head
  block_buffer_head = next_buffer_head;

  // Update position
  memcpy(position, target, sizeof(target)); // position[] = target[]

  planner_recalculate();

  st_wake_up();
}
Example #5
0
void lcd_adjust_z(){
  int enc_dif = 0;
  int cursor_pos = 1;
  int fsm = 0;

  
  
  
   lcd_implementation_clear();
      
      lcd.setCursor(0, 0);
     
      lcd.print(MSG_ADJUSTZ);
      
      lcd.setCursor(1, 1);
     
      lcd.print(MSG_YES);
      
      lcd.setCursor(1, 2);
     
      lcd.print(MSG_NO);
      
      lcd.setCursor(0, 1);
     
      lcd.print(">");
      
     
      enc_dif = encoderDiff;
      
      while(fsm == 0){
        
        manage_heater();
          manage_inactivity(true);
          
          if( abs((enc_dif - encoderDiff))>4 ){
            
            if ( (abs(enc_dif-encoderDiff)) > 1 ){
            if (enc_dif > encoderDiff ){
                  cursor_pos --;
              }
              
              if (enc_dif < encoderDiff  ){
                  cursor_pos ++;
              }
              
              if(cursor_pos >2){
              cursor_pos = 2;
            }
            
            if(cursor_pos <1){
              cursor_pos = 1;
            }
            lcd.setCursor(0, 1);
            lcd.print(" ");
            lcd.setCursor(0, 2);
            lcd.print(" ");
            lcd.setCursor(0, cursor_pos);
            lcd.print(">");
              enc_dif = encoderDiff;
              delay(100);
            }
            
          }
          

          if(lcd_clicked()){
            fsm = cursor_pos;
            if(fsm == 1){
                EEPROM_read_B(4093,&babystepMem[0]);
                EEPROM_read_B(4091,&babystepMem[1]);
                EEPROM_read_B(4089,&babystepMem[2]);
                babystepsTodo[Z_AXIS] = babystepMem[2];
            }else{
                babystepMem[0] = 0;
                babystepMem[1] = 0;
                babystepMem[2] = 0;

                EEPROM_save_B(4093,&babystepMem[0]);
                EEPROM_save_B(4091,&babystepMem[1]);
                EEPROM_save_B(4089,&babystepMem[2]);
            }
            delay(500);
              
          }
          
          
          
        };
      
      
       lcd_implementation_clear();
  lcd_return_to_status();
  
}
Example #6
0
void lcd_alright(){
  int enc_dif = 0;
  int cursor_pos = 1;

  
  
  
   lcd_implementation_clear();
      
      lcd.setCursor(0, 0);
     
      lcd.print(MSG_CORRECTLY);
      
      lcd.setCursor(1, 1);
     
      lcd.print(MSG_YES);
      
      lcd.setCursor(1, 2);
     
      lcd.print(MSG_NOT_LOADED);
      
      
      lcd.setCursor(1, 3);
      lcd.print(MSG_NOT_COLOR);
      
      
       lcd.setCursor(0, 1);
     
      lcd.print(">");
      
     
      enc_dif = encoderDiff;
      
      while(lcd_change_fil_state == 0){
        
        manage_heater();
          manage_inactivity(true);
          
          if( abs((enc_dif - encoderDiff))>4 ){
            
            if ( (abs(enc_dif-encoderDiff)) > 1 ){
            if (enc_dif > encoderDiff ){
                  cursor_pos --;
              }
              
              if (enc_dif < encoderDiff  ){
                  cursor_pos ++;
              }
              
              if(cursor_pos >3){
              cursor_pos = 3;
            }
            
            if(cursor_pos <1){
              cursor_pos = 1;
            }
            lcd.setCursor(0, 1);
            lcd.print(" ");
            lcd.setCursor(0, 2);
            lcd.print(" ");
            lcd.setCursor(0, 3);
            lcd.print(" ");
            lcd.setCursor(0, cursor_pos);
            lcd.print(">");
              enc_dif = encoderDiff;
              delay(100);
            }
            
          }
          

          if(lcd_clicked()){
            
            lcd_change_fil_state = cursor_pos;
            delay(500);
              
          }
          
          
          
        };
      
      
       lcd_implementation_clear();
  lcd_return_to_status();
  
}
Example #7
0
void plan_buffer_line(const float &x, const float &y, const float &z, const float &e, float feed_rate, const uint8_t &extruder)
#endif  //LEVEL_SENSOR
{
  // Calculate the buffer head after we push this byte
  next_buffer_head = next_block_index(block_buffer_head);

  // If the buffer is full: good! That means we are well ahead of the robot. 
  // Rest here until there is room in the buffer.
#ifndef DOGLCD
  buffer_recursivity++;
#endif // DOGLCD

  while(block_buffer_tail == next_buffer_head)
  {
    next_buffer_head = next_block_index(block_buffer_head);

    temp::TemperatureManager::single::instance().manageTemperatureControl(); 
#ifndef DOGLCD
        manage_inactivity(); 
#endif //DOGLCD
    lcd_update();

#ifdef DOGLCD
    if (stop_planner_buffer == true)
    {
      stop_planner_buffer = false;
      planner_buffer_stopped = true;
      return;
    }
#endif // DOGLCD
  }

#ifndef DOGLCD
  buffer_recursivity--;
#endif // DOGLCD

#ifdef LEVEL_SENSOR
  apply_rotation_xyz(plan_bed_level_matrix, x, y, z);
#endif // LEVEL_SENSOR

  // The target position of the tool in absolute steps
  // Calculate target position in absolute steps
  //this should be done after the wait, because otherwise a M92 code within the gcode disrupts this calculation somehow
  long target[4];
  target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]);
  target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]);
  target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]);     
  target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]);

  #ifdef PREVENT_DANGEROUS_EXTRUDE
  if(target[E_AXIS]!=position[E_AXIS])
  {
    if(degHotend(active_extruder)<extrude_min_temp)
    {
      position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part
      SERIAL_ECHO_START;
      SERIAL_ECHOLNPGM(MSG_ERR_COLD_EXTRUDE_STOP);
    }
    
    #ifdef PREVENT_LENGTHY_EXTRUDE
    if(labs(target[E_AXIS]-position[E_AXIS])>axis_steps_per_unit[E_AXIS]*EXTRUDE_MAXLENGTH)
    {
      position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part
      SERIAL_ECHO_START;
      SERIAL_ECHOLNPGM(MSG_ERR_LONG_EXTRUDE_STOP);
    }
    #endif
  }
  #endif

  // Prepare to set up new block
  block_t *block = &block_buffer[block_buffer_head];

  // Mark block as not busy (Not executed by the stepper interrupt)
  block->busy = false;

  // Number of steps for each axis
#ifndef COREXY
// default non-h-bot planning
block->steps_x = labs(target[X_AXIS]-position[X_AXIS]);
block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]);
#else
// corexy planning
// these equations follow the form of the dA and dB equations on http://www.corexy.com/theory.html
block->steps_x = labs((target[X_AXIS]-position[X_AXIS]) + (target[Y_AXIS]-position[Y_AXIS]));
block->steps_y = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-position[Y_AXIS]));
#endif
  block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]);
  block->steps_e = labs(target[E_AXIS]-position[E_AXIS]);
  block->steps_e *= volumetric_multiplier[active_extruder];
  block->steps_e *= extrudemultiply;
  block->steps_e /= 100;
  block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e)));

  // Bail if this is a zero-length block
  if (block->step_event_count <= dropsegments)
  { 
    return; 
  }

  block->fan_speed = fanSpeed;
  #ifdef BARICUDA
  block->valve_pressure = ValvePressure;
  block->e_to_p_pressure = EtoPPressure;
  #endif

  // Compute direction bits for this block 
  block->direction_bits = 0;
#ifndef COREXY
  if (target[X_AXIS] < position[X_AXIS])
  {
    block->direction_bits |= (1<<X_AXIS); 
  }
  if (target[Y_AXIS] < position[Y_AXIS])
  {
    block->direction_bits |= (1<<Y_AXIS); 
  }
#else
  if (target[X_AXIS] < position[X_AXIS])
  {
    block->direction_bits |= (1<<X_HEAD); //AlexBorro: Save the real Extruder (head) direction in X Axis
  }
  if (target[Y_AXIS] < position[Y_AXIS])
  {
    block->direction_bits |= (1<<Y_HEAD); //AlexBorro: Save the real Extruder (head) direction in Y Axis
  }
  if ((target[X_AXIS]-position[X_AXIS]) + (target[Y_AXIS]-position[Y_AXIS]) < 0)
  {
    block->direction_bits |= (1<<X_AXIS); //AlexBorro: Motor A direction (Incorrectly implemented as X_AXIS)
  }
  if ((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-position[Y_AXIS]) < 0)
  {
    block->direction_bits |= (1<<Y_AXIS); //AlexBorro: Motor B direction (Incorrectly implemented as Y_AXIS)
  }
#endif
  if (target[Z_AXIS] < position[Z_AXIS])
  {
    block->direction_bits |= (1<<Z_AXIS); 
  }
  if (target[E_AXIS] < position[E_AXIS])
  {
    block->direction_bits |= (1<<E_AXIS); 
  }

  block->active_extruder = extruder;

  //enable active axes
  #ifdef COREXY
  if((block->steps_x != 0) || (block->steps_y != 0))
  {
    enable_x();
    enable_y();
  }
  #else
  if(block->steps_x != 0) enable_x();
  if(block->steps_y != 0) enable_y();
  #endif
#ifndef Z_LATE_ENABLE
  if(block->steps_z != 0) enable_z();
#endif

  // Enable extruder(s)
  if(block->steps_e != 0)
  {
    if (DISABLE_INACTIVE_EXTRUDER) //enable only selected extruder
    {

      if(g_uc_extruder_last_move[0] > 0) g_uc_extruder_last_move[0]--;
      if(g_uc_extruder_last_move[1] > 0) g_uc_extruder_last_move[1]--;
      if(g_uc_extruder_last_move[2] > 0) g_uc_extruder_last_move[2]--;
      if(g_uc_extruder_last_move[3] > 0) g_uc_extruder_last_move[3]--;
      
      switch(extruder)
      {
        case 0: 
          enable_e0(); 
          g_uc_extruder_last_move[0] = BLOCK_BUFFER_SIZE*2;
          
          if(g_uc_extruder_last_move[1] == 0) disable_e1(); 
          if(g_uc_extruder_last_move[2] == 0) disable_e2(); 
          if(g_uc_extruder_last_move[3] == 0) disable_e3(); 
        break;
        case 1:
          enable_e1(); 
          g_uc_extruder_last_move[1] = BLOCK_BUFFER_SIZE*2;
          
          if(g_uc_extruder_last_move[0] == 0) disable_e0(); 
          if(g_uc_extruder_last_move[2] == 0) disable_e2(); 
          if(g_uc_extruder_last_move[3] == 0) disable_e3(); 
        break;
        case 2:
          enable_e2(); 
          g_uc_extruder_last_move[2] = BLOCK_BUFFER_SIZE*2;
          
          if(g_uc_extruder_last_move[0] == 0) disable_e0(); 
          if(g_uc_extruder_last_move[1] == 0) disable_e1(); 
          if(g_uc_extruder_last_move[3] == 0) disable_e3(); 
        break;        
        case 3:
          enable_e3(); 
          g_uc_extruder_last_move[3] = BLOCK_BUFFER_SIZE*2;
          
          if(g_uc_extruder_last_move[0] == 0) disable_e0(); 
          if(g_uc_extruder_last_move[1] == 0) disable_e1(); 
          if(g_uc_extruder_last_move[2] == 0) disable_e2(); 
        break;        
      }
    }
    else //enable all
    {
      enable_e0();
      enable_e1();
      enable_e2();
      enable_e3();
    }
  }

  if (block->steps_e == 0)
  {
    if(feed_rate<mintravelfeedrate) feed_rate=mintravelfeedrate;
  }
  else
  {
    if(feed_rate<minimumfeedrate) feed_rate=minimumfeedrate;
  } 

/* This part of the code calculates the total length of the movement. 
For cartesian bots, the X_AXIS is the real X movement and same for Y_AXIS.
But for corexy bots, that is not true. The "X_AXIS" and "Y_AXIS" motors (that should be named to A_AXIS
and B_AXIS) cannot be used for X and Y length, because A=X+Y and B=X-Y.
So we need to create other 2 "AXIS", named X_HEAD and Y_HEAD, meaning the real displacement of the Head. 
Having the real displacement of the head, we can calculate the total movement length and apply the desired speed.
*/ 
  #ifndef COREXY
    float delta_mm[4];
    delta_mm[X_AXIS] = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS];
    delta_mm[Y_AXIS] = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS];
  #else
    float delta_mm[6];
    delta_mm[X_HEAD] = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS];
    delta_mm[Y_HEAD] = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS];
    delta_mm[X_AXIS] = ((target[X_AXIS]-position[X_AXIS]) + (target[Y_AXIS]-position[Y_AXIS]))/axis_steps_per_unit[X_AXIS];
    delta_mm[Y_AXIS] = ((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-position[Y_AXIS]))/axis_steps_per_unit[Y_AXIS];
  #endif
  delta_mm[Z_AXIS] = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS];
  delta_mm[E_AXIS] = ((target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS])*volumetric_multiplier[active_extruder]*extrudemultiply/100.0;
  if ( block->steps_x <=dropsegments && block->steps_y <=dropsegments && block->steps_z <=dropsegments )
  {
    block->millimeters = fabs(delta_mm[E_AXIS]);
  } 
  else
  {
    #ifndef COREXY
      block->millimeters = sqrt(square(delta_mm[X_AXIS]) + square(delta_mm[Y_AXIS]) + square(delta_mm[Z_AXIS]));
	#else
	  block->millimeters = sqrt(square(delta_mm[X_HEAD]) + square(delta_mm[Y_HEAD]) + square(delta_mm[Z_AXIS]));
    #endif	
  }
  float inverse_millimeters = 1.0/block->millimeters;  // Inverse millimeters to remove multiple divides 

    // Calculate speed in mm/second for each axis. No divide by zero due to previous checks.
  float inverse_second = feed_rate * inverse_millimeters;

  int moves_queued=(block_buffer_head-block_buffer_tail + BLOCK_BUFFER_SIZE) & (BLOCK_BUFFER_SIZE - 1);

  // slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill
#ifdef OLD_SLOWDOWN
  if(moves_queued < (BLOCK_BUFFER_SIZE * 0.5) && moves_queued > 1)
    feed_rate = feed_rate*moves_queued / (BLOCK_BUFFER_SIZE * 0.5); 
#endif

#ifdef SLOWDOWN
  //  segment time im micro seconds
  unsigned long segment_time = lround(1000000.0/inverse_second);
  if ((moves_queued > 1) && (moves_queued < (BLOCK_BUFFER_SIZE * 0.5)))
  {
    if (segment_time < minsegmenttime)
    { // buffer is draining, add extra time.  The amount of time added increases if the buffer is still emptied more.
      inverse_second=1000000.0/(segment_time+lround(2*(minsegmenttime-segment_time)/moves_queued));
      #ifdef XY_FREQUENCY_LIMIT
         segment_time = lround(1000000.0/inverse_second);
      #endif
    }
  }
#endif
  //  END OF SLOW DOWN SECTION    


  block->nominal_speed = block->millimeters * inverse_second; // (mm/sec) Always > 0
  block->nominal_rate = ceil(block->step_event_count * inverse_second); // (step/sec) Always > 0

#ifdef FILAMENT_SENSOR
  //FMM update ring buffer used for delay with filament measurements
  
  
    if((extruder==FILAMENT_SENSOR_EXTRUDER_NUM) && (delay_index2 > -1))  //only for extruder with filament sensor and if ring buffer is initialized
  	  {
    delay_dist = delay_dist + delta_mm[E_AXIS];  //increment counter with next move in e axis
  
    while (delay_dist >= (10*(MAX_MEASUREMENT_DELAY+1)))  //check if counter is over max buffer size in mm
      	  delay_dist = delay_dist - 10*(MAX_MEASUREMENT_DELAY+1);  //loop around the buffer
    while (delay_dist<0)
    	  delay_dist = delay_dist + 10*(MAX_MEASUREMENT_DELAY+1); //loop around the buffer
      
    delay_index1=delay_dist/10.0;  //calculate index
    
    //ensure the number is within range of the array after converting from floating point
    if(delay_index1<0)
    	delay_index1=0;
    else if (delay_index1>MAX_MEASUREMENT_DELAY)
    	delay_index1=MAX_MEASUREMENT_DELAY;
    	
    if(delay_index1 != delay_index2)  //moved index
  	  {
    	meas_sample=widthFil_to_size_ratio()-100;  //subtract off 100 to reduce magnitude - to store in a signed char
  	  }
    while( delay_index1 != delay_index2)
  	  {
  	  delay_index2 = delay_index2 + 1;
  	if(delay_index2>MAX_MEASUREMENT_DELAY)
  			  delay_index2=delay_index2-(MAX_MEASUREMENT_DELAY+1);  //loop around buffer when incrementing
  	  if(delay_index2<0)
  		delay_index2=0;
  	  else if (delay_index2>MAX_MEASUREMENT_DELAY)
  		delay_index2=MAX_MEASUREMENT_DELAY;  
  	  
  	  measurement_delay[delay_index2]=meas_sample;
  	  }
    	
    
  	  }
#endif


  // Calculate and limit speed in mm/sec for each axis
  float current_speed[4];
  float speed_factor = 1.0; //factor <=1 do decrease speed
  for(int i=0; i < 4; i++)
  {
    current_speed[i] = delta_mm[i] * inverse_second;
    if(fabs(current_speed[i]) > max_feedrate[i])
      speed_factor = min(speed_factor, max_feedrate[i] / fabs(current_speed[i]));
  }

  // Max segement time in us.
#ifdef XY_FREQUENCY_LIMIT
#define MAX_FREQ_TIME (1000000.0/XY_FREQUENCY_LIMIT)
  // Check and limit the xy direction change frequency
  unsigned char direction_change = block->direction_bits ^ old_direction_bits;
  old_direction_bits = block->direction_bits;
  segment_time = lround((float)segment_time / speed_factor);
  
  if((direction_change & (1<<X_AXIS)) == 0)
  {
    x_segment_time[0] += segment_time;
  }
  else
  {
    x_segment_time[2] = x_segment_time[1];
    x_segment_time[1] = x_segment_time[0];
    x_segment_time[0] = segment_time;
  }
  if((direction_change & (1<<Y_AXIS)) == 0)
  {
    y_segment_time[0] += segment_time;
  }
  else
  {
    y_segment_time[2] = y_segment_time[1];
    y_segment_time[1] = y_segment_time[0];
    y_segment_time[0] = segment_time;
  }
  long max_x_segment_time = max(x_segment_time[0], max(x_segment_time[1], x_segment_time[2]));
  long max_y_segment_time = max(y_segment_time[0], max(y_segment_time[1], y_segment_time[2]));
  long min_xy_segment_time =min(max_x_segment_time, max_y_segment_time);
  if(min_xy_segment_time < MAX_FREQ_TIME)
    speed_factor = min(speed_factor, speed_factor * (float)min_xy_segment_time / (float)MAX_FREQ_TIME);
#endif // XY_FREQUENCY_LIMIT

  // Correct the speed  
  if (speed_factor < 1.0) {
    for (unsigned char i = 0; i < NUM_AXIS; i++) current_speed[i] *= speed_factor;
    block->nominal_speed *= speed_factor;
    block->nominal_rate *= speed_factor;
  }

  // Compute and limit the acceleration rate for the trapezoid generator.  
  float steps_per_mm = block->step_event_count / block->millimeters;
  long bsx = block->steps_x, bsy = block->steps_y, bsz = block->steps_z, bse = block->steps_e;
  if (bsx == 0 && bsy == 0 && bsz == 0) {
    block->acceleration_st = ceil(retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
  }
  else if (bse == 0) {
    block->acceleration_st = ceil(travel_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
  }
  else {
    block->acceleration_st = ceil(acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
  }
  // Limit acceleration per axis
  unsigned long acc_st = block->acceleration_st,
                xsteps = axis_steps_per_sqr_second[X_AXIS],
                ysteps = axis_steps_per_sqr_second[Y_AXIS],
                zsteps = axis_steps_per_sqr_second[Z_AXIS],
                esteps = axis_steps_per_sqr_second[E_AXIS];
  if ((float)acc_st * bsx / block->step_event_count > xsteps) acc_st = xsteps;
  if ((float)acc_st * bsy / block->step_event_count > ysteps) acc_st = ysteps;
  if ((float)acc_st * bsz / block->step_event_count > zsteps) acc_st = zsteps;
  if ((float)acc_st * bse / block->step_event_count > esteps) acc_st = esteps;
 
  block->acceleration_st = acc_st;
  block->acceleration = acc_st / steps_per_mm;
  block->acceleration_rate = (long)(acc_st * 16777216.0 / (F_CPU / 8.0));

#if 0  // Use old jerk for now
  // Compute path unit vector
  double unit_vec[3];

  unit_vec[X_AXIS] = delta_mm[X_AXIS]*inverse_millimeters;
  unit_vec[Y_AXIS] = delta_mm[Y_AXIS]*inverse_millimeters;
  unit_vec[Z_AXIS] = delta_mm[Z_AXIS]*inverse_millimeters;

  // Compute maximum allowable entry speed at junction by centripetal acceleration approximation.
  // Let a circle be tangent to both previous and current path line segments, where the junction
  // deviation is defined as the distance from the junction to the closest edge of the circle,
  // colinear with the circle center. The circular segment joining the two paths represents the
  // path of centripetal acceleration. Solve for max velocity based on max acceleration about the
  // radius of the circle, defined indirectly by junction deviation. This may be also viewed as
  // path width or max_jerk in the previous grbl version. This approach does not actually deviate
  // from path, but used as a robust way to compute cornering speeds, as it takes into account the
  // nonlinearities of both the junction angle and junction velocity.
  double vmax_junction = MINIMUM_PLANNER_SPEED; // Set default max junction speed

  // Skip first block or when previous_nominal_speed is used as a flag for homing and offset cycles.
  if ((block_buffer_head != block_buffer_tail) && (previous_nominal_speed > 0.0)) {
    // Compute cosine of angle between previous and current path. (prev_unit_vec is negative)
    // NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity.
    double cos_theta = - previous_unit_vec[X_AXIS] * unit_vec[X_AXIS]
      - previous_unit_vec[Y_AXIS] * unit_vec[Y_AXIS]
      - previous_unit_vec[Z_AXIS] * unit_vec[Z_AXIS] ;

    // Skip and use default max junction speed for 0 degree acute junction.
    if (cos_theta < 0.95) {
      vmax_junction = min(previous_nominal_speed,block->nominal_speed);
      // Skip and avoid divide by zero for straight junctions at 180 degrees. Limit to min() of nominal speeds.
      if (cos_theta > -0.95) {
        // Compute maximum junction velocity based on maximum acceleration and junction deviation
        double sin_theta_d2 = sqrt(0.5*(1.0-cos_theta)); // Trig half angle identity. Always positive.
        vmax_junction = min(vmax_junction,
        sqrt(block->acceleration * junction_deviation * sin_theta_d2/(1.0-sin_theta_d2)) );
      }
    }
  }
#endif
  // Start with a safe speed
  float vmax_junction = max_xy_jerk / 2;
  float vmax_junction_factor = 1.0; 
  float mz2 = max_z_jerk / 2, me2 = max_e_jerk / 2;
  float csz = current_speed[Z_AXIS], cse = current_speed[E_AXIS];
  if (fabs(csz) > mz2) vmax_junction = min(vmax_junction, mz2);
  if (fabs(cse) > me2) vmax_junction = min(vmax_junction, me2);
  vmax_junction = min(vmax_junction, block->nominal_speed);
  float safe_speed = vmax_junction;

  if ((moves_queued > 1) && (previous_nominal_speed > 0.0001)) {
    float dx = current_speed[X_AXIS] - previous_speed[X_AXIS],
          dy = current_speed[Y_AXIS] - previous_speed[Y_AXIS],
          dz = fabs(csz - previous_speed[Z_AXIS]),
          de = fabs(cse - previous_speed[E_AXIS]),
          jerk = sqrt(dx * dx + dy * dy);

    //    if ((fabs(previous_speed[X_AXIS]) > 0.0001) || (fabs(previous_speed[Y_AXIS]) > 0.0001)) {
    vmax_junction = block->nominal_speed;
    //    }
    if (jerk > max_xy_jerk) vmax_junction_factor = max_xy_jerk / jerk;
    if (dz > max_z_jerk) vmax_junction_factor = min(vmax_junction_factor, max_z_jerk / dz);
    if (de > max_e_jerk) vmax_junction_factor = min(vmax_junction_factor, max_e_jerk / de);

    vmax_junction = min(previous_nominal_speed, vmax_junction * vmax_junction_factor); // Limit speed to max previous speed
  }
  block->max_entry_speed = vmax_junction;

  // Initialize block entry speed. Compute based on deceleration to user-defined MINIMUM_PLANNER_SPEED.
  double v_allowable = max_allowable_speed(-block->acceleration, MINIMUM_PLANNER_SPEED, block->millimeters);
  block->entry_speed = min(vmax_junction, v_allowable);

  // Initialize planner efficiency flags
  // Set flag if block will always reach maximum junction speed regardless of entry/exit speeds.
  // If a block can de/ac-celerate from nominal speed to zero within the length of the block, then
  // the current block and next block junction speeds are guaranteed to always be at their maximum
  // junction speeds in deceleration and acceleration, respectively. This is due to how the current
  // block nominal speed limits both the current and next maximum junction speeds. Hence, in both
  // the reverse and forward planners, the corresponding block junction speed will always be at the
  // the maximum junction speed and may always be ignored for any speed reduction checks.
  block->nominal_length_flag = (block->nominal_speed <= v_allowable); 
  block->recalculate_flag = true; // Always calculate trapezoid for new block

  // Update previous path unit_vector and nominal speed
  for (int i = 0; i < NUM_AXIS; i++) previous_speed[i] = current_speed[i];
  previous_nominal_speed = block->nominal_speed;


#ifdef ADVANCE
  // Calculate advance rate
  if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) {
    block->advance_rate = 0;
    block->advance = 0;
  }
  else {
    long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration_st);
    float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * 
      (current_speed[E_AXIS] * current_speed[E_AXIS] * EXTRUSION_AREA * EXTRUSION_AREA)*256;
    block->advance = advance;
    if(acc_dist == 0) {
      block->advance_rate = 0;
    } 
    else {
      block->advance_rate = advance / (float)acc_dist;
    }
  }
  /*
    SERIAL_ECHO_START;
   SERIAL_ECHOPGM("advance :");
   SERIAL_ECHO(block->advance/256.0);
   SERIAL_ECHOPGM("advance rate :");
   SERIAL_ECHOLN(block->advance_rate/256.0);
   */
#endif // ADVANCE

  calculate_trapezoid_for_block(block, block->entry_speed/block->nominal_speed, safe_speed/block->nominal_speed);

  // Move buffer head
  block_buffer_head = next_buffer_head;

  // Update position
  for (int i = 0; i < NUM_AXIS; i++) position[i] = target[i];

  planner_recalculate();

  st_wake_up();
}
  void plan_buffer_line(const float &x, const float &y, const float &z, const float &e, float feed_rate, const uint8_t &extruder)
#endif  //ENABLE_AUTO_BED_LEVELING
{
  // Calculate the buffer head after we push this byte
  int next_buffer_head = next_block_index(block_buffer_head);

  // If the buffer is full: good! That means we are well ahead of the robot. 
  // Rest here until there is room in the buffer.
  while(block_buffer_tail == next_buffer_head) {
    manage_heater(); 
    manage_inactivity(); 
    lcd_update();
  }

  #ifdef MESH_BED_LEVELING
    if (mbl.active) z += mbl.get_z(x, y);
  #endif

  #ifdef ENABLE_AUTO_BED_LEVELING
    apply_rotation_xyz(plan_bed_level_matrix, x, y, z);
  #endif

  // The target position of the tool in absolute steps
  // Calculate target position in absolute steps
  //this should be done after the wait, because otherwise a M92 code within the gcode disrupts this calculation somehow
  long target[NUM_AXIS];
  target[X_AXIS] = lround(x * axis_steps_per_unit[X_AXIS]);
  target[Y_AXIS] = lround(y * axis_steps_per_unit[Y_AXIS]);
  target[Z_AXIS] = lround(z * axis_steps_per_unit[Z_AXIS]);     
  target[E_AXIS] = lround(e * axis_steps_per_unit[E_AXIS]);

  float dx = target[X_AXIS] - position[X_AXIS],
        dy = target[Y_AXIS] - position[Y_AXIS],
        dz = target[Z_AXIS] - position[Z_AXIS],
        de = target[E_AXIS] - position[E_AXIS];

  #ifdef PREVENT_DANGEROUS_EXTRUDE
    if (de) {
      if (degHotend(active_extruder) < extrude_min_temp) {
        position[E_AXIS] = target[E_AXIS]; //behave as if the move really took place, but ignore E part
        SERIAL_ECHO_START;
        SERIAL_ECHOLNPGM(MSG_ERR_COLD_EXTRUDE_STOP);
      }
      #ifdef PREVENT_LENGTHY_EXTRUDE
        if (labs(de) > axis_steps_per_unit[E_AXIS] * EXTRUDE_MAXLENGTH) {
          position[E_AXIS] = target[E_AXIS]; // Behave as if the move really took place, but ignore E part
          SERIAL_ECHO_START;
          SERIAL_ECHOLNPGM(MSG_ERR_LONG_EXTRUDE_STOP);
        }
      #endif
    }
  #endif

  // Prepare to set up new block
  block_t *block = &block_buffer[block_buffer_head];

  // Mark block as not busy (Not executed by the stepper interrupt)
  block->busy = false;

  // Number of steps for each axis
  #ifdef COREXY
    // corexy planning
    // these equations follow the form of the dA and dB equations on http://www.corexy.com/theory.html
    block->steps[A_AXIS] = labs(dx + dy);
    block->steps[B_AXIS] = labs(dx - dy);
  #else
    // default non-h-bot planning
    block->steps[X_AXIS] = labs(dx);
    block->steps[Y_AXIS] = labs(dy);
  #endif

  block->steps[Z_AXIS] = labs(dz);
  block->steps[E_AXIS] = labs(de);
  block->steps[E_AXIS] *= volumetric_multiplier[active_extruder];
  block->steps[E_AXIS] *= extruder_multiply[active_extruder];
  block->steps[E_AXIS] /= 100;
  block->step_event_count = max(block->steps[X_AXIS], max(block->steps[Y_AXIS], max(block->steps[Z_AXIS], block->steps[E_AXIS])));

  // Bail if this is a zero-length block
  if (block->step_event_count <= dropsegments) return;

  block->fan_speed = fanSpeed;
  #ifdef BARICUDA
    block->valve_pressure = ValvePressure;
    block->e_to_p_pressure = EtoPPressure;
  #endif

  // Compute direction bits for this block 
  uint8_t db = 0;
  #ifdef COREXY
    if (dx < 0) db |= BIT(X_HEAD); // Save the real Extruder (head) direction in X Axis
    if (dy < 0) db |= BIT(Y_HEAD); // ...and Y
    if (dx + dy < 0) db |= BIT(A_AXIS); // Motor A direction
    if (dx - dy < 0) db |= BIT(B_AXIS); // Motor B direction
  #else
    if (dx < 0) db |= BIT(X_AXIS);
    if (dy < 0) db |= BIT(Y_AXIS); 
  #endif
  if (dz < 0) db |= BIT(Z_AXIS);
  if (de < 0) db |= BIT(E_AXIS); 
  block->direction_bits = db;

  block->active_extruder = extruder;

  //enable active axes
  #ifdef COREXY
    if (block->steps[A_AXIS] || block->steps[B_AXIS]) {
      enable_x();
      enable_y();
    }
  #else
    if (block->steps[X_AXIS]) enable_x();
    if (block->steps[Y_AXIS]) enable_y();
  #endif

  #ifndef Z_LATE_ENABLE
    if (block->steps[Z_AXIS]) enable_z();
  #endif

  // Enable extruder(s)
  if (block->steps[E_AXIS]) {
    if (DISABLE_INACTIVE_EXTRUDER) { //enable only selected extruder

      for (int i=0; i<EXTRUDERS; i++)
        if (g_uc_extruder_last_move[i] > 0) g_uc_extruder_last_move[i]--;
      
      switch(extruder) {
        case 0:
          enable_e0();
          g_uc_extruder_last_move[0] = BLOCK_BUFFER_SIZE * 2;
          #if EXTRUDERS > 1
            if (g_uc_extruder_last_move[1] == 0) disable_e1();
            #if EXTRUDERS > 2
              if (g_uc_extruder_last_move[2] == 0) disable_e2();
              #if EXTRUDERS > 3
                if (g_uc_extruder_last_move[3] == 0) disable_e3();
              #endif
            #endif
          #endif
        break;
        #if EXTRUDERS > 1
          case 1:
            enable_e1();
            g_uc_extruder_last_move[1] = BLOCK_BUFFER_SIZE*2;
            if (g_uc_extruder_last_move[0] == 0) disable_e0();
            #if EXTRUDERS > 2
              if (g_uc_extruder_last_move[2] == 0) disable_e2();
              #if EXTRUDERS > 3
                if (g_uc_extruder_last_move[3] == 0) disable_e3();
              #endif
            #endif
          break;
          #if EXTRUDERS > 2
            case 2:
              enable_e2();
              g_uc_extruder_last_move[2] = BLOCK_BUFFER_SIZE*2;
              if (g_uc_extruder_last_move[0] == 0) disable_e0();
              if (g_uc_extruder_last_move[1] == 0) disable_e1();
              #if EXTRUDERS > 3
                if (g_uc_extruder_last_move[3] == 0) disable_e3();
              #endif
            break;
            #if EXTRUDERS > 3
              case 3:
                enable_e3();
                g_uc_extruder_last_move[3] = BLOCK_BUFFER_SIZE*2;
                if (g_uc_extruder_last_move[0] == 0) disable_e0();
                if (g_uc_extruder_last_move[1] == 0) disable_e1();
                if (g_uc_extruder_last_move[2] == 0) disable_e2();
              break;
            #endif // EXTRUDERS > 3
          #endif // EXTRUDERS > 2
        #endif // EXTRUDERS > 1
      }
    }
    else { // enable all
      enable_e0();
      enable_e1();
      enable_e2();
      enable_e3();
    }
  }

  if (block->steps[E_AXIS]) {
    if (feed_rate < minimumfeedrate) feed_rate = minimumfeedrate;
  }
  else if (feed_rate < mintravelfeedrate) feed_rate = mintravelfeedrate;

  /**
   * This part of the code calculates the total length of the movement. 
   * For cartesian bots, the X_AXIS is the real X movement and same for Y_AXIS.
   * But for corexy bots, that is not true. The "X_AXIS" and "Y_AXIS" motors (that should be named to A_AXIS
   * and B_AXIS) cannot be used for X and Y length, because A=X+Y and B=X-Y.
   * So we need to create other 2 "AXIS", named X_HEAD and Y_HEAD, meaning the real displacement of the Head. 
   * Having the real displacement of the head, we can calculate the total movement length and apply the desired speed.
   */ 
  #ifdef COREXY
    float delta_mm[6];
    delta_mm[X_HEAD] = dx / axis_steps_per_unit[A_AXIS];
    delta_mm[Y_HEAD] = dy / axis_steps_per_unit[B_AXIS];
    delta_mm[A_AXIS] = (dx + dy) / axis_steps_per_unit[A_AXIS];
    delta_mm[B_AXIS] = (dx - dy) / axis_steps_per_unit[B_AXIS];
  #else
    float delta_mm[4];
    delta_mm[X_AXIS] = dx / axis_steps_per_unit[X_AXIS];
    delta_mm[Y_AXIS] = dy / axis_steps_per_unit[Y_AXIS];
  #endif
  delta_mm[Z_AXIS] = dz / axis_steps_per_unit[Z_AXIS];
  delta_mm[E_AXIS] = (de / axis_steps_per_unit[E_AXIS]) * volumetric_multiplier[active_extruder] * extruder_multiply[active_extruder] / 100.0;

  if (block->steps[X_AXIS] <= dropsegments && block->steps[Y_AXIS] <= dropsegments && block->steps[Z_AXIS] <= dropsegments) {
    block->millimeters = fabs(delta_mm[E_AXIS]);
  } 
  else {
    block->millimeters = sqrt(
      #ifdef COREXY
        square(delta_mm[X_HEAD]) + square(delta_mm[Y_HEAD])
      #else
        square(delta_mm[X_AXIS]) + square(delta_mm[Y_AXIS])
      #endif
      + square(delta_mm[Z_AXIS])
    );
  }
  float inverse_millimeters = 1.0 / block->millimeters;  // Inverse millimeters to remove multiple divides 

  // Calculate speed in mm/second for each axis. No divide by zero due to previous checks.
  float inverse_second = feed_rate * inverse_millimeters;

  int moves_queued = movesplanned();

  // Slow down when the buffer starts to empty, rather than wait at the corner for a buffer refill
  #if defined(OLD_SLOWDOWN) || defined(SLOWDOWN)
    bool mq = moves_queued > 1 && moves_queued < BLOCK_BUFFER_SIZE / 2;
    #ifdef OLD_SLOWDOWN
      if (mq) feed_rate *= 2.0 * moves_queued / BLOCK_BUFFER_SIZE;
    #endif
    #ifdef SLOWDOWN
      //  segment time im micro seconds
      unsigned long segment_time = lround(1000000.0/inverse_second);
      if (mq) {
        if (segment_time < minsegmenttime) {
          // buffer is draining, add extra time.  The amount of time added increases if the buffer is still emptied more.
          inverse_second = 1000000.0 / (segment_time + lround(2 * (minsegmenttime - segment_time) / moves_queued));
          #ifdef XY_FREQUENCY_LIMIT
            segment_time = lround(1000000.0 / inverse_second);
          #endif
        }
      }
    #endif
  #endif

  block->nominal_speed = block->millimeters * inverse_second; // (mm/sec) Always > 0
  block->nominal_rate = ceil(block->step_event_count * inverse_second); // (step/sec) Always > 0

  #ifdef FILAMENT_SENSOR
    //FMM update ring buffer used for delay with filament measurements
  
    if (extruder == FILAMENT_SENSOR_EXTRUDER_NUM && delay_index2 > -1) {  //only for extruder with filament sensor and if ring buffer is initialized

      const int MMD = MAX_MEASUREMENT_DELAY + 1, MMD10 = MMD * 10;

      delay_dist += delta_mm[E_AXIS];  // increment counter with next move in e axis
      while (delay_dist >= MMD10) delay_dist -= MMD10; // loop around the buffer
      while (delay_dist < 0) delay_dist += MMD10;

      delay_index1 = delay_dist / 10.0;  // calculate index
      delay_index1 = constrain(delay_index1, 0, MAX_MEASUREMENT_DELAY); // (already constrained above)

      if (delay_index1 != delay_index2) { // moved index
        meas_sample = widthFil_to_size_ratio() - 100;  // Subtract 100 to reduce magnitude - to store in a signed char
        while (delay_index1 != delay_index2) {
          // Increment and loop around buffer
          if (++delay_index2 >= MMD) delay_index2 -= MMD;
          delay_index2 = constrain(delay_index2, 0, MAX_MEASUREMENT_DELAY);
          measurement_delay[delay_index2] = meas_sample;
        }
      }
    }
  #endif

  // Calculate and limit speed in mm/sec for each axis
  float current_speed[NUM_AXIS];
  float speed_factor = 1.0; //factor <=1 do decrease speed
  for (int i = 0; i < NUM_AXIS; i++) {
    current_speed[i] = delta_mm[i] * inverse_second;
    float cs = fabs(current_speed[i]), mf = max_feedrate[i];
    if (cs > mf) speed_factor = min(speed_factor, mf / cs);
  }

  // Max segement time in us.
  #ifdef XY_FREQUENCY_LIMIT
    #define MAX_FREQ_TIME (1000000.0 / XY_FREQUENCY_LIMIT)

    // Check and limit the xy direction change frequency
    unsigned char direction_change = block->direction_bits ^ old_direction_bits;
    old_direction_bits = block->direction_bits;
    segment_time = lround((float)segment_time / speed_factor);
  
    long xs0 = axis_segment_time[X_AXIS][0],
         xs1 = axis_segment_time[X_AXIS][1],
         xs2 = axis_segment_time[X_AXIS][2],
         ys0 = axis_segment_time[Y_AXIS][0],
         ys1 = axis_segment_time[Y_AXIS][1],
         ys2 = axis_segment_time[Y_AXIS][2];

    if ((direction_change & BIT(X_AXIS)) != 0) {
      xs2 = axis_segment_time[X_AXIS][2] = xs1;
      xs1 = axis_segment_time[X_AXIS][1] = xs0;
      xs0 = 0;
    }
    xs0 = axis_segment_time[X_AXIS][0] = xs0 + segment_time;

    if ((direction_change & BIT(Y_AXIS)) != 0) {
      ys2 = axis_segment_time[Y_AXIS][2] = axis_segment_time[Y_AXIS][1];
      ys1 = axis_segment_time[Y_AXIS][1] = axis_segment_time[Y_AXIS][0];
      ys0 = 0;
    }
    ys0 = axis_segment_time[Y_AXIS][0] = ys0 + segment_time;

    long max_x_segment_time = max(xs0, max(xs1, xs2)),
         max_y_segment_time = max(ys0, max(ys1, ys2)),
         min_xy_segment_time = min(max_x_segment_time, max_y_segment_time);
    if (min_xy_segment_time < MAX_FREQ_TIME) {
      float low_sf = speed_factor * min_xy_segment_time / MAX_FREQ_TIME;
      speed_factor = min(speed_factor, low_sf);
    }
  #endif // XY_FREQUENCY_LIMIT

  // Correct the speed  
  if (speed_factor < 1.0) {
    for (unsigned char i = 0; i < NUM_AXIS; i++) current_speed[i] *= speed_factor;
    block->nominal_speed *= speed_factor;
    block->nominal_rate *= speed_factor;
  }

  // Compute and limit the acceleration rate for the trapezoid generator.  
  float steps_per_mm = block->step_event_count / block->millimeters;
  long bsx = block->steps[X_AXIS], bsy = block->steps[Y_AXIS], bsz = block->steps[Z_AXIS], bse = block->steps[E_AXIS];
  if (bsx == 0 && bsy == 0 && bsz == 0) {
    block->acceleration_st = ceil(retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
  }
  else if (bse == 0) {
    block->acceleration_st = ceil(travel_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
  }
  else {
    block->acceleration_st = ceil(acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
  }
  // Limit acceleration per axis
  unsigned long acc_st = block->acceleration_st,
                xsteps = axis_steps_per_sqr_second[X_AXIS],
                ysteps = axis_steps_per_sqr_second[Y_AXIS],
                zsteps = axis_steps_per_sqr_second[Z_AXIS],
                esteps = axis_steps_per_sqr_second[E_AXIS];
  if ((float)acc_st * bsx / block->step_event_count > xsteps) acc_st = xsteps;
  if ((float)acc_st * bsy / block->step_event_count > ysteps) acc_st = ysteps;
  if ((float)acc_st * bsz / block->step_event_count > zsteps) acc_st = zsteps;
  if ((float)acc_st * bse / block->step_event_count > esteps) acc_st = esteps;
 
  block->acceleration_st = acc_st;
  block->acceleration = acc_st / steps_per_mm;
  block->acceleration_rate = (long)(acc_st * 16777216.0 / (F_CPU / 8.0));

  #if 0  // Use old jerk for now
    // Compute path unit vector
    double unit_vec[3];

    unit_vec[X_AXIS] = delta_mm[X_AXIS]*inverse_millimeters;
    unit_vec[Y_AXIS] = delta_mm[Y_AXIS]*inverse_millimeters;
    unit_vec[Z_AXIS] = delta_mm[Z_AXIS]*inverse_millimeters;

    // Compute maximum allowable entry speed at junction by centripetal acceleration approximation.
    // Let a circle be tangent to both previous and current path line segments, where the junction
    // deviation is defined as the distance from the junction to the closest edge of the circle,
    // colinear with the circle center. The circular segment joining the two paths represents the
    // path of centripetal acceleration. Solve for max velocity based on max acceleration about the
    // radius of the circle, defined indirectly by junction deviation. This may be also viewed as
    // path width or max_jerk in the previous grbl version. This approach does not actually deviate
    // from path, but used as a robust way to compute cornering speeds, as it takes into account the
    // nonlinearities of both the junction angle and junction velocity.
    double vmax_junction = MINIMUM_PLANNER_SPEED; // Set default max junction speed

    // Skip first block or when previous_nominal_speed is used as a flag for homing and offset cycles.
    if ((block_buffer_head != block_buffer_tail) && (previous_nominal_speed > 0.0)) {
      // Compute cosine of angle between previous and current path. (prev_unit_vec is negative)
      // NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity.
      double cos_theta = - previous_unit_vec[X_AXIS] * unit_vec[X_AXIS]
        - previous_unit_vec[Y_AXIS] * unit_vec[Y_AXIS]
        - previous_unit_vec[Z_AXIS] * unit_vec[Z_AXIS] ;

      // Skip and use default max junction speed for 0 degree acute junction.
      if (cos_theta < 0.95) {
        vmax_junction = min(previous_nominal_speed,block->nominal_speed);
        // Skip and avoid divide by zero for straight junctions at 180 degrees. Limit to min() of nominal speeds.
        if (cos_theta > -0.95) {
          // Compute maximum junction velocity based on maximum acceleration and junction deviation
          double sin_theta_d2 = sqrt(0.5*(1.0-cos_theta)); // Trig half angle identity. Always positive.
          vmax_junction = min(vmax_junction,
          sqrt(block->acceleration * junction_deviation * sin_theta_d2/(1.0-sin_theta_d2)) );
        }
      }
    }
  #endif

  // Start with a safe speed
  float vmax_junction = max_xy_jerk / 2;
  float vmax_junction_factor = 1.0; 
  float mz2 = max_z_jerk / 2, me2 = max_e_jerk / 2;
  float csz = current_speed[Z_AXIS], cse = current_speed[E_AXIS];
  if (fabs(csz) > mz2) vmax_junction = min(vmax_junction, mz2);
  if (fabs(cse) > me2) vmax_junction = min(vmax_junction, me2);
  vmax_junction = min(vmax_junction, block->nominal_speed);
  float safe_speed = vmax_junction;

  if ((moves_queued > 1) && (previous_nominal_speed > 0.0001)) {
    float dx = current_speed[X_AXIS] - previous_speed[X_AXIS],
          dy = current_speed[Y_AXIS] - previous_speed[Y_AXIS],
          dz = fabs(csz - previous_speed[Z_AXIS]),
          de = fabs(cse - previous_speed[E_AXIS]),
          jerk = sqrt(dx * dx + dy * dy);

    //    if ((fabs(previous_speed[X_AXIS]) > 0.0001) || (fabs(previous_speed[Y_AXIS]) > 0.0001)) {
    vmax_junction = block->nominal_speed;
    //    }
    if (jerk > max_xy_jerk) vmax_junction_factor = max_xy_jerk / jerk;
    if (dz > max_z_jerk) vmax_junction_factor = min(vmax_junction_factor, max_z_jerk / dz);
    if (de > max_e_jerk) vmax_junction_factor = min(vmax_junction_factor, max_e_jerk / de);

    vmax_junction = min(previous_nominal_speed, vmax_junction * vmax_junction_factor); // Limit speed to max previous speed
  }
  block->max_entry_speed = vmax_junction;

  // Initialize block entry speed. Compute based on deceleration to user-defined MINIMUM_PLANNER_SPEED.
  double v_allowable = max_allowable_speed(-block->acceleration, MINIMUM_PLANNER_SPEED, block->millimeters);
  block->entry_speed = min(vmax_junction, v_allowable);

  // Initialize planner efficiency flags
  // Set flag if block will always reach maximum junction speed regardless of entry/exit speeds.
  // If a block can de/ac-celerate from nominal speed to zero within the length of the block, then
  // the current block and next block junction speeds are guaranteed to always be at their maximum
  // junction speeds in deceleration and acceleration, respectively. This is due to how the current
  // block nominal speed limits both the current and next maximum junction speeds. Hence, in both
  // the reverse and forward planners, the corresponding block junction speed will always be at the
  // the maximum junction speed and may always be ignored for any speed reduction checks.
  block->nominal_length_flag = (block->nominal_speed <= v_allowable); 
  block->recalculate_flag = true; // Always calculate trapezoid for new block

  // Update previous path unit_vector and nominal speed
  for (int i = 0; i < NUM_AXIS; i++) previous_speed[i] = current_speed[i];
  previous_nominal_speed = block->nominal_speed;

  #ifdef ADVANCE
    // Calculate advance rate
    if (!bse || (!bsx && !bsy && !bsz)) {
      block->advance_rate = 0;
      block->advance = 0;
    }
    else {
      long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration_st);
      float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * (cse * cse * EXTRUSION_AREA * EXTRUSION_AREA) * 256;
      block->advance = advance;
      block->advance_rate = acc_dist ? advance / (float)acc_dist : 0;
    }
    /*
      SERIAL_ECHO_START;
     SERIAL_ECHOPGM("advance :");
     SERIAL_ECHO(block->advance/256.0);
     SERIAL_ECHOPGM("advance rate :");
     SERIAL_ECHOLN(block->advance_rate/256.0);
     */
  #endif // ADVANCE

  calculate_trapezoid_for_block(block, block->entry_speed / block->nominal_speed, safe_speed / block->nominal_speed);

  // Move buffer head
  block_buffer_head = next_buffer_head;

  // Update position
  for (int i = 0; i < NUM_AXIS; i++) position[i] = target[i];

  planner_recalculate();

  st_wake_up();

} // plan_buffer_line()
void linear_move() { // make linear move with preset speeds and destinations, see G0 and G1
    //Determine direction of movement
    if (destination_x > current_x) {
        p_X_dir = !INVERT_X_DIR;
    } else {
        p_X_dir = INVERT_X_DIR;
    }

    if (destination_y > current_y) {
        p_Y_dir = !INVERT_Y_DIR;
    } else {
        p_Y_dir = INVERT_Y_DIR;
    }

    if (destination_z > current_z) {
        p_Z_dir = !INVERT_Z_DIR;
    } else {
        p_Z_dir = INVERT_Z_DIR;
    }

    if (destination_e > current_e) {
        p_E_dir = !INVERT_E_DIR;
    } else {
        p_E_dir = INVERT_E_DIR;
    }

    //Only enable axis that are moving. If the axis doesn't need to move then it can stay disabled depending on configuration.
    if (x_steps_remaining) enable_x();
    if (y_steps_remaining) enable_y();
    if (z_steps_remaining) enable_z();
    if (e_steps_remaining) enable_e();

    check_x_min_endstop();
    check_y_min_endstop();
    check_z_min_endstop();

    previous_millis_heater = millis();

    while (x_steps_remaining + y_steps_remaining + z_steps_remaining + e_steps_remaining > 0) { // move until no more steps remain
        if (x_steps_remaining>0) {
            if ((micros()-previous_micros_x) >= x_interval) {
                do_x_step();
                x_steps_remaining--;
            }
            check_x_min_endstop();
            led1 = 1;
        } else {
            led1 = 0;
            wait_us(2);
        }

        if (y_steps_remaining>0) {
            if ((micros()-previous_micros_y) >= y_interval) {
                do_y_step();
                y_steps_remaining--;
            }
            check_y_min_endstop();
            led2=1;
        } else {
            led2=0;
            wait_us(2);
        }

        if (z_steps_remaining>0) {
            if ((micros()-previous_micros_z) >= z_interval) {
                do_z_step();
                z_steps_remaining--;
            }
            check_z_min_endstop();
            led3=1;
        } else {
            led3=0;
            wait_us(2);
        }

        if (e_steps_remaining>0) {
            if ((micros()-previous_micros_e) >= e_interval) {
                do_e_step();
                e_steps_remaining--;
                led4=1;
            }
        } else {
            led4=0;
            wait_us(2);
        }

        if ( (millis() - previous_millis_heater) >= 500 ) {
            manage_heater();
            previous_millis_heater = millis();

            manage_inactivity(2);
        }

        wait_us(2);
    }

    led1=0;
    led2=0;
    led3=0;
    led4=0;

    if (DISABLE_X) disable_x();
    if (DISABLE_Y) disable_y();
    if (DISABLE_Z) disable_z();
    if (DISABLE_E) disable_e();

    // Update current position partly based on direction, we probably can combine this with the direction code above...
    if (destination_x > current_x) current_x = current_x + x_steps_to_take/x_steps_per_unit;
    else current_x = current_x - x_steps_to_take/x_steps_per_unit;
    if (destination_y > current_y) current_y = current_y + y_steps_to_take/y_steps_per_unit;
    else current_y = current_y - y_steps_to_take/y_steps_per_unit;
    if (destination_z > current_z) current_z = current_z + z_steps_to_take/z_steps_per_unit;
    else current_z = current_z - z_steps_to_take/z_steps_per_unit;
    if (destination_e > current_e) current_e = current_e + e_steps_to_take/e_steps_per_unit;
    else current_e = current_e - e_steps_to_take/e_steps_per_unit;
}
Example #10
0
/*----------------------------------------
*
* 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]);
  }

}
Example #11
0
// Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in 
// mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration
// calculation the caller must also provide the physical length of the line in millimeters.
void plan_buffer_line(float x, float y, float z, float e, float feed_rate) {
    int current_temp;
  
    // Calculate the buffer head after we push this byte
    int next_buffer_head = next_block_index(block_buffer_head);

    // If the buffer is full: good! That means we are well ahead of the robot. 
    // Rest here until there is room in the buffer.
    while(block_buffer_tail == next_buffer_head) { 
        manage_inactivity(1); 
#if (MINIMUM_FAN_START_SPEED > 0)
        manage_fan_start_speed();
#endif 
    }

    // The target position of the tool in absolute steps
    // Calculate target position in absolute steps
    //this should be done after the wait, because otherwise a M92 code within the gcode disrupts this calculation somehow
    long target[4];
    target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]);
    target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]);
    target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]);     
    target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]);
  
    current_temp = analog2temp( current_raw );
  
#if PREVENT_DANGEROUS_EXTRUDE > 0
    if(target[E_AXIS]!=position[E_AXIS]) {
        if(current_temp < EXTRUDE_MINTEMP && prevent_cold_extrude) {
            position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part
            serial_send(TXT_COLD_EXTRUSION_PREVENTED_CRLF);
        }
    
#if PREVENT_LENGTHY_EXTRUDE > 0
        if(labs(target[E_AXIS]-position[E_AXIS]) > axis_steps_per_unit[E_AXIS] * EXTRUDE_MAXLENGTH) {
            position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part
            serial_send(TXT_LONG_EXTRUSION_PREVENTED_CRLF);
        }
#endif
    }
#endif
    
    // Prepare to set up new block
    block_t *block = &block_buffer[block_buffer_head];
  
    // Mark block as not busy (Not executed by the stepper interrupt)
    block->busy = 0;

    // Number of steps for each axis
    block->steps_x = labs(target[X_AXIS]-position[X_AXIS]);
    block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]);
    block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]);
    block->steps_e = labs(target[E_AXIS]-position[E_AXIS]);
    block->steps_e = (long)(block->steps_e * extrudemultiply / 100.0);
    block->step_event_count = MAX(block->steps_x, MAX(block->steps_y, MAX(block->steps_z, block->steps_e)));
  
    // Bail if this is a zero-length block
    if (block->step_event_count <= DROP_SEGMENTS) return;

    // Compute direction bits for this block 
    block->direction_bits = 0;
    if (target[X_AXIS] < position[X_AXIS]) block->direction_bits |= (1<<X_AXIS);
    if (target[Y_AXIS] < position[Y_AXIS]) block->direction_bits |= (1<<Y_AXIS);
    if (target[Z_AXIS] < position[Z_AXIS]) block->direction_bits |= (1<<Z_AXIS);
    if (target[E_AXIS] < position[E_AXIS]) { 
            block->direction_bits |= (1<<E_AXIS); 
            //High Feedrate for retract
            max_E_feedrate_calc = MAX_RETRACT_FEEDRATE;
            retract_feedrate_aktiv = 1;
    }
    else {
        if(retract_feedrate_aktiv) {
                if(block->steps_e > 0) retract_feedrate_aktiv = 0;
        }
        else max_E_feedrate_calc = max_feedrate[E_AXIS]; 
    }

#ifdef DELAY_ENABLE
    if(block->steps_x != 0) {
        enable_x();
        delayMicroseconds(DELAY_ENABLE);
    }
    if(block->steps_y != 0) {
        enable_y();
        delayMicroseconds(DELAY_ENABLE);
    }
    if(block->steps_z != 0) {
        enable_z();
        delayMicroseconds(DELAY_ENABLE);
    }
    if(block->steps_e != 0) {
        enable_e();
        delayMicroseconds(DELAY_ENABLE);
    }
#else
    //enable active axes
    if(block->steps_x != 0) enable_x();
    if(block->steps_y != 0) enable_y();
    if(block->steps_z != 0) enable_z();
    if(block->steps_e != 0) enable_e();
#endif 
 
    if (block->steps_e == 0) {
        if(feed_rate<mintravelfeedrate) feed_rate=mintravelfeedrate;
    }
    else {
    	if(feed_rate<minimumfeedrate) feed_rate=minimumfeedrate;
    } 

    // slow down when the buffer starts to empty, rather than wait at the corner for a buffer refill
    int moves_queued=(block_buffer_head-block_buffer_tail + block_buffer_size) & block_buffer_mask;
#ifdef SLOWDOWN  
    if(moves_queued < (block_buffer_size * 0.5) && moves_queued > MIN_MOVES_QUEUED_FOR_SLOWDOWN)
        feed_rate = feed_rate*moves_queued / (float)(block_buffer_size * 0.5); 
#endif

    float delta_mm[4];
    delta_mm[X_AXIS] = (target[X_AXIS]-position[X_AXIS])/(float)(axis_steps_per_unit[X_AXIS]);
    delta_mm[Y_AXIS] = (target[Y_AXIS]-position[Y_AXIS])/(float)(axis_steps_per_unit[Y_AXIS]);
    delta_mm[Z_AXIS] = (target[Z_AXIS]-position[Z_AXIS])/(float)(axis_steps_per_unit[Z_AXIS]);
    //delta_mm[E_AXIS] = (target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS];
    delta_mm[E_AXIS] = ((target[E_AXIS]-position[E_AXIS])/(float)(axis_steps_per_unit[E_AXIS]))*extrudemultiply/100.0;
  
    if ( block->steps_x <= DROP_SEGMENTS && block->steps_y <= DROP_SEGMENTS && block->steps_z <= DROP_SEGMENTS )
        block->millimeters = fabs(delta_mm[E_AXIS]);
    else
        block->millimeters = sqrt(square(delta_mm[X_AXIS]) + square(delta_mm[Y_AXIS]) + square(delta_mm[Z_AXIS]));
  
    float inverse_millimeters = 1.0/(float)(block->millimeters);  // Inverse millimeters to remove multiple divides 
  
    // Calculate speed in mm/second for each axis. No divide by zero due to previous checks.
    float inverse_second = feed_rate * inverse_millimeters;
  
    block->nominal_speed = block->millimeters * inverse_second; // (mm/sec) Always > 0
    block->nominal_rate = ceil(block->step_event_count * inverse_second); // (step/sec) Always > 0
  
    /*
      #ifdef SLOWDOWN
      //  segment time im micro seconds
      long segment_time = lround(1000000.0/inverse_second);
      if ((moves_queued>0) && (moves_queued < (BLOCK_BUFFER_SIZE - 4))) {
      if (segment_time<minsegmenttime)  { // buffer is draining, add extra time.  The amount of time added increases if the buffer is still emptied more.
      segment_time=segment_time+lround(2*(minsegmenttime-segment_time)/moves_queued);
      }
      }
      else {
      if (segment_time<minsegmenttime) segment_time=minsegmenttime;
      }
      #endif
      //  END OF SLOW DOWN SECTION
      */

    // Calculate and limit speed in mm/sec for each axis
    float current_speed[4];
    float speed_factor = 1.0; //factor <=1 do decrease speed
    for(int i=0; i < 3; i++) {
        current_speed[i] = delta_mm[i] * inverse_second;
        if(fabs(current_speed[i]) > max_feedrate[i])
            speed_factor = fmin(speed_factor, max_feedrate[i] / fabs(current_speed[i]));
    }
  
    current_speed[E_AXIS] = delta_mm[E_AXIS] * inverse_second;
    if(fabs(current_speed[E_AXIS]) > max_E_feedrate_calc)
        speed_factor = fmin(speed_factor, max_E_feedrate_calc / fabs(current_speed[E_AXIS]));


    // Correct the speed  
    if( speed_factor < 1.0)  {
            for(unsigned char i=0; i < 4; i++) current_speed[i] *= speed_factor;
            block->nominal_speed *= speed_factor;
            block->nominal_rate *= speed_factor;
    }
    
    // Compute and limit the acceleration rate for the trapezoid generator.  
    float steps_per_mm = block->step_event_count/(float)(block->millimeters);
    if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) 
        block->acceleration_st = ceil(retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
    else {
        block->acceleration_st = ceil(move_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
        // Limit acceleration per axis
        if(((float)block->acceleration_st * (float)block->steps_x / (float)block->step_event_count) > axis_steps_per_sqr_second[X_AXIS])
            block->acceleration_st = axis_steps_per_sqr_second[X_AXIS];
        if(((float)block->acceleration_st * (float)block->steps_y / (float)block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS])
	
            block->acceleration_st = axis_steps_per_sqr_second[Y_AXIS];
        if(((float)block->acceleration_st * (float)block->steps_e / (float)block->step_event_count) > axis_steps_per_sqr_second[E_AXIS])
            block->acceleration_st = axis_steps_per_sqr_second[E_AXIS];
        if(((float)block->acceleration_st * (float)block->steps_z / (float)block->step_event_count ) > axis_steps_per_sqr_second[Z_AXIS])
            block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS];
    }
  
    block->acceleration = block->acceleration_st / (float)(steps_per_mm);
    block->acceleration_rate = (long)((float)block->acceleration_st * 8.388608);
  
#if 0  // Use old jerk for now
    // Compute path unit vector
    double unit_vec[3];

    unit_vec[X_AXIS] = delta_mm[X_AXIS]*inverse_millimeters;
    unit_vec[Y_AXIS] = delta_mm[Y_AXIS]*inverse_millimeters;
    unit_vec[Z_AXIS] = delta_mm[Z_AXIS]*inverse_millimeters;
  
    // Compute maximum allowable entry speed at junction by centripetal acceleration approximation.
    // Let a circle be tangent to both previous and current path line segments, where the junction
    // deviation is defined as the distance from the junction to the closest edge of the circle,
    // colinear with the circle center. The circular segment joining the two paths represents the
    // path of centripetal acceleration. Solve for max velocity based on max acceleration about the
    // radius of the circle, defined indirectly by junction deviation. This may be also viewed as
    // path width or max_jerk in the previous grbl version. This approach does not actually deviate
    // from path, but used as a robust way to compute cornering speeds, as it takes into account the
    // nonlinearities of both the junction angle and junction velocity.
    double vmax_junction = MINIMUM_PLANNER_SPEED; // Set default max junction speed

    // Skip first block or when previous_nominal_speed is used as a flag for homing and offset cycles.
    if ((block_buffer_head != block_buffer_tail) && (previous_nominal_speed > 0.0)) {
        // Compute cosine of angle between previous and current path. (prev_unit_vec is negative)
        // NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity.
        double cos_theta = - previous_unit_vec[X_AXIS] * unit_vec[X_AXIS]
            - previous_unit_vec[Y_AXIS] * unit_vec[Y_AXIS]
            - previous_unit_vec[Z_AXIS] * unit_vec[Z_AXIS] ;
                           
        // Skip and use default max junction speed for 0 degree acute junction.
        if (cos_theta < 0.95) {
            vmax_junction = min(previous_nominal_speed,block->nominal_speed);
            // Skip and avoid divide by zero for straight junctions at 180 degrees. Limit to min() of nominal speeds.
            if (cos_theta > -0.95) {
                // Compute maximum junction velocity based on maximum acceleration and junction deviation
                double sin_theta_d2 = sqrt(0.5*(1.0-cos_theta)); // Trig half angle identity. Always positive.
                vmax_junction = min(vmax_junction,
                                    sqrt(block->acceleration * junction_deviation * sin_theta_d2/(float)(1.0-sin_theta_d2)) );
            }
        }
    }
#endif
    // Start with a safe speed
    float vmax_junction = max_xy_jerk/2.0; 
    float vmax_junction_factor = 1.0; 

    if(fabs(current_speed[Z_AXIS]) > max_z_jerk/2.0) vmax_junction = fmin(vmax_junction, max_z_jerk/2.0);
    if(fabs(current_speed[E_AXIS]) > max_e_jerk/2.0) vmax_junction = fmin(vmax_junction, max_e_jerk/2.0);
    if(G92_reset_previous_speed == 1) {
            vmax_junction = 0.1;
            G92_reset_previous_speed = 0;  
    }

    vmax_junction = fmin(vmax_junction, block->nominal_speed);
    float safe_speed = vmax_junction;

    if ((moves_queued > 1) && (previous_nominal_speed > 0.0001)) {
        float jerk = sqrt(pow((current_speed[X_AXIS]-previous_speed[X_AXIS]), 2)+pow((current_speed[Y_AXIS]-previous_speed[Y_AXIS]), 2));
        //    if((fabs(previous_speed[X_AXIS]) > 0.0001) || (fabs(previous_speed[Y_AXIS]) > 0.0001)) {
        vmax_junction = block->nominal_speed;
        //    }
        if (jerk > max_xy_jerk) vmax_junction_factor = (max_xy_jerk/(float)(jerk));
        if(fabs(current_speed[Z_AXIS] - previous_speed[Z_AXIS]) > max_z_jerk)
            vmax_junction_factor= fmin(vmax_junction_factor, (max_z_jerk/fabs(current_speed[Z_AXIS] - previous_speed[Z_AXIS])));
        if(fabs(current_speed[E_AXIS] - previous_speed[E_AXIS]) > max_e_jerk)
            vmax_junction_factor = fmin(vmax_junction_factor, (max_e_jerk/fabs(current_speed[E_AXIS] - previous_speed[E_AXIS])));
        vmax_junction = fmin(previous_nominal_speed, vmax_junction * vmax_junction_factor); // Limit speed to max previous speed
    }
  
  
    block->max_entry_speed = vmax_junction;

    // Initialize block entry speed. Compute based on deceleration to user-defined MINIMUM_PLANNER_SPEED.
    double v_allowable = max_allowable_speed(-block->acceleration,MINIMUM_PLANNER_SPEED,block->millimeters);
    block->entry_speed = fmin(vmax_junction, v_allowable);
  
    // Initialize planner efficiency flags
    // Set flag if block will always reach maximum junction speed regardless of entry/exit speeds.
    // If a block can de/ac-celerate from nominal speed to zero within the length of the block, then
    // the current block and next block junction speeds are guaranteed to always be at their maximum
    // junction speeds in deceleration and acceleration, respectively. This is due to how the current
    // block nominal speed limits both the current and next maximum junction speeds. Hence, in both
    // the reverse and forward planners, the corresponding block junction speed will always be at the
    // the maximum junction speed and may always be ignored for any speed reduction checks.
    if (block->nominal_speed <= v_allowable) block->nominal_length_flag = 1;
    else block->nominal_length_flag = 0;
    block->recalculate_flag = 1; // Always calculate trapezoid for new block
  
    // Update previous path unit_vector and nominal speed
    memcpy(previous_speed, current_speed, sizeof(previous_speed)); // previous_speed[] = current_speed[]
    previous_nominal_speed = block->nominal_speed;
  
    calculate_trapezoid_for_block(block, block->entry_speed/(float)(block->nominal_speed),
                                  safe_speed/(float)(block->nominal_speed));
    
    // Move buffer head
    CRITICAL_SECTION_START;
    block_buffer_head = next_buffer_head;
    CRITICAL_SECTION_END;
  
    // Update position
    memcpy(position, target, sizeof(target)); // position[] = target[]

    planner_recalculate();
#ifdef AUTOTEMP
    getHighESpeed();
#endif
    st_wake_up();
}