void CardReader::unparseKeyLine(const char *key, char *value) {
  if (!cardOK || !isFileOpen()) return;
  file.writeError = false;
  file.write(key);
  if (file.writeError) {
    ECHO_LM(ER, MSG_SD_ERR_WRITE_TO_FILE);
    return;
  }
  
  file.writeError = false;
  file.write("=");
  if (file.writeError) {
    ECHO_LM(ER, MSG_SD_ERR_WRITE_TO_FILE);
    return;
  }
  
  file.writeError = false;
  file.write(value);
  if (file.writeError) {
    ECHO_LM(ER, MSG_SD_ERR_WRITE_TO_FILE);
    return;
  }

  file.writeError = false;
  file.write("\n");
  if (file.writeError) {
    ECHO_LM(ER, MSG_SD_ERR_WRITE_TO_FILE);
    return;
  }
}
void CardReader::initsd() {
  cardOK = false;
  if (root.isOpen()) root.close();

  #ifdef SDSLOW
    #define SPI_SPEED SPI_HALF_SPEED
  #else
    #define SPI_SPEED SPI_FULL_SPEED
  #endif

  if (!card.init(SPI_SPEED,SDSS)
    #if defined(LCD_SDSS) && (LCD_SDSS != SDSS)
      && !card.init(SPI_SPEED, LCD_SDSS)
    #endif
  ) {
    ECHO_LM(DB, MSG_SD_INIT_FAIL);
  }
  else if (!volume.init(&card)) {
    ECHO_LM(ER, MSG_SD_VOL_INIT_FAIL);
  }
  else if (!root.openRoot(&volume)) {
    ECHO_LM(ER, MSG_SD_OPENROOT_FAIL);
  }
  else {
    cardOK = true;
    ECHO_LM(DB, MSG_SD_CARD_OK);
  }
  workDir = root;
  curDir = &root;
  /*
  if (!workDir.openRoot(&volume)) {
    ECHO_EM(MSG_SD_WORKDIR_FAIL);
  }
  */
}
示例#3
0
void CardReader::initsd() {
  cardOK = false;
  if (root.isOpen()) root.close();

  #if ENABLED(SDEXTRASLOW)
    #define SPI_SPEED SPI_QUARTER_SPEED
  #elif ENABLED(SDSLOW)
    #define SPI_SPEED SPI_HALF_SPEED
  #else
    #define SPI_SPEED SPI_FULL_SPEED
  #endif

  if(!fat.begin(SDSS, SPI_SPEED)
    #if defined(LCD_SDSS) && (LCD_SDSS != SDSS)
      && !fat.begin(LCD_SDSS, SPI_SPEED)
    #endif
  ) {
    ECHO_LM(ER, SERIAL_SD_INIT_FAIL);
  }
  else {
    cardOK = true;
    ECHO_LM(DB, SERIAL_SD_CARD_OK);
  }
  fat.chdir(true);
  root = *fat.vwd();
  workDir = root;
  curDir = &root;
}
  void ConfigSD_PrintSettings(bool forReplay) {
    // Always have this function, even with SD_SETTINGS disabled, the current values will be shown

    #if HAS(POWER_CONSUMPTION_SENSOR)
      if (!forReplay) {
        ECHO_LM(INFO, "Watt/h consumed:");
      }
      ECHO_LVM(INFO, power_consumption_hour," Wh");
    #endif

    if (!forReplay) {
      ECHO_LM(INFO, "Power on time:");
    }
    char time[30];
    unsigned int day = printer_usage_seconds / 60 / 60 / 24, hours = (printer_usage_seconds / 60 / 60) % 24, minutes = (printer_usage_seconds / 60) % 60;
    sprintf_P(time, PSTR("  %i " MSG_END_DAY " %i " MSG_END_HOUR " %i " MSG_END_MINUTE), day, hours, minutes);
    ECHO_LT(INFO, time);

    if (!forReplay) {
      ECHO_LM(INFO, "Filament printed:");
    }
    char lung[30];
    unsigned int  kmeter = (long)printer_usage_filament / 1000 / 1000,
                  meter = ((long)printer_usage_filament / 1000) % 1000,
                  centimeter = ((long)printer_usage_filament / 10) % 100,
                  millimeter = ((long)printer_usage_filament) % 10;
    sprintf_P(lung, PSTR("  %i Km %i m %i cm %i mm"), kmeter, meter, centimeter, millimeter);
    ECHO_LT(INFO, lung);
  }
/**
* Configuration on SD card
*
* Author: Simone Primarosa
*
*/
void ConfigSD_ResetDefault() {
  #if HAS(POWER_CONSUMPTION_SENSOR)
    power_consumption_hour = 0;
  #endif
  print_job_counter.initStats();
  ECHO_LM(OK, "Hardcoded SD Default Settings Loaded");
}
/**
 * Configuration on SD card
 *
 * Author: Simone Primarosa
 *
 */
void ConfigSD_ResetDefault() {
  #if HAS(POWER_CONSUMPTION_SENSOR)
   power_consumption_hour = 0;
  #endif
  printer_usage_seconds  = 0;
  printer_usage_filament = 0;
  ECHO_LM(OK, "Hardcoded SD Default Settings Loaded");
}
示例#7
0
 bool NexUpload::_checkFile(void) {
   ECHO_LMT(DB, "Start checkFile ", _file_name);
   if (!card.selectFile(_file_name)) {
     ECHO_LM(ER, "file is not exit");
     return 0;
   }
   _unuploadByte = card.fileSize;
   return 1;
 }
示例#8
0
 void NexUpload::startUpload(void) {
   if (!_checkFile()) {
     ECHO_LM(ER, "The file is error");
     return;
   }
   if (_getBaudrate() == 0) {
     ECHO_LM(ER, "baudrate error");
     return;
   }
   if (!_setUploadBaudrate(_upload_baudrate)) {
     ECHO_LM(ER, "modify baudrate error");
     return;
   }
   if (!_uploadTftFile()) {
     ECHO_LM(ER, "upload file error");
     return;
   }
   card.closeFile();
   ECHO_LM(DB, "upload ok");
 }
void _EEPROM_writeData(int& pos, uint8_t* value, uint8_t size) {
  uint8_t c;
  while(size--) {
    eeprom_write_byte((unsigned char*)pos, *value);
    c = eeprom_read_byte((unsigned char*)pos);
    if (c != *value) {
      ECHO_LM(ER, SERIAL_ERR_EEPROM_WRITE);
    }
    pos++;
    value++;
  };
}
示例#10
0
void CardReader::write_command(char* buf) {
  char* begin = buf;
  char* npos = 0;
  char* end = buf + strlen(buf) - 1;
  file.writeError = false;
  if ((npos = strchr(buf, 'N')) != NULL) {
    begin = strchr(npos, ' ') + 1;
    end = strchr(npos, '*') - 1;
  }
  end[1] = '\r';
  end[2] = '\n';
  end[3] = '\0';
  file.write(begin);
  if (file.writeError) {
    ECHO_LM(ER, SERIAL_SD_ERR_WRITE_TO_FILE);
  }
}
/**
 * M502 - Reset Configuration
 */
