Esempio n. 1
0
int check_for_free_memory_corruption(const char * const title) {
  SERIAL_ECHO(title);

  char *ptr = END_OF_HEAP(), *sp = top_of_stack();
  int n = sp - ptr;

  SERIAL_ECHOPAIR("\nfmc() n=", n);
  SERIAL_ECHOPAIR("\n&__brkval: ", hex_address(&__brkval));
  SERIAL_ECHOPAIR("=",             hex_address(__brkval));
  SERIAL_ECHOPAIR("\n__bss_end: ", hex_address(&__bss_end));
  SERIAL_ECHOPAIR(" sp=",          hex_address(sp));

  if (sp < ptr)  {
    SERIAL_ECHOPGM(" sp < Heap ");
    // SET_INPUT_PULLUP(63);           // if the developer has a switch wired up to their controller board
    // safe_delay(5);                  // this code can be enabled to pause the display as soon as the
    // while ( READ(63))               // malfunction is detected.   It is currently defaulting to a switch
    //   idle();                       // being on pin-63 which is unassigend and available on most controller
    // safe_delay(20);                 // boards.
    // while ( !READ(63))
    //   idle();
    safe_delay(20);
    #ifdef M100_FREE_MEMORY_DUMPER
      M100_dump_routine("   Memory corruption detected with sp<Heap\n", (char*)0x1B80, (char*)0x21FF);
    #endif
  }

  // Scan through the range looking for the biggest block of 0xE5's we can find
  int block_cnt = 0;
  for (int i = 0; i < n; i++) {
    if (ptr[i] == TEST_BYTE) {
      int16_t j = count_test_bytes(ptr + i);
      if (j > 8) {
        // SERIAL_ECHOPAIR("Found ", j);
        // SERIAL_ECHOLNPAIR(" bytes free at ", hex_address(ptr + i));
        i += j;
        block_cnt++;
        SERIAL_ECHOPAIR(" (", block_cnt);
        SERIAL_ECHOPAIR(") found=", j);
        SERIAL_ECHOPGM("   ");
      }
    }
  }
  SERIAL_ECHOPAIR("  block_found=", block_cnt);

  if (block_cnt != 1 || __brkval != 0x0000)
    SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.");

  if (block_cnt == 0)       // Make sure the special case of no free blocks shows up as an
    block_cnt = -1;         // error to the calling code!

  SERIAL_ECHOPGM(" return=");
  if (block_cnt == 1) {
    SERIAL_CHAR('0');       // if the block_cnt is 1, nothing has broken up the free memory
    SERIAL_EOL();             // area and it is appropriate to say 'no corruption'.
    return 0;
  }
  SERIAL_ECHOLNPGM("true");
  return block_cnt;
}
Esempio n. 2
0
    void debug_current_and_destination(PGM_P title) {

      // if the title message starts with a '!' it is so important, we are going to
      // ignore the status of the g26_debug_flag
      if (*title != '!' && !g26_debug_flag) return;

      const float de = destination[E_AXIS] - current_position[E_AXIS];

      if (de == 0.0) return; // Printing moves only

      const float dx = destination[X_AXIS] - current_position[X_AXIS],
                  dy = destination[Y_AXIS] - current_position[Y_AXIS],
                  xy_dist = HYPOT(dx, dy);

      if (xy_dist == 0.0) return;

      const float fpmm = de / xy_dist;
      SERIAL_ECHOPAIR_F("   fpmm=", fpmm, 6);
      SERIAL_ECHOPAIR_F("    current=( ", current_position[X_AXIS], 6);
      SERIAL_ECHOPAIR_F(", ", current_position[Y_AXIS], 6);
      SERIAL_ECHOPAIR_F(", ", current_position[Z_AXIS], 6);
      SERIAL_ECHOPAIR_F(", ", current_position[E_AXIS], 6);
      SERIAL_ECHOPGM(" )   destination=( "); debug_echo_axis(X_AXIS);
      SERIAL_ECHOPGM(", "); debug_echo_axis(Y_AXIS);
      SERIAL_ECHOPGM(", "); debug_echo_axis(Z_AXIS);
      SERIAL_ECHOPGM(", "); debug_echo_axis(E_AXIS);
      SERIAL_ECHOPGM(" )   ");
      serialprintPGM(title);
      SERIAL_EOL();
    }
