Git Product home page Git Product logo

marlinkimbra's People

Contributors

magokimbra avatar nextime avatar pravdomil avatar ricardoga avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

marlinkimbra's Issues

Thermal Runaway Protection - ERROR

Arduino: 1.6.3 (Mac OS X), Placa:"Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"

temperature.cpp:1089:44: error: macro "ECHO_S" passed 2 arguments, but takes just 1
ECHO_S(ER, MSG_THERMAL_RUNAWAY_STOP);
^
temperature.cpp: In function 'void thermal_runaway_protection(TRState_, millis_t_, float, float, int, int, int)':
temperature.cpp:1089:9: error: 'ECHO_S' was not declared in this scope
ECHO_S(ER, MSG_THERMAL_RUNAWAY_STOP);
^
Erro compilando.

Este relatório deveria ter mais informações
"Mostrar saída verbosa durante a compilação"
habilitado em Arquivo > Preferências.

não compila #define Z_PROBE_ENDSTOP

Arduino: 1.6.4 (Mac OS X), Placa:"Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"

In file included from base.h:52:0,
from blinkm.cpp:6:
sanitycheck.h:1519: error: #error DEPENDENCY ERROR: You must set Z_PROBE_PIN to a valid pin if you enable Z_PROBE_ENDSTOP
#error DEPENDENCY ERROR: You must set Z_PROBE_PIN to a valid pin if you enable Z_PROBE_ENDSTOP
^

error DEPENDENCY ERROR: You must set Z_PROBE_PIN to a valid pin if you enable Z_PROBE_ENDSTOP

Este relatório deveria ter mais informações
"Mostrar saída verbosa durante a compilação"
habilitado em Arquivo > Preferências.

pins.h:

/****************************************************************************************

  • 33
  • RAMPS 1.3 / 1.4
  • RAMPS_13_HFB (Hotend0, Fan, Bed)
    ****************************************************************************************/

if MB(RAMPS_13_HFB)

#define KNOWN_BOARD 1

#if !defined(AVR_ATmega1280) && !defined(AVR_ATmega2560)
#error Oops! Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu.
#endif

#define LARGE_FLASH true

//X axis pins
#define ORIG_X_STEP_PIN 54
#define ORIG_X_DIR_PIN 55
#define ORIG_X_ENABLE_PIN 38
#define X_MIN_PIN 3
#define X_MAX_PIN 2

//Y axis pins
#define ORIG_Y_STEP_PIN 60
#define ORIG_Y_DIR_PIN 61
#define ORIG_Y_ENABLE_PIN 56
#define Y_MIN_PIN 14
#define Y_MAX_PIN 15

#define Y2_STEP_PIN 36
#define Y2_DIR_PIN 34
#define Y2_ENABLE_PIN 30

//Z axis pins
#define ORIG_Z_STEP_PIN 46
#define ORIG_Z_DIR_PIN 48
#define ORIG_Z_ENABLE_PIN 62
#define Z_MIN_PIN 18
#define Z_MAX_PIN 19
#define Z_PROBE_PIN 18

#define Z2_STEP_PIN 36
#define Z2_DIR_PIN 34
#define Z2_ENABLE_PIN 30

//E axis pins
#define ORIG_E0_STEP_PIN 26
#define ORIG_E0_DIR_PIN 28
#define ORIG_E0_ENABLE_PIN 24

#define ORIG_E1_STEP_PIN 36
#define ORIG_E1_DIR_PIN 34
#define ORIG_E1_ENABLE_PIN 30

#define SDPOWER -1
#define SDSS 53
#define LED_PIN 13

#define ORIG_FAN_PIN 9
#define PS_ON_PIN 12

Steps per unit

I am using two extruders and the steps per unit set both extruders with the value for second extruder and I have to manually set the steps for the first extruder on each restart. Is there a option to display this in eeprom settings repetier host as well?

New Nextion Display Interface

Good day! I want to give You to use Nextion the screen interface I designed for my printer. If You are interested in such cooperation, please contact me on [email protected]. Besides, I have a few code modifications for marlin to work the best initialization Nextion display.

link to china Nextion clone project (and program) in archive:
https://yadi.sk/d/22hPbiSpmuyqn

Miglioramento "Thermal Runaway Protection"

Salve,

Mi chiedevo se fosse possibile migliorare ulteriormente questa funzionalità coprendo anche il caso in cui il termistore sia rotto prima della stampa. Se non sbaglio al momento la funzione di protezione entra in funzione dopo che la temperatura di stampa è stata raggiunta. Credo sia un'ottima modifica introdurre un timer che parte all'accensione e si disattiva nel momento in cui entra in funzione quello già esistente.
In questo modo si può mettere anche un limite entro il quale la temperatura di stampa deve essere raggiunta.

DELTA SEGMENTS FOR MM!? NÃO FUNCIONA

/ Make delta curves from many straight lines (linear interpolation).
// This is a trade-off between visible corners (not enough segments)
// and processor overload (too many expensive sqrt calls).
// The new function do not use segments per second but segments per mm
// if you want use new function comment this (using // at the start of the line)
// #define DELTA_SEGMENTS_PER_SECOND 150

Extruder sometimes spins backwards on first turn

I recently got MarlinKimbra running on my MendelMax 3 (RAMBO) with a custom dual extruder setup. I have one 3mm geared extruder and one 1.75mm direct drive, with two different types of motor -- impossible to handle with standard Marlin. So far, with MarlinKimbra, it works very well most of the time. (add this to your list of supported hardware!).

There is one occasional bug I can't figure out. This usually happens after switching a tool with T1/T0 commands. Sometimes after the switch, when I try to manually extrude filament (I use Repetier-Host), the extruder spins backwards and retracts instead. I'll click "extrude 10mm" and instead it retracts 10mm. I can do this a number of times and the extruder will retract every time. Then, if I click the "retract" button, the extruder does retract whatever distance it's supposed to...and after that, the directions are back to normal. Both extrusion and retraction behave as intended.

So basically, after switching a tool the extrusion direction is reversed (but not the retraction), until a retraction command is sent, at which time it solves itself.

This hasn't caused major problems with prints so far because every tool change includes a retraction command, so it may be covering up the problem. I haven't gotten really deep into the calibration of toolchange behavior so I don't know for sure.

Any ideas on what might be going on? Are there logs I could pull to help solve the problem?

edit: this looks like it may be related to issue #5 as well, though I haven't experienced that specific problem yet.

M105 response

Hi! I am running dual head printer with MarlinKimbra and Octoprint. Octoprint is confused, when receiving response on M105 code:
Recv: T:77.1 /205.0 B:59.5 /60.0 T0:206.5 /205.0 T1:77.1 /205.0 B@:0 @:127 @0:40 @1:127 W:?

This is the answer - can you please explain, what the "B@:0 @:127 @0:40 @1:127 W:?" part is about?
Thanks,
Martins

ERROR AO DESCOMENTAR #define SDSUPPORT

Arduino: 1.6.4 (Mac OS X), Placa:"Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"

Opções de compilação alteradas, recompilando tudo
In file included from conditionals.h:217:0,
from base.h:51,
from cardreader.cpp:1:
pins.h:898: error: expected unqualified-id before numeric constant
#define SDSS 53
^
pins.h:5134:29: note: in expansion of macro 'SDSS'
#define SS_PIN SDSS
^
Sd2PinMap.h:44:15: note: in expansion of macro 'SS_PIN'
uint8_t const SS_PIN = 53; // B0
^
expected unqualified-id before numeric constant

Este relatório deveria ter mais informações
"Mostrar saída verbosa durante a compilação"
habilitado em Arquivo > Preferências.

#define PIDTEMPBED - ERROR

Arduino: 1.6.3 (Mac OS X), Placa:"Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"

ConfigurationStore.cpp:744:33: error: macro "ECHO_SMV" requires 4 arguments, but only 2 given
ECHO_SMV(" M304 P", bedKp); // for compatibility with hosts, only echos values for E0
^
ConfigurationStore.cpp: In function 'void Config_PrintSettings(bool)':
ConfigurationStore.cpp:744:7: error: 'ECHO_SMV' was not declared in this scope
ECHO_SMV(" M304 P", bedKp); // for compatibility with hosts, only echos values for E0
^
Erro compilando.

Este relatório deveria ter mais informações
"Mostrar saída verbosa durante a compilação"
habilitado em Arquivo > Preferências.

Nextion causing RAMPS 1.4 to reset

I am trying to implement the Nextion/MK firmware on my RAMPS 1.4 and am running into a reset issue. When running just the Nextion and a thermister it will stay on all day, but once I have the RAMPS board fully wired up with an ATX power supply, it starts to do a continual reset after 20 seconds. I've removed just about everything I can think of, but maybe someone has a PWM issue they've already troubleshot. I've tried a separate powersupply for just the LCD, but this configuration doesn't read the serial data coming from the Arduino.

Thoughts?

Configurazioni sulla SD

Giusto per curiosità come mai è stato tolto il sistema per le configurazioni sulla SD?
Saluti,
Simone

LCD compile error

ultralcd.cpp.o: In function _lcd_move': C:\Users\Trvorts\AppData\Local\Temp\build8714360466396254804.tmp/ultralcd.cpp:986: undefined reference torefresh_cmd_timeout()'

Arduino Compiler problem

All the time that try to compile MarlinKimbra.ino (downloaded the end of configuration) I receive the following compiler error:

In file included from /Configuration.h:613,
from /Marlin.h:25,
from blinkm.cpp:5:
Configuration_adv.h:335: error: expected ',' or ';' before 'const'

how can i fix it? i have also an older (i think) version of MarlinKimbra.ino and it works

ERROR!!

Arduino: 1.6.4 (Mac OS X), Placa:"Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"

In file included from blinkm.cpp:5:0:
base.h:50:31: fatal error: language/language.h: No such file or directory
#include "language/language.h"
^
compilation terminated.
Erro compilando.

Este relatório deveria ter mais informações
"Mostrar saída verbosa durante a compilação"
habilitado em Arquivo > Preferências.

The second extruder change his direction during printing.

Hi,
I have an H-bot printer with one hotend and two extruders. I have configured all with the on-line tool except for the mechanic.

The problem appear randomly while work the second extruder, It change direction during printing and the printing go fail!

What I can do? Is it a known problem?

Full Graphics LCD Panels LCD Contrast error

When selecting any full Graphics LCD 128 x 64 with Azteeg X3 Pro it errors during compilation
Errors are
Error at line 517 in file configuration_store.cpp

same error doesnt matter what controller board is selected....basically anything where contrast can be adjusted

\Kimbra Master\MarlinKimbra-master\MarlinKimbra\configuration_store.cpp: In function 'void Config_ResetDefault()':
Error at line 517 in file configuration_store.cpp
\Kimbra Master\MarlinKimbra-master\MarlinKimbra\configuration_store.cpp:517: error: 'lcd_contrast' was not declared in this scope
Failed compiling sketch

NEXTION HMI - NexVar issues

Hi,
First of all, good job with your firmware compatibility with NEXTION HMI! (and sorry for my English).

I'm testing this feature but I've some issues reading variable values like vacmd , etc...

In setmovePopCallback function of nextion_lcd.cpp gets the vacmd value and put it into buffer for a enqueued command when pushed move buttons.
This value doesn't match with value returned by NEXTION in the IDE program, it's something like this:

echo: enqueueing "G91"
echo: enqueueing "n feedrate (mm/s), V=Min trav" <------------ seems a incorrect reading¿? old buffer data¿?
echo: enqueueing "G90"

I've tried to clean the buffer, create a new buffer, etc... but only gets the same result or garbage...

It's normal? How can I test it (enable debugging maybe)?

Thank you!!!

Bed auto leveling manual!!

It is possible to make a manual bal small adjustments at the time of printing, such as babystep Z to Delta would have as a reference the towers and Cartesian the midpoint of each side of the table

Configuration.h problema di codifica

Salve,
con la nuova versione di arduino IDE 1.6.1 ho riscontrato il seguente avviso di compilazione:
"Configuration.h" contiene caratteri non riconosciuti. Se questo codice è stato creato con una vecchia versione di Arduino potresti dover usare il comando "Strumenti->Correggi codifica e ricarica" per aggiornare lo sketch. In caso contrario, per eliminare questo avviso, devi cancellare i caratteri non supportati dallo sketch."

Con Notepad++ ho convertito la codifica in ANSI e poi nuovamente in UTF-8 senza BOM e il problema si è risolto.
Credo che sia necessario aggiornare la codifica del file presente nella repository.

PS: Scrivo direttamente in italiano dato che è un problema banale e mi sembrava inutile riportarlo scrivendoti in inglese
Cordiali Saluti,
Simone

Bed PID autotune

Hey! Im trying to set my bed PID, but no matter what command i try it always does the autotune on the hotend. Am i missing something? Ive tried M303 E-1 SXXX, M303 SXXX, M303 E1 SXXX C8... But all of them heat up the extruder only.

Reprapdiscount LCD panel: SD card not functional + Bed temperature not displaying

I recently upgraded my Mendel(i2) to a dual extrusion setup and marlin desperately lacks functionality like same steps/mm and pid settings for both extruders.

The latest Marlin release has seamless LCD panel setup which shows extruder and heated bed temps and has full SD card functionality. But the dual extrusion issues remain.

After messing around with MarlinX2 with highly disappointing results, I decided to give this a shot and it is a beautiful piece of code. However, I have some issues:
-I just cannot get the SDcard to work or heat bed temp to display.
-Also the preheat menu lacks the preheat bed only option.
-The X and Y positions are kind of overkill since during print all that I kind of care about is %completion or to a minor degree the Z height