void Config_ResetDefault() {
  float tmp1[] = DEFAULT_AXIS_STEPS_PER_UNIT;
  float tmp2[] = DEFAULT_MAX_FEEDRATE;
  float tmp3[] = DEFAULT_MAX_ACCELERATION;
  float tmp4[] = DEFAULT_RETRACT_ACCELERATION;
  float tmp5[] = DEFAULT_EJERK;
  float tmp6[] = DEFAULT_Kp;
  float tmp7[] = DEFAULT_Ki;
  float tmp8[] = DEFAULT_Kd;
  float tmp9[] = DEFAULT_Kc;

  #if ENABLED(HOTEND_OFFSET_X) && ENABLED(HOTEND_OFFSET_Y) && ENABLED(HOTEND_OFFSET_Z)
    float tmp10[] = HOTEND_OFFSET_X;
    float tmp11[] = HOTEND_OFFSET_Y;
    float tmp12[] = HOTEND_OFFSET_Z;
  #endif

  #if MB(ALLIGATOR)
    float tmp13[] = MOTOR_CURRENT;
    for (int8_t i = 0; i < 3 + DRIVER_EXTRUDERS; i++)
      motor_current[i] = tmp13[i];
  #endif

  for (int8_t i = 0; i < 3 + EXTRUDERS; i++) {
    planner.axis_steps_per_mm[i] = tmp1[i];
    planner.max_feedrate[i] = tmp2[i];
    planner.max_acceleration_mm_per_s2[i] = tmp3[i];
  }

  for (int8_t i = 0; i < EXTRUDERS; i++) {
    planner.retract_acceleration[i] = tmp4[i];
    planner.max_e_jerk[i] = tmp5[i];
  }

  for (int8_t i = 0; i < HOTENDS; i++) {
    #if ENABLED(HOTEND_OFFSET_X) && ENABLED(HOTEND_OFFSET_Y) && ENABLED(HOTEND_OFFSET_Z)
      hotend_offset[X_AXIS][i] = tmp10[i];
      hotend_offset[Y_AXIS][i] = tmp11[i];
      hotend_offset[Z_AXIS][i] = tmp12[i];
    #else
      hotend_offset[X_AXIS][i] = 0;
      hotend_offset[Y_AXIS][i] = 0;
      hotend_offset[Z_AXIS][i] = 0;
    #endif
  }

  #if MECH(SCARA)
    for (int8_t i = 0; i < NUM_AXIS; i++) {
      if (i < COUNT(axis_scaling))
        axis_scaling[i] = 1;
    }
  #endif

  // steps per sq second need to be updated to agree with the units per sq second
  planner.reset_acceleration_rates();

  planner.acceleration = DEFAULT_ACCELERATION;
  planner.travel_acceleration = DEFAULT_TRAVEL_ACCELERATION;
  planner.min_feedrate = DEFAULT_MINIMUMFEEDRATE;
  planner.min_segment_time = DEFAULT_MINSEGMENTTIME;
  planner.min_travel_feedrate = DEFAULT_MINTRAVELFEEDRATE;
  planner.max_xy_jerk = DEFAULT_XYJERK;
  planner.max_z_jerk = DEFAULT_ZJERK;
  home_offset[X_AXIS] = home_offset[Y_AXIS] = home_offset[Z_AXIS] = 0;

  #if ENABLED(MESH_BED_LEVELING)
    mbl.reset();
  #endif

  #if HAS(BED_PROBE)
    zprobe_zoffset = Z_PROBE_OFFSET_FROM_NOZZLE;
  #endif

  #if MECH(DELTA)
    delta_radius = DEFAULT_DELTA_RADIUS;
    delta_diagonal_rod = DELTA_DIAGONAL_ROD;
    endstop_adj[0] = TOWER_A_ENDSTOP_ADJ;
    endstop_adj[1] = TOWER_B_ENDSTOP_ADJ;
    endstop_adj[2] = TOWER_C_ENDSTOP_ADJ;
    tower_adj[0] = TOWER_A_POSITION_ADJ;
    tower_adj[1] = TOWER_B_POSITION_ADJ;
    tower_adj[2] = TOWER_C_POSITION_ADJ;
    tower_adj[3] = TOWER_A_RADIUS_ADJ;
    tower_adj[4] = TOWER_B_RADIUS_ADJ;
    tower_adj[5] = TOWER_C_RADIUS_ADJ;
    diagrod_adj[0] = TOWER_A_DIAGROD_ADJ;
    diagrod_adj[1] = TOWER_B_DIAGROD_ADJ;
    diagrod_adj[2] = TOWER_C_DIAGROD_ADJ;
  #endif

  #if ENABLED(ULTIPANEL)
    plaPreheatHotendTemp = PLA_PREHEAT_HOTEND_TEMP;
    plaPreheatHPBTemp = PLA_PREHEAT_HPB_TEMP;
    plaPreheatFanSpeed = PLA_PREHEAT_FAN_SPEED;
    absPreheatHotendTemp = ABS_PREHEAT_HOTEND_TEMP;
    absPreheatHPBTemp = ABS_PREHEAT_HPB_TEMP;
    absPreheatFanSpeed = ABS_PREHEAT_FAN_SPEED;
    gumPreheatHotendTemp = GUM_PREHEAT_HOTEND_TEMP;
    gumPreheatHPBTemp = GUM_PREHEAT_HPB_TEMP;
    gumPreheatFanSpeed = GUM_PREHEAT_FAN_SPEED;
  #endif

  #if HAS(LCD_CONTRAST)
    lcd_contrast = DEFAULT_LCD_CONTRAST;
  #endif

  #if ENABLED(PIDTEMP)
    for (int8_t h = 0; h < HOTENDS; h++) {
      Kp[h] = tmp6[h];
      Ki[h] = scalePID_i(tmp7[h]);
      Kd[h] = scalePID_d(tmp8[h]);
      Kc[h] = tmp9[h];
    }
    #if ENABLED(PID_ADD_EXTRUSION_RATE)
      lpq_len = 20; // default last-position-queue size
    #endif
  #endif // PIDTEMP

  #if ENABLED(PIDTEMPBED)
    bedKp = DEFAULT_bedKp;
    bedKi = scalePID_i(DEFAULT_bedKi);
    bedKd = scalePID_d(DEFAULT_bedKd);
  #endif

  #if ENABLED(PIDTEMPCHAMBER)
    chamberKp = DEFAULT_chamberKp;
    chamberKi = scalePID_i(DEFAULT_chamberKi);
    chamberKd = scalePID_d(DEFAULT_chamberKd);
  #endif

  #if ENABLED(PIDTEMPCOOLER)
    coolerKp = DEFAULT_coolerKp;
    coolerKi = scalePID_i(DEFAULT_coolerKi);
    coolerKd = scalePID_d(DEFAULT_coolerKd);
  #endif

  #if ENABLED(FWRETRACT)
    autoretract_enabled = false;
    retract_length = RETRACT_LENGTH;
    #if EXTRUDERS > 1
      retract_length_swap = RETRACT_LENGTH_SWAP;
    #endif
    retract_feedrate = RETRACT_FEEDRATE;
    retract_zlift = RETRACT_ZLIFT;
    retract_recover_length = RETRACT_RECOVER_LENGTH;
    #if EXTRUDERS > 1
      retract_recover_length_swap = RETRACT_RECOVER_LENGTH_SWAP;
    #endif
    retract_recover_feedrate = RETRACT_RECOVER_FEEDRATE;
  #endif

  volumetric_enabled = false;

  #if ENABLED(IDLE_OOZING_PREVENT)
    IDLE_OOZING_enabled = true;
  #endif

  Config_Postprocess();

  ECHO_LM(DB, "Hardcoded Default Settings Loaded");
}
/**
 * M501 - Retrieve Configuration
 */