Esempio n. 3
0
  void PrintJobRecovery::debug(PGM_P const prefix) {
    serialprintPGM(prefix);
    SERIAL_ECHOLNPAIR(" Job Recovery Info...\nvalid_head:", int(info.valid_head), " valid_foot:", int(info.valid_foot));
    if (info.valid_head) {
      if (info.valid_head == info.valid_foot) {
        SERIAL_ECHOPGM("current_position: ");
        LOOP_XYZE(i) {
          SERIAL_ECHO(info.current_position[i]);
          if (i < E_AXIS) SERIAL_CHAR(',');
        }
        SERIAL_EOL();
        SERIAL_ECHOLNPAIR("feedrate: ", info.feedrate);

        #if HOTENDS > 1
          SERIAL_ECHOLNPAIR("active_hotend: ", int(info.active_hotend));
        #endif

        SERIAL_ECHOPGM("target_temperature: ");
        HOTEND_LOOP() {
          SERIAL_ECHO(info.target_temperature[e]);
          if (e < HOTENDS - 1) SERIAL_CHAR(',');
        }
        SERIAL_EOL();

        #if HAS_HEATED_BED
          SERIAL_ECHOLNPAIR("target_temperature_bed: ", info.target_temperature_bed);
        #endif

        #if FAN_COUNT
          SERIAL_ECHOPGM("fan_speed: ");
          FANS_LOOP(i) {
            SERIAL_ECHO(int(info.fan_speed[i]));
            if (i < FAN_COUNT - 1) SERIAL_CHAR(',');
          }
          SERIAL_EOL();
        #endif

        #if HAS_LEVELING
          SERIAL_ECHOLNPAIR("leveling: ", int(info.leveling), "\n fade: ", int(info.fade));
        #endif
        #if ENABLED(FWRETRACT)
          SERIAL_ECHOPGM("retract: ");
          for (int8_t e = 0; e < EXTRUDERS; e++) {
            SERIAL_ECHO(info.retract[e]);
            if (e < EXTRUDERS - 1) SERIAL_CHAR(',');
          }
          SERIAL_EOL();
          SERIAL_ECHOLNPAIR("retract_hop: ", info.retract_hop);
        #endif
        SERIAL_ECHOLNPAIR("cmd_queue_index_r: ", int(info.cmd_queue_index_r));
        SERIAL_ECHOLNPAIR("commands_in_queue: ", int(info.commands_in_queue));
        for (uint8_t i = 0; i < info.commands_in_queue; i++) SERIAL_ECHOLNPAIR("> ", info.command_queue[i]);
        SERIAL_ECHOLNPAIR("sd_filename: ", info.sd_filename);
        SERIAL_ECHOLNPAIR("sdpos: ", info.sdpos);
        SERIAL_ECHOLNPAIR("print_job_elapsed: ", info.print_job_elapsed);
      }
      else
Esempio n. 4
0
/**
 * M900: Get or Set Linear Advance K-factor
 *
 *  K<factor>   Set advance K factor
 */
void GcodeSuite::M900() {

  #if EXTRUDERS < 2
    constexpr uint8_t tmp_extruder = 0;
  #else
    const uint8_t tmp_extruder = parser.seenval('T') ? parser.value_int() : active_extruder;
    if (tmp_extruder >= EXTRUDERS) {
      SERIAL_ECHOLNPGM("?T value out of range.");
      return;
    }
  #endif

  if (parser.seenval('K')) {
    const float newK = parser.floatval('K');
    if (WITHIN(newK, 0, 10)) {
      planner.synchronize();
      planner.extruder_advance_K[tmp_extruder] = newK;
    }
    else
      SERIAL_ECHOLNPGM("?K value out of range (0-10).");
  }
  else {
    SERIAL_ECHO_START();
    #if EXTRUDERS < 2
      SERIAL_ECHOLNPAIR("Advance K=", planner.extruder_advance_K[0]);
    #else
      SERIAL_ECHOPGM("Advance K");
      LOOP_L_N(i, EXTRUDERS) {
        SERIAL_CHAR(' '); SERIAL_ECHO(int(i));
        SERIAL_CHAR('='); SERIAL_ECHO(planner.extruder_advance_K[i]);
      }
      SERIAL_EOL();
    #endif
  }
Esempio n. 5
0
 void PrintCounter::debug(const char func[]) {
   if (DEBUGGING(INFO)) {
     SERIAL_ECHOPGM("PrintCounter::");
     serialprintPGM(func);
     SERIAL_ECHOLNPGM("()");
   }
 }
Esempio n. 6
0
void CardReader::chdir(const char* relpath)
{
	SdFile newfile;
	SdFile* parent=&root;

	if(workDir.isOpen())
	{ parent=&workDir; }

	if(!newfile.open(*parent,relpath, O_READ))
	{
		SERIAL_ECHO_START;
		SERIAL_ECHOPGM(MSG_SD_CANT_ENTER_SUBDIR);
		SERIAL_ECHOLN(relpath);
	}
	else
	{
		if(workDirDepth < MAX_DIR_DEPTH)
		{
			for(int d = ++workDirDepth; d--;)
			{ workDirParents[d+1] = workDirParents[d]; }
			workDirParents[0]=*parent;
		}
		workDir=newfile;
	}
}
Esempio n. 7
0
 void Stopwatch::debug(const char func[]) {
   if (DEBUGGING(INFO)) {
     SERIAL_ECHOPGM("Stopwatch::");
     serialprintPGM(func);
     SERIAL_ECHOLNPGM("()");
   }
 }
Esempio n. 8
0
void checkHitEndstops()
{
 if( endstop_x_hit || endstop_y_hit || endstop_z_hit) {
   SERIAL_ECHO_START;
   SERIAL_ECHOPGM(MSG_ENDSTOPS_HIT);
   if(endstop_x_hit) {
     SERIAL_ECHOPAIR(" X:",(float)endstops_trigsteps[X_AXIS]/axis_steps_per_unit[X_AXIS]);
     LCD_MESSAGEPGM(MSG_ENDSTOPS_HIT "X");
   }
   if(endstop_y_hit) {
     SERIAL_ECHOPAIR(" Y:",(float)endstops_trigsteps[Y_AXIS]/axis_steps_per_unit[Y_AXIS]);
     LCD_MESSAGEPGM(MSG_ENDSTOPS_HIT "Y");
   }
   if(endstop_z_hit) {
     SERIAL_ECHOPAIR(" Z:",(float)endstops_trigsteps[Z_AXIS]/axis_steps_per_unit[Z_AXIS]);
     LCD_MESSAGEPGM(MSG_ENDSTOPS_HIT "Z");
   }
   SERIAL_ECHOLN("");
   endstop_x_hit=false;
   endstop_y_hit=false;
   endstop_z_hit=false;
#ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED
   if (abort_on_endstop_hit)
   {
     card.sdprinting = false;
     card.closefile();
     quickStop();
     setTargetHotend0(0);
     setTargetHotend1(0);
     setTargetHotend2(0);
   }
#endif
 }
}
Esempio n. 9
0
void checkHitEndstops()
{
 if( endstop_x_hit || endstop_y_hit || endstop_z_hit || endstop_p_hit || endstop_v_hit) {
   SERIAL_ECHO_START;
   SERIAL_ECHOPGM(MSG_ENDSTOPS_HIT);
   if(endstop_x_hit) {
     SERIAL_ECHOPAIR(" X:",(float)endstops_trigsteps[X_AXIS]/axis_steps_per_unit[X_AXIS]);
   }
   if(endstop_y_hit) {
     SERIAL_ECHOPAIR(" Y:",(float)endstops_trigsteps[Y_AXIS]/axis_steps_per_unit[Y_AXIS]);
   }
   if(endstop_z_hit) {
     SERIAL_ECHOPAIR(" Z:",(float)endstops_trigsteps[Z_AXIS]/axis_steps_per_unit[Z_AXIS]);
   }
   if(endstop_p_hit) {
     SERIAL_ECHOPAIR(" P:",(float)endstops_trigsteps[P_AXIS]/axis_steps_per_unit[P_AXIS]);
   }
   if(endstop_v_hit) {
     SERIAL_ECHOPAIR(" V:",(float)endstops_trigsteps[V_AXIS]/axis_steps_per_unit[V_AXIS]);
   }

   SERIAL_ECHOLN("");
   endstop_x_hit=false;
   endstop_y_hit=false;
   endstop_z_hit=false;
   endstop_p_hit=false;
   endstop_v_hit=false;
 }
}
Esempio n. 10
0
void Mixer::normalize(const uint8_t tool_index) {
  float cmax = 0;
  #ifdef MIXER_NORMALIZER_DEBUG
    float csum = 0;
  #endif
  MIXER_STEPPER_LOOP(i) {
    const float v = collector[i];
    NOLESS(cmax, v);
    #ifdef MIXER_NORMALIZER_DEBUG
      csum += v;
    #endif
  }
  #ifdef MIXER_NORMALIZER_DEBUG
    SERIAL_ECHOPGM("Mixer: Old relation : [ ");
    MIXER_STEPPER_LOOP(i) {
      SERIAL_ECHO_F(collector[i] / csum, 3);
      SERIAL_CHAR(' ');
    }
    SERIAL_ECHOLNPGM("]");
  #endif

  // Scale all values so their maximum is COLOR_A_MASK
  const float scale = float(COLOR_A_MASK) / cmax;
  MIXER_STEPPER_LOOP(i) color[tool_index][i] = collector[i] * scale;

  #ifdef MIXER_NORMALIZER_DEBUG
    csum = 0;
    SERIAL_ECHOPGM("Mixer: Normalize to : [ ");
    MIXER_STEPPER_LOOP(i) {
      SERIAL_ECHO(uint16_t(color[tool_index][i]));
      SERIAL_CHAR(' ');
      csum += color[tool_index][i];
    }
    SERIAL_ECHOLNPGM("]");
    SERIAL_ECHOPGM("Mixer: New relation : [ ");
    MIXER_STEPPER_LOOP(i) {
      SERIAL_ECHO_F(uint16_t(color[tool_index][i]) / csum, 3);
      SERIAL_CHAR(' ');
    }
    SERIAL_ECHOLNPGM("]");
  #endif

  #if ENABLED(GRADIENT_MIX)
    refresh_gradient();
  #endif
}
Esempio n. 11
0
  /**
   * Get a long pretty path based on a DOS 8.3 path
   */
  void CardReader::printLongPath(char *path) {
    lsAction = LS_GetFilename;

    int i, pathLen = strlen(path);

    // SERIAL_ECHOPGM("Full Path: "); SERIAL_ECHOLN(path);

    // Zero out slashes to make segments
    for (i = 0; i < pathLen; i++) if (path[i] == '/') path[i] = '\0';

    SdFile diveDir = root; // start from the root for segment 1
    for (i = 0; i < pathLen;) {

      if (path[i] == '\0') i++; // move past a single nul

      char *segment = &path[i]; // The segment after most slashes

      // If a segment is empty (extra-slash) then exit
      if (!*segment) break;

      // Go to the next segment
      while (path[++i]) { }

      // SERIAL_ECHOPGM("Looking for segment: "); SERIAL_ECHOLN(segment);

      // Find the item, setting the long filename
      diveDir.rewind();
      lsDive("", diveDir, segment);

      // Print /LongNamePart to serial output
      SERIAL_PROTOCOLCHAR('/');
      SERIAL_PROTOCOL(longFilename[0] ? longFilename : "???");

      // If the filename was printed then that's it
      if (!filenameIsDir) break;

      // SERIAL_ECHOPGM("Opening dir: "); SERIAL_ECHOLN(segment);

      // Open the sub-item as the new dive parent
      SdFile dir;
      if (!dir.open(diveDir, segment, O_READ)) {
        SERIAL_EOL;
        SERIAL_ECHO_START;
        SERIAL_ECHOPGM(MSG_SD_CANT_OPEN_SUBDIR);
        SERIAL_ECHO(segment);
        break;
      }

      diveDir.close();
      diveDir = dir;

    } // while i<pathLen

    SERIAL_EOL;
  }
Esempio n. 12
0
void automatic_current_control(TMC2130Stepper &st, String axisID) {
  // Check otpw even if we don't use automatic control. Allows for flag inspection.
  const bool is_otpw = st.checkOT();

  // Report if a warning was triggered
  static bool previous_otpw = false;
  if (is_otpw && !previous_otpw) {
    char timestamp[10];
    duration_t elapsed = print_job_timer.duration();
    const bool has_days = (elapsed.value > 60*60*24L);
    (void)elapsed.toDigital(timestamp, has_days);
    SERIAL_ECHO(timestamp);
    SERIAL_ECHOPGM(": ");
    SERIAL_ECHO(axisID);
    SERIAL_ECHOLNPGM(" driver overtemperature warning!");
  }
  previous_otpw = is_otpw;

  #if ENABLED(AUTOMATIC_CURRENT_CONTROL) && CURRENT_STEP > 0
    // Return if user has not enabled current control start with M906 S1.
    if (!auto_current_control) return;

    /**
     * Decrease current if is_otpw is true.
     * Bail out if driver is disabled.
     * Increase current if OTPW has not been triggered yet.
     */
    uint16_t current = st.getCurrent();
    if (is_otpw) {
      st.setCurrent(current - CURRENT_STEP, R_SENSE, HOLD_MULTIPLIER);
      #if ENABLED(REPORT_CURRENT_CHANGE)
        SERIAL_ECHO(axisID);
        SERIAL_ECHOPAIR(" current decreased to ", st.getCurrent());
      #endif
    }

    else if (!st.isEnabled())
      return;

    else if (!is_otpw && !st.getOTPW()) {
      current += CURRENT_STEP;
      if (current <= AUTO_ADJUST_MAX) {
        st.setCurrent(current, R_SENSE, HOLD_MULTIPLIER);
        #if ENABLED(REPORT_CURRENT_CHANGE)
          SERIAL_ECHO(axisID);
          SERIAL_ECHOPAIR(" current increased to ", st.getCurrent());
        #endif
      }
    }
    SERIAL_EOL();
  #endif
}
Esempio n. 13
0
void Endstops::report_state() {
  if (endstop_hit_bits) {
    #if ENABLED(ULTRA_LCD)
      char chrX = ' ', chrY = ' ', chrZ = ' ', chrP = ' ';
      #define _SET_STOP_CHAR(A,C) (chr## A = C)
    #else
      #define _SET_STOP_CHAR(A,C) ;
    #endif

    #define _ENDSTOP_HIT_ECHO(A,C) do{ \
      SERIAL_ECHOPAIR(" " STRINGIFY(A) ":", stepper.triggered_position_mm(A ##_AXIS)); \
      _SET_STOP_CHAR(A,C); }while(0)

    #define _ENDSTOP_HIT_TEST(A,C) \
      if (TEST(endstop_hit_bits, A ##_MIN) || TEST(endstop_hit_bits, A ##_MAX)) \
        _ENDSTOP_HIT_ECHO(A,C)

    SERIAL_ECHO_START;
    SERIAL_ECHOPGM(MSG_ENDSTOPS_HIT);
    _ENDSTOP_HIT_TEST(X, 'X');
    _ENDSTOP_HIT_TEST(Y, 'Y');
    _ENDSTOP_HIT_TEST(Z, 'Z');

    #if ENABLED(Z_MIN_PROBE_ENDSTOP)
      #define P_AXIS Z_AXIS
      if (TEST(endstop_hit_bits, Z_MIN_PROBE)) _ENDSTOP_HIT_ECHO(P, 'P');
    #endif
    SERIAL_EOL;

    #if ENABLED(ULTRA_LCD)
      char msg[3 * strlen(MSG_LCD_ENDSTOPS) + 8 + 1]; // Room for a UTF 8 string
      sprintf_P(msg, PSTR(MSG_LCD_ENDSTOPS " %c %c %c %c"), chrX, chrY, chrZ, chrP);
      lcd_setstatus(msg);
    #endif

    hit_on_purpose();

    #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) && ENABLED(SDSUPPORT)
      if (stepper.abort_on_endstop_hit) {
        card.sdprinting = false;
        card.closefile();
        quickstop_stepper();
        thermalManager.disable_all_heaters(); // switch off all heaters.
      }
    #endif
  }
} // Endstops::report_state
Esempio n. 14
0
void CardReader::chdir(const char * relpath) {
  SdFile newfile;
  SdFile *parent = &root;

  if (workDir.isOpen()) parent = &workDir;

  if (!newfile.open(*parent, relpath, O_READ)) {
    SERIAL_ECHO_START;
    SERIAL_ECHOPGM(MSG_SD_CANT_ENTER_SUBDIR);
    SERIAL_ECHOLN(relpath);
  }
  else {
    if (workDirDepth < MAX_DIR_DEPTH)
      workDirParents[workDirDepth++] = *parent;
    workDir = newfile;
  }
}
Esempio n. 15
0
/**
 * Extrapolate a single point from its neighbors
 */
static void extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir) {
  #if ENABLED(DEBUG_LEVELING_FEATURE)
    if (DEBUGGING(LEVELING)) {
      SERIAL_ECHOPGM("Extrapolate [");
      if (x < 10) SERIAL_CHAR(' ');
      SERIAL_ECHO((int)x);
      SERIAL_CHAR(xdir ? (xdir > 0 ? '+' : '-') : ' ');
      SERIAL_CHAR(' ');
      if (y < 10) SERIAL_CHAR(' ');
      SERIAL_ECHO((int)y);
      SERIAL_CHAR(ydir ? (ydir > 0 ? '+' : '-') : ' ');
      SERIAL_CHAR(']');
    }
  #endif
  if (!isnan(z_values[x][y])) {
    #if ENABLED(DEBUG_LEVELING_FEATURE)
      if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM(" (done)");
    #endif
    return;  // Don't overwrite good values.
  }
  SERIAL_EOL();

  // Get X neighbors, Y neighbors, and XY neighbors
  const uint8_t x1 = x + xdir, y1 = y + ydir, x2 = x1 + xdir, y2 = y1 + ydir;
  float a1 = z_values[x1][y ], a2 = z_values[x2][y ],
        b1 = z_values[x ][y1], b2 = z_values[x ][y2],
        c1 = z_values[x1][y1], c2 = z_values[x2][y2];

  // Treat far unprobed points as zero, near as equal to far
  if (isnan(a2)) a2 = 0.0;
  if (isnan(a1)) a1 = a2;
  if (isnan(b2)) b2 = 0.0;
  if (isnan(b1)) b1 = b2;
  if (isnan(c2)) c2 = 0.0;
  if (isnan(c1)) c1 = c2;

  const float a = 2 * a1 - a2, b = 2 * b1 - b2, c = 2 * c1 - c2;

  // Take the average instead of the median
  z_values[x][y] = (a + b + c) / 3.0;

  // Median is robust (ignores outliers).
  // z_values[x][y] = (a < b) ? ((b < c) ? b : (c < a) ? a : c)
  //                                : ((c < b) ? b : (a < c) ? a : c);
}
Esempio n. 16
0
void checkHitEndstops() {
  if (endstop_x_hit || endstop_y_hit || endstop_z_hit || endstop_z_probe_hit) { // #ifdef || endstop_z_probe_hit to save space if needed.
    SERIAL_ECHO_START;
    SERIAL_ECHOPGM(MSG_ENDSTOPS_HIT);
    if (endstop_x_hit) {
      SERIAL_ECHOPAIR(" X:", (float)endstops_trigsteps[X_AXIS] / axis_steps_per_unit[X_AXIS]);
      LCD_MESSAGEPGM(MSG_ENDSTOPS_HIT "X");
    }
    if (endstop_y_hit) {
      SERIAL_ECHOPAIR(" Y:", (float)endstops_trigsteps[Y_AXIS] / axis_steps_per_unit[Y_AXIS]);
      LCD_MESSAGEPGM(MSG_ENDSTOPS_HIT "Y");
    }
    if (endstop_z_hit) {
      SERIAL_ECHOPAIR(" Z:", (float)endstops_trigsteps[Z_AXIS] / axis_steps_per_unit[Z_AXIS]);
      LCD_MESSAGEPGM(MSG_ENDSTOPS_HIT "Z");
    }
    #ifdef Z_PROBE_ENDSTOP
    if (endstop_z_probe_hit) {
      SERIAL_ECHOPAIR(" Z_PROBE:", (float)endstops_trigsteps[Z_AXIS] / axis_steps_per_unit[Z_AXIS]);
      LCD_MESSAGEPGM(MSG_ENDSTOPS_HIT "ZP");
    }
    #endif
    SERIAL_EOL;

    endstops_hit_on_purpose();

    #if defined(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) && defined(SDSUPPORT)
      if (abort_on_endstop_hit) {
        card.sdprinting = false;
        card.closefile();
        quickStop();
        setTargetHotend0(0);
        setTargetHotend1(0);
        setTargetHotend2(0);
        setTargetHotend3(0);
        setTargetBed(0);
      }
    #endif
  }
}
Esempio n. 17
0
void checkHitEndstops() {
  if (endstop_hit_bits) {
    SERIAL_ECHO_START;
    SERIAL_ECHOPGM(MSG_ENDSTOPS_HIT);
    if (endstop_hit_bits & BIT(X_MIN)) {
      SERIAL_ECHOPAIR(" X:", (float)endstops_trigsteps[X_AXIS] / axis_steps_per_unit[X_AXIS]);
      LCD_MESSAGEPGM(MSG_ENDSTOPS_HIT "X");
    }
    if (endstop_hit_bits & BIT(Y_MIN)) {
      SERIAL_ECHOPAIR(" Y:", (float)endstops_trigsteps[Y_AXIS] / axis_steps_per_unit[Y_AXIS]);
      LCD_MESSAGEPGM(MSG_ENDSTOPS_HIT "Y");
    }
    if (endstop_hit_bits & BIT(Z_MIN)) {
      SERIAL_ECHOPAIR(" Z:", (float)endstops_trigsteps[Z_AXIS] / axis_steps_per_unit[Z_AXIS]);
      LCD_MESSAGEPGM(MSG_ENDSTOPS_HIT "Z");
    }
    #ifdef Z_PROBE_ENDSTOP
    if (endstop_hit_bits & BIT(Z_PROBE)) {
      SERIAL_ECHOPAIR(" Z_PROBE:", (float)endstops_trigsteps[Z_AXIS] / axis_steps_per_unit[Z_AXIS]);
      LCD_MESSAGEPGM(MSG_ENDSTOPS_HIT "ZP");
    }
    #endif
    SERIAL_EOL;

    endstops_hit_on_purpose();

    #if defined(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) && defined(SDSUPPORT)
      if (abort_on_endstop_hit) {
        card.sdprinting = false;
        card.closefile();
        quickStop();
        disable_all_heaters(); // switch off all heaters.
      }
    #endif
  }
}
Esempio n. 18
0
 void GCodeParser::debug() {
   SERIAL_ECHOPAIR("Command: ", command_ptr);
   SERIAL_ECHOPAIR(" (", command_letter);
   SERIAL_ECHO(codenum);
   SERIAL_ECHOLNPGM(")");
   #if ENABLED(FASTER_GCODE_PARSER)
     SERIAL_ECHO(" args: \"");
     for (char c = 'A'; c <= 'Z'; ++c)
       if (seen(c)) { SERIAL_CHAR(c); SERIAL_CHAR(' '); }
   #else
     SERIAL_ECHOPAIR(" args: \"", command_args);
   #endif
   SERIAL_ECHOPGM("\"");
   if (string_arg) {
     SERIAL_ECHOPGM(" string: \"");
     SERIAL_ECHO(string_arg);
     SERIAL_CHAR('"');
   }
   SERIAL_ECHOPGM("\n\n");
   for (char c = 'A'; c <= 'Z'; ++c) {
     if (seen(c)) {
       SERIAL_ECHOPAIR("Code '", c); SERIAL_ECHOPGM("':");
       if (has_value()) {
         SERIAL_ECHOPAIR("\n    float: ", value_float());
         SERIAL_ECHOPAIR("\n     long: ", value_long());
         SERIAL_ECHOPAIR("\n    ulong: ", value_ulong());
         SERIAL_ECHOPAIR("\n   millis: ", value_millis());
         SERIAL_ECHOPAIR("\n   sec-ms: ", value_millis_from_seconds());
         SERIAL_ECHOPAIR("\n      int: ", value_int());
         SERIAL_ECHOPAIR("\n   ushort: ", value_ushort());
         SERIAL_ECHOPAIR("\n     byte: ", (int)value_byte());
         SERIAL_ECHOPAIR("\n     bool: ", (int)value_bool());
         SERIAL_ECHOPAIR("\n   linear: ", value_linear_units());
         SERIAL_ECHOPAIR("\n  celsius: ", value_celsius());
       }
       else
         SERIAL_ECHOPGM(" (no value)");
       SERIAL_ECHOPGM("\n\n");
     }
   }
 }
Esempio n. 19
0
  void log_machine_info() {
    SERIAL_ECHOLNPGM("Machine Type: "
      #if ENABLED(DELTA)
        "Delta"
      #elif IS_SCARA
        "SCARA"
      #elif IS_CORE
        "Core"
      #else
        "Cartesian"
      #endif
    );

    SERIAL_ECHOLNPGM("Probe: "
      #if ENABLED(PROBE_MANUALLY)
        "PROBE_MANUALLY"
      #elif ENABLED(FIX_MOUNTED_PROBE)
        "FIX_MOUNTED_PROBE"
      #elif ENABLED(BLTOUCH)
        "BLTOUCH"
      #elif HAS_Z_SERVO_PROBE
        "SERVO PROBE"
      #elif ENABLED(Z_PROBE_SLED)
        "Z_PROBE_SLED"
      #elif ENABLED(Z_PROBE_ALLEN_KEY)
        "Z_PROBE_ALLEN_KEY"
      #else
        "NONE"
      #endif
    );

    #if HAS_BED_PROBE
      SERIAL_ECHOPAIR(
        "Probe Offset X:" STRINGIFY(X_PROBE_OFFSET_FROM_EXTRUDER)
                    " Y:" STRINGIFY(Y_PROBE_OFFSET_FROM_EXTRUDER)
                    " Z:", zprobe_zoffset
      );
      if ((X_PROBE_OFFSET_FROM_EXTRUDER) > 0)
        SERIAL_ECHOPGM(" (Right");
      else if ((X_PROBE_OFFSET_FROM_EXTRUDER) < 0)
        SERIAL_ECHOPGM(" (Left");
      else if ((Y_PROBE_OFFSET_FROM_EXTRUDER) != 0)
        SERIAL_ECHOPGM(" (Middle");
      else
        SERIAL_ECHOPGM(" (Aligned With");

      if ((Y_PROBE_OFFSET_FROM_EXTRUDER) > 0) {
        #if IS_SCARA
          SERIAL_ECHOPGM("-Distal");
        #else
          SERIAL_ECHOPGM("-Back");
        #endif
      }
      else if ((Y_PROBE_OFFSET_FROM_EXTRUDER) < 0) {
        #if IS_SCARA
          SERIAL_ECHOPGM("-Proximal");
        #else
          SERIAL_ECHOPGM("-Front");
        #endif
      }
      else if ((X_PROBE_OFFSET_FROM_EXTRUDER) != 0)
        SERIAL_ECHOPGM("-Center");

      if (zprobe_zoffset < 0)
        SERIAL_ECHOPGM(" & Below");
      else if (zprobe_zoffset > 0)
        SERIAL_ECHOPGM(" & Above");
      else
        SERIAL_ECHOPGM(" & Same Z as");
      SERIAL_ECHOLNPGM(" Nozzle)");
    #endif

    #if HAS_ABL_OR_UBL
      SERIAL_ECHOLNPGM("Auto Bed Leveling: "
        #if ENABLED(AUTO_BED_LEVELING_LINEAR)
          "LINEAR"
        #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
          "BILINEAR"
        #elif ENABLED(AUTO_BED_LEVELING_3POINT)
          "3POINT"
        #elif ENABLED(AUTO_BED_LEVELING_UBL)
          "UBL"
        #endif
      );
      if (planner.leveling_active) {
        SERIAL_ECHOLNPGM(" (enabled)");
        #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
          if (planner.z_fade_height)
            SERIAL_ECHOLNPAIR("Z Fade: ", planner.z_fade_height);
        #endif
        #if ABL_PLANAR
          const float diff[XYZ] = {
            planner.get_axis_position_mm(X_AXIS) - current_position[X_AXIS],
            planner.get_axis_position_mm(Y_AXIS) - current_position[Y_AXIS],
            planner.get_axis_position_mm(Z_AXIS) - current_position[Z_AXIS]
          };
          SERIAL_ECHOPGM("ABL Adjustment X");
          if (diff[X_AXIS] > 0) SERIAL_CHAR('+');
          SERIAL_ECHO(diff[X_AXIS]);
          SERIAL_ECHOPGM(" Y");
          if (diff[Y_AXIS] > 0) SERIAL_CHAR('+');
          SERIAL_ECHO(diff[Y_AXIS]);
          SERIAL_ECHOPGM(" Z");
          if (diff[Z_AXIS] > 0) SERIAL_CHAR('+');
          SERIAL_ECHO(diff[Z_AXIS]);
        #else
          #if ENABLED(AUTO_BED_LEVELING_UBL)
            SERIAL_ECHOPGM("UBL Adjustment Z");
            const float rz = ubl.get_z_correction(current_position[X_AXIS], current_position[Y_AXIS]);
          #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
            SERIAL_ECHOPGM("ABL Adjustment Z");
            const float rz = bilinear_z_offset(current_position);
          #endif
          SERIAL_ECHO(ftostr43sign(rz, '+'));
          #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
            if (planner.z_fade_height) {
              SERIAL_ECHOPAIR(" (", ftostr43sign(rz * planner.fade_scaling_factor_for_z(current_position[Z_AXIS]), '+'));
              SERIAL_CHAR(')');
            }
          #endif
        #endif
      }
      else
        SERIAL_ECHOLNPGM(" (disabled)");

      SERIAL_EOL();

    #elif ENABLED(MESH_BED_LEVELING)

      SERIAL_ECHOPGM("Mesh Bed Leveling");
      if (planner.leveling_active) {
        SERIAL_ECHOLNPGM(" (enabled)");
        SERIAL_ECHOPAIR("MBL Adjustment Z", ftostr43sign(mbl.get_z(current_position[X_AXIS], current_position[Y_AXIS]
          #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
            , 1.0
          #endif
        ), '+'));
        #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
          if (planner.z_fade_height) {
            SERIAL_ECHOPAIR(" (", ftostr43sign(
              mbl.get_z(current_position[X_AXIS], current_position[Y_AXIS], planner.fade_scaling_factor_for_z(current_position[Z_AXIS])), '+'
            ));
            SERIAL_CHAR(')');
          }
        #endif
      }
      else
        SERIAL_ECHOPGM(" (disabled)");

      SERIAL_EOL();

    #endif // MESH_BED_LEVELING
  }
void Config_PrintSettings(bool forReplay) {
  // Always have this function, even with EEPROM_SETTINGS disabled, the current values will be shown

  CONFIG_ECHO_START;

  if (!forReplay) {
    SERIAL_ECHOLNPGM("Steps per unit:");
    CONFIG_ECHO_START;
  }
  SERIAL_ECHOPAIR("  M92 X", axis_steps_per_unit[X_AXIS]);
  SERIAL_ECHOPAIR(" Y", axis_steps_per_unit[Y_AXIS]);
  SERIAL_ECHOPAIR(" Z", axis_steps_per_unit[Z_AXIS]);
  SERIAL_ECHOPAIR(" E", axis_steps_per_unit[E_AXIS]);
  SERIAL_EOL;

  CONFIG_ECHO_START;

  #if ENABLED(SCARA)
    if (!forReplay) {
      SERIAL_ECHOLNPGM("Scaling factors:");
      CONFIG_ECHO_START;
    }
    SERIAL_ECHOPAIR("  M365 X", axis_scaling[X_AXIS]);
    SERIAL_ECHOPAIR(" Y", axis_scaling[Y_AXIS]);
    SERIAL_ECHOPAIR(" Z", axis_scaling[Z_AXIS]);
    SERIAL_EOL;
    CONFIG_ECHO_START;
  #endif // SCARA

  if (!forReplay) {
    SERIAL_ECHOLNPGM("Maximum feedrates (mm/s):");
    CONFIG_ECHO_START;
  }
  SERIAL_ECHOPAIR("  M203 X", max_feedrate[X_AXIS]);
  SERIAL_ECHOPAIR(" Y", max_feedrate[Y_AXIS]);
  SERIAL_ECHOPAIR(" Z", max_feedrate[Z_AXIS]);
  SERIAL_ECHOPAIR(" E", max_feedrate[E_AXIS]);
  SERIAL_EOL;

  CONFIG_ECHO_START;
  if (!forReplay) {
    SERIAL_ECHOLNPGM("Maximum Acceleration (mm/s2):");
    CONFIG_ECHO_START;
  }
  SERIAL_ECHOPAIR("  M201 X", max_acceleration_units_per_sq_second[X_AXIS]);
  SERIAL_ECHOPAIR(" Y", max_acceleration_units_per_sq_second[Y_AXIS]);
  SERIAL_ECHOPAIR(" Z", max_acceleration_units_per_sq_second[Z_AXIS]);
  SERIAL_ECHOPAIR(" E", max_acceleration_units_per_sq_second[E_AXIS]);
  SERIAL_EOL;
  CONFIG_ECHO_START;
  if (!forReplay) {
    SERIAL_ECHOLNPGM("Accelerations: P=printing, R=retract and T=travel");
    CONFIG_ECHO_START;
  }
  SERIAL_ECHOPAIR("  M204 P", acceleration);
  SERIAL_ECHOPAIR(" R", retract_acceleration);
  SERIAL_ECHOPAIR(" T", travel_acceleration);
  SERIAL_EOL;

  CONFIG_ECHO_START;
  if (!forReplay) {
    SERIAL_ECHOLNPGM("Advanced variables: S=Min feedrate (mm/s), T=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)");
    CONFIG_ECHO_START;
  }
  SERIAL_ECHOPAIR("  M205 S", minimumfeedrate);
  SERIAL_ECHOPAIR(" T", mintravelfeedrate);
  SERIAL_ECHOPAIR(" B", minsegmenttime);
  SERIAL_ECHOPAIR(" X", max_xy_jerk);
  SERIAL_ECHOPAIR(" Z", max_z_jerk);
  SERIAL_ECHOPAIR(" E", max_e_jerk);
  SERIAL_EOL;

  CONFIG_ECHO_START;
  if (!forReplay) {
    SERIAL_ECHOLNPGM("Home offset (mm):");
    CONFIG_ECHO_START;
  }
  SERIAL_ECHOPAIR("  M206 X", home_offset[X_AXIS]);
  SERIAL_ECHOPAIR(" Y", home_offset[Y_AXIS]);
  SERIAL_ECHOPAIR(" Z", home_offset[Z_AXIS]);
  SERIAL_EOL;

  #if ENABLED(MESH_BED_LEVELING)
    if (!forReplay) {
      SERIAL_ECHOLNPGM("Mesh bed leveling:");
      CONFIG_ECHO_START;
    }
    SERIAL_ECHOPAIR("  M420 S", (unsigned long)mbl.active);
    SERIAL_ECHOPAIR(" X", (unsigned long)MESH_NUM_X_POINTS);
    SERIAL_ECHOPAIR(" Y", (unsigned long)MESH_NUM_Y_POINTS);
    SERIAL_EOL;
    for (int y = 0; y < MESH_NUM_Y_POINTS; y++) {
      for (int x = 0; x < MESH_NUM_X_POINTS; x++) {
        CONFIG_ECHO_START;
        SERIAL_ECHOPAIR("  M421 X", mbl.get_x(x));
        SERIAL_ECHOPAIR(" Y", mbl.get_y(y));
        SERIAL_ECHOPAIR(" Z", mbl.z_values[y][x]);
        SERIAL_EOL;
      }
    }
  #endif

  #if ENABLED(DELTA)
    CONFIG_ECHO_START;
    if (!forReplay) {
      SERIAL_ECHOLNPGM("Endstop adjustment (mm):");
      CONFIG_ECHO_START;
    }
    SERIAL_ECHOPAIR("  M666 X", endstop_adj[X_AXIS]);
    SERIAL_ECHOPAIR(" Y", endstop_adj[Y_AXIS]);
    SERIAL_ECHOPAIR(" Z", endstop_adj[Z_AXIS]);
    SERIAL_EOL;
    CONFIG_ECHO_START;
    SERIAL_ECHOLNPGM("Delta settings: L=delta_diagonal_rod, R=delta_radius, S=delta_segments_per_second");
    CONFIG_ECHO_START;
    SERIAL_ECHOPAIR("  M665 L", delta_diagonal_rod);
    SERIAL_ECHOPAIR(" R", delta_radius);
    SERIAL_ECHOPAIR(" S", delta_segments_per_second);
    SERIAL_EOL;
  #elif ENABLED(Z_DUAL_ENDSTOPS)
    CONFIG_ECHO_START;
    if (!forReplay) {
      SERIAL_ECHOLNPGM("Z2 Endstop adjustment (mm):");
      CONFIG_ECHO_START;
    }
    SERIAL_ECHOPAIR("  M666 Z", z_endstop_adj);
    SERIAL_EOL;
  #endif // DELTA

  #if ENABLED(ULTIPANEL)
    CONFIG_ECHO_START;
    if (!forReplay) {
      SERIAL_ECHOLNPGM("Material heatup parameters:");
      CONFIG_ECHO_START;
    }
    SERIAL_ECHOPAIR("  M145 M0 H", (unsigned long)plaPreheatHotendTemp);
    SERIAL_ECHOPAIR(" B", (unsigned long)plaPreheatHPBTemp);
    SERIAL_ECHOPAIR(" F", (unsigned long)plaPreheatFanSpeed);
    SERIAL_EOL;
    CONFIG_ECHO_START;
    SERIAL_ECHOPAIR("  M145 M1 H", (unsigned long)absPreheatHotendTemp);
    SERIAL_ECHOPAIR(" B", (unsigned long)absPreheatHPBTemp);
    SERIAL_ECHOPAIR(" F", (unsigned long)absPreheatFanSpeed);
    SERIAL_EOL;
  #endif // ULTIPANEL

  #if ENABLED(PIDTEMP) || ENABLED(PIDTEMPBED)

    CONFIG_ECHO_START;
    if (!forReplay) {
      SERIAL_ECHOLNPGM("PID settings:");
    }
    #if ENABLED(PIDTEMP)
      #if EXTRUDERS > 1
        if (forReplay) {
          for (uint8_t i = 0; i < EXTRUDERS; i++) {
            CONFIG_ECHO_START;
            SERIAL_ECHOPAIR("  M301 E", (unsigned long)i);
            SERIAL_ECHOPAIR(" P", PID_PARAM(Kp, i));
            SERIAL_ECHOPAIR(" I", unscalePID_i(PID_PARAM(Ki, i)));
            SERIAL_ECHOPAIR(" D", unscalePID_d(PID_PARAM(Kd, i)));
            #if ENABLED(PID_ADD_EXTRUSION_RATE)
              SERIAL_ECHOPAIR(" C", PID_PARAM(Kc, i));
              if (i == 0) SERIAL_ECHOPAIR(" L", lpq_len);
            #endif
            SERIAL_EOL;
          }
        }
        else
      #endif // EXTRUDERS > 1
      // !forReplay || EXTRUDERS == 1
      {
        CONFIG_ECHO_START;
        SERIAL_ECHOPAIR("  M301 P", PID_PARAM(Kp, 0)); // for compatibility with hosts, only echo values for E0
        SERIAL_ECHOPAIR(" I", unscalePID_i(PID_PARAM(Ki, 0)));
        SERIAL_ECHOPAIR(" D", unscalePID_d(PID_PARAM(Kd, 0)));
        #if ENABLED(PID_ADD_EXTRUSION_RATE)
          SERIAL_ECHOPAIR(" C", PID_PARAM(Kc, 0));
          SERIAL_ECHOPAIR(" L", lpq_len);
        #endif
        SERIAL_EOL;
      }
    #endif // PIDTEMP

    #if ENABLED(PIDTEMPBED)
      CONFIG_ECHO_START;
      SERIAL_ECHOPAIR("  M304 P", bedKp);
      SERIAL_ECHOPAIR(" I", unscalePID_i(bedKi));
      SERIAL_ECHOPAIR(" D", unscalePID_d(bedKd));
      SERIAL_EOL;
    #endif

  #endif // PIDTEMP || PIDTEMPBED

  #if ENABLED(HAS_LCD_CONTRAST)
    CONFIG_ECHO_START;
    if (!forReplay) {
      SERIAL_ECHOLNPGM("LCD Contrast:");
      CONFIG_ECHO_START;
    }
    SERIAL_ECHOPAIR("  M250 C", (unsigned long)lcd_contrast);
    SERIAL_EOL;
  #endif

  #if ENABLED(FWRETRACT)

    CONFIG_ECHO_START;
    if (!forReplay) {
      SERIAL_ECHOLNPGM("Retract: S=Length (mm) F:Speed (mm/m) Z: ZLift (mm)");
      CONFIG_ECHO_START;
    }
    SERIAL_ECHOPAIR("  M207 S", retract_length);
    #if EXTRUDERS > 1
      SERIAL_ECHOPAIR(" W", retract_length_swap);
    #endif
    SERIAL_ECHOPAIR(" F", retract_feedrate * 60);
    SERIAL_ECHOPAIR(" Z", retract_zlift);
    SERIAL_EOL;
    CONFIG_ECHO_START;
    if (!forReplay) {
      SERIAL_ECHOLNPGM("Recover: S=Extra length (mm) F:Speed (mm/m)");
      CONFIG_ECHO_START;
    }
    SERIAL_ECHOPAIR("  M208 S", retract_recover_length);
    #if EXTRUDERS > 1
      SERIAL_ECHOPAIR(" W", retract_recover_length_swap);
    #endif
    SERIAL_ECHOPAIR(" F", retract_recover_feedrate * 60);
    SERIAL_EOL;
    CONFIG_ECHO_START;
    if (!forReplay) {
      SERIAL_ECHOLNPGM("Auto-Retract: S=0 to disable, 1 to interpret extrude-only moves as retracts or recoveries");
      CONFIG_ECHO_START;
    }
    SERIAL_ECHOPAIR("  M209 S", (unsigned long)(autoretract_enabled ? 1 : 0));
    SERIAL_EOL;

  #endif // FWRETRACT

  /**
   * Volumetric extrusion M200
   */
  if (!forReplay) {
    CONFIG_ECHO_START;
    SERIAL_ECHOPGM("Filament settings:");
    if (volumetric_enabled)
      SERIAL_EOL;
    else
      SERIAL_ECHOLNPGM(" Disabled");
  }

  CONFIG_ECHO_START;
  SERIAL_ECHOPAIR("  M200 D", filament_size[0]);
  SERIAL_EOL;
  #if EXTRUDERS > 1
    CONFIG_ECHO_START;
    SERIAL_ECHOPAIR("  M200 T1 D", filament_size[1]);
    SERIAL_EOL;
    #if EXTRUDERS > 2
      CONFIG_ECHO_START;
      SERIAL_ECHOPAIR("  M200 T2 D", filament_size[2]);
      SERIAL_EOL;
      #if EXTRUDERS > 3
        CONFIG_ECHO_START;
        SERIAL_ECHOPAIR("  M200 T3 D", filament_size[3]);
        SERIAL_EOL;
      #endif
    #endif
  #endif

  if (!volumetric_enabled) {
    CONFIG_ECHO_START;
    SERIAL_ECHOLNPGM("  M200 D0");
  }

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

  reset(); // No codes to report

  // Skip spaces
  while (*p == ' ') ++p;

  // Skip N[-0-9] if included in the command line
  if (*p == 'N' && NUMERIC_SIGNED(p[1])) {
    #if ENABLED(FASTER_GCODE_PARSER)
      //set('N', p + 1);     // (optional) Set the 'N' parameter value
    #endif
    p += 2;                  // skip N[-0-9]
    while (NUMERIC(*p)) ++p; // skip [0-9]*
    while (*p == ' ')   ++p; // skip [ ]*
  }

  // *p now points to the current command, which should be G, M, or T
  command_ptr = p;

  // Get the command letter, which must be G, M, or T
  const char letter = *p++;

  // Nullify asterisk and trailing whitespace
  char *starpos = strchr(p, '*');
  if (starpos) {
    --starpos;                          // *
    while (*starpos == ' ') --starpos;  // spaces...
    starpos[1] = '\0';
  }

  // Bail if the letter is not G, M, or T
  switch (letter) { case 'G': case 'M': case 'T': break; default: return; }

  // Skip spaces to get the numeric part
  while (*p == ' ') p++;

  // Bail if there's no command code number
  if (!NUMERIC(*p)) return;

  // Save the command letter at this point
  // A '?' signifies an unknown command
  command_letter = letter;

  // Get the code number - integer digits only
  codenum = 0;
  do {
    codenum *= 10, codenum += *p++ - '0';
  } while (NUMERIC(*p));

  // Allow for decimal point in command
  #if USE_GCODE_SUBCODES
    if (*p == '.') {
      p++;
      while (NUMERIC(*p))
        subcode *= 10, subcode += *p++ - '0';
    }
  #endif

  // Skip all spaces to get to the first argument, or nul
  while (*p == ' ') p++;

  // The command parameters (if any) start here, for sure!

  #if DISABLED(FASTER_GCODE_PARSER)
    command_args = p; // Scan for parameters in seen()
  #endif

  // Only use string_arg for these M codes
  if (letter == 'M') switch (codenum) { case 23: case 28: case 30: case 117: case 118: case 928: string_arg = p; return; default: break; }

  #if ENABLED(DEBUG_GCODE_PARSER)
    const bool debug = codenum == 800;
  #endif

  /**
   * Find all parameters, set flags and pointers for fast parsing
   *
   * Most codes ignore 'string_arg', but those that want a string will get the right pointer.
   * The following loop assigns the first "parameter" having no numeric value to 'string_arg'.
   * This allows M0/M1 with expire time to work: "M0 S5 You Win!"
   */
  string_arg = NULL;
  while (char code = *p++) {                    // Get the next parameter. A NUL ends the loop

    // Special handling for M32 [P] !/path/to/file.g#
    // The path must be the last parameter
    if (code == '!' && letter == 'M' && codenum == 32) {
      string_arg = p;                           // Name starts after '!'
      char * const lb = strchr(p, '#');         // Already seen '#' as SD char (to pause buffering)
      if (lb) *lb = '\0';                       // Safe to mark the end of the filename
      return;
    }

    // Arguments MUST be uppercase for fast GCode parsing
    #if ENABLED(FASTER_GCODE_PARSER)
      #define PARAM_TEST WITHIN(code, 'A', 'Z')
    #else
      #define PARAM_TEST true
    #endif

    if (PARAM_TEST) {

      while (*p == ' ') p++;                    // Skip spaces between parameters & values
      const bool has_num = DECIMAL_SIGNED(*p);  // The parameter has a number [-+0-9.]

      #if ENABLED(DEBUG_GCODE_PARSER)
        if (debug) {
          SERIAL_ECHOPAIR("Got letter ", code); // DEBUG
          SERIAL_ECHOPAIR(" at index ", (int)(p - command_ptr - 1)); // DEBUG
          if (has_num) SERIAL_ECHOPGM(" (has_num)");
        }
      #endif

      if (!has_num && !string_arg) {            // No value? First time, keep as string_arg
        string_arg = p - 1;
        #if ENABLED(DEBUG_GCODE_PARSER)
          if (debug) SERIAL_ECHOPAIR(" string_arg: ", hex_address((void*)string_arg)); // DEBUG
        #endif
      }

      #if ENABLED(DEBUG_GCODE_PARSER)
        if (debug) SERIAL_EOL();
      #endif

      #if ENABLED(FASTER_GCODE_PARSER)
        set(code, has_num ? p : NULL            // Set parameter exists and pointer (NULL for no number)
          #if ENABLED(DEBUG_GCODE_PARSER)
            , debug
          #endif
        );
      #endif
    }
    else if (!string_arg) {                     // Not A-Z? First time, keep as the string_arg
      string_arg = p - 1;
      #if ENABLED(DEBUG_GCODE_PARSER)
        if (debug) SERIAL_ECHOPAIR(" string_arg: ", hex_address((void*)string_arg)); // DEBUG
      #endif
    }

    if (!WITHIN(*p, 'A', 'Z')) {
      while (*p && NUMERIC(*p)) p++;            // Skip over the value section of a parameter
      while (*p == ' ') p++;                    // Skip over all spaces
    }
  }
}
Esempio n. 24
0
/**
 * Dive into a folder and recurse depth-first to perform a pre-set operation lsAction:
 *   LS_Count       - Add +1 to nrFiles for every file within the parent
 *   LS_GetFilename - Get the filename of the file indexed by nrFiles
 *   LS_SerialPrint - Print the full path of each file to serial output
 */
void CardReader::lsDive(const char *prepend, SdFile parent, const char * const match/*=NULL*/) {
  dir_t p;
  uint8_t cnt = 0;

  // Read the next entry from a directory
  while (parent.readDir(p, longFilename) > 0) {

    // If the entry is a directory and the action is LS_SerialPrint
    if (DIR_IS_SUBDIR(&p) && lsAction != LS_Count && lsAction != LS_GetFilename) {

      // Get the short name for the item, which we know is a folder
      char lfilename[FILENAME_LENGTH];
      createFilename(lfilename, p);

      // Allocate enough stack space for the full path to a folder, trailing slash, and nul
      boolean prepend_is_empty = (prepend[0] == '\0');
      int len = (prepend_is_empty ? 1 : strlen(prepend)) + strlen(lfilename) + 1 + 1;
      char path[len];

      // Append the FOLDERNAME12/ to the passed string.
      // It contains the full path to the "parent" argument.
      // We now have the full path to the item in this folder.
      strcpy(path, prepend_is_empty ? "/" : prepend); // root slash if prepend is empty
      strcat(path, lfilename); // FILENAME_LENGTH-1 characters maximum
      strcat(path, "/");       // 1 character

      // Serial.print(path);

      // Get a new directory object using the full path
      // and dive recursively into it.
      SdFile dir;
      if (!dir.open(parent, lfilename, O_READ)) {
        if (lsAction == LS_SerialPrint) {
          SERIAL_ECHO_START;
          SERIAL_ECHOPGM(MSG_SD_CANT_OPEN_SUBDIR);
          SERIAL_ECHOLN(lfilename);
        }
      }
      lsDive(path, dir);
      // close() is done automatically by destructor of SdFile
    }
    else {
      uint8_t pn0 = p.name[0];
      if (pn0 == DIR_NAME_FREE) break;
      if (pn0 == DIR_NAME_DELETED || pn0 == '.') continue;
      if (longFilename[0] == '.') continue;

      if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;

      filenameIsDir = DIR_IS_SUBDIR(&p);

      if (!filenameIsDir && (p.name[8] != 'G' || p.name[9] == '~')) continue;

      switch (lsAction) {
        case LS_Count:
          nrFiles++;
          break;
        case LS_SerialPrint:
          createFilename(filename, p);
          SERIAL_PROTOCOL(prepend);
          SERIAL_PROTOCOLLN(filename);
          break;
        case LS_GetFilename:
          createFilename(filename, p);
          if (match != NULL) {
            if (strcasecmp(match, filename) == 0) return;
          }
          else if (cnt == nrFiles) return;
          cnt++;
          break;
      }

    }
  } // while readDir
}
Esempio n. 25
0
void Config_PrintSettings()
{  // Always have this function, even with EEPROM_SETTINGS disabled, the current values will be shown
    SERIAL_ECHOLNPGM(STRING_CONFIG_H_AUTHOR);
    SERIAL_ECHOPGM("Compiled: ");
    SERIAL_ECHOLNPGM(__DATE__);
    SERIAL_ECHO_START;
    SERIAL_ECHOLNPGM("Steps per unit:");
    SERIAL_ECHO_START;
    SERIAL_ECHOPAIR("  M92 X",axis_steps_per_unit[0]);
    SERIAL_ECHOPAIR(" Y",axis_steps_per_unit[1]);
    SERIAL_ECHOPAIR(" Z",axis_steps_per_unit[2]);
    SERIAL_ECHOPAIR(" E",axis_steps_per_unit[3]);
    SERIAL_ECHOLN("");
      
    SERIAL_ECHO_START;
    SERIAL_ECHOLNPGM("Maximum feedrates (mm/s):");
    SERIAL_ECHO_START;
    SERIAL_ECHOPAIR("  M203 X",max_feedrate[0]);
    SERIAL_ECHOPAIR(" Y",max_feedrate[1] ); 
    SERIAL_ECHOPAIR(" Z", max_feedrate[2] ); 
    SERIAL_ECHOPAIR(" E", max_feedrate[3]);
    SERIAL_ECHOLN("");

    SERIAL_ECHO_START;
    SERIAL_ECHOLNPGM("Maximum Acceleration (mm/s2):");
    SERIAL_ECHO_START;
    SERIAL_ECHOPAIR("  M201 X" ,max_acceleration_units_per_sq_second[0] ); 
    SERIAL_ECHOPAIR(" Y" , max_acceleration_units_per_sq_second[1] ); 
    SERIAL_ECHOPAIR(" Z" ,max_acceleration_units_per_sq_second[2] );
    SERIAL_ECHOPAIR(" E" ,max_acceleration_units_per_sq_second[3]);
    SERIAL_ECHOLN("");
    SERIAL_ECHO_START;
    SERIAL_ECHOLNPGM("Acceleration: S=acceleration, T=retract acceleration");
    SERIAL_ECHO_START;
    SERIAL_ECHOPAIR("  M204 S",acceleration ); 
    SERIAL_ECHOPAIR(" T" ,retract_acceleration);
    SERIAL_ECHOLN("");

    SERIAL_ECHO_START;
    SERIAL_ECHOLNPGM("Advanced variables: S=Min feedrate (mm/s), T=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)");
    SERIAL_ECHO_START;
    SERIAL_ECHOPAIR("  M205 S",minimumfeedrate ); 
    SERIAL_ECHOPAIR(" T" ,mintravelfeedrate ); 
    SERIAL_ECHOPAIR(" B" ,minsegmenttime ); 
    SERIAL_ECHOPAIR(" X" ,max_xy_jerk ); 
    SERIAL_ECHOPAIR(" Z" ,max_z_jerk);
    SERIAL_ECHOPAIR(" E" ,max_e_jerk);
    SERIAL_ECHOLN(""); 

    SERIAL_ECHO_START;
    SERIAL_ECHOLNPGM("Home offset (mm):");
    SERIAL_ECHO_START;
    SERIAL_ECHOPAIR("  M206 X",add_homeing[0] );
    SERIAL_ECHOPAIR(" Y" ,add_homeing[1] );
    SERIAL_ECHOPAIR(" Z" ,add_homeing[2] );
    SERIAL_ECHOLN("");
#ifdef DELTA
    SERIAL_ECHO_START;
    SERIAL_ECHOLNPGM("Endstop adjustement (mm):");
    SERIAL_ECHO_START;
    SERIAL_ECHOPAIR("  M666 X",endstop_adj[0] );
    SERIAL_ECHOPAIR(" Y" ,endstop_adj[1] );
    SERIAL_ECHOPAIR(" Z" ,endstop_adj[2] );
    SERIAL_ECHOLN("");
#endif
#ifdef PIDTEMP
    SERIAL_ECHO_START;
    SERIAL_ECHOLNPGM("PID settings:");
    SERIAL_ECHO_START;
    SERIAL_ECHOPAIR("   M301 P",Kp); 
    SERIAL_ECHOPAIR(" I" ,unscalePID_i(Ki)); 
    SERIAL_ECHOPAIR(" D" ,unscalePID_d(Kd));
    SERIAL_ECHOLN(""); 
#endif

    SERIAL_ECHO_START;
    SERIAL_ECHOLNPGM("DIGIPOT:");
    SERIAL_ECHO_START;
    SERIAL_ECHOPAIR("  M907 X",digipot_motor_current[0]);
    SERIAL_ECHOPAIR(" Y",digipot_motor_current[1]);
    SERIAL_ECHOPAIR(" Z",digipot_motor_current[2]);
    SERIAL_ECHOPAIR(" E",digipot_motor_current[3]);
    SERIAL_ECHOLN("");

    SERIAL_ECHO_START;
    SERIAL_ECHOLNPGM("Z PROBE OFFSET:");
    SERIAL_ECHO_START;
    SERIAL_ECHOPAIR("  M3 S",zprobe_offset);
    SERIAL_ECHOLN("");
} 
Esempio n. 26
0
/**
 * M48: Z probe repeatability measurement function.
 *
 * Usage:
 *   M48 <P#> <X#> <Y#> <V#> <E> <L#> <S>
 *     P = Number of sampled points (4-50, default 10)
 *     X = Sample X position
 *     Y = Sample Y position
 *     V = Verbose level (0-4, default=1)
 *     E = Engage Z probe for each reading
 *     L = Number of legs of movement before probe
 *     S = Schizoid (Or Star if you prefer)
 *
 * This function requires the machine to be homed before invocation.
 */
void GcodeSuite::M48() {

  if (axis_unhomed_error()) return;

  const int8_t verbose_level = parser.byteval('V', 1);
  if (!WITHIN(verbose_level, 0, 4)) {
    SERIAL_ECHOLNPGM("?(V)erbose level is implausible (0-4).");
    return;
  }

  if (verbose_level > 0)
    SERIAL_ECHOLNPGM("M48 Z-Probe Repeatability Test");

  const int8_t n_samples = parser.byteval('P', 10);
  if (!WITHIN(n_samples, 4, 50)) {
    SERIAL_ECHOLNPGM("?Sample size not plausible (4-50).");
    return;
  }

  const ProbePtRaise raise_after = parser.boolval('E') ? PROBE_PT_STOW : PROBE_PT_RAISE;

  float X_current = current_position[X_AXIS],
        Y_current = current_position[Y_AXIS];

  const float X_probe_location = parser.linearval('X', X_current + X_PROBE_OFFSET_FROM_EXTRUDER),
              Y_probe_location = parser.linearval('Y', Y_current + Y_PROBE_OFFSET_FROM_EXTRUDER);

  if (!position_is_reachable_by_probe(X_probe_location, Y_probe_location)) {
    SERIAL_ECHOLNPGM("? (X,Y) out of bounds.");
    return;
  }

  bool seen_L = parser.seen('L');
  uint8_t n_legs = seen_L ? parser.value_byte() : 0;
  if (n_legs > 15) {
    SERIAL_ECHOLNPGM("?Number of legs in movement not plausible (0-15).");
    return;
  }
  if (n_legs == 1) n_legs = 2;

  const bool schizoid_flag = parser.boolval('S');
  if (schizoid_flag && !seen_L) n_legs = 7;

  /**
   * Now get everything to the specified probe point So we can safely do a
   * probe to get us close to the bed.  If the Z-Axis is far from the bed,
   * we don't want to use that as a starting point for each probe.
   */
  if (verbose_level > 2)
    SERIAL_ECHOLNPGM("Positioning the probe...");

  // Disable bed level correction in M48 because we want the raw data when we probe

  #if HAS_LEVELING
    const bool was_enabled = planner.leveling_active;
    set_bed_leveling_enabled(false);
  #endif

  setup_for_endstop_or_probe_move();

  float mean = 0.0, sigma = 0.0, min = 99999.9, max = -99999.9, sample_set[n_samples];

  // Move to the first point, deploy, and probe
  const float t = probe_pt(X_probe_location, Y_probe_location, raise_after, verbose_level);
  bool probing_good = !isnan(t);

  if (probing_good) {
    randomSeed(millis());

    for (uint8_t n = 0; n < n_samples; n++) {
      if (n_legs) {
        const int dir = (random(0, 10) > 5.0) ? -1 : 1;  // clockwise or counter clockwise
        float angle = random(0, 360);
        const float radius = random(
          #if ENABLED(DELTA)
            (int) (0.1250000000 * (DELTA_PRINTABLE_RADIUS)),
            (int) (0.3333333333 * (DELTA_PRINTABLE_RADIUS))
          #else
            (int) 5.0, (int) (0.125 * MIN(X_BED_SIZE, Y_BED_SIZE))
          #endif
        );

        if (verbose_level > 3) {
          SERIAL_ECHOPAIR("Starting radius: ", radius);
          SERIAL_ECHOPAIR("   angle: ", angle);
          SERIAL_ECHOPGM(" Direction: ");
          if (dir > 0) SERIAL_ECHOPGM("Counter-");
          SERIAL_ECHOLNPGM("Clockwise");
        }

        for (uint8_t l = 0; l < n_legs - 1; l++) {
          float delta_angle;

          if (schizoid_flag)
            // The points of a 5 point star are 72 degrees apart.  We need to
            // skip a point and go to the next one on the star.
            delta_angle = dir * 2.0 * 72.0;

          else
            // If we do this line, we are just trying to move further
            // around the circle.
            delta_angle = dir * (float) random(25, 45);

          angle += delta_angle;

          while (angle > 360.0)   // We probably do not need to keep the angle between 0 and 2*PI, but the
            angle -= 360.0;       // Arduino documentation says the trig functions should not be given values
          while (angle < 0.0)     // outside of this range.   It looks like they behave correctly with
            angle += 360.0;       // numbers outside of the range, but just to be safe we clamp them.

          X_current = X_probe_location - (X_PROBE_OFFSET_FROM_EXTRUDER) + cos(RADIANS(angle)) * radius;
          Y_current = Y_probe_location - (Y_PROBE_OFFSET_FROM_EXTRUDER) + sin(RADIANS(angle)) * radius;

          #if DISABLED(DELTA)
            X_current = constrain(X_current, X_MIN_POS, X_MAX_POS);
            Y_current = constrain(Y_current, Y_MIN_POS, Y_MAX_POS);
          #else
            // If we have gone out too far, we can do a simple fix and scale the numbers
            // back in closer to the origin.
            while (!position_is_reachable_by_probe(X_current, Y_current)) {
              X_current *= 0.8;
              Y_current *= 0.8;
              if (verbose_level > 3) {
                SERIAL_ECHOPAIR("Pulling point towards center:", X_current);
                SERIAL_ECHOLNPAIR(", ", Y_current);
              }
            }
          #endif
          if (verbose_level > 3) {
            SERIAL_ECHOPGM("Going to:");
            SERIAL_ECHOPAIR(" X", X_current);
            SERIAL_ECHOPAIR(" Y", Y_current);
            SERIAL_ECHOLNPAIR(" Z", current_position[Z_AXIS]);
          }
          do_blocking_move_to_xy(X_current, Y_current);
        } // n_legs loop
      } // n_legs

      // Probe a single point
      sample_set[n] = probe_pt(X_probe_location, Y_probe_location, raise_after, 0);

      // Break the loop if the probe fails
      probing_good = !isnan(sample_set[n]);
      if (!probing_good) break;

      /**
       * Get the current mean for the data points we have so far
       */
      float sum = 0.0;
      for (uint8_t j = 0; j <= n; j++) sum += sample_set[j];
      mean = sum / (n + 1);

      NOMORE(min, sample_set[n]);
      NOLESS(max, sample_set[n]);

      /**
       * Now, use that mean to calculate the standard deviation for the
       * data points we have so far
       */
      sum = 0.0;
      for (uint8_t j = 0; j <= n; j++)
        sum += sq(sample_set[j] - mean);

      sigma = SQRT(sum / (n + 1));
      if (verbose_level > 0) {
        if (verbose_level > 1) {
          SERIAL_ECHO(n + 1);
          SERIAL_ECHOPAIR(" of ", (int)n_samples);
          SERIAL_ECHOPAIR_F(": z: ", sample_set[n], 3);
          if (verbose_level > 2) {
            SERIAL_ECHOPAIR_F(" mean: ", mean, 4);
            SERIAL_ECHOPAIR_F(" sigma: ", sigma, 6);
            SERIAL_ECHOPAIR_F(" min: ", min, 3);
            SERIAL_ECHOPAIR_F(" max: ", max, 3);
            SERIAL_ECHOPAIR_F(" range: ", max-min, 3);
          }
          SERIAL_EOL();
        }
      }

    } // n_samples loop
  }

  STOW_PROBE();

  if (probing_good) {
    SERIAL_ECHOLNPGM("Finished!");

    if (verbose_level > 0) {
      SERIAL_ECHOPAIR_F("Mean: ", mean, 6);
      SERIAL_ECHOPAIR_F(" Min: ", min, 3);
      SERIAL_ECHOPAIR_F(" Max: ", max, 3);
      SERIAL_ECHOLNPAIR_F(" Range: ", max-min, 3);
    }

    SERIAL_ECHOLNPAIR_F("Standard Deviation: ", sigma, 6);
    SERIAL_EOL();
  }

  clean_up_after_endstop_or_probe_move();

  // Re-enable bed level correction if it had been on
  #if HAS_LEVELING
    set_bed_leveling_enabled(was_enabled);
  #endif

  report_current_position();
}
Esempio n. 27
0
void CardReader::openFile(char* name, bool read, bool replace_current/*=true*/) {
  if (!cardOK) return;
  if (file.isOpen()) { //replacing current file by new file, or subfile call
    if (!replace_current) {
     if (file_subcall_ctr > SD_PROCEDURE_DEPTH - 1) {
       SERIAL_ERROR_START;
       SERIAL_ERRORPGM("trying to call sub-gcode files with too many levels. MAX level is:");
       SERIAL_ERRORLN(SD_PROCEDURE_DEPTH);
       kill();
       return;
     }

     SERIAL_ECHO_START;
     SERIAL_ECHOPGM("SUBROUTINE CALL target:\"");
     SERIAL_ECHO(name);
     SERIAL_ECHOPGM("\" parent:\"");

     //store current filename and position
     getAbsFilename(filenames[file_subcall_ctr]);

     SERIAL_ECHO(filenames[file_subcall_ctr]);
     SERIAL_ECHOPGM("\" pos");
     SERIAL_ECHOLN(sdpos);
     filespos[file_subcall_ctr] = sdpos;
     file_subcall_ctr++;
    }
    else {
     SERIAL_ECHO_START;
     SERIAL_ECHOPGM("Now doing file: ");
     SERIAL_ECHOLN(name);
    }
    file.close();
  }
  else { //opening fresh file
    file_subcall_ctr = 0; //resetting procedure depth in case user cancels print while in procedure
    SERIAL_ECHO_START;
    SERIAL_ECHOPGM("Now fresh file: ");
    SERIAL_ECHOLN(name);
  }
  sdprinting = false;

  SdFile myDir;
  curDir = &root;
  char *fname = name;

  char *dirname_start, *dirname_end;
  if (name[0] == '/') {
    dirname_start = &name[1];
    while(dirname_start > 0) {
      dirname_end = strchr(dirname_start, '/');
      //SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start - name));
      //SERIAL_ECHO("end  :");SERIAL_ECHOLN((int)(dirname_end - name));
      if (dirname_end > 0 && dirname_end > dirname_start) {
        char subdirname[FILENAME_LENGTH];
        strncpy(subdirname, dirname_start, dirname_end - dirname_start);
        subdirname[dirname_end - dirname_start] = 0;
        SERIAL_ECHOLN(subdirname);
        if (!myDir.open(curDir, subdirname, O_READ)) {
          SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
          SERIAL_PROTOCOL(subdirname);
          SERIAL_PROTOCOLCHAR('.');
          return;
        }
        else {
          //SERIAL_ECHOLN("dive ok");
        }

        curDir = &myDir;
        dirname_start = dirname_end + 1;
      }
      else { // the remainder after all /fsa/fdsa/ is the filename
        fname = dirname_start;
        //SERIAL_ECHOLN("remainder");
        //SERIAL_ECHOLN(fname);
        break;
      }
    }
  }
  else { //relative path
    curDir = &workDir;
  }

  if (read) {
    if (file.open(curDir, fname, O_READ)) {
      filesize = file.fileSize();
      SERIAL_PROTOCOLPGM(MSG_SD_FILE_OPENED);
      SERIAL_PROTOCOL(fname);
      SERIAL_PROTOCOLPGM(MSG_SD_SIZE);
      SERIAL_PROTOCOLLN(filesize);
      sdpos = 0;

      SERIAL_PROTOCOLLNPGM(MSG_SD_FILE_SELECTED);
      getfilename(0, fname);
      lcd_setstatus(longFilename[0] ? longFilename : fname);
    }
    else {
      SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
      SERIAL_PROTOCOL(fname);
      SERIAL_PROTOCOLCHAR('.');
    }
  }
  else { //write
    if (!file.open(curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) {
      SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
      SERIAL_PROTOCOL(fname);
      SERIAL_PROTOCOLCHAR('.');
    }
    else {
      saving = true;
      SERIAL_PROTOCOLPGM(MSG_SD_WRITE_TO_FILE);
      SERIAL_PROTOCOLLN(name);
      lcd_setstatus(fname);
    }
  }
}
Esempio n. 28
0
 static void debug_echo_axis(const AxisEnum axis) {
   if (current_position[axis] == destination[axis])
     SERIAL_ECHOPGM("-------------");
   else
     SERIAL_ECHO_F(destination[X_AXIS], 6);
 }
Esempio n. 29
0
void PrintCounter::showStats() {
  char buffer[21];
  duration_t elapsed;

  SERIAL_PROTOCOLPGM(MSG_STATS);

  SERIAL_ECHOPGM("Prints: ");
  SERIAL_ECHO(this->data.totalPrints);

  SERIAL_ECHOPGM(", Finished: ");
  SERIAL_ECHO(this->data.finishedPrints);

  SERIAL_ECHOPGM(", Failed: "); // Note: Removes 1 from failures with an active counter
  SERIAL_ECHO(this->data.totalPrints - this->data.finishedPrints
    - ((this->isRunning() || this->isPaused()) ? 1 : 0));

  SERIAL_EOL;
  SERIAL_PROTOCOLPGM(MSG_STATS);

  elapsed = this->data.printTime;
  elapsed.toString(buffer);

  SERIAL_ECHOPGM("Total time: ");
  SERIAL_ECHO(buffer);

  #if ENABLED(DEBUG_PRINTCOUNTER)
    SERIAL_ECHOPGM(" (");
    SERIAL_ECHO(this->data.printTime);
    SERIAL_ECHOPGM(")");
  #endif

  elapsed = this->data.longestPrint;
  elapsed.toString(buffer);

  SERIAL_ECHOPGM(", Longest job: ");
  SERIAL_ECHO(buffer);

  #if ENABLED(DEBUG_PRINTCOUNTER)
    SERIAL_ECHOPGM(" (");
    SERIAL_ECHO(this->data.longestPrint);
    SERIAL_ECHOPGM(")");
  #endif

  SERIAL_EOL;
  SERIAL_PROTOCOLPGM(MSG_STATS);

  SERIAL_ECHOPGM("Filament used: ");
  SERIAL_ECHO(this->data.filamentUsed / 1000);
  SERIAL_ECHOPGM("m");

  SERIAL_EOL;
}
Esempio n. 30
0
/**
 * M420: Enable/Disable Bed Leveling and/or set the Z fade height.
 *
 *   S[bool]   Turns leveling on or off
 *   Z[height] Sets the Z fade height (0 or none to disable)
 *   V[bool]   Verbose - Print the leveling grid
 *
 * With AUTO_BED_LEVELING_UBL only:
 *
 *   L[index]  Load UBL mesh from index (0 is default)
 *   T[map]    0:Human-readable 1:CSV 2:"LCD" 4:Compact
 *
 * With mesh-based leveling only:
 *
 *   C         Center mesh on the mean of the lowest and highest
 *
 * With MARLIN_DEV_MODE:
 *   S2        Create a simple random mesh and enable
 */
void GcodeSuite::M420() {
  const bool seen_S = parser.seen('S'),
             to_enable = seen_S ? parser.value_bool() : planner.leveling_active;

  #if ENABLED(MARLIN_DEV_MODE)
    if (parser.intval('S') == 2) {
      #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
        bilinear_start[X_AXIS] = MIN_PROBE_X;
        bilinear_start[Y_AXIS] = MIN_PROBE_Y;
        bilinear_grid_spacing[X_AXIS] = (MAX_PROBE_X - (MIN_PROBE_X)) / (GRID_MAX_POINTS_X - 1);
        bilinear_grid_spacing[Y_AXIS] = (MAX_PROBE_Y - (MIN_PROBE_Y)) / (GRID_MAX_POINTS_Y - 1);
      #endif
      for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++)
        for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; y++)
          Z_VALUES(x, y) = 0.001 * random(-200, 200);
      SERIAL_ECHOPGM("Simulated " STRINGIFY(GRID_MAX_POINTS_X) "x" STRINGIFY(GRID_MAX_POINTS_X) " mesh ");
      SERIAL_ECHOPAIR(" (", MIN_PROBE_X);
      SERIAL_CHAR(','); SERIAL_ECHO(MIN_PROBE_Y);
      SERIAL_ECHOPAIR(")-(", MAX_PROBE_X);
      SERIAL_CHAR(','); SERIAL_ECHO(MAX_PROBE_Y);
      SERIAL_ECHOLNPGM(")");
    }
  #endif

  // If disabling leveling do it right away
  // (Don't disable for just M420 or M420 V)
  if (seen_S && !to_enable) set_bed_leveling_enabled(false);

  const float oldpos[] = { current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] };

  #if ENABLED(AUTO_BED_LEVELING_UBL)

    // L to load a mesh from the EEPROM
    if (parser.seen('L')) {

      set_bed_leveling_enabled(false);

      #if ENABLED(EEPROM_SETTINGS)
        const int8_t storage_slot = parser.has_value() ? parser.value_int() : ubl.storage_slot;
        const int16_t a = settings.calc_num_meshes();

        if (!a) {
          SERIAL_ECHOLNPGM("?EEPROM storage not available.");
          return;
        }

        if (!WITHIN(storage_slot, 0, a - 1)) {
          SERIAL_ECHOLNPGM("?Invalid storage slot.");
          SERIAL_ECHOLNPAIR("?Use 0 to ", a - 1);
          return;
        }

        settings.load_mesh(storage_slot);
        ubl.storage_slot = storage_slot;

      #else

        SERIAL_ECHOLNPGM("?EEPROM storage not available.");
        return;

      #endif
    }

    // L or V display the map info
    if (parser.seen('L') || parser.seen('V')) {
      ubl.display_map(parser.byteval('T'));
      SERIAL_ECHOPGM("Mesh is ");
      if (!ubl.mesh_is_valid()) SERIAL_ECHOPGM("in");
      SERIAL_ECHOLNPAIR("valid\nStorage slot: ", ubl.storage_slot);
    }

  #endif // AUTO_BED_LEVELING_UBL

  const bool seenV = parser.seen('V');

  #if HAS_MESH

    if (leveling_is_valid()) {

      // Subtract the given value or the mean from all mesh values
      if (parser.seen('C')) {
        const float cval = parser.value_float();
        #if ENABLED(AUTO_BED_LEVELING_UBL)

          set_bed_leveling_enabled(false);
          ubl.adjust_mesh_to_mean(true, cval);

        #else

          #if ENABLED(M420_C_USE_MEAN)

            // Get the sum and average of all mesh values
            float mesh_sum = 0;
            for (uint8_t x = GRID_MAX_POINTS_X; x--;)
              for (uint8_t y = GRID_MAX_POINTS_Y; y--;)
                mesh_sum += Z_VALUES(x, y);
            const float zmean = mesh_sum / float(GRID_MAX_POINTS);

          #else

            // Find the low and high mesh values
            float lo_val = 100, hi_val = -100;
            for (uint8_t x = GRID_MAX_POINTS_X; x--;)
              for (uint8_t y = GRID_MAX_POINTS_Y; y--;) {
                const float z = Z_VALUES(x, y);
                NOMORE(lo_val, z);
                NOLESS(hi_val, z);
              }
            // Take the mean of the lowest and highest
            const float zmean = (lo_val + hi_val) / 2.0 + cval;

          #endif

          // If not very close to 0, adjust the mesh
          if (!NEAR_ZERO(zmean)) {
            set_bed_leveling_enabled(false);
            // Subtract the mean from all values
            for (uint8_t x = GRID_MAX_POINTS_X; x--;)
              for (uint8_t y = GRID_MAX_POINTS_Y; y--;)
                Z_VALUES(x, y) -= zmean;
            #if ENABLED(ABL_BILINEAR_SUBDIVISION)
              bed_level_virt_interpolate();
            #endif
          }

        #endif
      }

    }
    else if (to_enable || seenV) {
      SERIAL_ECHO_MSG("Invalid mesh.");
      goto EXIT_M420;
    }

  #endif // HAS_MESH

  // V to print the matrix or mesh
  if (seenV) {
    #if ABL_PLANAR
      planner.bed_level_matrix.debug(PSTR("Bed Level Correction Matrix:"));
    #else
      if (leveling_is_valid()) {
        #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
          print_bilinear_leveling_grid();
          #if ENABLED(ABL_BILINEAR_SUBDIVISION)
            print_bilinear_leveling_grid_virt();
          #endif
        #elif ENABLED(MESH_BED_LEVELING)
          SERIAL_ECHOLNPGM("Mesh Bed Level data:");
          mbl.report_mesh();
        #endif
      }
    #endif
  }

  #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
    if (parser.seen('Z')) set_z_fade_height(parser.value_linear_units(), false);
  #endif

  // Enable leveling if specified, or if previously active
  set_bed_leveling_enabled(to_enable);

  #if HAS_MESH
    EXIT_M420:
  #endif

  // Error if leveling failed to enable or reenable
  if (to_enable && !planner.leveling_active)
    SERIAL_ERROR_MSG(MSG_ERR_M420_FAILED);

  SERIAL_ECHO_START();
  SERIAL_ECHOPGM("Bed Leveling ");
  serialprintln_onoff(planner.leveling_active);

  #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
    SERIAL_ECHO_START();
    SERIAL_ECHOPGM("Fade Height ");
    if (planner.z_fade_height > 0.0)
      SERIAL_ECHOLN(planner.z_fade_height);
    else
      SERIAL_ECHOLNPGM(MSG_OFF);
  #endif

  // Report change in position
  if (memcmp(oldpos, current_position, sizeof(oldpos)))
    report_current_position();
}