/** * M100 D * Dump 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 test bytes indicate nothing has * used that memory yet. There should not be anything but test bytes within * the block. If so, it may indicate memory corruption due to a bad pointer. * Unexpected bytes are flagged in the right column. */ void dump_free_memory(const char *ptr, const char *sp) { // // Start and end the dump on a nice 16 byte boundary // (even though the values are not 16-byte aligned). // ptr = (char *)((uint16_t)ptr & 0xFFF0); // Align to 16-byte boundary sp = (char *)((uint16_t)sp | 0x000F); // Align sp to the 15th byte (at or above sp) // Dump command main loop while (ptr < sp) { print_hex_word((uint16_t)ptr); // Print the address SERIAL_CHAR(':'); for (uint8_t i = 0; i < 16; i++) { // and 16 data bytes if (i == 8) SERIAL_CHAR('-'); print_hex_byte(ptr[i]); SERIAL_CHAR(' '); } safe_delay(25); SERIAL_CHAR('|'); // Point out non test bytes for (uint8_t i = 0; i < 16; i++) { char ccc = (char)ptr[i]; // cast to char before automatically casting to char on assignment, in case the compiler is broken if (&ptr[i] >= (const char*)command_queue && &ptr[i] < (const char*)(command_queue + sizeof(command_queue))) { // Print out ASCII in the command buffer area if (!WITHIN(ccc, ' ', 0x7E)) ccc = ' '; } else { // If not in the command buffer area, flag bytes that don't match the test byte ccc = (ccc == TEST_BYTE) ? ' ' : '?'; } SERIAL_CHAR(ccc); } SERIAL_EOL(); ptr += 16; safe_delay(25); idle(); } }
/** * M81: Turn off Power, including Power Supply, if there is one. * * This code should ALWAYS be available for EMERGENCY SHUTDOWN! */ void GcodeSuite::M81() { thermalManager.disable_all_heaters(); print_job_timer.stop(); planner.finish_and_disable(); #if FAN_COUNT > 0 thermalManager.zero_fan_speeds(); #if ENABLED(PROBING_FANS_OFF) thermalManager.fans_paused = false; ZERO(thermalManager.paused_fan_speed); #endif #endif safe_delay(1000); // Wait 1 second before switching off #if HAS_SUICIDE suicide(); #elif HAS_POWER_SWITCH PSU_OFF(); #endif #if HAS_LCD_MENU LCD_MESSAGEPGM(MACHINE_NAME " " MSG_OFF "."); #endif }
void unified_bed_leveling::report_state() { echo_name(); SERIAL_PROTOCOLPGM(" System v" UBL_VERSION " "); if (!planner.leveling_active) SERIAL_PROTOCOLPGM("in"); SERIAL_PROTOCOLLNPGM("active."); safe_delay(50); }
inline void _move_nozzle_servo(const uint8_t e, const uint8_t angle_index) { constexpr int8_t sns_index[2] = { SWITCHING_NOZZLE_SERVO_NR, SWITCHING_NOZZLE_E1_SERVO_NR }; constexpr int16_t sns_angles[2] = SWITCHING_NOZZLE_SERVO_ANGLES; planner.synchronize(); MOVE_SERVO(sns_index[e], sns_angles[angle_index]); safe_delay(500); }
bool set_bltouch_deployed(const bool deploy) { if (deploy && TEST_BLTOUCH()) { // If BL-Touch says it's triggered bltouch_command(BLTOUCH_RESET); // try to reset it. bltouch_command(BLTOUCH_DEPLOY); // Also needs to deploy and stow to bltouch_command(BLTOUCH_STOW); // clear the triggered condition. safe_delay(1500); // Wait for internal self-test to complete. // (Measured completion time was 0.65 seconds // after reset, deploy, and stow sequence) if (TEST_BLTOUCH()) { // If it still claims to be triggered... SERIAL_ERROR_START(); SERIAL_ERRORLNPGM(MSG_STOP_BLTOUCH); stop(); // punt! return true; } } bltouch_command(deploy ? BLTOUCH_DEPLOY : BLTOUCH_STOW); #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) { SERIAL_ECHOPAIR("set_bltouch_deployed(", deploy); SERIAL_CHAR(')'); SERIAL_EOL(); } #endif return false; }
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; }
void setup_neopixel() { SET_OUTPUT(NEOPIXEL_PIN); pixels.setBrightness(NEOPIXEL_BRIGHTNESS); // 0 - 255 range pixels.begin(); pixels.show(); // initialize to all off #if ENABLED(NEOPIXEL_STARTUP_TEST) safe_delay(1000); set_neopixel_color(pixels.Color(255, 0, 0, 0)); // red safe_delay(1000); set_neopixel_color(pixels.Color(0, 255, 0, 0)); // green safe_delay(1000); set_neopixel_color(pixels.Color(0, 0, 255, 0)); // blue safe_delay(1000); #endif set_neopixel_color(pixels.Color(NEO_WHITE)); // white }
static void serial_echo_xy(const int16_t x, const int16_t y) { SERIAL_CHAR('('); SERIAL_ECHO(x); SERIAL_CHAR(','); SERIAL_ECHO(y); SERIAL_CHAR(')'); safe_delay(10); }
void move_extruder_servo(const uint8_t e) { planner.synchronize(); #if EXTRUDERS & 1 if (e < EXTRUDERS - 1) #endif { MOVE_SERVO(_SERVO_NR(e), servo_angles[_SERVO_NR(e)][e]); safe_delay(500); } }
inline void home_z_safely() { // Disallow Z homing if X or Y are unknown if (!TEST(axis_known_position, X_AXIS) || !TEST(axis_known_position, Y_AXIS)) { LCD_MESSAGEPGM(MSG_ERR_Z_HOMING); SERIAL_ECHO_MSG(MSG_ERR_Z_HOMING); return; } #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Z_SAFE_HOMING >>>"); #endif sync_plan_position(); /** * Move the Z probe (or just the nozzle) to the safe homing point */ destination[X_AXIS] = Z_SAFE_HOMING_X_POINT; destination[Y_AXIS] = Z_SAFE_HOMING_Y_POINT; destination[Z_AXIS] = current_position[Z_AXIS]; // Z is already at the right height #if HOMING_Z_WITH_PROBE destination[X_AXIS] -= X_PROBE_OFFSET_FROM_EXTRUDER; destination[Y_AXIS] -= Y_PROBE_OFFSET_FROM_EXTRUDER; #endif if (position_is_reachable(destination[X_AXIS], destination[Y_AXIS])) { #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) DEBUG_POS("Z_SAFE_HOMING", destination); #endif // This causes the carriage on Dual X to unpark #if ENABLED(DUAL_X_CARRIAGE) active_extruder_parked = false; #endif #if ENABLED(SENSORLESS_HOMING) safe_delay(500); // Short delay needed to settle #endif do_blocking_move_to_xy(destination[X_AXIS], destination[Y_AXIS]); homeaxis(Z_AXIS); } else { LCD_MESSAGEPGM(MSG_ZPROBE_OUT); SERIAL_ECHO_MSG(MSG_ZPROBE_OUT); } #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< Z_SAFE_HOMING"); #endif }
void Servo::move(const int value) { constexpr uint16_t servo_delay[] = SERVO_DELAY; static_assert(COUNT(servo_delay) == NUM_SERVOS, "SERVO_DELAY must be an array NUM_SERVOS long."); if (this->attach(0) >= 0) { this->write(value); safe_delay(servo_delay[this->servoIndex]); #if ENABLED(DEACTIVATE_SERVOS_AFTER_MOVE) this->detach(); #endif } }
void probing_pause(const bool p) { #if ENABLED(PROBING_HEATERS_OFF) thermalManager.pause(p); #endif #if ENABLED(PROBING_FANS_OFF) fans_pause(p); #endif if (p) safe_delay( #if DELAY_BEFORE_PROBING > 25 DELAY_BEFORE_PROBING #else 25 #endif ); }
/** * Detect ubl_lcd_clicked, debounce it, and return true for cancel */ bool user_canceled() { if (!ubl_lcd_clicked()) return false; safe_delay(10); // Wait for click to settle #if ENABLED(ULTRA_LCD) lcd_setstatusPGM(PSTR("Mesh Validation Stopped."), 99); lcd_quick_feedback(); #endif while (!ubl_lcd_clicked()) idle(); // Wait for button release // If the button is suddenly pressed again, // ask the user to resolve the issue lcd_setstatusPGM(PSTR("Release button"), 99); // will never appear... while (ubl_lcd_clicked()) idle(); // unless this loop happens lcd_reset_status(); return true; }
LOOP_L_N(f, COUNT(custom_bootscreen_animation)) { if (f) safe_delay(CUSTOM_BOOTSCREEN_FRAME_TIME); draw_custom_bootscreen((u8g_pgm_uint8_t*)pgm_read_ptr(&custom_bootscreen_animation[f]), f == 0); }
void bltouch_command(const int angle) { MOVE_SERVO(Z_ENDSTOP_SERVO_NR, angle); // Give the BL-Touch the command and wait safe_delay(BLTOUCH_DELAY); }
inline void switching_toolhead_tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool no_move/*=false*/) { if (no_move) return; constexpr uint16_t angles[2] = SWITCHING_TOOLHEAD_SERVO_ANGLES; const float toolheadposx[] = SWITCHING_TOOLHEAD_X_POS, placexpos = toolheadposx[active_extruder], grabxpos = toolheadposx[tmp_extruder]; /** * 1. Raise Z to give enough clearance * 2. Move to switch position of current toolhead * 3. Unlock tool and drop it in the dock * 4. Move to the new toolhead * 5. Grab and lock the new toolhead */ // 1. Raise Z to give enough clearance if (DEBUGGING(LEVELING)) DEBUG_POS("Starting Toolhead change", current_position); current_position[Z_AXIS] += toolchange_settings.z_raise; if (DEBUGGING(LEVELING)) DEBUG_POS("(1) Raise Z-Axis", current_position); fast_line_to_current(Z_AXIS); planner.synchronize(); // 2. Move to switch position of current toolhead current_position[X_AXIS] = placexpos; if (DEBUGGING(LEVELING)) { DEBUG_ECHOLNPAIR("(2) Place old tool ", int(active_extruder)); DEBUG_POS("Move X SwitchPos", current_position); } fast_line_to_current(X_AXIS); planner.synchronize(); current_position[Y_AXIS] = SWITCHING_TOOLHEAD_Y_POS - SWITCHING_TOOLHEAD_Y_SECURITY; if (DEBUGGING(LEVELING)) DEBUG_POS("Move Y SwitchPos + Security", current_position); fast_line_to_current(Y_AXIS); planner.synchronize(); // 3. Unlock tool and drop it in the dock if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("(3) Unlock and Place Toolhead"); MOVE_SERVO(SWITCHING_TOOLHEAD_SERVO_NR, angles[1]); safe_delay(500); current_position[Y_AXIS] = SWITCHING_TOOLHEAD_Y_POS; if (DEBUGGING(LEVELING)) DEBUG_POS("Move Y SwitchPos", current_position); planner.buffer_line(current_position,(planner.settings.max_feedrate_mm_s[Y_AXIS] * 0.5), active_extruder); planner.synchronize(); safe_delay(200); current_position[Y_AXIS] -= SWITCHING_TOOLHEAD_Y_CLEAR; if (DEBUGGING(LEVELING)) DEBUG_POS("Move back Y clear", current_position); fast_line_to_current(Y_AXIS); // move away from docked toolhead planner.synchronize(); // 4. Move to the new toolhead if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("(4) Move to new toolhead position"); current_position[X_AXIS] = grabxpos; if (DEBUGGING(LEVELING)) DEBUG_POS("Move to new toolhead X", current_position); fast_line_to_current(X_AXIS); planner.synchronize(); current_position[Y_AXIS] = SWITCHING_TOOLHEAD_Y_POS - SWITCHING_TOOLHEAD_Y_SECURITY; if (DEBUGGING(LEVELING)) DEBUG_POS("Move Y SwitchPos + Security", current_position); fast_line_to_current(Y_AXIS); planner.synchronize(); // 5. Grab and lock the new toolhead if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("(5) Grab and lock new toolhead "); current_position[Y_AXIS] = SWITCHING_TOOLHEAD_Y_POS; if (DEBUGGING(LEVELING)) DEBUG_POS("Move Y SwitchPos", current_position); planner.buffer_line(current_position, planner.settings.max_feedrate_mm_s[Y_AXIS] * 0.5, active_extruder); planner.synchronize(); safe_delay(200); MOVE_SERVO(SWITCHING_TOOLHEAD_SERVO_NR, angles[0]); safe_delay(500); current_position[Y_AXIS] -= SWITCHING_TOOLHEAD_Y_CLEAR; if (DEBUGGING(LEVELING)) DEBUG_POS("Move back Y clear", current_position); fast_line_to_current(Y_AXIS); // move away from docked toolhead planner.synchronize(); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Toolhead change done."); }
void move_nozzle_servo(const uint8_t angle_index) { planner.synchronize(); MOVE_SERVO(SWITCHING_NOZZLE_SERVO_NR, servo_angles[SWITCHING_NOZZLE_SERVO_NR][e]); safe_delay(500); }
void unified_bed_leveling::display_map(const int map_type) { constexpr uint8_t spaces = 8 * (GRID_MAX_POINTS_X - 2); SERIAL_PROTOCOLPGM("\nBed Topography Report"); if (map_type == 0) { SERIAL_PROTOCOLPGM(":\n\n"); serial_echo_xy(0, GRID_MAX_POINTS_Y - 1); SERIAL_ECHO_SP(spaces + 3); serial_echo_xy(GRID_MAX_POINTS_X - 1, GRID_MAX_POINTS_Y - 1); SERIAL_EOL(); serial_echo_xy(MESH_MIN_X, MESH_MAX_Y); SERIAL_ECHO_SP(spaces); serial_echo_xy(MESH_MAX_X, MESH_MAX_Y); SERIAL_EOL(); } else { SERIAL_PROTOCOLPGM(" for "); serialprintPGM(map_type == 1 ? PSTR("CSV:\n\n") : PSTR("LCD:\n\n")); } const float current_xi = get_cell_index_x(current_position[X_AXIS] + (MESH_X_DIST) / 2.0), current_yi = get_cell_index_y(current_position[Y_AXIS] + (MESH_Y_DIST) / 2.0); for (int8_t j = GRID_MAX_POINTS_Y - 1; j >= 0; j--) { for (uint8_t i = 0; i < GRID_MAX_POINTS_X; i++) { const bool is_current = i == current_xi && j == current_yi; // is the nozzle here? then mark the number if (map_type == 0) SERIAL_CHAR(is_current ? '[' : ' '); const float f = z_values[i][j]; if (isnan(f)) { serialprintPGM(map_type == 0 ? PSTR(" . ") : PSTR("NAN")); } else if (map_type <= 1) { // if we don't do this, the columns won't line up nicely if (map_type == 0 && f >= 0.0) SERIAL_CHAR(' '); SERIAL_PROTOCOL_F(f, 3); } idle(); if (map_type == 1 && i < GRID_MAX_POINTS_X - 1) SERIAL_CHAR(','); #if TX_BUFFER_SIZE > 0 MYSERIAL.flushTX(); #endif safe_delay(15); if (map_type == 0) { SERIAL_CHAR(is_current ? ']' : ' '); SERIAL_CHAR(' '); } } SERIAL_EOL(); if (j && map_type == 0) { // we want the (0,0) up tight against the block of numbers SERIAL_CHAR(' '); SERIAL_EOL(); } } if (map_type == 0) { serial_echo_xy(MESH_MIN_X, MESH_MIN_Y); SERIAL_ECHO_SP(spaces + 4); serial_echo_xy(MESH_MAX_X, MESH_MIN_Y); SERIAL_EOL(); serial_echo_xy(0, 0); SERIAL_ECHO_SP(spaces + 5); serial_echo_xy(GRID_MAX_POINTS_X - 1, 0); SERIAL_EOL(); } }
// Output the contents of a file, first parameter is the filename, second is the limit ( in number of lines to output ) void SimpleShell::cat_command( string parameters, StreamOutput *stream ) { // Get parameters ( filename and line limit ) string filename = absolute_from_relative(shift_parameter( parameters )); string limit_parameter = shift_parameter( parameters ); int limit = -1; int delay= 0; bool send_eof= false; if ( limit_parameter == "-d" ) { string d= shift_parameter( parameters ); char *e = NULL; delay = strtol(d.c_str(), &e, 10); if (e <= d.c_str()) { delay = 0; } else { send_eof= true; // we need to terminate file send with an eof } }else if ( limit_parameter != "" ) { char *e = NULL; limit = strtol(limit_parameter.c_str(), &e, 10); if (e <= limit_parameter.c_str()) limit = -1; } // we have been asked to delay before cat, probably to allow time to issue upload command if(delay > 0) { safe_delay(delay*1000); } // Open file FILE *lp = fopen(filename.c_str(), "r"); if (lp == NULL) { stream->printf("File not found: %s\r\n", filename.c_str()); return; } string buffer; int c; int newlines = 0; int linecnt = 0; // Print each line of the file while ((c = fgetc (lp)) != EOF) { buffer.append((char *)&c, 1); if ( c == '\n' || ++linecnt > 80) { if(c == '\n') newlines++; stream->puts(buffer.c_str()); buffer.clear(); if(linecnt > 80) linecnt = 0; // we need to kick things or they die THEKERNEL->call_event(ON_IDLE); } if ( newlines == limit ) { break; } }; fclose(lp); if(send_eof) { stream->puts("\032"); // ^Z terminates the upload } }