void Config_RetrieveSettings() {
  int i = EEPROM_OFFSET;
  char stored_ver[6];
  uint16_t stored_checksum;
  EEPROM_READ_VAR(i, stored_ver);
  EEPROM_READ_VAR(i, stored_checksum);

  if (DEBUGGING(INFO)) {
    ECHO_SMV(INFO, "Version: [", version);
    ECHO_MV("] Stored version: [", stored_ver);
    ECHO_EM("]");
  }

  if (strncmp(version, stored_ver, 5) != 0) {
    Config_ResetDefault();
  }
  else {
    float dummy = 0;

    eeprom_checksum = 0; // clear before reading first "real data"

    // version number match
    EEPROM_READ_VAR(i, planner.axis_steps_per_mm);
    EEPROM_READ_VAR(i, planner.max_feedrate);
    EEPROM_READ_VAR(i, planner.max_acceleration_mm_per_s2);

    EEPROM_READ_VAR(i, planner.acceleration);
    EEPROM_READ_VAR(i, planner.retract_acceleration);
    EEPROM_READ_VAR(i, planner.travel_acceleration);
    EEPROM_READ_VAR(i, planner.min_feedrate);
    EEPROM_READ_VAR(i, planner.min_travel_feedrate);
    EEPROM_READ_VAR(i, planner.min_segment_time);
    EEPROM_READ_VAR(i, planner.max_xy_jerk);
    EEPROM_READ_VAR(i, planner.max_z_jerk);
    EEPROM_READ_VAR(i, planner.max_e_jerk);
    EEPROM_READ_VAR(i, home_offset);
    EEPROM_READ_VAR(i, hotend_offset);

    #if ENABLED(MESH_BED_LEVELING)
      uint8_t mesh_num_x = 0, mesh_num_y = 0;
      EEPROM_READ_VAR(i, mbl.status);
      EEPROM_READ_VAR(i, mbl.z_offset);
      EEPROM_READ_VAR(i, mesh_num_x);
      EEPROM_READ_VAR(i, mesh_num_y);
      EEPROM_READ_VAR(i, mbl.z_values);
    #endif

    #if HEATER_USES_AD595
      EEPROM_READ_VAR(i, ad595_offset);
      EEPROM_READ_VAR(i, ad595_gain);
      for (int8_t h = 0; h < HOTENDS; h++)
        if (ad595_gain[h] == 0) ad595_gain[h] == TEMP_SENSOR_AD595_GAIN;
    #endif

    #if MECH(DELTA)
      EEPROM_READ_VAR(i, endstop_adj);
      EEPROM_READ_VAR(i, delta_radius);
      EEPROM_READ_VAR(i, delta_diagonal_rod);
      EEPROM_READ_VAR(i, sw_endstop_max);
      EEPROM_READ_VAR(i, tower_adj);
      EEPROM_READ_VAR(i, diagrod_adj);
    #endif //DELTA

    #if HASNT(BED_PROBE)
      float zprobe_zoffset = 0;
    #endif
    EEPROM_READ_VAR(i, zprobe_zoffset);

    #if DISABLED(ULTIPANEL)
      int plaPreheatHotendTemp, plaPreheatHPBTemp, plaPreheatFanSpeed,
          absPreheatHotendTemp, absPreheatHPBTemp, absPreheatFanSpeed,
          gumPreheatHotendTemp, gumPreheatHPBTemp, gumPreheatFanSpeed;
    #endif

    EEPROM_READ_VAR(i, plaPreheatHotendTemp);
    EEPROM_READ_VAR(i, plaPreheatHPBTemp);
    EEPROM_READ_VAR(i, plaPreheatFanSpeed);
    EEPROM_READ_VAR(i, absPreheatHotendTemp);
    EEPROM_READ_VAR(i, absPreheatHPBTemp);
    EEPROM_READ_VAR(i, absPreheatFanSpeed);
    EEPROM_READ_VAR(i, gumPreheatHotendTemp);
    EEPROM_READ_VAR(i, gumPreheatHPBTemp);
    EEPROM_READ_VAR(i, gumPreheatFanSpeed);

    #if ENABLED(PIDTEMP)
      for (int8_t h = 0; h < HOTENDS; h++) {
        EEPROM_READ_VAR(i, PID_PARAM(Kp, h));
        EEPROM_READ_VAR(i, PID_PARAM(Ki, h));
        EEPROM_READ_VAR(i, PID_PARAM(Kd, h));
        EEPROM_READ_VAR(i, PID_PARAM(Kc, h));
      }
    #endif // PIDTEMP

    #if DISABLED(PID_ADD_EXTRUSION_RATE)
      int lpq_len;
    #endif
    EEPROM_READ_VAR(i, lpq_len);

    #if ENABLED(PIDTEMPBED)
      EEPROM_READ_VAR(i, bedKp);
      EEPROM_READ_VAR(i, bedKi);
      EEPROM_READ_VAR(i, bedKd);
    #endif

    #if ENABLED(PIDTEMPCHAMBER)
      EEPROM_READ_VAR(i, chamberKp);
      EEPROM_READ_VAR(i, chamberKi);
      EEPROM_READ_VAR(i, chamberKd);
    #endif

    #if ENABLED(PIDTEMPCOOLER)
      EEPROM_READ_VAR(i, coolerKp);
      EEPROM_READ_VAR(i, coolerKi);
      EEPROM_READ_VAR(i, coolerKd);
    #endif

    #if HASNT(LCD_CONTRAST)
      int lcd_contrast;
    #endif
    EEPROM_READ_VAR(i, lcd_contrast);

    #if MECH(SCARA)
      EEPROM_READ_VAR(i, axis_scaling);  // 3 floats
    #endif

    #if ENABLED(FWRETRACT)
      EEPROM_READ_VAR(i, autoretract_enabled);
      EEPROM_READ_VAR(i, retract_length);
      #if EXTRUDERS > 1
        EEPROM_READ_VAR(i, retract_length_swap);
      #else
        EEPROM_READ_VAR(i, dummy);
      #endif
      EEPROM_READ_VAR(i, retract_feedrate);
      EEPROM_READ_VAR(i, retract_zlift);
      EEPROM_READ_VAR(i, retract_recover_length);
      #if EXTRUDERS > 1
        EEPROM_READ_VAR(i, retract_recover_length_swap);
      #else
        EEPROM_READ_VAR(i, dummy);
      #endif
      EEPROM_READ_VAR(i, retract_recover_feedrate);
    #endif // FWRETRACT

    EEPROM_READ_VAR(i, volumetric_enabled);

    for (int8_t e = 0; e < EXTRUDERS; e++)
      EEPROM_READ_VAR(i, filament_size[e]);

    #if ENABLED(IDLE_OOZING_PREVENT)
      EEPROM_READ_VAR(i, IDLE_OOZING_enabled);
    #endif

    #if MB(ALLIGATOR)
      EEPROM_READ_VAR(i, motor_current);
    #endif

    if (eeprom_checksum == stored_checksum) {
      Config_Postprocess();
      ECHO_SV(DB, version);
      ECHO_MV(" stored settings retrieved (", i);
      ECHO_EM(" bytes)");
    }
    else {
      ECHO_LM(ER, "EEPROM checksum mismatch");
      Config_ResetDefault();
    }
  }

  #if ENABLED(EEPROM_CHITCHAT)
    Config_PrintSettings();
  #endif
}
  /**
   * Print Configuration Settings - M503
   */
  void Config_PrintSettings(bool forReplay) {
    // Always have this function, even with EEPROM_SETTINGS disabled, the current values will be shown

    if (!forReplay) {
      ECHO_LM(CFG, "Steps per unit:");
    }
    ECHO_SMV(CFG, "  M92 X", axis_steps_per_unit[X_AXIS]);
    ECHO_MV(" Y", axis_steps_per_unit[Y_AXIS]);
    ECHO_MV(" Z", axis_steps_per_unit[Z_AXIS]);
    ECHO_EMV(" E", axis_steps_per_unit[E_AXIS]);
    #if EXTRUDERS > 1
      for (short i = 1; i < EXTRUDERS; i++) {
        ECHO_SMV(CFG, "  M92 T", i);
        ECHO_EMV(" E", axis_steps_per_unit[E_AXIS + i]);
      }
    #endif //EXTRUDERS > 1

    #if MECH(SCARA)
      if (!forReplay) {
        ECHO_LM(CFG, "Scaling factors:");
      }
      ECHO_SMV(CFG, "  M365 X", axis_scaling[X_AXIS]);
      ECHO_MV(" Y", axis_scaling[Y_AXIS]);
      ECHO_EMV(" Z", axis_scaling[Z_AXIS]);
    #endif // SCARA

    if (!forReplay) {
      ECHO_LM(CFG, "Maximum feedrates (mm/s):");
    }
    ECHO_SMV(CFG, "  M203 X", max_feedrate[X_AXIS]);
    ECHO_MV(" Y", max_feedrate[Y_AXIS] ); 
    ECHO_MV(" Z", max_feedrate[Z_AXIS] ); 
    ECHO_EMV(" E", max_feedrate[E_AXIS]);
    #if EXTRUDERS > 1
      for (short i = 1; i < EXTRUDERS; i++) {
        ECHO_SMV(CFG, "  M203 T", i);
        ECHO_EMV(" E", max_feedrate[E_AXIS + i]);
      }
    #endif //EXTRUDERS > 1

    if (!forReplay) {
      ECHO_LM(CFG, "Maximum Acceleration (mm/s2):");
    }
    ECHO_SMV(CFG, "  M201 X", max_acceleration_units_per_sq_second[X_AXIS] );
    ECHO_MV(" Y", max_acceleration_units_per_sq_second[Y_AXIS] );
    ECHO_MV(" Z", max_acceleration_units_per_sq_second[Z_AXIS] );
    ECHO_EMV(" E", max_acceleration_units_per_sq_second[E_AXIS]);
    #if EXTRUDERS > 1
      for (int8_t i = 1; i < EXTRUDERS; i++) {
        ECHO_SMV(CFG, "  M201 T", i);
        ECHO_EMV(" E", max_acceleration_units_per_sq_second[E_AXIS + i]);
      }
    #endif //EXTRUDERS > 1
    ECHO_E;
    
    if (!forReplay) {
      ECHO_LM(CFG, "Accelerations: P=printing, V=travel and T* R=retract");
    }
    ECHO_SMV(CFG,"  M204 P", acceleration);
    ECHO_EMV(" V", travel_acceleration);
    #if EXTRUDERS > 0
      for (int8_t i = 0; i < EXTRUDERS; i++) {
        ECHO_SMV(CFG, "  M204 T", i);
        ECHO_EMV(" R", retract_acceleration[i]);
      }
    #endif

    if (!forReplay) {
      ECHO_LM(CFG, "Advanced variables: S=Min feedrate (mm/s), V=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum XY jerk (mm/s),  Z=maximum Z jerk (mm/s),  E=maximum E jerk (mm/s)");
    }
    ECHO_SMV(CFG, "  M205 S", minimumfeedrate );
    ECHO_MV(" V", mintravelfeedrate );
    ECHO_MV(" B", minsegmenttime );
    ECHO_MV(" X", max_xy_jerk );
    ECHO_MV(" Z", max_z_jerk);
    ECHO_EMV(" E", max_e_jerk[0]);
    #if (EXTRUDERS > 1)
      for(int8_t i = 1; i < EXTRUDERS; i++) {
        ECHO_SMV(CFG, "  M205 T", i);
        ECHO_EMV(" E" , max_e_jerk[i]);
      }
    #endif

    if (!forReplay) {
      ECHO_LM(CFG, "Home offset (mm):");
    }
    ECHO_SMV(CFG, "  M206 X", home_offset[X_AXIS] );
    ECHO_MV(" Y", home_offset[Y_AXIS] );
    ECHO_EMV(" Z", home_offset[Z_AXIS] );

    if (!forReplay) {
      ECHO_LM(CFG, "Hotend offset (mm):");
    }
    for (int8_t h = 0; h < HOTENDS; h++) {
      ECHO_SMV(CFG, "  M218 T", h);
      ECHO_MV(" X", hotend_offset[X_AXIS][h]);
      ECHO_MV(" Y", hotend_offset[Y_AXIS][h]);
      ECHO_EMV(" Z", hotend_offset[Z_AXIS][h]);
    }

    #if HEATER_USES_AD595
      if (!forReplay) {
        ECHO_LM(CFG, "AD595 Offset and Gain:");
      }
      for (int8_t h = 0; h < HOTENDS; h++) {
        ECHO_SMV(CFG, "  M595 T", h);
        ECHO_MV(" O", ad595_offset[h]);
        ECHO_EMV(", S", ad595_gain[h]);
      }
    #endif // HEATER_USES_AD595

    #if MECH(DELTA)
      if (!forReplay) {
        ECHO_LM(CFG, "Delta Geometry adjustment:");
      }
      ECHO_SMV(CFG, "  M666 A", tower_adj[0], 3);
      ECHO_MV(" B", tower_adj[1], 3);
      ECHO_MV(" C", tower_adj[2], 3);
      ECHO_MV(" I", tower_adj[3], 3);
      ECHO_MV(" J", tower_adj[4], 3);
      ECHO_MV(" K", tower_adj[5], 3);
      ECHO_MV(" U", diagrod_adj[0], 3);
      ECHO_MV(" V", diagrod_adj[1], 3);
      ECHO_MV(" W", diagrod_adj[2], 3);
      ECHO_MV(" R", delta_radius);
      ECHO_MV(" D", delta_diagonal_rod);
      ECHO_EMV(" H", sw_endstop_max[2]);

      if (!forReplay) {
        ECHO_LM(CFG, "Endstop Offsets:");
      }
      ECHO_SMV(CFG, "  M666 X", endstop_adj[X_AXIS]);
      ECHO_MV(" Y", endstop_adj[Y_AXIS]);
      ECHO_EMV(" Z", endstop_adj[Z_AXIS]);

      if (!forReplay) {
        ECHO_LM(CFG, "Z-Probe Offset:");
      }
      ECHO_SMV(CFG, "  M666 P X", z_probe_offset[0]);
      ECHO_MV(" Y", z_probe_offset[1]);
      ECHO_EMV(" Z", z_probe_offset[2]);

    #elif ENABLED(Z_DUAL_ENDSTOPS)
      if (!forReplay) {
        ECHO_LM(CFG, "Z2 Endstop adjustement (mm):");
      }
      ECHO_LMV(CFG, "  M666 Z", z_endstop_adj );
    #elif ENABLED(AUTO_BED_LEVELING_FEATURE)
      if (!forReplay) {
        ECHO_LM(CFG, "Z Probe offset (mm)");
      }
      ECHO_LMV(CFG, "  M666 P", zprobe_zoffset);
    #endif

    #if ENABLED(ULTIPANEL)
      if (!forReplay) {
        ECHO_LM(CFG, "Material heatup parameters:");
      }
      ECHO_SMV(CFG, "  M145 S0 H", plaPreheatHotendTemp);
      ECHO_MV(" B", plaPreheatHPBTemp);
      ECHO_MV(" F", plaPreheatFanSpeed);
      ECHO_EM(" (Material PLA)");
      ECHO_SMV(CFG, "  M145 S1 H", absPreheatHotendTemp);
      ECHO_MV(" B", absPreheatHPBTemp);
      ECHO_MV(" F", absPreheatFanSpeed);
      ECHO_EM(" (Material ABS)");
      ECHO_SMV(CFG, "  M145 S2 H", gumPreheatHotendTemp);
      ECHO_MV(" B", gumPreheatHPBTemp);
      ECHO_MV(" F", gumPreheatFanSpeed);
      ECHO_EM(" (Material GUM)");
    #endif // ULTIPANEL

    #if ENABLED(PIDTEMP) || ENABLED(PIDTEMPBED)
      if (!forReplay) {
        ECHO_LM(CFG, "PID settings:");
      }
      #if ENABLED(PIDTEMP)
        for (uint8_t h = 0; h < HOTENDS; h++) {
          ECHO_SMV(CFG, "  M301 H", h);
          ECHO_MV(" P", PID_PARAM(Kp, h));
          ECHO_MV(" I", unscalePID_i(PID_PARAM(Ki, h)));
          ECHO_MV(" D", unscalePID_d(PID_PARAM(Kd, h)));
          #if ENABLED(PID_ADD_EXTRUSION_RATE)
            ECHO_MV(" C", PID_PARAM(Kc, h));
          #endif
          ECHO_E;
        }
        #if ENABLED(PID_ADD_EXTRUSION_RATE)
          ECHO_SMV(CFG, "  M301 L", lpq_len);
        #endif
      #endif
      #if ENABLED(PIDTEMPBED)
        ECHO_SMV(CFG, "  M304 P", bedKp); // for compatibility with hosts, only echos values for E0
        ECHO_MV(" I", unscalePID_i(bedKi));
        ECHO_EMV(" D", unscalePID_d(bedKd));
      #endif
    #endif

    #if ENABLED(FWRETRACT)
      if (!forReplay) {
        ECHO_LM(CFG, "Retract: S=Length (mm) F:Speed (mm/m) Z: ZLift (mm)");
      }
      ECHO_SMV(CFG, "  M207 S", retract_length);
      ECHO_MV(" F", retract_feedrate*60);
      ECHO_EMV(" Z", retract_zlift);
      
      if (!forReplay) {
        ECHO_LM(CFG, "Recover: S=Extra length (mm) F:Speed (mm/m)");
      }
      ECHO_SMV(CFG, "  M208 S", retract_recover_length);
      ECHO_MV(" F", retract_recover_feedrate*60);
      
      if (!forReplay) {
        ECHO_LM(CFG, "Auto-Retract: S=0 to disable, 1 to interpret extrude-only moves as retracts or recoveries");
      }
      ECHO_LMV(CFG, "  M209 S", autoretract_enabled);

      #if EXTRUDERS > 1
        if (!forReplay) {
          ECHO_LM(CFG, "Multi-extruder settings:");
          ECHO_LMV(CFG, "   Swap retract length (mm):    ", retract_length_swap);
          ECHO_LMV(CFG, "   Swap rec. addl. length (mm): ", retract_recover_length_swap);
        }
      #endif // EXTRUDERS > 1

    #endif // FWRETRACT

    if (volumetric_enabled) {
      if (!forReplay) {
        ECHO_LM(CFG, "Filament settings:");
      }
      ECHO_LMV(CFG, "  M200 D", filament_size[0]);

      #if EXTRUDERS > 1
        ECHO_LMV(CFG, "  M200 T1 D", filament_size[1]);
        #if EXTRUDERS > 2
          ECHO_LMV(CFG, "  M200 T2 D", filament_size[2]);
          #if EXTRUDERS > 3
            ECHO_LMV(CFG, "  M200 T3 D", filament_size[3]);
          #endif
        #endif
      #endif

    } else {
      if (!forReplay) {
        ECHO_LM(CFG, "Filament settings: Disabled");
      }
    }

    #if MB(ALLIGATOR)
      if (!forReplay) {
        ECHO_LM(CFG, "Current:");
      }
      ECHO_SMV(CFG, "  M906 X", motor_current[X_AXIS]);
      ECHO_MV(" Y", motor_current[Y_AXIS]);
      ECHO_MV(" Z", motor_current[Z_AXIS]);
      ECHO_EMV(" E", motor_current[E_AXIS]);
      #if DRIVER_EXTRUDERS > 1
        for (uint8_t i = 1; i < DRIVER_EXTRUDERS; i++) {
          ECHO_SMV(CFG, "  M906 T", i);
          ECHO_EMV(" E", motor_current[E_AXIS + i]);
        }
      #endif // DRIVER_EXTRUDERS > 1
    #endif // ALLIGATOR

    ConfigSD_PrintSettings(forReplay);

  }