My current setup is a Mendel(i2), bowden fed dual extruder(greg-wade herringbone gears), all metal hotends (http://www.ebay.com/itm/181910932202?_trksid=p2060353.m2749.l2649&ssPageName=STRK%3AMEBIDX%3AIT), RAMBO board, Marlin firmware(https://github.com/MarlinFirmware/Marlin)- using the september release.

While I agree I might be asking for too much, wirefree SD card printing has kind of spoilt me. I would love it, if someone could bridge these 2 firmwares.

BABYSTEPPING don't work

This report would have more information with
"Show verbose output during compilation"
enabled in File > Preferences.
Arduino: 1.0.6 (Mac OS X), Board: "Arduino Mega 2560 or Mega ADK"
temperature.cpp: In function 'void __vector_22()':
temperature.cpp:1983: error: 'babystep' was not declared in this scope
temperature.cpp:1989: error: 'babystep' was not declared in this scope

[BUG] Preblemi cinetica cartesiana (Estrusore???)

Dalla versione 4.1.3 in su ho problemi con i movimenti della stampante, credo sia dovuto all'implementazione dell' EJerk sull estrusore oppure all'aggiunta dell'accellerazione sulla ritrazione.
Spiego il problema.
Avvio il gcode dalla SD, la stampante si riscalda, fa homing e tutto, si muove verso il punto per iniziare la stampa, fa un rumore duro (tipo il tonfo quando si spegne uno stepper) e parte la stampa.
Nel gcode io ho le accellerazioni per i movimenti settate a 1250
Se le alzo a 3000 il problema lo fa ogni layer change.

Tutto ciò non succede con la versione 4.1.2.
Credo sia un bug significativamente grave, ora ispeziono i cambiamenti nel codice tra le versioni e vedo di fixare.
Perchè anche la qualità di stampa ne risente molto.
Lo stesso gcode a causa di questo problema con la 4.1.2 viene fuori molto meglio di quello fatto con la 4.1.5

Not compile sketch

C:\DOCUME1*****\LOCALS1\Temp\build92b315221a45dac1da7e7fb9e76d9964.tmp/core\core.a(main.cpp.o): In function `main':

D:\distr\Free_Soft\Programming\arduino-1.6.6\hardware\arduino\avr\cores\arduino/main.cpp:37: undefined reference to `setup'

D:\distr\Free_Soft\Programming\arduino-1.6.6\hardware\arduino\avr\cores\arduino/main.cpp:47: undefined reference to `loop'

collect2.exe: error: ld returned 1 exit status

exit status 1

Trying to compile the project.

error #define BABYSTEPPING

Arduino: 1.6.7 (Mac OS X), Placa:"Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"

In file included from sketch/base.h:38:0,
from /Users/brenosouza/Downloads/MarlinKimbra-master-31/MK/MK.ino:192:
sketch/module/sanitycheck.h:500:8: error: #error DEPENDENCY ERROR: Missing setting BABYSTEP_Z_MULTIPLICATOR
#error DEPENDENCY ERROR: Missing setting BABYSTEP_Z_MULTIPLICATOR
^
exit status 1
Erro compilando.

Este relatório deveria ter mais informações
"Mostrar saída verbosa durante a compilação"
habilitado em Arquivo > Preferências.

pins2tool.h

Salve,
a cosa dovrebbe servire questo file?
Attualmente se tenuto in compilazione sovrascrive il pin della ventola impedendone il funzionamento.
Saluti,
Simone

With REPRAP_DISCOUNT_SMART_CONTROLLER used, compiling results in refresh_cmd_timeout error

With REPRAP_DISCOUNT_SMART_CONTROLLER used, compiling results in refresh_cmd_timeout not defined error in the ultralcd.cpp file.
I was able to add the following line:
inline void refresh_cmd_timeout() {}
to a random location in the file ultralcd.cpp file to make it happy and all seems well. Dunno for sure what the purpose of this call is for, though. Here is my resultant ultralcd.cpp file:

include "base.h"

if ENABLED(ULTRA_LCD)

include "Marlin_main.h"

include "cardreader.h"

include "temperature.h"

if ENABLED(AUTO_BED_LEVELING_FEATURE)

#include "vector_3.h"

endif

include "planner.h"

include "stepper_indirection.h"

include "stepper.h"

include "configuration_store.h"

include "ultralcd.h"

if HAS(BUZZER)

#include "buzzer.h"

endif

int8_t encoderDiff; // updated from interrupt context and added to encoderPosition every LCD update

bool encoderRateMultiplierEnabled;
int32_t lastEncoderMovementMillis;

if !MECH(DELTA) && DISABLED(Z_SAFE_HOMING) && Z_HOME_DIR < 0

int pageShowInfo = 0;
void set_pageShowInfo(int value){ pageShowInfo = value; }

endif

int plaPreheatHotendTemp;
int plaPreheatHPBTemp;
int plaPreheatFanSpeed;

int absPreheatHotendTemp;
int absPreheatHPBTemp;
int absPreheatFanSpeed;

int gumPreheatHotendTemp;
int gumPreheatHPBTemp;
int gumPreheatFanSpeed;

if HAS(LCD_FILAMENT_SENSOR) || HAS(LCD_POWER_SENSOR)

millis_t previous_lcd_status_ms = 0;

endif

if HAS(LCD_POWER_SENSOR)

millis_t print_millis = 0;

endif

// Function pointer to menu functions.
typedef void (*menuFunc_t)();

uint8_t lcd_status_message_level;
char lcd_status_message[3 * LCD_WIDTH + 1] = WELCOME_MSG; // worst case is kana with up to 3*LCD_WIDTH+1

if ENABLED(DOGLCD)

#include "dogm_lcd_implementation.h"
#define LCD_Printpos(x, y) u8g.setPrintPos(x + 5, (y + 1) * (DOG_CHAR_HEIGHT + 2))

else

#include "ultralcd_implementation_hitachi_HD44780.h"
#define LCD_Printpos(x, y) lcd.setCursor(x, y)

endif

// The main status screen
static void lcd_status_screen();

if ENABLED(ULTIPANEL)

#if HAS(POWER_SWITCH)
extern bool powersupply;
#endif
static float manual_feedrate[] = MANUAL_FEEDRATE;
static void lcd_main_menu();
static void lcd_tune_menu();
static void lcd_prepare_menu();
static void lcd_prepare_motion_menu();
static void lcd_prepare_temperature_menu();
static void lcd_move_menu();
static void lcd_control_menu();
static void lcd_stats_menu();
static void lcd_control_temperature_menu();
static void lcd_control_temperature_preheat_pla_settings_menu();
static void lcd_control_temperature_preheat_abs_settings_menu();
static void lcd_control_temperature_preheat_gum_settings_menu();
static void lcd_control_motion_menu();
static void lcd_control_volumetric_menu();
#if HAS(LCD_CONTRAST)
static void lcd_set_contrast();
#endif
#if ENABLED(FWRETRACT)
static void lcd_control_retract_menu();
#endif

#if MECH(DELTA)
static void lcd_delta_calibrate_menu();
#elif !MECH(DELTA) && DISABLED(Z_SAFE_HOMING) && Z_HOME_DIR < 0
static void lcd_level_bed();
static void config_lcd_level_bed();
#endif // DELTA

/* Different types of actions that can be used in menu items. /
static void menu_action_back(menuFunc_t data);
static void menu_action_submenu(menuFunc_t data);
static void menu_action_gcode(const char
pgcode);
static void menu_action_function(menuFunc_t data);
static void menu_action_setting_edit_bool(const char* pstr, bool* ptr);
static void menu_action_setting_edit_int3(const char* pstr, int* ptr, int minValue, int maxValue);
static void menu_action_setting_edit_float3(const char* pstr, float* ptr, float minValue, float maxValue);
static void menu_action_setting_edit_float32(const char* pstr, float* ptr, float minValue, float maxValue);
static void menu_action_setting_edit_float43(const char* pstr, float* ptr, float minValue, float maxValue);
static void menu_action_setting_edit_float5(const char* pstr, float* ptr, float minValue, float maxValue);
static void menu_action_setting_edit_float51(const char* pstr, float* ptr, float minValue, float maxValue);
static void menu_action_setting_edit_float52(const char* pstr, float* ptr, float minValue, float maxValue);
static void menu_action_setting_edit_long5(const char* pstr, unsigned long* ptr, unsigned long minValue, unsigned long maxValue);
static void menu_action_setting_edit_callback_bool(const char* pstr, bool* ptr, menuFunc_t callbackFunc);
static void menu_action_setting_edit_callback_int3(const char* pstr, int* ptr, int minValue, int maxValue, menuFunc_t callbackFunc);
static void menu_action_setting_edit_callback_float3(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
static void menu_action_setting_edit_callback_float32(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
static void menu_action_setting_edit_callback_float43(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
static void menu_action_setting_edit_callback_float5(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
static void menu_action_setting_edit_callback_float51(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
static void menu_action_setting_edit_callback_float52(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
static void menu_action_setting_edit_callback_long5(const char* pstr, unsigned long* ptr, unsigned long minValue, unsigned long maxValue, menuFunc_t callbackFunc);

#if ENABLED(SDSUPPORT)
static void lcd_sdcard_menu();
static void menu_action_sdfile(const char* filename, char* longFilename);
static void menu_action_sddirectory(const char* filename, char* longFilename);
#endif

#define ENCODER_FEEDRATE_DEADZONE 10

#if DISABLED(LCD_I2C_VIKI)
#if DISABLED(ENCODER_STEPS_PER_MENU_ITEM)
#define ENCODER_STEPS_PER_MENU_ITEM 5
#endif
#if DISABLED(ENCODER_PULSES_PER_STEP)
#define ENCODER_PULSES_PER_STEP 1
#endif
#else
#if DISABLED(ENCODER_STEPS_PER_MENU_ITEM)
#define ENCODER_STEPS_PER_MENU_ITEM 2 // VIKI LCD rotary encoder uses a different number of steps per rotation
#endif
#if DISABLED(ENCODER_PULSES_PER_STEP)
#define ENCODER_PULSES_PER_STEP 1
#endif
#endif

/* Helper macros for menus */

/**

  • START_MENU generates the init code for a menu function
    */

    if ENABLED(BTN_BACK) && BTN_BACK > 0

    define START_MENU(last_menu) do { \

    encoderRateMultiplierEnabled = false;
    if (encoderPosition > 0x8000) encoderPosition = 0;
    uint8_t encoderLine = encoderPosition / ENCODER_STEPS_PER_MENU_ITEM;
    if (encoderLine < currentMenuViewOffset) currentMenuViewOffset = encoderLine;
    uint8_t _lineNr = currentMenuViewOffset, _menuItemNr;
    bool wasClicked = LCD_CLICKED, itemSelected;
    bool wasBackClicked = LCD_BACK_CLICKED;
    if (wasBackClicked) {
    lcd_quick_feedback();
    menu_action_back( last_menu );
    return; }
    for (uint8_t _drawLineNr = 0; _drawLineNr < LCD_HEIGHT; _drawLineNr++, _lineNr++) {
    _menuItemNr = 0;

    else

    define START_MENU(last_menu) do { \

    encoderRateMultiplierEnabled = false;
    if (encoderPosition > 0x8000) encoderPosition = 0;
    uint8_t encoderLine = encoderPosition / ENCODER_STEPS_PER_MENU_ITEM;
    if (encoderLine < currentMenuViewOffset) currentMenuViewOffset = encoderLine;
    uint8_t _lineNr = currentMenuViewOffset, _menuItemNr;
    bool wasClicked = LCD_CLICKED, itemSelected;
    for (uint8_t _drawLineNr = 0; _drawLineNr < LCD_HEIGHT; _drawLineNr++, _lineNr++) {
    _menuItemNr = 0;

    endif

    /**

  • MENU_ITEM generates draw & handler code for a menu item, potentially calling:
    *

  • lcd_implementation_drawmenu_[type](sel, row, label, arg3...)

  • menu_action_type

  • Examples:

  • MENU_ITEM(back, MSG_WATCH, lcd_status_screen)

  • lcd_implementation_drawmenu_back(sel, row, PSTR(MSG_WATCH), lcd_status_screen)
    
  • menu_action_back(lcd_status_screen)
    
  • MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause)

  • lcd_implementation_drawmenu_function(sel, row, PSTR(MSG_PAUSE_PRINT), lcd_sdcard_pause)
    
  • menu_action_function(lcd_sdcard_pause)
    
  • MENU_ITEM_EDIT(int3, MSG_SPEED, &feedrate_multiplier, 10, 999)

  • MENU_ITEM(setting_edit_int3, MSG_SPEED, PSTR(MSG_SPEED), &feedrate_multiplier, 10, 999)

  • lcd_implementation_drawmenu_setting_edit_int3(sel, row, PSTR(MSG_SPEED), PSTR(MSG_SPEED), &feedrate_multiplier, 10, 999)
    
  • menu_action_setting_edit_int3(PSTR(MSG_SPEED), &feedrate_multiplier, 10, 999)
    

    */

    define MENU_ITEM(type, label, args...) do { \

    if (_menuItemNr == _lineNr) {
    itemSelected = encoderLine == menuItemNr;
    if (lcdDrawUpdate)
    lcd_implementation_drawmenu
    ## type(itemSelected, drawLineNr, PSTR(label), ## args);
    if (wasClicked && itemSelected) {
    lcd_quick_feedback();
    menu_action
    ## type(args);
    return;
    }
    }
    _menuItemNr++;
    } while(0)

    if ENABLED(ENCODER_RATE_MULTIPLIER)

    //#define ENCODER_RATE_MULTIPLIER_DEBUG // If defined, output the encoder steps per second value

    /**

    • MENU_MULTIPLIER_ITEM generates drawing and handling code for a multiplier menu item
      */
      #define MENU_MULTIPLIER_ITEM(type, label, args...) do {
      if (_menuItemNr == _lineNr) {
      itemSelected = encoderLine == menuItemNr;
      if (lcdDrawUpdate)
      lcd_implementation_drawmenu
      ## type(itemSelected, drawLineNr, PSTR(label), ## args);
      if (wasClicked && itemSelected) {
      lcd_quick_feedback();
      encoderRateMultiplierEnabled = true;
      lastEncoderMovementMillis = 0;
      menu_action
      ## type(args);
      return;
      }
      }
      _menuItemNr++;
      } while(0)
      #endif //ENCODER_RATE_MULTIPLIER

    define MENU_ITEM_DUMMY() do { _menuItemNr++; } while(0)

    define MENU_ITEM_EDIT(type, label, args...) MENU_ITEM(setting_edit_ ## type, label, PSTR(label), ## args)

    define MENU_ITEM_EDIT_CALLBACK(type, label, args...) MENU_ITEM(setting_edit_callback_ ## type, label, PSTR(label), ## args)

    if ENABLED(ENCODER_RATE_MULTIPLIER)

    #define MENU_MULTIPLIER_ITEM_EDIT(type, label, args...) MENU_MULTIPLIER_ITEM(setting_edit_ ## type, label, PSTR(label), ## args)
    #define MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(type, label, args...) MENU_MULTIPLIER_ITEM(setting_edit_callback_ ## type, label, PSTR(label), ## args)

    else //!ENCODER_RATE_MULTIPLIER

    #define MENU_MULTIPLIER_ITEM_EDIT(type, label, args...) MENU_ITEM(setting_edit_ ## type, label, PSTR(label), ## args)
    #define MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(type, label, args...) MENU_ITEM(setting_edit_callback_ ## type, label, PSTR(label), ## args)

    endif //!ENCODER_RATE_MULTIPLIER

    define END_MENU() \

    if (encoderLine >= _menuItemNr) { encoderPosition = _menuItemNr * ENCODER_STEPS_PER_MENU_ITEM - 1; encoderLine = encoderPosition / ENCODER_STEPS_PER_MENU_ITEM; }
    if (encoderLine >= currentMenuViewOffset + LCD_HEIGHT) { currentMenuViewOffset = encoderLine - LCD_HEIGHT + 1; lcdDrawUpdate = 1; _lineNr = currentMenuViewOffset - 1; _drawLineNr = -1; }
    } } while(0)

    /** Used variables to keep track of the menu */
    volatile uint8_t buttons; //the last checked buttons in a bit array.

    if ENABLED(REPRAPWORLD_KEYPAD)

    volatile uint8_t buttons_reprapworld_keypad; // to store the keypad shift register values

    endif

    if ENABLED(LCD_HAS_SLOW_BUTTONS)

    volatile uint8_t slow_buttons; // Bits of the pressed buttons.

    endif

    uint8_t currentMenuViewOffset; /* scroll offset in the current menu */
    millis_t next_button_update_ms;
    uint8_t lastEncoderBits;
    uint32_t encoderPosition;

    if PIN_EXISTS(SD_DETECT)

    uint8_t lcd_sd_status;

    endif

endif // ULTIPANEL

menuFunc_t currentMenu = lcd_status_screen; /* function pointer to the currently active menu /
millis_t next_lcd_update_ms;
uint8_t lcd_status_update_delay;
bool ignore_click = false;
bool wait_for_unclick;
uint8_t lcdDrawUpdate = 2; /
Set to none-zero when the LCD needs to draw, decreased after every draw. Set to 2 in LCD routines so the LCD gets at least 1 full redraw (first redraw is partial) */

//prevMenu and prevEncoderPosition are used to store the previous menu location when editing settings.
menuFunc_t prevMenu = NULL;
uint16_t prevEncoderPosition;
//Variables used when editing values.
const char* editLabel;
void* editValue;
int32_t minEditValue, maxEditValue;
menuFunc_t callbackFunc;

// place-holders for Ki and Kd edits
float raw_Ki, raw_Kd;

/**

  • General function to go directly to a menu
    */
    static void lcd_goto_menu(menuFunc_t menu, const bool feedback = false, const uint32_t encoder = 0) {
    if (currentMenu != menu) {
    currentMenu = menu;
    #if ENABLED(NEWPANEL)
    encoderPosition = encoder;
    if (feedback) lcd_quick_feedback();
    #endif
    // For LCD_PROGRESS_BAR re-initialize the custom characters
    #if ENABLED(LCD_PROGRESS_BAR)
    lcd_set_custom_characters(menu == lcd_status_screen);
    #endif
    }
    }

/**
*

  • "Info Screen"
    *
  • This is very display-dependent, so the lcd implementation draws this.
    */

static void lcd_status_screen() {
encoderRateMultiplierEnabled = false;

#if ENABLED(LCD_PROGRESS_BAR)
millis_t ms = millis();
#if DISABLED(PROGRESS_MSG_ONCE)
if (ms > progress_bar_ms + PROGRESS_BAR_MSG_TIME + PROGRESS_BAR_BAR_TIME) {
progress_bar_ms = ms;
}
#endif
#if PROGRESS_MSG_EXPIRE > 0
// Handle message expire
if (expire_status_ms > 0) {
#if ENABLED(SDSUPPORT)
if (card.isFileOpen()) {
// Expire the message when printing is active
if (IS_SD_PRINTING) {
if (ms >= expire_status_ms) {
lcd_status_message[0] = '\0';
expire_status_ms = 0;
}
}
else {
expire_status_ms += LCD_UPDATE_INTERVAL;
}
}
else {
expire_status_ms = 0;
}
#else
expire_status_ms = 0;
#endif // SDSUPPORT
}
#endif
#endif //LCD_PROGRESS_BAR

lcd_implementation_status_screen();

#if HAS(LCD_POWER_SENSOR)
if (millis() > print_millis + 2000) print_millis = millis();
#endif

#if HAS(LCD_FILAMENT_SENSOR) || HAS(LCD_POWER_SENSOR)
#if HAS(LCD_FILAMENT_SENSOR) && HAS(LCD_POWER_SENSOR)
if (millis() > previous_lcd_status_ms + 15000)
#else
if (millis() > previous_lcd_status_ms + 10000)
#endif
{
previous_lcd_status_ms = millis();
}
#endif

#if ENABLED(ULTIPANEL)

bool current_click = LCD_CLICKED;

if (ignore_click) {
  if (wait_for_unclick) {
    if (!current_click)
      ignore_click = wait_for_unclick = false;
    else
      current_click = false;
  }
  else if (current_click) {
    lcd_quick_feedback();
    wait_for_unclick = true;
    current_click = false;
  }
}

if (current_click) {
  lcd_goto_menu(lcd_main_menu, true);
  lcd_implementation_init( // to maybe revive the LCD if static electricity killed it.
    #if ENABLED(LCD_PROGRESS_BAR)
      currentMenu == lcd_status_screen
    #endif
  );
  #if HAS(LCD_FILAMENT_SENSOR) || HAS(LCD_POWER_SENSOR)
    previous_lcd_status_ms = millis();  // get status message to show up for a while
  #endif
}

#if ENABLED(ULTIPANEL_FEEDMULTIPLY)
  // Dead zone at 100% feedrate
  if ((feedrate_multiplier < 100 && (feedrate_multiplier + int(encoderPosition)) > 100) ||
      (feedrate_multiplier > 100 && (feedrate_multiplier + int(encoderPosition)) < 100)) {
    encoderPosition = 0;
    feedrate_multiplier = 100;
  }
  if (feedrate_multiplier == 100) {
    if (int(encoderPosition) > ENCODER_FEEDRATE_DEADZONE) {
      feedrate_multiplier += int(encoderPosition) - ENCODER_FEEDRATE_DEADZONE;
      encoderPosition = 0;
    }
    else if (int(encoderPosition) < -ENCODER_FEEDRATE_DEADZONE) {
      feedrate_multiplier += int(encoderPosition) + ENCODER_FEEDRATE_DEADZONE;
      encoderPosition = 0;
    }
  }
  else {
    feedrate_multiplier += int(encoderPosition);
    encoderPosition = 0;
  }
#endif // ULTIPANEL_FEEDMULTIPLY

feedrate_multiplier = constrain(feedrate_multiplier, 10, 999);

#endif // ULTIPANEL
}

if ENABLED(ULTIPANEL)

static void lcd_return_to_status() { lcd_goto_menu(lcd_status_screen); }

if ENABLED(SDSUPPORT)

static void lcd_sdcard_pause() { card.pauseSDPrint(); }

static void lcd_sdcard_resume() { card.startFileprint(); }

static void lcd_sdcard_stop() {
quickStop();
card.sdprinting = false;
card.closeFile();
autotempShutdown();
cancel_heatup = true;
lcd_setstatus(MSG_PRINT_ABORTED, true);
}

endif // SDSUPPORT

/**
*

  • "Main" menu
    *
    */

static void lcd_main_menu() {
START_MENU(lcd_status_screen);
MENU_ITEM(back, MSG_WATCH, lcd_status_screen);
if (movesplanned() || IS_SD_PRINTING)
MENU_ITEM(submenu, MSG_TUNE, lcd_tune_menu);
else {
MENU_ITEM(submenu, MSG_PREPARE, lcd_prepare_menu);
#if MECH(DELTA)
MENU_ITEM(submenu, MSG_DELTA_CALIBRATE, lcd_delta_calibrate_menu);
#endif // DELTA
}
MENU_ITEM(submenu, MSG_CONTROL, lcd_control_menu);
MENU_ITEM(submenu, MSG_STATS, lcd_stats_menu);
#if ENABLED(SDSUPPORT)
if (card.cardOK) {
if (card.isFileOpen()) {
if (card.sdprinting)
MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause);
else
MENU_ITEM(function, MSG_RESUME_PRINT, lcd_sdcard_resume);
MENU_ITEM(function, MSG_STOP_PRINT, lcd_sdcard_stop);
}
else {
MENU_ITEM(submenu, MSG_CARD_MENU, lcd_sdcard_menu);
#if !PIN_EXISTS(SD_DETECT)
MENU_ITEM(gcode, MSG_CNG_SDCARD, PSTR("M21")); // SD-card changed by user
#endif
}
}
else {
MENU_ITEM(submenu, MSG_NO_CARD, lcd_sdcard_menu);
#if !PIN_EXISTS(SD_DETECT)
MENU_ITEM(gcode, MSG_INIT_SDCARD, PSTR("M21")); // Manually initialize the SD-card via user interface
#endif
}
#endif // SDSUPPORT

END_MENU();
}

if ENABLED(SDSUPPORT) && ENABLED(MENU_ADDAUTOSTART)

static void lcd_autostart_sd() {
card.autostart_index = 0;
card.setroot();
card.checkautostart(true);
}

endif

/**

  • Set the home offset based on the current_position
    */
    void lcd_set_home_offsets() {
    // M428 Command
    enqueuecommands_P(PSTR("M428"));
    lcd_return_to_status();
    }

if ENABLED(BABYSTEPPING)

static void _lcd_babystep(menuFunc_t menu, int axis, const char* msg) {
if (encoderPosition != 0) {
babystepsTodo[axis] += (int)encoderPosition;
encoderPosition = 0;
lcdDrawUpdate = 1;
}
if (lcdDrawUpdate) lcd_implementation_drawedit(msg, "");
if (LCD_CLICKED) lcd_goto_menu(menu);
}
static void lcd_prepare_motion_babystep();
static void lcd_tune_babystep_x() { _lcd_babystep(lcd_tune_menu, X_AXIS, PSTR(MSG_BABYSTEPPING_X)); }
static void lcd_tune_babystep_y() { _lcd_babystep(lcd_tune_menu, Y_AXIS, PSTR(MSG_BABYSTEPPING_Y)); }
static void lcd_tune_babystep_z() { _lcd_babystep(lcd_tune_menu, Z_AXIS, PSTR(MSG_BABYSTEPPING_Z)); }
static void lcd_prepare_babystep_x() { _lcd_babystep(lcd_prepare_motion_babystep, X_AXIS, PSTR(MSG_BABYSTEPPING_X)); }
static void lcd_prepare_babystep_y() { _lcd_babystep(lcd_prepare_motion_babystep, Y_AXIS, PSTR(MSG_BABYSTEPPING_Y)); }
static void lcd_prepare_babystep_z() { _lcd_babystep(lcd_prepare_motion_babystep, Z_AXIS, PSTR(MSG_BABYSTEPPING_Z)); }

static void lcd_prepare_motion_babystep() {
START_MENU(lcd_main_menu);
MENU_ITEM(back, MSG_MOTION, lcd_prepare_motion_menu);
#if ENABLED(BABYSTEP_XY)
MENU_ITEM(submenu, MSG_BABYSTEP_X, lcd_prepare_babystep_x);
MENU_ITEM(submenu, MSG_BABYSTEP_Y, lcd_prepare_babystep_y);
#endif //BABYSTEP_XY
MENU_ITEM(submenu, MSG_BABYSTEP_Z, lcd_prepare_babystep_z);
END_MENU();
}

endif // BABYSTEPPING

static void lcd_tune_fixstep() {
#if MECH(DELTA)
enqueuecommands_P(PSTR("G28 B"));
#else
enqueuecommands_P(PSTR("G28 X Y B"));
#endif
}

/**
*

  • "Tune" submenu
    *
    */

static void lcd_tune_menu() {
START_MENU(lcd_main_menu);
MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
MENU_ITEM_EDIT(int3, MSG_SPEED, &feedrate_multiplier, 10, 999);
#if TEMP_SENSOR_0 != 0
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_NOZZLE " 0", &target_temperature[0], 0, HEATER_0_MAXTEMP);
#endif
#if TEMP_SENSOR_1 != 0
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_NOZZLE " 1", &target_temperature[1], 0, HEATER_1_MAXTEMP);
#endif
#if TEMP_SENSOR_2 != 0
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_NOZZLE " 2", &target_temperature[2], 0, HEATER_2_MAXTEMP);
#endif
#if TEMP_SENSOR_3 != 0
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_NOZZLE " 3", &target_temperature[3], 0, HEATER_3_MAXTEMP);
#endif
#if TEMP_SENSOR_BED != 0
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_BED, &target_temperature_bed, 0, BED_MAXTEMP);
#endif
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_FAN_SPEED, &fanSpeed, 0, 255);
MENU_ITEM_EDIT(int3, MSG_FLOW " 0", &extruder_multiplier[0], 10, 999);
#if TEMP_SENSOR_1 != 0
MENU_ITEM_EDIT(int3, MSG_FLOW " 1", &extruder_multiplier[1], 10, 999);
#endif
#if TEMP_SENSOR_2 != 0
MENU_ITEM_EDIT(int3, MSG_FLOW " 2", &extruder_multiplier[2], 10, 999);
#endif
#if TEMP_SENSOR_3 != 0
MENU_ITEM_EDIT(int3, MSG_FLOW " 3", &extruder_multiplier[3], 10, 999);
#endif

#if ENABLED(BABYSTEPPING)
#if ENABLED(BABYSTEP_XY)
MENU_ITEM(submenu, MSG_BABYSTEP_X, lcd_tune_babystep_x);
MENU_ITEM(submenu, MSG_BABYSTEP_Y, lcd_tune_babystep_y);
#endif //BABYSTEP_XY
MENU_ITEM(submenu, MSG_BABYSTEP_Z, lcd_tune_babystep_z);
#endif

MENU_ITEM(function, MSG_FIX_LOSE_STEPS, lcd_tune_fixstep);

#if ENABLED(FILAMENTCHANGEENABLE)
MENU_ITEM(gcode, MSG_FILAMENTCHANGE, PSTR("M600"));
#endif
END_MENU();
}

if ENABLED(EASY_LOAD)

static void lcd_extrude(float length, float feedrate) {
current_position[E_AXIS] += length;
#if MECH(DELTA)
calculate_delta(current_position);
plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], feedrate, active_extruder, active_driver);
#else
plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate, active_extruder, active_driver);
#endif
}
static void lcd_purge() {lcd_extrude(LCD_PURGE_LENGTH, LCD_PURGE_FEEDRATE);}
static void lcd_retract() {lcd_extrude(-LCD_RETRACT_LENGTH, LCD_RETRACT_FEEDRATE);}
static void lcd_easy_load() {
allow_lengthy_extrude_once = true;
lcd_extrude(BOWDEN_LENGTH, LCD_LOAD_FEEDRATE);
lcd_return_to_status();
}
static void lcd_easy_unload() {
allow_lengthy_extrude_once = true;
lcd_extrude(-BOWDEN_LENGTH, LCD_UNLOAD_FEEDRATE);
lcd_return_to_status();
}

endif //EASY_LOAD

void _lcd_preheat(int endnum, const float temph, const float tempb, const int fan) {
if (temph > 0) setTargetHotend(temph, endnum);
#if TEMP_SENSOR_BED != 0
setTargetBed(tempb);
#endif
fanSpeed = fan;
lcd_return_to_status();
}
void lcd_preheat_pla0() { _lcd_preheat(0, plaPreheatHotendTemp, plaPreheatHPBTemp, plaPreheatFanSpeed); }
void lcd_preheat_abs0() { _lcd_preheat(0, absPreheatHotendTemp, absPreheatHPBTemp, absPreheatFanSpeed); }
void lcd_preheat_gum0() { _lcd_preheat(0, gumPreheatHotendTemp, gumPreheatHPBTemp, gumPreheatFanSpeed); }

if HOTENDS > 1

void lcd_preheat_pla1() { _lcd_preheat(1, plaPreheatHotendTemp, plaPreheatHPBTemp, plaPreheatFanSpeed); }
void lcd_preheat_abs1() { _lcd_preheat(1, absPreheatHotendTemp, absPreheatHPBTemp, absPreheatFanSpeed); }
void lcd_preheat_gum1() { _lcd_preheat(1, gumPreheatHotendTemp, gumPreheatHPBTemp, gumPreheatFanSpeed); }
#if HOTENDS > 2
void lcd_preheat_pla2() { _lcd_preheat(2, plaPreheatHotendTemp, plaPreheatHPBTemp, plaPreheatFanSpeed); }
void lcd_preheat_abs2() { _lcd_preheat(2, absPreheatHotendTemp, absPreheatHPBTemp, absPreheatFanSpeed); }
void lcd_preheat_gum2() { _lcd_preheat(2, gumPreheatHotendTemp, gumPreheatHPBTemp, gumPreheatFanSpeed); }
#if HOTENDS > 3
void lcd_preheat_pla3() { _lcd_preheat(3, plaPreheatHotendTemp, plaPreheatHPBTemp, plaPreheatFanSpeed); }
void lcd_preheat_abs3() { _lcd_preheat(3, absPreheatHotendTemp, absPreheatHPBTemp, absPreheatFanSpeed); }
void lcd_preheat_gum3() { _lcd_preheat(3, gumPreheatHotendTemp, gumPreheatHPBTemp, gumPreheatFanSpeed); }
#endif
#endif

void lcd_preheat_pla0123() {
setTargetHotend0(plaPreheatHotendTemp);
setTargetHotend1(plaPreheatHotendTemp);
setTargetHotend2(plaPreheatHotendTemp);
_lcd_preheat(3, plaPreheatHotendTemp, plaPreheatHPBTemp, plaPreheatFanSpeed);
}
void lcd_preheat_abs0123() {
setTargetHotend0(absPreheatHotendTemp);
setTargetHotend1(absPreheatHotendTemp);
setTargetHotend2(absPreheatHotendTemp);
_lcd_preheat(3, absPreheatHotendTemp, absPreheatHPBTemp, absPreheatFanSpeed);
}
void lcd_preheat_gum0123() {
setTargetHotend0(gumPreheatHotendTemp);
setTargetHotend1(gumPreheatHotendTemp);
setTargetHotend2(gumPreheatHotendTemp);
_lcd_preheat(3, gumPreheatHotendTemp, gumPreheatHPBTemp, gumPreheatFanSpeed);
}

endif // HOTENDS > 1

if TEMP_SENSOR_BED != 0

void lcd_preheat_pla_bedonly() { _lcd_preheat(0, 0, plaPreheatHPBTemp, plaPreheatFanSpeed); }
void lcd_preheat_abs_bedonly() { _lcd_preheat(0, 0, absPreheatHPBTemp, absPreheatFanSpeed); }
void lcd_preheat_gum_bedonly() { _lcd_preheat(0, 0, gumPreheatHPBTemp, gumPreheatFanSpeed); }

endif

static void lcd_preheat_pla_menu() {
START_MENU(lcd_prepare_temperature_menu);
MENU_ITEM(back, MSG_TEMPERATURE, lcd_prepare_temperature_menu);
MENU_ITEM(function, MSG_PREHEAT_PLA " 0", lcd_preheat_pla0);
#if HOTENDS > 1
MENU_ITEM(function, MSG_PREHEAT_PLA " 1", lcd_preheat_pla1);
#if HOTENDS > 2
MENU_ITEM(function, MSG_PREHEAT_PLA " 2", lcd_preheat_pla2);
#if HOTENDS > 3
MENU_ITEM(function, MSG_PREHEAT_PLA " 3", lcd_preheat_pla3);
#endif
#endif
MENU_ITEM(function, MSG_PREHEAT_PLA_ALL, lcd_preheat_pla0123);
#endif
#if TEMP_SENSOR_BED != 0
MENU_ITEM(function, MSG_PREHEAT_PLA_BEDONLY, lcd_preheat_pla_bedonly);
#endif
END_MENU();
}

static void lcd_preheat_abs_menu() {
START_MENU(lcd_prepare_temperature_menu);
MENU_ITEM(back, MSG_TEMPERATURE, lcd_prepare_temperature_menu);
MENU_ITEM(function, MSG_PREHEAT_ABS " 0", lcd_preheat_abs0);
#if HOTENDS > 1
MENU_ITEM(function, MSG_PREHEAT_ABS " 1", lcd_preheat_abs1);
#if HOTENDS > 2
MENU_ITEM(function, MSG_PREHEAT_ABS " 2", lcd_preheat_abs2);
#if HOTENDS > 3
MENU_ITEM(function, MSG_PREHEAT_ABS " 3", lcd_preheat_abs3);
#endif
#endif
MENU_ITEM(function, MSG_PREHEAT_ABS_ALL, lcd_preheat_abs0123);
#endif
#if TEMP_SENSOR_BED != 0
MENU_ITEM(function, MSG_PREHEAT_ABS_BEDONLY, lcd_preheat_abs_bedonly);
#endif
END_MENU();
}

static void lcd_preheat_gum_menu() {
START_MENU(lcd_prepare_temperature_menu);
MENU_ITEM(back, MSG_TEMPERATURE, lcd_prepare_temperature_menu);
MENU_ITEM(function, MSG_PREHEAT_GUM " 0", lcd_preheat_gum0);
#if HOTENDS > 1
MENU_ITEM(function, MSG_PREHEAT_GUM " 1", lcd_preheat_gum1);
#if HOTENDS > 2
MENU_ITEM(function, MSG_PREHEAT_GUM " 2", lcd_preheat_gum2);
#if HOTENDS > 3
MENU_ITEM(function, MSG_PREHEAT_GUM " 3", lcd_preheat_gum3);
#endif
#endif
MENU_ITEM(function, MSG_PREHEAT_GUM_ALL, lcd_preheat_gum0123);
#endif
#if TEMP_SENSOR_BED != 0
MENU_ITEM(function, MSG_PREHEAT_GUM_BEDONLY, lcd_preheat_gum_bedonly);
#endif
END_MENU();
}

void lcd_cooldown() {
disable_all_heaters();
fanSpeed = 0;
lcd_return_to_status();
}

/**
*

  • "Prepare" submenu
    *
    */

static void lcd_prepare_menu() {
START_MENU(lcd_main_menu);

//
// ^ Main
//
MENU_ITEM(back, MSG_MAIN, lcd_main_menu);

MENU_ITEM(submenu, MSG_MOTION, lcd_prepare_motion_menu);
MENU_ITEM(submenu, MSG_TEMPERATURE, lcd_prepare_temperature_menu);
END_MENU();
}

/**
*

  • "Prepare > Motion" submenu
    *
    */

static void lcd_prepare_motion_menu() {
START_MENU(lcd_prepare_menu);
//
// ^ Prepare
//
MENU_ITEM(back, MSG_PREPARE, lcd_prepare_menu);

//
// Auto Home
//
MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28"));

//
// Level Bed
//
#if ENABLED(AUTO_BED_LEVELING_FEATURE)
if (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS])
MENU_ITEM(gcode, MSG_LEVEL_BED, PSTR("G29"));
#elif !MECH(DELTA) && DISABLED(Z_SAFE_HOMING) && Z_HOME_DIR < 0
MENU_ITEM(submenu, MSG_MBL_SETTING, config_lcd_level_bed);
#endif

//
// Set Home Offsets
//
MENU_ITEM(function, MSG_SET_HOME_OFFSETS, lcd_set_home_offsets);

//Add Preset menu for LASER setting '14. 7. 22
#if ENABLED(LASERBEAM)
MENU_ITEM_EDIT(int3, MSG_LASER, &laser_ttl_modulation, 0, 255);
if(laser_ttl_modulation == 0) {
WRITE(LASER_PWR_PIN, LOW);
}
else {
WRITE(LASER_PWR_PIN, HIGH);
}
#endif

//
// Move Axis
//
MENU_ITEM(submenu, MSG_MOVE_AXIS, lcd_move_menu);

//
// Easy Load
//
#if ENABLED(EASY_LOAD)
MENU_ITEM(function, MSG_E_BOWDEN_LENGTH, lcd_easy_load);
MENU_ITEM(function, MSG_R_BOWDEN_LENGTH, lcd_easy_unload);
MENU_ITEM(function, MSG_PURGE_XMM, lcd_purge);
MENU_ITEM(function, MSG_RETRACT_XMM, lcd_retract);
#endif // EASY_LOAD

//
// Babystepping
//
#if ENABLED(BABYSTEPPING)
MENU_ITEM(submenu, MSG_BABYSTEP, lcd_prepare_motion_babystep);
#endif

MENU_ITEM(function, MSG_FIX_LOSE_STEPS, lcd_tune_fixstep);

//
// Disable Steppers
//
MENU_ITEM(gcode, MSG_DISABLE_STEPPERS, PSTR("M84"));

END_MENU();
}

/**
*

  • "Prepare > Temperature" submenu
    *
    */

static void lcd_prepare_temperature_menu() {
START_MENU(lcd_prepare_menu);
//
// ^ Prepare
//
MENU_ITEM(back, MSG_PREPARE, lcd_prepare_menu);
//
// Nozzle, Nozzle 2, Nozzle 3, Nozzle 4
//
#if TEMP_SENSOR_0 != 0
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_NOZZLE " 0", &target_temperature[0], 0, HEATER_0_MAXTEMP);
#endif
#if HOTENDS > 1 && TEMP_SENSOR_1 != 0
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_NOZZLE " 1", &target_temperature[1], 0, HEATER_1_MAXTEMP);
#if HOTENDS > 2 && TEMP_SENSOR_2 != 0
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_NOZZLE " 2", &target_temperature[2], 0, HEATER_2_MAXTEMP);
#if HOTENDS > 3 && TEMP_SENSOR_3 != 0
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_NOZZLE " 3", &target_temperature[3], 0, HEATER_3_MAXTEMP);
#endif // HOTENDS > 3
#endif // HOTENDS > 2
#endif // HOTENDS > 1

//
// Bed
//
#if TEMP_SENSOR_BED != 0
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_BED, &target_temperature_bed, 0, BED_MAXTEMP);
#endif

//
// Fan Speed
//
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_FAN_SPEED, &fanSpeed, 0, 255);

//
// Preheat PLA
// Preheat ABS
// Preheat GUM
//
#if TEMP_SENSOR_0 != 0
#if TEMP_SENSOR_1 != 0 || TEMP_SENSOR_2 != 0 || TEMP_SENSOR_3 != 0 || TEMP_SENSOR_BED != 0
MENU_ITEM(submenu, MSG_PREHEAT_PLA, lcd_preheat_pla_menu);
MENU_ITEM(submenu, MSG_PREHEAT_ABS, lcd_preheat_abs_menu);
MENU_ITEM(submenu, MSG_PREHEAT_GUM, lcd_preheat_gum_menu);
#else
MENU_ITEM(function, MSG_PREHEAT_PLA, lcd_preheat_pla0);
MENU_ITEM(function, MSG_PREHEAT_ABS, lcd_preheat_abs0);
MENU_ITEM(function, MSG_PREHEAT_GUM, lcd_preheat_gum0);
#endif
#endif

//
// Cooldown
//
MENU_ITEM(function, MSG_COOLDOWN, lcd_cooldown);

END_MENU();
}

if MECH(DELTA)

static void lcd_delta_calibrate_menu() {
START_MENU(lcd_main_menu);
MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28"));
MENU_ITEM(gcode, MSG_DELTA_CALIBRATE_X, PSTR("G0 F8000 X-77.94 Y-45 Z0"));
MENU_ITEM(gcode, MSG_DELTA_CALIBRATE_Y, PSTR("G0 F8000 X77.94 Y-45 Z0"));
MENU_ITEM(gcode, MSG_DELTA_CALIBRATE_Z, PSTR("G0 F8000 X0 Y90 Z0"));
MENU_ITEM(gcode, MSG_DELTA_CALIBRATE_CENTER, PSTR("G0 F8000 X0 Y0 Z0"));
END_MENU();
}

endif // DELTA

inline void line_to_current(float feedrate) {
#if MECH(DELTA)
calculate_delta(current_position);
plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], feedrate/60, active_extruder, active_driver);
#else
plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate/60, active_extruder, active_driver);
#endif
}

/**
*

  • "Prepare" > "Move Axis" submenu
    *
    */

float move_menu_scale;
static void lcd_move_menu_axis();

static void _lcd_move(const char *name, AxisEnum axis, int min, int max) {
if (encoderPosition != 0) {
refresh_cmd_timeout();
current_position[axis] += float((int)encoderPosition) * move_menu_scale;
if (SOFTWARE_MIN_ENDSTOPS && current_position[axis] < min) current_position[axis] = min;
if (SOFTWARE_MAX_ENDSTOPS && current_position[axis] > max) current_position[axis] = max;
encoderPosition = 0;
line_to_current(manual_feedrate[axis]);
lcdDrawUpdate = 1;
}
if (lcdDrawUpdate) lcd_implementation_drawedit(name, ftostr31(current_position[axis]));
if (LCD_CLICKED) lcd_goto_menu(lcd_move_menu_axis);
}
static void lcd_move_x() { _lcd_move(PSTR(MSG_MOVE_X), X_AXIS, X_MIN_POS, X_MAX_POS); }
static void lcd_move_y() { _lcd_move(PSTR(MSG_MOVE_Y), Y_AXIS, Y_MIN_POS, Y_MAX_POS); }
static void lcd_move_z() { _lcd_move(PSTR(MSG_MOVE_Z), Z_AXIS, Z_MIN_POS, Z_MAX_POS); }
static void lcd_move_e() {
if (encoderPosition != 0) {
#if ENABLED(IDLE_OOZING_PREVENT)
IDLE_OOZING_retract(false);
#endif
current_position[E_AXIS] += float((int)encoderPosition) * move_menu_scale;
encoderPosition = 0;
line_to_current(manual_feedrate[E_AXIS]);
lcdDrawUpdate = 1;
}
if (lcdDrawUpdate) lcd_implementation_drawedit(PSTR(MSG_MOVE_E), ftostr31(current_position[E_AXIS]));
if (LCD_CLICKED) lcd_goto_menu(lcd_move_menu_axis);
}

/**
*

  • "Prepare" > "Move Xmm" > "Move XYZ" submenu
    *
    */
    inline void refresh_cmd_timeout() {
    }
    static void lcd_move_menu_axis() {
    START_MENU(lcd_move_menu);
    MENU_ITEM(back, MSG_MOVE_AXIS, lcd_move_menu);
    MENU_ITEM(submenu, MSG_MOVE_X, lcd_move_x);
    MENU_ITEM(submenu, MSG_MOVE_Y, lcd_move_y);
    MENU_ITEM(submenu, MSG_MOVE_Z, lcd_move_z);
    if (move_menu_scale < 10.0) {
    MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_e);
    }
    END_MENU();
    }

static void lcd_move_menu_10mm() {
move_menu_scale = 10.0;
lcd_move_menu_axis();
}
static void lcd_move_menu_1mm() {
move_menu_scale = 1.0;
lcd_move_menu_axis();
}
static void lcd_move_menu_01mm() {
move_menu_scale = 0.1;
lcd_move_menu_axis();
}

/**
*

  • "Prepare" > "Move Axis" submenu
    *
    */

static void lcd_move_menu() {
START_MENU(lcd_prepare_motion_menu);
MENU_ITEM(back, MSG_MOTION, lcd_prepare_motion_menu);
MENU_ITEM(submenu, MSG_MOVE_10MM, lcd_move_menu_10mm);
MENU_ITEM(submenu, MSG_MOVE_1MM, lcd_move_menu_1mm);
MENU_ITEM(submenu, MSG_MOVE_01MM, lcd_move_menu_01mm);
//TODO:X,Y,Z,E
END_MENU();
}

/**
*

  • "Control" submenu
    *
    */

static void lcd_control_menu() {
START_MENU(lcd_main_menu);
MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
MENU_ITEM(submenu, MSG_TEMPERATURE, lcd_control_temperature_menu);
MENU_ITEM(submenu, MSG_MOTION, lcd_control_motion_menu);
MENU_ITEM(submenu, MSG_FILAMENT, lcd_control_volumetric_menu);

#if HAS(LCD_CONTRAST)
//MENU_ITEM_EDIT(int3, MSG_CONTRAST, &lcd_contrast, 0, 63);
MENU_ITEM(submenu, MSG_CONTRAST, lcd_set_contrast);
#endif
#if ENABLED(FWRETRACT)
MENU_ITEM(submenu, MSG_RETRACT, lcd_control_retract_menu);
#endif

//
// Switch power on/off
//
#if HAS(POWER_SWITCH)
if (powersupply)
MENU_ITEM(gcode, MSG_SWITCH_PS_OFF, PSTR("M81"));
else
MENU_ITEM(gcode, MSG_SWITCH_PS_ON, PSTR("M80"));
#endif

//
// Autostart
//
#if ENABLED(SDSUPPORT) && ENABLED(MENU_ADDAUTOSTART)
MENU_ITEM(function, MSG_AUTOSTART, lcd_autostart_sd);
#endif

#if ENABLED(EEPROM_SETTINGS)
MENU_ITEM(function, MSG_STORE_EPROM, Config_StoreSettings);
MENU_ITEM(function, MSG_LOAD_EPROM, Config_RetrieveSettings);
#endif
MENU_ITEM(function, MSG_RESTORE_FAILSAFE, Config_ResetDefault);
END_MENU();
}

/**
*

  • "Statistics" submenu
    *
    */

static void lcd_stats_menu() {
char row[30];
int day = printer_usage_seconds / 60 / 60 / 24, hours = (printer_usage_seconds / 60 / 60) % 24, minutes = (printer_usage_seconds / 60) % 60;
sprintf_P(row, PSTR(MSG_ONFOR " %id %ih %im"), day, hours, minutes);
LCD_Printpos(0, 0); lcd_print(row);
#if HAS(POWER_CONSUMPTION_SENSOR)
sprintf_P(row, PSTR(MSG_PWRCONSUMED " %iWh"), power_consumption_hour);
LCD_Printpos(0, 1); lcd_print(row);
#endif
if (LCD_CLICKED) lcd_goto_menu(lcd_main_menu);
}

/**
*

  • "Temperature" submenu
    *
    */

if ENABLED(PIDTEMP)

// Helpers for editing PID Ki & Kd values
// grab the PID value out of the temp variable; scale it; then update the PID driver
void copy_and_scalePID_i(int e) {
PID_PARAM(Ki, e) = scalePID_i(raw_Ki);
updatePID();
}
void copy_and_scalePID_d(int e) {
PID_PARAM(Kd, e) = scalePID_d(raw_Kd);
updatePID();
}
void copy_and_scalePID_i_H0() { copy_and_scalePID_i(0); }
void copy_and_scalePID_d_H0() { copy_and_scalePID_d(0); }
#if HOTENDS > 1
void copy_and_scalePID_i_H1() { copy_and_scalePID_i(1); }
void copy_and_scalePID_d_H1() { copy_and_scalePID_d(1); }
#if HOTENDS > 2
void copy_and_scalePID_i_H2() { copy_and_scalePID_i(2); }
void copy_and_scalePID_d_H2() { copy_and_scalePID_d(2); }
#if HOTENDS > 3
void copy_and_scalePID_i_H3() { copy_and_scalePID_i(3); }
void copy_and_scalePID_d_H3() { copy_and_scalePID_d(3); }
#endif //HOTENDS > 3
#endif //HOTENDS > 2
#endif //HOTENDS > 1

endif //PIDTEMP

/**
*

  • "Control" > "Temperature" submenu
    *
    */
    static void lcd_control_temperature_menu() {
    START_MENU(lcd_control_menu);

    //
    // ^ Control
    //
    MENU_ITEM(back, MSG_CONTROL, lcd_control_menu);

    //
    // Autotemp, Min, Max, Fact
    //

    if ENABLED(AUTOTEMP) && (TEMP_SENSOR_0 != 0)

    MENU_ITEM_EDIT(bool, MSG_AUTOTEMP, &autotemp_enabled);
    MENU_ITEM_EDIT(float3, MSG_MIN, &autotemp_min, 0, HEATER_0_MAXTEMP);
    MENU_ITEM_EDIT(float3, MSG_MAX, &autotemp_max, 0, HEATER_0_MAXTEMP);
    MENU_ITEM_EDIT(float32, MSG_FACTOR, &autotemp_factor, 0.0, 1.0);

    endif

    //
    // PID-P, PID-I, PID-D
    //

    if ENABLED(PIDTEMP)

    // set up temp variables - undo the default scaling
    raw_Ki = unscalePID_i(PID_PARAM(Ki,0));
    raw_Kd = unscalePID_d(PID_PARAM(Kd,0));
    MENU_ITEM_EDIT(float52, MSG_PID_P, &PID_PARAM(Kp,0), 1, 9990);
    // i is typically a small value so allows values below 1
    MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_I, &raw_Ki, 0.01, 9990, copy_and_scalePID_i_H0);
    MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_D, &raw_Kd, 1, 9990, copy_and_scalePID_d_H0);
    #if HOTENDS > 1
    // set up temp variables - undo the default scaling
    raw_Ki = unscalePID_i(PID_PARAM(Ki,1));
    raw_Kd = unscalePID_d(PID_PARAM(Kd,1));
    MENU_ITEM_EDIT(float52, MSG_PID_P MSG_H1, &PID_PARAM(Kp,1), 1, 9990);
    // i is typically a small value so allows values below 1
    MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_I MSG_H1, &raw_Ki, 0.01, 9990, copy_and_scalePID_i_H1);
    MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_D MSG_H1, &raw_Kd, 1, 9990, copy_and_scalePID_d_H1);
    #if HOTENDS > 2
    // set up temp variables - undo the default scaling
    raw_Ki = unscalePID_i(PID_PARAM(Ki,2));
    raw_Kd = unscalePID_d(PID_PARAM(Kd,2));
    MENU_ITEM_EDIT(float52, MSG_PID_P MSG_H2, &PID_PARAM(Kp,2), 1, 9990);
    // i is typically a small value so allows values below 1
    MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_I MSG_H2, &raw_Ki, 0.01, 9990, copy_and_scalePID_i_H2);
    MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_D MSG_H2, &raw_Kd, 1, 9990, copy_and_scalePID_d_H2);
    #if HOTENDS > 3
    // set up temp variables - undo the default scaling
    raw_Ki = unscalePID_i(PID_PARAM(Ki,3));
    raw_Kd = unscalePID_d(PID_PARAM(Kd,3));
    MENU_ITEM_EDIT(float52, MSG_PID_P MSG_H3, &PID_PARAM(Kp,3), 1, 9990);
    // i is typically a small value so allows values below 1
    MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_I MSG_H3, &raw_Ki, 0.01, 9990, copy_and_scalePID_i_H3);
    MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_D MSG_H3, &raw_Kd, 1, 9990, copy_and_scalePID_d_H3);
    #endif // HOTENDS > 3
    #endif // HOTENDS > 2
    #endif // HOTENDS > 1

    endif // PIDTEMP

    //
    // Idle oozing
    //

    if ENABLED(IDLE_OOZING_PREVENT)

    MENU_ITEM_EDIT(bool, MSG_IDLEOOZING, &IDLE_OOZING_enabled);

    endif

    //
    // Preheat PLA conf
    //
    MENU_ITEM(submenu, MSG_PREHEAT_PLA_SETTINGS, lcd_control_temperature_preheat_pla_settings_menu);

    //
    // Preheat ABS conf
    //
    MENU_ITEM(submenu, MSG_PREHEAT_ABS_SETTINGS, lcd_control_temperature_preheat_abs_settings_menu);

    //
    // Preheat GUM conf
    //
    MENU_ITEM(submenu, MSG_PREHEAT_GUM_SETTINGS, lcd_control_temperature_preheat_gum_settings_menu);
    END_MENU();
    }

/**
*

  • "Temperature" > "Preheat PLA conf" submenu
    *
    */
    static void lcd_control_temperature_preheat_pla_settings_menu() {
    START_MENU(lcd_control_temperature_menu);
    MENU_ITEM(back, MSG_TEMPERATURE, lcd_control_temperature_menu);
    MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &plaPreheatFanSpeed, 0, 255);
    #if TEMP_SENSOR_0 != 0
    MENU_ITEM_EDIT(int3, MSG_NOZZLE, &plaPreheatHotendTemp, HEATER_0_MINTEMP, HEATER_0_MAXTEMP);
    #endif
    #if TEMP_SENSOR_BED != 0
    MENU_ITEM_EDIT(int3, MSG_BED, &plaPreheatHPBTemp, BED_MINTEMP, BED_MAXTEMP);
    #endif
    #if ENABLED(EEPROM_SETTINGS)
    MENU_ITEM(function, MSG_STORE_EPROM, Config_StoreSettings);
    #endif
    END_MENU();
    }

/**
*

  • "Temperature" > "Preheat ABS conf" submenu
    *
    */
    static void lcd_control_temperature_preheat_abs_settings_menu() {
    START_MENU(lcd_control_temperature_menu);
    MENU_ITEM(back, MSG_TEMPERATURE, lcd_control_temperature_menu);
    MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &absPreheatFanSpeed, 0, 255);
    #if TEMP_SENSOR_0 != 0
    MENU_ITEM_EDIT(int3, MSG_NOZZLE, &absPreheatHotendTemp, HEATER_0_MINTEMP, HEATER_0_MAXTEMP);
    #endif
    #if TEMP_SENSOR_BED != 0
    MENU_ITEM_EDIT(int3, MSG_BED, &absPreheatHPBTemp, BED_MINTEMP, BED_MAXTEMP);
    #endif
    #if ENABLED(EEPROM_SETTINGS)
    MENU_ITEM(function, MSG_STORE_EPROM, Config_StoreSettings);
    #endif
    END_MENU();
    }

/**
*

  • "Temperature" > "Preheat GUM conf" submenu
    *
    */
    static void lcd_control_temperature_preheat_gum_settings_menu() {
    START_MENU(lcd_control_temperature_menu);
    MENU_ITEM(back, MSG_TEMPERATURE, lcd_control_temperature_menu);
    MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &gumPreheatFanSpeed, 0, 255);
    #if TEMP_SENSOR_0 != 0
    MENU_ITEM_EDIT(int3, MSG_NOZZLE, &gumPreheatHotendTemp, HEATER_0_MINTEMP, HEATER_0_MAXTEMP);
    #endif
    #if TEMP_SENSOR_BED != 0
    MENU_ITEM_EDIT(int3, MSG_BED, &gumPreheatHPBTemp, BED_MINTEMP, BED_MAXTEMP);
    #endif
    #if ENABLED(EEPROM_SETTINGS)
    MENU_ITEM(function, MSG_STORE_EPROM, Config_StoreSettings);
    #endif
    END_MENU();
    }

/**
*

  • "Control" > "Motion" submenu
    *
    */
    static void lcd_control_motion_menu() {
    START_MENU(lcd_control_menu);
    MENU_ITEM(back, MSG_CONTROL, lcd_control_menu);

    if ENABLED(AUTO_BED_LEVELING_FEATURE)

    MENU_ITEM_EDIT(float32, MSG_ZPROBE_ZOFFSET, &zprobe_zoffset, -50, 50);

    endif

    MENU_ITEM_EDIT(float5, MSG_ACC, &acceleration, 10, 99000);
    MENU_ITEM_EDIT(float3, MSG_VXY_JERK, &max_xy_jerk, 1, 990);
    MENU_ITEM_EDIT(float52, MSG_VZ_JERK, &max_z_jerk, 0.1, 990);
    MENU_ITEM_EDIT(float3, MSG_VMAX MSG_X, &max_feedrate[X_AXIS], 1, 999);
    MENU_ITEM_EDIT(float3, MSG_VMAX MSG_Y, &max_feedrate[Y_AXIS], 1, 999);
    MENU_ITEM_EDIT(float3, MSG_VMAX MSG_Z, &max_feedrate[Z_AXIS], 1, 999);
    MENU_ITEM_EDIT(float3, MSG_VMIN, &minimumfeedrate, 0, 999);
    MENU_ITEM_EDIT(float3, MSG_VTRAV_MIN, &mintravelfeedrate, 0, 999);
    MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_X, &max_acceleration_units_per_sq_second[X_AXIS], 100, 99000, reset_acceleration_rates);
    MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_Y, &max_acceleration_units_per_sq_second[Y_AXIS], 100, 99000, reset_acceleration_rates);
    MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_Z, &max_acceleration_units_per_sq_second[Z_AXIS], 10, 99000, reset_acceleration_rates);
    MENU_ITEM_EDIT(float5, MSG_A_TRAVEL, &travel_acceleration, 100, 99000);
    MENU_ITEM_EDIT(float52, MSG_XSTEPS, &axis_steps_per_unit[X_AXIS], 5, 9999);
    MENU_ITEM_EDIT(float52, MSG_YSTEPS, &axis_steps_per_unit[Y_AXIS], 5, 9999);
    MENU_ITEM_EDIT(float51, MSG_ZSTEPS, &axis_steps_per_unit[Z_AXIS], 5, 9999);

    if EXTRUDERS > 0

    MENU_ITEM_EDIT(float3, MSG_VE_JERK MSG_E "0", &max_e_jerk[0], 1, 990);
    MENU_ITEM_EDIT(float3, MSG_VMAX MSG_E "0", &max_feedrate[E_AXIS], 1, 999);
    MENU_ITEM_EDIT(long5, MSG_AMAX MSG_E "0", &max_acceleration_units_per_sq_second[E_AXIS], 100, 99000);
    MENU_ITEM_EDIT(float5, MSG_A_RETRACT MSG_E "0", &retract_acceleration[0], 100, 99000);
    MENU_ITEM_EDIT(float51, MSG_E0STEPS, &axis_steps_per_unit[E_AXIS], 5, 9999);
    #if EXTRUDERS > 1
    MENU_ITEM_EDIT(float3, MSG_VE_JERK MSG_E "1", &max_e_jerk[1], 1, 990);
    MENU_ITEM_EDIT(float3, MSG_VMAX MSG_E "1", &max_feedrate[E_AXIS + 1], 1, 999);
    MENU_ITEM_EDIT(long5, MSG_AMAX MSG_E "1", &max_acceleration_units_per_sq_second[E_AXIS + 1], 100, 99000);
    MENU_ITEM_EDIT(float5, MSG_A_RETRACT MSG_E "1", &retract_acceleration[1], 100, 99000);
    MENU_ITEM_EDIT(float51, MSG_E1STEPS, &axis_steps_per_unit[E_AXIS + 1], 5, 9999);
    #if EXTRUDERS > 2
    MENU_ITEM_EDIT(float3, MSG_VE_JERK MSG_E "2", &max_e_jerk[2], 1, 990);
    MENU_ITEM_EDIT(float3, MSG_VMAX MSG_E "2", &max_feedrate[E_AXIS + 2], 1, 999);
    MENU_ITEM_EDIT(long5, MSG_AMAX MSG_E "2", &max_acceleration_units_per_sq_second[E_AXIS + 2], 100, 99000);
    MENU_ITEM_EDIT(float5, MSG_A_RETRACT MSG_E "2", &retract_acceleration[2], 100, 99000);
    MENU_ITEM_EDIT(float51, MSG_E2STEPS, &axis_steps_per_unit[E_AXIS + 2], 5, 9999);
    #if EXTRUDERS > 3
    MENU_ITEM_EDIT(float3, MSG_VE_JERK MSG_E "3", &max_e_jerk[3], 1, 990);
    MENU_ITEM_EDIT(float3, MSG_VMAX MSG_E "3", &max_feedrate[E_AXIS + 3], 1, 999);
    MENU_ITEM_EDIT(long5, MSG_AMAX MSG_E "3", &max_acceleration_units_per_sq_second[E_AXIS + 3], 100, 99000);
    MENU_ITEM_EDIT(float5, MSG_A_RETRACT MSG_E "3", &retract_acceleration[3], 100, 99000);
    MENU_ITEM_EDIT(float51, MSG_E3STEPS, &axis_steps_per_unit[E_AXIS + 3], 5, 9999);
    #endif // EXTRUDERS > 3
    #endif // EXTRUDERS > 2
    #endif // EXTRUDERS > 1

    endif // EXTRUDERS > 0

    if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)

    MENU_ITEM_EDIT(bool, MSG_ENDSTOP_ABORT, &abort_on_endstop_hit);

    endif

    if MECH(SCARA)

    MENU_ITEM_EDIT(float74, MSG_XSCALE, &axis_scaling[X_AXIS],0.5,2);
    MENU_ITEM_EDIT(float74, MSG_YSCALE, &axis_scaling[Y_AXIS],0.5,2);

    endif

    END_MENU();
    }

/**
*

  • "Control" > "Filament" submenu
    *
    */
    static void lcd_control_volumetric_menu() {
    START_MENU(lcd_control_menu);
    MENU_ITEM(back, MSG_CONTROL, lcd_control_menu);

    MENU_ITEM_EDIT_CALLBACK(bool, MSG_VOLUMETRIC_ENABLED, &volumetric_enabled, calculate_volumetric_multipliers);

    if (volumetric_enabled) {
    MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_SIZE_EXTRUDER " 0", &filament_size[0], DEFAULT_NOMINAL_FILAMENT_DIA - .5, DEFAULT_NOMINAL_FILAMENT_DIA + .5, calculate_volumetric_multipliers);
    #if EXTRUDERS > 1
    MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_SIZE_EXTRUDER " 1", &filament_size[1], DEFAULT_NOMINAL_FILAMENT_DIA - .5, DEFAULT_NOMINAL_FILAMENT_DIA + .5, calculate_volumetric_multipliers);
    #if EXTRUDERS > 2
    MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_SIZE_EXTRUDER " 2", &filament_size[2], DEFAULT_NOMINAL_FILAMENT_DIA - .5, DEFAULT_NOMINAL_FILAMENT_DIA + .5, calculate_volumetric_multipliers);
    #if EXTRUDERS > 3
    MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_SIZE_EXTRUDER " 3", &filament_size[3], DEFAULT_NOMINAL_FILAMENT_DIA - .5, DEFAULT_NOMINAL_FILAMENT_DIA + .5, calculate_volumetric_multipliers);
    #endif //EXTRUDERS > 3
    #endif //EXTRUDERS > 2
    #endif //EXTRUDERS > 1
    }

    END_MENU();
    }

/**
*

  • "Control" > "Contrast" submenu
    *
    */
    #if HAS(LCD_CONTRAST)
    static void lcd_set_contrast() {
    if (encoderPosition != 0) {
    #if ENABLED(U8GLIB_LM6059_AF)
    lcd_contrast += encoderPosition;
    lcd_contrast &= 0xFF;
    #else
    lcd_contrast -= encoderPosition;
    lcd_contrast &= 0x3F;
    #endif
    encoderPosition = 0;
    lcdDrawUpdate = 1;
    u8g.setContrast(lcd_contrast);
    }
    if (lcdDrawUpdate) {
    #if ENABLED(U8GLIB_LM6059_AF)
    lcd_implementation_drawedit(PSTR(MSG_CONTRAST), itostr3(lcd_contrast));
    #else
    lcd_implementation_drawedit(PSTR(MSG_CONTRAST), itostr2(lcd_contrast));
    #endif
    }
    if (LCD_CLICKED) lcd_goto_menu(lcd_control_menu);
    }
    #endif // HAS(LCD_CONTRAST)

/**
*

  • "Control" > "Retract" submenu
    *
    */
    #if ENABLED(FWRETRACT)
    static void lcd_control_retract_menu() {
    START_MENU(lcd_control_menu);
    MENU_ITEM(back, MSG_CONTROL, lcd_control_menu);
    MENU_ITEM_EDIT(bool, MSG_AUTORETRACT, &autoretract_enabled);
    MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT, &retract_length, 0, 100);
    #if EXTRUDERS > 1
    MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT_SWAP, &retract_length_swap, 0, 100);
    #endif
    MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACTF, &retract_feedrate, 1, 999);
    MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT_ZLIFT, &retract_zlift, 0, 999);
    MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT_RECOVER, &retract_recover_length, 0, 100);
    #if EXTRUDERS > 1
    MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT_RECOVER_SWAP, &retract_recover_length_swap, 0, 100);
    #endif
    MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACT_RECOVERF, &retract_recover_feedrate, 1, 999);
    END_MENU();
    }
    #endif // FWRETRACT

if ENABLED(SDSUPPORT)

#if !PIN_EXISTS(SD_DETECT)
static void lcd_sd_refresh() {
card.initsd();
currentMenuViewOffset = 0;
}
#endif

static void lcd_sd_updir() {
card.updir();
currentMenuViewOffset = 0;
}

/**
*

  • "Print from SD" submenu
    *
    */
    void lcd_sdcard_menu() {
    if (lcdDrawUpdate == 0 && LCD_CLICKED == 0) return; // nothing to do (so don't thrash the SD card)
    uint16_t fileCnt = card.getnrfilenames();
    START_MENU(lcd_main_menu);
    MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
    card.getWorkDirName();
    if (card.filename[0] == '/') {
    #if !PIN_EXISTS(SD_DETECT)
    MENU_ITEM(function, LCD_STR_REFRESH MSG_REFRESH, lcd_sd_refresh);
    #endif
    }
    else {
    MENU_ITEM(function, LCD_STR_FOLDER "..", lcd_sd_updir);
    }

    for (uint16_t i = 0; i < fileCnt; i++) {
    if (_menuItemNr == _lineNr) {
    card.getfilename(
    #if ENABLED(SDCARD_RATHERRECENTFIRST)
    fileCnt-1 -
    #endif
    i
    );
    if (card.filenameIsDir)
    MENU_ITEM(sddirectory, MSG_CARD_MENU, card.filename, card.longFilename);
    else
    MENU_ITEM(sdfile, MSG_CARD_MENU, card.filename, card.longFilename);
    }
    else {
    MENU_ITEM_DUMMY();
    }
    }
    END_MENU();
    }

endif // SDSUPPORT

/**
*

  • Functions for editing single values
    *
    _/
    #define menu_edit_type(_type, _name, _strFunc, scale)
    bool menu_edit ## _name () {
    bool isClicked = LCD_CLICKED;
    if ((int32_t)encoderPosition < 0) encoderPosition = 0;
    if ((int32_t)encoderPosition > maxEditValue) encoderPosition = maxEditValue;
    if (lcdDrawUpdate)
    lcd_implementation_drawedit(editLabel, _strFunc(((_type)((int32_t)encoderPosition + minEditValue)) / scale));
    if (isClicked) {
    *((type)editValue) = ((type)((int32_t)encoderPosition + minEditValue)) / scale;
    lcd_goto_menu(prevMenu, prevEncoderPosition);
    }
    return isClicked;
    }
    void menu_edit
    ## _name () { menu_edit ## name(); }
    void menu_edit_callback
    ## _name () { if (menu_edit ## _name ()) (*callbackFunc)(); }
    static void menu_action_setting_edit ## _name (const char* pstr, _type* ptr, _type minValue, type maxValue) {
    prevMenu = currentMenu;
    prevEncoderPosition = encoderPosition;

    lcdDrawUpdate = 2;
    currentMenu = menu_edit
    ## name;

    editLabel = pstr;
    editValue = ptr;
    minEditValue = minValue * scale;
    maxEditValue = maxValue * scale - minEditValue;
    encoderPosition = (*ptr) * scale - minEditValue;
    }
    static void menu_action_setting_edit
    ## _name (const char* pstr, _type* ptr, _type minValue, _type maxValue) {
    menu_action_setting_edit ## name(pstr, ptr, minValue, maxValue);
    currentMenu = menu_edit
    ## name;
    }
    static void menu_action_setting_edit_callback
    ## _name (const char* pstr, _type* ptr, _type minValue, _type maxValue, menuFunc_t callback) {
    menu_action_setting_edit ## name(pstr, ptr, minValue, maxValue);
    currentMenu = menu_edit_callback
    ## _name;
    callbackFunc = callback;
    }
    menu_edit_type(int, int3, itostr3, 1)
    menu_edit_type(float, float3, ftostr3, 1)
    menu_edit_type(float, float32, ftostr32, 100)
    menu_edit_type(float, float43, ftostr43, 1000)
    menu_edit_type(float, float5, ftostr5, 0.01)
    menu_edit_type(float, float51, ftostr51, 10)
    menu_edit_type(float, float52, ftostr52, 100)
    menu_edit_type(unsigned long, long5, ftostr5, 0.01)

/**
*

  • Handlers for RepRap World Keypad input
    *
    */
    #if ENABLED(REPRAPWORLD_KEYPAD)
    static void reprapworld_keypad_move_z_up() {
    encoderPosition = 1;
    move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP;
    lcd_move_z();
    }
    static void reprapworld_keypad_move_z_down() {
    encoderPosition = -1;
    move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP;
    lcd_move_z();
    }
    static void reprapworld_keypad_move_x_left() {
    encoderPosition = -1;
    move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP;
    lcd_move_x();
    }
    static void reprapworld_keypad_move_x_right() {
    encoderPosition = 1;
    move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP;
    lcd_move_x();
    }
    static void reprapworld_keypad_move_y_down() {
    encoderPosition = 1;
    move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP;
    lcd_move_y();
    }
    static void reprapworld_keypad_move_y_up() {
    encoderPosition = -1;
    move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP;
    lcd_move_y();
    }
    static void reprapworld_keypad_move_home() {
    enqueuecommands_P((PSTR("G28"))); // move all axis home
    }
    #endif // REPRAPWORLD_KEYPAD

/**
*

  • Audio feedback for controller clicks
    *
    */

if ENABLED(LCD_USE_I2C_BUZZER)

void lcd_buzz(long duration, uint16_t freq) { // called from buzz() in Marlin_main.cpp where lcd is unknown
lcd.buzz(duration, freq);
}

endif

void lcd_quick_feedback() {
lcdDrawUpdate = 2;
next_button_update_ms = millis() + 500;

#if ENABLED(LCD_USE_I2C_BUZZER)
#if DISABLED(LCD_FEEDBACK_FREQUENCY_HZ)
#define LCD_FEEDBACK_FREQUENCY_HZ 100
#endif
#if DISABLED(LCD_FEEDBACK_FREQUENCY_DURATION_MS)
#define LCD_FEEDBACK_FREQUENCY_DURATION_MS (1000/6)
#endif

lcd.buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS, LCD_FEEDBACK_FREQUENCY_HZ);

#elif HAS(BUZZER)
#if DISABLED(LCD_FEEDBACK_FREQUENCY_HZ)
#define LCD_FEEDBACK_FREQUENCY_HZ 5000
#endif
#if DISABLED(LCD_FEEDBACK_FREQUENCY_DURATION_MS)
#define LCD_FEEDBACK_FREQUENCY_DURATION_MS 2
#endif
buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS, LCD_FEEDBACK_FREQUENCY_HZ);
#else
#if DISABLED(LCD_FEEDBACK_FREQUENCY_DURATION_MS)
#define LCD_FEEDBACK_FREQUENCY_DURATION_MS 2
#endif
delay(LCD_FEEDBACK_FREQUENCY_DURATION_MS);
#endif
}

/**
*

  • Menu actions
    *
    /
    static void menu_action_back(menuFunc_t func) { lcd_goto_menu(func); }
    static void menu_action_submenu(menuFunc_t func) { lcd_goto_menu(func); }
    static void menu_action_gcode(const char
    pgcode) { enqueuecommands_P(pgcode); }
    static void menu_action_function(menuFunc_t func) { (func)(); }
    static void menu_action_sdfile(const char
    filename, char* longFilename) {
    char cmd[30];
    char* c;
    sprintf_P(cmd, PSTR("M23 %s"), filename);
    for(c = &cmd[4]; _c; c++) *c = tolower(_c);
    enqueuecommand(cmd);
    enqueuecommands_P(PSTR("M24"));
    lcd_return_to_status();
    }

if ENABLED(SDSUPPORT)

static void menu_action_sddirectory(const char* filename, char* longFilename) {
card.chdir(filename);
encoderPosition = 0;
}

endif

static void menu_action_setting_edit_bool(const char* pstr, bool* ptr) { _ptr = !(_ptr); }
static void menu_action_setting_edit_callback_bool(const char* pstr, bool* ptr, menuFunc_t callback) {
menu_action_setting_edit_bool(pstr, ptr);
(*callback)();
}

endif //ULTIPANEL

/** LCD API **/
void lcd_init() {
lcd_implementation_init();

#if ENABLED(NEWPANEL)

SET_INPUT(BTN_EN1);
SET_INPUT(BTN_EN2);
WRITE(BTN_EN1,HIGH);
WRITE(BTN_EN2,HIGH);
#if BTN_ENC > 0
  SET_INPUT(BTN_ENC);
  WRITE(BTN_ENC,HIGH);
#endif
#if ENABLED(REPRAPWORLD_KEYPAD)
  pinMode(SHIFT_CLK,OUTPUT);
  pinMode(SHIFT_LD,OUTPUT);
  pinMode(SHIFT_OUT,INPUT);
  WRITE(SHIFT_OUT,HIGH);
  WRITE(SHIFT_LD,HIGH);
#endif

#else // Not NEWPANEL
#if ENABLED(SR_LCD_2W_NL) // Non latching 2 wire shift register
pinMode (SR_DATA_PIN, OUTPUT);
pinMode (SR_CLK_PIN, OUTPUT);
#elif ENABLED(SHIFT_CLK)
pinMode(SHIFT_CLK,OUTPUT);
pinMode(SHIFT_LD,OUTPUT);
pinMode(SHIFT_EN,OUTPUT);
pinMode(SHIFT_OUT,INPUT);
WRITE(SHIFT_OUT,HIGH);
WRITE(SHIFT_LD,HIGH);
WRITE(SHIFT_EN,LOW);
#endif // SR_LCD_2W_NL
#endif//!NEWPANEL

#if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_DETECT)
pinMode(SD_DETECT_PIN, INPUT);
WRITE(SD_DETECT_PIN, HIGH);
lcd_sd_status = 2; // UNKNOWN
#endif

#if ENABLED(LCD_HAS_SLOW_BUTTONS)
slow_buttons = 0;
#endif

lcd_buttons_update();

#if ENABLED(ULTIPANEL)
encoderDiff = 0;
#endif
}

int lcd_strlen(char *s) {
int i = 0, j = 0;
while (s[i]) {
if ((s[i] & 0xc0) != 0x80) j++;
i++;
}
return j;
}

int lcd_strlen_P(const char *s) {
int j = 0;
while (pgm_read_byte(s)) {
if ((pgm_read_byte(s) & 0xc0) != 0x80) j++;
s++;
}
return j;
}

/**

  • Update the LCD, read encoder buttons, etc.
    • Read button states
    • Check the SD Card slot state
    • Act on RepRap World keypad input
    • Update the encoder position
    • Apply acceleration to the encoder position
    • Reset the Info Screen timeout if there's any input
    • Update status indicators, if any
    • Clear the LCD if lcdDrawUpdate == 2
  • Warning: This function is called from interrupt context!
    */
    void lcd_update() {

    if ENABLED(ULTIPANEL)

    static millis_t return_to_status_ms = 0;

    endif

    if ENABLED(LCD_HAS_SLOW_BUTTONS)

    slow_buttons = lcd_implementation_read_slow_buttons(); // buttons which take too long to read in interrupt context

    endif

    lcd_buttons_update();

    if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_DETECT)

    bool sd_status = IS_SD_INSERTED;
    if (sd_status != lcd_sd_status && lcd_detected()) {
    lcdDrawUpdate = 2;
    lcd_implementation_init( // to maybe revive the LCD if static electricity killed it.
    #if ENABLED(LCD_PROGRESS_BAR)
    currentMenu == lcd_status_screen
    #endif
    );
    if (sd_status) {
    card.initsd();
    if (lcd_sd_status != 2) LCD_MESSAGEPGM(MSG_SD_INSERTED);
    } else {
    card.release();
    if (lcd_sd_status != 2) LCD_MESSAGEPGM(MSG_SD_REMOVED);
    }
    lcd_sd_status = sd_status;
    }

    endif // SDSUPPORT && SD_DETECT_PIN

    millis_t ms = millis();
    if (ms > next_lcd_update_ms) {

    #if ENABLED(ULTIPANEL)

    #if ENABLED(REPRAPWORLD_KEYPAD)
      if (REPRAPWORLD_KEYPAD_MOVE_Z_UP)     reprapworld_keypad_move_z_up();
      if (REPRAPWORLD_KEYPAD_MOVE_Z_DOWN)   reprapworld_keypad_move_z_down();
      if (REPRAPWORLD_KEYPAD_MOVE_X_LEFT)   reprapworld_keypad_move_x_left();
      if (REPRAPWORLD_KEYPAD_MOVE_X_RIGHT)  reprapworld_keypad_move_x_right();
      if (REPRAPWORLD_KEYPAD_MOVE_Y_DOWN)   reprapworld_keypad_move_y_down();
      if (REPRAPWORLD_KEYPAD_MOVE_Y_UP)     reprapworld_keypad_move_y_up();
      if (REPRAPWORLD_KEYPAD_MOVE_HOME)     reprapworld_keypad_move_home();
    #endif
    
    bool encoderPastThreshold = (abs(encoderDiff) >= ENCODER_PULSES_PER_STEP);
    if (encoderPastThreshold || LCD_CLICKED) {
      if (encoderPastThreshold) {
        int32_t encoderMultiplier = 1;
    
        #if ENABLED(ENCODER_RATE_MULTIPLIER)
    
          if (encoderRateMultiplierEnabled) {
            int32_t encoderMovementSteps = abs(encoderDiff) / ENCODER_PULSES_PER_STEP;
    
            if (lastEncoderMovementMillis != 0) {
              // Note that the rate is always calculated between to passes through the 
              // loop and that the abs of the encoderDiff value is tracked.
              float encoderStepRate = (float)(encoderMovementSteps) / ((float)(ms - lastEncoderMovementMillis)) * 1000.0;
    
              if (encoderStepRate >= ENCODER_100X_STEPS_PER_SEC)     encoderMultiplier = 100;
              else if (encoderStepRate >= ENCODER_10X_STEPS_PER_SEC) encoderMultiplier = 10;
    
              #if ENABLED(ENCODER_RATE_MULTIPLIER_DEBUG)
                ECHO_SMV(DB, "Enc Step Rate: ", encoderStepRate);
                ECHO_MV("  Multiplier: ", encoderMultiplier);
                ECHO_MV("  ENCODER_10X_STEPS_PER_SEC: ", ENCODER_10X_STEPS_PER_SEC);
                ECHO_EMV("  ENCODER_100X_STEPS_PER_SEC: ", ENCODER_100X_STEPS_PER_SEC);
              #endif
            }
    
            lastEncoderMovementMillis = ms;
          } // encoderRateMultiplierEnabled
        #endif //ENCODER_RATE_MULTIPLIER
    
        encoderPosition += (encoderDiff * encoderMultiplier) / ENCODER_PULSES_PER_STEP;
        encoderDiff = 0;
      }
      return_to_status_ms = ms + LCD_TIMEOUT_TO_STATUS;
      lcdDrawUpdate = 1;
    }
    

    #endif //ULTIPANEL

    if (currentMenu == lcd_status_screen) {
    if (!lcd_status_update_delay) {
    lcdDrawUpdate = 1;
    lcd_status_update_delay = 10; /* redraw the main screen every second. This is easier then trying keep track of all things that change on the screen _/
    }
    else {
    lcd_status_update_delay--;
    }
    }
    #if ENABLED(DOGLCD) // Changes due to different driver architecture of the DOGM display
    if (lcdDrawUpdate) {
    blink++; // Variable for fan animation and alive dot
    u8g.firstPage();
    do {
    lcd_setFont(FONT_MENU);
    u8g.setPrintPos(125, 0);
    if (blink % 2) u8g.setColorIndex(1); else u8g.setColorIndex(0); // Set color for the alive dot
    u8g.drawPixel(127, 63); // draw alive dot
    u8g.setColorIndex(1); // black on white
    (_currentMenu)();
    } while( u8g.nextPage() );
    }
    #else
    (*currentMenu)();
    #endif

    #if ENABLED(LCD_HAS_STATUS_INDICATORS)
    lcd_implementation_update_indicators();
    #endif

    #if ENABLED(ULTIPANEL)

    // Return to Status Screen after a timeout
    if (currentMenu != lcd_status_screen &&
      #if !MECH(DELTA) && DISABLED(Z_SAFE_HOMING) && Z_HOME_DIR < 0
        currentMenu != lcd_level_bed &&
      #endif
      millis() > return_to_status_ms
    ) {
      lcd_return_to_status();
      lcdDrawUpdate = 2;
    }
    

    #endif // ULTIPANEL

    if (lcdDrawUpdate == 2) lcd_implementation_clear();
    if (lcdDrawUpdate) lcdDrawUpdate--;
    next_lcd_update_ms = ms + LCD_UPDATE_INTERVAL;
    }
    }

void lcd_ignore_click(bool b) {
ignore_click = b;
wait_for_unclick = false;
}

void lcd_finishstatus(bool persist=false) {
#if ENABLED(LCD_PROGRESS_BAR)
progress_bar_ms = millis();
#if PROGRESS_MSG_EXPIRE > 0
expire_status_ms = persist ? 0 : progress_bar_ms + PROGRESS_MSG_EXPIRE;
#endif
#endif
lcdDrawUpdate = 2;

#if HAS(LCD_FILAMENT_SENSOR) || HAS(LCD_POWER_SENSOR)
previous_lcd_status_ms = millis(); //get status message to show up for a while
#endif
}

if ENABLED(LCD_PROGRESS_BAR) && PROGRESS_MSG_EXPIRE > 0

void dontExpireStatus() { expire_status_ms = 0; }

endif

void set_utf_strlen(char *s, uint8_t n) {
uint8_t i = 0, j = 0;
while (s[i] && (j < n)) {
if ((s[i] & 0xc0u) != 0x80u) j++;
i++;
}
while (j++ < n) s[i++] = ' ';
s[i] = 0;
}

bool lcd_hasstatus() { return (lcd_status_message[0] != '\0'); }

void lcd_setstatus(const char* message, bool persist) {
if (lcd_status_message_level > 0) return;
strncpy(lcd_status_message, message, 3*LCD_WIDTH);
set_utf_strlen(lcd_status_message, LCD_WIDTH);
lcd_finishstatus(persist);
}

void lcd_setstatuspgm(const char* message, uint8_t level) {
if (level >= lcd_status_message_level) {
strncpy_P(lcd_status_message, message, 3*LCD_WIDTH);
set_utf_strlen(lcd_status_message, LCD_WIDTH);
lcd_status_message_level = level;
lcd_finishstatus(level > 0);
}
}

void lcd_setalertstatuspgm(const char* message) {
lcd_setstatuspgm(message, 1);
#if ENABLED(ULTIPANEL)
lcd_return_to_status();
#endif
}

void lcd_reset_alert_level() { lcd_status_message_level = 0; }

if HAS(LCD_CONTRAST)

void lcd_setcontrast(uint8_t value) {
lcd_contrast = value & 0x3F;
u8g.setContrast(lcd_contrast);
}

endif

if ENABLED(ULTIPANEL)

/**

  • Setup Rotary Encoder Bit Values (for two pin encoders to indicate movement)

  • These values are independent of which pins are used for EN_A and EN_B indications

  • The rotary encoder part is also independent to the chipset used for the LCD
    */

    if ENABLED(EN_A) && ENABLED(EN_B)

    #define encrot0 0
    #define encrot1 2
    #define encrot2 3
    #define encrot3 1

    endif

    /**

  • Read encoder buttons from the hardware registers

  • Warning: This function is called from interrupt context!
    */
    void lcd_buttons_update() {
    #if ENABLED(NEWPANEL)
    uint8_t newbutton = 0;
    #if ENABLED(INVERT_ROTARY_SWITCH)
    if (READ(BTN_EN1) == 0) newbutton |= EN_B;
    if (READ(BTN_EN2) == 0) newbutton |= EN_A;
    #else
    if (READ(BTN_EN1) == 0) newbutton |= EN_A;
    if (READ(BTN_EN2) == 0) newbutton |= EN_B;
    #endif
    #if BTN_ENC > 0
    millis_t ms = millis();
    if (ms > next_button_update_ms && READ(BTN_ENC) == 0) newbutton |= EN_C;
    #if ENABLED(BTN_BACK) && BTN_BACK > 0
    if (ms > next_button_update_ms && READ(BTN_BACK) == 0) newbutton |= EN_D;
    #endif
    #endif
    buttons = newbutton;
    #if ENABLED(LCD_HAS_SLOW_BUTTONS)
    buttons |= slow_buttons;
    #endif
    #if ENABLED(REPRAPWORLD_KEYPAD)
    // for the reprapworld_keypad
    uint8_t newbutton_reprapworld_keypad=0;
    WRITE(SHIFT_LD, LOW);
    WRITE(SHIFT_LD, HIGH);
    for(int8_t i = 0; i < 8; i++) {
    newbutton_reprapworld_keypad >>= 1;
    if (READ(SHIFT_OUT)) newbutton_reprapworld_keypad |= BIT(7);
    WRITE(SHIFT_CLK, HIGH);
    WRITE(SHIFT_CLK, LOW);
    }
    buttons_reprapworld_keypad=~newbutton_reprapworld_keypad; //invert it, because a pressed switch produces a logical 0
    #endif
    #else //read it from the shift register
    uint8_t newbutton = 0;
    WRITE(SHIFT_LD, LOW);
    WRITE(SHIFT_LD, HIGH);
    unsigned char tmp_buttons = 0;
    for(int8_t i=0; i<8; i++) {
    newbutton >>= 1;
    if (READ(SHIFT_OUT)) newbutton |= BIT(7);
    WRITE(SHIFT_CLK, HIGH);
    WRITE(SHIFT_CLK, LOW);
    }
    buttons = ~newbutton; //invert it, because a pressed switch produces a logical 0
    #endif //!NEWPANEL

    //manage encoder rotation
    uint8_t enc=0;
    if (buttons & EN_A) enc |= B01;
    if (buttons & EN_B) enc |= B10;
    if (enc != lastEncoderBits) {
    switch(enc) {
    case encrot0:
    if (lastEncoderBits==encrot3) encoderDiff++;
    else if (lastEncoderBits==encrot1) encoderDiff--;
    break;
    case encrot1:
    if (lastEncoderBits==encrot0) encoderDiff++;
    else if (lastEncoderBits==encrot2) encoderDiff--;
    break;
    case encrot2:
    if (lastEncoderBits==encrot1) encoderDiff++;
    else if (lastEncoderBits==encrot3) encoderDiff--;
    break;
    case encrot3:
    if (lastEncoderBits==encrot2) encoderDiff++;
    else if (lastEncoderBits==encrot0) encoderDiff--;
    break;
    }
    }
    lastEncoderBits = enc;
    }

    bool lcd_detected(void) {
    #if (ENABLED(LCD_I2C_TYPE_MCP23017) || ENABLED(LCD_I2C_TYPE_MCP23008)) && ENABLED(DETECT_DEVICE)
    return lcd.LcdDetected() == 1;
    #else
    return true;
    #endif
    }

    bool lcd_clicked() { return LCD_CLICKED; }

endif // ULTIPANEL

/_/
/_* Number to string conversion /
/
***/

char conv[8];

// Convert float to string with +123.4 format
char *ftostr3(const float &x) {
return itostr3((int)x);
}

// Convert int to string with 12 format
char *itostr2(const uint8_t &x) {
//sprintf(conv,"%5.1f",x);
int xx = x;
conv[0] = (xx / 10) % 10 + '0';
conv[1] = xx % 10 + '0';
conv[2] = 0;
return conv;
}

// Convert float to string with +123.4 format
char *ftostr31(const float &x) {
int xx = abs(x * 10);
conv[0] = (x >= 0) ? '+' : '-';
conv[1] = (xx / 1000) % 10 + '0';
conv[2] = (xx / 100) % 10 + '0';
conv[3] = (xx / 10) % 10 + '0';
conv[4] = '.';
conv[5] = xx % 10 + '0';
conv[6] = 0;
return conv;
}

// Convert float to string with 123.4 format, dropping sign
char *ftostr31ns(const float &x) {
int xx = abs(x * 10);
conv[0] = (xx / 1000) % 10 + '0';
conv[1] = (xx / 100) % 10 + '0';
conv[2] = (xx / 10) % 10 + '0';
conv[3] = '.';
conv[4] = xx % 10 + '0';
conv[5] = 0;
return conv;
}

// Convert float to string with 123.4 format
char *ftostr32(const float &x) {
long xx = abs(x * 100);
conv[0] = x >= 0 ? (xx / 10000) % 10 + '0' : '-';
conv[1] = (xx / 1000) % 10 + '0';
conv[2] = (xx / 100) % 10 + '0';
conv[3] = '.';
conv[4] = (xx / 10) % 10 + '0';
conv[5] = xx % 10 + '0';
conv[6] = 0;
return conv;
}

// Convert float to string with 1.234 format
char *ftostr43(const float &x) {
long xx = x * 1000;
if (xx >= 0) {
conv[0] = (xx / 1000) % 10 + '0';
}
else {
conv[0] = '-';
}
xx = abs(xx);
conv[1] = '.';
conv[2] = (xx / 100) % 10 + '0';
conv[3] = (xx / 10) % 10 + '0';
conv[4] = (xx) % 10 + '0';
conv[5] = 0;
return conv;
}

// Convert float to string with 1.23 format
char _ftostr12ns(const float &x) {
long xx=x_100;

xx=abs(xx);
conv[0]=(xx/100)%10+'0';
conv[1]='.';
conv[2]=(xx/10)%10+'0';
conv[3]=(xx)%10+'0';
conv[4]=0;
return conv;
}

// Convert float to space-padded string with -23.4 format
char *ftostr32sp(const float &x) {
long xx = abs(x * 100);
uint8_t dig;

if (x < 0) { // negative val = -_0
conv[0] = '-';
dig = (xx / 1000) % 10;
conv[1] = dig ? '0' + dig : ' ';
}
else { // positive val = __0
dig = (xx / 10000) % 10;
if (dig) {
conv[0] = '0' + dig;
conv[1] = '0' + (xx / 1000) % 10;
}
else {
conv[0] = ' ';
dig = (xx / 1000) % 10;
conv[1] = dig ? '0' + dig : ' ';
}
}

conv[2] = '0' + (xx / 100) % 10; // lsd always

dig = xx % 10;
if (dig) { // 2 decimal places
conv[5] = '0' + dig;
conv[4] = '0' + (xx / 10) % 10;
conv[3] = '.';
}
else { // 1 or 0 decimal place
dig = (xx / 10) % 10;
if (dig) {
conv[4] = '0' + dig;
conv[3] = '.';
}
else {
conv[3] = conv[4] = ' ';
}
conv[5] = ' ';
}
conv[6] = '\0';
return conv;
}

// Convert int to lj string with +123.0 format
char *itostr31(const int &x) {
conv[0] = x >= 0 ? '+' : '-';
int xx = abs(x);
conv[1] = (xx / 100) % 10 + '0';
conv[2] = (xx / 10) % 10 + '0';
conv[3] = xx % 10 + '0';
conv[4] = '.';
conv[5] = '0';
conv[6] = 0;
return conv;
}

// Convert int to rj string with 123 or -12 format
char *itostr3(const int &x) {
int xx = x;
if (xx < 0) {
conv[0] = '-';
xx = -xx;
}
else
conv[0] = xx >= 100 ? (xx / 100) % 10 + '0' : ' ';

conv[1] = xx >= 10 ? (xx / 10) % 10 + '0' : ' ';
conv[2] = xx % 10 + '0';
conv[3] = 0;
return conv;
}

// Convert int to lj string with 123 format
char *itostr3left(const int &xx) {
if (xx >= 100) {
conv[0] = (xx / 100) % 10 + '0';
conv[1] = (xx / 10) % 10 + '0';
conv[2] = xx % 10 + '0';
conv[3] = 0;
}
else if (xx >= 10) {
conv[0] = (xx / 10) % 10 + '0';
conv[1] = xx % 10 + '0';
conv[2] = 0;
}
else {
conv[0] = xx % 10 + '0';
conv[1] = 0;
}
return conv;
}

// Convert int to rj string with 1234 format
char *itostr4(const int &xx) {
conv[0] = xx >= 1000 ? (xx / 1000) % 10 + '0' : ' ';
conv[1] = xx >= 100 ? (xx / 100) % 10 + '0' : ' ';
conv[2] = xx >= 10 ? (xx / 10) % 10 + '0' : ' ';
conv[3] = xx % 10 + '0';
conv[4] = 0;
return conv;
}

char *ltostr7(const long &xx) {
if (xx >= 1000000)
conv[0]=(xx/1000000)%10+'0';
else
conv[0]=' ';
if (xx >= 100000)
conv[1]=(xx/100000)%10+'0';
else
conv[1]=' ';
if (xx >= 10000)
conv[2]=(xx/10000)%10+'0';
else
conv[2]=' ';
if (xx >= 1000)
conv[3]=(xx/1000)%10+'0';
else
conv[3]=' ';
if (xx >= 100)
conv[4]=(xx/100)%10+'0';
else
conv[4]=' ';
if (xx >= 10)
conv[5]=(xx/10)%10+'0';
else
conv[5]=' ';
conv[6]=(xx)%10+'0';
conv[7]=0;
return conv;
}

// convert float to string with +123 format
char *ftostr30(const float &x) {
int xx=x;
conv[0]=(xx>=0)?'+':'-';
xx=abs(xx);
conv[1]=(xx/100)%10+'0';
conv[2]=(xx/10)%10+'0';
conv[3]=(xx)%10+'0';
conv[4]=0;
return conv;
}

// Convert float to rj string with 12345 format
char *ftostr5(const float &x) {
long xx = abs(x);
conv[0] = xx >= 10000 ? (xx / 10000) % 10 + '0' : ' ';
conv[1] = xx >= 1000 ? (xx / 1000) % 10 + '0' : ' ';
conv[2] = xx >= 100 ? (xx / 100) % 10 + '0' : ' ';
conv[3] = xx >= 10 ? (xx / 10) % 10 + '0' : ' ';
conv[4] = xx % 10 + '0';
conv[5] = 0;
return conv;
}

// Convert float to string with +1234.5 format
char *ftostr51(const float &x) {
long xx = abs(x * 10);
conv[0] = (x >= 0) ? '+' : '-';
conv[1] = (xx / 10000) % 10 + '0';
conv[2] = (xx / 1000) % 10 + '0';
conv[3] = (xx / 100) % 10 + '0';
conv[4] = (xx / 10) % 10 + '0';
conv[5] = '.';
conv[6] = xx % 10 + '0';
conv[7] = 0;
return conv;
}

// Convert float to string with +123.45 format
char *ftostr52(const float &x) {
conv[0] = (x >= 0) ? '+' : '-';
long xx = abs(x * 100);
conv[1] = (xx / 10000) % 10 + '0';
conv[2] = (xx / 1000) % 10 + '0';
conv[3] = (xx / 100) % 10 + '0';
conv[4] = '.';
conv[5] = (xx / 10) % 10 + '0';
conv[6] = xx % 10 + '0';
conv[7] = 0;
return conv;
}

if DISABLED(DELTA) && DISABLED(Z_SAFE_HOMING) && Z_HOME_DIR < 0

static void lcd_level_bed() {

switch(pageShowInfo) {
  case 0:
    {
      LCD_Printpos(0, 0); lcd_printPGM(PSTR(MSG_MBL_INTRO));
      LCD_Printpos(0, 1); lcd_printPGM(PSTR(MSG_MBL_BUTTON));
    }
  break;
  case 1:
    {
      LCD_Printpos(0, 0); lcd_printPGM(PSTR(MSG_MBL_1));
      LCD_Printpos(0, 1); lcd_printPGM(PSTR(MSG_MBL_BUTTON));
    }
  break;
  case 2:
    {
      LCD_Printpos(0, 0); lcd_printPGM(PSTR(MSG_MBL_2));
      LCD_Printpos(0, 1); lcd_printPGM(PSTR(MSG_MBL_BUTTON));
    }
  break;
  case 3:
    {
      LCD_Printpos(0, 0); lcd_printPGM(PSTR(MSG_MBL_3));
      LCD_Printpos(0, 1); lcd_printPGM(PSTR(MSG_MBL_BUTTON));
    }
  break;
  case 4:
    {
      LCD_Printpos(0, 0); lcd_printPGM(PSTR(MSG_MBL_4));
      LCD_Printpos(0, 1); lcd_printPGM(PSTR(MSG_MBL_BUTTON));
    }
  break;
  case 5:
    {
      LCD_Printpos(0, 0); lcd_printPGM(PSTR(MSG_MBL_5));
      LCD_Printpos(0, 1); lcd_printPGM(PSTR(MSG_MBL_BUTTON));
    }
  break;
  case 6:
    {
      LCD_Printpos(0, 0); lcd_printPGM(PSTR(MSG_MBL_6));
      LCD_Printpos(0, 1); lcd_printPGM(PSTR("                  "));
      delay(5000);
      enqueuecommands_P(PSTR("G28"));
      lcd_goto_menu(lcd_prepare_motion_menu);
    }
  break;
}

}

static void config_lcd_level_bed() {
ECHO_EM(MSG_MBL_SETTING);
enqueuecommands_P(PSTR("G28 M"));
pageShowInfo = 0;
lcd_goto_menu(lcd_level_bed);
}

endif

endif //ULTRA_LCD

if ENABLED(SDSUPPORT) && ENABLED(SD_SETTINGS)

void set_sd_dot() {
#if ENABLED(DOGLCD)
u8g.firstPage();
do {
u8g.setColorIndex(1);
u8g.drawPixel(0, 0); // draw sd dot
u8g.setColorIndex(1); // black on white
(_currentMenu)();
} while( u8g.nextPage() );
#endif
}
void unset_sd_dot() {
#if ENABLED(DOGLCD)
u8g.firstPage();
do {
u8g.setColorIndex(0);
u8g.drawPixel(0, 0); // draw sd dot
u8g.setColorIndex(1); // black on white
(_currentMenu)();
} while( u8g.nextPage() );
#endif
}

endif

quando descomenta #define SHOW_TEMP_ADC_VALUES

Arduino: 1.6.4 (Mac OS X), Placa:"Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"

In file included from base.h:54:0,
from Marlin_main.cpp:30:
Marlin_main.cpp: In function 'void gcode_M105()':
Marlin_main.cpp:5152: error: 'OVERSAMPLENR' was not declared in this scope
ECHO_MV("C->", rawBedTemp()/OVERSAMPLENR, 0);
^
comunication.h:47:51: note: in definition of macro 'SERIAL_PRINT'
#define SERIAL_PRINT(msg, args...) MYSERIAL.print(msg, ##args)
^
Marlin_main.cpp:5152:7: note: in expansion of macro 'ECHO_MV'
ECHO_MV("C->", rawBedTemp()/OVERSAMPLENR, 0);
^
'OVERSAMPLENR' was not declared in this scope

Este relatório deveria ter mais informações
"Mostrar saída verbosa durante a compilação"
habilitado em Arquivo > Preferências.

Configurator tool & Power off

Hi! I just switched from Marlin, as I am preparing for my new Cyclope hotend. Now I am using Prusa I3 with two Bowden extruders, two E3D hotends, RAMPS 1.4 board and RepRapDiscount Smart controller LCD. MarlinKimbra 4.2. There is two things I think would be nice to see:

  1. In Configurator tool - I miss the distance settings for two hotend setup. (X&Y from hotend0 to hotend1)
  2. In LCD menu I missed "Power Off/On" option, what just sends M81/M80. As I am writing, I think, that is probably missing, because I choose PowerSupply0? I am using this function to shutdown my OctoPi. It is watching for M81 and if it is find - Shutting down the Raspberry.

babySTEPPING don't work

Arduino: 1.6.3 (Mac OS X), Placa:"Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"

temperature.cpp: In function 'void __vector_22()':
temperature.cpp:1653:34: error: 'babystep' was not declared in this scope
babystep(axis,/fwd/true);
^
temperature.cpp:1657:35: error: 'babystep' was not declared in this scope
babystep(axis,/fwd/false);
^
Erro compilando.

Este relatório deveria ter mais informações
"Mostrar saída verbosa durante a compilação"
habilitado em Arquivo > Preferências.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.