mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2024-11-27 22:08:02 +00:00
a129078927
Add an emergency-command parser to MarlinSerial's RX interrupt. The parser tries to find and execute M108,M112,M410 before the commands disappear in the RX-buffer. To avoid false positives for M117, comments and commands followed by filenames (M23, M28, M30, M32, M33) are filtered. This enables Marlin to receive and react on the Emergency command at all times - regardless of whether the buffers are full or not. It remains to convince hosts to send the commands. To inform the hosts about the new feature a new entry in the M115-report was made. "`EMERGENCY_CODES:M112,M108,M410;`". The parser is fast. It only ever needs two switch decisions and one assignment of the new state for every character. One problem remains. If the host has sent an incomplete line before sending an emergency command the emergency command could be omitted when the parser is in `state_IGNORE`. In that case the host should send "\ncommand\n" Also introduces M108 to break the waiting for the heaters in M109, M190 and M303. Rename `cancel_heatup` to `wait_for_heatup` to better see the purpose.
398 lines
13 KiB
C
398 lines
13 KiB
C
/**
|
|
* Marlin 3D Printer Firmware
|
|
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
|
*
|
|
* Based on Sprinter and grbl.
|
|
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
#ifndef MARLIN_H
|
|
#define MARLIN_H
|
|
|
|
#define FORCE_INLINE __attribute__((always_inline)) inline
|
|
/**
|
|
* Compiler warning on unused variable.
|
|
*/
|
|
#define UNUSED(x) (void) (x)
|
|
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <inttypes.h>
|
|
|
|
#include <util/delay.h>
|
|
#include <avr/pgmspace.h>
|
|
#include <avr/eeprom.h>
|
|
#include <avr/interrupt.h>
|
|
|
|
|
|
#include "fastio.h"
|
|
#include "Configuration.h"
|
|
#include "pins.h"
|
|
|
|
#ifndef SANITYCHECK_H
|
|
#error "Your Configuration.h and Configuration_adv.h files are outdated!"
|
|
#endif
|
|
|
|
#include "Arduino.h"
|
|
|
|
typedef unsigned long millis_t;
|
|
|
|
#ifdef USBCON
|
|
#include "HardwareSerial.h"
|
|
#endif
|
|
|
|
#include "MarlinSerial.h"
|
|
|
|
#include "WString.h"
|
|
|
|
#if ENABLED(PRINTCOUNTER)
|
|
#include "printcounter.h"
|
|
#else
|
|
#include "stopwatch.h"
|
|
#endif
|
|
|
|
#ifdef USBCON
|
|
#if ENABLED(BLUETOOTH)
|
|
#define MYSERIAL bluetoothSerial
|
|
#else
|
|
#define MYSERIAL Serial
|
|
#endif // BLUETOOTH
|
|
#else
|
|
#define MYSERIAL customizedSerial
|
|
#endif
|
|
|
|
#define SERIAL_CHAR(x) MYSERIAL.write(x)
|
|
#define SERIAL_EOL SERIAL_CHAR('\n')
|
|
|
|
#define SERIAL_PROTOCOLCHAR(x) SERIAL_CHAR(x)
|
|
#define SERIAL_PROTOCOL(x) MYSERIAL.print(x)
|
|
#define SERIAL_PROTOCOL_F(x,y) MYSERIAL.print(x,y)
|
|
#define SERIAL_PROTOCOLPGM(x) serialprintPGM(PSTR(x))
|
|
#define SERIAL_PROTOCOLLN(x) do{ MYSERIAL.print(x); SERIAL_EOL; }while(0)
|
|
#define SERIAL_PROTOCOLLNPGM(x) do{ serialprintPGM(PSTR(x "\n")); }while(0)
|
|
|
|
#define SERIAL_PROTOCOLPAIR(name, value) SERIAL_ECHOPAIR(name, value)
|
|
|
|
extern const char errormagic[] PROGMEM;
|
|
extern const char echomagic[] PROGMEM;
|
|
|
|
#define SERIAL_ERROR_START serialprintPGM(errormagic)
|
|
#define SERIAL_ERROR(x) SERIAL_PROTOCOL(x)
|
|
#define SERIAL_ERRORPGM(x) SERIAL_PROTOCOLPGM(x)
|
|
#define SERIAL_ERRORLN(x) SERIAL_PROTOCOLLN(x)
|
|
#define SERIAL_ERRORLNPGM(x) SERIAL_PROTOCOLLNPGM(x)
|
|
|
|
#define SERIAL_ECHO_START serialprintPGM(echomagic)
|
|
#define SERIAL_ECHO(x) SERIAL_PROTOCOL(x)
|
|
#define SERIAL_ECHOPGM(x) SERIAL_PROTOCOLPGM(x)
|
|
#define SERIAL_ECHOLN(x) SERIAL_PROTOCOLLN(x)
|
|
#define SERIAL_ECHOLNPGM(x) SERIAL_PROTOCOLLNPGM(x)
|
|
|
|
#define SERIAL_ECHOPAIR(name,value) (serial_echopair_P(PSTR(name),(value)))
|
|
|
|
void serial_echopair_P(const char* s_P, int v);
|
|
void serial_echopair_P(const char* s_P, long v);
|
|
void serial_echopair_P(const char* s_P, float v);
|
|
void serial_echopair_P(const char* s_P, double v);
|
|
void serial_echopair_P(const char* s_P, unsigned long v);
|
|
FORCE_INLINE void serial_echopair_P(const char* s_P, bool v) { serial_echopair_P(s_P, (int)v); }
|
|
FORCE_INLINE void serial_echopair_P(const char* s_P, void *v) { serial_echopair_P(s_P, (unsigned long)v); }
|
|
|
|
// Things to write to serial from Program memory. Saves 400 to 2k of RAM.
|
|
FORCE_INLINE void serialprintPGM(const char* str) {
|
|
char ch;
|
|
while ((ch = pgm_read_byte(str))) {
|
|
MYSERIAL.write(ch);
|
|
str++;
|
|
}
|
|
}
|
|
|
|
void idle(
|
|
#if ENABLED(FILAMENT_CHANGE_FEATURE)
|
|
bool no_stepper_sleep = false // pass true to keep steppers from disabling on timeout
|
|
#endif
|
|
);
|
|
|
|
void manage_inactivity(bool ignore_stepper_queue = false);
|
|
|
|
#if ENABLED(DUAL_X_CARRIAGE)
|
|
extern bool extruder_duplication_enabled;
|
|
#endif
|
|
|
|
#if ENABLED(DUAL_X_CARRIAGE) && HAS_X_ENABLE && HAS_X2_ENABLE
|
|
#define enable_x() do { X_ENABLE_WRITE( X_ENABLE_ON); X2_ENABLE_WRITE( X_ENABLE_ON); } while (0)
|
|
#define disable_x() do { X_ENABLE_WRITE(!X_ENABLE_ON); X2_ENABLE_WRITE(!X_ENABLE_ON); axis_known_position[X_AXIS] = false; } while (0)
|
|
#elif HAS_X_ENABLE
|
|
#define enable_x() X_ENABLE_WRITE( X_ENABLE_ON)
|
|
#define disable_x() { X_ENABLE_WRITE(!X_ENABLE_ON); axis_known_position[X_AXIS] = false; }
|
|
#else
|
|
#define enable_x() ;
|
|
#define disable_x() ;
|
|
#endif
|
|
|
|
#if HAS_Y_ENABLE
|
|
#if ENABLED(Y_DUAL_STEPPER_DRIVERS)
|
|
#define enable_y() { Y_ENABLE_WRITE( Y_ENABLE_ON); Y2_ENABLE_WRITE(Y_ENABLE_ON); }
|
|
#define disable_y() { Y_ENABLE_WRITE(!Y_ENABLE_ON); Y2_ENABLE_WRITE(!Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; }
|
|
#else
|
|
#define enable_y() Y_ENABLE_WRITE( Y_ENABLE_ON)
|
|
#define disable_y() { Y_ENABLE_WRITE(!Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; }
|
|
#endif
|
|
#else
|
|
#define enable_y() ;
|
|
#define disable_y() ;
|
|
#endif
|
|
|
|
#if HAS_Z_ENABLE
|
|
#if ENABLED(Z_DUAL_STEPPER_DRIVERS)
|
|
#define enable_z() { Z_ENABLE_WRITE( Z_ENABLE_ON); Z2_ENABLE_WRITE(Z_ENABLE_ON); }
|
|
#define disable_z() { Z_ENABLE_WRITE(!Z_ENABLE_ON); Z2_ENABLE_WRITE(!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
|
|
#else
|
|
#define enable_z() Z_ENABLE_WRITE( Z_ENABLE_ON)
|
|
#define disable_z() { Z_ENABLE_WRITE(!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
|
|
#endif
|
|
#else
|
|
#define enable_z() ;
|
|
#define disable_z() ;
|
|
#endif
|
|
|
|
#if HAS_E0_ENABLE
|
|
#define enable_e0() E0_ENABLE_WRITE( E_ENABLE_ON)
|
|
#define disable_e0() E0_ENABLE_WRITE(!E_ENABLE_ON)
|
|
#else
|
|
#define enable_e0() /* nothing */
|
|
#define disable_e0() /* nothing */
|
|
#endif
|
|
|
|
#if (EXTRUDERS > 1) && HAS_E1_ENABLE
|
|
#define enable_e1() E1_ENABLE_WRITE( E_ENABLE_ON)
|
|
#define disable_e1() E1_ENABLE_WRITE(!E_ENABLE_ON)
|
|
#else
|
|
#define enable_e1() /* nothing */
|
|
#define disable_e1() /* nothing */
|
|
#endif
|
|
|
|
#if (EXTRUDERS > 2) && HAS_E2_ENABLE
|
|
#define enable_e2() E2_ENABLE_WRITE( E_ENABLE_ON)
|
|
#define disable_e2() E2_ENABLE_WRITE(!E_ENABLE_ON)
|
|
#else
|
|
#define enable_e2() /* nothing */
|
|
#define disable_e2() /* nothing */
|
|
#endif
|
|
|
|
#if (EXTRUDERS > 3) && HAS_E3_ENABLE
|
|
#define enable_e3() E3_ENABLE_WRITE( E_ENABLE_ON)
|
|
#define disable_e3() E3_ENABLE_WRITE(!E_ENABLE_ON)
|
|
#else
|
|
#define enable_e3() /* nothing */
|
|
#define disable_e3() /* nothing */
|
|
#endif
|
|
|
|
/**
|
|
* The axis order in all axis related arrays is X, Y, Z, E
|
|
*/
|
|
#define NUM_AXIS 4
|
|
|
|
/**
|
|
* Axis indices as enumerated constants
|
|
*
|
|
* A_AXIS and B_AXIS are used by COREXY printers
|
|
* X_HEAD and Y_HEAD is used for systems that don't have a 1:1 relationship between X_AXIS and X Head movement, like CoreXY bots.
|
|
*/
|
|
enum AxisEnum {NO_AXIS = -1, X_AXIS = 0, A_AXIS = 0, Y_AXIS = 1, B_AXIS = 1, Z_AXIS = 2, C_AXIS = 2, E_AXIS = 3, X_HEAD = 4, Y_HEAD = 5, Z_HEAD = 5};
|
|
|
|
#define _AXIS(AXIS) AXIS ##_AXIS
|
|
|
|
typedef enum { LINEARUNIT_MM = 0, LINEARUNIT_INCH = 1 } LinearUnit;
|
|
typedef enum { TEMPUNIT_C = 0, TEMPUNIT_K = 1, TEMPUNIT_F = 2 } TempUnit;
|
|
|
|
void enable_all_steppers();
|
|
void disable_all_steppers();
|
|
|
|
void FlushSerialRequestResend();
|
|
void ok_to_send();
|
|
|
|
void reset_bed_level();
|
|
void kill(const char*);
|
|
|
|
#if DISABLED(DELTA) && DISABLED(SCARA)
|
|
void set_current_position_from_planner();
|
|
#endif
|
|
|
|
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
|
|
void handle_filament_runout();
|
|
#endif
|
|
|
|
/**
|
|
* Debug flags - not yet widely applied
|
|
*/
|
|
enum DebugFlags {
|
|
DEBUG_NONE = 0,
|
|
DEBUG_ECHO = _BV(0), ///< Echo commands in order as they are processed
|
|
DEBUG_INFO = _BV(1), ///< Print messages for code that has debug output
|
|
DEBUG_ERRORS = _BV(2), ///< Not implemented
|
|
DEBUG_DRYRUN = _BV(3), ///< Ignore temperature setting and E movement commands
|
|
DEBUG_COMMUNICATION = _BV(4), ///< Not implemented
|
|
DEBUG_LEVELING = _BV(5) ///< Print detailed output for homing and leveling
|
|
};
|
|
extern uint8_t marlin_debug_flags;
|
|
#define DEBUGGING(F) (marlin_debug_flags & (DEBUG_## F))
|
|
|
|
extern bool Running;
|
|
inline bool IsRunning() { return Running; }
|
|
inline bool IsStopped() { return !Running; }
|
|
|
|
bool enqueue_and_echo_command(const char* cmd, bool say_ok=false); //put a single ASCII command at the end of the current buffer or return false when it is full
|
|
void enqueue_and_echo_command_now(const char* cmd); // enqueue now, only return when the command has been enqueued
|
|
void enqueue_and_echo_commands_P(const char* cmd); //put one or many ASCII commands at the end of the current buffer, read from flash
|
|
void clear_command_queue();
|
|
|
|
void clamp_to_software_endstops(float target[3]);
|
|
|
|
extern millis_t previous_cmd_ms;
|
|
inline void refresh_cmd_timeout() { previous_cmd_ms = millis(); }
|
|
|
|
#if ENABLED(FAST_PWM_FAN)
|
|
void setPwmFrequency(uint8_t pin, int val);
|
|
#endif
|
|
|
|
#ifndef CRITICAL_SECTION_START
|
|
#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli();
|
|
#define CRITICAL_SECTION_END SREG = _sreg;
|
|
#endif
|
|
|
|
extern bool axis_relative_modes[];
|
|
extern int feedrate_multiplier;
|
|
extern bool volumetric_enabled;
|
|
extern int extruder_multiplier[EXTRUDERS]; // sets extrude multiply factor (in percent) for each extruder individually
|
|
extern float filament_size[EXTRUDERS]; // cross-sectional area of filament (in millimeters), typically around 1.75 or 2.85, 0 disables the volumetric calculations for the extruder.
|
|
extern float volumetric_multiplier[EXTRUDERS]; // reciprocal of cross-sectional area of filament (in square millimeters), stored this way to reduce computational burden in planner
|
|
extern float current_position[NUM_AXIS];
|
|
extern float home_offset[3]; // axis[n].home_offset
|
|
extern float sw_endstop_min[3]; // axis[n].sw_endstop_min
|
|
extern float sw_endstop_max[3]; // axis[n].sw_endstop_max
|
|
extern bool axis_known_position[3]; // axis[n].is_known
|
|
extern bool axis_homed[3]; // axis[n].is_homed
|
|
extern bool wait_for_heatup;
|
|
|
|
// GCode support for external objects
|
|
bool code_seen(char);
|
|
int code_value_int();
|
|
float code_value_temp_abs();
|
|
float code_value_temp_diff();
|
|
|
|
#if ENABLED(DELTA)
|
|
extern float delta[3];
|
|
extern float endstop_adj[3]; // axis[n].endstop_adj
|
|
extern float delta_radius;
|
|
extern float delta_diagonal_rod;
|
|
extern float delta_segments_per_second;
|
|
extern float delta_diagonal_rod_trim_tower_1;
|
|
extern float delta_diagonal_rod_trim_tower_2;
|
|
extern float delta_diagonal_rod_trim_tower_3;
|
|
void calculate_delta(float cartesian[3]);
|
|
void recalc_delta_settings(float radius, float diagonal_rod);
|
|
#if ENABLED(AUTO_BED_LEVELING_FEATURE)
|
|
extern int delta_grid_spacing[2];
|
|
void adjust_delta(float cartesian[3]);
|
|
#endif
|
|
#elif ENABLED(SCARA)
|
|
extern float axis_scaling[3]; // Build size scaling
|
|
void calculate_delta(float cartesian[3]);
|
|
void calculate_SCARA_forward_Transform(float f_scara[3]);
|
|
#endif
|
|
|
|
#if ENABLED(Z_DUAL_ENDSTOPS)
|
|
extern float z_endstop_adj;
|
|
#endif
|
|
|
|
#if HAS_BED_PROBE
|
|
extern float zprobe_zoffset;
|
|
#endif
|
|
|
|
#if ENABLED(HOST_KEEPALIVE_FEATURE)
|
|
extern uint8_t host_keepalive_interval;
|
|
#endif
|
|
|
|
#if FAN_COUNT > 0
|
|
extern int fanSpeeds[FAN_COUNT];
|
|
#endif
|
|
|
|
#if ENABLED(BARICUDA)
|
|
extern int baricuda_valve_pressure;
|
|
extern int baricuda_e_to_p_pressure;
|
|
#endif
|
|
|
|
#if ENABLED(FILAMENT_WIDTH_SENSOR)
|
|
extern float filament_width_nominal; //holds the theoretical filament diameter i.e., 3.00 or 1.75
|
|
extern bool filament_sensor; //indicates that filament sensor readings should control extrusion
|
|
extern float filament_width_meas; //holds the filament diameter as accurately measured
|
|
extern int8_t measurement_delay[]; //ring buffer to delay measurement
|
|
extern int filwidth_delay_index1, filwidth_delay_index2; //ring buffer index. used by planner, temperature, and main code
|
|
extern int meas_delay_cm; //delay distance
|
|
#endif
|
|
|
|
#if ENABLED(FILAMENT_CHANGE_FEATURE)
|
|
enum FilamentChangeMenuResponse {
|
|
FILAMENT_CHANGE_RESPONSE_WAIT_FOR,
|
|
FILAMENT_CHANGE_RESPONSE_EXTRUDE_MORE,
|
|
FILAMENT_CHANGE_RESPONSE_RESUME_PRINT
|
|
};
|
|
extern FilamentChangeMenuResponse filament_change_menu_response;
|
|
#endif
|
|
|
|
#if ENABLED(PID_ADD_EXTRUSION_RATE)
|
|
extern int lpq_len;
|
|
#endif
|
|
|
|
#if ENABLED(FWRETRACT)
|
|
extern bool autoretract_enabled;
|
|
extern bool retracted[EXTRUDERS]; // extruder[n].retracted
|
|
extern float retract_length, retract_length_swap, retract_feedrate_mm_s, retract_zlift;
|
|
extern float retract_recover_length, retract_recover_length_swap, retract_recover_feedrate;
|
|
#endif
|
|
|
|
// Print job timer
|
|
#if ENABLED(PRINTCOUNTER)
|
|
extern PrintCounter print_job_timer;
|
|
#else
|
|
extern Stopwatch print_job_timer;
|
|
#endif
|
|
|
|
// Handling multiple extruders pins
|
|
extern uint8_t active_extruder;
|
|
|
|
#if HAS_TEMP_HOTEND || HAS_TEMP_BED
|
|
void print_heaterstates();
|
|
#endif
|
|
|
|
void calculate_volumetric_multipliers();
|
|
|
|
// Buzzer
|
|
#if HAS_BUZZER
|
|
#if ENABLED(SPEAKER)
|
|
#include "speaker.h"
|
|
extern Speaker buzzer;
|
|
#else
|
|
#include "buzzer.h"
|
|
extern Buzzer buzzer;
|
|
#endif
|
|
#endif
|
|
|
|
#endif //MARLIN_H
|