/**
 * Reset Configuration Settings - M502
 */
void Config_ResetDefault() {
  float tmp1[] = DEFAULT_AXIS_STEPS_PER_UNIT;
  float tmp2[] = DEFAULT_MAX_FEEDRATE;
  float tmp3[] = DEFAULT_MAX_ACCELERATION;
  float tmp4[] = DEFAULT_RETRACT_ACCELERATION;
  float tmp5[] = DEFAULT_EJERK;
  #if ENABLED(PIDTEMP)
    float tmp6[] = DEFAULT_Kp;
    float tmp7[] = DEFAULT_Ki;
    float tmp8[] = DEFAULT_Kd;
    float tmp9[] = DEFAULT_Kc;
  #endif // PIDTEMP

  #if ENABLED(HOTEND_OFFSET_X) && ENABLED(HOTEND_OFFSET_Y) && ENABLED(HOTEND_OFFSET_Z)
    float tmp10[] = HOTEND_OFFSET_X;
    float tmp11[] = HOTEND_OFFSET_Y;
    float tmp12[] = HOTEND_OFFSET_Z;
  #else
    float tmp10[] = {0};
    float tmp11[] = {0};
    float tmp12[] = {0};
  #endif

  #if MB(ALLIGATOR)
    float tmp13[] = MOTOR_CURRENT;
  #endif

  for (int8_t i = 0; i < 3 + EXTRUDERS; i++) {
    short max_i;
    max_i = sizeof(tmp1) / sizeof(*tmp1);
    if(i < max_i)
      axis_steps_per_unit[i] = tmp1[i];
    else
      axis_steps_per_unit[i] = tmp1[max_i - 1];
    max_i = sizeof(tmp2) / sizeof(*tmp2);
    if(i < max_i)
      max_feedrate[i] = tmp2[i];
    else
      max_feedrate[i] = tmp2[max_i - 1];
    max_i = sizeof(tmp3) / sizeof(*tmp3);
    if(i < max_i)
      max_acceleration_units_per_sq_second[i] = tmp3[i];
    else
      max_acceleration_units_per_sq_second[i] = tmp3[max_i - 1];
    if(i < EXTRUDERS) {
      max_i = sizeof(tmp4) / sizeof(*tmp4);
      if(i < max_i)
        retract_acceleration[i] = tmp4[i];
      else
        retract_acceleration[i] = tmp4[max_i - 1];
      max_i = sizeof(tmp5) / sizeof(*tmp5);
      if(i < max_i)
        max_e_jerk[i] = tmp5[i];
      else
        max_e_jerk[i] = tmp5[max_i - 1];
      max_i = sizeof(tmp10) / sizeof(*tmp10);
      if(i < max_i)
        hotend_offset[X_AXIS][i] = tmp10[i];
      else
        hotend_offset[X_AXIS][i] = 0;
      max_i = sizeof(tmp11) / sizeof(*tmp11);
      if(i < max_i)
        hotend_offset[Y_AXIS][i] = tmp11[i];
      else
        hotend_offset[Y_AXIS][i] = 0;
      max_i = sizeof(tmp12) / sizeof(*tmp12);
      if(i < max_i)
        hotend_offset[Z_AXIS][i] = tmp12[i];
      else
        hotend_offset[Z_AXIS][i] = 0;
    }
    #if MB(ALLIGATOR)
      max_i = sizeof(tmp13) / sizeof(*tmp13);
      if(i < max_i)
        motor_current[i] = tmp13[i];
      else
        motor_current[i] = tmp13[max_i - 1];
    #endif
  }

  #if MECH(SCARA)
    for (int8_t i = 0; i < NUM_AXIS; i++) {
      if (i < COUNT(axis_scaling))
        axis_scaling[i] = 1;
    }
  #endif

  // steps per sq second need to be updated to agree with the units per sq second
  reset_acceleration_rates();

  acceleration = DEFAULT_ACCELERATION;
  travel_acceleration = DEFAULT_TRAVEL_ACCELERATION;
  minimumfeedrate = DEFAULT_MINIMUMFEEDRATE;
  minsegmenttime = DEFAULT_MINSEGMENTTIME;
  mintravelfeedrate = DEFAULT_MINTRAVELFEEDRATE;
  max_xy_jerk = DEFAULT_XYJERK;
  max_z_jerk = DEFAULT_ZJERK;
  home_offset[X_AXIS] = home_offset[Y_AXIS] = home_offset[Z_AXIS] = 0;

  #if ENABLED(AUTO_BED_LEVELING_FEATURE)
    zprobe_zoffset = Z_PROBE_OFFSET_FROM_EXTRUDER;
  #elif !MECH(DELTA)
    zprobe_zoffset = 0;
  #endif

  #if MECH(DELTA)
    delta_radius = DEFAULT_DELTA_RADIUS;
    delta_diagonal_rod = DELTA_DIAGONAL_ROD;
    endstop_adj[0] = TOWER_A_ENDSTOP_ADJ;
    endstop_adj[1] = TOWER_B_ENDSTOP_ADJ;
    endstop_adj[2] = TOWER_C_ENDSTOP_ADJ;
    tower_adj[0] = TOWER_A_POSITION_ADJ;
    tower_adj[1] = TOWER_B_POSITION_ADJ;
    tower_adj[2] = TOWER_C_POSITION_ADJ;
    tower_adj[3] = TOWER_A_RADIUS_ADJ;
    tower_adj[4] = TOWER_B_RADIUS_ADJ;
    tower_adj[5] = TOWER_C_RADIUS_ADJ;
    diagrod_adj[0] = TOWER_A_DIAGROD_ADJ;
    diagrod_adj[1] = TOWER_B_DIAGROD_ADJ;
    diagrod_adj[2] = TOWER_C_DIAGROD_ADJ;
    z_probe_offset[0] = X_PROBE_OFFSET_FROM_EXTRUDER;
    z_probe_offset[1] = Y_PROBE_OFFSET_FROM_EXTRUDER;
    z_probe_offset[2] = Z_PROBE_OFFSET_FROM_EXTRUDER;
    set_delta_constants();
  #endif

  #if ENABLED(ULTIPANEL)
    plaPreheatHotendTemp = PLA_PREHEAT_HOTEND_TEMP;
    plaPreheatHPBTemp = PLA_PREHEAT_HPB_TEMP;
    plaPreheatFanSpeed = PLA_PREHEAT_FAN_SPEED;
    absPreheatHotendTemp = ABS_PREHEAT_HOTEND_TEMP;
    absPreheatHPBTemp = ABS_PREHEAT_HPB_TEMP;
    absPreheatFanSpeed = ABS_PREHEAT_FAN_SPEED;
    gumPreheatHotendTemp = GUM_PREHEAT_HOTEND_TEMP;
    gumPreheatHPBTemp = GUM_PREHEAT_HPB_TEMP;
    gumPreheatFanSpeed = GUM_PREHEAT_FAN_SPEED;
  #endif

  #if HAS(LCD_CONTRAST)
    lcd_contrast = DEFAULT_LCD_CONTRAST;
  #endif

  #if ENABLED(PIDTEMP)
    for (int8_t h = 0; h < HOTENDS; h++) {
      Kp[h] = tmp6[h];
      Ki[h] = scalePID_i(tmp7[h]);
      Kd[h] = scalePID_d(tmp8[h]);
      Kc[h] = tmp9[h];
    }
    #if ENABLED(PID_ADD_EXTRUSION_RATE)
      lpq_len = 20; // default last-position-queue size
    #endif
    // call updatePID (similar to when we have processed M301)
    updatePID();
  #endif // PIDTEMP

  #if ENABLED(PIDTEMPBED)
    bedKp = DEFAULT_bedKp;
    bedKi = scalePID_i(DEFAULT_bedKi);
    bedKd = scalePID_d(DEFAULT_bedKd);
  #endif

  #if ENABLED(FWRETRACT)
    autoretract_enabled = false;
    retract_length = RETRACT_LENGTH;
    #if EXTRUDERS > 1
      retract_length_swap = RETRACT_LENGTH_SWAP;
    #endif
    retract_feedrate = RETRACT_FEEDRATE;
    retract_zlift = RETRACT_ZLIFT;
    retract_recover_length = RETRACT_RECOVER_LENGTH;
    #if EXTRUDERS > 1
      retract_recover_length_swap = RETRACT_RECOVER_LENGTH_SWAP;
    #endif
    retract_recover_feedrate = RETRACT_RECOVER_FEEDRATE;
  #endif

  volumetric_enabled = false;
  calculate_volumetric_multipliers();

  #if ENABLED(IDLE_OOZING_PREVENT)
    IDLE_OOZING_enabled = true;
  #endif

  ECHO_LM(DB, "Hardcoded Default Settings Loaded");
}
示例#15
0
  void lcd_init() {
    HAL::delayMilliseconds(2000);

    for (uint8_t i = 0; i < 10; i++) {
      NextionON = nexInit();
      if (NextionON) break;
      delay(1000);
    }

    if (!NextionON) {
      ECHO_LM(DB, "Nextion LCD not connected!");
    }
    else {
      ECHO_LM(DB, "Nextion LCD connected!");

      Pstart.attachPop(ExitPopCallback);
      Exit1.attachPop(ExitPopCallback);
      Exit3.attachPop(ExitPopCallback);

      #if ENABLED(NEXTION_GFX)
        gfx.color_set(VC_AXIS + X_AXIS, 63488);
        gfx.color_set(VC_AXIS + Y_AXIS, 2016);
        gfx.color_set(VC_AXIS + Z_AXIS, 31);
        gfx.color_set(VC_MOVE, 2047);
        gfx.color_set(VC_TOOL, 65535);
      #endif

      #if ENABLED(SDSUPPORT)
        MSD1.attachPop(setpageSDPopCallback);
        MSD3.attachPop(setpageSDPopCallback);
        MSD5.attachPop(setpageSDPopCallback);
        MSD6.attachPop(setpageSDPopCallback);
        sdlist.attachPop(sdlistPopCallback);
        ScrollUp.attachPop(sdlistPopCallback);
        ScrollDown.attachPop(sdlistPopCallback);
        Exit2.attachPop(ExitPopCallback);
        NPlay.attachPop(PlayPausePopCallback);
        NStop.attachPop(StopPopCallback);
      #endif

      #if HAS_TEMP_0
        hot0.attachPop(hotPopCallback,      &hot0);
      #endif
      #if HAS_TEMP_1
        hot1.attachPop(hotPopCallback,      &hot1);
      #endif
      #if HAS_TEMP_2 || HAS_TEMP_BED
        hot2.attachPop(hotPopCallback,      &hot2);
      #endif

      Fanpic.attachPop(setfanPopCallback,   &Fanpic);
      m11.attachPop(sethotPopCallback,      &m11);
      tup.attachPop(settempPopCallback,     &tup);
      tdown.attachPop(settempPopCallback,   &tdown);
      XYHome.attachPop(setmovePopCallback);
      XYUp.attachPop(setmovePopCallback);
      XYRight.attachPop(setmovePopCallback);
      XYDown.attachPop(setmovePopCallback);
      XYLeft.attachPop(setmovePopCallback);
      ZHome.attachPop(setmovePopCallback);
      ZUp.attachPop(setmovePopCallback);
      ZDown.attachPop(setmovePopCallback);
      SpeedOk.attachPop(ExitPopCallback);
      Benter.attachPop(setgcodePopCallback);

      startimer.enable();
    }
  }
