From be031e18509884c42051fba6849af06e089e383f Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 3 Oct 2023 14:57:07 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20More=20ExtUI=20documentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/inc/Conditionals_LCD.h | 2 +- Marlin/src/lcd/e3v2/common/dwin_api.cpp | 2 +- Marlin/src/lcd/extui/ui_api.cpp | 98 +++++++++++++++++-------- Marlin/src/lcd/extui/ui_api.h | 84 +++++++++++++++++---- 4 files changed, 140 insertions(+), 46 deletions(-) diff --git a/Marlin/src/inc/Conditionals_LCD.h b/Marlin/src/inc/Conditionals_LCD.h index b069e2d2b173..2e51e3db6add 100644 --- a/Marlin/src/inc/Conditionals_LCD.h +++ b/Marlin/src/inc/Conditionals_LCD.h @@ -490,7 +490,7 @@ // Extensible UI serial touch screens. (See src/lcd/extui) #if ANY(HAS_DGUS_LCD, MALYAN_LCD, ANYCUBIC_LCD_I3MEGA, ANYCUBIC_LCD_CHIRON, NEXTION_TFT, TOUCH_UI_FTDI_EVE) - #define IS_EXTUI 1 + #define IS_EXTUI 1 // Just for sanity check. #define EXTENSIBLE_UI #endif diff --git a/Marlin/src/lcd/e3v2/common/dwin_api.cpp b/Marlin/src/lcd/e3v2/common/dwin_api.cpp index af28cfe62bfc..4442b5847d58 100644 --- a/Marlin/src/lcd/e3v2/common/dwin_api.cpp +++ b/Marlin/src/lcd/e3v2/common/dwin_api.cpp @@ -317,7 +317,7 @@ void dwinDrawFloatValue(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t //uint8_t *fvalue = (uint8_t*)&value; size_t i = 0; #if DISABLED(DWIN_CREALITY_LCD_JYERSUI) - dwinDrawRectangle(1, bColor, x, y, x + fontWidth(size) * (iNum+fNum+1), y + fontHeight(size)); + dwinDrawRectangle(1, bColor, x, y, x + fontWidth(size) * (iNum + fNum + 1), y + fontHeight(size)); #endif dwinByte(i, 0x14); dwinByte(i, (bShow * 0x80) | (zeroFill * 0x20) | (zeroMode * 0x10) | size); diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp index 7f216107289a..bccc543b7f34 100644 --- a/Marlin/src/lcd/extui/ui_api.cpp +++ b/Marlin/src/lcd/extui/ui_api.cpp @@ -172,35 +172,6 @@ namespace ExtUI { if (!flags.printer_killed) thermalManager.task(); } - void enableHeater(const extruder_t extruder) { - #if HAS_HOTEND && HEATER_IDLE_HANDLER - thermalManager.reset_hotend_idle_timer(extruder - E0); - #else - UNUSED(extruder); - #endif - } - - void enableHeater(const heater_t heater) { - #if HEATER_IDLE_HANDLER - switch (heater) { - #if HAS_HEATED_BED - case BED: thermalManager.reset_bed_idle_timer(); return; - #endif - #if HAS_HEATED_CHAMBER - case CHAMBER: return; // Chamber has no idle timer - #endif - #if HAS_COOLER - case COOLER: return; // Cooler has no idle timer - #endif - default: - TERN_(HAS_HOTEND, thermalManager.reset_hotend_idle_timer(heater - H0)); - break; - } - #else - UNUSED(heater); - #endif - } - #if ENABLED(JOYSTICK) /** * Jogs in the direction given by the vector (dx, dy, dz). @@ -237,6 +208,39 @@ namespace ExtUI { } #endif + // + // Heaters locked / idle + // + + void enableHeater(const extruder_t extruder) { + #if HAS_HOTEND && HEATER_IDLE_HANDLER + thermalManager.reset_hotend_idle_timer(extruder - E0); + #else + UNUSED(extruder); + #endif + } + + void enableHeater(const heater_t heater) { + #if HEATER_IDLE_HANDLER + switch (heater) { + #if HAS_HEATED_BED + case BED: thermalManager.reset_bed_idle_timer(); return; + #endif + #if HAS_HEATED_CHAMBER + case CHAMBER: return; // Chamber has no idle timer + #endif + #if HAS_COOLER + case COOLER: return; // Cooler has no idle timer + #endif + default: + TERN_(HAS_HOTEND, thermalManager.reset_hotend_idle_timer(heater - H0)); + break; + } + #else + UNUSED(heater); + #endif + } + bool isHeaterIdle(const extruder_t extruder) { #if HAS_HOTEND && HEATER_IDLE_HANDLER return thermalManager.heater_idle[extruder - E0].timed_out; @@ -302,6 +306,9 @@ namespace ExtUI { return GET_TEMP_ADJUSTMENT(thermalManager.degTargetHotend(extruder - E0)); } + // + // Fan target/actual speed + // float getTargetFan_percent(const fan_t fan) { UNUSED(fan); return TERN0(HAS_FAN, thermalManager.fanSpeedPercent(fan - FAN0)); @@ -312,6 +319,9 @@ namespace ExtUI { return TERN0(HAS_FAN, thermalManager.scaledFanSpeedPercent(fan - FAN0)); } + // + // High level axis and extruder positions + // float getAxisPosition_mm(const axis_t axis) { return current_position[axis]; } @@ -349,6 +359,9 @@ namespace ExtUI { line_to_current_position(feedrate ?: manual_feedrate_mm_s.e); } + // + // Tool changing + // void setActiveTool(const extruder_t extruder, bool no_move) { #if HAS_MULTI_EXTRUDER const uint8_t e = extruder - E0; @@ -370,11 +383,17 @@ namespace ExtUI { extruder_t getActiveTool() { return getTool(active_extruder); } + // + // Moving axes and extruders + // bool isMoving() { return planner.has_blocks_queued(); } + // + // Motion might be blocked by NO_MOTION_BEFORE_HOMING + // bool canMove(const axis_t axis) { switch (axis) { - #if IS_KINEMATIC || ENABLED(NO_MOTION_BEFORE_HOMING) + #if ANY(IS_KINEMATIC, NO_MOTION_BEFORE_HOMING) OPTCODE(HAS_X_AXIS, case X: return !axis_should_home(X_AXIS)) OPTCODE(HAS_Y_AXIS, case Y: return !axis_should_home(Y_AXIS)) OPTCODE(HAS_Z_AXIS, case Z: return !axis_should_home(Z_AXIS)) @@ -385,20 +404,34 @@ namespace ExtUI { } } + // + // E Motion might be prevented by cold material + // bool canMove(const extruder_t extruder) { return !thermalManager.tooColdToExtrude(extruder - E0); } + // + // Host Keepalive, used by awaitingUserConfirm + // #if ENABLED(HOST_KEEPALIVE_FEATURE) GcodeSuite::MarlinBusyState getHostKeepaliveState() { return gcode.busy_state; } bool getHostKeepaliveIsPaused() { return gcode.host_keepalive_is_paused(); } #endif + // + // Soft Endstops Enabled/Disabled State + // + #if HAS_SOFTWARE_ENDSTOPS bool getSoftEndstopState() { return soft_endstop._enabled; } void setSoftEndstopState(const bool value) { soft_endstop._enabled = value; } #endif + // + // Trinamic Current / Bump Sensitivity + // + #if HAS_TRINAMIC_CONFIG float getAxisCurrent_mA(const axis_t axis) { switch (axis) { @@ -626,6 +659,10 @@ namespace ExtUI { } #endif + // + // Planner Accessors / Setters + // + float getAxisSteps_per_mm(const axis_t axis) { return planner.settings.axis_steps_per_mm[axis]; } @@ -1103,6 +1140,7 @@ namespace ExtUI { bool isMediaInserted() { return TERN0(HAS_MEDIA, IS_SD_INSERTED()); } + // Pause/Resume/Stop are implemented in MarlinUI void pausePrint() { ui.pause_print(); } void resumePrint() { ui.resume_print(); } void stopPrint() { ui.abort_print(); } diff --git a/Marlin/src/lcd/extui/ui_api.h b/Marlin/src/lcd/extui/ui_api.h index 125c85ffa275..0d2c3e8d86a5 100644 --- a/Marlin/src/lcd/extui/ui_api.h +++ b/Marlin/src/lcd/extui/ui_api.h @@ -72,6 +72,28 @@ namespace ExtUI { typedef float bed_mesh_t[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y]; #endif + /** + * The Extensible UI API is a utility class that can be used to implement: + * - An LCD view that responds to standard events, e.g., onMediaInserted(...) + * - An LCD that polls firmware states and settings in a standard manner. + * (e.g., With tool indexes and extruder indexes). + * - Standard hooks to send data to a serial-based controller. + * + * ExtUI is best used when: + * - The display handles LCD touch / buttons so the firmware doesn't see these events. + * - Commands and value edits are sent over serial to Marlin as G-codes. + * - The display can get data from Marlin, but is not necessarily drawn by Marlin. + * - The display cannot implement a MarlinUI menu. + * - The display is implemented with code callbacks alongside ExtUI callbacks. + * + * Building an ExtUI layer: + * - Start by making an lcd/extui subfolder. Copy 'example' or another display. + * - Many of these methods are optional. Implement them according to your UI needs. + * - If your display needs information from Marlin, add an accessor to ExtUI. + * - If some addition seems like it should be standard part of ExtUI, submit a PR with the new + * methods added to this API. Implement in the ExtUI example and/or with some existing displays. + */ + bool isMoving(); bool isAxisPositionKnown(const axis_t); bool isAxisPositionKnown(const extruder_t); @@ -89,11 +111,6 @@ namespace ExtUI { bool getHostKeepaliveIsPaused(); #endif - bool isHeaterIdle(const heater_t); - bool isHeaterIdle(const extruder_t); - void enableHeater(const heater_t); - void enableHeater(const extruder_t); - #if ENABLED(JOYSTICK) void jog(const xyz_float_t &dir); void _joystick_update(xyz_float_t &norm_jog); @@ -101,7 +118,7 @@ namespace ExtUI { /** * Getters and setters - * Should be used by the EXTENSIBLE_UI to query or change Marlin's state. + * Use to query or change Marlin's state. */ PGM_P getFirmwareName_str(); @@ -110,6 +127,7 @@ namespace ExtUI { void setSoftEndstopState(const bool); #endif + // Trinamic Current / Bump Sensitivity #if HAS_TRINAMIC_CONFIG float getAxisCurrent_mA(const axis_t); float getAxisCurrent_mA(const extruder_t); @@ -120,37 +138,50 @@ namespace ExtUI { void setTMCBumpSensitivity(const_float_t, const axis_t); #endif + // Actual and target accessors, by Heater ID, Extruder ID, Fan ID + void enableHeater(const heater_t); + void enableHeater(const extruder_t); + bool isHeaterIdle(const heater_t); + bool isHeaterIdle(const extruder_t); celsius_float_t getActualTemp_celsius(const heater_t); celsius_float_t getActualTemp_celsius(const extruder_t); celsius_float_t getTargetTemp_celsius(const heater_t); celsius_float_t getTargetTemp_celsius(const extruder_t); - float getTargetFan_percent(const fan_t); float getActualFan_percent(const fan_t); + float getTargetFan_percent(const fan_t); + + // High level positions, by Axis ID, Extruder ID float getAxisPosition_mm(const axis_t); float getAxisPosition_mm(const extruder_t); + // Axis steps-per-mm, by Axis ID, Extruder ID float getAxisSteps_per_mm(const axis_t); float getAxisSteps_per_mm(const extruder_t); + // Speed and acceleration limits, per Axis ID or Extruder ID feedRate_t getAxisMaxFeedrate_mm_s(const axis_t); feedRate_t getAxisMaxFeedrate_mm_s(const extruder_t); float getAxisMaxAcceleration_mm_s2(const axis_t); float getAxisMaxAcceleration_mm_s2(const extruder_t); + // Standard speeds, as set in the planner feedRate_t getMinFeedrate_mm_s(); feedRate_t getMinTravelFeedrate_mm_s(); feedRate_t getFeedrate_mm_s(); + // Standard accelerations, as set in the planner float getPrintingAcceleration_mm_s2(); float getRetractAcceleration_mm_s2(); float getTravelAcceleration_mm_s2(); + // A speed multiplier for overall printing float getFeedrate_percent(); + // The flow percentage of an extruder int16_t getFlow_percent(const extruder_t); + // Progress / Elapsed Time inline uint8_t getProgress_percent() { return ui.get_progress_percent(); } - #if HAS_PRINT_PROGRESS_PERMYRIAD inline uint16_t getProgress_permyriad() { return ui.get_progress_permyriad(); } #endif - uint32_t getProgress_seconds_elapsed(); + // Material Preheat Presets #if HAS_PREHEAT uint16_t getMaterial_preset_E(const uint16_t); #if HAS_HEATED_BED @@ -158,6 +189,7 @@ namespace ExtUI { #endif #endif + // IDEX Machine Mode #if ENABLED(DUAL_X_CARRIAGE) uint8_t getIDEX_Mode(); #endif @@ -170,12 +202,14 @@ namespace ExtUI { #endif #if HAS_LEVELING + // Global leveling state, events bool getLevelingActive(); void setLevelingActive(const bool); bool getLevelingIsValid(); void onLevelingStart(); void onLevelingDone(); #if HAS_MESH + // Mesh data, utilities, events bed_mesh_t& getMeshArray(); float getMeshPoint(const xy_uint8_t &pos); void setMeshPoint(const xy_uint8_t &pos, const_float_t zval); @@ -198,17 +232,20 @@ namespace ExtUI { #endif #endif + // Send an 'M876 S' host response #if ENABLED(HOST_PROMPT_SUPPORT) void setHostResponse(const uint8_t); #endif + // Provide a simulated click to MarlinUI inline void simulateUserClick() { - #if ANY(HAS_MARLINUI_MENU, EXTENSIBLE_UI, DWIN_CREALITY_LCD_JYERSUI) + #if ANY(HAS_MARLINUI_MENU, EXTENSIBLE_UI) ui.lcd_clicked = true; #endif } #if ENABLED(PRINTCOUNTER) + // Printcounter strings (See nextion_tft.cpp) char* getFailedPrints_str(char buffer[21]); char* getTotalPrints_str(char buffer[21]); char* getFinishedPrints_str(char buffer[21]); @@ -217,12 +254,17 @@ namespace ExtUI { char* getFilamentUsed_str(char buffer[21]); #endif + // Temperature Control void setTargetTemp_celsius(const_float_t, const heater_t); void setTargetTemp_celsius(const_float_t, const extruder_t); void setTargetFan_percent(const_float_t, const fan_t); void coolDown(); + + // Motion Control void setAxisPosition_mm(const_float_t, const axis_t, const feedRate_t=0); void setAxisPosition_mm(const_float_t, const extruder_t, const feedRate_t=0); + + // Planner Control void setAxisSteps_per_mm(const_float_t, const axis_t); void setAxisSteps_per_mm(const_float_t, const extruder_t); void setAxisMaxFeedrate_mm_s(const feedRate_t, const axis_t); @@ -237,20 +279,25 @@ namespace ExtUI { void setTravelAcceleration_mm_s2(const_float_t); void setFeedrate_percent(const_float_t); void setFlow_percent(const int16_t, const extruder_t); + + // Waiting for User Interaction bool awaitingUserConfirm(); void setUserConfirmed(); #if M600_PURGE_MORE_RESUMABLE + // "Purge More" has a control screen void setPauseMenuResponse(PauseMenuResponse); extern PauseMessage pauseModeStatus; PauseMode getPauseMode(); #endif #if ENABLED(LIN_ADVANCE) + // Linear Advance Control float getLinearAdvance_mm_mm_s(const extruder_t); void setLinearAdvance_mm_mm_s(const_float_t, const extruder_t); #endif + // JD or Jerk Control #if HAS_JUNCTION_DEVIATION float getJunctionDeviation_mm(); void setJunctionDeviation_mm(const_float_t); @@ -261,10 +308,12 @@ namespace ExtUI { void setAxisMaxJerk_mm_s(const_float_t, const extruder_t); #endif + // Tool Changing extruder_t getTool(const uint8_t extruder); extruder_t getActiveTool(); void setActiveTool(const extruder_t, bool no_move); + // Babystepping (axis, probe offset) #if ENABLED(BABYSTEPPING) int16_t mmToWholeSteps(const_float_t mm, const axis_t axis); float mmFromWholeSteps(int16_t steps, const axis_t axis); @@ -273,20 +322,24 @@ namespace ExtUI { void smartAdjustAxis_steps(const int16_t steps, const axis_t axis, bool linked_nozzles); #endif + // Hotend Offsets #if HAS_HOTEND_OFFSET float getNozzleOffset_mm(const axis_t, const extruder_t); void setNozzleOffset_mm(const_float_t, const axis_t, const extruder_t); void normalizeNozzleOffset(const axis_t axis); #endif + // The Probe Z Offset float getZOffset_mm(); void setZOffset_mm(const_float_t); + // The Probe XYZ Offset #if HAS_BED_PROBE float getProbeOffset_mm(const axis_t); void setProbeOffset_mm(const_float_t, const axis_t); #endif + // Backlash Control #if ENABLED(BACKLASH_GCODE) float getAxisBacklash_mm(const axis_t); void setAxisBacklash_mm(const_float_t, const axis_t); @@ -300,6 +353,7 @@ namespace ExtUI { #endif #endif + // Filament Runout Sensor #if HAS_FILAMENT_SENSOR bool getFilamentRunoutEnabled(); void setFilamentRunoutEnabled(const bool); @@ -312,6 +366,7 @@ namespace ExtUI { #endif #endif + // Case Light Control #if ENABLED(CASE_LIGHT_ENABLE) bool getCaseLightState(); void setCaseLightState(const bool); @@ -322,11 +377,13 @@ namespace ExtUI { #endif #endif + // Power-Loss Recovery #if ENABLED(POWER_LOSS_RECOVERY) bool getPowerLossRecoveryEnabled(); void setPowerLossRecoveryEnabled(const bool); #endif + // Hotend PID #if ENABLED(PIDTEMP) float getPID_Kp(const extruder_t); float getPID_Ki(const extruder_t); @@ -335,6 +392,7 @@ namespace ExtUI { void startPIDTune(const celsius_t, extruder_t); #endif + // Bed PID #if ENABLED(PIDTEMPBED) float getBedPID_Kp(); float getBedPID_Ki(); @@ -361,8 +419,7 @@ namespace ExtUI { /** * Media access routines - * - * Should be used by the EXTENSIBLE_UI to operate on files + * Use these to operate on files */ bool isMediaInserted(); bool isPrintingFromMediaPaused(); @@ -394,8 +451,7 @@ namespace ExtUI { /** * Event callback routines - * - * Should be declared by EXTENSIBLE_UI and will be called by Marlin + * Must be defined, and will be called by Marlin as needed */ void onStartup(); void onIdle();