示例#16
0
  void plan_buffer_line(const float& x, const float& y, const float& z, const float& e, float feed_rate, const uint8_t extruder, const uint8_t driver)
#endif  // AUTO_BED_LEVELING_FEATURE
{

  #if ENABLED(ZWOBBLE)
    // Calculate ZWobble
    zwobble.InsertCorrection(z);
  #endif
  #if ENABLED(HYSTERESIS)
    // Calculate Hysteresis
    hysteresis.InsertCorrection(x, y, z, e);
  #endif

  // 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) idle();

  #if ENABLED(AUTO_BED_LEVELING_FEATURE)
    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 + extruder]);

  // If changing extruder have to recalculate current position based on 
  // the steps-per-mm value for the new extruder.
  #if EXTRUDERS > 1
    if(last_extruder != extruder && axis_steps_per_unit[E_AXIS + extruder] != 
                                    axis_steps_per_unit[E_AXIS + last_extruder]) {
      float factor = float(axis_steps_per_unit[E_AXIS + extruder]) /
                     float(axis_steps_per_unit[E_AXIS + last_extruder]);
      position[E_AXIS] = lround(position[E_AXIS] * factor);
    }
  #endif

  long  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];
  #if MECH(COREXY)
    long da = dx + COREX_YZ_FACTOR * dy;
    long db = dx - COREX_YZ_FACTOR * dy;
  #elif MECH(COREXZ)
    long da = dx + COREX_YZ_FACTOR * dz;
    long dc = dx - COREX_YZ_FACTOR * dz;
  #endif

  #if ENABLED(PREVENT_DANGEROUS_EXTRUDE)
    if (de) {
      #if ENABLED(NPR2)
        if (extruder != 1)
      #endif
        {
          if (degHotend(extruder) < extrude_min_temp && !(debugLevel & DEBUG_DRYRUN)) {
            position[E_AXIS] = target[E_AXIS]; //behave as if the move really took place, but ignore E part
            de = 0; // no difference
            ECHO_LM(ER, SERIAL_ERR_COLD_EXTRUDE_STOP);
          }
        }

      #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
        if (labs(de) > axis_steps_per_unit[E_AXIS + extruder] * (EXTRUDE_MAXLENGTH)) {
          #if ENABLED(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
          de = 0; // no difference
          ECHO_LM(ER, SERIAL_ERR_LONG_EXTRUDE_STOP);
          #if ENABLED(EASY_LOAD)
            }
            allow_lengthy_extrude_once = false;
          #endif
        }
      #endif // PREVENT_LENGTHY_EXTRUDE
    }
  #endif // PREVENT_DANGEROUS_EXTRUDE

  // 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
  #if MECH(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(da);
    block->steps[B_AXIS] = labs(db);
    block->steps[Z_AXIS] = labs(dz);
  #elif MECH(COREXZ)
    // corexz planning
    block->steps[A_AXIS] = labs(da);
    block->steps[Y_AXIS] = labs(dy);
    block->steps[C_AXIS] = labs(dc);
  #else
    // default non-h-bot planning
    block->steps[X_AXIS] = labs(dx);
    block->steps[Y_AXIS] = labs(dy);
    block->steps[Z_AXIS] = labs(dz);
  #endif

  block->steps[E_AXIS] = labs(de);
  block->steps[E_AXIS] *= volumetric_multiplier[extruder];
  block->steps[E_AXIS] *= extruder_multiplier[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 <= DROP_SEGMENTS) return;

  block->fan_speed = fanSpeed;

  #if ENABLED(BARICUDA)
    block->valve_pressure = ValvePressure;
    block->e_to_p_pressure = EtoPPressure;
  #endif

  // For a mixing extruder, get steps for each
  #if ENABLED(COLOR_MIXING_EXTRUDER)
    for (uint8_t i = 0; i < DRIVER_EXTRUDERS; i++)
      block->mix_event_count[i] = block->step_event_count / mixing_factor[i];
  #endif

  // Add update block variables for LASER BEAM control 
  #if ENABLED(LASERBEAM)
    block->laser_ttlmodulation = laser_ttl_modulation;
  #endif

  // Compute direction bits for this block 
  uint8_t dirb = 0;
  #if MECH(COREXY)
    if (dx < 0) SBI(dirb, X_HEAD); // Save the real Extruder (head) direction in X Axis
    if (dy < 0) SBI(dirb, Y_HEAD); // ...and Y
    if (dz < 0) SBI(dirb, Z_AXIS);
    if (da < 0) SBI(dirb, A_AXIS); // Motor A direction
    if (db < 0) SBI(dirb, B_AXIS); // Motor B direction
  #elif MECH(COREXZ)
    if (dx < 0) SBI(dirb, X_HEAD); // Save the real Extruder (head) direction in X Axis
    if (dy < 0) SBI(dirb, Y_AXIS);
    if (dz < 0) SBI(dirb, Z_HEAD); // ...and Z
    if (da < 0) SBI(dirb, A_AXIS); // Motor A direction
    if (dc < 0) SBI(dirb, C_AXIS); // Motor B direction
  #else
    if (dx < 0) SBI(dirb, X_AXIS);
    if (dy < 0) SBI(dirb, Y_AXIS); 
    if (dz < 0) SBI(dirb, Z_AXIS);
  #endif
  if (de < 0) SBI(dirb, E_AXIS); 
  block->direction_bits = dirb;

  block->active_driver = driver;

  // Enable active axes
  #if MECH(COREXY)
    if (block->steps[A_AXIS] || block->steps[B_AXIS]) {
      enable_x();
      enable_y();
    }
    #if DISABLED(Z_LATE_ENABLE)
      if (block->steps[Z_AXIS]) enable_z();
    #endif
  #elif MECH(COREXZ)
    if (block->steps[A_AXIS] || block->steps[C_AXIS]) {
      enable_x();
      enable_z();
    }
    if (block->steps[Y_AXIS]) enable_y();
  #else
    if (block->steps[X_AXIS]) enable_x();
    if (block->steps[Y_AXIS]) enable_y();
    #if DISABLED(Z_LATE_ENABLE)
      if (block->steps[Z_AXIS]) enable_z();
    #endif
  #endif

  // Enable extruder(s)
  if (block->steps[E_AXIS]) {
    #if DISABLED(MKR4) && DISABLED(NPR2)
      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();
                  #if EXTRUDERS > 4
                    if (g_uc_extruder_last_move[4] == 0) disable_e4();
                    #if EXTRUDERS > 5
                      if (g_uc_extruder_last_move[5] == 0) disable_e5();
                    #endif
                  #endif
                #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();
                  #if EXTRUDERS > 4
                    if (g_uc_extruder_last_move[4] == 0) disable_e4();
                    #if EXTRUDERS > 5
                      if (g_uc_extruder_last_move[5] == 0) disable_e5();
                    #endif
                  #endif
                #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();
                  #if EXTRUDERS > 4
                    if (g_uc_extruder_last_move[4] == 0) disable_e4();
                    #if EXTRUDERS > 5
                      if (g_uc_extruder_last_move[5] == 0) disable_e5();
                    #endif
                  #endif
                #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();
                  #if EXTRUDERS > 4
                    if (g_uc_extruder_last_move[4] == 0) disable_e4();
                    #if EXTRUDERS > 5
                      if (g_uc_extruder_last_move[5] == 0) disable_e5();
                    #endif
                  #endif
                break;
                #if EXTRUDERS > 4
                  case 4:
                    enable_e4();
                    g_uc_extruder_last_move[4] = (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();
                    if (g_uc_extruder_last_move[3] == 0) disable_e3();
                    #if EXTRUDERS > 5
                      if (g_uc_extruder_last_move[5] == 0) disable_e5();
                    #endif
                  break;
                  #if EXTRUDERS > 5
                    case 4:
                      enable_e5();
                      g_uc_extruder_last_move[5] = (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();
                      if (g_uc_extruder_last_move[3] == 0) disable_e3();
                      if (g_uc_extruder_last_move[4] == 0) disable_e4();
                    break;
                  #endif // EXTRUDERS > 5
                #endif // EXTRUDERS > 4
              #endif // EXTRUDERS > 3
            #endif // EXTRUDERS > 2
          #endif // EXTRUDERS > 1
        }
      }
      else //enable all
      {
        enable_e0();
        enable_e1();
        enable_e2();
        enable_e3();
        enable_e4();
        enable_e5();
      }
    #else //MKR4 or NPr2
      switch(extruder)
      {
        case 0:
          enable_e0();
        break;
        case 1:
          enable_e1();
        break;
        case 2:
          enable_e0();
        break;
        case 3:
          enable_e1();
        break;
      }
    #endif //!MKR4 && !NPR2
  }

  if (block->steps[E_AXIS])
    NOLESS(feed_rate, minimumfeedrate);
  else
    NOLESS(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.
   */
  #if MECH(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[Z_AXIS] = dz / axis_steps_per_unit[Z_AXIS];
    delta_mm[A_AXIS] = da / axis_steps_per_unit[A_AXIS];
    delta_mm[B_AXIS] = db / axis_steps_per_unit[B_AXIS];
  #elif MECH(COREXZ)
    float delta_mm[6];
    delta_mm[X_HEAD] = dx / axis_steps_per_unit[A_AXIS];
    delta_mm[Y_AXIS] = dy / axis_steps_per_unit[Y_AXIS];
    delta_mm[Z_HEAD] = dz / axis_steps_per_unit[C_AXIS];
    delta_mm[A_AXIS] = da / axis_steps_per_unit[A_AXIS];
    delta_mm[C_AXIS] = dc / axis_steps_per_unit[C_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];
    delta_mm[Z_AXIS] = dz / axis_steps_per_unit[Z_AXIS];
  #endif
  delta_mm[E_AXIS] = (de / axis_steps_per_unit[E_AXIS + extruder]) * volumetric_multiplier[extruder] * extruder_multiplier[extruder] / 100.0;

  if (block->steps[X_AXIS] <= DROP_SEGMENTS && block->steps[Y_AXIS] <= DROP_SEGMENTS && block->steps[Z_AXIS] <= DROP_SEGMENTS) {
    block->millimeters = fabs(delta_mm[E_AXIS]);
  }
  else {
    block->millimeters = sqrt(
      #if MECH(COREXY)
        square(delta_mm[X_HEAD]) + square(delta_mm[Y_HEAD]) + square(delta_mm[Z_AXIS])
      #elif MECH(COREXZ)
        square(delta_mm[X_HEAD]) + square(delta_mm[Y_AXIS]) + square(delta_mm[Z_HEAD])
      #else
        square(delta_mm[X_AXIS]) + square(delta_mm[Y_AXIS]) + 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 = movesplanned();

  // Slow down when the buffer starts to empty, rather than wait at the corner for a buffer refill
  #if ENABLED(OLD_SLOWDOWN) || ENABLED(SLOWDOWN)
    bool mq = moves_queued > 1 && moves_queued < (BLOCK_BUFFER_SIZE) / 2;
    #if ENABLED(OLD_SLOWDOWN)
      if (mq) feed_rate *= 2.0 * moves_queued / (BLOCK_BUFFER_SIZE);
    #endif
    #if ENABLED(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));
          #if ENABLED(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

  #if ENABLED(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.
  #if ENABLED(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 (TEST(direction_change, X_AXIS)) {
      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 (TEST(direction_change, Y_AXIS)) {
      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[extruder] * 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 + extruder];
  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;

  #ifdef __SAM3X8E__
    block->acceleration_rate = (long)(acc_st * (4294967296.0 / (HAL_TIMER_RATE)));
  #else
    block->acceleration_rate = (long)(acc_st * 16777216.0 / (F_CPU / 8.0));
  #endif

  #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[extruder] / 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 dsx = current_speed[X_AXIS] - previous_speed[X_AXIS],
          dsy = current_speed[Y_AXIS] - previous_speed[Y_AXIS],
          dsz = fabs(csz - previous_speed[Z_AXIS]),
          dse = fabs(cse - previous_speed[E_AXIS]),
          jerk = sqrt(dsx * dsx + dsy * dsy);

    //    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 (dsz > max_z_jerk) vmax_junction_factor = min(vmax_junction_factor, max_z_jerk / dsz);
    if (dse > max_e_jerk[extruder]) vmax_junction_factor = min(vmax_junction_factor, max_e_jerk[extruder] / dse);

    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
  memcpy(previous_speed, current_speed, sizeof(previous_speed)); // previous_speed[] = current_speed[]
  previous_nominal_speed = block->nominal_speed;

  #if ENABLED(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;
    }
    /*
    ECHO_SMV(OK, "advance :", block->advance/256);
    ECHO_EMV("advance rate :", block->advance_rate/256);
    */
  #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();

} // plan_buffer_line()
示例#17
0
  void PID_autotune(float temp, int hotend, int ncycles) {
    float input = 0.0;
    int cycles = 0;
    bool heating = true;

    millis_t temp_ms = millis(), t1 = temp_ms, t2 = temp_ms;
    long t_high = 0, t_low = 0;

    long bias, d;
    float Ku, Tu;
    float Kp_temp, Ki_temp, Kd_temp;
    float max = 0, min = 10000;

    #if HAS_AUTO_FAN
      millis_t next_auto_fan_check_ms = temp_ms + 2500;
    #endif

    if (hotend >= HOTENDS
      #if !HAS_TEMP_BED
         || hotend < 0
      #endif
    ) {
      ECHO_LM(ER, MSG_PID_BAD_EXTRUDER_NUM);
      return;
    }

    ECHO_LM(DB, MSG_PID_AUTOTUNE_START);
    if (hotend < 0) {
      ECHO_SM(DB, "BED");
    }
    else {
        ECHO_SMV(DB, "Hotend: ", hotend);
    }
    ECHO_MV(" Temp: ", temp);
    ECHO_EMV(" Cycles: ", ncycles);

    disable_all_heaters(); // switch off all heaters.

    if (hotend < 0)
      soft_pwm_bed = bias = d = MAX_BED_POWER / 2;
    else
      soft_pwm[hotend] = bias = d = PID_MAX / 2;

    // PID Tuning loop
    for (;;) {

      millis_t ms = millis();

      if (temp_meas_ready) { // temp sample ready
        updateTemperaturesFromRawValues();

        input = (hotend<0)?current_temperature_bed:current_temperature[hotend];

        max = max(max, input);
        min = min(min, input);

        #if HAS_AUTO_FAN
          if (ms > next_auto_fan_check_ms) {
            checkExtruderAutoFans();
            next_auto_fan_check_ms = ms + 2500;
          }
        #endif

        if (heating && input > temp) {
          if (ms > t2 + 5000) {
            heating = false;
            if (hotend < 0)
              soft_pwm_bed = (bias - d) >> 1;
            else
              soft_pwm[hotend] = (bias - d) >> 1;
            t1 = ms;
            t_high = t1 - t2;
            max = temp;
          }
        }

        if (!heating && input < temp) {
          if (ms > t1 + 5000) {
            heating = true;
            t2 = ms;
            t_low = t2 - t1;
            if (cycles > 0) {
              long max_pow = hotend < 0 ? MAX_BED_POWER : PID_MAX;
              bias += (d*(t_high - t_low))/(t_low + t_high);
              bias = constrain(bias, 20, max_pow - 20);
              d = (bias > max_pow / 2) ? max_pow - 1 - bias : bias;

              ECHO_MV(MSG_BIAS, bias);
              ECHO_MV(MSG_D, d);
              ECHO_MV(MSG_T_MIN, min);
              ECHO_MV(MSG_T_MAX, max);
              if (cycles > 2) {
                Ku = (4.0 * d) / (3.14159265 * (max - min) / 2.0);
                Tu = ((float)(t_low + t_high) / 1000.0);
                ECHO_MV(MSG_KU, Ku);
                ECHO_EMV(MSG_TU, Tu);
                Kp_temp = 0.6 * Ku;
                Ki_temp = 2 * Kp_temp / Tu;
                Kd_temp = Kp_temp * Tu / 8;
                
                ECHO_EM(MSG_CLASSIC_PID);
                ECHO_MV(MSG_KP, Kp_temp);
                ECHO_MV(MSG_KI, Ki_temp);
                ECHO_EMV(MSG_KD, Kd_temp);
              }
              else {
                ECHO_E;
              }
            }
            if (hotend < 0)
              soft_pwm_bed = (bias + d) >> 1;
            else
              soft_pwm[hotend] = (bias + d) >> 1;
            cycles++;
            min = temp;
          }