From 16b9239a26088ac682a1c3683542f36a4ab573ed Mon Sep 17 00:00:00 2001 From: Guillaume Seguin Date: Wed, 29 May 2013 18:06:12 +0200 Subject: [PATCH 001/256] Report temperatures for all extruders --- Marlin/Marlin_main.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 47202aff82..d5f43022e1 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1068,6 +1068,14 @@ void process_commands() SERIAL_PROTOCOL_F(degTargetBed(),1); #endif //TEMP_BED_PIN #else + for (int8_t cur_extruder = 0; cur_extruder < EXTRUDERS; ++cur_extruder) { + SERIAL_PROTOCOLPGM(" T"); + SERIAL_PROTOCOL(cur_extruder); + SERIAL_PROTOCOLPGM(":"); + SERIAL_PROTOCOL_F(degHotend(cur_extruder),1); + SERIAL_PROTOCOLPGM(" /"); + SERIAL_PROTOCOL_F(degTargetHotend(cur_extruder),1); + } SERIAL_ERROR_START; SERIAL_ERRORLNPGM(MSG_ERR_NO_THERMISTORS); #endif From 01ed99143c1468afa5980708536738c5f96a8035 Mon Sep 17 00:00:00 2001 From: Guillaume Seguin Date: Tue, 23 Jul 2013 23:34:42 +0200 Subject: [PATCH 002/256] Woops, fix logic --- Marlin/Marlin_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index d2d1ae5d88..eb0bf554e0 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1210,7 +1210,6 @@ void process_commands() SERIAL_PROTOCOLPGM(" /"); SERIAL_PROTOCOL_F(degTargetBed(),1); #endif //TEMP_BED_PIN - #else for (int8_t cur_extruder = 0; cur_extruder < EXTRUDERS; ++cur_extruder) { SERIAL_PROTOCOLPGM(" T"); SERIAL_PROTOCOL(cur_extruder); @@ -1219,6 +1218,7 @@ void process_commands() SERIAL_PROTOCOLPGM(" /"); SERIAL_PROTOCOL_F(degTargetHotend(cur_extruder),1); } + #else SERIAL_ERROR_START; SERIAL_ERRORLNPGM(MSG_ERR_NO_THERMISTORS); #endif From 374bc99fa3873efd49346128fb127c1aee5862f2 Mon Sep 17 00:00:00 2001 From: Guillaume Seguin Date: Wed, 24 Jul 2013 12:09:53 +0200 Subject: [PATCH 003/256] Add support of LiquidTWI2-based panels to Makefile Use LIQUID_TWI2=1 as make argument to enable this support --- Marlin/Makefile | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/Marlin/Makefile b/Marlin/Makefile index a56bc1eab1..5cc25ea014 100644 --- a/Marlin/Makefile +++ b/Marlin/Makefile @@ -54,6 +54,9 @@ UPLOAD_PORT ?= /dev/arduino #Directory used to build files in, contains all the build files, from object files to the final hex file. BUILD_DIR ?= applet +# This defines whether Liquid_TWI2 support will be built +LIQUID_TWI2 ?= 0 + ############################################################################ # Below here nothing should be changed... @@ -199,9 +202,19 @@ VPATH += $(HARDWARE_SRC) ifeq ($(HARDWARE_VARIANT), arduino) VPATH += $(ARDUINO_INSTALL_DIR)/libraries/LiquidCrystal VPATH += $(ARDUINO_INSTALL_DIR)/libraries/SPI +ifeq ($(LIQUID_TWI2), 1) +VPATH += $(ARDUINO_INSTALL_DIR)/libraries/Wire +VPATH += $(ARDUINO_INSTALL_DIR)/libraries/Wire/utility +VPATH += $(ARDUINO_INSTALL_DIR)/libraries/LiquidTWI2 +endif else VPATH += $(HARDWARE_DIR)/libraries/LiquidCrystal VPATH += $(HARDWARE_DIR)/libraries/SPI +ifeq ($(LIQUID_TWI2), 1) +VPATH += $(HARDWARE_DIR)/libraries/Wire +VPATH += $(HARDWARE_DIR)/libraries/Wire/utility +VPATH += $(HARDWARE_DIR)/libraries/LiquidTWI2 +endif endif ifeq ($(HARDWARE_VARIANT), arduino) HARDWARE_SUB_VARIANT ?= mega @@ -218,8 +231,13 @@ CXXSRC = WMath.cpp WString.cpp Print.cpp Marlin_main.cpp \ MarlinSerial.cpp Sd2Card.cpp SdBaseFile.cpp SdFatUtil.cpp \ SdFile.cpp SdVolume.cpp motion_control.cpp planner.cpp \ stepper.cpp temperature.cpp cardreader.cpp ConfigurationStore.cpp \ - watchdog.cpp -CXXSRC += LiquidCrystal.cpp ultralcd.cpp SPI.cpp Servo.cpp Tone.cpp + watchdog.cpp SPI.cpp Servo.cpp Tone.cpp ultralcd.cpp +ifeq ($(LIQUID_TWI2), 0) +CXXSRC += LiquidCrystal.cpp +else +SRC += twi.c +CXXSRC += Wire.cpp LiquidTWI2.cpp +endif #Check for Arduino 1.0.0 or higher and use the correct sourcefiles for that version ifeq ($(shell [ $(ARDUINO_VERSION) -ge 100 ] && echo true), true) From e019197b32ecf29a0ca273d3d05a6d9e58af6d5b Mon Sep 17 00:00:00 2001 From: ellensp Date: Sat, 27 Jul 2013 00:13:49 +1200 Subject: [PATCH 004/256] renamed ArduinoAddons/Arduino_1.x.x/sanguino to Sanguino. Now make works for Arduino > 1.0 on linux --- .../Arduino_1.x.x/{sanguino => Sanguino}/boards.txt | 0 .../bootloaders/atmega/ATmegaBOOT_168.c | 0 .../atmega/ATmegaBOOT_168_atmega1284p.hex | 0 .../atmega/ATmegaBOOT_168_atmega1284p_8m.hex | 0 .../atmega/ATmegaBOOT_168_atmega644p.hex | 0 .../bootloaders/atmega/Makefile | 0 .../bootloaders/atmega644p/ATmegaBOOT.c | 0 .../bootloaders/atmega644p/ATmegaBOOT.c.tst | 0 .../bootloaders/atmega644p/ATmegaBOOT_644P.elf | Bin .../bootloaders/atmega644p/ATmegaBOOT_644P.hex | 0 .../bootloaders/atmega644p/Makefile | 0 .../bootloaders/atmega644p/README.txt | 0 .../{sanguino => Sanguino}/cores/arduino/Arduino.h | 0 .../{sanguino => Sanguino}/cores/arduino/CDC.cpp | 0 .../{sanguino => Sanguino}/cores/arduino/Client.h | 0 .../{sanguino => Sanguino}/cores/arduino/HID.cpp | 0 .../cores/arduino/HardwareSerial.cpp | 0 .../cores/arduino/HardwareSerial.h | 0 .../cores/arduino/IPAddress.cpp | 0 .../cores/arduino/IPAddress.h | 0 .../{sanguino => Sanguino}/cores/arduino/Platform.h | 0 .../{sanguino => Sanguino}/cores/arduino/Print.cpp | 0 .../{sanguino => Sanguino}/cores/arduino/Print.h | 0 .../cores/arduino/Printable.h | 0 .../{sanguino => Sanguino}/cores/arduino/Server.h | 0 .../{sanguino => Sanguino}/cores/arduino/Stream.cpp | 0 .../{sanguino => Sanguino}/cores/arduino/Stream.h | 0 .../{sanguino => Sanguino}/cores/arduino/Tone.cpp | 0 .../{sanguino => Sanguino}/cores/arduino/USBAPI.h | 0 .../cores/arduino/USBCore.cpp | 0 .../{sanguino => Sanguino}/cores/arduino/USBCore.h | 0 .../{sanguino => Sanguino}/cores/arduino/USBDesc.h | 0 .../{sanguino => Sanguino}/cores/arduino/Udp.h | 0 .../cores/arduino/WCharacter.h | 0 .../cores/arduino/WInterrupts.c | 0 .../{sanguino => Sanguino}/cores/arduino/WMath.cpp | 0 .../cores/arduino/WString.cpp | 0 .../{sanguino => Sanguino}/cores/arduino/WString.h | 0 .../{sanguino => Sanguino}/cores/arduino/binary.h | 0 .../{sanguino => Sanguino}/cores/arduino/main.cpp | 0 .../{sanguino => Sanguino}/cores/arduino/new.cpp | 0 .../{sanguino => Sanguino}/cores/arduino/new.h | 0 .../{sanguino => Sanguino}/cores/arduino/wiring.c | 0 .../cores/arduino/wiring_analog.c | 0 .../cores/arduino/wiring_digital.c | 0 .../cores/arduino/wiring_private.h | 0 .../cores/arduino/wiring_pulse.c | 0 .../cores/arduino/wiring_shift.c | 0 .../variants/standard/pins_arduino.h | 0 49 files changed, 0 insertions(+), 0 deletions(-) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/boards.txt (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/bootloaders/atmega/ATmegaBOOT_168.c (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/bootloaders/atmega/ATmegaBOOT_168_atmega1284p.hex (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/bootloaders/atmega/ATmegaBOOT_168_atmega1284p_8m.hex (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/bootloaders/atmega/ATmegaBOOT_168_atmega644p.hex (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/bootloaders/atmega/Makefile (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/bootloaders/atmega644p/ATmegaBOOT.c (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/bootloaders/atmega644p/ATmegaBOOT.c.tst (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/bootloaders/atmega644p/ATmegaBOOT_644P.elf (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/bootloaders/atmega644p/ATmegaBOOT_644P.hex (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/bootloaders/atmega644p/Makefile (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/bootloaders/atmega644p/README.txt (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/Arduino.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/CDC.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/Client.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/HID.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/HardwareSerial.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/HardwareSerial.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/IPAddress.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/IPAddress.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/Platform.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/Print.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/Print.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/Printable.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/Server.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/Stream.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/Stream.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/Tone.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/USBAPI.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/USBCore.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/USBCore.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/USBDesc.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/Udp.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/WCharacter.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/WInterrupts.c (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/WMath.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/WString.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/WString.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/binary.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/main.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/new.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/new.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/wiring.c (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/wiring_analog.c (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/wiring_digital.c (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/wiring_private.h (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/wiring_pulse.c (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/cores/arduino/wiring_shift.c (100%) rename ArduinoAddons/Arduino_1.x.x/{sanguino => Sanguino}/variants/standard/pins_arduino.h (100%) diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/boards.txt b/ArduinoAddons/Arduino_1.x.x/Sanguino/boards.txt similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/boards.txt rename to ArduinoAddons/Arduino_1.x.x/Sanguino/boards.txt diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega/ATmegaBOOT_168.c b/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/ATmegaBOOT_168.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega/ATmegaBOOT_168.c rename to ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/ATmegaBOOT_168.c diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p.hex b/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p.hex similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p.hex rename to ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p.hex diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p_8m.hex b/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p_8m.hex similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p_8m.hex rename to ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p_8m.hex diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega644p.hex b/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega644p.hex similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega644p.hex rename to ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega644p.hex diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega/Makefile b/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/Makefile similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega/Makefile rename to ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/Makefile diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega644p/ATmegaBOOT.c b/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/ATmegaBOOT.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega644p/ATmegaBOOT.c rename to ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/ATmegaBOOT.c diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega644p/ATmegaBOOT.c.tst b/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/ATmegaBOOT.c.tst similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega644p/ATmegaBOOT.c.tst rename to ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/ATmegaBOOT.c.tst diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.elf b/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.elf similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.elf rename to ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.elf diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.hex b/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.hex similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.hex rename to ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.hex diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega644p/Makefile b/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/Makefile similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega644p/Makefile rename to ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/Makefile diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega644p/README.txt b/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/README.txt similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/bootloaders/atmega644p/README.txt rename to ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/README.txt diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Arduino.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Arduino.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Arduino.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Arduino.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/CDC.cpp b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/CDC.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/CDC.cpp rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/CDC.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Client.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Client.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Client.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Client.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/HID.cpp b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/HID.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/HID.cpp rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/HID.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/HardwareSerial.cpp b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/HardwareSerial.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/HardwareSerial.cpp rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/HardwareSerial.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/HardwareSerial.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/HardwareSerial.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/HardwareSerial.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/HardwareSerial.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/IPAddress.cpp b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/IPAddress.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/IPAddress.cpp rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/IPAddress.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/IPAddress.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/IPAddress.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/IPAddress.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/IPAddress.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Platform.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Platform.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Platform.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Platform.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Print.cpp b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Print.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Print.cpp rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Print.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Print.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Print.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Print.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Print.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Printable.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Printable.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Printable.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Printable.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Server.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Server.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Server.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Server.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Stream.cpp b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Stream.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Stream.cpp rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Stream.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Stream.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Stream.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Stream.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Stream.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Tone.cpp b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Tone.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Tone.cpp rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Tone.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/USBAPI.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/USBAPI.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/USBAPI.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/USBAPI.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/USBCore.cpp b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/USBCore.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/USBCore.cpp rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/USBCore.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/USBCore.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/USBCore.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/USBCore.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/USBCore.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/USBDesc.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/USBDesc.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/USBDesc.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/USBDesc.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Udp.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Udp.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/Udp.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Udp.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/WCharacter.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WCharacter.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/WCharacter.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WCharacter.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/WInterrupts.c b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WInterrupts.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/WInterrupts.c rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WInterrupts.c diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/WMath.cpp b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WMath.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/WMath.cpp rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WMath.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/WString.cpp b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WString.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/WString.cpp rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WString.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/WString.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WString.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/WString.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WString.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/binary.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/binary.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/binary.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/binary.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/main.cpp b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/main.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/main.cpp rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/main.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/new.cpp b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/new.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/new.cpp rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/new.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/new.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/new.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/new.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/new.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/wiring.c b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/wiring.c rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring.c diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/wiring_analog.c b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_analog.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/wiring_analog.c rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_analog.c diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/wiring_digital.c b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_digital.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/wiring_digital.c rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_digital.c diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/wiring_private.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_private.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/wiring_private.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_private.h diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/wiring_pulse.c b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_pulse.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/wiring_pulse.c rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_pulse.c diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/wiring_shift.c b/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_shift.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/cores/arduino/wiring_shift.c rename to ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_shift.c diff --git a/ArduinoAddons/Arduino_1.x.x/sanguino/variants/standard/pins_arduino.h b/ArduinoAddons/Arduino_1.x.x/Sanguino/variants/standard/pins_arduino.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/sanguino/variants/standard/pins_arduino.h rename to ArduinoAddons/Arduino_1.x.x/Sanguino/variants/standard/pins_arduino.h From eb23a68e92e5bf571287961a435a9edf23121ee0 Mon Sep 17 00:00:00 2001 From: Guillaume Seguin Date: Sun, 28 Jul 2013 18:18:41 +0200 Subject: [PATCH 005/256] Update French translation in language.h --- Marlin/language.h | 139 ++++++++++++++++++++++------------------------ 1 file changed, 67 insertions(+), 72 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index 17222c7cd2..39e459f94d 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -373,96 +373,91 @@ #if LANGUAGE_CHOICE == 3 - #define WELCOME_MSG MACHINE_NAME " Pret." + #define WELCOME_MSG MACHINE_NAME " prete." #define MSG_SD_INSERTED "Carte inseree" #define MSG_SD_REMOVED "Carte retiree" - #define MSG_MAIN " Principal \003" - #define MSG_AUTOSTART " Demarrage auto." - #define MSG_DISABLE_STEPPERS " Desactiver moteurs" - #define MSG_AUTO_HOME " Home auto." - #define MSG_SET_ORIGIN " Regler origine" + #define MSG_MAIN "Menu principal" + #define MSG_AUTOSTART "Demarrage auto" + #define MSG_DISABLE_STEPPERS "Arreter moteurs" + #define MSG_AUTO_HOME "Home auto." + #define MSG_SET_ORIGIN "Regler origine" #define MSG_PREHEAT_PLA " Prechauffage PLA" #define MSG_PREHEAT_PLA_SETTINGS " Regl. prechauffe PLA" - #define MSG_PREHEAT_ABS " Prechauffage ABS" - #define MSG_PREHEAT_ABS_SETTINGS " Regl. prechauffe ABS" - #define MSG_COOLDOWN " Refroidissement" - #define MSG_SWITCH_PS_ON "Allumer alimentation" - #define MSG_SWITCH_PS_OFF "Eteindre alimentation" - #define MSG_EXTRUDE " Extrusion" - #define MSG_RETRACT " Retractation" - #define MSG_PREHEAT_PLA " Prechauffage PLA" - #define MSG_PREHEAT_ABS " Prechauffage ABS" - #define MSG_MOVE_AXIS " Deplacer axe \x7E" - #define MSG_SPEED " Vitesse:" - #define MSG_NOZZLE " \002Buse:" - #define MSG_NOZZLE1 " \002Buse2:" - #define MSG_NOZZLE2 " \002Buse3:" - #define MSG_BED " \002Lit:" - #define MSG_FAN_SPEED " Vitesse ventilateur:" - #define MSG_FLOW " Flux:" - #define MSG_CONTROL " Controle \003" - #define MSG_MIN " \002 Min:" - #define MSG_MAX " \002 Max:" - #define MSG_FACTOR " \002 Facteur:" - #define MSG_AUTOTEMP " Temp. Auto.:" + #define MSG_PREHEAT_ABS "Prechauffage ABS" + #define MSG_PREHEAT_ABS_SETTINGS "Regl. prechauffe ABS" + #define MSG_COOLDOWN "Refroidir" + #define MSG_SWITCH_PS_ON "Allumer alim." + #define MSG_SWITCH_PS_OFF "Eteindre alim." + #define MSG_EXTRUDE "Extrusion" + #define MSG_RETRACT "Retraction" + #define MSG_PREHEAT_PLA "Prechauffage PLA" + #define MSG_PREHEAT_ABS "Prechauffage ABS" + #define MSG_MOVE_AXIS "Deplacer un axe" + #define MSG_SPEED " Vitesse" + #define MSG_NOZZLE "Buse" + #define MSG_NOZZLE1 "Buse2" + #define MSG_NOZZLE2 "Buse3" + #define MSG_BED "Plateau" + #define MSG_FAN_SPEED "Vitesse ventilateur" + #define MSG_FLOW "Flux" + #define MSG_CONTROL "Controler" + #define MSG_MIN " \002 Min" + #define MSG_MAX " \002 Max" + #define MSG_FACTOR " \002 Facteur" + #define MSG_AUTOTEMP "Temp. Auto." #define MSG_ON "Marche " #define MSG_OFF "Arret" - #define MSG_PID_P " PID-P: " - #define MSG_PID_I " PID-I: " - #define MSG_PID_D " PID-D: " - #define MSG_PID_C " PID-C: " - #define MSG_ACC " Acc:" + #define MSG_PID_P "PID-P" + #define MSG_PID_I "PID-I" + #define MSG_PID_D "PID-D" + #define MSG_PID_C "PID-C" + #define MSG_ACC "Accel" #define MSG_VXY_JERK "Vxy-jerk" #define MSG_VZ_JERK "Vz-jerk" #define MSG_VE_JERK "Ve-jerk" - #define MSG_VMAX " Vmax " - #define MSG_X "x:" - #define MSG_Y "y:" - #define MSG_Z "z:" - #define MSG_E "e:" - #define MSG_VMIN " Vmin:" - #define MSG_VTRAV_MIN " Vdepl min:" - #define MSG_AMAX " Amax " - #define MSG_A_RETRACT " A-retract:" - #define MSG_XSTEPS " Xpas/mm:" - #define MSG_YSTEPS " Ypas/mm:" - #define MSG_ZSTEPS " Zpas/mm:" - #define MSG_ESTEPS " Epas/mm:" - #define MSG_MAIN_WIDE " Principal \003" - #define MSG_RECTRACT "Rectracter" + #define MSG_VMAX "Vmax" + #define MSG_X "x" + #define MSG_Y "y" + #define MSG_Z "z" + #define MSG_E "e" + #define MSG_VMIN "Vmin" + #define MSG_VTRAV_MIN "Vdepl min" + #define MSG_AMAX "Amax " + #define MSG_A_RETRACT "A-retract" + #define MSG_XSTEPS "Xpas/mm" + #define MSG_YSTEPS "Ypas/mm" + #define MSG_ZSTEPS "Zpas/mm" + #define MSG_ESTEPS "Epas/mm" #define MSG_TEMPERATURE "Temperature" #define MSG_MOTION "Mouvement" - #define MSG_CONTRAST "LCD contrast" - #define MSG_STORE_EPROM " Sauvegarder memoire" - #define MSG_LOAD_EPROM " Lire memoire" - #define MSG_RESTORE_FAILSAFE " Restaurer memoire" - #define MSG_REFRESH "\004Actualiser" - #define MSG_WATCH " Surveiller \003" - #define MSG_PREPARE " Preparer \x7E" - #define MSG_PREPARE_ALT " Prepare \003" - #define MSG_CONTROL_ARROW " Controle \x7E" - #define MSG_RETRACT_ARROW " Retracter \x7E" - #define MSG_TUNE " Regler \x7E" - #define MSG_PAUSE_PRINT " Pause impression \x7E" - #define MSG_RESUME_PRINT " Reprendre impression \x7E" - #define MSG_STOP_PRINT " Arreter impression \x7E" - #define MSG_CARD_MENU " Menu carte \x7E" - #define MSG_NO_CARD " Pas de carte" + #define MSG_CONTRAST "Contraste LCD" + #define MSG_STORE_EPROM "Sauver config" + #define MSG_LOAD_EPROM "Lire config" + #define MSG_RESTORE_FAILSAFE "Restaurer defauts" + #define MSG_REFRESH "Actualiser" + #define MSG_WATCH "Surveiller" + #define MSG_PREPARE "Preparer" + #define MSG_TUNE "Regler" + #define MSG_PAUSE_PRINT "Interrompre impr." + #define MSG_RESUME_PRINT "Reprendre impr." + #define MSG_STOP_PRINT "Arreter impr." + #define MSG_CARD_MENU "Impr. depuis SD" + #define MSG_NO_CARD "Pas de carte" #define MSG_DWELL "Repos..." #define MSG_USERWAIT "Attente de l'utilisateur..." #define MSG_RESUMING "Reprise de l'impression" #define MSG_NO_MOVE "Aucun mouvement." #define MSG_PART_RELEASE "Relache partielle" - #define MSG_KILLED "TUE." + #define MSG_KILLED "MORT." #define MSG_STOPPED "STOPPE." #define MSG_STEPPER_RELEASED "RELACHE." - #define MSG_CONTROL_RETRACT " Retractation mm:" - #define MSG_CONTROL_RETRACTF " Retractation F:" - #define MSG_CONTROL_RETRACT_ZLIFT " Hop mm:" - #define MSG_CONTROL_RETRACT_RECOVER " UnRet +mm:" - #define MSG_CONTROL_RETRACT_RECOVERF " UnRet F:" - #define MSG_AUTORETRACT " Retract. Auto.:" - #define MSG_FILAMENTCHANGE "Change filament" + #define MSG_CONTROL_RETRACT "Retraction mm" + #define MSG_CONTROL_RETRACTF "Retraction F" + #define MSG_CONTROL_RETRACT_ZLIFT "Hop mm" + #define MSG_CONTROL_RETRACT_RECOVER "UnRet +mm" + #define MSG_CONTROL_RETRACT_RECOVERF "UnRet F" + #define MSG_AUTORETRACT "Retract. Auto." + #define MSG_FILAMENTCHANGE "Changer filament" #define MSG_INIT_SDCARD "Init. la carte SD" #define MSG_CNG_SDCARD "Changer de carte SD" From 1902d339b0d5e9fef5fdc31456d852fa3ea436bb Mon Sep 17 00:00:00 2001 From: Guillaume Seguin Date: Sun, 28 Jul 2013 19:19:57 +0200 Subject: [PATCH 006/256] Add Panelolu2 pins for RAMPS1.3 --- Marlin/pins.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Marlin/pins.h b/Marlin/pins.h index 60235800a4..4e53d07ac2 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -485,6 +485,14 @@ #define BTN_ENC 35 #define SDCARDDETECT 49 + #elif defined(LCD_I2C_PANELOLU2) + #define BTN_EN1 47 //reverse if the encoder turns the wrong way. + #define BTN_EN2 43 + #define BTN_ENC 32 + #define SDSS 53 + #define SDCARDDETECT -1 + #define KILL_PIN 41 + #define FAN_PIN 45 #else //arduino pin which triggers an piezzo beeper #define BEEPER 33 // Beeper on AUX-4 From 55c287a69e7a3fb38220328b5eb938999af1d1d4 Mon Sep 17 00:00:00 2001 From: Nicolas Rossi Date: Sun, 28 Jul 2013 22:54:37 +0200 Subject: [PATCH 007/256] Fixed move from panel for delta bot #557 --- Marlin/Marlin.h | 1 + Marlin/Marlin_main.cpp | 7 ++++--- Marlin/ultralcd.cpp | 20 ++++++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index 1ae9494e34..b92d81072a 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -163,6 +163,7 @@ void ClearToSend(); void get_coordinates(); #ifdef DELTA void calculate_delta(float cartesian[3]); +extern float delta[3]; #endif void prepare_move(); void kill(); diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 886edca490..007991781b 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -198,14 +198,15 @@ int EtoPPressure=0; bool powersupply = true; #endif +#ifdef DELTA +float delta[3] = {0.0, 0.0, 0.0}; +#endif + //=========================================================================== //=============================private variables============================= //=========================================================================== const char axis_codes[NUM_AXIS] = {'X', 'Y', 'Z', 'E'}; static float destination[NUM_AXIS] = { 0.0, 0.0, 0.0, 0.0}; -#ifdef DELTA -static float delta[3] = {0.0, 0.0, 0.0}; -#endif static float offset[3] = {0.0, 0.0, 0.0}; static bool home_all_axis = true; static float feedrate = 1500.0, next_feedrate, saved_feedrate; diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index f6fc82d40c..163c414293 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -374,7 +374,12 @@ static void lcd_move_x() if (max_software_endstops && current_position[X_AXIS] > X_MAX_POS) current_position[X_AXIS] = X_MAX_POS; encoderPosition = 0; + #ifdef DELTA + calculate_delta(current_position); + plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], 600, active_extruder); + #else plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600, active_extruder); + #endif lcdDrawUpdate = 1; } if (lcdDrawUpdate) @@ -398,7 +403,12 @@ static void lcd_move_y() if (max_software_endstops && current_position[Y_AXIS] > Y_MAX_POS) current_position[Y_AXIS] = Y_MAX_POS; encoderPosition = 0; + #ifdef DELTA + calculate_delta(current_position); + plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], 600, active_extruder); + #else plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600, active_extruder); + #endif lcdDrawUpdate = 1; } if (lcdDrawUpdate) @@ -422,7 +432,12 @@ static void lcd_move_z() if (max_software_endstops && current_position[Z_AXIS] > Z_MAX_POS) current_position[Z_AXIS] = Z_MAX_POS; encoderPosition = 0; + #ifdef DELTA + calculate_delta(current_position); + plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS]/60, active_extruder); + #else plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS]/60, active_extruder); + #endif lcdDrawUpdate = 1; } if (lcdDrawUpdate) @@ -442,7 +457,12 @@ static void lcd_move_e() { current_position[E_AXIS] += float((int)encoderPosition) * move_menu_scale; encoderPosition = 0; + #ifdef DELTA + calculate_delta(current_position); + plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], 20, active_extruder); + #else plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 20, active_extruder); + #endif lcdDrawUpdate = 1; } if (lcdDrawUpdate) From be2dea1dc622f9057af23e0510da773c2fc81663 Mon Sep 17 00:00:00 2001 From: Brendan-csel Date: Mon, 29 Jul 2013 20:58:09 +1200 Subject: [PATCH 008/256] Save LCD_CLICKED before it is cleared The SD card menu was refreshing so slowly that the button interrupt was clearing LCD_CLICKED before the menu items could check it. --- Marlin/ultralcd.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index f6fc82d40c..df17a30330 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -96,6 +96,7 @@ static void menu_action_setting_edit_callback_long5(const char* pstr, unsigned l if (encoderPosition > 0x8000) encoderPosition = 0; \ if (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM < currentMenuViewOffset) currentMenuViewOffset = encoderPosition / ENCODER_STEPS_PER_MENU_ITEM;\ uint8_t _lineNr = currentMenuViewOffset, _menuItemNr; \ + bool wasClicked = LCD_CLICKED;\ for(uint8_t _drawLineNr = 0; _drawLineNr < LCD_HEIGHT; _drawLineNr++, _lineNr++) { \ _menuItemNr = 0; #define MENU_ITEM(type, label, args...) do { \ @@ -108,7 +109,7 @@ static void menu_action_setting_edit_callback_long5(const char* pstr, unsigned l lcd_implementation_drawmenu_ ## type (_drawLineNr, _label_pstr , ## args ); \ }\ }\ - if (LCD_CLICKED && (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) == _menuItemNr) {\ + if (wasClicked && (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) == _menuItemNr) {\ lcd_quick_feedback(); \ menu_action_ ## type ( args ); \ return;\ From d80aecda0a8dea4e15c15bb221fe9508cc355a63 Mon Sep 17 00:00:00 2001 From: Brendan-csel Date: Mon, 29 Jul 2013 21:00:29 +1200 Subject: [PATCH 009/256] Skip SD menu refresh if nothing has changed --- Marlin/ultralcd.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index df17a30330..f2c40575da 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -675,6 +675,8 @@ static void lcd_sd_updir() 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(); MENU_ITEM(back, MSG_MAIN, lcd_main_menu); From 376d8af2c8f2eb53583c9689f2871256f32a7e7f Mon Sep 17 00:00:00 2001 From: Guillaume Seguin Date: Wed, 29 May 2013 18:06:12 +0200 Subject: [PATCH 010/256] Report temperatures for all extruders --- Marlin/Marlin_main.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 007991781b..942b43bc1d 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1220,6 +1220,14 @@ void process_commands() SERIAL_PROTOCOL_F(degTargetBed(),1); #endif //TEMP_BED_PIN #else + for (int8_t cur_extruder = 0; cur_extruder < EXTRUDERS; ++cur_extruder) { + SERIAL_PROTOCOLPGM(" T"); + SERIAL_PROTOCOL(cur_extruder); + SERIAL_PROTOCOLPGM(":"); + SERIAL_PROTOCOL_F(degHotend(cur_extruder),1); + SERIAL_PROTOCOLPGM(" /"); + SERIAL_PROTOCOL_F(degTargetHotend(cur_extruder),1); + } SERIAL_ERROR_START; SERIAL_ERRORLNPGM(MSG_ERR_NO_THERMISTORS); #endif From 6c42a3a33969bc55a32998c489c78bc522b3f773 Mon Sep 17 00:00:00 2001 From: Guillaume Seguin Date: Tue, 23 Jul 2013 23:34:42 +0200 Subject: [PATCH 011/256] Woops, fix logic --- Marlin/Marlin_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 942b43bc1d..800cc8ae23 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1219,7 +1219,6 @@ void process_commands() SERIAL_PROTOCOLPGM(" /"); SERIAL_PROTOCOL_F(degTargetBed(),1); #endif //TEMP_BED_PIN - #else for (int8_t cur_extruder = 0; cur_extruder < EXTRUDERS; ++cur_extruder) { SERIAL_PROTOCOLPGM(" T"); SERIAL_PROTOCOL(cur_extruder); @@ -1228,6 +1227,7 @@ void process_commands() SERIAL_PROTOCOLPGM(" /"); SERIAL_PROTOCOL_F(degTargetHotend(cur_extruder),1); } + #else SERIAL_ERROR_START; SERIAL_ERRORLNPGM(MSG_ERR_NO_THERMISTORS); #endif From 4d435c38a64447209fe229aac7c0ff1af49cb4b2 Mon Sep 17 00:00:00 2001 From: Guillaume Seguin Date: Wed, 24 Jul 2013 12:09:53 +0200 Subject: [PATCH 012/256] Add support of LiquidTWI2-based panels to Makefile Use LIQUID_TWI2=1 as make argument to enable this support --- Marlin/Makefile | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/Marlin/Makefile b/Marlin/Makefile index a56bc1eab1..5cc25ea014 100644 --- a/Marlin/Makefile +++ b/Marlin/Makefile @@ -54,6 +54,9 @@ UPLOAD_PORT ?= /dev/arduino #Directory used to build files in, contains all the build files, from object files to the final hex file. BUILD_DIR ?= applet +# This defines whether Liquid_TWI2 support will be built +LIQUID_TWI2 ?= 0 + ############################################################################ # Below here nothing should be changed... @@ -199,9 +202,19 @@ VPATH += $(HARDWARE_SRC) ifeq ($(HARDWARE_VARIANT), arduino) VPATH += $(ARDUINO_INSTALL_DIR)/libraries/LiquidCrystal VPATH += $(ARDUINO_INSTALL_DIR)/libraries/SPI +ifeq ($(LIQUID_TWI2), 1) +VPATH += $(ARDUINO_INSTALL_DIR)/libraries/Wire +VPATH += $(ARDUINO_INSTALL_DIR)/libraries/Wire/utility +VPATH += $(ARDUINO_INSTALL_DIR)/libraries/LiquidTWI2 +endif else VPATH += $(HARDWARE_DIR)/libraries/LiquidCrystal VPATH += $(HARDWARE_DIR)/libraries/SPI +ifeq ($(LIQUID_TWI2), 1) +VPATH += $(HARDWARE_DIR)/libraries/Wire +VPATH += $(HARDWARE_DIR)/libraries/Wire/utility +VPATH += $(HARDWARE_DIR)/libraries/LiquidTWI2 +endif endif ifeq ($(HARDWARE_VARIANT), arduino) HARDWARE_SUB_VARIANT ?= mega @@ -218,8 +231,13 @@ CXXSRC = WMath.cpp WString.cpp Print.cpp Marlin_main.cpp \ MarlinSerial.cpp Sd2Card.cpp SdBaseFile.cpp SdFatUtil.cpp \ SdFile.cpp SdVolume.cpp motion_control.cpp planner.cpp \ stepper.cpp temperature.cpp cardreader.cpp ConfigurationStore.cpp \ - watchdog.cpp -CXXSRC += LiquidCrystal.cpp ultralcd.cpp SPI.cpp Servo.cpp Tone.cpp + watchdog.cpp SPI.cpp Servo.cpp Tone.cpp ultralcd.cpp +ifeq ($(LIQUID_TWI2), 0) +CXXSRC += LiquidCrystal.cpp +else +SRC += twi.c +CXXSRC += Wire.cpp LiquidTWI2.cpp +endif #Check for Arduino 1.0.0 or higher and use the correct sourcefiles for that version ifeq ($(shell [ $(ARDUINO_VERSION) -ge 100 ] && echo true), true) From aae42c68f94653b44c8ece27aa89a35152d7e4e3 Mon Sep 17 00:00:00 2001 From: Guillaume Seguin Date: Sun, 28 Jul 2013 18:18:41 +0200 Subject: [PATCH 013/256] Update French translation in language.h --- Marlin/language.h | 139 ++++++++++++++++++++++------------------------ 1 file changed, 67 insertions(+), 72 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index 17222c7cd2..39e459f94d 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -373,96 +373,91 @@ #if LANGUAGE_CHOICE == 3 - #define WELCOME_MSG MACHINE_NAME " Pret." + #define WELCOME_MSG MACHINE_NAME " prete." #define MSG_SD_INSERTED "Carte inseree" #define MSG_SD_REMOVED "Carte retiree" - #define MSG_MAIN " Principal \003" - #define MSG_AUTOSTART " Demarrage auto." - #define MSG_DISABLE_STEPPERS " Desactiver moteurs" - #define MSG_AUTO_HOME " Home auto." - #define MSG_SET_ORIGIN " Regler origine" + #define MSG_MAIN "Menu principal" + #define MSG_AUTOSTART "Demarrage auto" + #define MSG_DISABLE_STEPPERS "Arreter moteurs" + #define MSG_AUTO_HOME "Home auto." + #define MSG_SET_ORIGIN "Regler origine" #define MSG_PREHEAT_PLA " Prechauffage PLA" #define MSG_PREHEAT_PLA_SETTINGS " Regl. prechauffe PLA" - #define MSG_PREHEAT_ABS " Prechauffage ABS" - #define MSG_PREHEAT_ABS_SETTINGS " Regl. prechauffe ABS" - #define MSG_COOLDOWN " Refroidissement" - #define MSG_SWITCH_PS_ON "Allumer alimentation" - #define MSG_SWITCH_PS_OFF "Eteindre alimentation" - #define MSG_EXTRUDE " Extrusion" - #define MSG_RETRACT " Retractation" - #define MSG_PREHEAT_PLA " Prechauffage PLA" - #define MSG_PREHEAT_ABS " Prechauffage ABS" - #define MSG_MOVE_AXIS " Deplacer axe \x7E" - #define MSG_SPEED " Vitesse:" - #define MSG_NOZZLE " \002Buse:" - #define MSG_NOZZLE1 " \002Buse2:" - #define MSG_NOZZLE2 " \002Buse3:" - #define MSG_BED " \002Lit:" - #define MSG_FAN_SPEED " Vitesse ventilateur:" - #define MSG_FLOW " Flux:" - #define MSG_CONTROL " Controle \003" - #define MSG_MIN " \002 Min:" - #define MSG_MAX " \002 Max:" - #define MSG_FACTOR " \002 Facteur:" - #define MSG_AUTOTEMP " Temp. Auto.:" + #define MSG_PREHEAT_ABS "Prechauffage ABS" + #define MSG_PREHEAT_ABS_SETTINGS "Regl. prechauffe ABS" + #define MSG_COOLDOWN "Refroidir" + #define MSG_SWITCH_PS_ON "Allumer alim." + #define MSG_SWITCH_PS_OFF "Eteindre alim." + #define MSG_EXTRUDE "Extrusion" + #define MSG_RETRACT "Retraction" + #define MSG_PREHEAT_PLA "Prechauffage PLA" + #define MSG_PREHEAT_ABS "Prechauffage ABS" + #define MSG_MOVE_AXIS "Deplacer un axe" + #define MSG_SPEED " Vitesse" + #define MSG_NOZZLE "Buse" + #define MSG_NOZZLE1 "Buse2" + #define MSG_NOZZLE2 "Buse3" + #define MSG_BED "Plateau" + #define MSG_FAN_SPEED "Vitesse ventilateur" + #define MSG_FLOW "Flux" + #define MSG_CONTROL "Controler" + #define MSG_MIN " \002 Min" + #define MSG_MAX " \002 Max" + #define MSG_FACTOR " \002 Facteur" + #define MSG_AUTOTEMP "Temp. Auto." #define MSG_ON "Marche " #define MSG_OFF "Arret" - #define MSG_PID_P " PID-P: " - #define MSG_PID_I " PID-I: " - #define MSG_PID_D " PID-D: " - #define MSG_PID_C " PID-C: " - #define MSG_ACC " Acc:" + #define MSG_PID_P "PID-P" + #define MSG_PID_I "PID-I" + #define MSG_PID_D "PID-D" + #define MSG_PID_C "PID-C" + #define MSG_ACC "Accel" #define MSG_VXY_JERK "Vxy-jerk" #define MSG_VZ_JERK "Vz-jerk" #define MSG_VE_JERK "Ve-jerk" - #define MSG_VMAX " Vmax " - #define MSG_X "x:" - #define MSG_Y "y:" - #define MSG_Z "z:" - #define MSG_E "e:" - #define MSG_VMIN " Vmin:" - #define MSG_VTRAV_MIN " Vdepl min:" - #define MSG_AMAX " Amax " - #define MSG_A_RETRACT " A-retract:" - #define MSG_XSTEPS " Xpas/mm:" - #define MSG_YSTEPS " Ypas/mm:" - #define MSG_ZSTEPS " Zpas/mm:" - #define MSG_ESTEPS " Epas/mm:" - #define MSG_MAIN_WIDE " Principal \003" - #define MSG_RECTRACT "Rectracter" + #define MSG_VMAX "Vmax" + #define MSG_X "x" + #define MSG_Y "y" + #define MSG_Z "z" + #define MSG_E "e" + #define MSG_VMIN "Vmin" + #define MSG_VTRAV_MIN "Vdepl min" + #define MSG_AMAX "Amax " + #define MSG_A_RETRACT "A-retract" + #define MSG_XSTEPS "Xpas/mm" + #define MSG_YSTEPS "Ypas/mm" + #define MSG_ZSTEPS "Zpas/mm" + #define MSG_ESTEPS "Epas/mm" #define MSG_TEMPERATURE "Temperature" #define MSG_MOTION "Mouvement" - #define MSG_CONTRAST "LCD contrast" - #define MSG_STORE_EPROM " Sauvegarder memoire" - #define MSG_LOAD_EPROM " Lire memoire" - #define MSG_RESTORE_FAILSAFE " Restaurer memoire" - #define MSG_REFRESH "\004Actualiser" - #define MSG_WATCH " Surveiller \003" - #define MSG_PREPARE " Preparer \x7E" - #define MSG_PREPARE_ALT " Prepare \003" - #define MSG_CONTROL_ARROW " Controle \x7E" - #define MSG_RETRACT_ARROW " Retracter \x7E" - #define MSG_TUNE " Regler \x7E" - #define MSG_PAUSE_PRINT " Pause impression \x7E" - #define MSG_RESUME_PRINT " Reprendre impression \x7E" - #define MSG_STOP_PRINT " Arreter impression \x7E" - #define MSG_CARD_MENU " Menu carte \x7E" - #define MSG_NO_CARD " Pas de carte" + #define MSG_CONTRAST "Contraste LCD" + #define MSG_STORE_EPROM "Sauver config" + #define MSG_LOAD_EPROM "Lire config" + #define MSG_RESTORE_FAILSAFE "Restaurer defauts" + #define MSG_REFRESH "Actualiser" + #define MSG_WATCH "Surveiller" + #define MSG_PREPARE "Preparer" + #define MSG_TUNE "Regler" + #define MSG_PAUSE_PRINT "Interrompre impr." + #define MSG_RESUME_PRINT "Reprendre impr." + #define MSG_STOP_PRINT "Arreter impr." + #define MSG_CARD_MENU "Impr. depuis SD" + #define MSG_NO_CARD "Pas de carte" #define MSG_DWELL "Repos..." #define MSG_USERWAIT "Attente de l'utilisateur..." #define MSG_RESUMING "Reprise de l'impression" #define MSG_NO_MOVE "Aucun mouvement." #define MSG_PART_RELEASE "Relache partielle" - #define MSG_KILLED "TUE." + #define MSG_KILLED "MORT." #define MSG_STOPPED "STOPPE." #define MSG_STEPPER_RELEASED "RELACHE." - #define MSG_CONTROL_RETRACT " Retractation mm:" - #define MSG_CONTROL_RETRACTF " Retractation F:" - #define MSG_CONTROL_RETRACT_ZLIFT " Hop mm:" - #define MSG_CONTROL_RETRACT_RECOVER " UnRet +mm:" - #define MSG_CONTROL_RETRACT_RECOVERF " UnRet F:" - #define MSG_AUTORETRACT " Retract. Auto.:" - #define MSG_FILAMENTCHANGE "Change filament" + #define MSG_CONTROL_RETRACT "Retraction mm" + #define MSG_CONTROL_RETRACTF "Retraction F" + #define MSG_CONTROL_RETRACT_ZLIFT "Hop mm" + #define MSG_CONTROL_RETRACT_RECOVER "UnRet +mm" + #define MSG_CONTROL_RETRACT_RECOVERF "UnRet F" + #define MSG_AUTORETRACT "Retract. Auto." + #define MSG_FILAMENTCHANGE "Changer filament" #define MSG_INIT_SDCARD "Init. la carte SD" #define MSG_CNG_SDCARD "Changer de carte SD" From f4c3135c6da8d88776218c2257962d46d09d5e97 Mon Sep 17 00:00:00 2001 From: Guillaume Seguin Date: Sun, 28 Jul 2013 19:19:57 +0200 Subject: [PATCH 014/256] Add Panelolu2 pins for RAMPS1.3 --- Marlin/pins.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Marlin/pins.h b/Marlin/pins.h index 60235800a4..4e53d07ac2 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -485,6 +485,14 @@ #define BTN_ENC 35 #define SDCARDDETECT 49 + #elif defined(LCD_I2C_PANELOLU2) + #define BTN_EN1 47 //reverse if the encoder turns the wrong way. + #define BTN_EN2 43 + #define BTN_ENC 32 + #define SDSS 53 + #define SDCARDDETECT -1 + #define KILL_PIN 41 + #define FAN_PIN 45 #else //arduino pin which triggers an piezzo beeper #define BEEPER 33 // Beeper on AUX-4 From abc8320a689d567795bbf177352a2e86785af66e Mon Sep 17 00:00:00 2001 From: Brendan-csel Date: Mon, 29 Jul 2013 20:58:09 +1200 Subject: [PATCH 015/256] Save LCD_CLICKED before it is cleared The SD card menu was refreshing so slowly that the button interrupt was clearing LCD_CLICKED before the menu items could check it. --- Marlin/ultralcd.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 163c414293..25ed3ef9ce 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -96,6 +96,7 @@ static void menu_action_setting_edit_callback_long5(const char* pstr, unsigned l if (encoderPosition > 0x8000) encoderPosition = 0; \ if (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM < currentMenuViewOffset) currentMenuViewOffset = encoderPosition / ENCODER_STEPS_PER_MENU_ITEM;\ uint8_t _lineNr = currentMenuViewOffset, _menuItemNr; \ + bool wasClicked = LCD_CLICKED;\ for(uint8_t _drawLineNr = 0; _drawLineNr < LCD_HEIGHT; _drawLineNr++, _lineNr++) { \ _menuItemNr = 0; #define MENU_ITEM(type, label, args...) do { \ @@ -108,7 +109,7 @@ static void menu_action_setting_edit_callback_long5(const char* pstr, unsigned l lcd_implementation_drawmenu_ ## type (_drawLineNr, _label_pstr , ## args ); \ }\ }\ - if (LCD_CLICKED && (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) == _menuItemNr) {\ + if (wasClicked && (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) == _menuItemNr) {\ lcd_quick_feedback(); \ menu_action_ ## type ( args ); \ return;\ From d7f384f680479ab3e901196395d2ebf9bb584117 Mon Sep 17 00:00:00 2001 From: Brendan-csel Date: Mon, 29 Jul 2013 21:00:29 +1200 Subject: [PATCH 016/256] Skip SD menu refresh if nothing has changed --- Marlin/ultralcd.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 25ed3ef9ce..bb98421784 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -695,6 +695,8 @@ static void lcd_sd_updir() 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(); MENU_ITEM(back, MSG_MAIN, lcd_main_menu); From 4623e78ce0739437301b8e9944dbc761cad1f246 Mon Sep 17 00:00:00 2001 From: Nicolas Rossi Date: Tue, 30 Jul 2013 14:01:41 +0200 Subject: [PATCH 017/256] Added Honeywell thermistor 135-104LAF-J01 --- Marlin/Configuration.h | 1 + Marlin/thermistortables.h | 152 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index db02b1d5f6..158214a648 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -124,6 +124,7 @@ // 5 is 100K thermistor - ATC Semitec 104GT-2 (Used in ParCan) (4.7k pullup) // 6 is 100k EPCOS - Not as accurate as table 1 (created using a fluke thermocouple) (4.7k pullup) // 7 is 100k Honeywell thermistor 135-104LAG-J01 (4.7k pullup) +// 71 is 100k Honeywell thermistor 135-104LAF-J01 (4.7k pullup) // 8 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup) // 9 is 100k GE Sensing AL03006-58.2K-97-G1 (4.7k pullup) // 10 is 100k RS thermistor 198-961 (4.7k pullup) diff --git a/Marlin/thermistortables.h b/Marlin/thermistortables.h index 09182208f7..ecac95fe30 100644 --- a/Marlin/thermistortables.h +++ b/Marlin/thermistortables.h @@ -314,6 +314,158 @@ const short temptable_7[][2] PROGMEM = { {1023*OVERSAMPLENR, 0} //to allow internal 0 degrees C }; #endif + +#if (THERMISTORHEATER_0 == 71) || (THERMISTORHEATER_1 == 71) || (THERMISTORHEATER_2 == 71) || (THERMISTORBED == 71) // 100k Honeywell 135-104LAF-J01 +// R0 = 100000 Ohm +// T0 = 25 °C +// Beta = 3974 +// R1 = 0 Ohm +// R2 = 4700 Ohm +const short temptable_71[][2] PROGMEM = { + {35*OVERSAMPLENR, 300}, + {51*OVERSAMPLENR, 270}, + {54*OVERSAMPLENR, 265}, + {58*OVERSAMPLENR, 260}, + {59*OVERSAMPLENR, 258}, + {61*OVERSAMPLENR, 256}, + {63*OVERSAMPLENR, 254}, + {64*OVERSAMPLENR, 252}, + {66*OVERSAMPLENR, 250}, + {67*OVERSAMPLENR, 249}, + {68*OVERSAMPLENR, 248}, + {69*OVERSAMPLENR, 247}, + {70*OVERSAMPLENR, 246}, + {71*OVERSAMPLENR, 245}, + {72*OVERSAMPLENR, 244}, + {73*OVERSAMPLENR, 243}, + {74*OVERSAMPLENR, 242}, + {75*OVERSAMPLENR, 241}, + {76*OVERSAMPLENR, 240}, + {77*OVERSAMPLENR, 239}, + {78*OVERSAMPLENR, 238}, + {79*OVERSAMPLENR, 237}, + {80*OVERSAMPLENR, 236}, + {81*OVERSAMPLENR, 235}, + {82*OVERSAMPLENR, 234}, + {84*OVERSAMPLENR, 233}, + {85*OVERSAMPLENR, 232}, + {86*OVERSAMPLENR, 231}, + {87*OVERSAMPLENR, 230}, + {89*OVERSAMPLENR, 229}, + {90*OVERSAMPLENR, 228}, + {91*OVERSAMPLENR, 227}, + {92*OVERSAMPLENR, 226}, + {94*OVERSAMPLENR, 225}, + {95*OVERSAMPLENR, 224}, + {97*OVERSAMPLENR, 223}, + {98*OVERSAMPLENR, 222}, + {99*OVERSAMPLENR, 221}, + {101*OVERSAMPLENR, 220}, + {102*OVERSAMPLENR, 219}, + {104*OVERSAMPLENR, 218}, + {106*OVERSAMPLENR, 217}, + {107*OVERSAMPLENR, 216}, + {109*OVERSAMPLENR, 215}, + {110*OVERSAMPLENR, 214}, + {112*OVERSAMPLENR, 213}, + {114*OVERSAMPLENR, 212}, + {115*OVERSAMPLENR, 211}, + {117*OVERSAMPLENR, 210}, + {119*OVERSAMPLENR, 209}, + {121*OVERSAMPLENR, 208}, + {123*OVERSAMPLENR, 207}, + {125*OVERSAMPLENR, 206}, + {126*OVERSAMPLENR, 205}, + {128*OVERSAMPLENR, 204}, + {130*OVERSAMPLENR, 203}, + {132*OVERSAMPLENR, 202}, + {134*OVERSAMPLENR, 201}, + {136*OVERSAMPLENR, 200}, + {139*OVERSAMPLENR, 199}, + {141*OVERSAMPLENR, 198}, + {143*OVERSAMPLENR, 197}, + {145*OVERSAMPLENR, 196}, + {147*OVERSAMPLENR, 195}, + {150*OVERSAMPLENR, 194}, + {152*OVERSAMPLENR, 193}, + {154*OVERSAMPLENR, 192}, + {157*OVERSAMPLENR, 191}, + {159*OVERSAMPLENR, 190}, + {162*OVERSAMPLENR, 189}, + {164*OVERSAMPLENR, 188}, + {167*OVERSAMPLENR, 187}, + {170*OVERSAMPLENR, 186}, + {172*OVERSAMPLENR, 185}, + {175*OVERSAMPLENR, 184}, + {178*OVERSAMPLENR, 183}, + {181*OVERSAMPLENR, 182}, + {184*OVERSAMPLENR, 181}, + {187*OVERSAMPLENR, 180}, + {190*OVERSAMPLENR, 179}, + {193*OVERSAMPLENR, 178}, + {196*OVERSAMPLENR, 177}, + {199*OVERSAMPLENR, 176}, + {202*OVERSAMPLENR, 175}, + {205*OVERSAMPLENR, 174}, + {208*OVERSAMPLENR, 173}, + {212*OVERSAMPLENR, 172}, + {215*OVERSAMPLENR, 171}, + {219*OVERSAMPLENR, 170}, + {237*OVERSAMPLENR, 165}, + {256*OVERSAMPLENR, 160}, + {300*OVERSAMPLENR, 150}, + {351*OVERSAMPLENR, 140}, + {470*OVERSAMPLENR, 120}, + {504*OVERSAMPLENR, 115}, + {538*OVERSAMPLENR, 110}, + {552*OVERSAMPLENR, 108}, + {566*OVERSAMPLENR, 106}, + {580*OVERSAMPLENR, 104}, + {594*OVERSAMPLENR, 102}, + {608*OVERSAMPLENR, 100}, + {622*OVERSAMPLENR, 98}, + {636*OVERSAMPLENR, 96}, + {650*OVERSAMPLENR, 94}, + {664*OVERSAMPLENR, 92}, + {678*OVERSAMPLENR, 90}, + {712*OVERSAMPLENR, 85}, + {745*OVERSAMPLENR, 80}, + {758*OVERSAMPLENR, 78}, + {770*OVERSAMPLENR, 76}, + {783*OVERSAMPLENR, 74}, + {795*OVERSAMPLENR, 72}, + {806*OVERSAMPLENR, 70}, + {818*OVERSAMPLENR, 68}, + {829*OVERSAMPLENR, 66}, + {840*OVERSAMPLENR, 64}, + {850*OVERSAMPLENR, 62}, + {860*OVERSAMPLENR, 60}, + {870*OVERSAMPLENR, 58}, + {879*OVERSAMPLENR, 56}, + {888*OVERSAMPLENR, 54}, + {897*OVERSAMPLENR, 52}, + {905*OVERSAMPLENR, 50}, + {924*OVERSAMPLENR, 45}, + {940*OVERSAMPLENR, 40}, + {955*OVERSAMPLENR, 35}, + {967*OVERSAMPLENR, 30}, + {970*OVERSAMPLENR, 29}, + {972*OVERSAMPLENR, 28}, + {974*OVERSAMPLENR, 27}, + {976*OVERSAMPLENR, 26}, + {978*OVERSAMPLENR, 25}, + {980*OVERSAMPLENR, 24}, + {982*OVERSAMPLENR, 23}, + {984*OVERSAMPLENR, 22}, + {985*OVERSAMPLENR, 21}, + {987*OVERSAMPLENR, 20}, + {995*OVERSAMPLENR, 15}, + {1001*OVERSAMPLENR, 10}, + {1006*OVERSAMPLENR, 5}, + {1010*OVERSAMPLENR, 0}, +}; +#endif + #if (THERMISTORHEATER_0 == 8) || (THERMISTORHEATER_1 == 8) || (THERMISTORHEATER_2 == 8) || (THERMISTORBED == 8) // 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup) const short temptable_8[][2] PROGMEM = { From 9bf1cf1b22aa53b6b441854a6b17c0d58b470993 Mon Sep 17 00:00:00 2001 From: Nicolas Rossi Date: Tue, 30 Jul 2013 14:09:21 +0200 Subject: [PATCH 018/256] Pre-calculate diagonal rod length squared --- Marlin/Configuration.h | 3 +++ Marlin/Marlin_main.cpp | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 158214a648..9f6065f26e 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -107,6 +107,9 @@ #define DELTA_TOWER3_X 0.0 // back middle tower #define DELTA_TOWER3_Y DELTA_RADIUS +// Diagonal rod squared +#define DELTA_DIAGONAL_ROD_2 pow(DELTA_DIAGONAL_ROD,2) + //=========================================================================== //=============================Thermal Settings ============================ //=========================================================================== diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 800cc8ae23..c2fb9a7288 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -2254,15 +2254,15 @@ void clamp_to_software_endstops(float target[3]) #ifdef DELTA void calculate_delta(float cartesian[3]) { - delta[X_AXIS] = sqrt(sq(DELTA_DIAGONAL_ROD) + delta[X_AXIS] = sqrt(DELTA_DIAGONAL_ROD_2 - sq(DELTA_TOWER1_X-cartesian[X_AXIS]) - sq(DELTA_TOWER1_Y-cartesian[Y_AXIS]) ) + cartesian[Z_AXIS]; - delta[Y_AXIS] = sqrt(sq(DELTA_DIAGONAL_ROD) + delta[Y_AXIS] = sqrt(DELTA_DIAGONAL_ROD_2 - sq(DELTA_TOWER2_X-cartesian[X_AXIS]) - sq(DELTA_TOWER2_Y-cartesian[Y_AXIS]) ) + cartesian[Z_AXIS]; - delta[Z_AXIS] = sqrt(sq(DELTA_DIAGONAL_ROD) + delta[Z_AXIS] = sqrt(DELTA_DIAGONAL_ROD_2 - sq(DELTA_TOWER3_X-cartesian[X_AXIS]) - sq(DELTA_TOWER3_Y-cartesian[Y_AXIS]) ) + cartesian[Z_AXIS]; From 394ed08f8807979aaf7b1fd53939c84ecfa345d9 Mon Sep 17 00:00:00 2001 From: Nicolas Rossi Date: Tue, 30 Jul 2013 14:33:30 +0200 Subject: [PATCH 019/256] Added feedrate setting for manual moves from panel --- Marlin/Configuration_adv.h | 5 +++++ Marlin/ultralcd.cpp | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index f555d60692..58e8b2e6f3 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -193,6 +193,11 @@ #define DEFAULT_MINIMUMFEEDRATE 0.0 // minimum feedrate #define DEFAULT_MINTRAVELFEEDRATE 0.0 +// Feedrates for manual moves along X, Y, Z, E from panel +#ifdef ULTIPANEL +#define MANUAL_FEEDRATE {50*60, 50*60, 4*60, 60} // set the speeds for manual moves (mm/min) +#endif + // minimum time in microseconds that a movement needs to take if the buffer is emptied. #define DEFAULT_MINSEGMENTTIME 20000 diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index bb98421784..229e23e92d 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -18,6 +18,8 @@ int plaPreheatFanSpeed; int absPreheatHotendTemp; int absPreheatHPBTemp; int absPreheatFanSpeed; + +static float manual_feedrate[] = MANUAL_FEEDRATE; /* !Configuration settings */ //Function pointer to menu functions. @@ -377,9 +379,9 @@ static void lcd_move_x() encoderPosition = 0; #ifdef DELTA calculate_delta(current_position); - plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], 600, active_extruder); + plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[X_AXIS]/60, active_extruder); #else - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600, active_extruder); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[X_AXIS]/60, active_extruder); #endif lcdDrawUpdate = 1; } @@ -406,9 +408,9 @@ static void lcd_move_y() encoderPosition = 0; #ifdef DELTA calculate_delta(current_position); - plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], 600, active_extruder); + plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[Y_AXIS]/60, active_extruder); #else - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600, active_extruder); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[Y_AXIS]/60, active_extruder); #endif lcdDrawUpdate = 1; } @@ -435,9 +437,9 @@ static void lcd_move_z() encoderPosition = 0; #ifdef DELTA calculate_delta(current_position); - plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS]/60, active_extruder); + plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[Z_AXIS]/60, active_extruder); #else - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS]/60, active_extruder); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[Z_AXIS]/60, active_extruder); #endif lcdDrawUpdate = 1; } @@ -460,9 +462,9 @@ static void lcd_move_e() encoderPosition = 0; #ifdef DELTA calculate_delta(current_position); - plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], 20, active_extruder); + plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[E_AXIS]/60, active_extruder); #else - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 20, active_extruder); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[E_AXIS]/60, active_extruder); #endif lcdDrawUpdate = 1; } From a504c883468829d487f63a048996fe0db037daf2 Mon Sep 17 00:00:00 2001 From: daid Date: Thu, 1 Aug 2013 14:12:30 +0200 Subject: [PATCH 020/256] Fix a bug where the PID controllers D action kicks in hard as soon as the PID controller starts. --- Marlin/temperature.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index f5df7a1e72..5cbe1b4fa7 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -436,10 +436,9 @@ void manage_heater() //K1 defined in Configuration.h in the PID settings #define K2 (1.0-K1) dTerm[e] = (Kd * (pid_input - temp_dState[e]))*K2 + (K1 * dTerm[e]); - temp_dState[e] = pid_input; - pid_output = constrain(pTerm[e] + iTerm[e] - dTerm[e], 0, PID_MAX); } + temp_dState[e] = pid_input; #else pid_output = constrain(target_temperature[e], 0, PID_MAX); #endif //PID_OPENLOOP From 3700f688f5eb62843c2dba02fdeffeecf92bd1e4 Mon Sep 17 00:00:00 2001 From: "hg42@gmx.net" Date: Thu, 1 Aug 2013 14:56:39 +0200 Subject: [PATCH 021/256] convert PROTOCOL macros from statements to (multiple, comma separated) expressions --- Marlin/Marlin.h | 14 +++++++------- Marlin/temperature.cpp | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index b92d81072a..9881707896 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -51,22 +51,22 @@ #define MYSERIAL MSerial #endif -#define SERIAL_PROTOCOL(x) MYSERIAL.print(x); -#define SERIAL_PROTOCOL_F(x,y) MYSERIAL.print(x,y); -#define SERIAL_PROTOCOLPGM(x) serialprintPGM(PSTR(x)); -#define SERIAL_PROTOCOLLN(x) {MYSERIAL.print(x);MYSERIAL.write('\n');} -#define SERIAL_PROTOCOLLNPGM(x) {serialprintPGM(PSTR(x));MYSERIAL.write('\n');} +#define SERIAL_PROTOCOL(x) (MYSERIAL.print(x)) +#define SERIAL_PROTOCOL_F(x,y) (MYSERIAL.print(x,y)) +#define SERIAL_PROTOCOLPGM(x) (serialprintPGM(PSTR(x))) +#define SERIAL_PROTOCOLLN(x) (MYSERIAL.print(x),MYSERIAL.write('\n')) +#define SERIAL_PROTOCOLLNPGM(x) (serialprintPGM(PSTR(x)),MYSERIAL.write('\n')) const char errormagic[] PROGMEM ="Error:"; const char echomagic[] PROGMEM ="echo:"; -#define SERIAL_ERROR_START serialprintPGM(errormagic); +#define SERIAL_ERROR_START (serialprintPGM(errormagic)) #define SERIAL_ERROR(x) SERIAL_PROTOCOL(x) #define SERIAL_ERRORPGM(x) SERIAL_PROTOCOLPGM(x) #define SERIAL_ERRORLN(x) SERIAL_PROTOCOLLN(x) #define SERIAL_ERRORLNPGM(x) SERIAL_PROTOCOLLNPGM(x) -#define SERIAL_ECHO_START serialprintPGM(echomagic); +#define SERIAL_ECHO_START (serialprintPGM(echomagic)) #define SERIAL_ECHO(x) SERIAL_PROTOCOL(x) #define SERIAL_ECHOPGM(x) SERIAL_PROTOCOLPGM(x) #define SERIAL_ECHOLN(x) SERIAL_PROTOCOLLN(x) diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index f5df7a1e72..c732716b1d 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -244,7 +244,7 @@ void PID_autotune(float temp, int extruder, int ncycles) Kp = 0.6*Ku; Ki = 2*Kp/Tu; Kd = Kp*Tu/8; - SERIAL_PROTOCOLLNPGM(" Clasic PID ") + SERIAL_PROTOCOLLNPGM(" Clasic PID "); SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp); SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki); SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd); From 2ca983568d5cc658ba00ec0b92d5fd31455c0364 Mon Sep 17 00:00:00 2001 From: "hg42@gmx.net" Date: Thu, 1 Aug 2013 15:06:39 +0200 Subject: [PATCH 022/256] separate INVERTING for MIN and MAX endstops (6 #defines instead of 3) --- Marlin/Configuration.h | 29 ++- Marlin/Marlin_main.cpp | 76 +++--- .../delta/Configuration.h | 29 ++- Marlin/stepper.cpp | 238 +++++++++--------- 4 files changed, 189 insertions(+), 183 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index db02b1d5f6..bf2018674f 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -141,7 +141,7 @@ #define TEMP_SENSOR_BED 0 // This makes temp sensor 1 a redundant sensor for sensor 0. If the temperatures difference between these sensors is to high the print will be aborted. -//#define TEMP_SENSOR_1_AS_REDUNDANT +//#define TEMP_SENSOR_1_AS_REDUNDANT #define MAX_REDUNDANT_TEMP_SENSOR_DIFF 10 // Actual temperature must be close to target for this long before M109 returns success @@ -278,9 +278,12 @@ #endif // The pullups are needed if you directly connect a mechanical endswitch between the signal and ground pins. -const bool X_ENDSTOPS_INVERTING = true; // set to true to invert the logic of the endstops. -const bool Y_ENDSTOPS_INVERTING = true; // set to true to invert the logic of the endstops. -const bool Z_ENDSTOPS_INVERTING = true; // set to true to invert the logic of the endstops. +const bool X_MIN_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop. +const bool Y_MIN_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop. +const bool Z_MIN_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop. +const bool X_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop. +const bool Y_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop. +const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop. //#define DISABLE_MAX_ENDSTOPS //#define DISABLE_MIN_ENDSTOPS @@ -379,7 +382,7 @@ const bool Z_ENDSTOPS_INVERTING = true; // set to true to invert the logic of th //#define EEPROM_CHITCHAT // Preheat Constants -#define PLA_PREHEAT_HOTEND_TEMP 180 +#define PLA_PREHEAT_HOTEND_TEMP 180 #define PLA_PREHEAT_HPB_TEMP 70 #define PLA_PREHEAT_FAN_SPEED 255 // Insert Value between 0 and 255 @@ -464,7 +467,7 @@ const bool Z_ENDSTOPS_INVERTING = true; // set to true to invert the logic of th #define LCD_I2C_TYPE_PCF8575 #define LCD_I2C_ADDRESS 0x27 // I2C Address of the port expander #define NEWPANEL - #define ULTIPANEL + #define ULTIPANEL #endif // PANELOLU2 LCD with status LEDs, separate encoder and click inputs @@ -473,13 +476,13 @@ const bool Z_ENDSTOPS_INVERTING = true; // set to true to invert the logic of th // This uses the LiquidTWI2 library v1.2.3 or later ( https://github.com/lincomatic/LiquidTWI2 ) // Make sure the LiquidTWI2 directory is placed in the Arduino or Sketchbook libraries subdirectory. // (v1.2.3 no longer requires you to define PANELOLU in the LiquidTWI2.h library header file) - // Note: The PANELOLU2 encoder click input can either be directly connected to a pin - // (if BTN_ENC defined to != -1) or read through I2C (when BTN_ENC == -1). + // Note: The PANELOLU2 encoder click input can either be directly connected to a pin + // (if BTN_ENC defined to != -1) or read through I2C (when BTN_ENC == -1). #define LCD_I2C_TYPE_MCP23017 #define LCD_I2C_ADDRESS 0x20 // I2C Address of the port expander #define LCD_USE_I2C_BUZZER //comment out to disable buzzer on LCD #define NEWPANEL - #define ULTIPANEL + #define ULTIPANEL #endif // Panucatt VIKI LCD with status LEDs, integrated click & L/R/U/P buttons, separate encoder inputs @@ -489,11 +492,11 @@ const bool Z_ENDSTOPS_INVERTING = true; // set to true to invert the logic of th // Make sure the LiquidTWI2 directory is placed in the Arduino or Sketchbook libraries subdirectory. // Note: The pause/stop/resume LCD button pin should be connected to the Arduino // BTN_ENC pin (or set BTN_ENC to -1 if not used) - #define LCD_I2C_TYPE_MCP23017 + #define LCD_I2C_TYPE_MCP23017 #define LCD_I2C_ADDRESS 0x20 // I2C Address of the port expander #define LCD_USE_I2C_BUZZER //comment out to disable buzzer on LCD (requires LiquidTWI2 v1.2.3 or later) #define NEWPANEL - #define ULTIPANEL + #define ULTIPANEL #endif #ifdef ULTIPANEL @@ -565,10 +568,10 @@ const bool Z_ENDSTOPS_INVERTING = true; // set to true to invert the logic of th //#define NUM_SERVOS 3 // Servo index starts with 0 for M280 command // Servo Endstops -// +// // This allows for servo actuated endstops, primary usage is for the Z Axis to eliminate calibration or bed height changes. // Use M206 command to correct for switch height offset to actual nozzle height. Store that setting with M500. -// +// //#define SERVO_ENDSTOPS {-1, -1, 0} // Servo index for X, Y, Z. Disable with -1 //#define SERVO_ENDSTOP_ANGLES {0,0, 0,0, 70,0} // X,Y,Z Axis Extend and Retract angles diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 800cc8ae23..747668392c 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -431,10 +431,10 @@ void setup() lcd_init(); _delay_ms(1000); // wait 1sec to display the splash screen - + #if defined(CONTROLLERFAN_PIN) && CONTROLLERFAN_PIN > -1 SET_OUTPUT(CONTROLLERFAN_PIN); //Set pin used for driver cooling fan - #endif + #endif } @@ -691,15 +691,15 @@ XYZ_CONSTS_FROM_CONFIG(signed char, home_dir, HOME_DIR); #endif #if X_HOME_DIR != -1 || X2_HOME_DIR != 1 #error "Please use canonical x-carriage assignment" // the x-carriages are defined by their homing directions - #endif - + #endif + static float x_home_pos(int extruder) { if (extruder == 0) return base_home_pos(X_AXIS) + add_homeing[X_AXIS]; else // In dual carriage mode the extruder offset provides an override of the // second X-carriage offset when homed - otherwise X2_HOME_POS is used. - // This allow soft recalibration of the second extruder offset position without firmware reflash + // This allow soft recalibration of the second extruder offset position without firmware reflash // (through the M218 command). return (extruder_offset[X_AXIS][1] > 0) ? extruder_offset[X_AXIS][1] : X2_HOME_POS; } @@ -709,7 +709,7 @@ static int x_home_dir(int extruder) { } static float inactive_x_carriage_pos = X2_MAX_POS; -#endif +#endif static void axis_is_at_home(int axis) { #ifdef DUAL_X_CARRIAGE @@ -719,7 +719,7 @@ static void axis_is_at_home(int axis) { max_pos[X_AXIS] = max(extruder_offset[X_AXIS][1], X2_MAX_POS); return; } -#endif +#endif current_position[axis] = base_home_pos(axis) + add_homeing[axis]; min_pos[axis] = base_min_pos(axis) + add_homeing[axis]; max_pos[axis] = base_max_pos(axis) + add_homeing[axis]; @@ -745,7 +745,7 @@ static void homeaxis(int axis) { servos[servo_endstops[axis]].write(servo_endstop_angles[axis * 2]); } #endif - + current_position[axis] = 0; plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); destination[axis] = 1.5 * max_length(axis) * axis_home_dir; @@ -879,7 +879,7 @@ void process_commands() current_position[X_AXIS] = 0; current_position[Y_AXIS] = 0; current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); destination[X_AXIS] = 3 * Z_MAX_LENGTH; destination[Y_AXIS] = 3 * Z_MAX_LENGTH; @@ -892,7 +892,7 @@ void process_commands() current_position[X_AXIS] = destination[X_AXIS]; current_position[Y_AXIS] = destination[Y_AXIS]; current_position[Z_AXIS] = destination[Z_AXIS]; - + // take care of back off and rehome now we are all at the top HOMEAXIS(X); HOMEAXIS(Y); @@ -921,7 +921,7 @@ void process_commands() #else int x_axis_home_dir = x_home_dir(active_extruder); #endif - + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); destination[X_AXIS] = 1.5 * max_length(X_AXIS) * x_axis_home_dir;destination[Y_AXIS] = 1.5 * max_length(Y_AXIS) * home_dir(Y_AXIS); feedrate = homing_feedrate[X_AXIS]; @@ -954,7 +954,7 @@ void process_commands() HOMEAXIS(X); inactive_x_carriage_pos = current_position[X_AXIS]; active_extruder = tmp_extruder; - #endif + #endif HOMEAXIS(X); } @@ -988,7 +988,7 @@ void process_commands() } plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); #endif // else DELTA - + #ifdef ENDSTOPS_ONLY_FOR_HOMING enable_endstops(false); #endif @@ -1223,9 +1223,9 @@ void process_commands() SERIAL_PROTOCOLPGM(" T"); SERIAL_PROTOCOL(cur_extruder); SERIAL_PROTOCOLPGM(":"); - SERIAL_PROTOCOL_F(degHotend(cur_extruder),1); + SERIAL_PROTOCOL_F(degHotend(cur_extruder),1); SERIAL_PROTOCOLPGM(" /"); - SERIAL_PROTOCOL_F(degTargetHotend(cur_extruder),1); + SERIAL_PROTOCOL_F(degTargetHotend(cur_extruder),1); } #else SERIAL_ERROR_START; @@ -1250,7 +1250,7 @@ void process_commands() #ifdef AUTOTEMP autotemp_enabled=false; #endif - if (code_seen('S')) { + if (code_seen('S')) { setTargetHotend(code_value(), tmp_extruder); CooldownNoWait = true; } else if (code_seen('R')) { @@ -1327,7 +1327,7 @@ void process_commands() case 190: // M190 - Wait for bed heater to reach target. #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1 LCD_MESSAGEPGM(MSG_BED_HEATING); - if (code_seen('S')) { + if (code_seen('S')) { setTargetBed(code_value()); CooldownNoWait = true; } else if (code_seen('R')) { @@ -1335,9 +1335,9 @@ void process_commands() CooldownNoWait = false; } codenum = millis(); - + target_direction = isHeatingBed(); // true if heating, false if cooling - + while ( target_direction ? (isHeatingBed()) : (isCoolingBed()&&(CooldownNoWait==false)) ) { if(( millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. @@ -1417,7 +1417,7 @@ void process_commands() #endif break; #endif - + case 81: // M81 - Turn off Power Supply disable_heater(); st_synchronize(); @@ -1542,27 +1542,27 @@ void process_commands() SERIAL_PROTOCOLLN(MSG_M119_REPORT); #if defined(X_MIN_PIN) && X_MIN_PIN > -1 SERIAL_PROTOCOLPGM(MSG_X_MIN); - SERIAL_PROTOCOLLN(((READ(X_MIN_PIN)^X_ENDSTOPS_INVERTING)?MSG_ENDSTOP_HIT:MSG_ENDSTOP_OPEN)); + SERIAL_PROTOCOLLN(((READ(X_MIN_PIN)^X_MIN_ENDSTOP_INVERTING)?MSG_ENDSTOP_HIT:MSG_ENDSTOP_OPEN)); #endif #if defined(X_MAX_PIN) && X_MAX_PIN > -1 SERIAL_PROTOCOLPGM(MSG_X_MAX); - SERIAL_PROTOCOLLN(((READ(X_MAX_PIN)^X_ENDSTOPS_INVERTING)?MSG_ENDSTOP_HIT:MSG_ENDSTOP_OPEN)); + SERIAL_PROTOCOLLN(((READ(X_MAX_PIN)^X_MAX_ENDSTOP_INVERTING)?MSG_ENDSTOP_HIT:MSG_ENDSTOP_OPEN)); #endif #if defined(Y_MIN_PIN) && Y_MIN_PIN > -1 SERIAL_PROTOCOLPGM(MSG_Y_MIN); - SERIAL_PROTOCOLLN(((READ(Y_MIN_PIN)^Y_ENDSTOPS_INVERTING)?MSG_ENDSTOP_HIT:MSG_ENDSTOP_OPEN)); + SERIAL_PROTOCOLLN(((READ(Y_MIN_PIN)^Y_MIN_ENDSTOP_INVERTING)?MSG_ENDSTOP_HIT:MSG_ENDSTOP_OPEN)); #endif #if defined(Y_MAX_PIN) && Y_MAX_PIN > -1 SERIAL_PROTOCOLPGM(MSG_Y_MAX); - SERIAL_PROTOCOLLN(((READ(Y_MAX_PIN)^Y_ENDSTOPS_INVERTING)?MSG_ENDSTOP_HIT:MSG_ENDSTOP_OPEN)); + SERIAL_PROTOCOLLN(((READ(Y_MAX_PIN)^Y_MAX_ENDSTOP_INVERTING)?MSG_ENDSTOP_HIT:MSG_ENDSTOP_OPEN)); #endif #if defined(Z_MIN_PIN) && Z_MIN_PIN > -1 SERIAL_PROTOCOLPGM(MSG_Z_MIN); - SERIAL_PROTOCOLLN(((READ(Z_MIN_PIN)^Z_ENDSTOPS_INVERTING)?MSG_ENDSTOP_HIT:MSG_ENDSTOP_OPEN)); + SERIAL_PROTOCOLLN(((READ(Z_MIN_PIN)^Z_MIN_ENDSTOP_INVERTING)?MSG_ENDSTOP_HIT:MSG_ENDSTOP_OPEN)); #endif #if defined(Z_MAX_PIN) && Z_MAX_PIN > -1 SERIAL_PROTOCOLPGM(MSG_Z_MAX); - SERIAL_PROTOCOLLN(((READ(Z_MAX_PIN)^Z_ENDSTOPS_INVERTING)?MSG_ENDSTOP_HIT:MSG_ENDSTOP_OPEN)); + SERIAL_PROTOCOLLN(((READ(Z_MAX_PIN)^Z_MAX_ENDSTOP_INVERTING)?MSG_ENDSTOP_HIT:MSG_ENDSTOP_OPEN)); #endif break; //TODO: update for all axis, use for loop @@ -1699,7 +1699,7 @@ void process_commands() } } break; - + #if NUM_SERVOS > 0 case 280: // M280 - set servo position absolute. P: servo index, S: angle or microseconds { @@ -1987,7 +1987,7 @@ void process_commands() delay(3); WRITE(BEEPER,LOW); delay(3); - #else + #else lcd_buzz(1000/6,100); #endif } @@ -2103,8 +2103,8 @@ void process_commands() active_extruder = tmp_extruder; axis_is_at_home(X_AXIS); //this function updates X min/max values. current_position[X_AXIS] = inactive_x_carriage_pos; - inactive_x_carriage_pos = tmp_x_pos; - #else + inactive_x_carriage_pos = tmp_x_pos; + #else // Offset extruder (only by XY) int i; for(i = 0; i < 2; i++) { @@ -2340,10 +2340,10 @@ void prepare_arc_move(char isclockwise) { #if defined(CONTROLLERFAN_PIN) && CONTROLLERFAN_PIN > -1 #if defined(FAN_PIN) - #if CONTROLLERFAN_PIN == FAN_PIN + #if CONTROLLERFAN_PIN == FAN_PIN #error "You cannot set CONTROLLERFAN_PIN equal to FAN_PIN" #endif -#endif +#endif unsigned long lastMotor = 0; //Save the time for when a motor was turned on last unsigned long lastMotorCheck = 0; @@ -2368,17 +2368,17 @@ void controllerFan() { lastMotor = millis(); //... set time to NOW so the fan will turn on } - - if ((millis() - lastMotor) >= (CONTROLLERFAN_SECS*1000UL) || lastMotor == 0) //If the last time any driver was enabled, is longer since than CONTROLLERSEC... + + if ((millis() - lastMotor) >= (CONTROLLERFAN_SECS*1000UL) || lastMotor == 0) //If the last time any driver was enabled, is longer since than CONTROLLERSEC... { - digitalWrite(CONTROLLERFAN_PIN, 0); - analogWrite(CONTROLLERFAN_PIN, 0); + digitalWrite(CONTROLLERFAN_PIN, 0); + analogWrite(CONTROLLERFAN_PIN, 0); } else { // allows digital or PWM fan output to be used (see M42 handling) digitalWrite(CONTROLLERFAN_PIN, CONTROLLERFAN_SPEED); - analogWrite(CONTROLLERFAN_PIN, CONTROLLERFAN_SPEED); + analogWrite(CONTROLLERFAN_PIN, CONTROLLERFAN_SPEED); } } } @@ -2445,7 +2445,7 @@ void kill() #if defined(PS_ON_PIN) && PS_ON_PIN > -1 pinMode(PS_ON_PIN,INPUT); -#endif +#endif SERIAL_ERROR_START; SERIAL_ERRORLNPGM(MSG_ERR_KILLED); LCD_ALERTMESSAGEPGM(MSG_KILLED); diff --git a/Marlin/example_configurations/delta/Configuration.h b/Marlin/example_configurations/delta/Configuration.h index 7fbb4d85a2..cb92365696 100644 --- a/Marlin/example_configurations/delta/Configuration.h +++ b/Marlin/example_configurations/delta/Configuration.h @@ -141,7 +141,7 @@ #define TEMP_SENSOR_BED 0 // This makes temp sensor 1 a redundant sensor for sensor 0. If the temperatures difference between these sensors is to high the print will be aborted. -//#define TEMP_SENSOR_1_AS_REDUNDANT +//#define TEMP_SENSOR_1_AS_REDUNDANT #define MAX_REDUNDANT_TEMP_SENSOR_DIFF 10 // Actual temperature must be close to target for this long before M109 returns success @@ -278,9 +278,12 @@ #endif // The pullups are needed if you directly connect a mechanical endswitch between the signal and ground pins. -const bool X_ENDSTOPS_INVERTING = false; // set to true to invert the logic of the endstops. -const bool Y_ENDSTOPS_INVERTING = false; // set to true to invert the logic of the endstops. -const bool Z_ENDSTOPS_INVERTING = false; // set to true to invert the logic of the endstops. +const bool X_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop. +const bool Y_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop. +const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop. +const bool X_MAX_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop. +const bool Y_MAX_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop. +const bool Z_MAX_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop. // deltas never have min endstops #define DISABLE_MIN_ENDSTOPS @@ -386,7 +389,7 @@ const bool Z_ENDSTOPS_INVERTING = false; // set to true to invert the logic of t //#define EEPROM_CHITCHAT // Preheat Constants -#define PLA_PREHEAT_HOTEND_TEMP 180 +#define PLA_PREHEAT_HOTEND_TEMP 180 #define PLA_PREHEAT_HPB_TEMP 70 #define PLA_PREHEAT_FAN_SPEED 255 // Insert Value between 0 and 255 @@ -471,7 +474,7 @@ const bool Z_ENDSTOPS_INVERTING = false; // set to true to invert the logic of t #define LCD_I2C_TYPE_PCF8575 #define LCD_I2C_ADDRESS 0x27 // I2C Address of the port expander #define NEWPANEL - #define ULTIPANEL + #define ULTIPANEL #endif // PANELOLU2 LCD with status LEDs, separate encoder and click inputs @@ -480,13 +483,13 @@ const bool Z_ENDSTOPS_INVERTING = false; // set to true to invert the logic of t // This uses the LiquidTWI2 library v1.2.3 or later ( https://github.com/lincomatic/LiquidTWI2 ) // Make sure the LiquidTWI2 directory is placed in the Arduino or Sketchbook libraries subdirectory. // (v1.2.3 no longer requires you to define PANELOLU in the LiquidTWI2.h library header file) - // Note: The PANELOLU2 encoder click input can either be directly connected to a pin - // (if BTN_ENC defined to != -1) or read through I2C (when BTN_ENC == -1). + // Note: The PANELOLU2 encoder click input can either be directly connected to a pin + // (if BTN_ENC defined to != -1) or read through I2C (when BTN_ENC == -1). #define LCD_I2C_TYPE_MCP23017 #define LCD_I2C_ADDRESS 0x20 // I2C Address of the port expander #define LCD_USE_I2C_BUZZER //comment out to disable buzzer on LCD #define NEWPANEL - #define ULTIPANEL + #define ULTIPANEL #endif // Panucatt VIKI LCD with status LEDs, integrated click & L/R/U/P buttons, separate encoder inputs @@ -496,11 +499,11 @@ const bool Z_ENDSTOPS_INVERTING = false; // set to true to invert the logic of t // Make sure the LiquidTWI2 directory is placed in the Arduino or Sketchbook libraries subdirectory. // Note: The pause/stop/resume LCD button pin should be connected to the Arduino // BTN_ENC pin (or set BTN_ENC to -1 if not used) - #define LCD_I2C_TYPE_MCP23017 + #define LCD_I2C_TYPE_MCP23017 #define LCD_I2C_ADDRESS 0x20 // I2C Address of the port expander #define LCD_USE_I2C_BUZZER //comment out to disable buzzer on LCD (requires LiquidTWI2 v1.2.3 or later) #define NEWPANEL - #define ULTIPANEL + #define ULTIPANEL #endif #ifdef ULTIPANEL @@ -572,10 +575,10 @@ const bool Z_ENDSTOPS_INVERTING = false; // set to true to invert the logic of t //#define NUM_SERVOS 3 // Servo index starts with 0 for M280 command // Servo Endstops -// +// // This allows for servo actuated endstops, primary usage is for the Z Axis to eliminate calibration or bed height changes. // Use M206 command to correct for switch height offset to actual nozzle height. Store that setting with M500. -// +// //#define SERVO_ENDSTOPS {-1, -1, 0} // Servo index for X, Y, Z. Disable with -1 //#define SERVO_ENDSTOP_ANGLES {0,0, 0,0, 70,0} // X,Y,Z Axis Extend and Retract angles diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index 2f1d912600..0ba1001395 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -48,8 +48,8 @@ block_t *current_block; // A pointer to the block currently being traced // Variables used by The Stepper Driver Interrupt static unsigned char out_bits; // The next stepping-bits to be output static long counter_x, // Counter variables for the bresenham line tracer - counter_y, - counter_z, + counter_y, + counter_z, counter_e; volatile static unsigned long step_events_completed; // The number of step events executed in the current block #ifdef ADVANCE @@ -224,27 +224,27 @@ void enable_endstops(bool check) // | BLOCK 1 | BLOCK 2 | d // // time -----> -// -// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates -// first block->accelerate_until step_events_completed, then keeps going at constant speed until +// +// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates +// first block->accelerate_until step_events_completed, then keeps going at constant speed until // step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset. // The slope of acceleration is calculated with the leib ramp alghorithm. void st_wake_up() { // TCNT1 = 0; - ENABLE_STEPPER_DRIVER_INTERRUPT(); + ENABLE_STEPPER_DRIVER_INTERRUPT(); } void step_wait(){ for(int8_t i=0; i < 6; i++){ } } - + FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) { unsigned short timer; if(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY; - + if(step_rate > 20000) { // If steprate > 20kHz >> step 4 times step_rate = (step_rate >> 2)&0x3fff; step_loops = 4; @@ -255,11 +255,11 @@ FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) { } else { step_loops = 1; - } - + } + if(step_rate < (F_CPU/500000)) step_rate = (F_CPU/500000); step_rate -= (F_CPU/500000); // Correct for minimal speed - if(step_rate >= (8*256)){ // higher step rate + if(step_rate >= (8*256)){ // higher step rate unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0]; unsigned char tmp_step_rate = (step_rate & 0x00ff); unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2); @@ -276,7 +276,7 @@ FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) { return timer; } -// Initializes the trapezoid generator from the current block. Called whenever a new +// Initializes the trapezoid generator from the current block. Called whenever a new // block begins. FORCE_INLINE void trapezoid_generator_reset() { #ifdef ADVANCE @@ -284,7 +284,7 @@ FORCE_INLINE void trapezoid_generator_reset() { final_advance = current_block->final_advance; // Do E steps + advance steps e_steps[current_block->active_extruder] += ((advance >>8) - old_advance); - old_advance = advance >>8; + old_advance = advance >>8; #endif deceleration_time = 0; // step_rate to timer interval @@ -294,7 +294,7 @@ FORCE_INLINE void trapezoid_generator_reset() { acc_step_rate = current_block->initial_rate; acceleration_time = calc_timer(acc_step_rate); OCR1A = acceleration_time; - + // SERIAL_ECHO_START; // SERIAL_ECHOPGM("advance :"); // SERIAL_ECHO(current_block->advance/256.0); @@ -304,13 +304,13 @@ FORCE_INLINE void trapezoid_generator_reset() { // SERIAL_ECHO(current_block->initial_advance/256.0); // SERIAL_ECHOPGM("final advance :"); // SERIAL_ECHOLN(current_block->final_advance/256.0); - + } -// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. -// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. +// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. +// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. ISR(TIMER1_COMPA_vect) -{ +{ // If there is no current block, attempt to pop one from the buffer if (current_block == NULL) { // Anything in the buffer? @@ -322,24 +322,24 @@ ISR(TIMER1_COMPA_vect) counter_y = counter_x; counter_z = counter_x; counter_e = counter_x; - step_events_completed = 0; - - #ifdef Z_LATE_ENABLE + step_events_completed = 0; + + #ifdef Z_LATE_ENABLE if(current_block->steps_z > 0) { enable_z(); OCR1A = 2000; //1ms wait return; } #endif - + // #ifdef ADVANCE // e_steps[current_block->active_extruder] = 0; // #endif - } + } else { OCR1A=2000; // 1kHz. - } - } + } + } if (current_block != NULL) { // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt @@ -352,7 +352,7 @@ ISR(TIMER1_COMPA_vect) if (active_extruder != 0) WRITE(X2_DIR_PIN,INVERT_X_DIR); else - #endif + #endif WRITE(X_DIR_PIN, INVERT_X_DIR); count_direction[X_AXIS]=-1; } @@ -361,7 +361,7 @@ ISR(TIMER1_COMPA_vect) if (active_extruder != 0) WRITE(X2_DIR_PIN,!INVERT_X_DIR); else - #endif + #endif WRITE(X_DIR_PIN, !INVERT_X_DIR); count_direction[X_AXIS]=1; } @@ -373,7 +373,7 @@ ISR(TIMER1_COMPA_vect) WRITE(Y_DIR_PIN, !INVERT_Y_DIR); count_direction[Y_AXIS]=1; } - + // Set direction en check limit switches #ifndef COREXY if ((out_bits & (1< -1 - bool x_min_endstop=(READ(X_MIN_PIN) != X_ENDSTOPS_INVERTING); + bool x_min_endstop=(READ(X_MIN_PIN) != X_MIN_ENDSTOP_INVERTING); if(x_min_endstop && old_x_min_endstop && (current_block->steps_x > 0)) { endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; endstop_x_hit=true; @@ -400,15 +400,15 @@ ISR(TIMER1_COMPA_vect) } } else { // +direction - CHECK_ENDSTOPS + CHECK_ENDSTOPS { #ifdef DUAL_X_CARRIAGE // with 2 x-carriages, endstops are only checked in the homing direction for the active extruder if ((active_extruder == 0 && X_HOME_DIR == 1) || (active_extruder != 0 && X2_HOME_DIR == 1)) - #endif + #endif { #if defined(X_MAX_PIN) && X_MAX_PIN > -1 - bool x_max_endstop=(READ(X_MAX_PIN) != X_ENDSTOPS_INVERTING); + bool x_max_endstop=(READ(X_MAX_PIN) != X_MAX_ENDSTOP_INVERTING); if(x_max_endstop && old_x_max_endstop && (current_block->steps_x > 0)){ endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; endstop_x_hit=true; @@ -416,7 +416,7 @@ ISR(TIMER1_COMPA_vect) } old_x_max_endstop = x_max_endstop; #endif - } + } } } @@ -428,7 +428,7 @@ ISR(TIMER1_COMPA_vect) CHECK_ENDSTOPS { #if defined(Y_MIN_PIN) && Y_MIN_PIN > -1 - bool y_min_endstop=(READ(Y_MIN_PIN) != Y_ENDSTOPS_INVERTING); + bool y_min_endstop=(READ(Y_MIN_PIN) != Y_MIN_ENDSTOP_INVERTING); if(y_min_endstop && old_y_min_endstop && (current_block->steps_y > 0)) { endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; endstop_y_hit=true; @@ -442,7 +442,7 @@ ISR(TIMER1_COMPA_vect) CHECK_ENDSTOPS { #if defined(Y_MAX_PIN) && Y_MAX_PIN > -1 - bool y_max_endstop=(READ(Y_MAX_PIN) != Y_ENDSTOPS_INVERTING); + bool y_max_endstop=(READ(Y_MAX_PIN) != Y_MAX_ENDSTOP_INVERTING); if(y_max_endstop && old_y_max_endstop && (current_block->steps_y > 0)){ endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; endstop_y_hit=true; @@ -455,16 +455,16 @@ ISR(TIMER1_COMPA_vect) if ((out_bits & (1< -1 - bool z_min_endstop=(READ(Z_MIN_PIN) != Z_ENDSTOPS_INVERTING); + bool z_min_endstop=(READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING); if(z_min_endstop && old_z_min_endstop && (current_block->steps_z > 0)) { endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; endstop_z_hit=true; @@ -485,7 +485,7 @@ ISR(TIMER1_COMPA_vect) CHECK_ENDSTOPS { #if defined(Z_MAX_PIN) && Z_MAX_PIN > -1 - bool z_max_endstop=(READ(Z_MAX_PIN) != Z_ENDSTOPS_INVERTING); + bool z_max_endstop=(READ(Z_MAX_PIN) != Z_MAX_ENDSTOP_INVERTING); if(z_max_endstop && old_z_max_endstop && (current_block->steps_z > 0)) { endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; endstop_z_hit=true; @@ -506,10 +506,10 @@ ISR(TIMER1_COMPA_vect) count_direction[E_AXIS]=1; } #endif //!ADVANCE - - - for(int8_t i=0; i < step_loops; i++) { // Take multiple steps per interrupt (For high speed moves) + + + for(int8_t i=0; i < step_loops; i++) { // Take multiple steps per interrupt (For high speed moves) #ifndef AT90USB MSerial.checkRx(); // Check for serial chars. #endif @@ -524,7 +524,7 @@ ISR(TIMER1_COMPA_vect) else { e_steps[current_block->active_extruder]++; } - } + } #endif //ADVANCE counter_x += current_block->steps_x; @@ -533,38 +533,38 @@ ISR(TIMER1_COMPA_vect) if (active_extruder != 0) WRITE(X2_STEP_PIN,!INVERT_X_STEP_PIN); else - #endif + #endif WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); counter_x -= current_block->step_event_count; - count_position[X_AXIS]+=count_direction[X_AXIS]; + count_position[X_AXIS]+=count_direction[X_AXIS]; #ifdef DUAL_X_CARRIAGE if (active_extruder != 0) WRITE(X2_STEP_PIN,INVERT_X_STEP_PIN); else - #endif + #endif WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); } - + counter_y += current_block->steps_y; if (counter_y > 0) { WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN); - counter_y -= current_block->step_event_count; - count_position[Y_AXIS]+=count_direction[Y_AXIS]; + counter_y -= current_block->step_event_count; + count_position[Y_AXIS]+=count_direction[Y_AXIS]; WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN); } - + counter_z += current_block->steps_z; if (counter_z > 0) { WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); - + #ifdef Z_DUAL_STEPPER_DRIVERS WRITE(Z2_STEP_PIN, !INVERT_Z_STEP_PIN); #endif - + counter_z -= current_block->step_event_count; count_position[Z_AXIS]+=count_direction[Z_AXIS]; WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN); - + #ifdef Z_DUAL_STEPPER_DRIVERS WRITE(Z2_STEP_PIN, INVERT_Z_STEP_PIN); #endif @@ -579,17 +579,17 @@ ISR(TIMER1_COMPA_vect) WRITE_E_STEP(INVERT_E_STEP_PIN); } #endif //!ADVANCE - step_events_completed += 1; + step_events_completed += 1; if(step_events_completed >= current_block->step_event_count) break; } // Calculare new timer value unsigned short timer; unsigned short step_rate; if (step_events_completed <= (unsigned long int)current_block->accelerate_until) { - + MultiU24X24toH16(acc_step_rate, acceleration_time, current_block->acceleration_rate); acc_step_rate += current_block->initial_rate; - + // upper limit if(acc_step_rate > current_block->nominal_rate) acc_step_rate = current_block->nominal_rate; @@ -605,13 +605,13 @@ ISR(TIMER1_COMPA_vect) //if(advance > current_block->advance) advance = current_block->advance; // Do E steps + advance steps e_steps[current_block->active_extruder] += ((advance >>8) - old_advance); - old_advance = advance >>8; - + old_advance = advance >>8; + #endif - } - else if (step_events_completed > (unsigned long int)current_block->decelerate_after) { + } + else if (step_events_completed > (unsigned long int)current_block->decelerate_after) { MultiU24X24toH16(step_rate, deceleration_time, current_block->acceleration_rate); - + if(step_rate > acc_step_rate) { // Check step_rate stays positive step_rate = current_block->final_rate; } @@ -634,7 +634,7 @@ ISR(TIMER1_COMPA_vect) if(advance < final_advance) advance = final_advance; // Do E steps + advance steps e_steps[current_block->active_extruder] += ((advance >>8) - old_advance); - old_advance = advance >>8; + old_advance = advance >>8; #endif //ADVANCE } else { @@ -643,12 +643,12 @@ ISR(TIMER1_COMPA_vect) step_loops = step_loops_nominal; } - // If current block is finished, reset pointer + // If current block is finished, reset pointer if (step_events_completed >= current_block->step_event_count) { current_block = NULL; plan_discard_current_block(); - } - } + } + } } #ifdef ADVANCE @@ -667,7 +667,7 @@ ISR(TIMER1_COMPA_vect) WRITE(E0_DIR_PIN, INVERT_E0_DIR); e_steps[0]++; WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); - } + } else if (e_steps[0] > 0) { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); e_steps[0]--; @@ -681,7 +681,7 @@ ISR(TIMER1_COMPA_vect) WRITE(E1_DIR_PIN, INVERT_E1_DIR); e_steps[1]++; WRITE(E1_STEP_PIN, !INVERT_E_STEP_PIN); - } + } else if (e_steps[1] > 0) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); e_steps[1]--; @@ -696,7 +696,7 @@ ISR(TIMER1_COMPA_vect) WRITE(E2_DIR_PIN, INVERT_E2_DIR); e_steps[2]++; WRITE(E2_STEP_PIN, !INVERT_E_STEP_PIN); - } + } else if (e_steps[2] > 0) { WRITE(E2_DIR_PIN, !INVERT_E2_DIR); e_steps[2]--; @@ -712,7 +712,7 @@ void st_init() { digipot_init(); //Initialize Digipot Motor Current microstep_init(); //Initialize Microstepping Pins - + //Initialize Dir Pins #if defined(X_DIR_PIN) && X_DIR_PIN > -1 SET_OUTPUT(X_DIR_PIN); @@ -720,17 +720,17 @@ void st_init() #if defined(X2_DIR_PIN) && X2_DIR_PIN > -1 SET_OUTPUT(X2_DIR_PIN); #endif - #if defined(Y_DIR_PIN) && Y_DIR_PIN > -1 + #if defined(Y_DIR_PIN) && Y_DIR_PIN > -1 SET_OUTPUT(Y_DIR_PIN); #endif - #if defined(Z_DIR_PIN) && Z_DIR_PIN > -1 + #if defined(Z_DIR_PIN) && Z_DIR_PIN > -1 SET_OUTPUT(Z_DIR_PIN); #if defined(Z_DUAL_STEPPER_DRIVERS) && defined(Z2_DIR_PIN) && (Z2_DIR_PIN > -1) SET_OUTPUT(Z2_DIR_PIN); #endif #endif - #if defined(E0_DIR_PIN) && E0_DIR_PIN > -1 + #if defined(E0_DIR_PIN) && E0_DIR_PIN > -1 SET_OUTPUT(E0_DIR_PIN); #endif #if defined(E1_DIR_PIN) && (E1_DIR_PIN > -1) @@ -757,7 +757,7 @@ void st_init() #if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1 SET_OUTPUT(Z_ENABLE_PIN); if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH); - + #if defined(Z_DUAL_STEPPER_DRIVERS) && defined(Z2_ENABLE_PIN) && (Z2_ENABLE_PIN > -1) SET_OUTPUT(Z2_ENABLE_PIN); if(!Z_ENABLE_ON) WRITE(Z2_ENABLE_PIN,HIGH); @@ -777,67 +777,67 @@ void st_init() #endif //endstops and pullups - + #if defined(X_MIN_PIN) && X_MIN_PIN > -1 - SET_INPUT(X_MIN_PIN); + SET_INPUT(X_MIN_PIN); #ifdef ENDSTOPPULLUP_XMIN WRITE(X_MIN_PIN,HIGH); #endif #endif - + #if defined(Y_MIN_PIN) && Y_MIN_PIN > -1 - SET_INPUT(Y_MIN_PIN); + SET_INPUT(Y_MIN_PIN); #ifdef ENDSTOPPULLUP_YMIN WRITE(Y_MIN_PIN,HIGH); #endif #endif - + #if defined(Z_MIN_PIN) && Z_MIN_PIN > -1 - SET_INPUT(Z_MIN_PIN); + SET_INPUT(Z_MIN_PIN); #ifdef ENDSTOPPULLUP_ZMIN WRITE(Z_MIN_PIN,HIGH); #endif #endif - + #if defined(X_MAX_PIN) && X_MAX_PIN > -1 - SET_INPUT(X_MAX_PIN); + SET_INPUT(X_MAX_PIN); #ifdef ENDSTOPPULLUP_XMAX WRITE(X_MAX_PIN,HIGH); #endif #endif - + #if defined(Y_MAX_PIN) && Y_MAX_PIN > -1 - SET_INPUT(Y_MAX_PIN); + SET_INPUT(Y_MAX_PIN); #ifdef ENDSTOPPULLUP_YMAX WRITE(Y_MAX_PIN,HIGH); #endif #endif - + #if defined(Z_MAX_PIN) && Z_MAX_PIN > -1 - SET_INPUT(Z_MAX_PIN); + SET_INPUT(Z_MAX_PIN); #ifdef ENDSTOPPULLUP_ZMAX WRITE(Z_MAX_PIN,HIGH); #endif #endif - + //Initialize Step Pins - #if defined(X_STEP_PIN) && (X_STEP_PIN > -1) + #if defined(X_STEP_PIN) && (X_STEP_PIN > -1) SET_OUTPUT(X_STEP_PIN); WRITE(X_STEP_PIN,INVERT_X_STEP_PIN); disable_x(); - #endif - #if defined(X2_STEP_PIN) && (X2_STEP_PIN > -1) + #endif + #if defined(X2_STEP_PIN) && (X2_STEP_PIN > -1) SET_OUTPUT(X2_STEP_PIN); WRITE(X2_STEP_PIN,INVERT_X_STEP_PIN); disable_x(); - #endif - #if defined(Y_STEP_PIN) && (Y_STEP_PIN > -1) + #endif + #if defined(Y_STEP_PIN) && (Y_STEP_PIN > -1) SET_OUTPUT(Y_STEP_PIN); WRITE(Y_STEP_PIN,INVERT_Y_STEP_PIN); disable_y(); - #endif - #if defined(Z_STEP_PIN) && (Z_STEP_PIN > -1) + #endif + #if defined(Z_STEP_PIN) && (Z_STEP_PIN > -1) SET_OUTPUT(Z_STEP_PIN); WRITE(Z_STEP_PIN,INVERT_Z_STEP_PIN); #if defined(Z_DUAL_STEPPER_DRIVERS) && defined(Z2_STEP_PIN) && (Z2_STEP_PIN > -1) @@ -845,33 +845,33 @@ void st_init() WRITE(Z2_STEP_PIN,INVERT_Z_STEP_PIN); #endif disable_z(); - #endif - #if defined(E0_STEP_PIN) && (E0_STEP_PIN > -1) + #endif + #if defined(E0_STEP_PIN) && (E0_STEP_PIN > -1) SET_OUTPUT(E0_STEP_PIN); WRITE(E0_STEP_PIN,INVERT_E_STEP_PIN); disable_e0(); - #endif - #if defined(E1_STEP_PIN) && (E1_STEP_PIN > -1) + #endif + #if defined(E1_STEP_PIN) && (E1_STEP_PIN > -1) SET_OUTPUT(E1_STEP_PIN); WRITE(E1_STEP_PIN,INVERT_E_STEP_PIN); disable_e1(); - #endif - #if defined(E2_STEP_PIN) && (E2_STEP_PIN > -1) + #endif + #if defined(E2_STEP_PIN) && (E2_STEP_PIN > -1) SET_OUTPUT(E2_STEP_PIN); WRITE(E2_STEP_PIN,INVERT_E_STEP_PIN); disable_e2(); - #endif + #endif // waveform generation = 0100 = CTC TCCR1B &= ~(1< -1 const uint8_t digipot_motor_current[] = DIGIPOT_MOTOR_CURRENT; - - SPI.begin(); - pinMode(DIGIPOTSS_PIN, OUTPUT); - for(int i=0;i<=4;i++) + + SPI.begin(); + pinMode(DIGIPOTSS_PIN, OUTPUT); + for(int i=0;i<=4;i++) //digitalPotWrite(digipot_ch[i], digipot_motor_current[i]); digipot_current(i,digipot_motor_current[i]); #endif From c0c4c97db6fe92b61f0a169a9c96c0025cc4af07 Mon Sep 17 00:00:00 2001 From: Guillaume Seguin Date: Thu, 1 Aug 2013 19:20:27 +0200 Subject: [PATCH 023/256] Detect OS in Makefile to use the correct avrdude.conf path --- Marlin/Makefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Marlin/Makefile b/Marlin/Makefile index 5cc25ea014..59ec4d4f7e 100644 --- a/Marlin/Makefile +++ b/Marlin/Makefile @@ -312,7 +312,12 @@ LDFLAGS = -lm # Programming support using avrdude. Settings and variables. AVRDUDE_PORT = $(UPLOAD_PORT) AVRDUDE_WRITE_FLASH = -U flash:w:$(BUILD_DIR)/$(TARGET).hex:i -AVRDUDE_FLAGS = -D -C $(ARDUINO_INSTALL_DIR)/hardware/tools/avr/etc/avrdude.conf \ +ifeq ($(shell uname -s), Linux) +AVRDUDE_CONF = $(ARDUINO_INSTALL_DIR)/hardware/tools/avrdude.conf +else +AVRDUDE_CONF = $(ARDUINO_INSTALL_DIR)/hardware/tools/avr/etc/avrdude.conf +endif +AVRDUDE_FLAGS = -D -C $(AVRDUDE_CONF) \ -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ -b $(UPLOAD_RATE) From b0c8120fcc5d107b808bd7f85252c9235bd432b7 Mon Sep 17 00:00:00 2001 From: Nicolas Rossi Date: Sat, 3 Aug 2013 13:09:53 +0200 Subject: [PATCH 024/256] Added feedrate setting in exemple config for manual moves from panel --- Marlin/example_configurations/delta/Configuration_adv.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Marlin/example_configurations/delta/Configuration_adv.h b/Marlin/example_configurations/delta/Configuration_adv.h index f279b0e213..d3c2d1939b 100644 --- a/Marlin/example_configurations/delta/Configuration_adv.h +++ b/Marlin/example_configurations/delta/Configuration_adv.h @@ -195,6 +195,11 @@ #define DEFAULT_MINIMUMFEEDRATE 0.0 // minimum feedrate #define DEFAULT_MINTRAVELFEEDRATE 0.0 +// Feedrates for manual moves along X, Y, Z, E from panel +#ifdef ULTIPANEL +#define MANUAL_FEEDRATE {50*60, 50*60, 4*60, 60} // set the speeds for manual moves (mm/min) +#endif + // minimum time in microseconds that a movement needs to take if the buffer is emptied. #define DEFAULT_MINSEGMENTTIME 20000 From b42d24e31ef0060659236da1787bee87682fa68b Mon Sep 17 00:00:00 2001 From: Steve Kelly Date: Sat, 3 Aug 2013 11:37:12 -0500 Subject: [PATCH 025/256] add additional pins to avr2560 for rambo lcd --- Marlin/fastio.h | 96 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/Marlin/fastio.h b/Marlin/fastio.h index 0746bf12b9..b7fec27e10 100644 --- a/Marlin/fastio.h +++ b/Marlin/fastio.h @@ -1385,7 +1385,101 @@ pins #define DIO69_DDR DDRK #define DIO69_PWM NULL - +#define DIO70_PIN PING4 +#define DIO70_RPORT PING +#define DIO70_WPORT PORTG +#define DIO70_DDR DDRG +#define DIO70_PWM NULL + +#define DIO71_PIN PING3 +#define DIO71_RPORT PING +#define DIO71_WPORT PORTG +#define DIO71_DDR DDRG +#define DIO71_PWM NULL + +#define DIO72_PIN PINJ2 +#define DIO72_RPORT PINJ +#define DIO72_WPORT PORTJ +#define DIO72_DDR DDRJ +#define DIO72_PWM NULL + +#define DIO73_PIN PINJ3 +#define DIO73_RPORT PINJ +#define DIO73_WPORT PORTJ +#define DIO73_DDR DDRJ +#define DIO73_PWM NULL + +#define DIO74_PIN PINJ7 +#define DIO74_RPORT PINJ +#define DIO74_WPORT PORTJ +#define DIO74_DDR DDRJ +#define DIO74_PWM NULL + +#define DIO73_PIN PINJ4 +#define DIO73_RPORT PINJ +#define DIO73_WPORT PORTJ +#define DIO73_DDR DDRJ +#define DIO73_PWM NULL + +#define DIO76_PIN PINJ5 +#define DIO76_RPORT PINJ +#define DIO76_WPORT PORTJ +#define DIO76_DDR DDRJ +#define DIO76_PWM NULL + +#define DIO77_PIN PINJ6 +#define DIO77_RPORT PINJ +#define DIO77_WPORT PORTJ +#define DIO77_DDR DDRJ +#define DIO77_PWM NULL + +#define DIO78_PIN PINE2 +#define DIO78_RPORT PINE +#define DIO78_WPORT PORTE +#define DIO78_DDR DDRE +#define DIO78_PWM NULL + +#define DIO79_PIN PINE6 +#define DIO79_RPORT PINE +#define DIO79_WPORT PORTE +#define DIO79_DDR DDRE +#define DIO79_PWM NULL + +#define DIO80_PIN PINE7 +#define DIO80_RPORT PINE +#define DIO80_WPORT PORTE +#define DIO80_DDR DDRE +#define DIO80_PWM NULL + +#define DIO81_PIN PIND4 +#define DIO81_RPORT PIND +#define DIO81_WPORT PORTD +#define DIO81_DDR DDRD +#define DIO81_PWM NULL + +#define DIO82_PIN PIND5 +#define DIO82_RPORT PIND +#define DIO82_WPORT PORTD +#define DIO82_DDR DDRD +#define DIO82_PWM NULL + +#define DIO83_PIN PIND6 +#define DIO83_RPORT PIND +#define DIO83_WPORT PORTD +#define DIO83_DDR DDRD +#define DIO83_PWM NULL + +#define DIO84_PIN PINH2 +#define DIO84_RPORT PINH +#define DIO84_WPORT PORTH +#define DIO84_DDR DDRH +#define DIO84_PWM NULL + +#define DIO85_PIN PINH7 +#define DIO85_RPORT PINH +#define DIO85_WPORT PORTH +#define DIO85_DDR DDRH +#define DIO85_PWM NULL #undef PA0 #define PA0_PIN PINA0 From 53614e51442adaa6f254f8323e2fc0449e9b63dd Mon Sep 17 00:00:00 2001 From: Steve Kelly Date: Sat, 3 Aug 2013 11:45:53 -0500 Subject: [PATCH 026/256] add pins for rambo lcd --- Marlin/pins.h | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/Marlin/pins.h b/Marlin/pins.h index 4e53d07ac2..87556cc2f3 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -1723,9 +1723,74 @@ #define LED_PIN 13 #define FAN_PIN 8 #define PS_ON_PIN 4 -#define KILL_PIN -1 +#define KILL_PIN -1 //80 with Smart Controller LCD #define SUICIDE_PIN -1 //PIN that has to be turned on right after start, to keep power flowing. +#ifdef ULTRA_LCD + #define KILL_PIN 80 + #ifdef NEWPANEL + //arduino pin which triggers an piezzo beeper + #define BEEPER 79 // Beeper on AUX-4 + #define LCD_PINS_RS 70 + #define LCD_PINS_ENABLE 71 + #define LCD_PINS_D4 72 + #define LCD_PINS_D5 73 + #define LCD_PINS_D6 74 + #define LCD_PINS_D7 75 + + //buttons are directly attached using AUX-2 + #define BTN_EN1 76 + #define BTN_EN2 77 + #define BTN_ENC 78 //the click + + #define BLEN_C 2 + #define BLEN_B 1 + #define BLEN_A 0 + + #define SDCARDDETECT 81 // Ramps does not use this port + + //encoder rotation values + #define encrot0 0 + #define encrot1 2 + #define encrot2 3 + #define encrot3 1 + #else //old style panel with shift register + //arduino pin witch triggers an piezzo beeper + #define BEEPER 33 No Beeper added + //buttons are attached to a shift register + // Not wired this yet + // #define SHIFT_CLK 38 + // #define SHIFT_LD 42 + // #define SHIFT_OUT 40 + // #define SHIFT_EN 17 + + #define LCD_PINS_RS 75 + #define LCD_PINS_ENABLE 17 + #define LCD_PINS_D4 23 + #define LCD_PINS_D5 25 + #define LCD_PINS_D6 27 + #define LCD_PINS_D7 29 + + //encoder rotation values + #define encrot0 0 + #define encrot1 2 + #define encrot2 3 + #define encrot3 1 + + //bits in the shift register that carry the buttons for: + // left up center down right red + #define BL_LE 7 + #define BL_UP 6 + #define BL_MI 5 + #define BL_DW 4 + #define BL_RI 3 + #define BL_ST 2 + #define BLEN_B 1 + #define BLEN_A 0 + #endif +#endif //ULTRA_LCD + + #endif /**************************************************************************************** From d7b1a8ba3360c9974eb2b2768e5d15a02f162227 Mon Sep 17 00:00:00 2001 From: Steve Kelly Date: Sat, 3 Aug 2013 12:42:34 -0500 Subject: [PATCH 027/256] add rambo arduino addons --- ArduinoAddons/Arduino_1.x.x/rambo/boards.txt | 22 + .../rambo/cores/arduino/Arduino.h | 215 ++++++ .../Arduino_1.x.x/rambo/cores/arduino/CDC.cpp | 239 ++++++ .../rambo/cores/arduino/Client.h | 26 + .../Arduino_1.x.x/rambo/cores/arduino/HID.cpp | 520 +++++++++++++ .../rambo/cores/arduino/HardwareSerial.cpp | 519 +++++++++++++ .../rambo/cores/arduino/HardwareSerial.h | 115 +++ .../rambo/cores/arduino/IPAddress.cpp | 56 ++ .../rambo/cores/arduino/IPAddress.h | 76 ++ .../rambo/cores/arduino/Platform.h | 23 + .../rambo/cores/arduino/Print.cpp | 268 +++++++ .../Arduino_1.x.x/rambo/cores/arduino/Print.h | 81 +++ .../rambo/cores/arduino/Printable.h | 40 + .../rambo/cores/arduino/Server.h | 9 + .../rambo/cores/arduino/Stream.cpp | 270 +++++++ .../rambo/cores/arduino/Stream.h | 96 +++ .../rambo/cores/arduino/Tone.cpp | 616 ++++++++++++++++ .../rambo/cores/arduino/USBAPI.h | 196 +++++ .../rambo/cores/arduino/USBCore.cpp | 684 ++++++++++++++++++ .../rambo/cores/arduino/USBCore.h | 303 ++++++++ .../rambo/cores/arduino/USBDesc.h | 63 ++ .../Arduino_1.x.x/rambo/cores/arduino/Udp.h | 88 +++ .../rambo/cores/arduino/WCharacter.h | 168 +++++ .../rambo/cores/arduino/WInterrupts.c | 322 +++++++++ .../rambo/cores/arduino/WMath.cpp | 60 ++ .../rambo/cores/arduino/WString.cpp | 645 +++++++++++++++++ .../rambo/cores/arduino/WString.h | 205 ++++++ .../rambo/cores/arduino/binary.h | 515 +++++++++++++ .../rambo/cores/arduino/main.cpp | 20 + .../Arduino_1.x.x/rambo/cores/arduino/new.cpp | 18 + .../Arduino_1.x.x/rambo/cores/arduino/new.h | 22 + .../rambo/cores/arduino/wiring.c | 324 +++++++++ .../rambo/cores/arduino/wiring_analog.c | 282 ++++++++ .../rambo/cores/arduino/wiring_digital.c | 178 +++++ .../rambo/cores/arduino/wiring_private.h | 71 ++ .../rambo/cores/arduino/wiring_pulse.c | 69 ++ .../rambo/cores/arduino/wiring_shift.c | 55 ++ .../rambo/variants/standard/pins_arduino.h | 411 +++++++++++ 38 files changed, 7890 insertions(+) create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/boards.txt create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Arduino.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/CDC.cpp create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Client.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HID.cpp create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HardwareSerial.cpp create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HardwareSerial.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/IPAddress.cpp create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/IPAddress.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Platform.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Print.cpp create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Print.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Printable.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Server.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Stream.cpp create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Stream.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Tone.cpp create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBAPI.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBCore.cpp create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBCore.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBDesc.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Udp.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WCharacter.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WInterrupts.c create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WMath.cpp create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WString.cpp create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WString.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/binary.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/main.cpp create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/new.cpp create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/new.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring.c create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_analog.c create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_digital.c create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_private.h create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_pulse.c create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_shift.c create mode 100644 ArduinoAddons/Arduino_1.x.x/rambo/variants/standard/pins_arduino.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/boards.txt b/ArduinoAddons/Arduino_1.x.x/rambo/boards.txt new file mode 100644 index 0000000000..d0901653c9 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/boards.txt @@ -0,0 +1,22 @@ +# See: http://code.google.com/p/arduino/wiki/Platforms + +############################################################## + +mega2560.name=RAMBo + +mega2560.upload.protocol=wiring +mega2560.upload.maximum_size=258048 +mega2560.upload.speed=115200 + +mega2560.bootloader.low_fuses=0xFF +mega2560.bootloader.high_fuses=0xD8 +mega2560.bootloader.extended_fuses=0xFD +mega2560.bootloader.path=stk500v2 +mega2560.bootloader.file=stk500boot_v2_mega2560.hex +mega2560.bootloader.unlock_bits=0x3F +mega2560.bootloader.lock_bits=0x0F + +mega2560.build.mcu=atmega2560 +mega2560.build.f_cpu=16000000L +mega2560.build.core=arduino +mega2560.build.variant=standard diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Arduino.h b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Arduino.h new file mode 100644 index 0000000000..b265825894 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Arduino.h @@ -0,0 +1,215 @@ +#ifndef Arduino_h +#define Arduino_h + +#include +#include +#include + +#include +#include +#include + +#include "binary.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#define HIGH 0x1 +#define LOW 0x0 + +#define INPUT 0x0 +#define OUTPUT 0x1 +#define INPUT_PULLUP 0x2 + +#define true 0x1 +#define false 0x0 + +#define PI 3.1415926535897932384626433832795 +#define HALF_PI 1.5707963267948966192313216916398 +#define TWO_PI 6.283185307179586476925286766559 +#define DEG_TO_RAD 0.017453292519943295769236907684886 +#define RAD_TO_DEG 57.295779513082320876798154814105 + +#define SERIAL 0x0 +#define DISPLAY 0x1 + +#define LSBFIRST 0 +#define MSBFIRST 1 + +#define CHANGE 1 +#define FALLING 2 +#define RISING 3 + +#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) +#define DEFAULT 0 +#define EXTERNAL 1 +#define INTERNAL 2 +#else +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__) +#define INTERNAL1V1 2 +#define INTERNAL2V56 3 +#else +#define INTERNAL 3 +#endif +#define DEFAULT 1 +#define EXTERNAL 0 +#endif + +// undefine stdlib's abs if encountered +#ifdef abs +#undef abs +#endif + +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) +#define abs(x) ((x)>0?(x):-(x)) +#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) +#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) +#define radians(deg) ((deg)*DEG_TO_RAD) +#define degrees(rad) ((rad)*RAD_TO_DEG) +#define sq(x) ((x)*(x)) + +#define interrupts() sei() +#define noInterrupts() cli() + +#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L ) +#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() ) +#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() ) + +#define lowByte(w) ((uint8_t) ((w) & 0xff)) +#define highByte(w) ((uint8_t) ((w) >> 8)) + +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1UL << (bit))) +#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) +#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) + + +typedef unsigned int word; + +#define bit(b) (1UL << (b)) + +typedef uint8_t boolean; +typedef uint8_t byte; + +void init(void); + +void pinMode(uint8_t, uint8_t); +void digitalWrite(uint8_t, uint8_t); +int digitalRead(uint8_t); +int analogRead(uint8_t); +void analogReference(uint8_t mode); +void analogWrite(uint8_t, int); + +unsigned long millis(void); +unsigned long micros(void); +void delay(unsigned long); +void delayMicroseconds(unsigned int us); +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout); + +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); +uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); + +void attachInterrupt(uint8_t, void (*)(void), int mode); +void detachInterrupt(uint8_t); + +void setup(void); +void loop(void); + +// Get the bit location within the hardware port of the given virtual pin. +// This comes from the pins_*.c file for the active board configuration. + +#define analogInPinToBit(P) (P) + +// On the ATmega1280, the addresses of some of the port registers are +// greater than 255, so we can't store them in uint8_t's. +extern const uint16_t PROGMEM port_to_mode_PGM[]; +extern const uint16_t PROGMEM port_to_input_PGM[]; +extern const uint16_t PROGMEM port_to_output_PGM[]; + +extern const uint8_t PROGMEM digital_pin_to_port_PGM[]; +// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[]; +extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[]; +extern const uint8_t PROGMEM digital_pin_to_timer_PGM[]; + +// Get the bit location within the hardware port of the given virtual pin. +// This comes from the pins_*.c file for the active board configuration. +// +// These perform slightly better as macros compared to inline functions +// +#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) ) +#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) ) +#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) ) +#define analogInPinToBit(P) (P) +#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) ) +#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) ) +#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) ) + +#define NOT_A_PIN 0 +#define NOT_A_PORT 0 + +#ifdef ARDUINO_MAIN +#define PA 1 +#define PB 2 +#define PC 3 +#define PD 4 +#define PE 5 +#define PF 6 +#define PG 7 +#define PH 8 +#define PJ 10 +#define PK 11 +#define PL 12 +#endif + +#define NOT_ON_TIMER 0 +#define TIMER0A 1 +#define TIMER0B 2 +#define TIMER1A 3 +#define TIMER1B 4 +#define TIMER2 5 +#define TIMER2A 6 +#define TIMER2B 7 + +#define TIMER3A 8 +#define TIMER3B 9 +#define TIMER3C 10 +#define TIMER4A 11 +#define TIMER4B 12 +#define TIMER4C 13 +#define TIMER4D 14 +#define TIMER5A 15 +#define TIMER5B 16 +#define TIMER5C 17 + +#ifdef __cplusplus +} // extern "C" +#endif + +#ifdef __cplusplus +#include "WCharacter.h" +#include "WString.h" +#include "HardwareSerial.h" + +uint16_t makeWord(uint16_t w); +uint16_t makeWord(byte h, byte l); + +#define word(...) makeWord(__VA_ARGS__) + +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); + +void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0); +void noTone(uint8_t _pin); + +// WMath prototypes +long random(long); +long random(long, long); +void randomSeed(unsigned int); +long map(long, long, long, long, long); + +#endif + +#include "pins_arduino.h" + +#endif diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/CDC.cpp b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/CDC.cpp new file mode 100644 index 0000000000..701e48398f --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/CDC.cpp @@ -0,0 +1,239 @@ + + +/* Copyright (c) 2011, Peter Barrett +** +** Permission to use, copy, modify, and/or distribute this software for +** any purpose with or without fee is hereby granted, provided that the +** above copyright notice and this permission notice appear in all copies. +** +** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR +** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +** SOFTWARE. +*/ + +#include "Platform.h" +#include "USBAPI.h" +#include + +#if defined(USBCON) +#ifdef CDC_ENABLED + +#if (RAMEND < 1000) +#define SERIAL_BUFFER_SIZE 16 +#else +#define SERIAL_BUFFER_SIZE 64 +#endif + +struct ring_buffer +{ + unsigned char buffer[SERIAL_BUFFER_SIZE]; + volatile int head; + volatile int tail; +}; + +ring_buffer cdc_rx_buffer = { { 0 }, 0, 0}; + +typedef struct +{ + u32 dwDTERate; + u8 bCharFormat; + u8 bParityType; + u8 bDataBits; + u8 lineState; +} LineInfo; + +static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 }; + +#define WEAK __attribute__ ((weak)) + +extern const CDCDescriptor _cdcInterface PROGMEM; +const CDCDescriptor _cdcInterface = +{ + D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,1), + + // CDC communication interface + D_INTERFACE(CDC_ACM_INTERFACE,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0), + D_CDCCS(CDC_HEADER,0x10,0x01), // Header (1.10 bcd) + D_CDCCS(CDC_CALL_MANAGEMENT,1,1), // Device handles call management (not) + D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT,6), // SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported + D_CDCCS(CDC_UNION,CDC_ACM_INTERFACE,CDC_DATA_INTERFACE), // Communication interface is master, data interface is slave 0 + D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_ACM),USB_ENDPOINT_TYPE_INTERRUPT,0x10,0x40), + + // CDC data interface + D_INTERFACE(CDC_DATA_INTERFACE,2,CDC_DATA_INTERFACE_CLASS,0,0), + D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,0x40,0), + D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,0x40,0) +}; + +int WEAK CDC_GetInterface(u8* interfaceNum) +{ + interfaceNum[0] += 2; // uses 2 + return USB_SendControl(TRANSFER_PGM,&_cdcInterface,sizeof(_cdcInterface)); +} + +bool WEAK CDC_Setup(Setup& setup) +{ + u8 r = setup.bRequest; + u8 requestType = setup.bmRequestType; + + if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) + { + if (CDC_GET_LINE_CODING == r) + { + USB_SendControl(0,(void*)&_usbLineInfo,7); + return true; + } + } + + if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) + { + if (CDC_SET_LINE_CODING == r) + { + USB_RecvControl((void*)&_usbLineInfo,7); + return true; + } + + if (CDC_SET_CONTROL_LINE_STATE == r) + { + _usbLineInfo.lineState = setup.wValueL; + + // auto-reset into the bootloader is triggered when the port, already + // open at 1200 bps, is closed. this is the signal to start the watchdog + // with a relatively long period so it can finish housekeeping tasks + // like servicing endpoints before the sketch ends + if (1200 == _usbLineInfo.dwDTERate) { + // We check DTR state to determine if host port is open (bit 0 of lineState). + if ((_usbLineInfo.lineState & 0x01) == 0) { + *(uint16_t *)0x0800 = 0x7777; + wdt_enable(WDTO_120MS); + } else { + // Most OSs do some intermediate steps when configuring ports and DTR can + // twiggle more than once before stabilizing. + // To avoid spurious resets we set the watchdog to 250ms and eventually + // cancel if DTR goes back high. + + wdt_disable(); + wdt_reset(); + *(uint16_t *)0x0800 = 0x0; + } + } + return true; + } + } + return false; +} + + +int _serialPeek = -1; +void Serial_::begin(uint16_t baud_count) +{ +} + +void Serial_::end(void) +{ +} + +void Serial_::accept(void) +{ + ring_buffer *buffer = &cdc_rx_buffer; + int i = (unsigned int)(buffer->head+1) % SERIAL_BUFFER_SIZE; + + // if we should be storing the received character into the location + // just before the tail (meaning that the head would advance to the + // current location of the tail), we're about to overflow the buffer + // and so we don't write the character or advance the head. + + // while we have room to store a byte + while (i != buffer->tail) { + int c = USB_Recv(CDC_RX); + if (c == -1) + break; // no more data + buffer->buffer[buffer->head] = c; + buffer->head = i; + + i = (unsigned int)(buffer->head+1) % SERIAL_BUFFER_SIZE; + } +} + +int Serial_::available(void) +{ + ring_buffer *buffer = &cdc_rx_buffer; + return (unsigned int)(SERIAL_BUFFER_SIZE + buffer->head - buffer->tail) % SERIAL_BUFFER_SIZE; +} + +int Serial_::peek(void) +{ + ring_buffer *buffer = &cdc_rx_buffer; + if (buffer->head == buffer->tail) { + return -1; + } else { + return buffer->buffer[buffer->tail]; + } +} + +int Serial_::read(void) +{ + ring_buffer *buffer = &cdc_rx_buffer; + // if the head isn't ahead of the tail, we don't have any characters + if (buffer->head == buffer->tail) { + return -1; + } else { + unsigned char c = buffer->buffer[buffer->tail]; + buffer->tail = (unsigned int)(buffer->tail + 1) % SERIAL_BUFFER_SIZE; + return c; + } +} + +void Serial_::flush(void) +{ + USB_Flush(CDC_TX); +} + +size_t Serial_::write(uint8_t c) +{ + /* only try to send bytes if the high-level CDC connection itself + is open (not just the pipe) - the OS should set lineState when the port + is opened and clear lineState when the port is closed. + bytes sent before the user opens the connection or after + the connection is closed are lost - just like with a UART. */ + + // TODO - ZE - check behavior on different OSes and test what happens if an + // open connection isn't broken cleanly (cable is yanked out, host dies + // or locks up, or host virtual serial port hangs) + if (_usbLineInfo.lineState > 0) { + int r = USB_Send(CDC_TX,&c,1); + if (r > 0) { + return r; + } else { + setWriteError(); + return 0; + } + } + setWriteError(); + return 0; +} + +// This operator is a convenient way for a sketch to check whether the +// port has actually been configured and opened by the host (as opposed +// to just being connected to the host). It can be used, for example, in +// setup() before printing to ensure that an application on the host is +// actually ready to receive and display the data. +// We add a short delay before returning to fix a bug observed by Federico +// where the port is configured (lineState != 0) but not quite opened. +Serial_::operator bool() { + bool result = false; + if (_usbLineInfo.lineState > 0) + result = true; + delay(10); + return result; +} + +Serial_ Serial; + +#endif +#endif /* if defined(USBCON) */ diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Client.h b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Client.h new file mode 100644 index 0000000000..ea134838a2 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Client.h @@ -0,0 +1,26 @@ +#ifndef client_h +#define client_h +#include "Print.h" +#include "Stream.h" +#include "IPAddress.h" + +class Client : public Stream { + +public: + virtual int connect(IPAddress ip, uint16_t port) =0; + virtual int connect(const char *host, uint16_t port) =0; + virtual size_t write(uint8_t) =0; + virtual size_t write(const uint8_t *buf, size_t size) =0; + virtual int available() = 0; + virtual int read() = 0; + virtual int read(uint8_t *buf, size_t size) = 0; + virtual int peek() = 0; + virtual void flush() = 0; + virtual void stop() = 0; + virtual uint8_t connected() = 0; + virtual operator bool() = 0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; +}; + +#endif diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HID.cpp b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HID.cpp new file mode 100644 index 0000000000..ac63608449 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HID.cpp @@ -0,0 +1,520 @@ + + +/* Copyright (c) 2011, Peter Barrett +** +** Permission to use, copy, modify, and/or distribute this software for +** any purpose with or without fee is hereby granted, provided that the +** above copyright notice and this permission notice appear in all copies. +** +** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR +** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +** SOFTWARE. +*/ + +#include "Platform.h" +#include "USBAPI.h" +#include "USBDesc.h" + +#if defined(USBCON) +#ifdef HID_ENABLED + +//#define RAWHID_ENABLED + +// Singletons for mouse and keyboard + +Mouse_ Mouse; +Keyboard_ Keyboard; + +//================================================================================ +//================================================================================ + +// HID report descriptor + +#define LSB(_x) ((_x) & 0xFF) +#define MSB(_x) ((_x) >> 8) + +#define RAWHID_USAGE_PAGE 0xFFC0 +#define RAWHID_USAGE 0x0C00 +#define RAWHID_TX_SIZE 64 +#define RAWHID_RX_SIZE 64 + +extern const u8 _hidReportDescriptor[] PROGMEM; +const u8 _hidReportDescriptor[] = { + + // Mouse + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 54 + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x85, 0x01, // REPORT_ID (1) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x03, // USAGE_MAXIMUM (Button 3) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x09, 0x38, // USAGE (Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + + // Keyboard + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 47 + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x02, // REPORT_ID (2) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION + +#if RAWHID_ENABLED + // RAW HID + 0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), // 30 + 0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), + + 0xA1, 0x01, // Collection 0x01 + 0x85, 0x03, // REPORT_ID (3) + 0x75, 0x08, // report size = 8 bits + 0x15, 0x00, // logical minimum = 0 + 0x26, 0xFF, 0x00, // logical maximum = 255 + + 0x95, 64, // report count TX + 0x09, 0x01, // usage + 0x81, 0x02, // Input (array) + + 0x95, 64, // report count RX + 0x09, 0x02, // usage + 0x91, 0x02, // Output (array) + 0xC0 // end collection +#endif +}; + +extern const HIDDescriptor _hidInterface PROGMEM; +const HIDDescriptor _hidInterface = +{ + D_INTERFACE(HID_INTERFACE,1,3,0,0), + D_HIDREPORT(sizeof(_hidReportDescriptor)), + D_ENDPOINT(USB_ENDPOINT_IN (HID_ENDPOINT_INT),USB_ENDPOINT_TYPE_INTERRUPT,0x40,0x01) +}; + +//================================================================================ +//================================================================================ +// Driver + +u8 _hid_protocol = 1; +u8 _hid_idle = 1; + +#define WEAK __attribute__ ((weak)) + +int WEAK HID_GetInterface(u8* interfaceNum) +{ + interfaceNum[0] += 1; // uses 1 + return USB_SendControl(TRANSFER_PGM,&_hidInterface,sizeof(_hidInterface)); +} + +int WEAK HID_GetDescriptor(int i) +{ + return USB_SendControl(TRANSFER_PGM,_hidReportDescriptor,sizeof(_hidReportDescriptor)); +} + +void WEAK HID_SendReport(u8 id, const void* data, int len) +{ + USB_Send(HID_TX, &id, 1); + USB_Send(HID_TX | TRANSFER_RELEASE,data,len); +} + +bool WEAK HID_Setup(Setup& setup) +{ + u8 r = setup.bRequest; + u8 requestType = setup.bmRequestType; + if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) + { + if (HID_GET_REPORT == r) + { + //HID_GetReport(); + return true; + } + if (HID_GET_PROTOCOL == r) + { + //Send8(_hid_protocol); // TODO + return true; + } + } + + if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) + { + if (HID_SET_PROTOCOL == r) + { + _hid_protocol = setup.wValueL; + return true; + } + + if (HID_SET_IDLE == r) + { + _hid_idle = setup.wValueL; + return true; + } + } + return false; +} + +//================================================================================ +//================================================================================ +// Mouse + +Mouse_::Mouse_(void) : _buttons(0) +{ +} + +void Mouse_::begin(void) +{ +} + +void Mouse_::end(void) +{ +} + +void Mouse_::click(uint8_t b) +{ + _buttons = b; + move(0,0,0); + _buttons = 0; + move(0,0,0); +} + +void Mouse_::move(signed char x, signed char y, signed char wheel) +{ + u8 m[4]; + m[0] = _buttons; + m[1] = x; + m[2] = y; + m[3] = wheel; + HID_SendReport(1,m,4); +} + +void Mouse_::buttons(uint8_t b) +{ + if (b != _buttons) + { + _buttons = b; + move(0,0,0); + } +} + +void Mouse_::press(uint8_t b) +{ + buttons(_buttons | b); +} + +void Mouse_::release(uint8_t b) +{ + buttons(_buttons & ~b); +} + +bool Mouse_::isPressed(uint8_t b) +{ + if ((b & _buttons) > 0) + return true; + return false; +} + +//================================================================================ +//================================================================================ +// Keyboard + +Keyboard_::Keyboard_(void) +{ +} + +void Keyboard_::begin(void) +{ +} + +void Keyboard_::end(void) +{ +} + +void Keyboard_::sendReport(KeyReport* keys) +{ + HID_SendReport(2,keys,sizeof(KeyReport)); +} + +extern +const uint8_t _asciimap[128] PROGMEM; + +#define SHIFT 0x80 +const uint8_t _asciimap[128] = +{ + 0x00, // NUL + 0x00, // SOH + 0x00, // STX + 0x00, // ETX + 0x00, // EOT + 0x00, // ENQ + 0x00, // ACK + 0x00, // BEL + 0x2a, // BS Backspace + 0x2b, // TAB Tab + 0x28, // LF Enter + 0x00, // VT + 0x00, // FF + 0x00, // CR + 0x00, // SO + 0x00, // SI + 0x00, // DEL + 0x00, // DC1 + 0x00, // DC2 + 0x00, // DC3 + 0x00, // DC4 + 0x00, // NAK + 0x00, // SYN + 0x00, // ETB + 0x00, // CAN + 0x00, // EM + 0x00, // SUB + 0x00, // ESC + 0x00, // FS + 0x00, // GS + 0x00, // RS + 0x00, // US + + 0x2c, // ' ' + 0x1e|SHIFT, // ! + 0x34|SHIFT, // " + 0x20|SHIFT, // # + 0x21|SHIFT, // $ + 0x22|SHIFT, // % + 0x24|SHIFT, // & + 0x34, // ' + 0x26|SHIFT, // ( + 0x27|SHIFT, // ) + 0x25|SHIFT, // * + 0x2e|SHIFT, // + + 0x36, // , + 0x2d, // - + 0x37, // . + 0x38, // / + 0x27, // 0 + 0x1e, // 1 + 0x1f, // 2 + 0x20, // 3 + 0x21, // 4 + 0x22, // 5 + 0x23, // 6 + 0x24, // 7 + 0x25, // 8 + 0x26, // 9 + 0x33|SHIFT, // : + 0x33, // ; + 0x36|SHIFT, // < + 0x2e, // = + 0x37|SHIFT, // > + 0x38|SHIFT, // ? + 0x1f|SHIFT, // @ + 0x04|SHIFT, // A + 0x05|SHIFT, // B + 0x06|SHIFT, // C + 0x07|SHIFT, // D + 0x08|SHIFT, // E + 0x09|SHIFT, // F + 0x0a|SHIFT, // G + 0x0b|SHIFT, // H + 0x0c|SHIFT, // I + 0x0d|SHIFT, // J + 0x0e|SHIFT, // K + 0x0f|SHIFT, // L + 0x10|SHIFT, // M + 0x11|SHIFT, // N + 0x12|SHIFT, // O + 0x13|SHIFT, // P + 0x14|SHIFT, // Q + 0x15|SHIFT, // R + 0x16|SHIFT, // S + 0x17|SHIFT, // T + 0x18|SHIFT, // U + 0x19|SHIFT, // V + 0x1a|SHIFT, // W + 0x1b|SHIFT, // X + 0x1c|SHIFT, // Y + 0x1d|SHIFT, // Z + 0x2f, // [ + 0x31, // bslash + 0x30, // ] + 0x23|SHIFT, // ^ + 0x2d|SHIFT, // _ + 0x35, // ` + 0x04, // a + 0x05, // b + 0x06, // c + 0x07, // d + 0x08, // e + 0x09, // f + 0x0a, // g + 0x0b, // h + 0x0c, // i + 0x0d, // j + 0x0e, // k + 0x0f, // l + 0x10, // m + 0x11, // n + 0x12, // o + 0x13, // p + 0x14, // q + 0x15, // r + 0x16, // s + 0x17, // t + 0x18, // u + 0x19, // v + 0x1a, // w + 0x1b, // x + 0x1c, // y + 0x1d, // z + 0x2f|SHIFT, // + 0x31|SHIFT, // | + 0x30|SHIFT, // } + 0x35|SHIFT, // ~ + 0 // DEL +}; + +uint8_t USBPutChar(uint8_t c); + +// press() adds the specified key (printing, non-printing, or modifier) +// to the persistent key report and sends the report. Because of the way +// USB HID works, the host acts like the key remains pressed until we +// call release(), releaseAll(), or otherwise clear the report and resend. +size_t Keyboard_::press(uint8_t k) +{ + uint8_t i; + if (k >= 136) { // it's a non-printing key (not a modifier) + k = k - 136; + } else if (k >= 128) { // it's a modifier key + _keyReport.modifiers |= (1<<(k-128)); + k = 0; + } else { // it's a printing key + k = pgm_read_byte(_asciimap + k); + if (!k) { + setWriteError(); + return 0; + } + if (k & 0x80) { // it's a capital letter or other character reached with shift + _keyReport.modifiers |= 0x02; // the left shift modifier + k &= 0x7F; + } + } + + // Add k to the key report only if it's not already present + // and if there is an empty slot. + if (_keyReport.keys[0] != k && _keyReport.keys[1] != k && + _keyReport.keys[2] != k && _keyReport.keys[3] != k && + _keyReport.keys[4] != k && _keyReport.keys[5] != k) { + + for (i=0; i<6; i++) { + if (_keyReport.keys[i] == 0x00) { + _keyReport.keys[i] = k; + break; + } + } + if (i == 6) { + setWriteError(); + return 0; + } + } + sendReport(&_keyReport); + return 1; +} + +// release() takes the specified key out of the persistent key report and +// sends the report. This tells the OS the key is no longer pressed and that +// it shouldn't be repeated any more. +size_t Keyboard_::release(uint8_t k) +{ + uint8_t i; + if (k >= 136) { // it's a non-printing key (not a modifier) + k = k - 136; + } else if (k >= 128) { // it's a modifier key + _keyReport.modifiers &= ~(1<<(k-128)); + k = 0; + } else { // it's a printing key + k = pgm_read_byte(_asciimap + k); + if (!k) { + return 0; + } + if (k & 0x80) { // it's a capital letter or other character reached with shift + _keyReport.modifiers &= ~(0x02); // the left shift modifier + k &= 0x7F; + } + } + + // Test the key report to see if k is present. Clear it if it exists. + // Check all positions in case the key is present more than once (which it shouldn't be) + for (i=0; i<6; i++) { + if (0 != k && _keyReport.keys[i] == k) { + _keyReport.keys[i] = 0x00; + } + } + + sendReport(&_keyReport); + return 1; +} + +void Keyboard_::releaseAll(void) +{ + _keyReport.keys[0] = 0; + _keyReport.keys[1] = 0; + _keyReport.keys[2] = 0; + _keyReport.keys[3] = 0; + _keyReport.keys[4] = 0; + _keyReport.keys[5] = 0; + _keyReport.modifiers = 0; + sendReport(&_keyReport); +} + +size_t Keyboard_::write(uint8_t c) +{ + uint8_t p = press(c); // Keydown + uint8_t r = release(c); // Keyup + return (p); // just return the result of press() since release() almost always returns 1 +} + +#endif + +#endif /* if defined(USBCON) */ \ No newline at end of file diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HardwareSerial.cpp b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HardwareSerial.cpp new file mode 100644 index 0000000000..794a7be898 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HardwareSerial.cpp @@ -0,0 +1,519 @@ +/* + HardwareSerial.cpp - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus +*/ + +#include +#include +#include +#include +#include "Arduino.h" +#include "wiring_private.h" + +// this next line disables the entire HardwareSerial.cpp, +// this is so I can support Attiny series and any other chip without a uart +#if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H) + +#include "HardwareSerial.h" + +/* + * on ATmega8, the uart and its bits are not numbered, so there is no "TXC0" + * definition. + */ +#if !defined(TXC0) +#if defined(TXC) +#define TXC0 TXC +#elif defined(TXC1) +// Some devices have uart1 but no uart0 +#define TXC0 TXC1 +#else +#error TXC0 not definable in HardwareSerial.h +#endif +#endif + +// Define constants and variables for buffering incoming serial data. We're +// using a ring buffer (I think), in which head is the index of the location +// to which to write the next incoming character and tail is the index of the +// location from which to read. +#if (RAMEND < 1000) + #define SERIAL_BUFFER_SIZE 16 +#else + #define SERIAL_BUFFER_SIZE 64 +#endif + +struct ring_buffer +{ + unsigned char buffer[SERIAL_BUFFER_SIZE]; + volatile unsigned int head; + volatile unsigned int tail; +}; + +#if defined(USBCON) + ring_buffer rx_buffer = { { 0 }, 0, 0}; + ring_buffer tx_buffer = { { 0 }, 0, 0}; +#endif +#if defined(UBRRH) || defined(UBRR0H) + ring_buffer rx_buffer = { { 0 }, 0, 0 }; + ring_buffer tx_buffer = { { 0 }, 0, 0 }; +#endif +#if defined(UBRR1H) + ring_buffer rx_buffer1 = { { 0 }, 0, 0 }; + ring_buffer tx_buffer1 = { { 0 }, 0, 0 }; +#endif +#if defined(UBRR2H) + ring_buffer rx_buffer2 = { { 0 }, 0, 0 }; + ring_buffer tx_buffer2 = { { 0 }, 0, 0 }; +#endif +#if defined(UBRR3H) + ring_buffer rx_buffer3 = { { 0 }, 0, 0 }; + ring_buffer tx_buffer3 = { { 0 }, 0, 0 }; +#endif + +inline void store_char(unsigned char c, ring_buffer *buffer) +{ + int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE; + + // if we should be storing the received character into the location + // just before the tail (meaning that the head would advance to the + // current location of the tail), we're about to overflow the buffer + // and so we don't write the character or advance the head. + if (i != buffer->tail) { + buffer->buffer[buffer->head] = c; + buffer->head = i; + } +} + +#if !defined(USART0_RX_vect) && defined(USART1_RX_vect) +// do nothing - on the 32u4 the first USART is USART1 +#else +#if !defined(USART_RX_vect) && !defined(SIG_USART0_RECV) && \ + !defined(SIG_UART0_RECV) && !defined(USART0_RX_vect) && \ + !defined(SIG_UART_RECV) + #error "Don't know what the Data Received vector is called for the first UART" +#else + void serialEvent() __attribute__((weak)); + void serialEvent() {} + #define serialEvent_implemented +#if defined(USART_RX_vect) + SIGNAL(USART_RX_vect) +#elif defined(SIG_USART0_RECV) + SIGNAL(SIG_USART0_RECV) +#elif defined(SIG_UART0_RECV) + SIGNAL(SIG_UART0_RECV) +#elif defined(USART0_RX_vect) + SIGNAL(USART0_RX_vect) +#elif defined(SIG_UART_RECV) + SIGNAL(SIG_UART_RECV) +#endif + { + #if defined(UDR0) + if (bit_is_clear(UCSR0A, UPE0)) { + unsigned char c = UDR0; + store_char(c, &rx_buffer); + } else { + unsigned char c = UDR0; + }; + #elif defined(UDR) + if (bit_is_clear(UCSRA, PE)) { + unsigned char c = UDR; + store_char(c, &rx_buffer); + } else { + unsigned char c = UDR; + }; + #else + #error UDR not defined + #endif + } +#endif +#endif + +#if defined(USART1_RX_vect) + void serialEvent1() __attribute__((weak)); + void serialEvent1() {} + #define serialEvent1_implemented + SIGNAL(USART1_RX_vect) + { + if (bit_is_clear(UCSR1A, UPE1)) { + unsigned char c = UDR1; + store_char(c, &rx_buffer1); + } else { + unsigned char c = UDR1; + }; + } +#elif defined(SIG_USART1_RECV) + #error SIG_USART1_RECV +#endif + +#if defined(USART2_RX_vect) && defined(UDR2) + void serialEvent2() __attribute__((weak)); + void serialEvent2() {} + #define serialEvent2_implemented + SIGNAL(USART2_RX_vect) + { + if (bit_is_clear(UCSR2A, UPE2)) { + unsigned char c = UDR2; + store_char(c, &rx_buffer2); + } else { + unsigned char c = UDR2; + }; + } +#elif defined(SIG_USART2_RECV) + #error SIG_USART2_RECV +#endif + +#if defined(USART3_RX_vect) && defined(UDR3) + void serialEvent3() __attribute__((weak)); + void serialEvent3() {} + #define serialEvent3_implemented + SIGNAL(USART3_RX_vect) + { + if (bit_is_clear(UCSR3A, UPE3)) { + unsigned char c = UDR3; + store_char(c, &rx_buffer3); + } else { + unsigned char c = UDR3; + }; + } +#elif defined(SIG_USART3_RECV) + #error SIG_USART3_RECV +#endif + +void serialEventRun(void) +{ +#ifdef serialEvent_implemented + if (Serial.available()) serialEvent(); +#endif +#ifdef serialEvent1_implemented + if (Serial1.available()) serialEvent1(); +#endif +#ifdef serialEvent2_implemented + if (Serial2.available()) serialEvent2(); +#endif +#ifdef serialEvent3_implemented + if (Serial3.available()) serialEvent3(); +#endif +} + + +#if !defined(USART0_UDRE_vect) && defined(USART1_UDRE_vect) +// do nothing - on the 32u4 the first USART is USART1 +#else +#if !defined(UART0_UDRE_vect) && !defined(UART_UDRE_vect) && !defined(USART0_UDRE_vect) && !defined(USART_UDRE_vect) + #error "Don't know what the Data Register Empty vector is called for the first UART" +#else +#if defined(UART0_UDRE_vect) +ISR(UART0_UDRE_vect) +#elif defined(UART_UDRE_vect) +ISR(UART_UDRE_vect) +#elif defined(USART0_UDRE_vect) +ISR(USART0_UDRE_vect) +#elif defined(USART_UDRE_vect) +ISR(USART_UDRE_vect) +#endif +{ + if (tx_buffer.head == tx_buffer.tail) { + // Buffer empty, so disable interrupts +#if defined(UCSR0B) + cbi(UCSR0B, UDRIE0); +#else + cbi(UCSRB, UDRIE); +#endif + } + else { + // There is more data in the output buffer. Send the next byte + unsigned char c = tx_buffer.buffer[tx_buffer.tail]; + tx_buffer.tail = (tx_buffer.tail + 1) % SERIAL_BUFFER_SIZE; + + #if defined(UDR0) + UDR0 = c; + #elif defined(UDR) + UDR = c; + #else + #error UDR not defined + #endif + } +} +#endif +#endif + +#ifdef USART1_UDRE_vect +ISR(USART1_UDRE_vect) +{ + if (tx_buffer1.head == tx_buffer1.tail) { + // Buffer empty, so disable interrupts + cbi(UCSR1B, UDRIE1); + } + else { + // There is more data in the output buffer. Send the next byte + unsigned char c = tx_buffer1.buffer[tx_buffer1.tail]; + tx_buffer1.tail = (tx_buffer1.tail + 1) % SERIAL_BUFFER_SIZE; + + UDR1 = c; + } +} +#endif + +#ifdef USART2_UDRE_vect +ISR(USART2_UDRE_vect) +{ + if (tx_buffer2.head == tx_buffer2.tail) { + // Buffer empty, so disable interrupts + cbi(UCSR2B, UDRIE2); + } + else { + // There is more data in the output buffer. Send the next byte + unsigned char c = tx_buffer2.buffer[tx_buffer2.tail]; + tx_buffer2.tail = (tx_buffer2.tail + 1) % SERIAL_BUFFER_SIZE; + + UDR2 = c; + } +} +#endif + +#ifdef USART3_UDRE_vect +ISR(USART3_UDRE_vect) +{ + if (tx_buffer3.head == tx_buffer3.tail) { + // Buffer empty, so disable interrupts + cbi(UCSR3B, UDRIE3); + } + else { + // There is more data in the output buffer. Send the next byte + unsigned char c = tx_buffer3.buffer[tx_buffer3.tail]; + tx_buffer3.tail = (tx_buffer3.tail + 1) % SERIAL_BUFFER_SIZE; + + UDR3 = c; + } +} +#endif + + +// Constructors //////////////////////////////////////////////////////////////// + +HardwareSerial::HardwareSerial(ring_buffer *rx_buffer, ring_buffer *tx_buffer, + volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, + volatile uint8_t *ucsra, volatile uint8_t *ucsrb, + volatile uint8_t *ucsrc, volatile uint8_t *udr, + uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x) +{ + _rx_buffer = rx_buffer; + _tx_buffer = tx_buffer; + _ubrrh = ubrrh; + _ubrrl = ubrrl; + _ucsra = ucsra; + _ucsrb = ucsrb; + _ucsrc = ucsrc; + _udr = udr; + _rxen = rxen; + _txen = txen; + _rxcie = rxcie; + _udrie = udrie; + _u2x = u2x; +} + +// Public Methods ////////////////////////////////////////////////////////////// + +void HardwareSerial::begin(unsigned long baud) +{ + uint16_t baud_setting; + bool use_u2x = true; + +#if F_CPU == 16000000UL + // hardcoded exception for compatibility with the bootloader shipped + // with the Duemilanove and previous boards and the firmware on the 8U2 + // on the Uno and Mega 2560. + if (baud == 57600) { + use_u2x = false; + } +#endif + +try_again: + + if (use_u2x) { + *_ucsra = 1 << _u2x; + baud_setting = (F_CPU / 4 / baud - 1) / 2; + } else { + *_ucsra = 0; + baud_setting = (F_CPU / 8 / baud - 1) / 2; + } + + if ((baud_setting > 4095) && use_u2x) + { + use_u2x = false; + goto try_again; + } + + // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) + *_ubrrh = baud_setting >> 8; + *_ubrrl = baud_setting; + + transmitting = false; + + sbi(*_ucsrb, _rxen); + sbi(*_ucsrb, _txen); + sbi(*_ucsrb, _rxcie); + cbi(*_ucsrb, _udrie); +} + +void HardwareSerial::begin(unsigned long baud, byte config) +{ + uint16_t baud_setting; + uint8_t current_config; + bool use_u2x = true; + +#if F_CPU == 16000000UL + // hardcoded exception for compatibility with the bootloader shipped + // with the Duemilanove and previous boards and the firmware on the 8U2 + // on the Uno and Mega 2560. + if (baud == 57600) { + use_u2x = false; + } +#endif + +try_again: + + if (use_u2x) { + *_ucsra = 1 << _u2x; + baud_setting = (F_CPU / 4 / baud - 1) / 2; + } else { + *_ucsra = 0; + baud_setting = (F_CPU / 8 / baud - 1) / 2; + } + + if ((baud_setting > 4095) && use_u2x) + { + use_u2x = false; + goto try_again; + } + + // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) + *_ubrrh = baud_setting >> 8; + *_ubrrl = baud_setting; + + //set the data bits, parity, and stop bits +#if defined(__AVR_ATmega8__) + config |= 0x80; // select UCSRC register (shared with UBRRH) +#endif + *_ucsrc = config; + + sbi(*_ucsrb, _rxen); + sbi(*_ucsrb, _txen); + sbi(*_ucsrb, _rxcie); + cbi(*_ucsrb, _udrie); +} + +void HardwareSerial::end() +{ + // wait for transmission of outgoing data + while (_tx_buffer->head != _tx_buffer->tail) + ; + + cbi(*_ucsrb, _rxen); + cbi(*_ucsrb, _txen); + cbi(*_ucsrb, _rxcie); + cbi(*_ucsrb, _udrie); + + // clear any received data + _rx_buffer->head = _rx_buffer->tail; +} + +int HardwareSerial::available(void) +{ + return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % SERIAL_BUFFER_SIZE; +} + +int HardwareSerial::peek(void) +{ + if (_rx_buffer->head == _rx_buffer->tail) { + return -1; + } else { + return _rx_buffer->buffer[_rx_buffer->tail]; + } +} + +int HardwareSerial::read(void) +{ + // if the head isn't ahead of the tail, we don't have any characters + if (_rx_buffer->head == _rx_buffer->tail) { + return -1; + } else { + unsigned char c = _rx_buffer->buffer[_rx_buffer->tail]; + _rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE; + return c; + } +} + +void HardwareSerial::flush() +{ + // UDR is kept full while the buffer is not empty, so TXC triggers when EMPTY && SENT + while (transmitting && ! (*_ucsra & _BV(TXC0))); + transmitting = false; +} + +size_t HardwareSerial::write(uint8_t c) +{ + int i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE; + + // If the output buffer is full, there's nothing for it other than to + // wait for the interrupt handler to empty it a bit + // ???: return 0 here instead? + while (i == _tx_buffer->tail) + ; + + _tx_buffer->buffer[_tx_buffer->head] = c; + _tx_buffer->head = i; + + sbi(*_ucsrb, _udrie); + // clear the TXC bit -- "can be cleared by writing a one to its bit location" + transmitting = true; + sbi(*_ucsra, TXC0); + + return 1; +} + +HardwareSerial::operator bool() { + return true; +} + +// Preinstantiate Objects ////////////////////////////////////////////////////// + +#if defined(UBRRH) && defined(UBRRL) + HardwareSerial Serial(&rx_buffer, &tx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR, RXEN, TXEN, RXCIE, UDRIE, U2X); +#elif defined(UBRR0H) && defined(UBRR0L) + HardwareSerial Serial(&rx_buffer, &tx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UCSR0C, &UDR0, RXEN0, TXEN0, RXCIE0, UDRIE0, U2X0); +#elif defined(USBCON) + // do nothing - Serial object and buffers are initialized in CDC code +#else + #error no serial port defined (port 0) +#endif + +#if defined(UBRR1H) + HardwareSerial Serial1(&rx_buffer1, &tx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UCSR1C, &UDR1, RXEN1, TXEN1, RXCIE1, UDRIE1, U2X1); +#endif +#if defined(UBRR2H) + HardwareSerial Serial2(&rx_buffer2, &tx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UCSR2C, &UDR2, RXEN2, TXEN2, RXCIE2, UDRIE2, U2X2); +#endif +#if defined(UBRR3H) + HardwareSerial Serial3(&rx_buffer3, &tx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UCSR3C, &UDR3, RXEN3, TXEN3, RXCIE3, UDRIE3, U2X3); +#endif + +#endif // whole file + diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HardwareSerial.h b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HardwareSerial.h new file mode 100644 index 0000000000..a73117f568 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HardwareSerial.h @@ -0,0 +1,115 @@ +/* + HardwareSerial.h - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus +*/ + +#ifndef HardwareSerial_h +#define HardwareSerial_h + +#include + +#include "Stream.h" + +struct ring_buffer; + +class HardwareSerial : public Stream +{ + private: + ring_buffer *_rx_buffer; + ring_buffer *_tx_buffer; + volatile uint8_t *_ubrrh; + volatile uint8_t *_ubrrl; + volatile uint8_t *_ucsra; + volatile uint8_t *_ucsrb; + volatile uint8_t *_ucsrc; + volatile uint8_t *_udr; + uint8_t _rxen; + uint8_t _txen; + uint8_t _rxcie; + uint8_t _udrie; + uint8_t _u2x; + bool transmitting; + public: + HardwareSerial(ring_buffer *rx_buffer, ring_buffer *tx_buffer, + volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, + volatile uint8_t *ucsra, volatile uint8_t *ucsrb, + volatile uint8_t *ucsrc, volatile uint8_t *udr, + uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x); + void begin(unsigned long); + void begin(unsigned long, uint8_t); + void end(); + virtual int available(void); + virtual int peek(void); + virtual int read(void); + virtual void flush(void); + virtual size_t write(uint8_t); + inline size_t write(unsigned long n) { return write((uint8_t)n); } + inline size_t write(long n) { return write((uint8_t)n); } + inline size_t write(unsigned int n) { return write((uint8_t)n); } + inline size_t write(int n) { return write((uint8_t)n); } + using Print::write; // pull in write(str) and write(buf, size) from Print + operator bool(); +}; + +// Define config for Serial.begin(baud, config); +#define SERIAL_5N1 0x00 +#define SERIAL_6N1 0x02 +#define SERIAL_7N1 0x04 +#define SERIAL_8N1 0x06 +#define SERIAL_5N2 0x08 +#define SERIAL_6N2 0x0A +#define SERIAL_7N2 0x0C +#define SERIAL_8N2 0x0E +#define SERIAL_5E1 0x20 +#define SERIAL_6E1 0x22 +#define SERIAL_7E1 0x24 +#define SERIAL_8E1 0x26 +#define SERIAL_5E2 0x28 +#define SERIAL_6E2 0x2A +#define SERIAL_7E2 0x2C +#define SERIAL_8E2 0x2E +#define SERIAL_5O1 0x30 +#define SERIAL_6O1 0x32 +#define SERIAL_7O1 0x34 +#define SERIAL_8O1 0x36 +#define SERIAL_5O2 0x38 +#define SERIAL_6O2 0x3A +#define SERIAL_7O2 0x3C +#define SERIAL_8O2 0x3E + +#if defined(UBRRH) || defined(UBRR0H) + extern HardwareSerial Serial; +#elif defined(USBCON) + #include "USBAPI.h" +// extern HardwareSerial Serial_; +#endif +#if defined(UBRR1H) + extern HardwareSerial Serial1; +#endif +#if defined(UBRR2H) + extern HardwareSerial Serial2; +#endif +#if defined(UBRR3H) + extern HardwareSerial Serial3; +#endif + +extern void serialEventRun(void) __attribute__((weak)); + +#endif diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/IPAddress.cpp b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/IPAddress.cpp new file mode 100644 index 0000000000..fe3deb77a2 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/IPAddress.cpp @@ -0,0 +1,56 @@ + +#include +#include + +IPAddress::IPAddress() +{ + memset(_address, 0, sizeof(_address)); +} + +IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) +{ + _address[0] = first_octet; + _address[1] = second_octet; + _address[2] = third_octet; + _address[3] = fourth_octet; +} + +IPAddress::IPAddress(uint32_t address) +{ + memcpy(_address, &address, sizeof(_address)); +} + +IPAddress::IPAddress(const uint8_t *address) +{ + memcpy(_address, address, sizeof(_address)); +} + +IPAddress& IPAddress::operator=(const uint8_t *address) +{ + memcpy(_address, address, sizeof(_address)); + return *this; +} + +IPAddress& IPAddress::operator=(uint32_t address) +{ + memcpy(_address, (const uint8_t *)&address, sizeof(_address)); + return *this; +} + +bool IPAddress::operator==(const uint8_t* addr) +{ + return memcmp(addr, _address, sizeof(_address)) == 0; +} + +size_t IPAddress::printTo(Print& p) const +{ + size_t n = 0; + for (int i =0; i < 3; i++) + { + n += p.print(_address[i], DEC); + n += p.print('.'); + } + n += p.print(_address[3], DEC); + return n; +} + diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/IPAddress.h b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/IPAddress.h new file mode 100644 index 0000000000..2585aec0e4 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/IPAddress.h @@ -0,0 +1,76 @@ +/* + * + * MIT License: + * Copyright (c) 2011 Adrian McEwen + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * adrianm@mcqn.com 1/1/2011 + */ + +#ifndef IPAddress_h +#define IPAddress_h + +#include + +// A class to make it easier to handle and pass around IP addresses + +class IPAddress : public Printable { +private: + uint8_t _address[4]; // IPv4 address + // Access the raw byte array containing the address. Because this returns a pointer + // to the internal structure rather than a copy of the address this function should only + // be used when you know that the usage of the returned uint8_t* will be transient and not + // stored. + uint8_t* raw_address() { return _address; }; + +public: + // Constructors + IPAddress(); + IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); + IPAddress(uint32_t address); + IPAddress(const uint8_t *address); + + // Overloaded cast operator to allow IPAddress objects to be used where a pointer + // to a four-byte uint8_t array is expected + operator uint32_t() { return *((uint32_t*)_address); }; + bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); }; + bool operator==(const uint8_t* addr); + + // Overloaded index operator to allow getting and setting individual octets of the address + uint8_t operator[](int index) const { return _address[index]; }; + uint8_t& operator[](int index) { return _address[index]; }; + + // Overloaded copy operators to allow initialisation of IPAddress objects from other types + IPAddress& operator=(const uint8_t *address); + IPAddress& operator=(uint32_t address); + + virtual size_t printTo(Print& p) const; + + friend class EthernetClass; + friend class UDP; + friend class Client; + friend class Server; + friend class DhcpClass; + friend class DNSClient; +}; + +const IPAddress INADDR_NONE(0,0,0,0); + + +#endif diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Platform.h b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Platform.h new file mode 100644 index 0000000000..8b8f742771 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Platform.h @@ -0,0 +1,23 @@ + +#ifndef __PLATFORM_H__ +#define __PLATFORM_H__ + +#include +#include +#include +#include +#include + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; + +#include "Arduino.h" + +#if defined(USBCON) + #include "USBDesc.h" + #include "USBCore.h" + #include "USBAPI.h" +#endif /* if defined(USBCON) */ + +#endif diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Print.cpp b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Print.cpp new file mode 100644 index 0000000000..53961ec478 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Print.cpp @@ -0,0 +1,268 @@ +/* + Print.cpp - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + */ + +#include +#include +#include +#include +#include "Arduino.h" + +#include "Print.h" + +// Public Methods ////////////////////////////////////////////////////////////// + +/* default implementation: may be overridden */ +size_t Print::write(const uint8_t *buffer, size_t size) +{ + size_t n = 0; + while (size--) { + n += write(*buffer++); + } + return n; +} + +size_t Print::print(const __FlashStringHelper *ifsh) +{ + const char PROGMEM *p = (const char PROGMEM *)ifsh; + size_t n = 0; + while (1) { + unsigned char c = pgm_read_byte(p++); + if (c == 0) break; + n += write(c); + } + return n; +} + +size_t Print::print(const String &s) +{ + size_t n = 0; + for (uint16_t i = 0; i < s.length(); i++) { + n += write(s[i]); + } + return n; +} + +size_t Print::print(const char str[]) +{ + return write(str); +} + +size_t Print::print(char c) +{ + return write(c); +} + +size_t Print::print(unsigned char b, int base) +{ + return print((unsigned long) b, base); +} + +size_t Print::print(int n, int base) +{ + return print((long) n, base); +} + +size_t Print::print(unsigned int n, int base) +{ + return print((unsigned long) n, base); +} + +size_t Print::print(long n, int base) +{ + if (base == 0) { + return write(n); + } else if (base == 10) { + if (n < 0) { + int t = print('-'); + n = -n; + return printNumber(n, 10) + t; + } + return printNumber(n, 10); + } else { + return printNumber(n, base); + } +} + +size_t Print::print(unsigned long n, int base) +{ + if (base == 0) return write(n); + else return printNumber(n, base); +} + +size_t Print::print(double n, int digits) +{ + return printFloat(n, digits); +} + +size_t Print::println(const __FlashStringHelper *ifsh) +{ + size_t n = print(ifsh); + n += println(); + return n; +} + +size_t Print::print(const Printable& x) +{ + return x.printTo(*this); +} + +size_t Print::println(void) +{ + size_t n = print('\r'); + n += print('\n'); + return n; +} + +size_t Print::println(const String &s) +{ + size_t n = print(s); + n += println(); + return n; +} + +size_t Print::println(const char c[]) +{ + size_t n = print(c); + n += println(); + return n; +} + +size_t Print::println(char c) +{ + size_t n = print(c); + n += println(); + return n; +} + +size_t Print::println(unsigned char b, int base) +{ + size_t n = print(b, base); + n += println(); + return n; +} + +size_t Print::println(int num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned int num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(long num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned long num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(double num, int digits) +{ + size_t n = print(num, digits); + n += println(); + return n; +} + +size_t Print::println(const Printable& x) +{ + size_t n = print(x); + n += println(); + return n; +} + +// Private Methods ///////////////////////////////////////////////////////////// + +size_t Print::printNumber(unsigned long n, uint8_t base) { + char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. + char *str = &buf[sizeof(buf) - 1]; + + *str = '\0'; + + // prevent crash if called with base == 1 + if (base < 2) base = 10; + + do { + unsigned long m = n; + n /= base; + char c = m - base * n; + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while(n); + + return write(str); +} + +size_t Print::printFloat(double number, uint8_t digits) +{ + size_t n = 0; + + if (isnan(number)) return print("nan"); + if (isinf(number)) return print("inf"); + if (number > 4294967040.0) return print ("ovf"); // constant determined empirically + if (number <-4294967040.0) return print ("ovf"); // constant determined empirically + + // Handle negative numbers + if (number < 0.0) + { + n += print('-'); + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for (uint8_t i=0; i 0) { + n += print("."); + } + + // Extract digits from the remainder one at a time + while (digits-- > 0) + { + remainder *= 10.0; + int toPrint = int(remainder); + n += print(toPrint); + remainder -= toPrint; + } + + return n; +} diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Print.h b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Print.h new file mode 100644 index 0000000000..dc76150871 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Print.h @@ -0,0 +1,81 @@ +/* + Print.h - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef Print_h +#define Print_h + +#include +#include // for size_t + +#include "WString.h" +#include "Printable.h" + +#define DEC 10 +#define HEX 16 +#define OCT 8 +#define BIN 2 + +class Print +{ + private: + int write_error; + size_t printNumber(unsigned long, uint8_t); + size_t printFloat(double, uint8_t); + protected: + void setWriteError(int err = 1) { write_error = err; } + public: + Print() : write_error(0) {} + + int getWriteError() { return write_error; } + void clearWriteError() { setWriteError(0); } + + virtual size_t write(uint8_t) = 0; + size_t write(const char *str) { + if (str == NULL) return 0; + return write((const uint8_t *)str, strlen(str)); + } + virtual size_t write(const uint8_t *buffer, size_t size); + + size_t print(const __FlashStringHelper *); + size_t print(const String &); + size_t print(const char[]); + size_t print(char); + size_t print(unsigned char, int = DEC); + size_t print(int, int = DEC); + size_t print(unsigned int, int = DEC); + size_t print(long, int = DEC); + size_t print(unsigned long, int = DEC); + size_t print(double, int = 2); + size_t print(const Printable&); + + size_t println(const __FlashStringHelper *); + size_t println(const String &s); + size_t println(const char[]); + size_t println(char); + size_t println(unsigned char, int = DEC); + size_t println(int, int = DEC); + size_t println(unsigned int, int = DEC); + size_t println(long, int = DEC); + size_t println(unsigned long, int = DEC); + size_t println(double, int = 2); + size_t println(const Printable&); + size_t println(void); +}; + +#endif diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Printable.h b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Printable.h new file mode 100644 index 0000000000..d03c9af62c --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Printable.h @@ -0,0 +1,40 @@ +/* + Printable.h - Interface class that allows printing of complex types + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef Printable_h +#define Printable_h + +#include + +class Print; + +/** The Printable class provides a way for new classes to allow themselves to be printed. + By deriving from Printable and implementing the printTo method, it will then be possible + for users to print out instances of this class by passing them into the usual + Print::print and Print::println methods. +*/ + +class Printable +{ + public: + virtual size_t printTo(Print& p) const = 0; +}; + +#endif + diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Server.h b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Server.h new file mode 100644 index 0000000000..9674c76269 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Server.h @@ -0,0 +1,9 @@ +#ifndef server_h +#define server_h + +class Server : public Print { +public: + virtual void begin() =0; +}; + +#endif diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Stream.cpp b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Stream.cpp new file mode 100644 index 0000000000..aafb7fcf97 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Stream.cpp @@ -0,0 +1,270 @@ +/* + Stream.cpp - adds parsing methods to Stream class + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Created July 2011 + parsing functions based on TextFinder library by Michael Margolis + */ + +#include "Arduino.h" +#include "Stream.h" + +#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait +#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field + +// private method to read stream with timeout +int Stream::timedRead() +{ + int c; + _startMillis = millis(); + do { + c = read(); + if (c >= 0) return c; + } while(millis() - _startMillis < _timeout); + return -1; // -1 indicates timeout +} + +// private method to peek stream with timeout +int Stream::timedPeek() +{ + int c; + _startMillis = millis(); + do { + c = peek(); + if (c >= 0) return c; + } while(millis() - _startMillis < _timeout); + return -1; // -1 indicates timeout +} + +// returns peek of the next digit in the stream or -1 if timeout +// discards non-numeric characters +int Stream::peekNextDigit() +{ + int c; + while (1) { + c = timedPeek(); + if (c < 0) return c; // timeout + if (c == '-') return c; + if (c >= '0' && c <= '9') return c; + read(); // discard non-numeric + } +} + +// Public Methods +////////////////////////////////////////////////////////////// + +void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait +{ + _timeout = timeout; +} + + // find returns true if the target string is found +bool Stream::find(char *target) +{ + return findUntil(target, NULL); +} + +// reads data from the stream until the target string of given length is found +// returns true if target string is found, false if timed out +bool Stream::find(char *target, size_t length) +{ + return findUntil(target, length, NULL, 0); +} + +// as find but search ends if the terminator string is found +bool Stream::findUntil(char *target, char *terminator) +{ + return findUntil(target, strlen(target), terminator, strlen(terminator)); +} + +// reads data from the stream until the target string of the given length is found +// search terminated if the terminator string is found +// returns true if target string is found, false if terminated or timed out +bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen) +{ + size_t index = 0; // maximum target string length is 64k bytes! + size_t termIndex = 0; + int c; + + if( *target == 0) + return true; // return true if target is a null string + while( (c = timedRead()) > 0){ + + if(c != target[index]) + index = 0; // reset index if any char does not match + + if( c == target[index]){ + //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1); + if(++index >= targetLen){ // return true if all chars in the target match + return true; + } + } + + if(termLen > 0 && c == terminator[termIndex]){ + if(++termIndex >= termLen) + return false; // return false if terminate string found before target string + } + else + termIndex = 0; + } + return false; +} + + +// returns the first valid (long) integer value from the current position. +// initial characters that are not digits (or the minus sign) are skipped +// function is terminated by the first character that is not a digit. +long Stream::parseInt() +{ + return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout) +} + +// as above but a given skipChar is ignored +// this allows format characters (typically commas) in values to be ignored +long Stream::parseInt(char skipChar) +{ + boolean isNegative = false; + long value = 0; + int c; + + c = peekNextDigit(); + // ignore non numeric leading characters + if(c < 0) + return 0; // zero returned if timeout + + do{ + if(c == skipChar) + ; // ignore this charactor + else if(c == '-') + isNegative = true; + else if(c >= '0' && c <= '9') // is c a digit? + value = value * 10 + c - '0'; + read(); // consume the character we got with peek + c = timedPeek(); + } + while( (c >= '0' && c <= '9') || c == skipChar ); + + if(isNegative) + value = -value; + return value; +} + + +// as parseInt but returns a floating point value +float Stream::parseFloat() +{ + return parseFloat(NO_SKIP_CHAR); +} + +// as above but the given skipChar is ignored +// this allows format characters (typically commas) in values to be ignored +float Stream::parseFloat(char skipChar){ + boolean isNegative = false; + boolean isFraction = false; + long value = 0; + char c; + float fraction = 1.0; + + c = peekNextDigit(); + // ignore non numeric leading characters + if(c < 0) + return 0; // zero returned if timeout + + do{ + if(c == skipChar) + ; // ignore + else if(c == '-') + isNegative = true; + else if (c == '.') + isFraction = true; + else if(c >= '0' && c <= '9') { // is c a digit? + value = value * 10 + c - '0'; + if(isFraction) + fraction *= 0.1; + } + read(); // consume the character we got with peek + c = timedPeek(); + } + while( (c >= '0' && c <= '9') || c == '.' || c == skipChar ); + + if(isNegative) + value = -value; + if(isFraction) + return value * fraction; + else + return value; +} + +// read characters from stream into buffer +// terminates if length characters have been read, or timeout (see setTimeout) +// returns the number of characters placed in the buffer +// the buffer is NOT null terminated. +// +size_t Stream::readBytes(char *buffer, size_t length) +{ + size_t count = 0; + while (count < length) { + int c = timedRead(); + if (c < 0) break; + *buffer++ = (char)c; + count++; + } + return count; +} + + +// as readBytes with terminator character +// terminates if length characters have been read, timeout, or if the terminator character detected +// returns the number of characters placed in the buffer (0 means no valid data found) + +size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) +{ + if (length < 1) return 0; + size_t index = 0; + while (index < length) { + int c = timedRead(); + if (c < 0 || c == terminator) break; + *buffer++ = (char)c; + index++; + } + return index; // return number of characters, not including null terminator +} + +String Stream::readString() +{ + String ret; + int c = timedRead(); + while (c >= 0) + { + ret += (char)c; + c = timedRead(); + } + return ret; +} + +String Stream::readStringUntil(char terminator) +{ + String ret; + int c = timedRead(); + while (c >= 0 && c != terminator) + { + ret += (char)c; + c = timedRead(); + } + return ret; +} + diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Stream.h b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Stream.h new file mode 100644 index 0000000000..58bbf752f3 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Stream.h @@ -0,0 +1,96 @@ +/* + Stream.h - base class for character-based streams. + Copyright (c) 2010 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + parsing functions based on TextFinder library by Michael Margolis +*/ + +#ifndef Stream_h +#define Stream_h + +#include +#include "Print.h" + +// compatability macros for testing +/* +#define getInt() parseInt() +#define getInt(skipChar) parseInt(skipchar) +#define getFloat() parseFloat() +#define getFloat(skipChar) parseFloat(skipChar) +#define getString( pre_string, post_string, buffer, length) +readBytesBetween( pre_string, terminator, buffer, length) +*/ + +class Stream : public Print +{ + private: + unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read + unsigned long _startMillis; // used for timeout measurement + int timedRead(); // private method to read stream with timeout + int timedPeek(); // private method to peek stream with timeout + int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout + + public: + virtual int available() = 0; + virtual int read() = 0; + virtual int peek() = 0; + virtual void flush() = 0; + + Stream() {_timeout=1000;} + +// parsing methods + + void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second + + bool find(char *target); // reads data from the stream until the target string is found + // returns true if target string is found, false if timed out (see setTimeout) + + bool find(char *target, size_t length); // reads data from the stream until the target string of given length is found + // returns true if target string is found, false if timed out + + bool findUntil(char *target, char *terminator); // as find but search ends if the terminator string is found + + bool findUntil(char *target, size_t targetLen, char *terminate, size_t termLen); // as above but search ends if the terminate string is found + + + long parseInt(); // returns the first valid (long) integer value from the current position. + // initial characters that are not digits (or the minus sign) are skipped + // integer is terminated by the first character that is not a digit. + + float parseFloat(); // float version of parseInt + + size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer + // terminates if length characters have been read or timeout (see setTimeout) + // returns the number of characters placed in the buffer (0 means no valid data found) + + size_t readBytesUntil( char terminator, char *buffer, size_t length); // as readBytes with terminator character + // terminates if length characters have been read, timeout, or if the terminator character detected + // returns the number of characters placed in the buffer (0 means no valid data found) + + // Arduino String functions to be added here + String readString(); + String readStringUntil(char terminator); + + protected: + long parseInt(char skipChar); // as above but the given skipChar is ignored + // as above but the given skipChar is ignored + // this allows format characters (typically commas) in values to be ignored + + float parseFloat(char skipChar); // as above but the given skipChar is ignored +}; + +#endif diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Tone.cpp b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Tone.cpp new file mode 100644 index 0000000000..9bb6fe721c --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Tone.cpp @@ -0,0 +1,616 @@ +/* Tone.cpp + + A Tone Generator Library + + Written by Brett Hagman + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Version Modified By Date Comments +------- ----------- -------- -------- +0001 B Hagman 09/08/02 Initial coding +0002 B Hagman 09/08/18 Multiple pins +0003 B Hagman 09/08/18 Moved initialization from constructor to begin() +0004 B Hagman 09/09/26 Fixed problems with ATmega8 +0005 B Hagman 09/11/23 Scanned prescalars for best fit on 8 bit timers + 09/11/25 Changed pin toggle method to XOR + 09/11/25 Fixed timer0 from being excluded +0006 D Mellis 09/12/29 Replaced objects with functions +0007 M Sproul 10/08/29 Changed #ifdefs from cpu to register +0008 S Kanemoto 12/06/22 Fixed for Leonardo by @maris_HY +*************************************************/ + +#include +#include +#include "Arduino.h" +#include "pins_arduino.h" + +#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__) +#define TCCR2A TCCR2 +#define TCCR2B TCCR2 +#define COM2A1 COM21 +#define COM2A0 COM20 +#define OCR2A OCR2 +#define TIMSK2 TIMSK +#define OCIE2A OCIE2 +#define TIMER2_COMPA_vect TIMER2_COMP_vect +#define TIMSK1 TIMSK +#endif + +// timerx_toggle_count: +// > 0 - duration specified +// = 0 - stopped +// < 0 - infinitely (until stop() method called, or new play() called) + +#if !defined(__AVR_ATmega8__) +volatile long timer0_toggle_count; +volatile uint8_t *timer0_pin_port; +volatile uint8_t timer0_pin_mask; +#endif + +volatile long timer1_toggle_count; +volatile uint8_t *timer1_pin_port; +volatile uint8_t timer1_pin_mask; +volatile long timer2_toggle_count; +volatile uint8_t *timer2_pin_port; +volatile uint8_t timer2_pin_mask; + +#if defined(TIMSK3) +volatile long timer3_toggle_count; +volatile uint8_t *timer3_pin_port; +volatile uint8_t timer3_pin_mask; +#endif + +#if defined(TIMSK4) +volatile long timer4_toggle_count; +volatile uint8_t *timer4_pin_port; +volatile uint8_t timer4_pin_mask; +#endif + +#if defined(TIMSK5) +volatile long timer5_toggle_count; +volatile uint8_t *timer5_pin_port; +volatile uint8_t timer5_pin_mask; +#endif + + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + +#define AVAILABLE_TONE_PINS 1 +#define USE_TIMER2 + +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 3, 4, 5, 1, 0 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255, 255, 255, 255 */ }; + +#elif defined(__AVR_ATmega8__) + +#define AVAILABLE_TONE_PINS 1 +#define USE_TIMER2 + +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ }; + +#elif defined(__AVR_ATmega32U4__) + +#define AVAILABLE_TONE_PINS 1 +#define USE_TIMER3 + +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 3 /*, 1 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ }; + +#else + +#define AVAILABLE_TONE_PINS 1 +#define USE_TIMER2 + +// Leave timer 0 to last. +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1, 0 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255 */ }; + +#endif + + + +static int8_t toneBegin(uint8_t _pin) +{ + int8_t _timer = -1; + + // if we're already using the pin, the timer should be configured. + for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { + if (tone_pins[i] == _pin) { + return pgm_read_byte(tone_pin_to_timer_PGM + i); + } + } + + // search for an unused timer. + for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { + if (tone_pins[i] == 255) { + tone_pins[i] = _pin; + _timer = pgm_read_byte(tone_pin_to_timer_PGM + i); + break; + } + } + + if (_timer != -1) + { + // Set timer specific stuff + // All timers in CTC mode + // 8 bit timers will require changing prescalar values, + // whereas 16 bit timers are set to either ck/1 or ck/64 prescalar + switch (_timer) + { + #if defined(TCCR0A) && defined(TCCR0B) + case 0: + // 8 bit timer + TCCR0A = 0; + TCCR0B = 0; + bitWrite(TCCR0A, WGM01, 1); + bitWrite(TCCR0B, CS00, 1); + timer0_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer0_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + + #if defined(TCCR1A) && defined(TCCR1B) && defined(WGM12) + case 1: + // 16 bit timer + TCCR1A = 0; + TCCR1B = 0; + bitWrite(TCCR1B, WGM12, 1); + bitWrite(TCCR1B, CS10, 1); + timer1_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer1_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + + #if defined(TCCR2A) && defined(TCCR2B) + case 2: + // 8 bit timer + TCCR2A = 0; + TCCR2B = 0; + bitWrite(TCCR2A, WGM21, 1); + bitWrite(TCCR2B, CS20, 1); + timer2_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer2_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + + #if defined(TCCR3A) && defined(TCCR3B) && defined(TIMSK3) + case 3: + // 16 bit timer + TCCR3A = 0; + TCCR3B = 0; + bitWrite(TCCR3B, WGM32, 1); + bitWrite(TCCR3B, CS30, 1); + timer3_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer3_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + + #if defined(TCCR4A) && defined(TCCR4B) && defined(TIMSK4) + case 4: + // 16 bit timer + TCCR4A = 0; + TCCR4B = 0; + #if defined(WGM42) + bitWrite(TCCR4B, WGM42, 1); + #elif defined(CS43) + #warning this may not be correct + // atmega32u4 + bitWrite(TCCR4B, CS43, 1); + #endif + bitWrite(TCCR4B, CS40, 1); + timer4_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer4_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + + #if defined(TCCR5A) && defined(TCCR5B) && defined(TIMSK5) + case 5: + // 16 bit timer + TCCR5A = 0; + TCCR5B = 0; + bitWrite(TCCR5B, WGM52, 1); + bitWrite(TCCR5B, CS50, 1); + timer5_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer5_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + } + } + + return _timer; +} + + + +// frequency (in hertz) and duration (in milliseconds). + +void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) +{ + uint8_t prescalarbits = 0b001; + long toggle_count = 0; + uint32_t ocr = 0; + int8_t _timer; + + _timer = toneBegin(_pin); + + if (_timer >= 0) + { + // Set the pinMode as OUTPUT + pinMode(_pin, OUTPUT); + + // if we are using an 8 bit timer, scan through prescalars to find the best fit + if (_timer == 0 || _timer == 2) + { + ocr = F_CPU / frequency / 2 - 1; + prescalarbits = 0b001; // ck/1: same for both timers + if (ocr > 255) + { + ocr = F_CPU / frequency / 2 / 8 - 1; + prescalarbits = 0b010; // ck/8: same for both timers + + if (_timer == 2 && ocr > 255) + { + ocr = F_CPU / frequency / 2 / 32 - 1; + prescalarbits = 0b011; + } + + if (ocr > 255) + { + ocr = F_CPU / frequency / 2 / 64 - 1; + prescalarbits = _timer == 0 ? 0b011 : 0b100; + + if (_timer == 2 && ocr > 255) + { + ocr = F_CPU / frequency / 2 / 128 - 1; + prescalarbits = 0b101; + } + + if (ocr > 255) + { + ocr = F_CPU / frequency / 2 / 256 - 1; + prescalarbits = _timer == 0 ? 0b100 : 0b110; + if (ocr > 255) + { + // can't do any better than /1024 + ocr = F_CPU / frequency / 2 / 1024 - 1; + prescalarbits = _timer == 0 ? 0b101 : 0b111; + } + } + } + } + +#if defined(TCCR0B) + if (_timer == 0) + { + TCCR0B = prescalarbits; + } + else +#endif +#if defined(TCCR2B) + { + TCCR2B = prescalarbits; + } +#else + { + // dummy place holder to make the above ifdefs work + } +#endif + } + else + { + // two choices for the 16 bit timers: ck/1 or ck/64 + ocr = F_CPU / frequency / 2 - 1; + + prescalarbits = 0b001; + if (ocr > 0xffff) + { + ocr = F_CPU / frequency / 2 / 64 - 1; + prescalarbits = 0b011; + } + + if (_timer == 1) + { +#if defined(TCCR1B) + TCCR1B = (TCCR1B & 0b11111000) | prescalarbits; +#endif + } +#if defined(TCCR3B) + else if (_timer == 3) + TCCR3B = (TCCR3B & 0b11111000) | prescalarbits; +#endif +#if defined(TCCR4B) + else if (_timer == 4) + TCCR4B = (TCCR4B & 0b11111000) | prescalarbits; +#endif +#if defined(TCCR5B) + else if (_timer == 5) + TCCR5B = (TCCR5B & 0b11111000) | prescalarbits; +#endif + + } + + + // Calculate the toggle count + if (duration > 0) + { + toggle_count = 2 * frequency * duration / 1000; + } + else + { + toggle_count = -1; + } + + // Set the OCR for the given timer, + // set the toggle count, + // then turn on the interrupts + switch (_timer) + { + +#if defined(OCR0A) && defined(TIMSK0) && defined(OCIE0A) + case 0: + OCR0A = ocr; + timer0_toggle_count = toggle_count; + bitWrite(TIMSK0, OCIE0A, 1); + break; +#endif + + case 1: +#if defined(OCR1A) && defined(TIMSK1) && defined(OCIE1A) + OCR1A = ocr; + timer1_toggle_count = toggle_count; + bitWrite(TIMSK1, OCIE1A, 1); +#elif defined(OCR1A) && defined(TIMSK) && defined(OCIE1A) + // this combination is for at least the ATmega32 + OCR1A = ocr; + timer1_toggle_count = toggle_count; + bitWrite(TIMSK, OCIE1A, 1); +#endif + break; + +#if defined(OCR2A) && defined(TIMSK2) && defined(OCIE2A) + case 2: + OCR2A = ocr; + timer2_toggle_count = toggle_count; + bitWrite(TIMSK2, OCIE2A, 1); + break; +#endif + +#if defined(TIMSK3) + case 3: + OCR3A = ocr; + timer3_toggle_count = toggle_count; + bitWrite(TIMSK3, OCIE3A, 1); + break; +#endif + +#if defined(TIMSK4) + case 4: + OCR4A = ocr; + timer4_toggle_count = toggle_count; + bitWrite(TIMSK4, OCIE4A, 1); + break; +#endif + +#if defined(OCR5A) && defined(TIMSK5) && defined(OCIE5A) + case 5: + OCR5A = ocr; + timer5_toggle_count = toggle_count; + bitWrite(TIMSK5, OCIE5A, 1); + break; +#endif + + } + } +} + + +// XXX: this function only works properly for timer 2 (the only one we use +// currently). for the others, it should end the tone, but won't restore +// proper PWM functionality for the timer. +void disableTimer(uint8_t _timer) +{ + switch (_timer) + { + case 0: + #if defined(TIMSK0) + TIMSK0 = 0; + #elif defined(TIMSK) + TIMSK = 0; // atmega32 + #endif + break; + +#if defined(TIMSK1) && defined(OCIE1A) + case 1: + bitWrite(TIMSK1, OCIE1A, 0); + break; +#endif + + case 2: + #if defined(TIMSK2) && defined(OCIE2A) + bitWrite(TIMSK2, OCIE2A, 0); // disable interrupt + #endif + #if defined(TCCR2A) && defined(WGM20) + TCCR2A = (1 << WGM20); + #endif + #if defined(TCCR2B) && defined(CS22) + TCCR2B = (TCCR2B & 0b11111000) | (1 << CS22); + #endif + #if defined(OCR2A) + OCR2A = 0; + #endif + break; + +#if defined(TIMSK3) + case 3: + TIMSK3 = 0; + break; +#endif + +#if defined(TIMSK4) + case 4: + TIMSK4 = 0; + break; +#endif + +#if defined(TIMSK5) + case 5: + TIMSK5 = 0; + break; +#endif + } +} + + +void noTone(uint8_t _pin) +{ + int8_t _timer = -1; + + for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { + if (tone_pins[i] == _pin) { + _timer = pgm_read_byte(tone_pin_to_timer_PGM + i); + tone_pins[i] = 255; + } + } + + disableTimer(_timer); + + digitalWrite(_pin, 0); +} + +#ifdef USE_TIMER0 +ISR(TIMER0_COMPA_vect) +{ + if (timer0_toggle_count != 0) + { + // toggle the pin + *timer0_pin_port ^= timer0_pin_mask; + + if (timer0_toggle_count > 0) + timer0_toggle_count--; + } + else + { + disableTimer(0); + *timer0_pin_port &= ~(timer0_pin_mask); // keep pin low after stop + } +} +#endif + + +#ifdef USE_TIMER1 +ISR(TIMER1_COMPA_vect) +{ + if (timer1_toggle_count != 0) + { + // toggle the pin + *timer1_pin_port ^= timer1_pin_mask; + + if (timer1_toggle_count > 0) + timer1_toggle_count--; + } + else + { + disableTimer(1); + *timer1_pin_port &= ~(timer1_pin_mask); // keep pin low after stop + } +} +#endif + + +#ifdef USE_TIMER2 +ISR(TIMER2_COMPA_vect) +{ + + if (timer2_toggle_count != 0) + { + // toggle the pin + *timer2_pin_port ^= timer2_pin_mask; + + if (timer2_toggle_count > 0) + timer2_toggle_count--; + } + else + { + // need to call noTone() so that the tone_pins[] entry is reset, so the + // timer gets initialized next time we call tone(). + // XXX: this assumes timer 2 is always the first one used. + noTone(tone_pins[0]); +// disableTimer(2); +// *timer2_pin_port &= ~(timer2_pin_mask); // keep pin low after stop + } +} +#endif + + +#ifdef USE_TIMER3 +ISR(TIMER3_COMPA_vect) +{ + if (timer3_toggle_count != 0) + { + // toggle the pin + *timer3_pin_port ^= timer3_pin_mask; + + if (timer3_toggle_count > 0) + timer3_toggle_count--; + } + else + { + disableTimer(3); + *timer3_pin_port &= ~(timer3_pin_mask); // keep pin low after stop + } +} +#endif + + +#ifdef USE_TIMER4 +ISR(TIMER4_COMPA_vect) +{ + if (timer4_toggle_count != 0) + { + // toggle the pin + *timer4_pin_port ^= timer4_pin_mask; + + if (timer4_toggle_count > 0) + timer4_toggle_count--; + } + else + { + disableTimer(4); + *timer4_pin_port &= ~(timer4_pin_mask); // keep pin low after stop + } +} +#endif + + +#ifdef USE_TIMER5 +ISR(TIMER5_COMPA_vect) +{ + if (timer5_toggle_count != 0) + { + // toggle the pin + *timer5_pin_port ^= timer5_pin_mask; + + if (timer5_toggle_count > 0) + timer5_toggle_count--; + } + else + { + disableTimer(5); + *timer5_pin_port &= ~(timer5_pin_mask); // keep pin low after stop + } +} +#endif diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBAPI.h b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBAPI.h new file mode 100644 index 0000000000..eb2e5937db --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBAPI.h @@ -0,0 +1,196 @@ + + +#ifndef __USBAPI__ +#define __USBAPI__ + +#if defined(USBCON) + +//================================================================================ +//================================================================================ +// USB + +class USBDevice_ +{ +public: + USBDevice_(); + bool configured(); + + void attach(); + void detach(); // Serial port goes down too... + void poll(); +}; +extern USBDevice_ USBDevice; + +//================================================================================ +//================================================================================ +// Serial over CDC (Serial1 is the physical port) + +class Serial_ : public Stream +{ +private: + ring_buffer *_cdc_rx_buffer; +public: + void begin(uint16_t baud_count); + void end(void); + + virtual int available(void); + virtual void accept(void); + virtual int peek(void); + virtual int read(void); + virtual void flush(void); + virtual size_t write(uint8_t); + using Print::write; // pull in write(str) and write(buf, size) from Print + operator bool(); +}; +extern Serial_ Serial; + +//================================================================================ +//================================================================================ +// Mouse + +#define MOUSE_LEFT 1 +#define MOUSE_RIGHT 2 +#define MOUSE_MIDDLE 4 +#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE) + +class Mouse_ +{ +private: + uint8_t _buttons; + void buttons(uint8_t b); +public: + Mouse_(void); + void begin(void); + void end(void); + void click(uint8_t b = MOUSE_LEFT); + void move(signed char x, signed char y, signed char wheel = 0); + void press(uint8_t b = MOUSE_LEFT); // press LEFT by default + void release(uint8_t b = MOUSE_LEFT); // release LEFT by default + bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default +}; +extern Mouse_ Mouse; + +//================================================================================ +//================================================================================ +// Keyboard + +#define KEY_LEFT_CTRL 0x80 +#define KEY_LEFT_SHIFT 0x81 +#define KEY_LEFT_ALT 0x82 +#define KEY_LEFT_GUI 0x83 +#define KEY_RIGHT_CTRL 0x84 +#define KEY_RIGHT_SHIFT 0x85 +#define KEY_RIGHT_ALT 0x86 +#define KEY_RIGHT_GUI 0x87 + +#define KEY_UP_ARROW 0xDA +#define KEY_DOWN_ARROW 0xD9 +#define KEY_LEFT_ARROW 0xD8 +#define KEY_RIGHT_ARROW 0xD7 +#define KEY_BACKSPACE 0xB2 +#define KEY_TAB 0xB3 +#define KEY_RETURN 0xB0 +#define KEY_ESC 0xB1 +#define KEY_INSERT 0xD1 +#define KEY_DELETE 0xD4 +#define KEY_PAGE_UP 0xD3 +#define KEY_PAGE_DOWN 0xD6 +#define KEY_HOME 0xD2 +#define KEY_END 0xD5 +#define KEY_CAPS_LOCK 0xC1 +#define KEY_F1 0xC2 +#define KEY_F2 0xC3 +#define KEY_F3 0xC4 +#define KEY_F4 0xC5 +#define KEY_F5 0xC6 +#define KEY_F6 0xC7 +#define KEY_F7 0xC8 +#define KEY_F8 0xC9 +#define KEY_F9 0xCA +#define KEY_F10 0xCB +#define KEY_F11 0xCC +#define KEY_F12 0xCD + +// Low level key report: up to 6 keys and shift, ctrl etc at once +typedef struct +{ + uint8_t modifiers; + uint8_t reserved; + uint8_t keys[6]; +} KeyReport; + +class Keyboard_ : public Print +{ +private: + KeyReport _keyReport; + void sendReport(KeyReport* keys); +public: + Keyboard_(void); + void begin(void); + void end(void); + virtual size_t write(uint8_t k); + virtual size_t press(uint8_t k); + virtual size_t release(uint8_t k); + virtual void releaseAll(void); +}; +extern Keyboard_ Keyboard; + +//================================================================================ +//================================================================================ +// Low level API + +typedef struct +{ + uint8_t bmRequestType; + uint8_t bRequest; + uint8_t wValueL; + uint8_t wValueH; + uint16_t wIndex; + uint16_t wLength; +} Setup; + +//================================================================================ +//================================================================================ +// HID 'Driver' + +int HID_GetInterface(uint8_t* interfaceNum); +int HID_GetDescriptor(int i); +bool HID_Setup(Setup& setup); +void HID_SendReport(uint8_t id, const void* data, int len); + +//================================================================================ +//================================================================================ +// MSC 'Driver' + +int MSC_GetInterface(uint8_t* interfaceNum); +int MSC_GetDescriptor(int i); +bool MSC_Setup(Setup& setup); +bool MSC_Data(uint8_t rx,uint8_t tx); + +//================================================================================ +//================================================================================ +// CSC 'Driver' + +int CDC_GetInterface(uint8_t* interfaceNum); +int CDC_GetDescriptor(int i); +bool CDC_Setup(Setup& setup); + +//================================================================================ +//================================================================================ + +#define TRANSFER_PGM 0x80 +#define TRANSFER_RELEASE 0x40 +#define TRANSFER_ZERO 0x20 + +int USB_SendControl(uint8_t flags, const void* d, int len); +int USB_RecvControl(void* d, int len); + +uint8_t USB_Available(uint8_t ep); +int USB_Send(uint8_t ep, const void* data, int len); // blocking +int USB_Recv(uint8_t ep, void* data, int len); // non-blocking +int USB_Recv(uint8_t ep); // non-blocking +void USB_Flush(uint8_t ep); + +#endif + +#endif /* if defined(USBCON) */ \ No newline at end of file diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBCore.cpp b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBCore.cpp new file mode 100644 index 0000000000..d3e0170656 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBCore.cpp @@ -0,0 +1,684 @@ + + +/* Copyright (c) 2010, Peter Barrett +** +** Permission to use, copy, modify, and/or distribute this software for +** any purpose with or without fee is hereby granted, provided that the +** above copyright notice and this permission notice appear in all copies. +** +** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR +** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +** SOFTWARE. +*/ + +#include "Platform.h" +#include "USBAPI.h" +#include "USBDesc.h" + +#if defined(USBCON) + +#define EP_TYPE_CONTROL 0x00 +#define EP_TYPE_BULK_IN 0x81 +#define EP_TYPE_BULK_OUT 0x80 +#define EP_TYPE_INTERRUPT_IN 0xC1 +#define EP_TYPE_INTERRUPT_OUT 0xC0 +#define EP_TYPE_ISOCHRONOUS_IN 0x41 +#define EP_TYPE_ISOCHRONOUS_OUT 0x40 + +/** Pulse generation counters to keep track of the number of milliseconds remaining for each pulse type */ +#define TX_RX_LED_PULSE_MS 100 +volatile u8 TxLEDPulse; /**< Milliseconds remaining for data Tx LED pulse */ +volatile u8 RxLEDPulse; /**< Milliseconds remaining for data Rx LED pulse */ + +//================================================================== +//================================================================== + +extern const u16 STRING_LANGUAGE[] PROGMEM; +extern const u16 STRING_IPRODUCT[] PROGMEM; +extern const u16 STRING_IMANUFACTURER[] PROGMEM; +extern const DeviceDescriptor USB_DeviceDescriptor PROGMEM; +extern const DeviceDescriptor USB_DeviceDescriptorA PROGMEM; + +const u16 STRING_LANGUAGE[2] = { + (3<<8) | (2+2), + 0x0409 // English +}; + +const u16 STRING_IPRODUCT[17] = { + (3<<8) | (2+2*16), +#if USB_PID == 0x8036 + 'A','r','d','u','i','n','o',' ','L','e','o','n','a','r','d','o' +#elif USB_PID == 0x8037 + 'A','r','d','u','i','n','o',' ','M','i','c','r','o',' ',' ',' ' +#elif USB_PID == 0x803C + 'A','r','d','u','i','n','o',' ','E','s','p','l','o','r','a',' ' +#elif USB_PID == 0x9208 + 'L','i','l','y','P','a','d','U','S','B',' ',' ',' ',' ',' ',' ' +#else + 'U','S','B',' ','I','O',' ','B','o','a','r','d',' ',' ',' ',' ' +#endif +}; + +const u16 STRING_IMANUFACTURER[12] = { + (3<<8) | (2+2*11), +#if USB_VID == 0x2341 + 'A','r','d','u','i','n','o',' ','L','L','C' +#elif USB_VID == 0x1b4f + 'S','p','a','r','k','F','u','n',' ',' ',' ' +#else + 'U','n','k','n','o','w','n',' ',' ',' ',' ' +#endif +}; + +#ifdef CDC_ENABLED +#define DEVICE_CLASS 0x02 +#else +#define DEVICE_CLASS 0x00 +#endif + +// DEVICE DESCRIPTOR +const DeviceDescriptor USB_DeviceDescriptor = + D_DEVICE(0x00,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1); + +const DeviceDescriptor USB_DeviceDescriptorA = + D_DEVICE(DEVICE_CLASS,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1); + +//================================================================== +//================================================================== + +volatile u8 _usbConfiguration = 0; + +static inline void WaitIN(void) +{ + while (!(UEINTX & (1< len) + n = len; + len -= n; + { + LockEP lock(ep); + if (ep & TRANSFER_ZERO) + { + while (n--) + Send8(0); + } + else if (ep & TRANSFER_PGM) + { + while (n--) + Send8(pgm_read_byte(data++)); + } + else + { + while (n--) + Send8(*data++); + } + if (!ReadWriteAllowed() || ((len == 0) && (ep & TRANSFER_RELEASE))) // Release full buffer + ReleaseTX(); + } + } + TXLED1; // light the TX LED + TxLEDPulse = TX_RX_LED_PULSE_MS; + return r; +} + +extern const u8 _initEndpoints[] PROGMEM; +const u8 _initEndpoints[] = +{ + 0, + +#ifdef CDC_ENABLED + EP_TYPE_INTERRUPT_IN, // CDC_ENDPOINT_ACM + EP_TYPE_BULK_OUT, // CDC_ENDPOINT_OUT + EP_TYPE_BULK_IN, // CDC_ENDPOINT_IN +#endif + +#ifdef HID_ENABLED + EP_TYPE_INTERRUPT_IN // HID_ENDPOINT_INT +#endif +}; + +#define EP_SINGLE_64 0x32 // EP0 +#define EP_DOUBLE_64 0x36 // Other endpoints + +static +void InitEP(u8 index, u8 type, u8 size) +{ + UENUM = index; + UECONX = 1; + UECFG0X = type; + UECFG1X = size; +} + +static +void InitEndpoints() +{ + for (u8 i = 1; i < sizeof(_initEndpoints); i++) + { + UENUM = i; + UECONX = 1; + UECFG0X = pgm_read_byte(_initEndpoints+i); + UECFG1X = EP_DOUBLE_64; + } + UERST = 0x7E; // And reset them + UERST = 0; +} + +// Handle CLASS_INTERFACE requests +static +bool ClassInterfaceRequest(Setup& setup) +{ + u8 i = setup.wIndex; + +#ifdef CDC_ENABLED + if (CDC_ACM_INTERFACE == i) + return CDC_Setup(setup); +#endif + +#ifdef HID_ENABLED + if (HID_INTERFACE == i) + return HID_Setup(setup); +#endif + return false; +} + +int _cmark; +int _cend; +void InitControl(int end) +{ + SetEP(0); + _cmark = 0; + _cend = end; +} + +static +bool SendControl(u8 d) +{ + if (_cmark < _cend) + { + if (!WaitForINOrOUT()) + return false; + Send8(d); + if (!((_cmark + 1) & 0x3F)) + ClearIN(); // Fifo is full, release this packet + } + _cmark++; + return true; +}; + +// Clipped by _cmark/_cend +int USB_SendControl(u8 flags, const void* d, int len) +{ + int sent = len; + const u8* data = (const u8*)d; + bool pgm = flags & TRANSFER_PGM; + while (len--) + { + u8 c = pgm ? pgm_read_byte(data++) : *data++; + if (!SendControl(c)) + return -1; + } + return sent; +} + +// Does not timeout or cross fifo boundaries +// Will only work for transfers <= 64 bytes +// TODO +int USB_RecvControl(void* d, int len) +{ + WaitOUT(); + Recv((u8*)d,len); + ClearOUT(); + return len; +} + +int SendInterfaces() +{ + int total = 0; + u8 interfaces = 0; + +#ifdef CDC_ENABLED + total = CDC_GetInterface(&interfaces); +#endif + +#ifdef HID_ENABLED + total += HID_GetInterface(&interfaces); +#endif + + return interfaces; +} + +// Construct a dynamic configuration descriptor +// This really needs dynamic endpoint allocation etc +// TODO +static +bool SendConfiguration(int maxlen) +{ + // Count and measure interfaces + InitControl(0); + int interfaces = SendInterfaces(); + ConfigDescriptor config = D_CONFIG(_cmark + sizeof(ConfigDescriptor),interfaces); + + // Now send them + InitControl(maxlen); + USB_SendControl(0,&config,sizeof(ConfigDescriptor)); + SendInterfaces(); + return true; +} + +u8 _cdcComposite = 0; + +static +bool SendDescriptor(Setup& setup) +{ + u8 t = setup.wValueH; + if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t) + return SendConfiguration(setup.wLength); + + InitControl(setup.wLength); +#ifdef HID_ENABLED + if (HID_REPORT_DESCRIPTOR_TYPE == t) + return HID_GetDescriptor(t); +#endif + + u8 desc_length = 0; + const u8* desc_addr = 0; + if (USB_DEVICE_DESCRIPTOR_TYPE == t) + { + if (setup.wLength == 8) + _cdcComposite = 1; + desc_addr = _cdcComposite ? (const u8*)&USB_DeviceDescriptorA : (const u8*)&USB_DeviceDescriptor; + } + else if (USB_STRING_DESCRIPTOR_TYPE == t) + { + if (setup.wValueL == 0) + desc_addr = (const u8*)&STRING_LANGUAGE; + else if (setup.wValueL == IPRODUCT) + desc_addr = (const u8*)&STRING_IPRODUCT; + else if (setup.wValueL == IMANUFACTURER) + desc_addr = (const u8*)&STRING_IMANUFACTURER; + else + return false; + } + + if (desc_addr == 0) + return false; + if (desc_length == 0) + desc_length = pgm_read_byte(desc_addr); + + USB_SendControl(TRANSFER_PGM,desc_addr,desc_length); + return true; +} + +// Endpoint 0 interrupt +ISR(USB_COM_vect) +{ + SetEP(0); + if (!ReceivedSetupInt()) + return; + + Setup setup; + Recv((u8*)&setup,8); + ClearSetupInt(); + + u8 requestType = setup.bmRequestType; + if (requestType & REQUEST_DEVICETOHOST) + WaitIN(); + else + ClearIN(); + + bool ok = true; + if (REQUEST_STANDARD == (requestType & REQUEST_TYPE)) + { + // Standard Requests + u8 r = setup.bRequest; + if (GET_STATUS == r) + { + Send8(0); // TODO + Send8(0); + } + else if (CLEAR_FEATURE == r) + { + } + else if (SET_FEATURE == r) + { + } + else if (SET_ADDRESS == r) + { + WaitIN(); + UDADDR = setup.wValueL | (1<> 8) & 0xFF) + +#define CDC_V1_10 0x0110 +#define CDC_COMMUNICATION_INTERFACE_CLASS 0x02 + +#define CDC_CALL_MANAGEMENT 0x01 +#define CDC_ABSTRACT_CONTROL_MODEL 0x02 +#define CDC_HEADER 0x00 +#define CDC_ABSTRACT_CONTROL_MANAGEMENT 0x02 +#define CDC_UNION 0x06 +#define CDC_CS_INTERFACE 0x24 +#define CDC_CS_ENDPOINT 0x25 +#define CDC_DATA_INTERFACE_CLASS 0x0A + +#define MSC_SUBCLASS_SCSI 0x06 +#define MSC_PROTOCOL_BULK_ONLY 0x50 + +#define HID_HID_DESCRIPTOR_TYPE 0x21 +#define HID_REPORT_DESCRIPTOR_TYPE 0x22 +#define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23 + + +// Device +typedef struct { + u8 len; // 18 + u8 dtype; // 1 USB_DEVICE_DESCRIPTOR_TYPE + u16 usbVersion; // 0x200 + u8 deviceClass; + u8 deviceSubClass; + u8 deviceProtocol; + u8 packetSize0; // Packet 0 + u16 idVendor; + u16 idProduct; + u16 deviceVersion; // 0x100 + u8 iManufacturer; + u8 iProduct; + u8 iSerialNumber; + u8 bNumConfigurations; +} DeviceDescriptor; + +// Config +typedef struct { + u8 len; // 9 + u8 dtype; // 2 + u16 clen; // total length + u8 numInterfaces; + u8 config; + u8 iconfig; + u8 attributes; + u8 maxPower; +} ConfigDescriptor; + +// String + +// Interface +typedef struct +{ + u8 len; // 9 + u8 dtype; // 4 + u8 number; + u8 alternate; + u8 numEndpoints; + u8 interfaceClass; + u8 interfaceSubClass; + u8 protocol; + u8 iInterface; +} InterfaceDescriptor; + +// Endpoint +typedef struct +{ + u8 len; // 7 + u8 dtype; // 5 + u8 addr; + u8 attr; + u16 packetSize; + u8 interval; +} EndpointDescriptor; + +// Interface Association Descriptor +// Used to bind 2 interfaces together in CDC compostite device +typedef struct +{ + u8 len; // 8 + u8 dtype; // 11 + u8 firstInterface; + u8 interfaceCount; + u8 functionClass; + u8 funtionSubClass; + u8 functionProtocol; + u8 iInterface; +} IADDescriptor; + +// CDC CS interface descriptor +typedef struct +{ + u8 len; // 5 + u8 dtype; // 0x24 + u8 subtype; + u8 d0; + u8 d1; +} CDCCSInterfaceDescriptor; + +typedef struct +{ + u8 len; // 4 + u8 dtype; // 0x24 + u8 subtype; + u8 d0; +} CDCCSInterfaceDescriptor4; + +typedef struct +{ + u8 len; + u8 dtype; // 0x24 + u8 subtype; // 1 + u8 bmCapabilities; + u8 bDataInterface; +} CMFunctionalDescriptor; + +typedef struct +{ + u8 len; + u8 dtype; // 0x24 + u8 subtype; // 1 + u8 bmCapabilities; +} ACMFunctionalDescriptor; + +typedef struct +{ + // IAD + IADDescriptor iad; // Only needed on compound device + + // Control + InterfaceDescriptor cif; // + CDCCSInterfaceDescriptor header; + CMFunctionalDescriptor callManagement; // Call Management + ACMFunctionalDescriptor controlManagement; // ACM + CDCCSInterfaceDescriptor functionalDescriptor; // CDC_UNION + EndpointDescriptor cifin; + + // Data + InterfaceDescriptor dif; + EndpointDescriptor in; + EndpointDescriptor out; +} CDCDescriptor; + +typedef struct +{ + InterfaceDescriptor msc; + EndpointDescriptor in; + EndpointDescriptor out; +} MSCDescriptor; + +typedef struct +{ + u8 len; // 9 + u8 dtype; // 0x21 + u8 addr; + u8 versionL; // 0x101 + u8 versionH; // 0x101 + u8 country; + u8 desctype; // 0x22 report + u8 descLenL; + u8 descLenH; +} HIDDescDescriptor; + +typedef struct +{ + InterfaceDescriptor hid; + HIDDescDescriptor desc; + EndpointDescriptor in; +} HIDDescriptor; + + +#define D_DEVICE(_class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs) \ + { 18, 1, 0x200, _class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs } + +#define D_CONFIG(_totalLength,_interfaces) \ + { 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_BUS_POWERED, USB_CONFIG_POWER_MA(500) } + +#define D_INTERFACE(_n,_numEndpoints,_class,_subClass,_protocol) \ + { 9, 4, _n, 0, _numEndpoints, _class,_subClass, _protocol, 0 } + +#define D_ENDPOINT(_addr,_attr,_packetSize, _interval) \ + { 7, 5, _addr,_attr,_packetSize, _interval } + +#define D_IAD(_firstInterface, _count, _class, _subClass, _protocol) \ + { 8, 11, _firstInterface, _count, _class, _subClass, _protocol, 0 } + +#define D_HIDREPORT(_descriptorLength) \ + { 9, 0x21, 0x1, 0x1, 0, 1, 0x22, _descriptorLength, 0 } + +#define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 } +#define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 } + + +#endif \ No newline at end of file diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBDesc.h b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBDesc.h new file mode 100644 index 0000000000..900713e0f9 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBDesc.h @@ -0,0 +1,63 @@ + + +/* Copyright (c) 2011, Peter Barrett +** +** Permission to use, copy, modify, and/or distribute this software for +** any purpose with or without fee is hereby granted, provided that the +** above copyright notice and this permission notice appear in all copies. +** +** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR +** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +** SOFTWARE. +*/ + +#define CDC_ENABLED +#define HID_ENABLED + + +#ifdef CDC_ENABLED +#define CDC_INTERFACE_COUNT 2 +#define CDC_ENPOINT_COUNT 3 +#else +#define CDC_INTERFACE_COUNT 0 +#define CDC_ENPOINT_COUNT 0 +#endif + +#ifdef HID_ENABLED +#define HID_INTERFACE_COUNT 1 +#define HID_ENPOINT_COUNT 1 +#else +#define HID_INTERFACE_COUNT 0 +#define HID_ENPOINT_COUNT 0 +#endif + +#define CDC_ACM_INTERFACE 0 // CDC ACM +#define CDC_DATA_INTERFACE 1 // CDC Data +#define CDC_FIRST_ENDPOINT 1 +#define CDC_ENDPOINT_ACM (CDC_FIRST_ENDPOINT) // CDC First +#define CDC_ENDPOINT_OUT (CDC_FIRST_ENDPOINT+1) +#define CDC_ENDPOINT_IN (CDC_FIRST_ENDPOINT+2) + +#define HID_INTERFACE (CDC_ACM_INTERFACE + CDC_INTERFACE_COUNT) // HID Interface +#define HID_FIRST_ENDPOINT (CDC_FIRST_ENDPOINT + CDC_ENPOINT_COUNT) +#define HID_ENDPOINT_INT (HID_FIRST_ENDPOINT) + +#define INTERFACE_COUNT (MSC_INTERFACE + MSC_INTERFACE_COUNT) + +#ifdef CDC_ENABLED +#define CDC_RX CDC_ENDPOINT_OUT +#define CDC_TX CDC_ENDPOINT_IN +#endif + +#ifdef HID_ENABLED +#define HID_TX HID_ENDPOINT_INT +#endif + +#define IMANUFACTURER 1 +#define IPRODUCT 2 + diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Udp.h b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Udp.h new file mode 100644 index 0000000000..dc5644b9df --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Udp.h @@ -0,0 +1,88 @@ +/* + * Udp.cpp: Library to send/receive UDP packets. + * + * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) + * 1) UDP does not guarantee the order in which assembled UDP packets are received. This + * might not happen often in practice, but in larger network topologies, a UDP + * packet can be received out of sequence. + * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being + * aware of it. Again, this may not be a concern in practice on small local networks. + * For more information, see http://www.cafeaulait.org/course/week12/35.html + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ + +#ifndef udp_h +#define udp_h + +#include +#include + +class UDP : public Stream { + +public: + virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual void stop() =0; // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port) =0; + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port) =0; + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket() =0; + // Write a single byte into the packet + virtual size_t write(uint8_t) =0; + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size) =0; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket() =0; + // Number of bytes remaining in the current packet + virtual int available() =0; + // Read a single byte from the current packet + virtual int read() =0; + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len) =0; + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) =0; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek() =0; + virtual void flush() =0; // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP() =0; + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort() =0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; +}; + +#endif diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WCharacter.h b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WCharacter.h new file mode 100644 index 0000000000..79733b50a5 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WCharacter.h @@ -0,0 +1,168 @@ +/* + WCharacter.h - Character utility functions for Wiring & Arduino + Copyright (c) 2010 Hernando Barragan. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef Character_h +#define Character_h + +#include + +// WCharacter.h prototypes +inline boolean isAlphaNumeric(int c) __attribute__((always_inline)); +inline boolean isAlpha(int c) __attribute__((always_inline)); +inline boolean isAscii(int c) __attribute__((always_inline)); +inline boolean isWhitespace(int c) __attribute__((always_inline)); +inline boolean isControl(int c) __attribute__((always_inline)); +inline boolean isDigit(int c) __attribute__((always_inline)); +inline boolean isGraph(int c) __attribute__((always_inline)); +inline boolean isLowerCase(int c) __attribute__((always_inline)); +inline boolean isPrintable(int c) __attribute__((always_inline)); +inline boolean isPunct(int c) __attribute__((always_inline)); +inline boolean isSpace(int c) __attribute__((always_inline)); +inline boolean isUpperCase(int c) __attribute__((always_inline)); +inline boolean isHexadecimalDigit(int c) __attribute__((always_inline)); +inline int toAscii(int c) __attribute__((always_inline)); +inline int toLowerCase(int c) __attribute__((always_inline)); +inline int toUpperCase(int c)__attribute__((always_inline)); + + +// Checks for an alphanumeric character. +// It is equivalent to (isalpha(c) || isdigit(c)). +inline boolean isAlphaNumeric(int c) +{ + return ( isalnum(c) == 0 ? false : true); +} + + +// Checks for an alphabetic character. +// It is equivalent to (isupper(c) || islower(c)). +inline boolean isAlpha(int c) +{ + return ( isalpha(c) == 0 ? false : true); +} + + +// Checks whether c is a 7-bit unsigned char value +// that fits into the ASCII character set. +inline boolean isAscii(int c) +{ + return ( isascii (c) == 0 ? false : true); +} + + +// Checks for a blank character, that is, a space or a tab. +inline boolean isWhitespace(int c) +{ + return ( isblank (c) == 0 ? false : true); +} + + +// Checks for a control character. +inline boolean isControl(int c) +{ + return ( iscntrl (c) == 0 ? false : true); +} + + +// Checks for a digit (0 through 9). +inline boolean isDigit(int c) +{ + return ( isdigit (c) == 0 ? false : true); +} + + +// Checks for any printable character except space. +inline boolean isGraph(int c) +{ + return ( isgraph (c) == 0 ? false : true); +} + + +// Checks for a lower-case character. +inline boolean isLowerCase(int c) +{ + return (islower (c) == 0 ? false : true); +} + + +// Checks for any printable character including space. +inline boolean isPrintable(int c) +{ + return ( isprint (c) == 0 ? false : true); +} + + +// Checks for any printable character which is not a space +// or an alphanumeric character. +inline boolean isPunct(int c) +{ + return ( ispunct (c) == 0 ? false : true); +} + + +// Checks for white-space characters. For the avr-libc library, +// these are: space, formfeed ('\f'), newline ('\n'), carriage +// return ('\r'), horizontal tab ('\t'), and vertical tab ('\v'). +inline boolean isSpace(int c) +{ + return ( isspace (c) == 0 ? false : true); +} + + +// Checks for an uppercase letter. +inline boolean isUpperCase(int c) +{ + return ( isupper (c) == 0 ? false : true); +} + + +// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7 +// 8 9 a b c d e f A B C D E F. +inline boolean isHexadecimalDigit(int c) +{ + return ( isxdigit (c) == 0 ? false : true); +} + + +// Converts c to a 7-bit unsigned char value that fits into the +// ASCII character set, by clearing the high-order bits. +inline int toAscii(int c) +{ + return toascii (c); +} + + +// Warning: +// Many people will be unhappy if you use this function. +// This function will convert accented letters into random +// characters. + +// Converts the letter c to lower case, if possible. +inline int toLowerCase(int c) +{ + return tolower (c); +} + + +// Converts the letter c to upper case, if possible. +inline int toUpperCase(int c) +{ + return toupper (c); +} + +#endif \ No newline at end of file diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WInterrupts.c b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WInterrupts.c new file mode 100644 index 0000000000..62efc9cadb --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WInterrupts.c @@ -0,0 +1,322 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Wiring project - http://wiring.uniandes.edu.co + + Copyright (c) 2004-05 Hernando Barragan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + Modified 24 November 2006 by David A. Mellis + Modified 1 August 2010 by Mark Sproul +*/ + +#include +#include +#include +#include +#include + +#include "wiring_private.h" + +static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS]; +// volatile static voidFuncPtr twiIntFunc; + +void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) { + if(interruptNum < EXTERNAL_NUM_INTERRUPTS) { + intFunc[interruptNum] = userFunc; + + // Configure the interrupt mode (trigger on low input, any change, rising + // edge, or falling edge). The mode constants were chosen to correspond + // to the configuration bits in the hardware register, so we simply shift + // the mode into place. + + // Enable the interrupt. + + switch (interruptNum) { +#if defined(__AVR_ATmega32U4__) + // I hate doing this, but the register assignment differs between the 1280/2560 + // and the 32U4. Since avrlib defines registers PCMSK1 and PCMSK2 that aren't + // even present on the 32U4 this is the only way to distinguish between them. + case 0: + EICRA = (EICRA & ~((1<= howbig) { + return howsmall; + } + long diff = howbig - howsmall; + return random(diff) + howsmall; +} + +long map(long x, long in_min, long in_max, long out_min, long out_max) +{ + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +unsigned int makeWord(unsigned int w) { return w; } +unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; } \ No newline at end of file diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WString.cpp b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WString.cpp new file mode 100644 index 0000000000..c6839fc0d9 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WString.cpp @@ -0,0 +1,645 @@ +/* + WString.cpp - String library for Wiring & Arduino + ...mostly rewritten by Paul Stoffregen... + Copyright (c) 2009-10 Hernando Barragan. All rights reserved. + Copyright 2011, Paul Stoffregen, paul@pjrc.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "WString.h" + + +/*********************************************/ +/* Constructors */ +/*********************************************/ + +String::String(const char *cstr) +{ + init(); + if (cstr) copy(cstr, strlen(cstr)); +} + +String::String(const String &value) +{ + init(); + *this = value; +} + +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +String::String(String &&rval) +{ + init(); + move(rval); +} +String::String(StringSumHelper &&rval) +{ + init(); + move(rval); +} +#endif + +String::String(char c) +{ + init(); + char buf[2]; + buf[0] = c; + buf[1] = 0; + *this = buf; +} + +String::String(unsigned char value, unsigned char base) +{ + init(); + char buf[9]; + utoa(value, buf, base); + *this = buf; +} + +String::String(int value, unsigned char base) +{ + init(); + char buf[18]; + itoa(value, buf, base); + *this = buf; +} + +String::String(unsigned int value, unsigned char base) +{ + init(); + char buf[17]; + utoa(value, buf, base); + *this = buf; +} + +String::String(long value, unsigned char base) +{ + init(); + char buf[34]; + ltoa(value, buf, base); + *this = buf; +} + +String::String(unsigned long value, unsigned char base) +{ + init(); + char buf[33]; + ultoa(value, buf, base); + *this = buf; +} + +String::~String() +{ + free(buffer); +} + +/*********************************************/ +/* Memory Management */ +/*********************************************/ + +inline void String::init(void) +{ + buffer = NULL; + capacity = 0; + len = 0; + flags = 0; +} + +void String::invalidate(void) +{ + if (buffer) free(buffer); + buffer = NULL; + capacity = len = 0; +} + +unsigned char String::reserve(unsigned int size) +{ + if (buffer && capacity >= size) return 1; + if (changeBuffer(size)) { + if (len == 0) buffer[0] = 0; + return 1; + } + return 0; +} + +unsigned char String::changeBuffer(unsigned int maxStrLen) +{ + char *newbuffer = (char *)realloc(buffer, maxStrLen + 1); + if (newbuffer) { + buffer = newbuffer; + capacity = maxStrLen; + return 1; + } + return 0; +} + +/*********************************************/ +/* Copy and Move */ +/*********************************************/ + +String & String::copy(const char *cstr, unsigned int length) +{ + if (!reserve(length)) { + invalidate(); + return *this; + } + len = length; + strcpy(buffer, cstr); + return *this; +} + +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +void String::move(String &rhs) +{ + if (buffer) { + if (capacity >= rhs.len) { + strcpy(buffer, rhs.buffer); + len = rhs.len; + rhs.len = 0; + return; + } else { + free(buffer); + } + } + buffer = rhs.buffer; + capacity = rhs.capacity; + len = rhs.len; + rhs.buffer = NULL; + rhs.capacity = 0; + rhs.len = 0; +} +#endif + +String & String::operator = (const String &rhs) +{ + if (this == &rhs) return *this; + + if (rhs.buffer) copy(rhs.buffer, rhs.len); + else invalidate(); + + return *this; +} + +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +String & String::operator = (String &&rval) +{ + if (this != &rval) move(rval); + return *this; +} + +String & String::operator = (StringSumHelper &&rval) +{ + if (this != &rval) move(rval); + return *this; +} +#endif + +String & String::operator = (const char *cstr) +{ + if (cstr) copy(cstr, strlen(cstr)); + else invalidate(); + + return *this; +} + +/*********************************************/ +/* concat */ +/*********************************************/ + +unsigned char String::concat(const String &s) +{ + return concat(s.buffer, s.len); +} + +unsigned char String::concat(const char *cstr, unsigned int length) +{ + unsigned int newlen = len + length; + if (!cstr) return 0; + if (length == 0) return 1; + if (!reserve(newlen)) return 0; + strcpy(buffer + len, cstr); + len = newlen; + return 1; +} + +unsigned char String::concat(const char *cstr) +{ + if (!cstr) return 0; + return concat(cstr, strlen(cstr)); +} + +unsigned char String::concat(char c) +{ + char buf[2]; + buf[0] = c; + buf[1] = 0; + return concat(buf, 1); +} + +unsigned char String::concat(unsigned char num) +{ + char buf[4]; + itoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(int num) +{ + char buf[7]; + itoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(unsigned int num) +{ + char buf[6]; + utoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(long num) +{ + char buf[12]; + ltoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(unsigned long num) +{ + char buf[11]; + ultoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +/*********************************************/ +/* Concatenate */ +/*********************************************/ + +StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(rhs.buffer, rhs.len)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr) +{ + StringSumHelper &a = const_cast(lhs); + if (!cstr || !a.concat(cstr, strlen(cstr))) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, char c) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(c)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, int num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, long num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +/*********************************************/ +/* Comparison */ +/*********************************************/ + +int String::compareTo(const String &s) const +{ + if (!buffer || !s.buffer) { + if (s.buffer && s.len > 0) return 0 - *(unsigned char *)s.buffer; + if (buffer && len > 0) return *(unsigned char *)buffer; + return 0; + } + return strcmp(buffer, s.buffer); +} + +unsigned char String::equals(const String &s2) const +{ + return (len == s2.len && compareTo(s2) == 0); +} + +unsigned char String::equals(const char *cstr) const +{ + if (len == 0) return (cstr == NULL || *cstr == 0); + if (cstr == NULL) return buffer[0] == 0; + return strcmp(buffer, cstr) == 0; +} + +unsigned char String::operator<(const String &rhs) const +{ + return compareTo(rhs) < 0; +} + +unsigned char String::operator>(const String &rhs) const +{ + return compareTo(rhs) > 0; +} + +unsigned char String::operator<=(const String &rhs) const +{ + return compareTo(rhs) <= 0; +} + +unsigned char String::operator>=(const String &rhs) const +{ + return compareTo(rhs) >= 0; +} + +unsigned char String::equalsIgnoreCase( const String &s2 ) const +{ + if (this == &s2) return 1; + if (len != s2.len) return 0; + if (len == 0) return 1; + const char *p1 = buffer; + const char *p2 = s2.buffer; + while (*p1) { + if (tolower(*p1++) != tolower(*p2++)) return 0; + } + return 1; +} + +unsigned char String::startsWith( const String &s2 ) const +{ + if (len < s2.len) return 0; + return startsWith(s2, 0); +} + +unsigned char String::startsWith( const String &s2, unsigned int offset ) const +{ + if (offset > len - s2.len || !buffer || !s2.buffer) return 0; + return strncmp( &buffer[offset], s2.buffer, s2.len ) == 0; +} + +unsigned char String::endsWith( const String &s2 ) const +{ + if ( len < s2.len || !buffer || !s2.buffer) return 0; + return strcmp(&buffer[len - s2.len], s2.buffer) == 0; +} + +/*********************************************/ +/* Character Access */ +/*********************************************/ + +char String::charAt(unsigned int loc) const +{ + return operator[](loc); +} + +void String::setCharAt(unsigned int loc, char c) +{ + if (loc < len) buffer[loc] = c; +} + +char & String::operator[](unsigned int index) +{ + static char dummy_writable_char; + if (index >= len || !buffer) { + dummy_writable_char = 0; + return dummy_writable_char; + } + return buffer[index]; +} + +char String::operator[]( unsigned int index ) const +{ + if (index >= len || !buffer) return 0; + return buffer[index]; +} + +void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const +{ + if (!bufsize || !buf) return; + if (index >= len) { + buf[0] = 0; + return; + } + unsigned int n = bufsize - 1; + if (n > len - index) n = len - index; + strncpy((char *)buf, buffer + index, n); + buf[n] = 0; +} + +/*********************************************/ +/* Search */ +/*********************************************/ + +int String::indexOf(char c) const +{ + return indexOf(c, 0); +} + +int String::indexOf( char ch, unsigned int fromIndex ) const +{ + if (fromIndex >= len) return -1; + const char* temp = strchr(buffer + fromIndex, ch); + if (temp == NULL) return -1; + return temp - buffer; +} + +int String::indexOf(const String &s2) const +{ + return indexOf(s2, 0); +} + +int String::indexOf(const String &s2, unsigned int fromIndex) const +{ + if (fromIndex >= len) return -1; + const char *found = strstr(buffer + fromIndex, s2.buffer); + if (found == NULL) return -1; + return found - buffer; +} + +int String::lastIndexOf( char theChar ) const +{ + return lastIndexOf(theChar, len - 1); +} + +int String::lastIndexOf(char ch, unsigned int fromIndex) const +{ + if (fromIndex >= len) return -1; + char tempchar = buffer[fromIndex + 1]; + buffer[fromIndex + 1] = '\0'; + char* temp = strrchr( buffer, ch ); + buffer[fromIndex + 1] = tempchar; + if (temp == NULL) return -1; + return temp - buffer; +} + +int String::lastIndexOf(const String &s2) const +{ + return lastIndexOf(s2, len - s2.len); +} + +int String::lastIndexOf(const String &s2, unsigned int fromIndex) const +{ + if (s2.len == 0 || len == 0 || s2.len > len) return -1; + if (fromIndex >= len) fromIndex = len - 1; + int found = -1; + for (char *p = buffer; p <= buffer + fromIndex; p++) { + p = strstr(p, s2.buffer); + if (!p) break; + if ((unsigned int)(p - buffer) <= fromIndex) found = p - buffer; + } + return found; +} + +String String::substring( unsigned int left ) const +{ + return substring(left, len); +} + +String String::substring(unsigned int left, unsigned int right) const +{ + if (left > right) { + unsigned int temp = right; + right = left; + left = temp; + } + String out; + if (left > len) return out; + if (right > len) right = len; + char temp = buffer[right]; // save the replaced character + buffer[right] = '\0'; + out = buffer + left; // pointer arithmetic + buffer[right] = temp; //restore character + return out; +} + +/*********************************************/ +/* Modification */ +/*********************************************/ + +void String::replace(char find, char replace) +{ + if (!buffer) return; + for (char *p = buffer; *p; p++) { + if (*p == find) *p = replace; + } +} + +void String::replace(const String& find, const String& replace) +{ + if (len == 0 || find.len == 0) return; + int diff = replace.len - find.len; + char *readFrom = buffer; + char *foundAt; + if (diff == 0) { + while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { + memcpy(foundAt, replace.buffer, replace.len); + readFrom = foundAt + replace.len; + } + } else if (diff < 0) { + char *writeTo = buffer; + while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { + unsigned int n = foundAt - readFrom; + memcpy(writeTo, readFrom, n); + writeTo += n; + memcpy(writeTo, replace.buffer, replace.len); + writeTo += replace.len; + readFrom = foundAt + find.len; + len += diff; + } + strcpy(writeTo, readFrom); + } else { + unsigned int size = len; // compute size needed for result + while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { + readFrom = foundAt + find.len; + size += diff; + } + if (size == len) return; + if (size > capacity && !changeBuffer(size)) return; // XXX: tell user! + int index = len - 1; + while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) { + readFrom = buffer + index + find.len; + memmove(readFrom + diff, readFrom, len - (readFrom - buffer)); + len += diff; + buffer[len] = 0; + memcpy(buffer + index, replace.buffer, replace.len); + index--; + } + } +} + +void String::toLowerCase(void) +{ + if (!buffer) return; + for (char *p = buffer; *p; p++) { + *p = tolower(*p); + } +} + +void String::toUpperCase(void) +{ + if (!buffer) return; + for (char *p = buffer; *p; p++) { + *p = toupper(*p); + } +} + +void String::trim(void) +{ + if (!buffer || len == 0) return; + char *begin = buffer; + while (isspace(*begin)) begin++; + char *end = buffer + len - 1; + while (isspace(*end) && end >= begin) end--; + len = end + 1 - begin; + if (begin > buffer) memcpy(buffer, begin, len); + buffer[len] = 0; +} + +/*********************************************/ +/* Parsing / Conversion */ +/*********************************************/ + +long String::toInt(void) const +{ + if (buffer) return atol(buffer); + return 0; +} + + diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WString.h b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WString.h new file mode 100644 index 0000000000..947325e5f5 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WString.h @@ -0,0 +1,205 @@ +/* + WString.h - String library for Wiring & Arduino + ...mostly rewritten by Paul Stoffregen... + Copyright (c) 2009-10 Hernando Barragan. All right reserved. + Copyright 2011, Paul Stoffregen, paul@pjrc.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef String_class_h +#define String_class_h +#ifdef __cplusplus + +#include +#include +#include +#include + +// When compiling programs with this class, the following gcc parameters +// dramatically increase performance and memory (RAM) efficiency, typically +// with little or no increase in code size. +// -felide-constructors +// -std=c++0x + +class __FlashStringHelper; +#define F(string_literal) (reinterpret_cast(PSTR(string_literal))) + +// An inherited class for holding the result of a concatenation. These +// result objects are assumed to be writable by subsequent concatenations. +class StringSumHelper; + +// The string class +class String +{ + // use a function pointer to allow for "if (s)" without the + // complications of an operator bool(). for more information, see: + // http://www.artima.com/cppsource/safebool.html + typedef void (String::*StringIfHelperType)() const; + void StringIfHelper() const {} + +public: + // constructors + // creates a copy of the initial value. + // if the initial value is null or invalid, or if memory allocation + // fails, the string will be marked as invalid (i.e. "if (s)" will + // be false). + String(const char *cstr = ""); + String(const String &str); + #ifdef __GXX_EXPERIMENTAL_CXX0X__ + String(String &&rval); + String(StringSumHelper &&rval); + #endif + explicit String(char c); + explicit String(unsigned char, unsigned char base=10); + explicit String(int, unsigned char base=10); + explicit String(unsigned int, unsigned char base=10); + explicit String(long, unsigned char base=10); + explicit String(unsigned long, unsigned char base=10); + ~String(void); + + // memory management + // return true on success, false on failure (in which case, the string + // is left unchanged). reserve(0), if successful, will validate an + // invalid string (i.e., "if (s)" will be true afterwards) + unsigned char reserve(unsigned int size); + inline unsigned int length(void) const {return len;} + + // creates a copy of the assigned value. if the value is null or + // invalid, or if the memory allocation fails, the string will be + // marked as invalid ("if (s)" will be false). + String & operator = (const String &rhs); + String & operator = (const char *cstr); + #ifdef __GXX_EXPERIMENTAL_CXX0X__ + String & operator = (String &&rval); + String & operator = (StringSumHelper &&rval); + #endif + + // concatenate (works w/ built-in types) + + // returns true on success, false on failure (in which case, the string + // is left unchanged). if the argument is null or invalid, the + // concatenation is considered unsucessful. + unsigned char concat(const String &str); + unsigned char concat(const char *cstr); + unsigned char concat(char c); + unsigned char concat(unsigned char c); + unsigned char concat(int num); + unsigned char concat(unsigned int num); + unsigned char concat(long num); + unsigned char concat(unsigned long num); + + // if there's not enough memory for the concatenated value, the string + // will be left unchanged (but this isn't signalled in any way) + String & operator += (const String &rhs) {concat(rhs); return (*this);} + String & operator += (const char *cstr) {concat(cstr); return (*this);} + String & operator += (char c) {concat(c); return (*this);} + String & operator += (unsigned char num) {concat(num); return (*this);} + String & operator += (int num) {concat(num); return (*this);} + String & operator += (unsigned int num) {concat(num); return (*this);} + String & operator += (long num) {concat(num); return (*this);} + String & operator += (unsigned long num) {concat(num); return (*this);} + + friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs); + friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr); + friend StringSumHelper & operator + (const StringSumHelper &lhs, char c); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, int num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, long num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num); + + // comparison (only works w/ Strings and "strings") + operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; } + int compareTo(const String &s) const; + unsigned char equals(const String &s) const; + unsigned char equals(const char *cstr) const; + unsigned char operator == (const String &rhs) const {return equals(rhs);} + unsigned char operator == (const char *cstr) const {return equals(cstr);} + unsigned char operator != (const String &rhs) const {return !equals(rhs);} + unsigned char operator != (const char *cstr) const {return !equals(cstr);} + unsigned char operator < (const String &rhs) const; + unsigned char operator > (const String &rhs) const; + unsigned char operator <= (const String &rhs) const; + unsigned char operator >= (const String &rhs) const; + unsigned char equalsIgnoreCase(const String &s) const; + unsigned char startsWith( const String &prefix) const; + unsigned char startsWith(const String &prefix, unsigned int offset) const; + unsigned char endsWith(const String &suffix) const; + + // character acccess + char charAt(unsigned int index) const; + void setCharAt(unsigned int index, char c); + char operator [] (unsigned int index) const; + char& operator [] (unsigned int index); + void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const; + void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const + {getBytes((unsigned char *)buf, bufsize, index);} + + // search + int indexOf( char ch ) const; + int indexOf( char ch, unsigned int fromIndex ) const; + int indexOf( const String &str ) const; + int indexOf( const String &str, unsigned int fromIndex ) const; + int lastIndexOf( char ch ) const; + int lastIndexOf( char ch, unsigned int fromIndex ) const; + int lastIndexOf( const String &str ) const; + int lastIndexOf( const String &str, unsigned int fromIndex ) const; + String substring( unsigned int beginIndex ) const; + String substring( unsigned int beginIndex, unsigned int endIndex ) const; + + // modification + void replace(char find, char replace); + void replace(const String& find, const String& replace); + void toLowerCase(void); + void toUpperCase(void); + void trim(void); + + // parsing/conversion + long toInt(void) const; + +protected: + char *buffer; // the actual char array + unsigned int capacity; // the array length minus one (for the '\0') + unsigned int len; // the String length (not counting the '\0') + unsigned char flags; // unused, for future features +protected: + void init(void); + void invalidate(void); + unsigned char changeBuffer(unsigned int maxStrLen); + unsigned char concat(const char *cstr, unsigned int length); + + // copy and move + String & copy(const char *cstr, unsigned int length); + #ifdef __GXX_EXPERIMENTAL_CXX0X__ + void move(String &rhs); + #endif +}; + +class StringSumHelper : public String +{ +public: + StringSumHelper(const String &s) : String(s) {} + StringSumHelper(const char *p) : String(p) {} + StringSumHelper(char c) : String(c) {} + StringSumHelper(unsigned char num) : String(num) {} + StringSumHelper(int num) : String(num) {} + StringSumHelper(unsigned int num) : String(num) {} + StringSumHelper(long num) : String(num) {} + StringSumHelper(unsigned long num) : String(num) {} +}; + +#endif // __cplusplus +#endif // String_class_h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/binary.h b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/binary.h new file mode 100644 index 0000000000..af1498033a --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/binary.h @@ -0,0 +1,515 @@ +#ifndef Binary_h +#define Binary_h + +#define B0 0 +#define B00 0 +#define B000 0 +#define B0000 0 +#define B00000 0 +#define B000000 0 +#define B0000000 0 +#define B00000000 0 +#define B1 1 +#define B01 1 +#define B001 1 +#define B0001 1 +#define B00001 1 +#define B000001 1 +#define B0000001 1 +#define B00000001 1 +#define B10 2 +#define B010 2 +#define B0010 2 +#define B00010 2 +#define B000010 2 +#define B0000010 2 +#define B00000010 2 +#define B11 3 +#define B011 3 +#define B0011 3 +#define B00011 3 +#define B000011 3 +#define B0000011 3 +#define B00000011 3 +#define B100 4 +#define B0100 4 +#define B00100 4 +#define B000100 4 +#define B0000100 4 +#define B00000100 4 +#define B101 5 +#define B0101 5 +#define B00101 5 +#define B000101 5 +#define B0000101 5 +#define B00000101 5 +#define B110 6 +#define B0110 6 +#define B00110 6 +#define B000110 6 +#define B0000110 6 +#define B00000110 6 +#define B111 7 +#define B0111 7 +#define B00111 7 +#define B000111 7 +#define B0000111 7 +#define B00000111 7 +#define B1000 8 +#define B01000 8 +#define B001000 8 +#define B0001000 8 +#define B00001000 8 +#define B1001 9 +#define B01001 9 +#define B001001 9 +#define B0001001 9 +#define B00001001 9 +#define B1010 10 +#define B01010 10 +#define B001010 10 +#define B0001010 10 +#define B00001010 10 +#define B1011 11 +#define B01011 11 +#define B001011 11 +#define B0001011 11 +#define B00001011 11 +#define B1100 12 +#define B01100 12 +#define B001100 12 +#define B0001100 12 +#define B00001100 12 +#define B1101 13 +#define B01101 13 +#define B001101 13 +#define B0001101 13 +#define B00001101 13 +#define B1110 14 +#define B01110 14 +#define B001110 14 +#define B0001110 14 +#define B00001110 14 +#define B1111 15 +#define B01111 15 +#define B001111 15 +#define B0001111 15 +#define B00001111 15 +#define B10000 16 +#define B010000 16 +#define B0010000 16 +#define B00010000 16 +#define B10001 17 +#define B010001 17 +#define B0010001 17 +#define B00010001 17 +#define B10010 18 +#define B010010 18 +#define B0010010 18 +#define B00010010 18 +#define B10011 19 +#define B010011 19 +#define B0010011 19 +#define B00010011 19 +#define B10100 20 +#define B010100 20 +#define B0010100 20 +#define B00010100 20 +#define B10101 21 +#define B010101 21 +#define B0010101 21 +#define B00010101 21 +#define B10110 22 +#define B010110 22 +#define B0010110 22 +#define B00010110 22 +#define B10111 23 +#define B010111 23 +#define B0010111 23 +#define B00010111 23 +#define B11000 24 +#define B011000 24 +#define B0011000 24 +#define B00011000 24 +#define B11001 25 +#define B011001 25 +#define B0011001 25 +#define B00011001 25 +#define B11010 26 +#define B011010 26 +#define B0011010 26 +#define B00011010 26 +#define B11011 27 +#define B011011 27 +#define B0011011 27 +#define B00011011 27 +#define B11100 28 +#define B011100 28 +#define B0011100 28 +#define B00011100 28 +#define B11101 29 +#define B011101 29 +#define B0011101 29 +#define B00011101 29 +#define B11110 30 +#define B011110 30 +#define B0011110 30 +#define B00011110 30 +#define B11111 31 +#define B011111 31 +#define B0011111 31 +#define B00011111 31 +#define B100000 32 +#define B0100000 32 +#define B00100000 32 +#define B100001 33 +#define B0100001 33 +#define B00100001 33 +#define B100010 34 +#define B0100010 34 +#define B00100010 34 +#define B100011 35 +#define B0100011 35 +#define B00100011 35 +#define B100100 36 +#define B0100100 36 +#define B00100100 36 +#define B100101 37 +#define B0100101 37 +#define B00100101 37 +#define B100110 38 +#define B0100110 38 +#define B00100110 38 +#define B100111 39 +#define B0100111 39 +#define B00100111 39 +#define B101000 40 +#define B0101000 40 +#define B00101000 40 +#define B101001 41 +#define B0101001 41 +#define B00101001 41 +#define B101010 42 +#define B0101010 42 +#define B00101010 42 +#define B101011 43 +#define B0101011 43 +#define B00101011 43 +#define B101100 44 +#define B0101100 44 +#define B00101100 44 +#define B101101 45 +#define B0101101 45 +#define B00101101 45 +#define B101110 46 +#define B0101110 46 +#define B00101110 46 +#define B101111 47 +#define B0101111 47 +#define B00101111 47 +#define B110000 48 +#define B0110000 48 +#define B00110000 48 +#define B110001 49 +#define B0110001 49 +#define B00110001 49 +#define B110010 50 +#define B0110010 50 +#define B00110010 50 +#define B110011 51 +#define B0110011 51 +#define B00110011 51 +#define B110100 52 +#define B0110100 52 +#define B00110100 52 +#define B110101 53 +#define B0110101 53 +#define B00110101 53 +#define B110110 54 +#define B0110110 54 +#define B00110110 54 +#define B110111 55 +#define B0110111 55 +#define B00110111 55 +#define B111000 56 +#define B0111000 56 +#define B00111000 56 +#define B111001 57 +#define B0111001 57 +#define B00111001 57 +#define B111010 58 +#define B0111010 58 +#define B00111010 58 +#define B111011 59 +#define B0111011 59 +#define B00111011 59 +#define B111100 60 +#define B0111100 60 +#define B00111100 60 +#define B111101 61 +#define B0111101 61 +#define B00111101 61 +#define B111110 62 +#define B0111110 62 +#define B00111110 62 +#define B111111 63 +#define B0111111 63 +#define B00111111 63 +#define B1000000 64 +#define B01000000 64 +#define B1000001 65 +#define B01000001 65 +#define B1000010 66 +#define B01000010 66 +#define B1000011 67 +#define B01000011 67 +#define B1000100 68 +#define B01000100 68 +#define B1000101 69 +#define B01000101 69 +#define B1000110 70 +#define B01000110 70 +#define B1000111 71 +#define B01000111 71 +#define B1001000 72 +#define B01001000 72 +#define B1001001 73 +#define B01001001 73 +#define B1001010 74 +#define B01001010 74 +#define B1001011 75 +#define B01001011 75 +#define B1001100 76 +#define B01001100 76 +#define B1001101 77 +#define B01001101 77 +#define B1001110 78 +#define B01001110 78 +#define B1001111 79 +#define B01001111 79 +#define B1010000 80 +#define B01010000 80 +#define B1010001 81 +#define B01010001 81 +#define B1010010 82 +#define B01010010 82 +#define B1010011 83 +#define B01010011 83 +#define B1010100 84 +#define B01010100 84 +#define B1010101 85 +#define B01010101 85 +#define B1010110 86 +#define B01010110 86 +#define B1010111 87 +#define B01010111 87 +#define B1011000 88 +#define B01011000 88 +#define B1011001 89 +#define B01011001 89 +#define B1011010 90 +#define B01011010 90 +#define B1011011 91 +#define B01011011 91 +#define B1011100 92 +#define B01011100 92 +#define B1011101 93 +#define B01011101 93 +#define B1011110 94 +#define B01011110 94 +#define B1011111 95 +#define B01011111 95 +#define B1100000 96 +#define B01100000 96 +#define B1100001 97 +#define B01100001 97 +#define B1100010 98 +#define B01100010 98 +#define B1100011 99 +#define B01100011 99 +#define B1100100 100 +#define B01100100 100 +#define B1100101 101 +#define B01100101 101 +#define B1100110 102 +#define B01100110 102 +#define B1100111 103 +#define B01100111 103 +#define B1101000 104 +#define B01101000 104 +#define B1101001 105 +#define B01101001 105 +#define B1101010 106 +#define B01101010 106 +#define B1101011 107 +#define B01101011 107 +#define B1101100 108 +#define B01101100 108 +#define B1101101 109 +#define B01101101 109 +#define B1101110 110 +#define B01101110 110 +#define B1101111 111 +#define B01101111 111 +#define B1110000 112 +#define B01110000 112 +#define B1110001 113 +#define B01110001 113 +#define B1110010 114 +#define B01110010 114 +#define B1110011 115 +#define B01110011 115 +#define B1110100 116 +#define B01110100 116 +#define B1110101 117 +#define B01110101 117 +#define B1110110 118 +#define B01110110 118 +#define B1110111 119 +#define B01110111 119 +#define B1111000 120 +#define B01111000 120 +#define B1111001 121 +#define B01111001 121 +#define B1111010 122 +#define B01111010 122 +#define B1111011 123 +#define B01111011 123 +#define B1111100 124 +#define B01111100 124 +#define B1111101 125 +#define B01111101 125 +#define B1111110 126 +#define B01111110 126 +#define B1111111 127 +#define B01111111 127 +#define B10000000 128 +#define B10000001 129 +#define B10000010 130 +#define B10000011 131 +#define B10000100 132 +#define B10000101 133 +#define B10000110 134 +#define B10000111 135 +#define B10001000 136 +#define B10001001 137 +#define B10001010 138 +#define B10001011 139 +#define B10001100 140 +#define B10001101 141 +#define B10001110 142 +#define B10001111 143 +#define B10010000 144 +#define B10010001 145 +#define B10010010 146 +#define B10010011 147 +#define B10010100 148 +#define B10010101 149 +#define B10010110 150 +#define B10010111 151 +#define B10011000 152 +#define B10011001 153 +#define B10011010 154 +#define B10011011 155 +#define B10011100 156 +#define B10011101 157 +#define B10011110 158 +#define B10011111 159 +#define B10100000 160 +#define B10100001 161 +#define B10100010 162 +#define B10100011 163 +#define B10100100 164 +#define B10100101 165 +#define B10100110 166 +#define B10100111 167 +#define B10101000 168 +#define B10101001 169 +#define B10101010 170 +#define B10101011 171 +#define B10101100 172 +#define B10101101 173 +#define B10101110 174 +#define B10101111 175 +#define B10110000 176 +#define B10110001 177 +#define B10110010 178 +#define B10110011 179 +#define B10110100 180 +#define B10110101 181 +#define B10110110 182 +#define B10110111 183 +#define B10111000 184 +#define B10111001 185 +#define B10111010 186 +#define B10111011 187 +#define B10111100 188 +#define B10111101 189 +#define B10111110 190 +#define B10111111 191 +#define B11000000 192 +#define B11000001 193 +#define B11000010 194 +#define B11000011 195 +#define B11000100 196 +#define B11000101 197 +#define B11000110 198 +#define B11000111 199 +#define B11001000 200 +#define B11001001 201 +#define B11001010 202 +#define B11001011 203 +#define B11001100 204 +#define B11001101 205 +#define B11001110 206 +#define B11001111 207 +#define B11010000 208 +#define B11010001 209 +#define B11010010 210 +#define B11010011 211 +#define B11010100 212 +#define B11010101 213 +#define B11010110 214 +#define B11010111 215 +#define B11011000 216 +#define B11011001 217 +#define B11011010 218 +#define B11011011 219 +#define B11011100 220 +#define B11011101 221 +#define B11011110 222 +#define B11011111 223 +#define B11100000 224 +#define B11100001 225 +#define B11100010 226 +#define B11100011 227 +#define B11100100 228 +#define B11100101 229 +#define B11100110 230 +#define B11100111 231 +#define B11101000 232 +#define B11101001 233 +#define B11101010 234 +#define B11101011 235 +#define B11101100 236 +#define B11101101 237 +#define B11101110 238 +#define B11101111 239 +#define B11110000 240 +#define B11110001 241 +#define B11110010 242 +#define B11110011 243 +#define B11110100 244 +#define B11110101 245 +#define B11110110 246 +#define B11110111 247 +#define B11111000 248 +#define B11111001 249 +#define B11111010 250 +#define B11111011 251 +#define B11111100 252 +#define B11111101 253 +#define B11111110 254 +#define B11111111 255 + +#endif diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/main.cpp b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/main.cpp new file mode 100644 index 0000000000..3d4e079d2a --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/main.cpp @@ -0,0 +1,20 @@ +#include + +int main(void) +{ + init(); + +#if defined(USBCON) + USBDevice.attach(); +#endif + + setup(); + + for (;;) { + loop(); + if (serialEventRun) serialEventRun(); + } + + return 0; +} + diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/new.cpp b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/new.cpp new file mode 100644 index 0000000000..0f6d4220ef --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/new.cpp @@ -0,0 +1,18 @@ +#include + +void * operator new(size_t size) +{ + return malloc(size); +} + +void operator delete(void * ptr) +{ + free(ptr); +} + +int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);}; +void __cxa_guard_release (__guard *g) {*(char *)g = 1;}; +void __cxa_guard_abort (__guard *) {}; + +void __cxa_pure_virtual(void) {}; + diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/new.h b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/new.h new file mode 100644 index 0000000000..cd940ce8b2 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/new.h @@ -0,0 +1,22 @@ +/* Header to define new/delete operators as they aren't provided by avr-gcc by default + Taken from http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=59453 + */ + +#ifndef NEW_H +#define NEW_H + +#include + +void * operator new(size_t size); +void operator delete(void * ptr); + +__extension__ typedef int __guard __attribute__((mode (__DI__))); + +extern "C" int __cxa_guard_acquire(__guard *); +extern "C" void __cxa_guard_release (__guard *); +extern "C" void __cxa_guard_abort (__guard *); + +extern "C" void __cxa_pure_virtual(void); + +#endif + diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring.c b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring.c new file mode 100644 index 0000000000..ac8bb6f9b4 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring.c @@ -0,0 +1,324 @@ +/* + wiring.c - Partial implementation of the Wiring API for the ATmega8. + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id$ +*/ + +#include "wiring_private.h" + +// the prescaler is set so that timer0 ticks every 64 clock cycles, and the +// the overflow handler is called every 256 ticks. +#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256)) + +// the whole number of milliseconds per timer0 overflow +#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000) + +// the fractional number of milliseconds per timer0 overflow. we shift right +// by three to fit these numbers into a byte. (for the clock speeds we care +// about - 8 and 16 MHz - this doesn't lose precision.) +#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3) +#define FRACT_MAX (1000 >> 3) + +volatile unsigned long timer0_overflow_count = 0; +volatile unsigned long timer0_millis = 0; +static unsigned char timer0_fract = 0; + +#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) +SIGNAL(TIM0_OVF_vect) +#else +SIGNAL(TIMER0_OVF_vect) +#endif +{ + // copy these to local variables so they can be stored in registers + // (volatile variables must be read from memory on every access) + unsigned long m = timer0_millis; + unsigned char f = timer0_fract; + + m += MILLIS_INC; + f += FRACT_INC; + if (f >= FRACT_MAX) { + f -= FRACT_MAX; + m += 1; + } + + timer0_fract = f; + timer0_millis = m; + timer0_overflow_count++; +} + +unsigned long millis() +{ + unsigned long m; + uint8_t oldSREG = SREG; + + // disable interrupts while we read timer0_millis or we might get an + // inconsistent value (e.g. in the middle of a write to timer0_millis) + cli(); + m = timer0_millis; + SREG = oldSREG; + + return m; +} + +unsigned long micros() { + unsigned long m; + uint8_t oldSREG = SREG, t; + + cli(); + m = timer0_overflow_count; +#if defined(TCNT0) + t = TCNT0; +#elif defined(TCNT0L) + t = TCNT0L; +#else + #error TIMER 0 not defined +#endif + + +#ifdef TIFR0 + if ((TIFR0 & _BV(TOV0)) && (t < 255)) + m++; +#else + if ((TIFR & _BV(TOV0)) && (t < 255)) + m++; +#endif + + SREG = oldSREG; + + return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond()); +} + +void delay(unsigned long ms) +{ + uint16_t start = (uint16_t)micros(); + + while (ms > 0) { + if (((uint16_t)micros() - start) >= 1000) { + ms--; + start += 1000; + } + } +} + +/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */ +void delayMicroseconds(unsigned int us) +{ + // calling avrlib's delay_us() function with low values (e.g. 1 or + // 2 microseconds) gives delays longer than desired. + //delay_us(us); +#if F_CPU >= 20000000L + // for the 20 MHz clock on rare Arduino boards + + // for a one-microsecond delay, simply wait 2 cycle and return. The overhead + // of the function call yields a delay of exactly a one microsecond. + __asm__ __volatile__ ( + "nop" "\n\t" + "nop"); //just waiting 2 cycle + if (--us == 0) + return; + + // the following loop takes a 1/5 of a microsecond (4 cycles) + // per iteration, so execute it five times for each microsecond of + // delay requested. + us = (us<<2) + us; // x5 us + + // account for the time taken in the preceeding commands. + us -= 2; + +#elif F_CPU >= 16000000L + // for the 16 MHz clock on most Arduino boards + + // for a one-microsecond delay, simply return. the overhead + // of the function call yields a delay of approximately 1 1/8 us. + if (--us == 0) + return; + + // the following loop takes a quarter of a microsecond (4 cycles) + // per iteration, so execute it four times for each microsecond of + // delay requested. + us <<= 2; + + // account for the time taken in the preceeding commands. + us -= 2; +#else + // for the 8 MHz internal clock on the ATmega168 + + // for a one- or two-microsecond delay, simply return. the overhead of + // the function calls takes more than two microseconds. can't just + // subtract two, since us is unsigned; we'd overflow. + if (--us == 0) + return; + if (--us == 0) + return; + + // the following loop takes half of a microsecond (4 cycles) + // per iteration, so execute it twice for each microsecond of + // delay requested. + us <<= 1; + + // partially compensate for the time taken by the preceeding commands. + // we can't subtract any more than this or we'd overflow w/ small delays. + us--; +#endif + + // busy wait + __asm__ __volatile__ ( + "1: sbiw %0,1" "\n\t" // 2 cycles + "brne 1b" : "=w" (us) : "0" (us) // 2 cycles + ); +} + +void init() +{ + // this needs to be called before setup() or some functions won't + // work there + sei(); + + // on the ATmega168, timer 0 is also used for fast hardware pwm + // (using phase-correct PWM would mean that timer 0 overflowed half as often + // resulting in different millis() behavior on the ATmega8 and ATmega168) +#if defined(TCCR0A) && defined(WGM01) + sbi(TCCR0A, WGM01); + sbi(TCCR0A, WGM00); +#endif + + // set timer 0 prescale factor to 64 +#if defined(__AVR_ATmega128__) + // CPU specific: different values for the ATmega128 + sbi(TCCR0, CS02); +#elif defined(TCCR0) && defined(CS01) && defined(CS00) + // this combination is for the standard atmega8 + sbi(TCCR0, CS01); + sbi(TCCR0, CS00); +#elif defined(TCCR0B) && defined(CS01) && defined(CS00) + // this combination is for the standard 168/328/1280/2560 + sbi(TCCR0B, CS01); + sbi(TCCR0B, CS00); +#elif defined(TCCR0A) && defined(CS01) && defined(CS00) + // this combination is for the __AVR_ATmega645__ series + sbi(TCCR0A, CS01); + sbi(TCCR0A, CS00); +#else + #error Timer 0 prescale factor 64 not set correctly +#endif + + // enable timer 0 overflow interrupt +#if defined(TIMSK) && defined(TOIE0) + sbi(TIMSK, TOIE0); +#elif defined(TIMSK0) && defined(TOIE0) + sbi(TIMSK0, TOIE0); +#else + #error Timer 0 overflow interrupt not set correctly +#endif + + // timers 1 and 2 are used for phase-correct hardware pwm + // this is better for motors as it ensures an even waveform + // note, however, that fast pwm mode can achieve a frequency of up + // 8 MHz (with a 16 MHz clock) at 50% duty cycle + +#if defined(TCCR1B) && defined(CS11) && defined(CS10) + TCCR1B = 0; + + // set timer 1 prescale factor to 64 + sbi(TCCR1B, CS11); +#if F_CPU >= 8000000L + sbi(TCCR1B, CS10); +#endif +#elif defined(TCCR1) && defined(CS11) && defined(CS10) + sbi(TCCR1, CS11); +#if F_CPU >= 8000000L + sbi(TCCR1, CS10); +#endif +#endif + // put timer 1 in 8-bit phase correct pwm mode +#if defined(TCCR1A) && defined(WGM10) + sbi(TCCR1A, WGM10); +#elif defined(TCCR1) + #warning this needs to be finished +#endif + + // set timer 2 prescale factor to 64 +#if defined(TCCR2) && defined(CS22) + sbi(TCCR2, CS22); +#elif defined(TCCR2B) && defined(CS22) + sbi(TCCR2B, CS22); +#else + #warning Timer 2 not finished (may not be present on this CPU) +#endif + + // configure timer 2 for phase correct pwm (8-bit) +#if defined(TCCR2) && defined(WGM20) + sbi(TCCR2, WGM20); +#elif defined(TCCR2A) && defined(WGM20) + sbi(TCCR2A, WGM20); +#else + #warning Timer 2 not finished (may not be present on this CPU) +#endif + +#if defined(TCCR3B) && defined(CS31) && defined(WGM30) + sbi(TCCR3B, CS31); // set timer 3 prescale factor to 64 + sbi(TCCR3B, CS30); + sbi(TCCR3A, WGM30); // put timer 3 in 8-bit phase correct pwm mode +#endif + +#if defined(TCCR4A) && defined(TCCR4B) && defined(TCCR4D) /* beginning of timer4 block for 32U4 and similar */ + sbi(TCCR4B, CS42); // set timer4 prescale factor to 64 + sbi(TCCR4B, CS41); + sbi(TCCR4B, CS40); + sbi(TCCR4D, WGM40); // put timer 4 in phase- and frequency-correct PWM mode + sbi(TCCR4A, PWM4A); // enable PWM mode for comparator OCR4A + sbi(TCCR4C, PWM4D); // enable PWM mode for comparator OCR4D +#else /* beginning of timer4 block for ATMEGA1280 and ATMEGA2560 */ +#if defined(TCCR4B) && defined(CS41) && defined(WGM40) + sbi(TCCR4B, CS41); // set timer 4 prescale factor to 64 + sbi(TCCR4B, CS40); + sbi(TCCR4A, WGM40); // put timer 4 in 8-bit phase correct pwm mode +#endif +#endif /* end timer4 block for ATMEGA1280/2560 and similar */ + +#if defined(TCCR5B) && defined(CS51) && defined(WGM50) + sbi(TCCR5B, CS51); // set timer 5 prescale factor to 64 + sbi(TCCR5B, CS50); + sbi(TCCR5A, WGM50); // put timer 5 in 8-bit phase correct pwm mode +#endif + +#if defined(ADCSRA) + // set a2d prescale factor to 128 + // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range. + // XXX: this will not work properly for other clock speeds, and + // this code should use F_CPU to determine the prescale factor. + sbi(ADCSRA, ADPS2); + sbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + + // enable a2d conversions + sbi(ADCSRA, ADEN); +#endif + + // the bootloader connects pins 0 and 1 to the USART; disconnect them + // here so they can be used as normal digital i/o; they will be + // reconnected in Serial.begin() +#if defined(UCSRB) + UCSRB = 0; +#elif defined(UCSR0B) + UCSR0B = 0; +#endif +} diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_analog.c b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_analog.c new file mode 100644 index 0000000000..23b01c65a0 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_analog.c @@ -0,0 +1,282 @@ +/* + wiring_analog.c - analog input and output + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + Modified 28 September 2010 by Mark Sproul + + $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ +*/ + +#include "wiring_private.h" +#include "pins_arduino.h" + +uint8_t analog_reference = DEFAULT; + +void analogReference(uint8_t mode) +{ + // can't actually set the register here because the default setting + // will connect AVCC and the AREF pin, which would cause a short if + // there's something connected to AREF. + analog_reference = mode; +} + +int analogRead(uint8_t pin) +{ + uint8_t low, high; + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + if (pin >= 54) pin -= 54; // allow for channel or pin numbers +#elif defined(__AVR_ATmega32U4__) + if (pin >= 18) pin -= 18; // allow for channel or pin numbers +#elif defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__) + if (pin >= 24) pin -= 24; // allow for channel or pin numbers +#else + if (pin >= 14) pin -= 14; // allow for channel or pin numbers +#endif + +#if defined(__AVR_ATmega32U4__) + pin = analogPinToChannel(pin); + ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5); +#elif defined(ADCSRB) && defined(MUX5) + // the MUX5 bit of ADCSRB selects whether we're reading from channels + // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high). + ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5); +#endif + + // set the analog reference (high two bits of ADMUX) and select the + // channel (low 4 bits). this also sets ADLAR (left-adjust result) + // to 0 (the default). +#if defined(ADMUX) + ADMUX = (analog_reference << 6) | (pin & 0x07); +#endif + + // without a delay, we seem to read from the wrong channel + //delay(1); + +#if defined(ADCSRA) && defined(ADCL) + // start the conversion + sbi(ADCSRA, ADSC); + + // ADSC is cleared when the conversion finishes + while (bit_is_set(ADCSRA, ADSC)); + + // we have to read ADCL first; doing so locks both ADCL + // and ADCH until ADCH is read. reading ADCL second would + // cause the results of each conversion to be discarded, + // as ADCL and ADCH would be locked when it completed. + low = ADCL; + high = ADCH; +#else + // we dont have an ADC, return 0 + low = 0; + high = 0; +#endif + + // combine the two bytes + return (high << 8) | low; +} + +// Right now, PWM output only works on the pins with +// hardware support. These are defined in the appropriate +// pins_*.c file. For the rest of the pins, we default +// to digital output. +void analogWrite(uint8_t pin, int val) +{ + // We need to make sure the PWM output is enabled for those pins + // that support it, as we turn it off when digitally reading or + // writing with them. Also, make sure the pin is in output mode + // for consistenty with Wiring, which doesn't require a pinMode + // call for the analog output pins. + pinMode(pin, OUTPUT); + if (val == 0) + { + digitalWrite(pin, LOW); + } + else if (val == 255) + { + digitalWrite(pin, HIGH); + } + else + { + switch(digitalPinToTimer(pin)) + { + // XXX fix needed for atmega8 + #if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__) + case TIMER0A: + // connect pwm to pin on timer 0 + sbi(TCCR0, COM00); + OCR0 = val; // set pwm duty + break; + #endif + + #if defined(TCCR0A) && defined(COM0A1) + case TIMER0A: + // connect pwm to pin on timer 0, channel A + sbi(TCCR0A, COM0A1); + OCR0A = val; // set pwm duty + break; + #endif + + #if defined(TCCR0A) && defined(COM0B1) + case TIMER0B: + // connect pwm to pin on timer 0, channel B + sbi(TCCR0A, COM0B1); + OCR0B = val; // set pwm duty + break; + #endif + + #if defined(TCCR1A) && defined(COM1A1) + case TIMER1A: + // connect pwm to pin on timer 1, channel A + sbi(TCCR1A, COM1A1); + OCR1A = val; // set pwm duty + break; + #endif + + #if defined(TCCR1A) && defined(COM1B1) + case TIMER1B: + // connect pwm to pin on timer 1, channel B + sbi(TCCR1A, COM1B1); + OCR1B = val; // set pwm duty + break; + #endif + + #if defined(TCCR2) && defined(COM21) + case TIMER2: + // connect pwm to pin on timer 2 + sbi(TCCR2, COM21); + OCR2 = val; // set pwm duty + break; + #endif + + #if defined(TCCR2A) && defined(COM2A1) + case TIMER2A: + // connect pwm to pin on timer 2, channel A + sbi(TCCR2A, COM2A1); + OCR2A = val; // set pwm duty + break; + #endif + + #if defined(TCCR2A) && defined(COM2B1) + case TIMER2B: + // connect pwm to pin on timer 2, channel B + sbi(TCCR2A, COM2B1); + OCR2B = val; // set pwm duty + break; + #endif + + #if defined(TCCR3A) && defined(COM3A1) + case TIMER3A: + // connect pwm to pin on timer 3, channel A + sbi(TCCR3A, COM3A1); + OCR3A = val; // set pwm duty + break; + #endif + + #if defined(TCCR3A) && defined(COM3B1) + case TIMER3B: + // connect pwm to pin on timer 3, channel B + sbi(TCCR3A, COM3B1); + OCR3B = val; // set pwm duty + break; + #endif + + #if defined(TCCR3A) && defined(COM3C1) + case TIMER3C: + // connect pwm to pin on timer 3, channel C + sbi(TCCR3A, COM3C1); + OCR3C = val; // set pwm duty + break; + #endif + + #if defined(TCCR4A) + case TIMER4A: + //connect pwm to pin on timer 4, channel A + sbi(TCCR4A, COM4A1); + #if defined(COM4A0) // only used on 32U4 + cbi(TCCR4A, COM4A0); + #endif + OCR4A = val; // set pwm duty + break; + #endif + + #if defined(TCCR4A) && defined(COM4B1) + case TIMER4B: + // connect pwm to pin on timer 4, channel B + sbi(TCCR4A, COM4B1); + OCR4B = val; // set pwm duty + break; + #endif + + #if defined(TCCR4A) && defined(COM4C1) + case TIMER4C: + // connect pwm to pin on timer 4, channel C + sbi(TCCR4A, COM4C1); + OCR4C = val; // set pwm duty + break; + #endif + + #if defined(TCCR4C) && defined(COM4D1) + case TIMER4D: + // connect pwm to pin on timer 4, channel D + sbi(TCCR4C, COM4D1); + #if defined(COM4D0) // only used on 32U4 + cbi(TCCR4C, COM4D0); + #endif + OCR4D = val; // set pwm duty + break; + #endif + + + #if defined(TCCR5A) && defined(COM5A1) + case TIMER5A: + // connect pwm to pin on timer 5, channel A + sbi(TCCR5A, COM5A1); + OCR5A = val; // set pwm duty + break; + #endif + + #if defined(TCCR5A) && defined(COM5B1) + case TIMER5B: + // connect pwm to pin on timer 5, channel B + sbi(TCCR5A, COM5B1); + OCR5B = val; // set pwm duty + break; + #endif + + #if defined(TCCR5A) && defined(COM5C1) + case TIMER5C: + // connect pwm to pin on timer 5, channel C + sbi(TCCR5A, COM5C1); + OCR5C = val; // set pwm duty + break; + #endif + + case NOT_ON_TIMER: + default: + if (val < 128) { + digitalWrite(pin, LOW); + } else { + digitalWrite(pin, HIGH); + } + } + } +} + diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_digital.c b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_digital.c new file mode 100644 index 0000000000..be323b1dfe --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_digital.c @@ -0,0 +1,178 @@ +/* + wiring_digital.c - digital input and output functions + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + Modified 28 September 2010 by Mark Sproul + + $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ +*/ + +#define ARDUINO_MAIN +#include "wiring_private.h" +#include "pins_arduino.h" + +void pinMode(uint8_t pin, uint8_t mode) +{ + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + volatile uint8_t *reg, *out; + + if (port == NOT_A_PIN) return; + + // JWS: can I let the optimizer do this? + reg = portModeRegister(port); + out = portOutputRegister(port); + + if (mode == INPUT) { + uint8_t oldSREG = SREG; + cli(); + *reg &= ~bit; + *out &= ~bit; + SREG = oldSREG; + } else if (mode == INPUT_PULLUP) { + uint8_t oldSREG = SREG; + cli(); + *reg &= ~bit; + *out |= bit; + SREG = oldSREG; + } else { + uint8_t oldSREG = SREG; + cli(); + *reg |= bit; + SREG = oldSREG; + } +} + +// Forcing this inline keeps the callers from having to push their own stuff +// on the stack. It is a good performance win and only takes 1 more byte per +// user than calling. (It will take more bytes on the 168.) +// +// But shouldn't this be moved into pinMode? Seems silly to check and do on +// each digitalread or write. +// +// Mark Sproul: +// - Removed inline. Save 170 bytes on atmega1280 +// - changed to a switch statment; added 32 bytes but much easier to read and maintain. +// - Added more #ifdefs, now compiles for atmega645 +// +//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline)); +//static inline void turnOffPWM(uint8_t timer) +static void turnOffPWM(uint8_t timer) +{ + switch (timer) + { + #if defined(TCCR1A) && defined(COM1A1) + case TIMER1A: cbi(TCCR1A, COM1A1); break; + #endif + #if defined(TCCR1A) && defined(COM1B1) + case TIMER1B: cbi(TCCR1A, COM1B1); break; + #endif + + #if defined(TCCR2) && defined(COM21) + case TIMER2: cbi(TCCR2, COM21); break; + #endif + + #if defined(TCCR0A) && defined(COM0A1) + case TIMER0A: cbi(TCCR0A, COM0A1); break; + #endif + + #if defined(TIMER0B) && defined(COM0B1) + case TIMER0B: cbi(TCCR0A, COM0B1); break; + #endif + #if defined(TCCR2A) && defined(COM2A1) + case TIMER2A: cbi(TCCR2A, COM2A1); break; + #endif + #if defined(TCCR2A) && defined(COM2B1) + case TIMER2B: cbi(TCCR2A, COM2B1); break; + #endif + + #if defined(TCCR3A) && defined(COM3A1) + case TIMER3A: cbi(TCCR3A, COM3A1); break; + #endif + #if defined(TCCR3A) && defined(COM3B1) + case TIMER3B: cbi(TCCR3A, COM3B1); break; + #endif + #if defined(TCCR3A) && defined(COM3C1) + case TIMER3C: cbi(TCCR3A, COM3C1); break; + #endif + + #if defined(TCCR4A) && defined(COM4A1) + case TIMER4A: cbi(TCCR4A, COM4A1); break; + #endif + #if defined(TCCR4A) && defined(COM4B1) + case TIMER4B: cbi(TCCR4A, COM4B1); break; + #endif + #if defined(TCCR4A) && defined(COM4C1) + case TIMER4C: cbi(TCCR4A, COM4C1); break; + #endif + #if defined(TCCR4C) && defined(COM4D1) + case TIMER4D: cbi(TCCR4C, COM4D1); break; + #endif + + #if defined(TCCR5A) + case TIMER5A: cbi(TCCR5A, COM5A1); break; + case TIMER5B: cbi(TCCR5A, COM5B1); break; + case TIMER5C: cbi(TCCR5A, COM5C1); break; + #endif + } +} + +void digitalWrite(uint8_t pin, uint8_t val) +{ + uint8_t timer = digitalPinToTimer(pin); + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + volatile uint8_t *out; + + if (port == NOT_A_PIN) return; + + // If the pin that support PWM output, we need to turn it off + // before doing a digital write. + if (timer != NOT_ON_TIMER) turnOffPWM(timer); + + out = portOutputRegister(port); + + uint8_t oldSREG = SREG; + cli(); + + if (val == LOW) { + *out &= ~bit; + } else { + *out |= bit; + } + + SREG = oldSREG; +} + +int digitalRead(uint8_t pin) +{ + uint8_t timer = digitalPinToTimer(pin); + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + + if (port == NOT_A_PIN) return LOW; + + // If the pin that support PWM output, we need to turn it off + // before getting a digital reading. + if (timer != NOT_ON_TIMER) turnOffPWM(timer); + + if (*portInputRegister(port) & bit) return HIGH; + return LOW; +} diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_private.h b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_private.h new file mode 100644 index 0000000000..f678265679 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_private.h @@ -0,0 +1,71 @@ +/* + wiring_private.h - Internal header file. + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.h 239 2007-01-12 17:58:39Z mellis $ +*/ + +#ifndef WiringPrivate_h +#define WiringPrivate_h + +#include +#include +#include +#include + +#include "Arduino.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef cbi +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#endif +#ifndef sbi +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) +#endif + +#define EXTERNAL_INT_0 0 +#define EXTERNAL_INT_1 1 +#define EXTERNAL_INT_2 2 +#define EXTERNAL_INT_3 3 +#define EXTERNAL_INT_4 4 +#define EXTERNAL_INT_5 5 +#define EXTERNAL_INT_6 6 +#define EXTERNAL_INT_7 7 + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +#define EXTERNAL_NUM_INTERRUPTS 8 +#elif defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__) +#define EXTERNAL_NUM_INTERRUPTS 3 +#elif defined(__AVR_ATmega32U4__) +#define EXTERNAL_NUM_INTERRUPTS 4 +#else +#define EXTERNAL_NUM_INTERRUPTS 2 +#endif + +typedef void (*voidFuncPtr)(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_pulse.c b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_pulse.c new file mode 100644 index 0000000000..0d968865d2 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_pulse.c @@ -0,0 +1,69 @@ +/* + wiring_pulse.c - pulseIn() function + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ +*/ + +#include "wiring_private.h" +#include "pins_arduino.h" + +/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH + * or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds + * to 3 minutes in length, but must be called at least a few dozen microseconds + * before the start of the pulse. */ +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) +{ + // cache the port and bit of the pin in order to speed up the + // pulse width measuring loop and achieve finer resolution. calling + // digitalRead() instead yields much coarser resolution. + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + uint8_t stateMask = (state ? bit : 0); + unsigned long width = 0; // keep initialization out of time critical area + + // convert the timeout from microseconds to a number of times through + // the initial loop; it takes 16 clock cycles per iteration. + unsigned long numloops = 0; + unsigned long maxloops = microsecondsToClockCycles(timeout) / 16; + + // wait for any previous pulse to end + while ((*portInputRegister(port) & bit) == stateMask) + if (numloops++ == maxloops) + return 0; + + // wait for the pulse to start + while ((*portInputRegister(port) & bit) != stateMask) + if (numloops++ == maxloops) + return 0; + + // wait for the pulse to stop + while ((*portInputRegister(port) & bit) == stateMask) { + if (numloops++ == maxloops) + return 0; + width++; + } + + // convert the reading to microseconds. The loop has been determined + // to be 20 clock cycles long and have about 16 clocks between the edge + // and the start of the loop. There will be some error introduced by + // the interrupt handlers. + return clockCyclesToMicroseconds(width * 21 + 16); +} diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_shift.c b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_shift.c new file mode 100644 index 0000000000..cfe786758c --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_shift.c @@ -0,0 +1,55 @@ +/* + wiring_shift.c - shiftOut() function + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ +*/ + +#include "wiring_private.h" + +uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) { + uint8_t value = 0; + uint8_t i; + + for (i = 0; i < 8; ++i) { + digitalWrite(clockPin, HIGH); + if (bitOrder == LSBFIRST) + value |= digitalRead(dataPin) << i; + else + value |= digitalRead(dataPin) << (7 - i); + digitalWrite(clockPin, LOW); + } + return value; +} + +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) +{ + uint8_t i; + + for (i = 0; i < 8; i++) { + if (bitOrder == LSBFIRST) + digitalWrite(dataPin, !!(val & (1 << i))); + else + digitalWrite(dataPin, !!(val & (1 << (7 - i)))); + + digitalWrite(clockPin, HIGH); + digitalWrite(clockPin, LOW); + } +} diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/variants/standard/pins_arduino.h b/ArduinoAddons/Arduino_1.x.x/rambo/variants/standard/pins_arduino.h new file mode 100644 index 0000000000..f49a23fc02 --- /dev/null +++ b/ArduinoAddons/Arduino_1.x.x/rambo/variants/standard/pins_arduino.h @@ -0,0 +1,411 @@ +/* + pins_arduino.h - Pin definition functions for Arduino + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2007 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.h 249 2007-02-03 16:52:51Z mellis $ +*/ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +#define NUM_DIGITAL_PINS 82 +#define NUM_ANALOG_INPUTS 16 +#define analogInputToDigitalPin(p) ((p < 16) ? (p) + 54 : -1) +#define digitalPinHasPWM(p) (((p) >= 2 && (p) <= 13) || ((p) >= 44 && (p)<= 46)) + +static const uint8_t SS = 53; +static const uint8_t MOSI = 51; +static const uint8_t MISO = 50; +static const uint8_t SCK = 52; + +static const uint8_t SDA = 20; +static const uint8_t SCL = 21; +static const uint8_t LED_BUILTIN = 13; + +static const uint8_t A0 = 54; +static const uint8_t A1 = 55; +static const uint8_t A2 = 56; +static const uint8_t A3 = 57; +static const uint8_t A4 = 58; +static const uint8_t A5 = 59; +static const uint8_t A6 = 60; +static const uint8_t A7 = 61; +static const uint8_t A8 = 62; +static const uint8_t A9 = 63; +static const uint8_t A10 = 64; +static const uint8_t A11 = 65; +static const uint8_t A12 = 66; +static const uint8_t A13 = 67; +static const uint8_t A14 = 68; +static const uint8_t A15 = 69; + +// A majority of the pins are NOT PCINTs, SO BE WARNED (i.e. you cannot use them as receive pins) +// Only pins available for RECEIVE (TRANSMIT can be on any pin): +// (I've deliberately left out pin mapping to the Hardware USARTs - seems senseless to me) +// Pins: 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69 + +#define digitalPinToPCICR(p) ( (((p) >= 10) && ((p) <= 13)) || \ + (((p) >= 50) && ((p) <= 53)) || \ + (((p) >= 62) && ((p) <= 69)) ? (&PCICR) : ((uint8_t *)0) ) + +#define digitalPinToPCICRbit(p) ( (((p) >= 10) && ((p) <= 13)) || (((p) >= 50) && ((p) <= 53)) ? 0 : \ + ( (((p) >= 62) && ((p) <= 69)) ? 2 : \ + 0 ) ) + +#define digitalPinToPCMSK(p) ( (((p) >= 10) && ((p) <= 13)) || (((p) >= 50) && ((p) <= 53)) ? (&PCMSK0) : \ + ( (((p) >= 62) && ((p) <= 69)) ? (&PCMSK2) : \ + ((uint8_t *)0) ) ) + +#define digitalPinToPCMSKbit(p) ( (((p) >= 10) && ((p) <= 13)) ? ((p) - 6) : \ + ( ((p) == 50) ? 3 : \ + ( ((p) == 51) ? 2 : \ + ( ((p) == 52) ? 1 : \ + ( ((p) == 53) ? 0 : \ + ( (((p) >= 62) && ((p) <= 69)) ? ((p) - 62) : \ + 0 ) ) ) ) ) ) + +#ifdef ARDUINO_MAIN + +const uint16_t PROGMEM port_to_mode_PGM[] = { + NOT_A_PORT, + (uint16_t) &DDRA, + (uint16_t) &DDRB, + (uint16_t) &DDRC, + (uint16_t) &DDRD, + (uint16_t) &DDRE, + (uint16_t) &DDRF, + (uint16_t) &DDRG, + (uint16_t) &DDRH, + NOT_A_PORT, + (uint16_t) &DDRJ, + (uint16_t) &DDRK, + (uint16_t) &DDRL, +}; + +const uint16_t PROGMEM port_to_output_PGM[] = { + NOT_A_PORT, + (uint16_t) &PORTA, + (uint16_t) &PORTB, + (uint16_t) &PORTC, + (uint16_t) &PORTD, + (uint16_t) &PORTE, + (uint16_t) &PORTF, + (uint16_t) &PORTG, + (uint16_t) &PORTH, + NOT_A_PORT, + (uint16_t) &PORTJ, + (uint16_t) &PORTK, + (uint16_t) &PORTL, +}; + +const uint16_t PROGMEM port_to_input_PGM[] = { + NOT_A_PIN, + (uint16_t) &PINA, + (uint16_t) &PINB, + (uint16_t) &PINC, + (uint16_t) &PIND, + (uint16_t) &PINE, + (uint16_t) &PINF, + (uint16_t) &PING, + (uint16_t) &PINH, + NOT_A_PIN, + (uint16_t) &PINJ, + (uint16_t) &PINK, + (uint16_t) &PINL, +}; + +const uint8_t PROGMEM digital_pin_to_port_PGM[] = { + // PORTLIST + // ------------------------------------------- + PE , // PE 0 ** 0 ** USART0_RX + PE , // PE 1 ** 1 ** USART0_TX + PE , // PE 4 ** 2 ** PWM2 + PE , // PE 5 ** 3 ** PWM3 + PG , // PG 5 ** 4 ** PWM4 + PE , // PE 3 ** 5 ** PWM5 + PH , // PH 3 ** 6 ** PWM6 + PH , // PH 4 ** 7 ** PWM7 + PH , // PH 5 ** 8 ** PWM8 + PH , // PH 6 ** 9 ** PWM9 + PB , // PB 4 ** 10 ** PWM10 + PB , // PB 5 ** 11 ** PWM11 + PB , // PB 6 ** 12 ** PWM12 + PB , // PB 7 ** 13 ** PWM13 + PJ , // PJ 1 ** 14 ** USART3_TX + PJ , // PJ 0 ** 15 ** USART3_RX + PH , // PH 1 ** 16 ** USART2_TX + PH , // PH 0 ** 17 ** USART2_RX + PD , // PD 3 ** 18 ** USART1_TX + PD , // PD 2 ** 19 ** USART1_RX + PD , // PD 1 ** 20 ** I2C_SDA + PD , // PD 0 ** 21 ** I2C_SCL + PA , // PA 0 ** 22 ** D22 + PA , // PA 1 ** 23 ** D23 + PA , // PA 2 ** 24 ** D24 + PA , // PA 3 ** 25 ** D25 + PA , // PA 4 ** 26 ** D26 + PA , // PA 5 ** 27 ** D27 + PA , // PA 6 ** 28 ** D28 + PA , // PA 7 ** 29 ** D29 + PC , // PC 7 ** 30 ** D30 + PC , // PC 6 ** 31 ** D31 + PC , // PC 5 ** 32 ** D32 + PC , // PC 4 ** 33 ** D33 + PC , // PC 3 ** 34 ** D34 + PC , // PC 2 ** 35 ** D35 + PC , // PC 1 ** 36 ** D36 + PC , // PC 0 ** 37 ** D37 + PD , // PD 7 ** 38 ** D38 + PG , // PG 2 ** 39 ** D39 + PG , // PG 1 ** 40 ** D40 + PG , // PG 0 ** 41 ** D41 + PL , // PL 7 ** 42 ** D42 + PL , // PL 6 ** 43 ** D43 + PL , // PL 5 ** 44 ** D44 + PL , // PL 4 ** 45 ** D45 + PL , // PL 3 ** 46 ** D46 + PL , // PL 2 ** 47 ** D47 + PL , // PL 1 ** 48 ** D48 + PL , // PL 0 ** 49 ** D49 + PB , // PB 3 ** 50 ** SPI_MISO + PB , // PB 2 ** 51 ** SPI_MOSI + PB , // PB 1 ** 52 ** SPI_SCK + PB , // PB 0 ** 53 ** SPI_SS + PF , // PF 0 ** 54 ** A0 + PF , // PF 1 ** 55 ** A1 + PF , // PF 2 ** 56 ** A2 + PF , // PF 3 ** 57 ** A3 + PF , // PF 4 ** 58 ** A4 + PF , // PF 5 ** 59 ** A5 + PF , // PF 6 ** 60 ** A6 + PF , // PF 7 ** 61 ** A7 + PK , // PK 0 ** 62 ** A8 + PK , // PK 1 ** 63 ** A9 + PK , // PK 2 ** 64 ** A10 + PK , // PK 3 ** 65 ** A11 + PK , // PK 4 ** 66 ** A12 + PK , // PK 5 ** 67 ** A13 + PK , // PK 6 ** 68 ** A14 + PK , // PK 7 ** 69 ** A15 + PG , // PG 4 ** 70 ** D70 + PG , // PG 3 ** 71 ** D71 + PJ , // PJ 2 ** 72 ** D72 + PJ , // PJ 3 ** 73 ** D73 + PJ , // PJ 7 ** 74 ** D74 + PJ , // PJ 4 ** 75 ** D75 + PJ , // PJ 5 ** 76 ** D76 + PJ , // PJ 6 ** 77 ** D77 + PE , // PE 2 ** 78 ** D78 + PE , // PE 6 ** 79 ** D79 + PE , // PE 7 ** 80 ** D80 + PD , // PD 4 ** 81 ** D81 + PD , // PD 5 ** 82 ** D82 + PD , // PD 6 ** 83 ** D83 + PH , // PH 2 ** 84 ** D84 + PH , // PH 7 ** 85 ** D85 +}; + +const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { + // PIN IN PORT + // ------------------------------------------- + _BV( 0 ) , // PE 0 ** 0 ** USART0_RX + _BV( 1 ) , // PE 1 ** 1 ** USART0_TX + _BV( 4 ) , // PE 4 ** 2 ** PWM2 + _BV( 5 ) , // PE 5 ** 3 ** PWM3 + _BV( 5 ) , // PG 5 ** 4 ** PWM4 + _BV( 3 ) , // PE 3 ** 5 ** PWM5 + _BV( 3 ) , // PH 3 ** 6 ** PWM6 + _BV( 4 ) , // PH 4 ** 7 ** PWM7 + _BV( 5 ) , // PH 5 ** 8 ** PWM8 + _BV( 6 ) , // PH 6 ** 9 ** PWM9 + _BV( 4 ) , // PB 4 ** 10 ** PWM10 + _BV( 5 ) , // PB 5 ** 11 ** PWM11 + _BV( 6 ) , // PB 6 ** 12 ** PWM12 + _BV( 7 ) , // PB 7 ** 13 ** PWM13 + _BV( 1 ) , // PJ 1 ** 14 ** USART3_TX + _BV( 0 ) , // PJ 0 ** 15 ** USART3_RX + _BV( 1 ) , // PH 1 ** 16 ** USART2_TX + _BV( 0 ) , // PH 0 ** 17 ** USART2_RX + _BV( 3 ) , // PD 3 ** 18 ** USART1_TX + _BV( 2 ) , // PD 2 ** 19 ** USART1_RX + _BV( 1 ) , // PD 1 ** 20 ** I2C_SDA + _BV( 0 ) , // PD 0 ** 21 ** I2C_SCL + _BV( 0 ) , // PA 0 ** 22 ** D22 + _BV( 1 ) , // PA 1 ** 23 ** D23 + _BV( 2 ) , // PA 2 ** 24 ** D24 + _BV( 3 ) , // PA 3 ** 25 ** D25 + _BV( 4 ) , // PA 4 ** 26 ** D26 + _BV( 5 ) , // PA 5 ** 27 ** D27 + _BV( 6 ) , // PA 6 ** 28 ** D28 + _BV( 7 ) , // PA 7 ** 29 ** D29 + _BV( 7 ) , // PC 7 ** 30 ** D30 + _BV( 6 ) , // PC 6 ** 31 ** D31 + _BV( 5 ) , // PC 5 ** 32 ** D32 + _BV( 4 ) , // PC 4 ** 33 ** D33 + _BV( 3 ) , // PC 3 ** 34 ** D34 + _BV( 2 ) , // PC 2 ** 35 ** D35 + _BV( 1 ) , // PC 1 ** 36 ** D36 + _BV( 0 ) , // PC 0 ** 37 ** D37 + _BV( 7 ) , // PD 7 ** 38 ** D38 + _BV( 2 ) , // PG 2 ** 39 ** D39 + _BV( 1 ) , // PG 1 ** 40 ** D40 + _BV( 0 ) , // PG 0 ** 41 ** D41 + _BV( 7 ) , // PL 7 ** 42 ** D42 + _BV( 6 ) , // PL 6 ** 43 ** D43 + _BV( 5 ) , // PL 5 ** 44 ** D44 + _BV( 4 ) , // PL 4 ** 45 ** D45 + _BV( 3 ) , // PL 3 ** 46 ** D46 + _BV( 2 ) , // PL 2 ** 47 ** D47 + _BV( 1 ) , // PL 1 ** 48 ** D48 + _BV( 0 ) , // PL 0 ** 49 ** D49 + _BV( 3 ) , // PB 3 ** 50 ** SPI_MISO + _BV( 2 ) , // PB 2 ** 51 ** SPI_MOSI + _BV( 1 ) , // PB 1 ** 52 ** SPI_SCK + _BV( 0 ) , // PB 0 ** 53 ** SPI_SS + _BV( 0 ) , // PF 0 ** 54 ** A0 + _BV( 1 ) , // PF 1 ** 55 ** A1 + _BV( 2 ) , // PF 2 ** 56 ** A2 + _BV( 3 ) , // PF 3 ** 57 ** A3 + _BV( 4 ) , // PF 4 ** 58 ** A4 + _BV( 5 ) , // PF 5 ** 59 ** A5 + _BV( 6 ) , // PF 6 ** 60 ** A6 + _BV( 7 ) , // PF 7 ** 61 ** A7 + _BV( 0 ) , // PK 0 ** 62 ** A8 + _BV( 1 ) , // PK 1 ** 63 ** A9 + _BV( 2 ) , // PK 2 ** 64 ** A10 + _BV( 3 ) , // PK 3 ** 65 ** A11 + _BV( 4 ) , // PK 4 ** 66 ** A12 + _BV( 5 ) , // PK 5 ** 67 ** A13 + _BV( 6 ) , // PK 6 ** 68 ** A14 + _BV( 7 ) , // PK 7 ** 69 ** A15 + _BV( 4 ) , // PG 4 ** 70 ** D70 + _BV( 3 ) , // PG 3 ** 71 ** D71 + _BV( 2 ) , // PJ 2 ** 72 ** D72 + _BV( 3 ) , // PJ 3 ** 73 ** D73 + _BV( 7 ) , // PJ 7 ** 74 ** D74 + _BV( 4 ) , // PJ 4 ** 75 ** D75 + _BV( 5 ) , // PJ 5 ** 76 ** D76 + _BV( 6 ) , // PJ 6 ** 77 ** D77 + _BV( 2 ) , // PE 2 ** 78 ** D78 + _BV( 6 ) , // PE 6 ** 79 ** D79 + _BV( 7 ) , // PE 7 ** 80 ** D80 + _BV( 4 ) , // PD 4 ** 81 ** D81 + _BV( 5 ) , // PD 5 ** 82 ** D82 + _BV( 6 ) , // PD 6 ** 83 ** D83 + _BV( 2 ) , // PH 2 ** 84 ** D84 + _BV( 7 ) , // PH 7 ** 85 ** D85 +}; + +const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { + // TIMERS + // ------------------------------------------- + NOT_ON_TIMER , // PE 0 ** 0 ** USART0_RX + NOT_ON_TIMER , // PE 1 ** 1 ** USART0_TX + TIMER3B , // PE 4 ** 2 ** PWM2 + TIMER3C , // PE 5 ** 3 ** PWM3 + TIMER0B , // PG 5 ** 4 ** PWM4 + TIMER3A , // PE 3 ** 5 ** PWM5 + TIMER4A , // PH 3 ** 6 ** PWM6 + TIMER4B , // PH 4 ** 7 ** PWM7 + TIMER4C , // PH 5 ** 8 ** PWM8 + TIMER2B , // PH 6 ** 9 ** PWM9 + TIMER2A , // PB 4 ** 10 ** PWM10 + TIMER1A , // PB 5 ** 11 ** PWM11 + TIMER1B , // PB 6 ** 12 ** PWM12 + TIMER0A , // PB 7 ** 13 ** PWM13 + NOT_ON_TIMER , // PJ 1 ** 14 ** USART3_TX + NOT_ON_TIMER , // PJ 0 ** 15 ** USART3_RX + NOT_ON_TIMER , // PH 1 ** 16 ** USART2_TX + NOT_ON_TIMER , // PH 0 ** 17 ** USART2_RX + NOT_ON_TIMER , // PD 3 ** 18 ** USART1_TX + NOT_ON_TIMER , // PD 2 ** 19 ** USART1_RX + NOT_ON_TIMER , // PD 1 ** 20 ** I2C_SDA + NOT_ON_TIMER , // PD 0 ** 21 ** I2C_SCL + NOT_ON_TIMER , // PA 0 ** 22 ** D22 + NOT_ON_TIMER , // PA 1 ** 23 ** D23 + NOT_ON_TIMER , // PA 2 ** 24 ** D24 + NOT_ON_TIMER , // PA 3 ** 25 ** D25 + NOT_ON_TIMER , // PA 4 ** 26 ** D26 + NOT_ON_TIMER , // PA 5 ** 27 ** D27 + NOT_ON_TIMER , // PA 6 ** 28 ** D28 + NOT_ON_TIMER , // PA 7 ** 29 ** D29 + NOT_ON_TIMER , // PC 7 ** 30 ** D30 + NOT_ON_TIMER , // PC 6 ** 31 ** D31 + NOT_ON_TIMER , // PC 5 ** 32 ** D32 + NOT_ON_TIMER , // PC 4 ** 33 ** D33 + NOT_ON_TIMER , // PC 3 ** 34 ** D34 + NOT_ON_TIMER , // PC 2 ** 35 ** D35 + NOT_ON_TIMER , // PC 1 ** 36 ** D36 + NOT_ON_TIMER , // PC 0 ** 37 ** D37 + NOT_ON_TIMER , // PD 7 ** 38 ** D38 + NOT_ON_TIMER , // PG 2 ** 39 ** D39 + NOT_ON_TIMER , // PG 1 ** 40 ** D40 + NOT_ON_TIMER , // PG 0 ** 41 ** D41 + NOT_ON_TIMER , // PL 7 ** 42 ** D42 + NOT_ON_TIMER , // PL 6 ** 43 ** D43 + TIMER5C , // PL 5 ** 44 ** D44 + TIMER5B , // PL 4 ** 45 ** D45 + TIMER5A , // PL 3 ** 46 ** D46 + NOT_ON_TIMER , // PL 2 ** 47 ** D47 + NOT_ON_TIMER , // PL 1 ** 48 ** D48 + NOT_ON_TIMER , // PL 0 ** 49 ** D49 + NOT_ON_TIMER , // PB 3 ** 50 ** SPI_MISO + NOT_ON_TIMER , // PB 2 ** 51 ** SPI_MOSI + NOT_ON_TIMER , // PB 1 ** 52 ** SPI_SCK + NOT_ON_TIMER , // PB 0 ** 53 ** SPI_SS + NOT_ON_TIMER , // PF 0 ** 54 ** A0 + NOT_ON_TIMER , // PF 1 ** 55 ** A1 + NOT_ON_TIMER , // PF 2 ** 56 ** A2 + NOT_ON_TIMER , // PF 3 ** 57 ** A3 + NOT_ON_TIMER , // PF 4 ** 58 ** A4 + NOT_ON_TIMER , // PF 5 ** 59 ** A5 + NOT_ON_TIMER , // PF 6 ** 60 ** A6 + NOT_ON_TIMER , // PF 7 ** 61 ** A7 + NOT_ON_TIMER , // PK 0 ** 62 ** A8 + NOT_ON_TIMER , // PK 1 ** 63 ** A9 + NOT_ON_TIMER , // PK 2 ** 64 ** A10 + NOT_ON_TIMER , // PK 3 ** 65 ** A11 + NOT_ON_TIMER , // PK 4 ** 66 ** A12 + NOT_ON_TIMER , // PK 5 ** 67 ** A13 + NOT_ON_TIMER , // PK 6 ** 68 ** A14 + NOT_ON_TIMER , // PK 7 ** 69 ** A15 + NOT_ON_TIMER , // PG 4 ** 70 ** D70 + NOT_ON_TIMER , // PG 3 ** 71 ** D71 + NOT_ON_TIMER , // PJ 2 ** 72 ** D72 + NOT_ON_TIMER , // PJ 3 ** 73 ** D73 + NOT_ON_TIMER , // PJ 7 ** 74 ** D74 + NOT_ON_TIMER , // PJ 4 ** 75 ** D75 + NOT_ON_TIMER , // PJ 5 ** 76 ** D76 + NOT_ON_TIMER , // PJ 6 ** 77 ** D77 + NOT_ON_TIMER , // PE 2 ** 78 ** D78 + NOT_ON_TIMER , // PE 6 ** 79 ** D79 + NOT_ON_TIMER , // PE 7 ** 80 ** D80 + NOT_ON_TIMER , // PD 4 ** 81 ** D81 + NOT_ON_TIMER , // PD 5 ** 82 ** D82 + NOT_ON_TIMER , // PD 6 ** 83 ** D83 + NOT_ON_TIMER , // PH 2 ** 84 ** D84 + NOT_ON_TIMER , // PH 7 ** 85 ** D85 +}; + +#endif + +#endif From 9547fb9dfb12152e620fdc03b48c563028c3d5fc Mon Sep 17 00:00:00 2001 From: Robert F-C Date: Thu, 8 Aug 2013 00:10:26 +1000 Subject: [PATCH 028/256] Add duplication and auto-park mode for dual x-carriage support. --- .gitignore | 1 + Marlin/Configuration_adv.h | 28 ++++- Marlin/Marlin_main.cpp | 237 +++++++++++++++++++++++++++++++++---- Marlin/stepper.cpp | 94 ++++++++++----- Marlin/stepper.h | 13 +- 5 files changed, 315 insertions(+), 58 deletions(-) diff --git a/.gitignore b/.gitignore index 0a12acfd7c..e8a57270c5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ applet/ *~ *.orig *.rej +*.bak \ No newline at end of file diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 58e8b2e6f3..3cbe131c95 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -155,8 +155,8 @@ // Configuration for second X-carriage // Note: the first x-carriage is defined as the x-carriage which homes to the minimum endstop; // the second x-carriage always homes to the maximum endstop. -#define X2_MIN_POS 88 // set minimum to ensure second x-carriage doesn't hit the parked first X-carriage -#define X2_MAX_POS 350.45 // set maximum to the distance between toolheads when both heads are homed +#define X2_MIN_POS 80 // set minimum to ensure second x-carriage doesn't hit the parked first X-carriage +#define X2_MAX_POS 353 // set maximum to the distance between toolheads when both heads are homed #define X2_HOME_DIR 1 // the second X-carriage always homes to the maximum endstop position #define X2_HOME_POS X2_MAX_POS // default home position is the maximum carriage position // However: In this mode the EXTRUDER_OFFSET_X value for the second extruder provides a software @@ -169,7 +169,29 @@ #define X2_STEP_PIN 25 #define X2_DIR_PIN 23 -#endif // DUAL_X_CARRIAGE +// There are a few selectable movement modes for dual x-carriages using M605 S +// Mode 0: Full control. The slicer has full control over both x-carriages and can achieve optimal travel results +// as long as it supports dual x-carriages. (M605 S0) +// Mode 1: Auto-park mode. The firmware will automatically park and unpark the x-carriages on tool changes so +// that additional slicer support is not required. (M605 S1) +// Mode 2: Duplication mode. The firmware will transparently make the second x-carriage and extruder copy all +// actions of the first x-carriage. This allows the printer to print 2 arbitrary items at +// once. (2nd extruder x offset and temp offset are set using: M605 S2 [Xnnn] [Rmmm]) + +// This is the default power-up mode which can be later using M605. +#define DEFAULT_DUAL_X_CARRIAGE_MODE 0 + +// As the x-carriages are independent we can now account for any relative Z offset +#define EXTRUDER1_Z_OFFSET 0.0 // z offset relative to extruder 0 + +// Default settings in "Auto-park Mode" +#define TOOLCHANGE_PARK_ZLIFT 0.2 // the distance to raise Z axis when parking an extruder +#define TOOLCHANGE_UNPARK_ZLIFT 1 // the distance to raise Z axis when unparking an extruder + +// Default x offset in duplication mode (typically set to half print bed width) +#define DEFAULT_DUPLICATION_X_OFFSET 100 + +#endif //DUAL_X_CARRIAGE //homing hits the endstop, then retracts by this distance, before it tries to slowly bump again: #define X_HOME_RETRACT_MM 5 diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index e15ffdf4e0..4609ce818e 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -139,6 +139,7 @@ // M503 - print the current settings (from memory not from eeprom) // M540 - Use S[0|1] to enable or disable the stop SD card print on endstop hit (requires ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) // M600 - Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal] +// M605 - Set dual x-carriage movement mode: S [ X R ] // M907 - Set digital trimpot motor current using axis codes. // M908 - Control digital trimpot directly. // M350 - Set microstepping mode. @@ -168,9 +169,15 @@ float current_position[NUM_AXIS] = { 0.0, 0.0, 0.0, 0.0 }; float add_homeing[3]={0,0,0}; float min_pos[3] = { X_MIN_POS, Y_MIN_POS, Z_MIN_POS }; float max_pos[3] = { X_MAX_POS, Y_MAX_POS, Z_MAX_POS }; -// Extruder offset, only in XY plane + +// Extruder offset #if EXTRUDERS > 1 -float extruder_offset[2][EXTRUDERS] = { +#ifndef DUAL_X_CARRIAGE + #define NUM_EXTRUDER_OFFSETS 2 // only in XY plane +#else + #define NUM_EXTRUDER_OFFSETS 3 // supports offsets in XYZ plane +#endif +float extruder_offset[NUM_EXTRUDER_OFFSETS][EXTRUDERS] = { #if defined(EXTRUDER_OFFSET_X) && defined(EXTRUDER_OFFSET_Y) EXTRUDER_OFFSET_X, EXTRUDER_OFFSET_Y #endif @@ -691,8 +698,13 @@ XYZ_CONSTS_FROM_CONFIG(signed char, home_dir, HOME_DIR); #endif #if X_HOME_DIR != -1 || X2_HOME_DIR != 1 #error "Please use canonical x-carriage assignment" // the x-carriages are defined by their homing directions - #endif + #endif +#define DXC_FULL_CONTROL_MODE 0 +#define DXC_AUTO_PARK_MODE 1 +#define DXC_DUPLICATION_MODE 2 +static int dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; + static float x_home_pos(int extruder) { if (extruder == 0) return base_home_pos(X_AXIS) + add_homeing[X_AXIS]; @@ -708,16 +720,31 @@ static int x_home_dir(int extruder) { return (extruder == 0) ? X_HOME_DIR : X2_HOME_DIR; } -static float inactive_x_carriage_pos = X2_MAX_POS; -#endif +static float inactive_extruder_x_pos = X2_MAX_POS; // used in mode 0 & 1 +static bool active_extruder_parked = false; // used in mode 1 & 2 +static float raised_parked_position[NUM_AXIS]; // used in mode 1 +static unsigned long delayed_move_time = 0; // used in mode 1 +static float duplicate_extruder_x_offset = DEFAULT_DUPLICATION_X_OFFSET; // used in mode 2 +static float duplicate_extruder_temp_offset = 0; // used in mode 2 +bool extruder_duplication_enabled = false; // used in mode 2 +#endif //DUAL_X_CARRIAGE static void axis_is_at_home(int axis) { #ifdef DUAL_X_CARRIAGE - if (axis == X_AXIS && active_extruder != 0) { - current_position[X_AXIS] = x_home_pos(active_extruder); - min_pos[X_AXIS] = X2_MIN_POS; - max_pos[X_AXIS] = max(extruder_offset[X_AXIS][1], X2_MAX_POS); - return; + if (axis == X_AXIS) { + if (active_extruder != 0) { + current_position[X_AXIS] = x_home_pos(active_extruder); + min_pos[X_AXIS] = X2_MIN_POS; + max_pos[X_AXIS] = max(extruder_offset[X_AXIS][1], X2_MAX_POS); + return; + } + else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && active_extruder == 0) { + current_position[X_AXIS] = base_home_pos(X_AXIS) + add_homeing[X_AXIS]; + min_pos[X_AXIS] = base_min_pos(X_AXIS) + add_homeing[X_AXIS]; + max_pos[X_AXIS] = min(base_max_pos(X_AXIS) + add_homeing[X_AXIS], + max(extruder_offset[X_AXIS][1], X2_MAX_POS) - duplicate_extruder_x_offset); + return; + } } #endif current_position[axis] = base_home_pos(axis) + add_homeing[axis]; @@ -869,7 +896,7 @@ void process_commands() for(int8_t i=0; i < NUM_AXIS; i++) { destination[i] = current_position[i]; } - feedrate = 0.0; + feedrate = 0.0; #ifdef DELTA // A delta can only safely home all axis at the same time @@ -920,6 +947,7 @@ void process_commands() int x_axis_home_dir = home_dir(X_AXIS); #else int x_axis_home_dir = x_home_dir(active_extruder); + extruder_duplication_enabled = false; #endif plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); @@ -950,12 +978,19 @@ void process_commands() { #ifdef DUAL_X_CARRIAGE int tmp_extruder = active_extruder; + extruder_duplication_enabled = false; active_extruder = !active_extruder; HOMEAXIS(X); - inactive_x_carriage_pos = current_position[X_AXIS]; + inactive_extruder_x_pos = current_position[X_AXIS]; active_extruder = tmp_extruder; - #endif HOMEAXIS(X); + // reset state used by the different modes + memcpy(raised_parked_position, current_position, sizeof(raised_parked_position)); + delayed_move_time = 0; + active_extruder_parked = true; + #else + HOMEAXIS(X); + #endif } if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) { @@ -1199,6 +1234,10 @@ void process_commands() break; } if (code_seen('S')) setTargetHotend(code_value(), tmp_extruder); +#ifdef DUAL_X_CARRIAGE + if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0) + setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset); +#endif setWatch(); break; case 140: // M140 set bed temp @@ -1252,9 +1291,17 @@ void process_commands() #endif if (code_seen('S')) { setTargetHotend(code_value(), tmp_extruder); +#ifdef DUAL_X_CARRIAGE + if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0) + setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset); +#endif CooldownNoWait = true; } else if (code_seen('R')) { setTargetHotend(code_value(), tmp_extruder); +#ifdef DUAL_X_CARRIAGE + if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0) + setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset); +#endif CooldownNoWait = false; } #ifdef AUTOTEMP @@ -1671,6 +1718,12 @@ void process_commands() { extruder_offset[Y_AXIS][tmp_extruder] = code_value(); } + #ifdef DUAL_X_CARRIAGE + if(code_seen('Z')) + { + extruder_offset[Z_AXIS][tmp_extruder] = code_value(); + } + #endif SERIAL_ECHO_START; SERIAL_ECHOPGM(MSG_HOTEND_OFFSET); for(tmp_extruder = 0; tmp_extruder < EXTRUDERS; tmp_extruder++) @@ -1679,6 +1732,10 @@ void process_commands() SERIAL_ECHO(extruder_offset[X_AXIS][tmp_extruder]); SERIAL_ECHO(","); SERIAL_ECHO(extruder_offset[Y_AXIS][tmp_extruder]); + #ifdef DUAL_X_CARRIAGE + SERIAL_ECHO(","); + SERIAL_ECHO(extruder_offset[Z_AXIS][tmp_extruder]); + #endif } SERIAL_ECHOLN(""); }break; @@ -2013,6 +2070,53 @@ void process_commands() } break; #endif //FILAMENTCHANGEENABLE + #ifdef DUAL_X_CARRIAGE + case 605: // Set dual x-carriage movement mode: + // M605 S0: Full control mode. The slicer has full control over x-carriage movement + // M605 S1: Auto-park mode. The inactive head will auto park/unpark without slicer involvement + // M605 S2 [Xnnn] [Rmmm]: Duplication mode. The second extruder will duplicate the first with nnn + // millimeters x-offset and an optional differential hotend temperature of + // mmm degrees. E.g., with "M605 S2 X100 R2" the second extruder will duplicate + // the first with a spacing of 100mm in the x direction and 2 degrees hotter. + // + // Note: the X axis should be homed after changing dual x-carriage mode. + { + st_synchronize(); + + if (code_seen('S')) + dual_x_carriage_mode = code_value(); + + if (dual_x_carriage_mode == DXC_DUPLICATION_MODE) + { + if (code_seen('X')) + duplicate_extruder_x_offset = max(code_value(),X2_MIN_POS - x_home_pos(0)); + + if (code_seen('R')) + duplicate_extruder_temp_offset = code_value(); + + SERIAL_ECHO_START; + SERIAL_ECHOPGM(MSG_HOTEND_OFFSET); + SERIAL_ECHO(" "); + SERIAL_ECHO(extruder_offset[X_AXIS][0]); + SERIAL_ECHO(","); + SERIAL_ECHO(extruder_offset[Y_AXIS][0]); + SERIAL_ECHO(" "); + SERIAL_ECHO(duplicate_extruder_x_offset); + SERIAL_ECHO(","); + SERIAL_ECHOLN(extruder_offset[Y_AXIS][1]); + } + else if (dual_x_carriage_mode != DXC_FULL_CONTROL_MODE && dual_x_carriage_mode != DXC_AUTO_PARK_MODE) + { + dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; + } + + active_extruder_parked = false; + extruder_duplication_enabled = false; + delayed_move_time = 0; + } + break; + #endif //DUAL_X_CARRIAGE + case 907: // M907 Set digital trimpot motor current using axis codes. { #if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1 @@ -2092,19 +2196,56 @@ void process_commands() // Save current position to return to after applying extruder offset memcpy(destination, current_position, sizeof(destination)); #ifdef DUAL_X_CARRIAGE - // only apply Y extruder offset in dual x carriage mode (x offset is already used in determining home pos) + if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE && Stopped == false && + (delayed_move_time != 0 || current_position[X_AXIS] != x_home_pos(active_extruder))) + { + // Park old head: 1) raise 2) move to park position 3) lower + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, + current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); + plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, + current_position[E_AXIS], max_feedrate[X_AXIS], active_extruder); + plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS], + current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); + st_synchronize(); + } + + // apply Y & Z extruder offset (x offset is already used in determining home pos) current_position[Y_AXIS] = current_position[Y_AXIS] - extruder_offset[Y_AXIS][active_extruder] + extruder_offset[Y_AXIS][tmp_extruder]; + current_position[Z_AXIS] = current_position[Z_AXIS] - + extruder_offset[Z_AXIS][active_extruder] + + extruder_offset[Z_AXIS][tmp_extruder]; + + active_extruder = tmp_extruder; - float tmp_x_pos = current_position[X_AXIS]; + // This function resets the max/min values - the current position may be overwritten below. + axis_is_at_home(X_AXIS); - // Set the new active extruder and position - active_extruder = tmp_extruder; - axis_is_at_home(X_AXIS); //this function updates X min/max values. - current_position[X_AXIS] = inactive_x_carriage_pos; - inactive_x_carriage_pos = tmp_x_pos; - #else + if (dual_x_carriage_mode == DXC_FULL_CONTROL_MODE) + { + current_position[X_AXIS] = inactive_extruder_x_pos; + inactive_extruder_x_pos = destination[X_AXIS]; + } + else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE) + { + active_extruder_parked = (active_extruder == 0); // this triggers the second extruder to move into the duplication position + if (active_extruder == 0 || active_extruder_parked) + current_position[X_AXIS] = inactive_extruder_x_pos; + else + current_position[X_AXIS] = destination[X_AXIS] + duplicate_extruder_x_offset; + inactive_extruder_x_pos = destination[X_AXIS]; + extruder_duplication_enabled = false; + } + else + { + // record raised toolhead position for use by unpark + memcpy(raised_parked_position, current_position, sizeof(raised_parked_position)); + raised_parked_position[Z_AXIS] += TOOLCHANGE_UNPARK_ZLIFT; + active_extruder_parked = true; + delayed_move_time = 0; + } + #else // Offset extruder (only by XY) int i; for(i = 0; i < 2; i++) { @@ -2309,6 +2450,48 @@ void prepare_move() active_extruder); } #else + +#ifdef DUAL_X_CARRIAGE + if (active_extruder_parked) + { + if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && active_extruder == 0) + { + // move duplicate extruder into correct duplication position. + plan_set_position(inactive_extruder_x_pos, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + plan_buffer_line(current_position[X_AXIS] + duplicate_extruder_x_offset, current_position[Y_AXIS], current_position[Z_AXIS], + current_position[E_AXIS], max_feedrate[X_AXIS], 1); + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + st_synchronize(); + extruder_duplication_enabled = true; + active_extruder_parked = false; + } + else if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE) // handle unparking of head + { + if (current_position[E_AXIS] == destination[E_AXIS]) + { + // this is a travel move - skit it but keep track of current position (so that it can later + // be used as start of first non-travel move) + if (delayed_move_time != 0xFFFFFFFFUL) + { + memcpy(current_position, destination, sizeof(current_position)); + if (destination[Z_AXIS] > raised_parked_position[Z_AXIS]) + raised_parked_position[Z_AXIS] = destination[Z_AXIS]; + delayed_move_time = millis(); + return; + } + } + delayed_move_time = 0; + // unpark extruder: 1) raise, 2) move into starting XY position, 3) lower + plan_buffer_line(raised_parked_position[X_AXIS], raised_parked_position[Y_AXIS], raised_parked_position[Z_AXIS], current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], raised_parked_position[Z_AXIS], + current_position[E_AXIS], min(max_feedrate[X_AXIS],max_feedrate[Y_AXIS]), active_extruder); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], + current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); + active_extruder_parked = false; + } + } +#endif //DUAL_X_CARRIAGE + // Do not use feedmultiply for E or Z only moves if( (current_position[X_AXIS] == destination [X_AXIS]) && (current_position[Y_AXIS] == destination [Y_AXIS])) { plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); @@ -2316,7 +2499,7 @@ void prepare_move() else { plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60/100.0, active_extruder); } -#endif +#endif //else DELTA for(int8_t i=0; i < NUM_AXIS; i++) { current_position[i] = destination[i]; } @@ -2428,6 +2611,16 @@ void manage_inactivity() WRITE(E0_ENABLE_PIN,oldstatus); } #endif + #if defined(DUAL_X_CARRIAGE) + // handle delayed move timeout + if (delayed_move_time != 0 && (millis() - delayed_move_time) > 1000 && Stopped == false) + { + // travel moves have been received so enact them + delayed_move_time = 0xFFFFFFFFUL; // force moves to be done + memcpy(destination,current_position,sizeof(destination)); + prepare_move(); + } + #endif check_axes_activity(); } diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index 0ba1001395..7d738ac5e9 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -349,20 +349,36 @@ ISR(TIMER1_COMPA_vect) // Set the direction bits (X_AXIS=A_AXIS and Y_AXIS=B_AXIS for COREXY) if((out_bits & (1<active_extruder != 0) + WRITE(X2_DIR_PIN, INVERT_X_DIR); + else + WRITE(X_DIR_PIN, INVERT_X_DIR); + } + #else WRITE(X_DIR_PIN, INVERT_X_DIR); + #endif count_direction[X_AXIS]=-1; } else{ #ifdef DUAL_X_CARRIAGE - if (active_extruder != 0) - WRITE(X2_DIR_PIN,!INVERT_X_DIR); - else - #endif + if (extruder_duplication_enabled){ + WRITE(X_DIR_PIN, !INVERT_X_DIR); + WRITE(X2_DIR_PIN, !INVERT_X_DIR); + } + else{ + if (current_block->active_extruder != 0) + WRITE(X2_DIR_PIN, !INVERT_X_DIR); + else + WRITE(X_DIR_PIN, !INVERT_X_DIR); + } + #else WRITE(X_DIR_PIN, !INVERT_X_DIR); + #endif count_direction[X_AXIS]=1; } if((out_bits & (1<active_extruder == 0 && X_HOME_DIR == -1) + || (current_block->active_extruder != 0 && X2_HOME_DIR == -1)) + #endif { #if defined(X_MIN_PIN) && X_MIN_PIN > -1 bool x_min_endstop=(READ(X_MIN_PIN) != X_MIN_ENDSTOP_INVERTING); @@ -404,8 +421,9 @@ ISR(TIMER1_COMPA_vect) { #ifdef DUAL_X_CARRIAGE // with 2 x-carriages, endstops are only checked in the homing direction for the active extruder - if ((active_extruder == 0 && X_HOME_DIR == 1) || (active_extruder != 0 && X2_HOME_DIR == 1)) - #endif + if ((current_block->active_extruder == 0 && X_HOME_DIR == 1) + || (current_block->active_extruder != 0 && X2_HOME_DIR == 1)) + #endif { #if defined(X_MAX_PIN) && X_MAX_PIN > -1 bool x_max_endstop=(READ(X_MAX_PIN) != X_MAX_ENDSTOP_INVERTING); @@ -455,8 +473,8 @@ ISR(TIMER1_COMPA_vect) if ((out_bits & (1<steps_x; if (counter_x > 0) { - #ifdef DUAL_X_CARRIAGE - if (active_extruder != 0) - WRITE(X2_STEP_PIN,!INVERT_X_STEP_PIN); - else - #endif + #ifdef DUAL_X_CARRIAGE + if (extruder_duplication_enabled){ WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); + WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN); + } + else { + if (current_block->active_extruder != 0) + WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN); + else + WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); + } + #else + WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); + #endif counter_x -= current_block->step_event_count; - count_position[X_AXIS]+=count_direction[X_AXIS]; - #ifdef DUAL_X_CARRIAGE - if (active_extruder != 0) - WRITE(X2_STEP_PIN,INVERT_X_STEP_PIN); - else - #endif + count_position[X_AXIS]+=count_direction[X_AXIS]; + #ifdef DUAL_X_CARRIAGE + if (extruder_duplication_enabled){ WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); + WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN); + } + else { + if (current_block->active_extruder != 0) + WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN); + else + WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); + } + #else + WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); + #endif } counter_y += current_block->steps_y; @@ -556,16 +590,16 @@ ISR(TIMER1_COMPA_vect) counter_z += current_block->steps_z; if (counter_z > 0) { WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); - - #ifdef Z_DUAL_STEPPER_DRIVERS + + #ifdef Z_DUAL_STEPPER_DRIVERS WRITE(Z2_STEP_PIN, !INVERT_Z_STEP_PIN); #endif counter_z -= current_block->step_event_count; count_position[Z_AXIS]+=count_direction[Z_AXIS]; WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN); - - #ifdef Z_DUAL_STEPPER_DRIVERS + + #ifdef Z_DUAL_STEPPER_DRIVERS WRITE(Z2_STEP_PIN, INVERT_Z_STEP_PIN); #endif } diff --git a/Marlin/stepper.h b/Marlin/stepper.h index 6e60a332e7..ac9dd8af59 100644 --- a/Marlin/stepper.h +++ b/Marlin/stepper.h @@ -28,9 +28,16 @@ #define NORM_E_DIR() { if(current_block->active_extruder == 2) { WRITE(E2_DIR_PIN, !INVERT_E2_DIR); } else { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }}} #define REV_E_DIR() { if(current_block->active_extruder == 2) { WRITE(E2_DIR_PIN, INVERT_E2_DIR); } else { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }}} #elif EXTRUDERS > 1 - #define WRITE_E_STEP(v) { if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }} - #define NORM_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }} - #define REV_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }} + #ifndef DUAL_X_CARRIAGE + #define WRITE_E_STEP(v) { if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }} + #define NORM_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }} + #define REV_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }} + #else + extern bool extruder_duplication_enabled; + #define WRITE_E_STEP(v) { if(extruder_duplication_enabled) { WRITE(E0_STEP_PIN, v); WRITE(E1_STEP_PIN, v); } else if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }} + #define NORM_E_DIR() { if(extruder_duplication_enabled) { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }} + #define REV_E_DIR() { if(extruder_duplication_enabled) { WRITE(E0_DIR_PIN, INVERT_E0_DIR); WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }} + #endif #else #define WRITE_E_STEP(v) WRITE(E0_STEP_PIN, v) #define NORM_E_DIR() WRITE(E0_DIR_PIN, !INVERT_E0_DIR) From 221286c10a9d8b29487cb8d4b70b9b13826e7d89 Mon Sep 17 00:00:00 2001 From: Robert F-C Date: Thu, 8 Aug 2013 00:16:38 +1000 Subject: [PATCH 029/256] Add .gitignore change to ignore .bak files (produced by WinMerge and other editors) --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e8a57270c5..a24cf93707 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ applet/ *~ *.orig *.rej -*.bak \ No newline at end of file +*.bak From 9aa22290775a198db33fff4ffd0e14736f898540 Mon Sep 17 00:00:00 2001 From: Peter Hercek Date: Wed, 28 Aug 2013 01:15:20 +0200 Subject: [PATCH 030/256] add command M666 for adjusting delta printer endstop position --- Marlin/ConfigurationStore.cpp | 20 +++++++++++++++++++- Marlin/Marlin.h | 3 +++ Marlin/Marlin_main.cpp | 22 +++++++++++++++++++++- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/Marlin/ConfigurationStore.cpp b/Marlin/ConfigurationStore.cpp index 65d030279d..5d47d3d545 100644 --- a/Marlin/ConfigurationStore.cpp +++ b/Marlin/ConfigurationStore.cpp @@ -37,7 +37,7 @@ void _EEPROM_readData(int &pos, uint8_t* value, uint8_t size) // the default values are used whenever there is a change to the data, to prevent // wrong data being written to the variables. // ALSO: always make sure the variables in the Store and retrieve sections are in the same order. -#define EEPROM_VERSION "V08" +#define EEPROM_VERSION "V09" #ifdef EEPROM_SETTINGS void Config_StoreSettings() @@ -57,6 +57,9 @@ void Config_StoreSettings() EEPROM_WRITE_VAR(i,max_z_jerk); EEPROM_WRITE_VAR(i,max_e_jerk); EEPROM_WRITE_VAR(i,add_homeing); + #ifdef DELTA + EEPROM_WRITE_VAR(i,endstop_adj); + #endif #ifndef ULTIPANEL int plaPreheatHotendTemp = PLA_PREHEAT_HOTEND_TEMP, plaPreheatHPBTemp = PLA_PREHEAT_HPB_TEMP, plaPreheatFanSpeed = PLA_PREHEAT_FAN_SPEED; int absPreheatHotendTemp = ABS_PREHEAT_HOTEND_TEMP, absPreheatHPBTemp = ABS_PREHEAT_HPB_TEMP, absPreheatFanSpeed = ABS_PREHEAT_FAN_SPEED; @@ -145,6 +148,15 @@ void Config_PrintSettings() SERIAL_ECHOPAIR(" Y" ,add_homeing[1] ); SERIAL_ECHOPAIR(" Z" ,add_homeing[2] ); SERIAL_ECHOLN(""); +#ifdef DELTA + SERIAL_ECHO_START; + SERIAL_ECHOLNPGM("Endstop adjustement (mm):"); + SERIAL_ECHO_START; + SERIAL_ECHOPAIR(" M666 X",endstop_adj[0] ); + SERIAL_ECHOPAIR(" Y" ,endstop_adj[1] ); + SERIAL_ECHOPAIR(" Z" ,endstop_adj[2] ); + SERIAL_ECHOLN(""); +#endif #ifdef PIDTEMP SERIAL_ECHO_START; SERIAL_ECHOLNPGM("PID settings:"); @@ -185,6 +197,9 @@ void Config_RetrieveSettings() EEPROM_READ_VAR(i,max_z_jerk); EEPROM_READ_VAR(i,max_e_jerk); EEPROM_READ_VAR(i,add_homeing); + #ifdef DELTA + EEPROM_READ_VAR(i,endstop_adj); + #endif #ifndef ULTIPANEL int plaPreheatHotendTemp, plaPreheatHPBTemp, plaPreheatFanSpeed; int absPreheatHotendTemp, absPreheatHPBTemp, absPreheatFanSpeed; @@ -244,6 +259,9 @@ void Config_ResetDefault() max_z_jerk=DEFAULT_ZJERK; max_e_jerk=DEFAULT_EJERK; add_homeing[0] = add_homeing[1] = add_homeing[2] = 0; +#ifdef DELTA + endstop_adj[0] = endstop_adj[1] = endstop_adj[2] = 0; +#endif #ifdef ULTIPANEL plaPreheatHotendTemp = PLA_PREHEAT_HOTEND_TEMP; plaPreheatHPBTemp = PLA_PREHEAT_HPB_TEMP; diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index 9881707896..6da0a83b5d 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -191,6 +191,9 @@ extern int feedmultiply; extern int extrudemultiply; // Sets extrude multiply factor (in percent) extern float current_position[NUM_AXIS] ; extern float add_homeing[3]; +#ifdef DELTA +extern float endstop_adj[3]; +#endif extern float min_pos[3]; extern float max_pos[3]; extern int fanSpeed; diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 4609ce818e..1c8cb63765 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -139,6 +139,7 @@ // M503 - print the current settings (from memory not from eeprom) // M540 - Use S[0|1] to enable or disable the stop SD card print on endstop hit (requires ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) // M600 - Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal] +// M666 - set delta endstop adjustemnt // M605 - Set dual x-carriage movement mode: S [ X R ] // M907 - Set digital trimpot motor current using axis codes. // M908 - Control digital trimpot directly. @@ -167,6 +168,9 @@ int saved_feedmultiply; int extrudemultiply=100; //100->1 200->2 float current_position[NUM_AXIS] = { 0.0, 0.0, 0.0, 0.0 }; float add_homeing[3]={0,0,0}; +#ifdef DELTA +float endstop_adj[3]={0,0,0}; +#endif float min_pos[3] = { X_MIN_POS, Y_MIN_POS, Z_MIN_POS }; float max_pos[3] = { X_MAX_POS, Y_MAX_POS, Z_MAX_POS }; @@ -794,7 +798,15 @@ static void homeaxis(int axis) { #endif plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); st_synchronize(); - +#ifdef DELTA + // retrace by the amount specified in endstop_adj + if (endstop_adj[axis] * axis_home_dir < 0) { + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[axis] = endstop_adj[axis]; + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); + st_synchronize(); + } +#endif axis_is_at_home(axis); destination[axis] = current_position[axis]; feedrate = 0.0; @@ -1658,6 +1670,14 @@ void process_commands() if(code_seen(axis_codes[i])) add_homeing[i] = code_value(); } break; + #ifdef DELTA + case 666: // M666 set delta endstop adjustemnt + for(int8_t i=0; i < 3; i++) + { + if(code_seen(axis_codes[i])) endstop_adj[i] = code_value(); + } + break; + #endif #ifdef FWRETRACT case 207: //M207 - set retract length S[positive mm] F[feedrate mm/sec] Z[additional zlift/hop] { From a447e76fdfecc18a5a93a8be9e99a0560c9cfbe7 Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Fri, 30 Aug 2013 14:39:19 +0200 Subject: [PATCH 031/256] Update read me. Added comment about products that have a patent. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 014871739a..0b0b74e085 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ ========================== Marlin 3D Printer Firmware ========================== +Marlin has a GPL license because I believe in open development. +Please do not use this code in products (3D printers, CNC etc) that are closed source or are crippled by a patent. [![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=ErikZalm&url=https://github.com/ErikZalm/Marlin&title=Marlin&language=&tags=github&category=software) From f26f26b7bdb493d65c62ea7c195c2e140b26b252 Mon Sep 17 00:00:00 2001 From: Jim Morris Date: Thu, 5 Sep 2013 16:36:55 -0700 Subject: [PATCH 032/256] Fix the example delta configuration as someone forgot to do it. --- Marlin/example_configurations/delta/Configuration.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Marlin/example_configurations/delta/Configuration.h b/Marlin/example_configurations/delta/Configuration.h index cb92365696..dbd2892b4b 100644 --- a/Marlin/example_configurations/delta/Configuration.h +++ b/Marlin/example_configurations/delta/Configuration.h @@ -82,6 +82,8 @@ // and processor overload (too many expensive sqrt calls). #define DELTA_SEGMENTS_PER_SECOND 200 +// NOTE NB all values for DELTA_* values MOUST be floating point, so always have a decimal point in them + // Center-to-center distance of the holes in the diagonal push rods. #define DELTA_DIAGONAL_ROD 250.0 // mm @@ -97,6 +99,8 @@ // Effective horizontal distance bridged by diagonal push rods. #define DELTA_RADIUS (DELTA_SMOOTH_ROD_OFFSET-DELTA_EFFECTOR_OFFSET-DELTA_CARRIAGE_OFFSET) +#define DELTA_DIAGONAL_ROD_2 sq(DELTA_DIAGONAL_ROD) + // Effective X/Y positions of the three vertical towers. #define SIN_60 0.8660254037844386 #define COS_60 0.5 From 3b315b3da0464efd39e1f5a379eaeba601c4871f Mon Sep 17 00:00:00 2001 From: Tim Koster Date: Fri, 6 Sep 2013 22:25:39 +0300 Subject: [PATCH 033/256] Added BlinkM support over i2c --- Marlin/BlinkM.cpp | 23 +++++++++++++++++++++++ Marlin/BlinkM.h | 14 ++++++++++++++ Marlin/Configuration.h | 3 +++ Marlin/Marlin_main.cpp | 17 +++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 Marlin/BlinkM.cpp create mode 100644 Marlin/BlinkM.h diff --git a/Marlin/BlinkM.cpp b/Marlin/BlinkM.cpp new file mode 100644 index 0000000000..15a2527bbf --- /dev/null +++ b/Marlin/BlinkM.cpp @@ -0,0 +1,23 @@ +/* + BlinkM.cpp - Library for controlling a BlinkM over i2c + Created by Tim Koster, August 21 2013. +*/ +#if (ARDUINO >= 100) + # include "Arduino.h" +#else + # include "WProgram.h" +#endif +#include "BlinkM.h" + +void SendColors(byte red, byte grn, byte blu) +{ + Wire.begin(); + Wire.beginTransmission(0x09); + Wire.write('o'); //to disable ongoing script, only needs to be used once + Wire.write('n'); + Wire.write(red); + Wire.write(grn); + Wire.write(blu); + Wire.endTransmission(); +} + diff --git a/Marlin/BlinkM.h b/Marlin/BlinkM.h new file mode 100644 index 0000000000..5136828782 --- /dev/null +++ b/Marlin/BlinkM.h @@ -0,0 +1,14 @@ +/* + BlinkM.h + Library header file for BlinkM library + */ +#if (ARDUINO >= 100) + # include "Arduino.h" +#else + # include "WProgram.h" +#endif + +#include "Wire.h" + +void SendColors(byte red, byte grn, byte blu); + diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 9ff27f5b00..67760abe3b 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -533,6 +533,9 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of # endif #endif +// define BlinkM Support +#define BlinkM + // Increase the FAN pwm frequency. Removes the PWM noise but increases heating in the FET/Arduino //#define FAST_PWM_FAN diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 4609ce818e..26fbd41232 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -40,6 +40,9 @@ #include "language.h" #include "pins_arduino.h" +#include "BlinkM.h" +#include "Wire.h" + #if NUM_SERVOS > 0 #include "Servo.h" #endif @@ -109,6 +112,7 @@ // M128 - EtoP Open (BariCUDA EtoP = electricity to air pressure transducer by jmil) // M129 - EtoP Closed (BariCUDA EtoP = electricity to air pressure transducer by jmil) // M140 - Set bed target temp +// M150 - Set BlinkM Colour Output R: Red<0-255> U(!): Green<0-255> B: Blue<0-255> over i2c, G for green does not work. // M190 - Sxxx Wait for bed current temp to reach target temp. Waits only when heating // Rxxx Wait for bed current temp to reach target temp. Waits when heating and cooling // M200 - Set filament diameter @@ -1613,6 +1617,19 @@ void process_commands() #endif break; //TODO: update for all axis, use for loop + case 150: // M150 + { + byte red; + byte grn; + byte blu; + + if(code_seen('R')) red = code_value(); + if(code_seen('U')) grn = code_value(); + if(code_seen('B')) blu = code_value(); + + SendColors(red,grn,blu); + } + break; case 201: // M201 for(int8_t i=0; i < NUM_AXIS; i++) { From 7016cc951186d876e7812cbeb945f5d27b125fb7 Mon Sep 17 00:00:00 2001 From: Tim Koster Date: Tue, 10 Sep 2013 12:18:29 +0300 Subject: [PATCH 034/256] Added BlinkM support over i2c --- Marlin/BlinkM.cpp | 23 +++++++++++++++++++++++ Marlin/BlinkM.h | 14 ++++++++++++++ Marlin/Configuration.h | 3 +++ Marlin/Marlin_main.cpp | 17 +++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 Marlin/BlinkM.cpp create mode 100644 Marlin/BlinkM.h diff --git a/Marlin/BlinkM.cpp b/Marlin/BlinkM.cpp new file mode 100644 index 0000000000..15a2527bbf --- /dev/null +++ b/Marlin/BlinkM.cpp @@ -0,0 +1,23 @@ +/* + BlinkM.cpp - Library for controlling a BlinkM over i2c + Created by Tim Koster, August 21 2013. +*/ +#if (ARDUINO >= 100) + # include "Arduino.h" +#else + # include "WProgram.h" +#endif +#include "BlinkM.h" + +void SendColors(byte red, byte grn, byte blu) +{ + Wire.begin(); + Wire.beginTransmission(0x09); + Wire.write('o'); //to disable ongoing script, only needs to be used once + Wire.write('n'); + Wire.write(red); + Wire.write(grn); + Wire.write(blu); + Wire.endTransmission(); +} + diff --git a/Marlin/BlinkM.h b/Marlin/BlinkM.h new file mode 100644 index 0000000000..5136828782 --- /dev/null +++ b/Marlin/BlinkM.h @@ -0,0 +1,14 @@ +/* + BlinkM.h + Library header file for BlinkM library + */ +#if (ARDUINO >= 100) + # include "Arduino.h" +#else + # include "WProgram.h" +#endif + +#include "Wire.h" + +void SendColors(byte red, byte grn, byte blu); + diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 9ff27f5b00..195331252f 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -557,6 +557,9 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of // Support for the BariCUDA Paste Extruder. //#define BARICUDA +//define BlinkM/CyzRgb Support +//#define BlinkM + /*********************************************************************\ * R/C SERVO support * Sponsored by TrinityLabs, Reworked by codexmas diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 4609ce818e..26fbd41232 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -40,6 +40,9 @@ #include "language.h" #include "pins_arduino.h" +#include "BlinkM.h" +#include "Wire.h" + #if NUM_SERVOS > 0 #include "Servo.h" #endif @@ -109,6 +112,7 @@ // M128 - EtoP Open (BariCUDA EtoP = electricity to air pressure transducer by jmil) // M129 - EtoP Closed (BariCUDA EtoP = electricity to air pressure transducer by jmil) // M140 - Set bed target temp +// M150 - Set BlinkM Colour Output R: Red<0-255> U(!): Green<0-255> B: Blue<0-255> over i2c, G for green does not work. // M190 - Sxxx Wait for bed current temp to reach target temp. Waits only when heating // Rxxx Wait for bed current temp to reach target temp. Waits when heating and cooling // M200 - Set filament diameter @@ -1613,6 +1617,19 @@ void process_commands() #endif break; //TODO: update for all axis, use for loop + case 150: // M150 + { + byte red; + byte grn; + byte blu; + + if(code_seen('R')) red = code_value(); + if(code_seen('U')) grn = code_value(); + if(code_seen('B')) blu = code_value(); + + SendColors(red,grn,blu); + } + break; case 201: // M201 for(int8_t i=0; i < NUM_AXIS; i++) { From 88dfeefca3c47158e634998c2ed96a21a6b04f50 Mon Sep 17 00:00:00 2001 From: Tim Koster Date: Tue, 10 Sep 2013 12:32:21 +0300 Subject: [PATCH 035/256] Define BlinkM default disabled --- Marlin/Configuration.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 33b96f5b33..195331252f 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -533,9 +533,6 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of # endif #endif -// define BlinkM Support -#define BlinkM - // Increase the FAN pwm frequency. Removes the PWM noise but increases heating in the FET/Arduino //#define FAST_PWM_FAN From 595580556c947914d8802be73b907a6aa58fb5d7 Mon Sep 17 00:00:00 2001 From: George Roberts Date: Tue, 10 Sep 2013 09:56:19 -0400 Subject: [PATCH 036/256] Fixed bug that makes ulticontroller knob backwards introduced Feb 28 2013 by Robert. Bug introduced in version 6beb42cdf65971aeca93868305ed93ae6ed732eb. Robert did a good job of simplifying but messed up this chunk of code. Looking at working version: 839bef6d5d436055c6cef051b6b32a84bd18d05a it seems there is no case where encrot3 should be defined as 2 because if ULTICONTROLLER is defined then NEWPANEL is also defined. --- Marlin/ultralcd_implementation_hitachi_HD44780.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Marlin/ultralcd_implementation_hitachi_HD44780.h b/Marlin/ultralcd_implementation_hitachi_HD44780.h index 9be57a905c..ac397f6753 100644 --- a/Marlin/ultralcd_implementation_hitachi_HD44780.h +++ b/Marlin/ultralcd_implementation_hitachi_HD44780.h @@ -128,17 +128,10 @@ extern volatile uint16_t buttons; //an extended version of the last checked but // 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 defined(EN_A) && defined(EN_B) - #ifndef ULTIMAKERCONTROLLER #define encrot0 0 #define encrot1 2 #define encrot2 3 #define encrot3 1 - #else - #define encrot0 0 - #define encrot1 1 - #define encrot2 3 - #define encrot3 2 - #endif #endif #endif //ULTIPANEL From acd8619809a11c793e7246787148ac5e7a81357a Mon Sep 17 00:00:00 2001 From: Martin Lukasik Date: Tue, 10 Sep 2013 22:10:58 +0100 Subject: [PATCH 037/256] Fan fix for Panelolu2+Sanguinololu. --- Marlin/pins.h | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/Marlin/pins.h b/Marlin/pins.h index 87556cc2f3..c6264e3180 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -492,7 +492,7 @@ #define SDSS 53 #define SDCARDDETECT -1 #define KILL_PIN 41 - #define FAN_PIN 45 + #else //arduino pin which triggers an piezzo beeper #define BEEPER 33 // Beeper on AUX-4 @@ -901,23 +901,23 @@ #define LED_PIN -1 #define FAN_PIN -1 -#if FAN_PIN == 12 || FAN_PIN ==13 -#define FAN_SOFT_PWM + #if FAN_PIN == 12 || FAN_PIN ==13 + #define FAN_SOFT_PWM #endif #ifdef MELZI -#define LED_PIN 27 /* On some broken versions of the Sanguino libraries the pin definitions are wrong, which then needs LED_PIN as pin 28. But you better upgrade your Sanguino libraries! See #368. */ -#define FAN_PIN 4 + #define LED_PIN 27 /* On some broken versions of the Sanguino libraries the pin definitions are wrong, which then needs LED_PIN as pin 28. But you better upgrade your Sanguino libraries! See #368. */ + #define FAN_PIN 4 // Works for Panelolu2 too #endif #ifdef STB -#define FAN_PIN 4 + #define FAN_PIN 4 // Uncomment this if you have the first generation (V1.10) of STBs board -#define LCD_PIN_BL 17 // LCD backlight LED + #define LCD_PIN_BL 17 // LCD backlight LED #endif #ifdef AZTEEG_X1 -#define FAN_PIN 4 + #define FAN_PIN 4 #endif #define PS_ON_PIN -1 @@ -929,19 +929,23 @@ #ifdef SANGUINOLOLU_V_1_2 -#define HEATER_BED_PIN 12 // (bed) -#define X_ENABLE_PIN 14 -#define Y_ENABLE_PIN 14 -#define Z_ENABLE_PIN 26 -#define E0_ENABLE_PIN 14 + #define HEATER_BED_PIN 12 // (bed) + #define X_ENABLE_PIN 14 + #define Y_ENABLE_PIN 14 + #define Z_ENABLE_PIN 26 + #define E0_ENABLE_PIN 14 + + #ifdef LCD_I2C_PANELOLU2 + #define FAN_PIN 4 // Uses Transistor1 (PWM) on Panelolu2's Sanguino Adapter Board to drive the fan + #endif #else -#define HEATER_BED_PIN 14 // (bed) +#define HEATER_BED_PIN 14 // (bed) #define X_ENABLE_PIN -1 #define Y_ENABLE_PIN -1 #define Z_ENABLE_PIN -1 -#define E0_ENABLE_PIN -1 +#define E0_ENABLE_PIN -1 #endif From f17506c504ee371c76de2ab717c04eec8d5faa35 Mon Sep 17 00:00:00 2001 From: GDV0 Date: Wed, 11 Sep 2013 23:09:37 +0200 Subject: [PATCH 038/256] FIx compilation error when enabling SERVO_ENDSTOPS (#591) --- Marlin/Marlin_main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 1c8cb63765..65b829bdc3 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -772,7 +772,7 @@ static void homeaxis(int axis) { // Engage Servo endstop if enabled #ifdef SERVO_ENDSTOPS - if (SERVO_ENDSTOPS[axis] > -1) { + if (servo_endstops[axis] > -1) { servos[servo_endstops[axis]].write(servo_endstop_angles[axis * 2]); } #endif @@ -814,7 +814,7 @@ static void homeaxis(int axis) { // Retract Servo endstop if enabled #ifdef SERVO_ENDSTOPS - if (SERVO_ENDSTOPS[axis] > -1) { + if (servo_endstops[axis] > -1) { servos[servo_endstops[axis]].write(servo_endstop_angles[axis * 2 + 1]); } #endif From bf7007d02fe02fa1d78ab50cbc68a3debf6bcfa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xoan=20Sampai=C3=B1o?= Date: Fri, 13 Sep 2013 04:12:51 +0200 Subject: [PATCH 039/256] add ENCODER_PULSES_PER_STEP --- Marlin/ultralcd.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 229e23e92d..4256878935 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -88,6 +88,7 @@ static void menu_action_setting_edit_callback_long5(const char* pstr, unsigned l #if !defined(LCD_I2C_VIKI) #define ENCODER_STEPS_PER_MENU_ITEM 5 + #define ENCODER_PULSES_PER_STEP 1 #else #define ENCODER_STEPS_PER_MENU_ITEM 2 // VIKI LCD rotary encoder uses a different number of steps per rotation #endif @@ -984,10 +985,10 @@ void lcd_update() reprapworld_keypad_move_home(); } #endif - if (encoderDiff) + if (abs(encoderDiff) >= ENCODER_PULSES_PER_STEP) { lcdDrawUpdate = 1; - encoderPosition += encoderDiff; + encoderPosition += encoderDiff / ENCODER_PULSES_PER_STEP; encoderDiff = 0; timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS; } From 3626b5ad8b7b3f73547383faa8887e2afa4ca3bb Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Sat, 14 Sep 2013 13:50:09 +0200 Subject: [PATCH 040/256] Removed Delta from the default config file. Changed EEPROM CHITCHAT behavior. M503 is always enabled. --- Marlin/Configuration.h | 40 ----------------------------------- Marlin/ConfigurationStore.cpp | 6 ++++-- Marlin/ConfigurationStore.h | 2 +- 3 files changed, 5 insertions(+), 43 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 9ff27f5b00..ef7a359e47 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -70,46 +70,6 @@ #define POWER_SUPPLY 1 - -//=========================================================================== -//============================== Delta Settings ============================= -//=========================================================================== -// Enable DELTA kinematics -//#define DELTA - -// 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). -#define DELTA_SEGMENTS_PER_SECOND 200 - -// Center-to-center distance of the holes in the diagonal push rods. -#define DELTA_DIAGONAL_ROD 250.0 // mm - -// Horizontal offset from middle of printer to smooth rod center. -#define DELTA_SMOOTH_ROD_OFFSET 175.0 // mm - -// Horizontal offset of the universal joints on the end effector. -#define DELTA_EFFECTOR_OFFSET 33.0 // mm - -// Horizontal offset of the universal joints on the carriages. -#define DELTA_CARRIAGE_OFFSET 18.0 // mm - -// Effective horizontal distance bridged by diagonal push rods. -#define DELTA_RADIUS (DELTA_SMOOTH_ROD_OFFSET-DELTA_EFFECTOR_OFFSET-DELTA_CARRIAGE_OFFSET) - -// Effective X/Y positions of the three vertical towers. -#define SIN_60 0.8660254037844386 -#define COS_60 0.5 -#define DELTA_TOWER1_X -SIN_60*DELTA_RADIUS // front left tower -#define DELTA_TOWER1_Y -COS_60*DELTA_RADIUS -#define DELTA_TOWER2_X SIN_60*DELTA_RADIUS // front right tower -#define DELTA_TOWER2_Y -COS_60*DELTA_RADIUS -#define DELTA_TOWER3_X 0.0 // back middle tower -#define DELTA_TOWER3_Y DELTA_RADIUS - -// Diagonal rod squared -#define DELTA_DIAGONAL_ROD_2 pow(DELTA_DIAGONAL_ROD,2) - //=========================================================================== //=============================Thermal Settings ============================ //=========================================================================== diff --git a/Marlin/ConfigurationStore.cpp b/Marlin/ConfigurationStore.cpp index 5d47d3d545..1fb72450c6 100644 --- a/Marlin/ConfigurationStore.cpp +++ b/Marlin/ConfigurationStore.cpp @@ -94,7 +94,7 @@ void Config_StoreSettings() #endif //EEPROM_SETTINGS -#ifdef EEPROM_CHITCHAT +#ifndef DISABLE_M503 void Config_PrintSettings() { // Always have this function, even with EEPROM_SETTINGS disabled, the current values will be shown SERIAL_ECHO_START; @@ -231,7 +231,9 @@ void Config_RetrieveSettings() { Config_ResetDefault(); } - Config_PrintSettings(); + #ifdef EEPROM_CHITCHAT + Config_PrintSettings(); + #endif } #endif diff --git a/Marlin/ConfigurationStore.h b/Marlin/ConfigurationStore.h index 2bbf4808c3..4f68b13a6a 100644 --- a/Marlin/ConfigurationStore.h +++ b/Marlin/ConfigurationStore.h @@ -5,7 +5,7 @@ void Config_ResetDefault(); -#ifdef EEPROM_CHITCHAT +#ifndef DISABLE_M503 void Config_PrintSettings(); #else FORCE_INLINE void Config_PrintSettings() {} From 7ee275b620fa055bb2b7516cf302ac3e531438ac Mon Sep 17 00:00:00 2001 From: Richard Miles Date: Tue, 17 Sep 2013 19:02:00 +0100 Subject: [PATCH 041/256] Added Y_DUAL_STEPPER_DRIVERS Enables two stepper drivers to be used for the Y axis (useful for Shapeoko style machines) Each Y driver can be stepped either the same way or in opposite directions, accounting for different hardware setups (leadscrew vs. belt driven) --- Marlin/Configuration_adv.h | 73 +++++++- Marlin/Marlin.h | 30 ++- Marlin/stepper.cpp | 366 ++++++++++++++++++++++++------------- 3 files changed, 325 insertions(+), 144 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 5f1c77a056..648a9beafc 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -18,12 +18,6 @@ //#define WATCH_TEMP_PERIOD 40000 //40 seconds //#define WATCH_TEMP_INCREASE 10 //Heat up at least 10 degree in 20 seconds -// Wait for Cooldown -// This defines if the M109 call should not block if it is cooling down. -// example: From a current temp of 220, you set M109 S200. -// if CooldownNoWait is defined M109 will not wait for the cooldown to finish -#define CooldownNoWait true - #ifdef PIDTEMP // this adds an experimental additional term to the heatingpower, proportional to the extrusion speed. // if Kc is choosen well, the additional required power due to increased melting should be compensated. @@ -152,6 +146,68 @@ #define EXTRUDERS 1 #endif +// Same again but for Y Axis. +#define Y_DUAL_STEPPER_DRIVERS + +// Define if the two Y drives need to rotate in opposite directions +#define INVERT_Y2_VS_Y_DIR true + +#ifdef Y_DUAL_STEPPER_DRIVERS + #undef EXTRUDERS + #define EXTRUDERS 1 +#endif + +#ifdef Z_DUAL_STEPPER_DRIVERS && Y_DUAL_STEPPER_DRIVERS + #error "You cannot have dual drivers for both Y and Z" +#endif + +// Enable this for dual x-carriage printers. +// A dual x-carriage design has the advantage that the inactive extruder can be parked which +// prevents hot-end ooze contaminating the print. It also reduces the weight of each x-carriage +// allowing faster printing speeds. +//#define DUAL_X_CARRIAGE +#ifdef DUAL_X_CARRIAGE +// Configuration for second X-carriage +// Note: the first x-carriage is defined as the x-carriage which homes to the minimum endstop; +// the second x-carriage always homes to the maximum endstop. +#define X2_MIN_POS 80 // set minimum to ensure second x-carriage doesn't hit the parked first X-carriage +#define X2_MAX_POS 353 // set maximum to the distance between toolheads when both heads are homed +#define X2_HOME_DIR 1 // the second X-carriage always homes to the maximum endstop position +#define X2_HOME_POS X2_MAX_POS // default home position is the maximum carriage position + // However: In this mode the EXTRUDER_OFFSET_X value for the second extruder provides a software + // override for X2_HOME_POS. This also allow recalibration of the distance between the two endstops + // without modifying the firmware (through the "M218 T1 X???" command). + // Remember: you should set the second extruder x-offset to 0 in your slicer. + +// Pins for second x-carriage stepper driver (defined here to avoid further complicating pins.h) +#define X2_ENABLE_PIN 29 +#define X2_STEP_PIN 25 +#define X2_DIR_PIN 23 + +// There are a few selectable movement modes for dual x-carriages using M605 S +// Mode 0: Full control. The slicer has full control over both x-carriages and can achieve optimal travel results +// as long as it supports dual x-carriages. (M605 S0) +// Mode 1: Auto-park mode. The firmware will automatically park and unpark the x-carriages on tool changes so +// that additional slicer support is not required. (M605 S1) +// Mode 2: Duplication mode. The firmware will transparently make the second x-carriage and extruder copy all +// actions of the first x-carriage. This allows the printer to print 2 arbitrary items at +// once. (2nd extruder x offset and temp offset are set using: M605 S2 [Xnnn] [Rmmm]) + +// This is the default power-up mode which can be later using M605. +#define DEFAULT_DUAL_X_CARRIAGE_MODE 0 + +// As the x-carriages are independent we can now account for any relative Z offset +#define EXTRUDER1_Z_OFFSET 0.0 // z offset relative to extruder 0 + +// Default settings in "Auto-park Mode" +#define TOOLCHANGE_PARK_ZLIFT 0.2 // the distance to raise Z axis when parking an extruder +#define TOOLCHANGE_UNPARK_ZLIFT 1 // the distance to raise Z axis when unparking an extruder + +// Default x offset in duplication mode (typically set to half print bed width) +#define DEFAULT_DUPLICATION_X_OFFSET 100 + +#endif //DUAL_X_CARRIAGE + //homing hits the endstop, then retracts by this distance, before it tries to slowly bump again: #define X_HOME_RETRACT_MM 5 #define Y_HOME_RETRACT_MM 5 @@ -174,6 +230,11 @@ #define DEFAULT_MINIMUMFEEDRATE 0.0 // minimum feedrate #define DEFAULT_MINTRAVELFEEDRATE 0.0 +// Feedrates for manual moves along X, Y, Z, E from panel +#ifdef ULTIPANEL +#define MANUAL_FEEDRATE {50*60, 50*60, 4*60, 60} // set the speeds for manual moves (mm/min) +#endif + // minimum time in microseconds that a movement needs to take if the buffer is emptied. #define DEFAULT_MINSEGMENTTIME 20000 diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index c9759eb219..3066017966 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -51,22 +51,22 @@ #define MYSERIAL MSerial #endif -#define SERIAL_PROTOCOL(x) MYSERIAL.print(x); -#define SERIAL_PROTOCOL_F(x,y) MYSERIAL.print(x,y); -#define SERIAL_PROTOCOLPGM(x) serialprintPGM(PSTR(x)); -#define SERIAL_PROTOCOLLN(x) {MYSERIAL.print(x);MYSERIAL.write('\n');} -#define SERIAL_PROTOCOLLNPGM(x) {serialprintPGM(PSTR(x));MYSERIAL.write('\n');} +#define SERIAL_PROTOCOL(x) (MYSERIAL.print(x)) +#define SERIAL_PROTOCOL_F(x,y) (MYSERIAL.print(x,y)) +#define SERIAL_PROTOCOLPGM(x) (serialprintPGM(PSTR(x))) +#define SERIAL_PROTOCOLLN(x) (MYSERIAL.print(x),MYSERIAL.write('\n')) +#define SERIAL_PROTOCOLLNPGM(x) (serialprintPGM(PSTR(x)),MYSERIAL.write('\n')) const char errormagic[] PROGMEM ="Error:"; const char echomagic[] PROGMEM ="echo:"; -#define SERIAL_ERROR_START serialprintPGM(errormagic); +#define SERIAL_ERROR_START (serialprintPGM(errormagic)) #define SERIAL_ERROR(x) SERIAL_PROTOCOL(x) #define SERIAL_ERRORPGM(x) SERIAL_PROTOCOLPGM(x) #define SERIAL_ERRORLN(x) SERIAL_PROTOCOLLN(x) #define SERIAL_ERRORLNPGM(x) SERIAL_PROTOCOLLNPGM(x) -#define SERIAL_ECHO_START serialprintPGM(echomagic); +#define SERIAL_ECHO_START (serialprintPGM(echomagic)) #define SERIAL_ECHO(x) SERIAL_PROTOCOL(x) #define SERIAL_ECHOPGM(x) SERIAL_PROTOCOLPGM(x) #define SERIAL_ECHOLN(x) SERIAL_PROTOCOLLN(x) @@ -96,7 +96,11 @@ void process_commands(); void manage_inactivity(); -#if defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1 +#if defined(DUAL_X_CARRIAGE) && defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1 \ + && defined(X2_ENABLE_PIN) && X2_ENABLE_PIN > -1 + #define enable_x() do { WRITE(X_ENABLE_PIN, X_ENABLE_ON); WRITE(X2_ENABLE_PIN, X_ENABLE_ON); } while (0) + #define disable_x() do { WRITE(X_ENABLE_PIN,!X_ENABLE_ON); WRITE(X2_ENABLE_PIN,!X_ENABLE_ON); } while (0) +#elif defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1 #define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) #define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON) #else @@ -105,8 +109,13 @@ void manage_inactivity(); #endif #if defined(Y_ENABLE_PIN) && Y_ENABLE_PIN > -1 - #define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON) - #define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON) + #ifdef Y_DUAL_STEPPER_DRIVERS + #define enable_y() { WRITE(Y_ENABLE_PIN, Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, Y_ENABLE_ON); } + #define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, !Y_ENABLE_ON); } + #else + #define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON) + #define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON) + #endif #else #define enable_y() ; #define disable_y() ; @@ -159,6 +168,7 @@ void ClearToSend(); void get_coordinates(); #ifdef DELTA void calculate_delta(float cartesian[3]); +extern float delta[3]; #endif void prepare_move(); void kill(); diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index a7991501e9..217030217a 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -48,8 +48,8 @@ block_t *current_block; // A pointer to the block currently being traced // Variables used by The Stepper Driver Interrupt static unsigned char out_bits; // The next stepping-bits to be output static long counter_x, // Counter variables for the bresenham line tracer - counter_y, - counter_z, + counter_y, + counter_z, counter_e; volatile static unsigned long step_events_completed; // The number of step events executed in the current block #ifdef ADVANCE @@ -224,27 +224,27 @@ void enable_endstops(bool check) // | BLOCK 1 | BLOCK 2 | d // // time -----> -// -// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates -// first block->accelerate_until step_events_completed, then keeps going at constant speed until +// +// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates +// first block->accelerate_until step_events_completed, then keeps going at constant speed until // step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset. // The slope of acceleration is calculated with the leib ramp alghorithm. void st_wake_up() { // TCNT1 = 0; - ENABLE_STEPPER_DRIVER_INTERRUPT(); + ENABLE_STEPPER_DRIVER_INTERRUPT(); } void step_wait(){ for(int8_t i=0; i < 6; i++){ } } - + FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) { unsigned short timer; if(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY; - + if(step_rate > 20000) { // If steprate > 20kHz >> step 4 times step_rate = (step_rate >> 2)&0x3fff; step_loops = 4; @@ -255,11 +255,11 @@ FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) { } else { step_loops = 1; - } - + } + if(step_rate < (F_CPU/500000)) step_rate = (F_CPU/500000); step_rate -= (F_CPU/500000); // Correct for minimal speed - if(step_rate >= (8*256)){ // higher step rate + if(step_rate >= (8*256)){ // higher step rate unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0]; unsigned char tmp_step_rate = (step_rate & 0x00ff); unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2); @@ -276,7 +276,7 @@ FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) { return timer; } -// Initializes the trapezoid generator from the current block. Called whenever a new +// Initializes the trapezoid generator from the current block. Called whenever a new // block begins. FORCE_INLINE void trapezoid_generator_reset() { #ifdef ADVANCE @@ -284,7 +284,7 @@ FORCE_INLINE void trapezoid_generator_reset() { final_advance = current_block->final_advance; // Do E steps + advance steps e_steps[current_block->active_extruder] += ((advance >>8) - old_advance); - old_advance = advance >>8; + old_advance = advance >>8; #endif deceleration_time = 0; // step_rate to timer interval @@ -294,7 +294,7 @@ FORCE_INLINE void trapezoid_generator_reset() { acc_step_rate = current_block->initial_rate; acceleration_time = calc_timer(acc_step_rate); OCR1A = acceleration_time; - + // SERIAL_ECHO_START; // SERIAL_ECHOPGM("advance :"); // SERIAL_ECHO(current_block->advance/256.0); @@ -304,13 +304,13 @@ FORCE_INLINE void trapezoid_generator_reset() { // SERIAL_ECHO(current_block->initial_advance/256.0); // SERIAL_ECHOPGM("final advance :"); // SERIAL_ECHOLN(current_block->final_advance/256.0); - + } -// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. -// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. +// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. +// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. ISR(TIMER1_COMPA_vect) -{ +{ // If there is no current block, attempt to pop one from the buffer if (current_block == NULL) { // Anything in the buffer? @@ -322,24 +322,24 @@ ISR(TIMER1_COMPA_vect) counter_y = counter_x; counter_z = counter_x; counter_e = counter_x; - step_events_completed = 0; - - #ifdef Z_LATE_ENABLE + step_events_completed = 0; + + #ifdef Z_LATE_ENABLE if(current_block->steps_z > 0) { enable_z(); OCR1A = 2000; //1ms wait return; } #endif - + // #ifdef ADVANCE // e_steps[current_block->active_extruder] = 0; // #endif - } + } else { OCR1A=2000; // 1kHz. - } - } + } + } if (current_block != NULL) { // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt @@ -348,22 +348,58 @@ ISR(TIMER1_COMPA_vect) // Set the direction bits (X_AXIS=A_AXIS and Y_AXIS=B_AXIS for COREXY) if((out_bits & (1<active_extruder != 0) + WRITE(X2_DIR_PIN, INVERT_X_DIR); + else + WRITE(X_DIR_PIN, INVERT_X_DIR); + } + #else + WRITE(X_DIR_PIN, INVERT_X_DIR); + #endif count_direction[X_AXIS]=-1; } else{ - WRITE(X_DIR_PIN, !INVERT_X_DIR); + #ifdef DUAL_X_CARRIAGE + if (extruder_duplication_enabled){ + WRITE(X_DIR_PIN, !INVERT_X_DIR); + WRITE(X2_DIR_PIN, !INVERT_X_DIR); + } + else{ + if (current_block->active_extruder != 0) + WRITE(X2_DIR_PIN, !INVERT_X_DIR); + else + WRITE(X_DIR_PIN, !INVERT_X_DIR); + } + #else + WRITE(X_DIR_PIN, !INVERT_X_DIR); + #endif count_direction[X_AXIS]=1; } if((out_bits & (1< -1 - bool x_min_endstop=(READ(X_MIN_PIN) != X_ENDSTOPS_INVERTING); - if(x_min_endstop && old_x_min_endstop && (current_block->steps_x > 0)) { - endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; - endstop_x_hit=true; - step_events_completed = current_block->step_event_count; - } - old_x_min_endstop = x_min_endstop; - #endif + #ifdef DUAL_X_CARRIAGE + // with 2 x-carriages, endstops are only checked in the homing direction for the active extruder + if ((current_block->active_extruder == 0 && X_HOME_DIR == -1) + || (current_block->active_extruder != 0 && X2_HOME_DIR == -1)) + #endif + { + #if defined(X_MIN_PIN) && X_MIN_PIN > -1 + bool x_min_endstop=(READ(X_MIN_PIN) != X_MIN_ENDSTOP_INVERTING); + if(x_min_endstop && old_x_min_endstop && (current_block->steps_x > 0)) { + endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; + endstop_x_hit=true; + step_events_completed = current_block->step_event_count; + } + old_x_min_endstop = x_min_endstop; + #endif + } } } else { // +direction - CHECK_ENDSTOPS + CHECK_ENDSTOPS { - #if defined(X_MAX_PIN) && X_MAX_PIN > -1 - bool x_max_endstop=(READ(X_MAX_PIN) != X_ENDSTOPS_INVERTING); - if(x_max_endstop && old_x_max_endstop && (current_block->steps_x > 0)){ - endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; - endstop_x_hit=true; - step_events_completed = current_block->step_event_count; - } - old_x_max_endstop = x_max_endstop; - #endif + #ifdef DUAL_X_CARRIAGE + // with 2 x-carriages, endstops are only checked in the homing direction for the active extruder + if ((current_block->active_extruder == 0 && X_HOME_DIR == 1) + || (current_block->active_extruder != 0 && X2_HOME_DIR == 1)) + #endif + { + #if defined(X_MAX_PIN) && X_MAX_PIN > -1 + bool x_max_endstop=(READ(X_MAX_PIN) != X_MAX_ENDSTOP_INVERTING); + if(x_max_endstop && old_x_max_endstop && (current_block->steps_x > 0)){ + endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; + endstop_x_hit=true; + step_events_completed = current_block->step_event_count; + } + old_x_max_endstop = x_max_endstop; + #endif + } } } @@ -406,7 +456,7 @@ ISR(TIMER1_COMPA_vect) CHECK_ENDSTOPS { #if defined(Y_MIN_PIN) && Y_MIN_PIN > -1 - bool y_min_endstop=(READ(Y_MIN_PIN) != Y_ENDSTOPS_INVERTING); + bool y_min_endstop=(READ(Y_MIN_PIN) != Y_MIN_ENDSTOP_INVERTING); if(y_min_endstop && old_y_min_endstop && (current_block->steps_y > 0)) { endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; endstop_y_hit=true; @@ -420,7 +470,7 @@ ISR(TIMER1_COMPA_vect) CHECK_ENDSTOPS { #if defined(Y_MAX_PIN) && Y_MAX_PIN > -1 - bool y_max_endstop=(READ(Y_MAX_PIN) != Y_ENDSTOPS_INVERTING); + bool y_max_endstop=(READ(Y_MAX_PIN) != Y_MAX_ENDSTOP_INVERTING); if(y_max_endstop && old_y_max_endstop && (current_block->steps_y > 0)){ endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; endstop_y_hit=true; @@ -434,15 +484,15 @@ ISR(TIMER1_COMPA_vect) if ((out_bits & (1< -1 - bool z_min_endstop=(READ(Z_MIN_PIN) != Z_ENDSTOPS_INVERTING); + bool z_min_endstop=(READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING); if(z_min_endstop && old_z_min_endstop && (current_block->steps_z > 0)) { endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; endstop_z_hit=true; @@ -455,7 +505,7 @@ ISR(TIMER1_COMPA_vect) else { // +direction WRITE(Z_DIR_PIN,!INVERT_Z_DIR); - #ifdef Z_DUAL_STEPPER_DRIVERS + #ifdef Z_DUAL_STEPPER_DRIVERS WRITE(Z2_DIR_PIN,!INVERT_Z_DIR); #endif @@ -463,7 +513,7 @@ ISR(TIMER1_COMPA_vect) CHECK_ENDSTOPS { #if defined(Z_MAX_PIN) && Z_MAX_PIN > -1 - bool z_max_endstop=(READ(Z_MAX_PIN) != Z_ENDSTOPS_INVERTING); + bool z_max_endstop=(READ(Z_MAX_PIN) != Z_MAX_ENDSTOP_INVERTING); if(z_max_endstop && old_z_max_endstop && (current_block->steps_z > 0)) { endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; endstop_z_hit=true; @@ -484,10 +534,10 @@ ISR(TIMER1_COMPA_vect) count_direction[E_AXIS]=1; } #endif //!ADVANCE - - - for(int8_t i=0; i < step_loops; i++) { // Take multiple steps per interrupt (For high speed moves) + + + for(int8_t i=0; i < step_loops; i++) { // Take multiple steps per interrupt (For high speed moves) #ifndef AT90USB MSerial.checkRx(); // Check for serial chars. #endif @@ -502,38 +552,73 @@ ISR(TIMER1_COMPA_vect) else { e_steps[current_block->active_extruder]++; } - } + } #endif //ADVANCE counter_x += current_block->steps_x; if (counter_x > 0) { + #ifdef DUAL_X_CARRIAGE + if (extruder_duplication_enabled){ + WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); + WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN); + } + else { + if (current_block->active_extruder != 0) + WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN); + else + WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); + } + #else WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); + #endif counter_x -= current_block->step_event_count; count_position[X_AXIS]+=count_direction[X_AXIS]; + #ifdef DUAL_X_CARRIAGE + if (extruder_duplication_enabled){ + WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); + WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN); + } + else { + if (current_block->active_extruder != 0) + WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN); + else + WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); + } + #else WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); + #endif } - + counter_y += current_block->steps_y; if (counter_y > 0) { WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN); - counter_y -= current_block->step_event_count; - count_position[Y_AXIS]+=count_direction[Y_AXIS]; + + #ifdef Y_DUAL_STEPPER_DRIVERS + WRITE(Y2_STEP_PIN, !INVERT_Y_STEP_PIN); + #endif + + counter_y -= current_block->step_event_count; + count_position[Y_AXIS]+=count_direction[Y_AXIS]; WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN); + + #ifdef Y_DUAL_STEPPER_DRIVERS + WRITE(Y2_STEP_PIN, INVERT_Y_STEP_PIN); + #endif } - + counter_z += current_block->steps_z; if (counter_z > 0) { WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); - #ifdef Z_DUAL_STEPPER_DRIVERS + #ifdef Z_DUAL_STEPPER_DRIVERS WRITE(Z2_STEP_PIN, !INVERT_Z_STEP_PIN); #endif - + counter_z -= current_block->step_event_count; count_position[Z_AXIS]+=count_direction[Z_AXIS]; WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN); - #ifdef Z_DUAL_STEPPER_DRIVERS + #ifdef Z_DUAL_STEPPER_DRIVERS WRITE(Z2_STEP_PIN, INVERT_Z_STEP_PIN); #endif } @@ -547,17 +632,17 @@ ISR(TIMER1_COMPA_vect) WRITE_E_STEP(INVERT_E_STEP_PIN); } #endif //!ADVANCE - step_events_completed += 1; + step_events_completed += 1; if(step_events_completed >= current_block->step_event_count) break; } // Calculare new timer value unsigned short timer; unsigned short step_rate; if (step_events_completed <= (unsigned long int)current_block->accelerate_until) { - + MultiU24X24toH16(acc_step_rate, acceleration_time, current_block->acceleration_rate); acc_step_rate += current_block->initial_rate; - + // upper limit if(acc_step_rate > current_block->nominal_rate) acc_step_rate = current_block->nominal_rate; @@ -573,13 +658,13 @@ ISR(TIMER1_COMPA_vect) //if(advance > current_block->advance) advance = current_block->advance; // Do E steps + advance steps e_steps[current_block->active_extruder] += ((advance >>8) - old_advance); - old_advance = advance >>8; - + old_advance = advance >>8; + #endif - } - else if (step_events_completed > (unsigned long int)current_block->decelerate_after) { + } + else if (step_events_completed > (unsigned long int)current_block->decelerate_after) { MultiU24X24toH16(step_rate, deceleration_time, current_block->acceleration_rate); - + if(step_rate > acc_step_rate) { // Check step_rate stays positive step_rate = current_block->final_rate; } @@ -602,7 +687,7 @@ ISR(TIMER1_COMPA_vect) if(advance < final_advance) advance = final_advance; // Do E steps + advance steps e_steps[current_block->active_extruder] += ((advance >>8) - old_advance); - old_advance = advance >>8; + old_advance = advance >>8; #endif //ADVANCE } else { @@ -611,12 +696,12 @@ ISR(TIMER1_COMPA_vect) step_loops = step_loops_nominal; } - // If current block is finished, reset pointer + // If current block is finished, reset pointer if (step_events_completed >= current_block->step_event_count) { current_block = NULL; plan_discard_current_block(); - } - } + } + } } #ifdef ADVANCE @@ -635,7 +720,7 @@ ISR(TIMER1_COMPA_vect) WRITE(E0_DIR_PIN, INVERT_E0_DIR); e_steps[0]++; WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); - } + } else if (e_steps[0] > 0) { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); e_steps[0]--; @@ -649,7 +734,7 @@ ISR(TIMER1_COMPA_vect) WRITE(E1_DIR_PIN, INVERT_E1_DIR); e_steps[1]++; WRITE(E1_STEP_PIN, !INVERT_E_STEP_PIN); - } + } else if (e_steps[1] > 0) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); e_steps[1]--; @@ -664,7 +749,7 @@ ISR(TIMER1_COMPA_vect) WRITE(E2_DIR_PIN, INVERT_E2_DIR); e_steps[2]++; WRITE(E2_STEP_PIN, !INVERT_E_STEP_PIN); - } + } else if (e_steps[2] > 0) { WRITE(E2_DIR_PIN, !INVERT_E2_DIR); e_steps[2]--; @@ -680,22 +765,29 @@ void st_init() { digipot_init(); //Initialize Digipot Motor Current microstep_init(); //Initialize Microstepping Pins - + //Initialize Dir Pins #if defined(X_DIR_PIN) && X_DIR_PIN > -1 SET_OUTPUT(X_DIR_PIN); #endif - #if defined(Y_DIR_PIN) && Y_DIR_PIN > -1 + #if defined(X2_DIR_PIN) && X2_DIR_PIN > -1 + SET_OUTPUT(X2_DIR_PIN); + #endif + #if defined(Y_DIR_PIN) && Y_DIR_PIN > -1 SET_OUTPUT(Y_DIR_PIN); + + #if defined(Y_DUAL_STEPPER_DRIVERS) && defined(Y2_DIR_PIN) && (Y2_DIR_PIN > -1) + SET_OUTPUT(Y2_DIR_PIN); + #endif #endif - #if defined(Z_DIR_PIN) && Z_DIR_PIN > -1 + #if defined(Z_DIR_PIN) && Z_DIR_PIN > -1 SET_OUTPUT(Z_DIR_PIN); #if defined(Z_DUAL_STEPPER_DRIVERS) && defined(Z2_DIR_PIN) && (Z2_DIR_PIN > -1) SET_OUTPUT(Z2_DIR_PIN); #endif #endif - #if defined(E0_DIR_PIN) && E0_DIR_PIN > -1 + #if defined(E0_DIR_PIN) && E0_DIR_PIN > -1 SET_OUTPUT(E0_DIR_PIN); #endif #if defined(E1_DIR_PIN) && (E1_DIR_PIN > -1) @@ -711,14 +803,23 @@ void st_init() SET_OUTPUT(X_ENABLE_PIN); if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH); #endif + #if defined(X2_ENABLE_PIN) && X2_ENABLE_PIN > -1 + SET_OUTPUT(X2_ENABLE_PIN); + if(!X_ENABLE_ON) WRITE(X2_ENABLE_PIN,HIGH); + #endif #if defined(Y_ENABLE_PIN) && Y_ENABLE_PIN > -1 SET_OUTPUT(Y_ENABLE_PIN); if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH); + + #if defined(Y_DUAL_STEPPER_DRIVERS) && defined(Y2_ENABLE_PIN) && (Y2_ENABLE_PIN > -1) + SET_OUTPUT(Y2_ENABLE_PIN); + if(!Y_ENABLE_ON) WRITE(Y2_ENABLE_PIN,HIGH); + #endif #endif #if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1 SET_OUTPUT(Z_ENABLE_PIN); if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH); - + #if defined(Z_DUAL_STEPPER_DRIVERS) && defined(Z2_ENABLE_PIN) && (Z2_ENABLE_PIN > -1) SET_OUTPUT(Z2_ENABLE_PIN); if(!Z_ENABLE_ON) WRITE(Z2_ENABLE_PIN,HIGH); @@ -738,62 +839,71 @@ void st_init() #endif //endstops and pullups - + #if defined(X_MIN_PIN) && X_MIN_PIN > -1 - SET_INPUT(X_MIN_PIN); + SET_INPUT(X_MIN_PIN); #ifdef ENDSTOPPULLUP_XMIN WRITE(X_MIN_PIN,HIGH); #endif #endif - + #if defined(Y_MIN_PIN) && Y_MIN_PIN > -1 - SET_INPUT(Y_MIN_PIN); + SET_INPUT(Y_MIN_PIN); #ifdef ENDSTOPPULLUP_YMIN WRITE(Y_MIN_PIN,HIGH); #endif #endif - + #if defined(Z_MIN_PIN) && Z_MIN_PIN > -1 - SET_INPUT(Z_MIN_PIN); + SET_INPUT(Z_MIN_PIN); #ifdef ENDSTOPPULLUP_ZMIN WRITE(Z_MIN_PIN,HIGH); #endif #endif - + #if defined(X_MAX_PIN) && X_MAX_PIN > -1 - SET_INPUT(X_MAX_PIN); + SET_INPUT(X_MAX_PIN); #ifdef ENDSTOPPULLUP_XMAX WRITE(X_MAX_PIN,HIGH); #endif #endif - + #if defined(Y_MAX_PIN) && Y_MAX_PIN > -1 - SET_INPUT(Y_MAX_PIN); + SET_INPUT(Y_MAX_PIN); #ifdef ENDSTOPPULLUP_YMAX WRITE(Y_MAX_PIN,HIGH); #endif #endif - + #if defined(Z_MAX_PIN) && Z_MAX_PIN > -1 - SET_INPUT(Z_MAX_PIN); + SET_INPUT(Z_MAX_PIN); #ifdef ENDSTOPPULLUP_ZMAX WRITE(Z_MAX_PIN,HIGH); #endif #endif - + //Initialize Step Pins - #if defined(X_STEP_PIN) && (X_STEP_PIN > -1) + #if defined(X_STEP_PIN) && (X_STEP_PIN > -1) SET_OUTPUT(X_STEP_PIN); WRITE(X_STEP_PIN,INVERT_X_STEP_PIN); disable_x(); - #endif - #if defined(Y_STEP_PIN) && (Y_STEP_PIN > -1) + #endif + #if defined(X2_STEP_PIN) && (X2_STEP_PIN > -1) + SET_OUTPUT(X2_STEP_PIN); + WRITE(X2_STEP_PIN,INVERT_X_STEP_PIN); + disable_x(); + #endif + #if defined(Y_STEP_PIN) && (Y_STEP_PIN > -1) SET_OUTPUT(Y_STEP_PIN); WRITE(Y_STEP_PIN,INVERT_Y_STEP_PIN); + #if defined(Y_DUAL_STEPPER_DRIVERS) && defined(Y2_STEP_PIN) && (Y2_STEP_PIN > -1) + SET_OUTPUT(Y2_STEP_PIN); + WRITE(Y2_STEP_PIN,INVERT_Y_STEP_PIN); + #endif disable_y(); - #endif - #if defined(Z_STEP_PIN) && (Z_STEP_PIN > -1) + #endif + #if defined(Z_STEP_PIN) && (Z_STEP_PIN > -1) SET_OUTPUT(Z_STEP_PIN); WRITE(Z_STEP_PIN,INVERT_Z_STEP_PIN); #if defined(Z_DUAL_STEPPER_DRIVERS) && defined(Z2_STEP_PIN) && (Z2_STEP_PIN > -1) @@ -801,33 +911,33 @@ void st_init() WRITE(Z2_STEP_PIN,INVERT_Z_STEP_PIN); #endif disable_z(); - #endif - #if defined(E0_STEP_PIN) && (E0_STEP_PIN > -1) + #endif + #if defined(E0_STEP_PIN) && (E0_STEP_PIN > -1) SET_OUTPUT(E0_STEP_PIN); WRITE(E0_STEP_PIN,INVERT_E_STEP_PIN); disable_e0(); - #endif - #if defined(E1_STEP_PIN) && (E1_STEP_PIN > -1) + #endif + #if defined(E1_STEP_PIN) && (E1_STEP_PIN > -1) SET_OUTPUT(E1_STEP_PIN); WRITE(E1_STEP_PIN,INVERT_E_STEP_PIN); disable_e1(); - #endif - #if defined(E2_STEP_PIN) && (E2_STEP_PIN > -1) + #endif + #if defined(E2_STEP_PIN) && (E2_STEP_PIN > -1) SET_OUTPUT(E2_STEP_PIN); WRITE(E2_STEP_PIN,INVERT_E_STEP_PIN); disable_e2(); - #endif + #endif // waveform generation = 0100 = CTC TCCR1B &= ~(1< -1 const uint8_t digipot_motor_current[] = DIGIPOT_MOTOR_CURRENT; - - SPI.begin(); - pinMode(DIGIPOTSS_PIN, OUTPUT); - for(int i=0;i<=4;i++) + + SPI.begin(); + pinMode(DIGIPOTSS_PIN, OUTPUT); + for(int i=0;i<=4;i++) //digitalPotWrite(digipot_ch[i], digipot_motor_current[i]); digipot_current(i,digipot_motor_current[i]); #endif From f4a59e4ce5987fafb1a4e849bc7fbcbb8d3bc920 Mon Sep 17 00:00:00 2001 From: Richard Miles Date: Tue, 17 Sep 2013 19:05:49 +0100 Subject: [PATCH 042/256] Revert "Added Y_DUAL_STEPPER_DRIVERS" This reverts commit 7ee275b620fa055bb2b7516cf302ac3e531438ac. --- Marlin/Configuration_adv.h | 73 +------- Marlin/Marlin.h | 30 +-- Marlin/stepper.cpp | 366 +++++++++++++------------------------ 3 files changed, 144 insertions(+), 325 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 648a9beafc..5f1c77a056 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -18,6 +18,12 @@ //#define WATCH_TEMP_PERIOD 40000 //40 seconds //#define WATCH_TEMP_INCREASE 10 //Heat up at least 10 degree in 20 seconds +// Wait for Cooldown +// This defines if the M109 call should not block if it is cooling down. +// example: From a current temp of 220, you set M109 S200. +// if CooldownNoWait is defined M109 will not wait for the cooldown to finish +#define CooldownNoWait true + #ifdef PIDTEMP // this adds an experimental additional term to the heatingpower, proportional to the extrusion speed. // if Kc is choosen well, the additional required power due to increased melting should be compensated. @@ -146,68 +152,6 @@ #define EXTRUDERS 1 #endif -// Same again but for Y Axis. -#define Y_DUAL_STEPPER_DRIVERS - -// Define if the two Y drives need to rotate in opposite directions -#define INVERT_Y2_VS_Y_DIR true - -#ifdef Y_DUAL_STEPPER_DRIVERS - #undef EXTRUDERS - #define EXTRUDERS 1 -#endif - -#ifdef Z_DUAL_STEPPER_DRIVERS && Y_DUAL_STEPPER_DRIVERS - #error "You cannot have dual drivers for both Y and Z" -#endif - -// Enable this for dual x-carriage printers. -// A dual x-carriage design has the advantage that the inactive extruder can be parked which -// prevents hot-end ooze contaminating the print. It also reduces the weight of each x-carriage -// allowing faster printing speeds. -//#define DUAL_X_CARRIAGE -#ifdef DUAL_X_CARRIAGE -// Configuration for second X-carriage -// Note: the first x-carriage is defined as the x-carriage which homes to the minimum endstop; -// the second x-carriage always homes to the maximum endstop. -#define X2_MIN_POS 80 // set minimum to ensure second x-carriage doesn't hit the parked first X-carriage -#define X2_MAX_POS 353 // set maximum to the distance between toolheads when both heads are homed -#define X2_HOME_DIR 1 // the second X-carriage always homes to the maximum endstop position -#define X2_HOME_POS X2_MAX_POS // default home position is the maximum carriage position - // However: In this mode the EXTRUDER_OFFSET_X value for the second extruder provides a software - // override for X2_HOME_POS. This also allow recalibration of the distance between the two endstops - // without modifying the firmware (through the "M218 T1 X???" command). - // Remember: you should set the second extruder x-offset to 0 in your slicer. - -// Pins for second x-carriage stepper driver (defined here to avoid further complicating pins.h) -#define X2_ENABLE_PIN 29 -#define X2_STEP_PIN 25 -#define X2_DIR_PIN 23 - -// There are a few selectable movement modes for dual x-carriages using M605 S -// Mode 0: Full control. The slicer has full control over both x-carriages and can achieve optimal travel results -// as long as it supports dual x-carriages. (M605 S0) -// Mode 1: Auto-park mode. The firmware will automatically park and unpark the x-carriages on tool changes so -// that additional slicer support is not required. (M605 S1) -// Mode 2: Duplication mode. The firmware will transparently make the second x-carriage and extruder copy all -// actions of the first x-carriage. This allows the printer to print 2 arbitrary items at -// once. (2nd extruder x offset and temp offset are set using: M605 S2 [Xnnn] [Rmmm]) - -// This is the default power-up mode which can be later using M605. -#define DEFAULT_DUAL_X_CARRIAGE_MODE 0 - -// As the x-carriages are independent we can now account for any relative Z offset -#define EXTRUDER1_Z_OFFSET 0.0 // z offset relative to extruder 0 - -// Default settings in "Auto-park Mode" -#define TOOLCHANGE_PARK_ZLIFT 0.2 // the distance to raise Z axis when parking an extruder -#define TOOLCHANGE_UNPARK_ZLIFT 1 // the distance to raise Z axis when unparking an extruder - -// Default x offset in duplication mode (typically set to half print bed width) -#define DEFAULT_DUPLICATION_X_OFFSET 100 - -#endif //DUAL_X_CARRIAGE - //homing hits the endstop, then retracts by this distance, before it tries to slowly bump again: #define X_HOME_RETRACT_MM 5 #define Y_HOME_RETRACT_MM 5 @@ -230,11 +174,6 @@ #define DEFAULT_MINIMUMFEEDRATE 0.0 // minimum feedrate #define DEFAULT_MINTRAVELFEEDRATE 0.0 -// Feedrates for manual moves along X, Y, Z, E from panel -#ifdef ULTIPANEL -#define MANUAL_FEEDRATE {50*60, 50*60, 4*60, 60} // set the speeds for manual moves (mm/min) -#endif - // minimum time in microseconds that a movement needs to take if the buffer is emptied. #define DEFAULT_MINSEGMENTTIME 20000 diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index 3066017966..c9759eb219 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -51,22 +51,22 @@ #define MYSERIAL MSerial #endif -#define SERIAL_PROTOCOL(x) (MYSERIAL.print(x)) -#define SERIAL_PROTOCOL_F(x,y) (MYSERIAL.print(x,y)) -#define SERIAL_PROTOCOLPGM(x) (serialprintPGM(PSTR(x))) -#define SERIAL_PROTOCOLLN(x) (MYSERIAL.print(x),MYSERIAL.write('\n')) -#define SERIAL_PROTOCOLLNPGM(x) (serialprintPGM(PSTR(x)),MYSERIAL.write('\n')) +#define SERIAL_PROTOCOL(x) MYSERIAL.print(x); +#define SERIAL_PROTOCOL_F(x,y) MYSERIAL.print(x,y); +#define SERIAL_PROTOCOLPGM(x) serialprintPGM(PSTR(x)); +#define SERIAL_PROTOCOLLN(x) {MYSERIAL.print(x);MYSERIAL.write('\n');} +#define SERIAL_PROTOCOLLNPGM(x) {serialprintPGM(PSTR(x));MYSERIAL.write('\n');} const char errormagic[] PROGMEM ="Error:"; const char echomagic[] PROGMEM ="echo:"; -#define SERIAL_ERROR_START (serialprintPGM(errormagic)) +#define SERIAL_ERROR_START serialprintPGM(errormagic); #define SERIAL_ERROR(x) SERIAL_PROTOCOL(x) #define SERIAL_ERRORPGM(x) SERIAL_PROTOCOLPGM(x) #define SERIAL_ERRORLN(x) SERIAL_PROTOCOLLN(x) #define SERIAL_ERRORLNPGM(x) SERIAL_PROTOCOLLNPGM(x) -#define SERIAL_ECHO_START (serialprintPGM(echomagic)) +#define SERIAL_ECHO_START serialprintPGM(echomagic); #define SERIAL_ECHO(x) SERIAL_PROTOCOL(x) #define SERIAL_ECHOPGM(x) SERIAL_PROTOCOLPGM(x) #define SERIAL_ECHOLN(x) SERIAL_PROTOCOLLN(x) @@ -96,11 +96,7 @@ void process_commands(); void manage_inactivity(); -#if defined(DUAL_X_CARRIAGE) && defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1 \ - && defined(X2_ENABLE_PIN) && X2_ENABLE_PIN > -1 - #define enable_x() do { WRITE(X_ENABLE_PIN, X_ENABLE_ON); WRITE(X2_ENABLE_PIN, X_ENABLE_ON); } while (0) - #define disable_x() do { WRITE(X_ENABLE_PIN,!X_ENABLE_ON); WRITE(X2_ENABLE_PIN,!X_ENABLE_ON); } while (0) -#elif defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1 +#if defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1 #define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) #define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON) #else @@ -109,13 +105,8 @@ void manage_inactivity(); #endif #if defined(Y_ENABLE_PIN) && Y_ENABLE_PIN > -1 - #ifdef Y_DUAL_STEPPER_DRIVERS - #define enable_y() { WRITE(Y_ENABLE_PIN, Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, Y_ENABLE_ON); } - #define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, !Y_ENABLE_ON); } - #else - #define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON) - #define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON) - #endif + #define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON) + #define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON) #else #define enable_y() ; #define disable_y() ; @@ -168,7 +159,6 @@ void ClearToSend(); void get_coordinates(); #ifdef DELTA void calculate_delta(float cartesian[3]); -extern float delta[3]; #endif void prepare_move(); void kill(); diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index 217030217a..a7991501e9 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -48,8 +48,8 @@ block_t *current_block; // A pointer to the block currently being traced // Variables used by The Stepper Driver Interrupt static unsigned char out_bits; // The next stepping-bits to be output static long counter_x, // Counter variables for the bresenham line tracer - counter_y, - counter_z, + counter_y, + counter_z, counter_e; volatile static unsigned long step_events_completed; // The number of step events executed in the current block #ifdef ADVANCE @@ -224,27 +224,27 @@ void enable_endstops(bool check) // | BLOCK 1 | BLOCK 2 | d // // time -----> -// -// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates -// first block->accelerate_until step_events_completed, then keeps going at constant speed until +// +// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates +// first block->accelerate_until step_events_completed, then keeps going at constant speed until // step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset. // The slope of acceleration is calculated with the leib ramp alghorithm. void st_wake_up() { // TCNT1 = 0; - ENABLE_STEPPER_DRIVER_INTERRUPT(); + ENABLE_STEPPER_DRIVER_INTERRUPT(); } void step_wait(){ for(int8_t i=0; i < 6; i++){ } } - + FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) { unsigned short timer; if(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY; - + if(step_rate > 20000) { // If steprate > 20kHz >> step 4 times step_rate = (step_rate >> 2)&0x3fff; step_loops = 4; @@ -255,11 +255,11 @@ FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) { } else { step_loops = 1; - } - + } + if(step_rate < (F_CPU/500000)) step_rate = (F_CPU/500000); step_rate -= (F_CPU/500000); // Correct for minimal speed - if(step_rate >= (8*256)){ // higher step rate + if(step_rate >= (8*256)){ // higher step rate unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0]; unsigned char tmp_step_rate = (step_rate & 0x00ff); unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2); @@ -276,7 +276,7 @@ FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) { return timer; } -// Initializes the trapezoid generator from the current block. Called whenever a new +// Initializes the trapezoid generator from the current block. Called whenever a new // block begins. FORCE_INLINE void trapezoid_generator_reset() { #ifdef ADVANCE @@ -284,7 +284,7 @@ FORCE_INLINE void trapezoid_generator_reset() { final_advance = current_block->final_advance; // Do E steps + advance steps e_steps[current_block->active_extruder] += ((advance >>8) - old_advance); - old_advance = advance >>8; + old_advance = advance >>8; #endif deceleration_time = 0; // step_rate to timer interval @@ -294,7 +294,7 @@ FORCE_INLINE void trapezoid_generator_reset() { acc_step_rate = current_block->initial_rate; acceleration_time = calc_timer(acc_step_rate); OCR1A = acceleration_time; - + // SERIAL_ECHO_START; // SERIAL_ECHOPGM("advance :"); // SERIAL_ECHO(current_block->advance/256.0); @@ -304,13 +304,13 @@ FORCE_INLINE void trapezoid_generator_reset() { // SERIAL_ECHO(current_block->initial_advance/256.0); // SERIAL_ECHOPGM("final advance :"); // SERIAL_ECHOLN(current_block->final_advance/256.0); - + } -// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. -// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. +// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. +// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. ISR(TIMER1_COMPA_vect) -{ +{ // If there is no current block, attempt to pop one from the buffer if (current_block == NULL) { // Anything in the buffer? @@ -322,24 +322,24 @@ ISR(TIMER1_COMPA_vect) counter_y = counter_x; counter_z = counter_x; counter_e = counter_x; - step_events_completed = 0; - - #ifdef Z_LATE_ENABLE + step_events_completed = 0; + + #ifdef Z_LATE_ENABLE if(current_block->steps_z > 0) { enable_z(); OCR1A = 2000; //1ms wait return; } #endif - + // #ifdef ADVANCE // e_steps[current_block->active_extruder] = 0; // #endif - } + } else { OCR1A=2000; // 1kHz. - } - } + } + } if (current_block != NULL) { // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt @@ -348,58 +348,22 @@ ISR(TIMER1_COMPA_vect) // Set the direction bits (X_AXIS=A_AXIS and Y_AXIS=B_AXIS for COREXY) if((out_bits & (1<active_extruder != 0) - WRITE(X2_DIR_PIN, INVERT_X_DIR); - else - WRITE(X_DIR_PIN, INVERT_X_DIR); - } - #else - WRITE(X_DIR_PIN, INVERT_X_DIR); - #endif + WRITE(X_DIR_PIN, INVERT_X_DIR); count_direction[X_AXIS]=-1; } else{ - #ifdef DUAL_X_CARRIAGE - if (extruder_duplication_enabled){ - WRITE(X_DIR_PIN, !INVERT_X_DIR); - WRITE(X2_DIR_PIN, !INVERT_X_DIR); - } - else{ - if (current_block->active_extruder != 0) - WRITE(X2_DIR_PIN, !INVERT_X_DIR); - else - WRITE(X_DIR_PIN, !INVERT_X_DIR); - } - #else - WRITE(X_DIR_PIN, !INVERT_X_DIR); - #endif + WRITE(X_DIR_PIN, !INVERT_X_DIR); count_direction[X_AXIS]=1; } if((out_bits & (1<active_extruder == 0 && X_HOME_DIR == -1) - || (current_block->active_extruder != 0 && X2_HOME_DIR == -1)) - #endif - { - #if defined(X_MIN_PIN) && X_MIN_PIN > -1 - bool x_min_endstop=(READ(X_MIN_PIN) != X_MIN_ENDSTOP_INVERTING); - if(x_min_endstop && old_x_min_endstop && (current_block->steps_x > 0)) { - endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; - endstop_x_hit=true; - step_events_completed = current_block->step_event_count; - } - old_x_min_endstop = x_min_endstop; - #endif - } + #if defined(X_MIN_PIN) && X_MIN_PIN > -1 + bool x_min_endstop=(READ(X_MIN_PIN) != X_ENDSTOPS_INVERTING); + if(x_min_endstop && old_x_min_endstop && (current_block->steps_x > 0)) { + endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; + endstop_x_hit=true; + step_events_completed = current_block->step_event_count; + } + old_x_min_endstop = x_min_endstop; + #endif } } else { // +direction - CHECK_ENDSTOPS + CHECK_ENDSTOPS { - #ifdef DUAL_X_CARRIAGE - // with 2 x-carriages, endstops are only checked in the homing direction for the active extruder - if ((current_block->active_extruder == 0 && X_HOME_DIR == 1) - || (current_block->active_extruder != 0 && X2_HOME_DIR == 1)) - #endif - { - #if defined(X_MAX_PIN) && X_MAX_PIN > -1 - bool x_max_endstop=(READ(X_MAX_PIN) != X_MAX_ENDSTOP_INVERTING); - if(x_max_endstop && old_x_max_endstop && (current_block->steps_x > 0)){ - endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; - endstop_x_hit=true; - step_events_completed = current_block->step_event_count; - } - old_x_max_endstop = x_max_endstop; - #endif - } + #if defined(X_MAX_PIN) && X_MAX_PIN > -1 + bool x_max_endstop=(READ(X_MAX_PIN) != X_ENDSTOPS_INVERTING); + if(x_max_endstop && old_x_max_endstop && (current_block->steps_x > 0)){ + endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; + endstop_x_hit=true; + step_events_completed = current_block->step_event_count; + } + old_x_max_endstop = x_max_endstop; + #endif } } @@ -456,7 +406,7 @@ ISR(TIMER1_COMPA_vect) CHECK_ENDSTOPS { #if defined(Y_MIN_PIN) && Y_MIN_PIN > -1 - bool y_min_endstop=(READ(Y_MIN_PIN) != Y_MIN_ENDSTOP_INVERTING); + bool y_min_endstop=(READ(Y_MIN_PIN) != Y_ENDSTOPS_INVERTING); if(y_min_endstop && old_y_min_endstop && (current_block->steps_y > 0)) { endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; endstop_y_hit=true; @@ -470,7 +420,7 @@ ISR(TIMER1_COMPA_vect) CHECK_ENDSTOPS { #if defined(Y_MAX_PIN) && Y_MAX_PIN > -1 - bool y_max_endstop=(READ(Y_MAX_PIN) != Y_MAX_ENDSTOP_INVERTING); + bool y_max_endstop=(READ(Y_MAX_PIN) != Y_ENDSTOPS_INVERTING); if(y_max_endstop && old_y_max_endstop && (current_block->steps_y > 0)){ endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; endstop_y_hit=true; @@ -484,15 +434,15 @@ ISR(TIMER1_COMPA_vect) if ((out_bits & (1< -1 - bool z_min_endstop=(READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING); + bool z_min_endstop=(READ(Z_MIN_PIN) != Z_ENDSTOPS_INVERTING); if(z_min_endstop && old_z_min_endstop && (current_block->steps_z > 0)) { endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; endstop_z_hit=true; @@ -505,7 +455,7 @@ ISR(TIMER1_COMPA_vect) else { // +direction WRITE(Z_DIR_PIN,!INVERT_Z_DIR); - #ifdef Z_DUAL_STEPPER_DRIVERS + #ifdef Z_DUAL_STEPPER_DRIVERS WRITE(Z2_DIR_PIN,!INVERT_Z_DIR); #endif @@ -513,7 +463,7 @@ ISR(TIMER1_COMPA_vect) CHECK_ENDSTOPS { #if defined(Z_MAX_PIN) && Z_MAX_PIN > -1 - bool z_max_endstop=(READ(Z_MAX_PIN) != Z_MAX_ENDSTOP_INVERTING); + bool z_max_endstop=(READ(Z_MAX_PIN) != Z_ENDSTOPS_INVERTING); if(z_max_endstop && old_z_max_endstop && (current_block->steps_z > 0)) { endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; endstop_z_hit=true; @@ -534,10 +484,10 @@ ISR(TIMER1_COMPA_vect) count_direction[E_AXIS]=1; } #endif //!ADVANCE + - - - for(int8_t i=0; i < step_loops; i++) { // Take multiple steps per interrupt (For high speed moves) + + for(int8_t i=0; i < step_loops; i++) { // Take multiple steps per interrupt (For high speed moves) #ifndef AT90USB MSerial.checkRx(); // Check for serial chars. #endif @@ -552,73 +502,38 @@ ISR(TIMER1_COMPA_vect) else { e_steps[current_block->active_extruder]++; } - } + } #endif //ADVANCE counter_x += current_block->steps_x; if (counter_x > 0) { - #ifdef DUAL_X_CARRIAGE - if (extruder_duplication_enabled){ - WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); - WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN); - } - else { - if (current_block->active_extruder != 0) - WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN); - else - WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); - } - #else WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); - #endif counter_x -= current_block->step_event_count; count_position[X_AXIS]+=count_direction[X_AXIS]; - #ifdef DUAL_X_CARRIAGE - if (extruder_duplication_enabled){ - WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); - WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN); - } - else { - if (current_block->active_extruder != 0) - WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN); - else - WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); - } - #else WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); - #endif } - + counter_y += current_block->steps_y; if (counter_y > 0) { WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN); - - #ifdef Y_DUAL_STEPPER_DRIVERS - WRITE(Y2_STEP_PIN, !INVERT_Y_STEP_PIN); - #endif - - counter_y -= current_block->step_event_count; - count_position[Y_AXIS]+=count_direction[Y_AXIS]; + counter_y -= current_block->step_event_count; + count_position[Y_AXIS]+=count_direction[Y_AXIS]; WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN); - - #ifdef Y_DUAL_STEPPER_DRIVERS - WRITE(Y2_STEP_PIN, INVERT_Y_STEP_PIN); - #endif } - + counter_z += current_block->steps_z; if (counter_z > 0) { WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); - #ifdef Z_DUAL_STEPPER_DRIVERS + #ifdef Z_DUAL_STEPPER_DRIVERS WRITE(Z2_STEP_PIN, !INVERT_Z_STEP_PIN); #endif - + counter_z -= current_block->step_event_count; count_position[Z_AXIS]+=count_direction[Z_AXIS]; WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN); - #ifdef Z_DUAL_STEPPER_DRIVERS + #ifdef Z_DUAL_STEPPER_DRIVERS WRITE(Z2_STEP_PIN, INVERT_Z_STEP_PIN); #endif } @@ -632,17 +547,17 @@ ISR(TIMER1_COMPA_vect) WRITE_E_STEP(INVERT_E_STEP_PIN); } #endif //!ADVANCE - step_events_completed += 1; + step_events_completed += 1; if(step_events_completed >= current_block->step_event_count) break; } // Calculare new timer value unsigned short timer; unsigned short step_rate; if (step_events_completed <= (unsigned long int)current_block->accelerate_until) { - + MultiU24X24toH16(acc_step_rate, acceleration_time, current_block->acceleration_rate); acc_step_rate += current_block->initial_rate; - + // upper limit if(acc_step_rate > current_block->nominal_rate) acc_step_rate = current_block->nominal_rate; @@ -658,13 +573,13 @@ ISR(TIMER1_COMPA_vect) //if(advance > current_block->advance) advance = current_block->advance; // Do E steps + advance steps e_steps[current_block->active_extruder] += ((advance >>8) - old_advance); - old_advance = advance >>8; - + old_advance = advance >>8; + #endif - } - else if (step_events_completed > (unsigned long int)current_block->decelerate_after) { + } + else if (step_events_completed > (unsigned long int)current_block->decelerate_after) { MultiU24X24toH16(step_rate, deceleration_time, current_block->acceleration_rate); - + if(step_rate > acc_step_rate) { // Check step_rate stays positive step_rate = current_block->final_rate; } @@ -687,7 +602,7 @@ ISR(TIMER1_COMPA_vect) if(advance < final_advance) advance = final_advance; // Do E steps + advance steps e_steps[current_block->active_extruder] += ((advance >>8) - old_advance); - old_advance = advance >>8; + old_advance = advance >>8; #endif //ADVANCE } else { @@ -696,12 +611,12 @@ ISR(TIMER1_COMPA_vect) step_loops = step_loops_nominal; } - // If current block is finished, reset pointer + // If current block is finished, reset pointer if (step_events_completed >= current_block->step_event_count) { current_block = NULL; plan_discard_current_block(); - } - } + } + } } #ifdef ADVANCE @@ -720,7 +635,7 @@ ISR(TIMER1_COMPA_vect) WRITE(E0_DIR_PIN, INVERT_E0_DIR); e_steps[0]++; WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); - } + } else if (e_steps[0] > 0) { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); e_steps[0]--; @@ -734,7 +649,7 @@ ISR(TIMER1_COMPA_vect) WRITE(E1_DIR_PIN, INVERT_E1_DIR); e_steps[1]++; WRITE(E1_STEP_PIN, !INVERT_E_STEP_PIN); - } + } else if (e_steps[1] > 0) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); e_steps[1]--; @@ -749,7 +664,7 @@ ISR(TIMER1_COMPA_vect) WRITE(E2_DIR_PIN, INVERT_E2_DIR); e_steps[2]++; WRITE(E2_STEP_PIN, !INVERT_E_STEP_PIN); - } + } else if (e_steps[2] > 0) { WRITE(E2_DIR_PIN, !INVERT_E2_DIR); e_steps[2]--; @@ -765,29 +680,22 @@ void st_init() { digipot_init(); //Initialize Digipot Motor Current microstep_init(); //Initialize Microstepping Pins - + //Initialize Dir Pins #if defined(X_DIR_PIN) && X_DIR_PIN > -1 SET_OUTPUT(X_DIR_PIN); #endif - #if defined(X2_DIR_PIN) && X2_DIR_PIN > -1 - SET_OUTPUT(X2_DIR_PIN); - #endif - #if defined(Y_DIR_PIN) && Y_DIR_PIN > -1 + #if defined(Y_DIR_PIN) && Y_DIR_PIN > -1 SET_OUTPUT(Y_DIR_PIN); - - #if defined(Y_DUAL_STEPPER_DRIVERS) && defined(Y2_DIR_PIN) && (Y2_DIR_PIN > -1) - SET_OUTPUT(Y2_DIR_PIN); - #endif #endif - #if defined(Z_DIR_PIN) && Z_DIR_PIN > -1 + #if defined(Z_DIR_PIN) && Z_DIR_PIN > -1 SET_OUTPUT(Z_DIR_PIN); #if defined(Z_DUAL_STEPPER_DRIVERS) && defined(Z2_DIR_PIN) && (Z2_DIR_PIN > -1) SET_OUTPUT(Z2_DIR_PIN); #endif #endif - #if defined(E0_DIR_PIN) && E0_DIR_PIN > -1 + #if defined(E0_DIR_PIN) && E0_DIR_PIN > -1 SET_OUTPUT(E0_DIR_PIN); #endif #if defined(E1_DIR_PIN) && (E1_DIR_PIN > -1) @@ -803,23 +711,14 @@ void st_init() SET_OUTPUT(X_ENABLE_PIN); if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH); #endif - #if defined(X2_ENABLE_PIN) && X2_ENABLE_PIN > -1 - SET_OUTPUT(X2_ENABLE_PIN); - if(!X_ENABLE_ON) WRITE(X2_ENABLE_PIN,HIGH); - #endif #if defined(Y_ENABLE_PIN) && Y_ENABLE_PIN > -1 SET_OUTPUT(Y_ENABLE_PIN); if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH); - - #if defined(Y_DUAL_STEPPER_DRIVERS) && defined(Y2_ENABLE_PIN) && (Y2_ENABLE_PIN > -1) - SET_OUTPUT(Y2_ENABLE_PIN); - if(!Y_ENABLE_ON) WRITE(Y2_ENABLE_PIN,HIGH); - #endif #endif #if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1 SET_OUTPUT(Z_ENABLE_PIN); if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH); - + #if defined(Z_DUAL_STEPPER_DRIVERS) && defined(Z2_ENABLE_PIN) && (Z2_ENABLE_PIN > -1) SET_OUTPUT(Z2_ENABLE_PIN); if(!Z_ENABLE_ON) WRITE(Z2_ENABLE_PIN,HIGH); @@ -839,71 +738,62 @@ void st_init() #endif //endstops and pullups - + #if defined(X_MIN_PIN) && X_MIN_PIN > -1 - SET_INPUT(X_MIN_PIN); + SET_INPUT(X_MIN_PIN); #ifdef ENDSTOPPULLUP_XMIN WRITE(X_MIN_PIN,HIGH); #endif #endif - + #if defined(Y_MIN_PIN) && Y_MIN_PIN > -1 - SET_INPUT(Y_MIN_PIN); + SET_INPUT(Y_MIN_PIN); #ifdef ENDSTOPPULLUP_YMIN WRITE(Y_MIN_PIN,HIGH); #endif #endif - + #if defined(Z_MIN_PIN) && Z_MIN_PIN > -1 - SET_INPUT(Z_MIN_PIN); + SET_INPUT(Z_MIN_PIN); #ifdef ENDSTOPPULLUP_ZMIN WRITE(Z_MIN_PIN,HIGH); #endif #endif - + #if defined(X_MAX_PIN) && X_MAX_PIN > -1 - SET_INPUT(X_MAX_PIN); + SET_INPUT(X_MAX_PIN); #ifdef ENDSTOPPULLUP_XMAX WRITE(X_MAX_PIN,HIGH); #endif #endif - + #if defined(Y_MAX_PIN) && Y_MAX_PIN > -1 - SET_INPUT(Y_MAX_PIN); + SET_INPUT(Y_MAX_PIN); #ifdef ENDSTOPPULLUP_YMAX WRITE(Y_MAX_PIN,HIGH); #endif #endif - + #if defined(Z_MAX_PIN) && Z_MAX_PIN > -1 - SET_INPUT(Z_MAX_PIN); + SET_INPUT(Z_MAX_PIN); #ifdef ENDSTOPPULLUP_ZMAX WRITE(Z_MAX_PIN,HIGH); #endif #endif - + //Initialize Step Pins - #if defined(X_STEP_PIN) && (X_STEP_PIN > -1) + #if defined(X_STEP_PIN) && (X_STEP_PIN > -1) SET_OUTPUT(X_STEP_PIN); WRITE(X_STEP_PIN,INVERT_X_STEP_PIN); disable_x(); - #endif - #if defined(X2_STEP_PIN) && (X2_STEP_PIN > -1) - SET_OUTPUT(X2_STEP_PIN); - WRITE(X2_STEP_PIN,INVERT_X_STEP_PIN); - disable_x(); - #endif - #if defined(Y_STEP_PIN) && (Y_STEP_PIN > -1) + #endif + #if defined(Y_STEP_PIN) && (Y_STEP_PIN > -1) SET_OUTPUT(Y_STEP_PIN); WRITE(Y_STEP_PIN,INVERT_Y_STEP_PIN); - #if defined(Y_DUAL_STEPPER_DRIVERS) && defined(Y2_STEP_PIN) && (Y2_STEP_PIN > -1) - SET_OUTPUT(Y2_STEP_PIN); - WRITE(Y2_STEP_PIN,INVERT_Y_STEP_PIN); - #endif disable_y(); - #endif - #if defined(Z_STEP_PIN) && (Z_STEP_PIN > -1) + #endif + #if defined(Z_STEP_PIN) && (Z_STEP_PIN > -1) SET_OUTPUT(Z_STEP_PIN); WRITE(Z_STEP_PIN,INVERT_Z_STEP_PIN); #if defined(Z_DUAL_STEPPER_DRIVERS) && defined(Z2_STEP_PIN) && (Z2_STEP_PIN > -1) @@ -911,33 +801,33 @@ void st_init() WRITE(Z2_STEP_PIN,INVERT_Z_STEP_PIN); #endif disable_z(); - #endif - #if defined(E0_STEP_PIN) && (E0_STEP_PIN > -1) + #endif + #if defined(E0_STEP_PIN) && (E0_STEP_PIN > -1) SET_OUTPUT(E0_STEP_PIN); WRITE(E0_STEP_PIN,INVERT_E_STEP_PIN); disable_e0(); - #endif - #if defined(E1_STEP_PIN) && (E1_STEP_PIN > -1) + #endif + #if defined(E1_STEP_PIN) && (E1_STEP_PIN > -1) SET_OUTPUT(E1_STEP_PIN); WRITE(E1_STEP_PIN,INVERT_E_STEP_PIN); disable_e1(); - #endif - #if defined(E2_STEP_PIN) && (E2_STEP_PIN > -1) + #endif + #if defined(E2_STEP_PIN) && (E2_STEP_PIN > -1) SET_OUTPUT(E2_STEP_PIN); WRITE(E2_STEP_PIN,INVERT_E_STEP_PIN); disable_e2(); - #endif + #endif // waveform generation = 0100 = CTC TCCR1B &= ~(1< -1 const uint8_t digipot_motor_current[] = DIGIPOT_MOTOR_CURRENT; - - SPI.begin(); - pinMode(DIGIPOTSS_PIN, OUTPUT); - for(int i=0;i<=4;i++) + + SPI.begin(); + pinMode(DIGIPOTSS_PIN, OUTPUT); + for(int i=0;i<=4;i++) //digitalPotWrite(digipot_ch[i], digipot_motor_current[i]); digipot_current(i,digipot_motor_current[i]); #endif From ed1ab42186fd8631456e4d7c6b572bf0a2d124f7 Mon Sep 17 00:00:00 2001 From: Richard Miles Date: Tue, 17 Sep 2013 19:19:20 +0100 Subject: [PATCH 043/256] Added Y_DUAL_STEPPER_DRIVERS Enables two stepper drivers to be used for the Y axis (useful for Shapeoko style machines) Each Y driver can be stepped in either the same way or in opposite directions, accounting for different hardware setups (leadscrew vs. belt driven) --- Marlin/Configuration_adv.h | 15 +++++++++++++++ Marlin/Marlin.h | 9 +++++++-- Marlin/stepper.cpp | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 5f1c77a056..bd411a403b 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -152,6 +152,21 @@ #define EXTRUDERS 1 #endif +// Same again but for Y Axis. +#define Y_DUAL_STEPPER_DRIVERS + +// Define if the two Y drives need to rotate in opposite directions +#define INVERT_Y2_VS_Y_DIR true + +#ifdef Y_DUAL_STEPPER_DRIVERS + #undef EXTRUDERS + #define EXTRUDERS 1 +#endif + +#ifdef Z_DUAL_STEPPER_DRIVERS && Y_DUAL_STEPPER_DRIVERS + #error "You cannot have dual drivers for both Y and Z" +#endif + //homing hits the endstop, then retracts by this distance, before it tries to slowly bump again: #define X_HOME_RETRACT_MM 5 #define Y_HOME_RETRACT_MM 5 diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index c9759eb219..c4460e79f0 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -105,8 +105,13 @@ void manage_inactivity(); #endif #if defined(Y_ENABLE_PIN) && Y_ENABLE_PIN > -1 - #define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON) - #define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON) + #ifdef Y_DUAL_STEPPER_DRIVERS + #define enable_y() { WRITE(Y_ENABLE_PIN, Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, Y_ENABLE_ON); } + #define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, !Y_ENABLE_ON); } + #else + #define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON) + #define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON) + #endif #else #define enable_y() ; #define disable_y() ; diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index a7991501e9..10c41b9a62 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -357,10 +357,20 @@ ISR(TIMER1_COMPA_vect) } if((out_bits & (1<steps_y; if (counter_y > 0) { WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN); + + #ifdef Y_DUAL_STEPPER_DRIVERS + WRITE(Y2_STEP_PIN, !INVERT_Y_STEP_PIN); + #endif + counter_y -= current_block->step_event_count; count_position[Y_AXIS]+=count_direction[Y_AXIS]; WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN); + + #ifdef Y_DUAL_STEPPER_DRIVERS + WRITE(Y2_STEP_PIN, INVERT_Y_STEP_PIN); + #endif } counter_z += current_block->steps_z; @@ -687,6 +706,10 @@ void st_init() #endif #if defined(Y_DIR_PIN) && Y_DIR_PIN > -1 SET_OUTPUT(Y_DIR_PIN); + + #if defined(Y_DUAL_STEPPER_DRIVERS) && defined(Y2_DIR_PIN) && (Y2_DIR_PIN > -1) + SET_OUTPUT(Y2_DIR_PIN); + #endif #endif #if defined(Z_DIR_PIN) && Z_DIR_PIN > -1 SET_OUTPUT(Z_DIR_PIN); @@ -714,6 +737,11 @@ void st_init() #if defined(Y_ENABLE_PIN) && Y_ENABLE_PIN > -1 SET_OUTPUT(Y_ENABLE_PIN); if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH); + + #if defined(Y_DUAL_STEPPER_DRIVERS) && defined(Y2_ENABLE_PIN) && (Y2_ENABLE_PIN > -1) + SET_OUTPUT(Y2_ENABLE_PIN); + if(!Y_ENABLE_ON) WRITE(Y2_ENABLE_PIN,HIGH); + #endif #endif #if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1 SET_OUTPUT(Z_ENABLE_PIN); @@ -791,6 +819,10 @@ void st_init() #if defined(Y_STEP_PIN) && (Y_STEP_PIN > -1) SET_OUTPUT(Y_STEP_PIN); WRITE(Y_STEP_PIN,INVERT_Y_STEP_PIN); + #if defined(Y_DUAL_STEPPER_DRIVERS) && defined(Y2_STEP_PIN) && (Y2_STEP_PIN > -1) + SET_OUTPUT(Y2_STEP_PIN); + WRITE(Y2_STEP_PIN,INVERT_Y_STEP_PIN); + #endif disable_y(); #endif #if defined(Z_STEP_PIN) && (Z_STEP_PIN > -1) From 77df2ab0e7e6253d2e1d975c76a9876ec46bd96b Mon Sep 17 00:00:00 2001 From: Richard Miles Date: Tue, 17 Sep 2013 21:49:44 +0100 Subject: [PATCH 044/256] Make Y_DUAL_STEPPER_DRIVERS disabled by default --- Marlin/Configuration_adv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index bd411a403b..4747842479 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -153,7 +153,7 @@ #endif // Same again but for Y Axis. -#define Y_DUAL_STEPPER_DRIVERS +//#define Y_DUAL_STEPPER_DRIVERS // Define if the two Y drives need to rotate in opposite directions #define INVERT_Y2_VS_Y_DIR true From 61db046b3285c56dea66e658d9b8530debaf63a1 Mon Sep 17 00:00:00 2001 From: Tim Koster Date: Fri, 20 Sep 2013 10:57:42 +0300 Subject: [PATCH 045/256] Added #ifdef BLINKM around new code. Also refined BlinkM.h. --- Marlin/BlinkM.cpp | 1 + Marlin/BlinkM.h | 4 ++++ Marlin/Configuration.h | 2 +- Marlin/Marlin_main.cpp | 2 ++ 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Marlin/BlinkM.cpp b/Marlin/BlinkM.cpp index 15a2527bbf..7b8a7867c2 100644 --- a/Marlin/BlinkM.cpp +++ b/Marlin/BlinkM.cpp @@ -7,6 +7,7 @@ #else # include "WProgram.h" #endif + #include "BlinkM.h" void SendColors(byte red, byte grn, byte blu) diff --git a/Marlin/BlinkM.h b/Marlin/BlinkM.h index 5136828782..fbb9399c23 100644 --- a/Marlin/BlinkM.h +++ b/Marlin/BlinkM.h @@ -8,7 +8,11 @@ # include "WProgram.h" #endif +#ifndef BLINKM +#define BLINKM + #include "Wire.h" void SendColors(byte red, byte grn, byte blu); +#endif diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 195331252f..d3168b5450 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -558,7 +558,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of //#define BARICUDA //define BlinkM/CyzRgb Support -//#define BlinkM +//#define BLINKM /*********************************************************************\ * R/C SERVO support diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 26fbd41232..7ecf6032c8 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1617,6 +1617,7 @@ void process_commands() #endif break; //TODO: update for all axis, use for loop + #ifdef BLINKM case 150: // M150 { byte red; @@ -1630,6 +1631,7 @@ void process_commands() SendColors(red,grn,blu); } break; + #endif //BLINKM case 201: // M201 for(int8_t i=0; i < NUM_AXIS; i++) { From 97b0da0c2e33270ea56e7c801ce5c15b0c4d0a2f Mon Sep 17 00:00:00 2001 From: Tim Koster Date: Sun, 22 Sep 2013 10:43:27 +0300 Subject: [PATCH 046/256] Removed #ifndef BLINKM --- Marlin/BlinkM.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Marlin/BlinkM.h b/Marlin/BlinkM.h index fbb9399c23..5136828782 100644 --- a/Marlin/BlinkM.h +++ b/Marlin/BlinkM.h @@ -8,11 +8,7 @@ # include "WProgram.h" #endif -#ifndef BLINKM -#define BLINKM - #include "Wire.h" void SendColors(byte red, byte grn, byte blu); -#endif From 3ca1ca686941944402438bd8bc03b1b810388fc8 Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Mon, 23 Sep 2013 23:18:35 +0200 Subject: [PATCH 047/256] Fixed missing ENCODER_PULSES_PER_STEP --- Marlin/ultralcd.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 4256878935..5c9cbf7752 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -91,6 +91,7 @@ static void menu_action_setting_edit_callback_long5(const char* pstr, unsigned l #define ENCODER_PULSES_PER_STEP 1 #else #define ENCODER_STEPS_PER_MENU_ITEM 2 // VIKI LCD rotary encoder uses a different number of steps per rotation + #define ENCODER_PULSES_PER_STEP 1 #endif From 9bc88f8bab9cd0c444c8a6248e2ad486125f4713 Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Mon, 23 Sep 2013 23:25:11 +0200 Subject: [PATCH 048/256] Placed optional ENCODER_PULSES_PER_STEP in the configuration.h file --- Marlin/Configuration.h | 2 +- Marlin/ultralcd.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index ef7a359e47..3927b16424 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -359,7 +359,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of //#define DOGLCD // Support for SPI LCD 128x64 (Controller ST7565R graphic Display Family) //#define SDSUPPORT // Enable SD Card Support in Hardware Console //#define SDSLOW // Use slower SD transfer mode (not normally needed - uncomment if you're getting volume init error) - +//#define ENCODER_PULSES_PER_STEP 1 // Increase if you have a high resolution encoder //#define ULTIMAKERCONTROLLER //as available from the ultimaker online store. //#define ULTIPANEL //the ultipanel as on thingiverse diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 5c9cbf7752..da4e064fc5 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -88,10 +88,14 @@ static void menu_action_setting_edit_callback_long5(const char* pstr, unsigned l #if !defined(LCD_I2C_VIKI) #define ENCODER_STEPS_PER_MENU_ITEM 5 - #define ENCODER_PULSES_PER_STEP 1 + #ifndef ENCODER_PULSES_PER_STEP + #define ENCODER_PULSES_PER_STEP 1 + #endif #else #define ENCODER_STEPS_PER_MENU_ITEM 2 // VIKI LCD rotary encoder uses a different number of steps per rotation - #define ENCODER_PULSES_PER_STEP 1 + #ifndef ENCODER_PULSES_PER_STEP + #define ENCODER_PULSES_PER_STEP 1 + #endif #endif From d8c2c810b49d43ecba84b3226c20a62900b34df9 Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Mon, 23 Sep 2013 23:29:46 +0200 Subject: [PATCH 049/256] Added info to the delta configuration files in the configuration.h file --- Marlin/Configuration.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 3927b16424..a65462fcb3 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -5,6 +5,13 @@ // Advanced settings can be found in Configuration_adv.h // BASIC SETTINGS: select your board type, temperature sensor type, axis scaling, and endstop configuration +//=========================================================================== +//============================= DELTA Printer =============================== +//=========================================================================== +// For a Delta printer rplace the configuration files wilth the files in the +// example_configurations/delta directory. +// + // User-specified version info of this build to display in [Pronterface, etc] terminal window during // startup. Implementation of an idea by Prof Braino to inform user that any changes made to this // build by the user have been successfully uploaded into firmware. From 0dca49a7c07721904922394f38ebaa8094c0aa45 Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Tue, 24 Sep 2013 17:31:16 +0200 Subject: [PATCH 050/256] Added Azteeg X3 board. --- Marlin/Configuration.h | 1 + Marlin/pins.h | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index a65462fcb3..54c448721c 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -45,6 +45,7 @@ // 64 = STB V1.1 // 65 = Azteeg X1 // 66 = Melzi with ATmega1284 (MaKr3d version) +// 67 = Azteeg X3 // 7 = Ultimaker // 71 = Ultimaker (Older electronics. Pre 1.5.4. This is rare) // 77 = 3Drag Controller diff --git a/Marlin/pins.h b/Marlin/pins.h index c6264e3180..cbc45abc7f 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -298,7 +298,7 @@ * Arduino Mega pin assignment * ****************************************************************************************/ -#if MOTHERBOARD == 3 || MOTHERBOARD == 33 || MOTHERBOARD == 34 || MOTHERBOARD == 35 || MOTHERBOARD == 77 +#if MOTHERBOARD == 3 || MOTHERBOARD == 33 || MOTHERBOARD == 34 || MOTHERBOARD == 35 || MOTHERBOARD == 77 || MOTHERBOARD == 67 #define KNOWN_BOARD 1 //////////////////FIX THIS////////////// @@ -314,7 +314,7 @@ // #define RAMPS_V_1_0 -#if MOTHERBOARD == 33 || MOTHERBOARD == 34 || MOTHERBOARD == 35 || MOTHERBOARD == 77 +#if MOTHERBOARD == 33 || MOTHERBOARD == 34 || MOTHERBOARD == 35 || MOTHERBOARD == 77 || MOTHERBOARD == 67 #define LARGE_FLASH true @@ -392,7 +392,7 @@ #define LED_PIN 13 #endif - #if MOTHERBOARD == 33 || MOTHERBOARD == 35 + #if MOTHERBOARD == 33 || MOTHERBOARD == 35 || MOTHERBOARD == 67 #define FAN_PIN 9 // (Sprinter config) #else #define FAN_PIN 4 // IO pin. Buffer needed @@ -420,7 +420,7 @@ #define HEATER_0_PIN 10 // EXTRUDER 1 #endif - #if MOTHERBOARD == 33 + #if MOTHERBOARD == 33 || MOTHERBOARD == 67 #define HEATER_1_PIN -1 #else #define HEATER_1_PIN 9 // EXTRUDER 2 (FAN On Sprinter) @@ -492,7 +492,12 @@ #define SDSS 53 #define SDCARDDETECT -1 #define KILL_PIN 41 - + #elif defined(LCD_I2C_VIKI) + #define BTN_EN1 22 //reverse if the encoder turns the wrong way. + #define BTN_EN2 7 + #define BTN_ENC -1 + #define SDSS 53 + #define SDCARDDETECT 49 #else //arduino pin which triggers an piezzo beeper #define BEEPER 33 // Beeper on AUX-4 From 57173739a16c5bcb7b1e420f1a0ed4c60c3608f6 Mon Sep 17 00:00:00 2001 From: phq1910 Date: Thu, 26 Sep 2013 11:29:44 -0300 Subject: [PATCH 051/256] Update Configuration.h Include CPU Sethi 3D --- Marlin/Configuration.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 54c448721c..fe22331d0a 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -32,6 +32,7 @@ // 11 = Gen7 v1.1, v1.2 = 11 // 12 = Gen7 v1.3 // 13 = Gen7 v1.4 +// 20 = Sethi 3D_1 // 3 = MEGA/RAMPS up to 1.2 = 3 // 33 = RAMPS 1.3 / 1.4 (Power outputs: Extruder, Fan, Bed) // 34 = RAMPS 1.3 / 1.4 (Power outputs: Extruder0, Extruder1, Bed) From 4f7c6dfe35faf351214e8d31a99fa61a9d95603b Mon Sep 17 00:00:00 2001 From: phq1910 Date: Thu, 26 Sep 2013 11:40:54 -0300 Subject: [PATCH 052/256] Update pins.h Include Pins cpu Sethi 3D --- Marlin/pins.h | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/Marlin/pins.h b/Marlin/pins.h index cbc45abc7f..1ae3cb486b 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -53,6 +53,83 @@ #endif /* 99 */ +/**************************************************************************************** +* Sethi 3D_1 pin assignment - www.sethi3d.com.br +* +****************************************************************************************/ + +#if MOTHERBOARD == 20 +#define KNOWN_BOARD + +#if !defined(__AVR_ATmega644P__) && !defined(__AVR_ATmega644__) && !defined(__AVR_ATmega1284P__) +#error Oops! Make sure you have 'Sethi 3D' selected from the 'Tools -> Boards' menu. + +#endif + +#ifndef GEN7_VERSION +#define GEN7_VERSION 12 // v1.x +#endif + +//x axis pins +#define X_STEP_PIN 19 +#define X_DIR_PIN 18 +#define X_ENABLE_PIN 24 +#define X_STOP_PIN 2 + +//y axis pins +#define Y_STEP_PIN 23 +#define Y_DIR_PIN 22 +#define Y_ENABLE_PIN 24 +#define Y_STOP_PIN 0 + +//z axis pins +#define Z_STEP_PIN 26 +#define Z_DIR_PIN 25 +#define Z_ENABLE_PIN 24 +#define Z_MIN_PIN 1 +#define Z_MAX_PIN 0 + +//extruder pins +#define E0_STEP_PIN 28 +#define E0_DIR_PIN 27 +#define E0_ENABLE_PIN 24 + +#define TEMP_0_PIN 1 +#define TEMP_1_PIN -1 +#define TEMP_2_PIN -1 +#define TEMP_BED_PIN 2 + +#define HEATER_0_PIN 4 +#define HEATER_1_PIN -1 +#define HEATER_2_PIN -1 +#define HEATER_BED_PIN 3 + +#define KILL_PIN -1 + +#define SDPOWER -1 +#define SDSS -1 // SCL pin of I2C header +#define LED_PIN -1 + +#if (GEN7_VERSION >= 13) +// Gen7 v1.3 removed the fan pin +#define FAN_PIN -1 +#else +#define FAN_PIN 31 +#endif +#define PS_ON_PIN 15 + +//All these generations of Gen7 supply thermistor power +//via PS_ON, so ignore bad thermistor readings +#define BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE + +//our pin for debugging. +#define DEBUG_PIN 0 + +//our RS485 pins +#define TX_ENABLE_PIN 12 +#define RX_ENABLE_PIN 13 + +#endif /**************************************************************************************** * Gen7 v1.1, v1.2, v1.3 pin assignment From 314fd13c39e1a5420adfbc9127339da80a1039aa Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Thu, 26 Sep 2013 20:32:19 +0200 Subject: [PATCH 053/256] Fix for Viki display --- Marlin/ultralcd.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index da4e064fc5..05ace2d491 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -104,7 +104,6 @@ static void menu_action_setting_edit_callback_long5(const char* pstr, unsigned l if (encoderPosition > 0x8000) encoderPosition = 0; \ if (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM < currentMenuViewOffset) currentMenuViewOffset = encoderPosition / ENCODER_STEPS_PER_MENU_ITEM;\ uint8_t _lineNr = currentMenuViewOffset, _menuItemNr; \ - bool wasClicked = LCD_CLICKED;\ for(uint8_t _drawLineNr = 0; _drawLineNr < LCD_HEIGHT; _drawLineNr++, _lineNr++) { \ _menuItemNr = 0; #define MENU_ITEM(type, label, args...) do { \ @@ -143,6 +142,7 @@ uint8_t currentMenuViewOffset; /* scroll offset in the current menu uint32_t blocking_enc; uint8_t lastEncoderBits; uint32_t encoderPosition; +bool wasClicked; #if (SDCARDDETECT > 0) bool lcd_oldcardstatus; #endif @@ -966,6 +966,7 @@ void lcd_update() if (lcd_next_update_millis < millis()) { + wasClicked = LCD_CLICKED; #ifdef ULTIPANEL #ifdef REPRAPWORLD_KEYPAD if (REPRAPWORLD_KEYPAD_MOVE_Z_UP) { From 253dfc4bc139d9cfc170ce0c829716e81c81bbe8 Mon Sep 17 00:00:00 2001 From: Alex Borro Date: Sun, 29 Sep 2013 13:20:06 -0300 Subject: [PATCH 054/256] Bed Auto Leveling feature Check the Readme for instruction how to enable and configure the feature --- Marlin/Configuration.h | 37 +++++ Marlin/Marlin.ino | 52 +++++++ Marlin/Marlin_main.cpp | 303 ++++++++++++++++++++++++++++++++++++++++- Marlin/Servo.cpp | 3 + Marlin/Servo.h | 3 + Marlin/planner.cpp | 39 ++++++ Marlin/planner.h | 22 +++ Marlin/stepper.cpp | 8 ++ Marlin/stepper.h | 11 +- Marlin/vector_3.cpp | 202 +++++++++++++++++++++++++++ Marlin/vector_3.h | 62 +++++++++ README.md | 68 +++++++++ 12 files changed, 806 insertions(+), 4 deletions(-) create mode 100644 Marlin/Marlin.ino create mode 100644 Marlin/vector_3.cpp create mode 100644 Marlin/vector_3.h diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index fe22331d0a..502ebd4389 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -292,13 +292,50 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #define min_software_endstops true // If true, axis won't move to coordinates less than HOME_POS. #define max_software_endstops true // If true, axis won't move to coordinates greater than the defined lengths below. + +//============================= Bed Auto Leveling =========================== + +//#define ENABLE_AUTO_BED_LEVELING // Delete the comment to enable (remove // at the start of the line) + +#ifdef ENABLE_AUTO_BED_LEVELING + + // these are the positions on the bed to do the probing + #define LEFT_PROBE_BED_POSITION 15 + #define RIGHT_PROBE_BED_POSITION 170 + #define BACK_PROBE_BED_POSITION 180 + #define FRONT_PROBE_BED_POSITION 20 + + // these are the offsets to the prob relative to the extruder tip (Hotend - Probe) + #define X_PROBE_OFFSET_FROM_EXTRUDER -25 + #define Y_PROBE_OFFSET_FROM_EXTRUDER -29 + #define Z_PROBE_OFFSET_FROM_EXTRUDER -12.35 + + #define XY_TRAVEL_SPEED 8000 // X and Y axis travel speed between probes, in mm/min + + #define Z_RAISE_BEFORE_PROBING 15 //How much the extruder will be raised before traveling to the first probing point. + #define Z_RAISE_BETWEEN_PROBINGS 5 //How much the extruder will be raised when traveling from between next probing points + + + //If defined, the Probe servo will be turned on only during movement and then turned off to avoid jerk + //The value is the delay to turn the servo off after powered on - depends on the servo speed; 300ms is good value, but you can try lower it. + // You MUST HAVE the SERVO_ENDSTOPS defined to use here a value higher than zero otherwise your code will not compile. + +// #define PROBE_SERVO_DEACTIVATION_DELAY 300 + +#endif + // Travel limits after homing #define X_MAX_POS 205 #define X_MIN_POS 0 #define Y_MAX_POS 205 #define Y_MIN_POS 0 #define Z_MAX_POS 200 + +#ifndef ENABLE_AUTO_BED_LEVELING #define Z_MIN_POS 0 +#else +#define Z_MIN_POS (-1*Z_PROBE_OFFSET_FROM_EXTRUDER) //With Auto Bed Leveling, the Z_MIN MUST have the same distance as Z_PROBE +#endif #define X_MAX_LENGTH (X_MAX_POS - X_MIN_POS) #define Y_MAX_LENGTH (Y_MAX_POS - Y_MIN_POS) diff --git a/Marlin/Marlin.ino b/Marlin/Marlin.ino new file mode 100644 index 0000000000..2d6211c971 --- /dev/null +++ b/Marlin/Marlin.ino @@ -0,0 +1,52 @@ +/* -*- c++ -*- */ + +/* + Reprap firmware based on Sprinter and grbl. + Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +/* + This firmware is a mashup between Sprinter and grbl. + (https://github.com/kliment/Sprinter) + (https://github.com/simen/grbl/tree) + + It has preliminary support for Matthew Roberts advance algorithm + http://reprap.org/pipermail/reprap-dev/2011-May/003323.html + */ + +/* All the implementation is done in *.cpp files to get better compatibility with avr-gcc without the Arduino IDE */ +/* Use this file to help the Arduino IDE find which Arduino libraries are needed and to keep documentation on GCode */ + +#include "Configuration.h" +#include "pins.h" + +#ifdef ULTRA_LCD + #if defined(LCD_I2C_TYPE_PCF8575) + #include + #include + #elif defined(LCD_I2C_TYPE_MCP23017) || defined(LCD_I2C_TYPE_MCP23008) + #include + #include + #elif defined(DOGLCD) + #include // library for graphics LCD by Oli Kraus (https://code.google.com/p/u8glib/) + #else + #include // library for character LCD + #endif +#endif + +#if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1 +#include +#endif diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 65b829bdc3..932af13552 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -29,6 +29,10 @@ #include "Marlin.h" +#ifdef ENABLE_AUTO_BED_LEVELING +#include "vector_3.h" +#endif // ENABLE_AUTO_BED_LEVELING + #include "ultralcd.h" #include "planner.h" #include "stepper.h" @@ -63,6 +67,8 @@ // G10 - retract filament according to settings of M207 // G11 - retract recover filament according to settings of M208 // G28 - Home all Axis +// G29 - Detailed Z-Probe, probes the bed at 3 points. You must de at the home position for this to work correctly. +// G30 - Single Z Probe, probes bed at current XY location. // G90 - Use Absolute Coordinates // G91 - Use Relative Coordinates // G92 - Set current position to cordinates given @@ -133,6 +139,8 @@ // M303 - PID relay autotune S sets the target temperature. (default target temperature = 150C) // M304 - Set bed PID parameters P I and D // M400 - Finish all moves +// M401 - Lower z-probe if present +// M402 - Raise z-probe if present // M500 - stores paramters in EEPROM // M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily). // M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to. @@ -388,6 +396,11 @@ void servo_init() } } #endif + + #if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) + delay(PROBE_SERVO_DEACTIVATION_DELAY); + servos[servo_endstops[Z_AXIS]].detach(); + #endif } void setup() @@ -756,6 +769,143 @@ static void axis_is_at_home(int axis) { max_pos[axis] = base_max_pos(axis) + add_homeing[axis]; } +#ifdef ENABLE_AUTO_BED_LEVELING +static void set_bed_level_equation(float z_at_xLeft_yFront, float z_at_xRight_yFront, float z_at_xLeft_yBack) { + plan_bed_level_matrix.set_to_identity(); + + vector_3 xLeftyFront = vector_3(LEFT_PROBE_BED_POSITION, FRONT_PROBE_BED_POSITION, z_at_xLeft_yFront); + vector_3 xLeftyBack = vector_3(LEFT_PROBE_BED_POSITION, BACK_PROBE_BED_POSITION, z_at_xLeft_yBack); + vector_3 xRightyFront = vector_3(RIGHT_PROBE_BED_POSITION, FRONT_PROBE_BED_POSITION, z_at_xRight_yFront); + + vector_3 xPositive = (xRightyFront - xLeftyFront).get_normal(); + vector_3 yPositive = (xLeftyBack - xLeftyFront).get_normal(); + vector_3 planeNormal = vector_3::cross(yPositive, xPositive).get_normal(); + + //planeNormal.debug("planeNormal"); + //yPositive.debug("yPositive"); + matrix_3x3 bedLevel = matrix_3x3::create_look_at(planeNormal, yPositive); + //bedLevel.debug("bedLevel"); + + //plan_bed_level_matrix.debug("bed level before"); + //vector_3 uncorrected_position = plan_get_position_mm(); + //uncorrected_position.debug("position before"); + + // and set our bed level equation to do the right thing + plan_bed_level_matrix = matrix_3x3::create_inverse(bedLevel); + //plan_bed_level_matrix.debug("bed level after"); + + vector_3 corrected_position = plan_get_position(); + //corrected_position.debug("position after"); + current_position[X_AXIS] = corrected_position.x; + current_position[Y_AXIS] = corrected_position.y; + current_position[Z_AXIS] = corrected_position.z; + + // but the bed at 0 so we don't go below it. + current_position[Z_AXIS] = -Z_PROBE_OFFSET_FROM_EXTRUDER; + + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); +} + +static void run_z_probe() { + plan_bed_level_matrix.set_to_identity(); + feedrate = homing_feedrate[Z_AXIS]; + + // move down until you find the bed + float zPosition = -10; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], zPosition, current_position[E_AXIS], feedrate/60, active_extruder); + st_synchronize(); + + // we have to let the planner know where we are right now as it is not where we said to go. + zPosition = st_get_position_mm(Z_AXIS); + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], zPosition, current_position[E_AXIS]); + + // move up the retract distance + zPosition += home_retract_mm(Z_AXIS); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], zPosition, current_position[E_AXIS], feedrate/60, active_extruder); + st_synchronize(); + + // move back down slowly to find bed + feedrate = homing_feedrate[Z_AXIS]/4; + zPosition -= home_retract_mm(Z_AXIS) * 2; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], zPosition, current_position[E_AXIS], feedrate/60, active_extruder); + st_synchronize(); + + current_position[Z_AXIS] = st_get_position_mm(Z_AXIS); + // make sure the planner knows where we are as it may be a bit different than we last said to move to + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); +} + +static void do_blocking_move_to(float x, float y, float z) { + float oldFeedRate = feedrate; + + feedrate = XY_TRAVEL_SPEED; + + current_position[X_AXIS] = x; + current_position[Y_AXIS] = y; + current_position[Z_AXIS] = z; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate/60, active_extruder); + st_synchronize(); + + feedrate = oldFeedRate; +} + +static void do_blocking_move_relative(float offset_x, float offset_y, float offset_z) { + do_blocking_move_to(current_position[X_AXIS] + offset_x, current_position[Y_AXIS] + offset_y, current_position[Z_AXIS] + offset_z); +} + +static void setup_for_endstop_move() { + saved_feedrate = feedrate; + saved_feedmultiply = feedmultiply; + feedmultiply = 100; + previous_millis_cmd = millis(); + + enable_endstops(true); +} + +static void clean_up_after_endstop_move() { +#ifdef ENDSTOPS_ONLY_FOR_HOMING + enable_endstops(false); +#endif + + feedrate = saved_feedrate; + feedmultiply = saved_feedmultiply; + previous_millis_cmd = millis(); +} + +static void engage_z_probe() { + // Engage Z Servo endstop if enabled + #ifdef SERVO_ENDSTOPS + if (servo_endstops[Z_AXIS] > -1) { +#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) + servos[servo_endstops[Z_AXIS]].attach(0); +#endif + servos[servo_endstops[Z_AXIS]].write(servo_endstop_angles[Z_AXIS * 2]); +#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) + delay(PROBE_SERVO_DEACTIVATION_DELAY); + servos[servo_endstops[Z_AXIS]].detach(); +#endif + } + #endif +} + +static void retract_z_probe() { + // Retract Z Servo endstop if enabled + #ifdef SERVO_ENDSTOPS + if (servo_endstops[Z_AXIS] > -1) { +#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) + servos[servo_endstops[Z_AXIS]].attach(0); +#endif + servos[servo_endstops[Z_AXIS]].write(servo_endstop_angles[Z_AXIS * 2 + 1]); +#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) + delay(PROBE_SERVO_DEACTIVATION_DELAY); + servos[servo_endstops[Z_AXIS]].detach(); +#endif + } + #endif +} + +#endif // #ifdef ENABLE_AUTO_BED_LEVELING + static void homeaxis(int axis) { #define HOMEAXIS_DO(LETTER) \ ((LETTER##_MIN_PIN > -1 && LETTER##_HOME_DIR==-1) || (LETTER##_MAX_PIN > -1 && LETTER##_HOME_DIR==1)) @@ -772,6 +922,10 @@ static void homeaxis(int axis) { // Engage Servo endstop if enabled #ifdef SERVO_ENDSTOPS +#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) + if (axis==Z_AXIS) engage_z_probe(); + else +#endif if (servo_endstops[axis] > -1) { servos[servo_endstops[axis]].write(servo_endstop_angles[axis * 2]); } @@ -818,6 +972,10 @@ static void homeaxis(int axis) { servos[servo_endstops[axis]].write(servo_endstop_angles[axis * 2 + 1]); } #endif +#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) + if (axis==Z_AXIS) retract_z_probe(); +#endif + } } #define HOMEAXIS(LETTER) homeaxis(LETTER##_AXIS) @@ -826,7 +984,9 @@ void process_commands() { unsigned long codenum; //throw away variable char *starpos = NULL; - +#ifdef ENABLE_AUTO_BED_LEVELING + float x_tmp, y_tmp, z_tmp, real_z; +#endif if(code_seen('G')) { switch((int)code_value()) @@ -898,6 +1058,11 @@ void process_commands() break; #endif //FWRETRACT case 28: //G28 Home all Axis one at a time +#ifdef ENABLE_AUTO_BED_LEVELING + plan_bed_level_matrix.set_to_identity(); //Reset the plane ("erase" all leveling data) +#endif //ENABLE_AUTO_BED_LEVELING + + saved_feedrate = feedrate; saved_feedmultiply = feedmultiply; feedmultiply = 100; @@ -1045,6 +1210,122 @@ void process_commands() previous_millis_cmd = millis(); endstops_hit_on_purpose(); break; + +#ifdef ENABLE_AUTO_BED_LEVELING + case 29: // G29 Detailed Z-Probe, probes the bed at 3 points. + { + #if Z_MIN_PIN == -1 + #error "You must have a Z_MIN endstop in order to enable Auto Bed Leveling feature!!! Z_MIN_PIN must point to a valid hardware pin." + #endif + + st_synchronize(); + // make sure the bed_level_rotation_matrix is identity or the planner will get it incorectly + //vector_3 corrected_position = plan_get_position_mm(); + //corrected_position.debug("position before G29"); + plan_bed_level_matrix.set_to_identity(); + vector_3 uncorrected_position = plan_get_position(); + //uncorrected_position.debug("position durring G29"); + current_position[X_AXIS] = uncorrected_position.x; + current_position[Y_AXIS] = uncorrected_position.y; + current_position[Z_AXIS] = uncorrected_position.z; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + setup_for_endstop_move(); + + feedrate = homing_feedrate[Z_AXIS]; + + // prob 1 + do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], Z_RAISE_BEFORE_PROBING); + do_blocking_move_to(LEFT_PROBE_BED_POSITION - X_PROBE_OFFSET_FROM_EXTRUDER, BACK_PROBE_BED_POSITION - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]); + + engage_z_probe(); // Engage Z Servo endstop if available + + run_z_probe(); + float z_at_xLeft_yBack = current_position[Z_AXIS]; + + SERIAL_PROTOCOLPGM("Bed x: "); + SERIAL_PROTOCOL(LEFT_PROBE_BED_POSITION); + SERIAL_PROTOCOLPGM(" y: "); + SERIAL_PROTOCOL(BACK_PROBE_BED_POSITION); + SERIAL_PROTOCOLPGM(" z: "); + SERIAL_PROTOCOL(current_position[Z_AXIS]); + SERIAL_PROTOCOLPGM("\n"); + + // prob 2 + do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); + do_blocking_move_to(LEFT_PROBE_BED_POSITION - X_PROBE_OFFSET_FROM_EXTRUDER, FRONT_PROBE_BED_POSITION - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]); + run_z_probe(); + float z_at_xLeft_yFront = current_position[Z_AXIS]; + + SERIAL_PROTOCOLPGM("Bed x: "); + SERIAL_PROTOCOL(LEFT_PROBE_BED_POSITION); + SERIAL_PROTOCOLPGM(" y: "); + SERIAL_PROTOCOL(FRONT_PROBE_BED_POSITION); + SERIAL_PROTOCOLPGM(" z: "); + SERIAL_PROTOCOL(current_position[Z_AXIS]); + SERIAL_PROTOCOLPGM("\n"); + + // prob 3 + do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); + // the current position will be updated by the blocking move so the head will not lower on this next call. + do_blocking_move_to(RIGHT_PROBE_BED_POSITION - X_PROBE_OFFSET_FROM_EXTRUDER, FRONT_PROBE_BED_POSITION - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]); + run_z_probe(); + float z_at_xRight_yFront = current_position[Z_AXIS]; + + SERIAL_PROTOCOLPGM("Bed x: "); + SERIAL_PROTOCOL(RIGHT_PROBE_BED_POSITION); + SERIAL_PROTOCOLPGM(" y: "); + SERIAL_PROTOCOL(FRONT_PROBE_BED_POSITION); + SERIAL_PROTOCOLPGM(" z: "); + SERIAL_PROTOCOL(current_position[Z_AXIS]); + SERIAL_PROTOCOLPGM("\n"); + + clean_up_after_endstop_move(); + + set_bed_level_equation(z_at_xLeft_yFront, z_at_xRight_yFront, z_at_xLeft_yBack); + + retract_z_probe(); // Retract Z Servo endstop if available + + st_synchronize(); + + // The following code correct the Z height difference from z-probe position and hotend tip position. + // The Z height on homing is measured by Z-Probe, but the probe is quite far from the hotend. + // When the bed is uneven, this height must be corrected. + real_z = float(st_get_position(Z_AXIS))/axis_steps_per_unit[Z_AXIS]; //get the real Z (since the auto bed leveling is already correcting the plane) + x_tmp = current_position[X_AXIS] + X_PROBE_OFFSET_FROM_EXTRUDER; + y_tmp = current_position[Y_AXIS] + Y_PROBE_OFFSET_FROM_EXTRUDER; + z_tmp = current_position[Z_AXIS]; + + apply_rotation_xyz(plan_bed_level_matrix, x_tmp, y_tmp, z_tmp); //Apply the correction sending the probe offset + current_position[Z_AXIS] = z_tmp - real_z + current_position[Z_AXIS]; //The difference is added to current position and sent to planner. + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + } + break; + + case 30: // G30 Single Z Probe + { + engage_z_probe(); // Engage Z Servo endstop if available + + st_synchronize(); + // TODO: make sure the bed_level_rotation_matrix is identity or the planner will get set incorectly + setup_for_endstop_move(); + + feedrate = homing_feedrate[Z_AXIS]; + + run_z_probe(); + SERIAL_PROTOCOLPGM("Bed Position X: "); + SERIAL_PROTOCOL(current_position[X_AXIS]); + SERIAL_PROTOCOLPGM(" Y: "); + SERIAL_PROTOCOL(current_position[Y_AXIS]); + SERIAL_PROTOCOLPGM(" Z: "); + SERIAL_PROTOCOL(current_position[Z_AXIS]); + SERIAL_PROTOCOLPGM("\n"); + + clean_up_after_endstop_move(); + + retract_z_probe(); // Retract Z Servo endstop if available + } + break; +#endif // ENABLE_AUTO_BED_LEVELING case 90: // G90 relative_mode = false; break; @@ -1787,7 +2068,14 @@ void process_commands() if (code_seen('S')) { servo_position = code_value(); if ((servo_index >= 0) && (servo_index < NUM_SERVOS)) { +#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) + servos[servo_index].attach(0); +#endif servos[servo_index].write(servo_position); +#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) + delay(PROBE_SERVO_DEACTIVATION_DELAY); + servos[servo_index].detach(); +#endif } else { SERIAL_ECHO_START; @@ -1938,6 +2226,19 @@ void process_commands() st_synchronize(); } break; +#if defined(ENABLE_AUTO_BED_LEVELING) && defined(SERVO_ENDSTOPS) + case 401: + { + engage_z_probe(); // Engage Z Servo endstop if available + } + break; + + case 402: + { + retract_z_probe(); // Retract Z Servo endstop if enabled + } + break; +#endif case 500: // M500 Store settings in EEPROM { Config_StoreSettings(); diff --git a/Marlin/Servo.cpp b/Marlin/Servo.cpp index 47c16aa719..5f8c7efe30 100644 --- a/Marlin/Servo.cpp +++ b/Marlin/Servo.cpp @@ -262,6 +262,9 @@ uint8_t Servo::attach(int pin) uint8_t Servo::attach(int pin, int min, int max) { if(this->servoIndex < MAX_SERVOS ) { +#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) + if (pin > 0) this->pin = pin; else pin = this->pin; +#endif pinMode( pin, OUTPUT) ; // set servo pin to output servos[this->servoIndex].Pin.nbr = pin; // todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128 diff --git a/Marlin/Servo.h b/Marlin/Servo.h index 17c99f7974..f2e0be1a9c 100644 --- a/Marlin/Servo.h +++ b/Marlin/Servo.h @@ -123,6 +123,9 @@ public: int read(); // returns current pulse width as an angle between 0 and 180 degrees int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release) bool attached(); // return true if this servo is attached, otherwise false +#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) + int pin; // store the hw pin of the servo +#endif private: uint8_t servoIndex; // index into the channel data for this servo int8_t min; // minimum is this value times 4 added to MIN_PULSE_WIDTH diff --git a/Marlin/planner.cpp b/Marlin/planner.cpp index 8eff191751..008c8d257f 100644 --- a/Marlin/planner.cpp +++ b/Marlin/planner.cpp @@ -75,6 +75,15 @@ float max_e_jerk; float mintravelfeedrate; unsigned long axis_steps_per_sqr_second[NUM_AXIS]; +#ifdef ENABLE_AUTO_BED_LEVELING +// this holds the required transform to compensate for bed level +matrix_3x3 plan_bed_level_matrix = { + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0, +}; +#endif // #ifdef ENABLE_AUTO_BED_LEVELING + // The current position of the tool in absolute steps long position[4]; //rescaled from extern when axis_steps_per_unit are changed by gcode static float previous_speed[4]; // Speed of previous path line segment @@ -513,7 +522,11 @@ float junction_deviation = 0.1; // Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in // mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration // calculation the caller must also provide the physical length of the line in millimeters. +#ifdef ENABLE_AUTO_BED_LEVELING +void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate, const uint8_t &extruder) +#else void plan_buffer_line(const float &x, const float &y, const float &z, const float &e, float feed_rate, const uint8_t &extruder) +#endif //ENABLE_AUTO_BED_LEVELING { // Calculate the buffer head after we push this byte int next_buffer_head = next_block_index(block_buffer_head); @@ -527,6 +540,10 @@ void plan_buffer_line(const float &x, const float &y, const float &z, const floa lcd_update(); } +#ifdef ENABLE_AUTO_BED_LEVELING + apply_rotation_xyz(plan_bed_level_matrix, x, y, z); +#endif // ENABLE_AUTO_BED_LEVELING + // The target position of the tool in absolute steps // Calculate target position in absolute steps //this should be done after the wait, because otherwise a M92 code within the gcode disrupts this calculation somehow @@ -919,8 +936,30 @@ block->steps_y = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-positi st_wake_up(); } +#ifdef ENABLE_AUTO_BED_LEVELING +vector_3 plan_get_position() { + vector_3 position = vector_3(st_get_position_mm(X_AXIS), st_get_position_mm(Y_AXIS), st_get_position_mm(Z_AXIS)); + + //position.debug("in plan_get position"); + //plan_bed_level_matrix.debug("in plan_get bed_level"); + matrix_3x3 inverse = matrix_3x3::create_inverse(plan_bed_level_matrix); + //inverse.debug("in plan_get inverse"); + position.apply_rotation(inverse); + //position.debug("after rotation"); + + return position; +} +#endif // ENABLE_AUTO_BED_LEVELING + +#ifdef ENABLE_AUTO_BED_LEVELING +void plan_set_position(float x, float y, float z, const float &e) +{ + apply_rotation_xyz(plan_bed_level_matrix, x, y, z); +#else void plan_set_position(const float &x, const float &y, const float &z, const float &e) { +#endif // ENABLE_AUTO_BED_LEVELING + position[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]); position[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]); position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); diff --git a/Marlin/planner.h b/Marlin/planner.h index 597eeb1c00..9df0174602 100644 --- a/Marlin/planner.h +++ b/Marlin/planner.h @@ -26,6 +26,10 @@ #include "Marlin.h" +#ifdef ENABLE_AUTO_BED_LEVELING +#include "vector_3.h" +#endif // ENABLE_AUTO_BED_LEVELING + // This struct is used when buffering the setup for each linear movement "nominal" values are as specified in // the source g-code and may never actually be reached if acceleration management is active. typedef struct { @@ -67,15 +71,33 @@ typedef struct { volatile char busy; } block_t; +#ifdef ENABLE_AUTO_BED_LEVELING +// this holds the required transform to compensate for bed level +extern matrix_3x3 plan_bed_level_matrix; +#endif // #ifdef ENABLE_AUTO_BED_LEVELING + // Initialize the motion plan subsystem void plan_init(); // Add a new linear movement to the buffer. x, y and z is the signed, absolute target position in // millimaters. Feed rate specifies the speed of the motion. + +#ifdef ENABLE_AUTO_BED_LEVELING +void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate, const uint8_t &extruder); + +// Get the position applying the bed level matrix if enabled +vector_3 plan_get_position(); +#else void plan_buffer_line(const float &x, const float &y, const float &z, const float &e, float feed_rate, const uint8_t &extruder); +#endif // ENABLE_AUTO_BED_LEVELING // Set position. Used for G92 instructions. +#ifdef ENABLE_AUTO_BED_LEVELING +void plan_set_position(float x, float y, float z, const float &e); +#else void plan_set_position(const float &x, const float &y, const float &z, const float &e); +#endif // ENABLE_AUTO_BED_LEVELING + void plan_set_e_position(const float &e); diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index 7d738ac5e9..8b39a41d64 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -969,6 +969,14 @@ long st_get_position(uint8_t axis) return count_pos; } +#ifdef ENABLE_AUTO_BED_LEVELING +float st_get_position_mm(uint8_t axis) +{ + float steper_position_in_steps = st_get_position(axis); + return steper_position_in_steps / axis_steps_per_unit[axis]; +} +#endif // ENABLE_AUTO_BED_LEVELING + void finishAndDisableSteppers() { st_synchronize(); diff --git a/Marlin/stepper.h b/Marlin/stepper.h index ac9dd8af59..82b41c90de 100644 --- a/Marlin/stepper.h +++ b/Marlin/stepper.h @@ -44,9 +44,9 @@ #define REV_E_DIR() WRITE(E0_DIR_PIN, INVERT_E0_DIR) #endif -#ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED -extern bool abort_on_endstop_hit; -#endif +#ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED +extern bool abort_on_endstop_hit; +#endif // Initialize and start the stepper motor subsystem void st_init(); @@ -61,6 +61,11 @@ void st_set_e_position(const long &e); // Get current position in steps long st_get_position(uint8_t axis); +#ifdef ENABLE_AUTO_BED_LEVELING +// Get current position in mm +float st_get_position_mm(uint8_t axis); +#endif //ENABLE_AUTO_BED_LEVELING + // The stepper subsystem goes to sleep when it runs out of things to execute. Call this // to notify the subsystem that it is time to go to work. void st_wake_up(); diff --git a/Marlin/vector_3.cpp b/Marlin/vector_3.cpp new file mode 100644 index 0000000000..8c8a0e1dc7 --- /dev/null +++ b/Marlin/vector_3.cpp @@ -0,0 +1,202 @@ +/* + vector_3.cpp - Vector library for bed leveling + Copyright (c) 2012 Lars Brubaker. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include +#include "Marlin.h" + +#ifdef ENABLE_AUTO_BED_LEVELING +#include "vector_3.h" + +vector_3::vector_3() +{ + this->x = 0; + this->y = 0; + this->z = 0; +} + +vector_3::vector_3(float x, float y, float z) +{ + this->x = x; + this->y = y; + this->z = z; +} + +vector_3 vector_3::cross(vector_3 left, vector_3 right) +{ + return vector_3(left.y * right.z - left.z * right.y, + left.z * right.x - left.x * right.z, + left.x * right.y - left.y * right.x); +} + +vector_3 vector_3::operator+(vector_3 v) +{ + return vector_3((x + v.x), (y + v.y), (z + v.z)); +} + +vector_3 vector_3::operator-(vector_3 v) +{ + return vector_3((x - v.x), (y - v.y), (z - v.z)); +} + +vector_3 vector_3::get_normal() +{ + vector_3 normalized = vector_3(x, y, z); + normalized.normalize(); + return normalized; +} + +float vector_3::get_length() +{ + float length = sqrt((x * x) + (y * y) + (z * z)); + return length; +} + +void vector_3::normalize() +{ + float length = get_length(); + x /= length; + y /= length; + z /= length; +} + +void vector_3::apply_rotation(matrix_3x3 matrix) +{ + float resultX = x * matrix.matrix[3*0+0] + y * matrix.matrix[3*1+0] + z * matrix.matrix[3*2+0]; + float resultY = x * matrix.matrix[3*0+1] + y * matrix.matrix[3*1+1] + z * matrix.matrix[3*2+1]; + float resultZ = x * matrix.matrix[3*0+2] + y * matrix.matrix[3*1+2] + z * matrix.matrix[3*2+2]; + + x = resultX; + y = resultY; + z = resultZ; +} + +void vector_3::debug(char* title) +{ + SERIAL_PROTOCOL(title); + SERIAL_PROTOCOLPGM(" x: "); + SERIAL_PROTOCOL(x); + SERIAL_PROTOCOLPGM(" y: "); + SERIAL_PROTOCOL(y); + SERIAL_PROTOCOLPGM(" z: "); + SERIAL_PROTOCOL(z); + SERIAL_PROTOCOLPGM("\n"); +} + +void apply_rotation_xyz(matrix_3x3 matrix, float &x, float& y, float& z) +{ + vector_3 vector = vector_3(x, y, z); + vector.apply_rotation(matrix); + x = vector.x; + y = vector.y; + z = vector.z; +} + +matrix_3x3 matrix_3x3::create_from_rows(vector_3 row_0, vector_3 row_1, vector_3 row_2) +{ + //row_0.debug("row_0"); + //row_1.debug("row_1"); + //row_2.debug("row_2"); + matrix_3x3 new_matrix; + new_matrix.matrix[0] = row_0.x; new_matrix.matrix[1] = row_0.y; new_matrix.matrix[2] = row_0.z; + new_matrix.matrix[3] = row_1.x; new_matrix.matrix[4] = row_1.y; new_matrix.matrix[5] = row_1.z; + new_matrix.matrix[6] = row_2.x; new_matrix.matrix[7] = row_2.y; new_matrix.matrix[8] = row_2.z; + //new_matrix.debug("new_matrix"); + + return new_matrix; +} + +void matrix_3x3::set_to_identity() +{ + matrix[0] = 1; matrix[1] = 0; matrix[2] = 0; + matrix[3] = 0; matrix[4] = 1; matrix[5] = 0; + matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; +} + +matrix_3x3 matrix_3x3::create_look_at(vector_3 target, vector_3 up) +{ + // There are lots of examples of look at code on the internet that don't do all these noramize and also find the position + // through several dot products. The problem with them is that they have a bit of error in that all the vectors arn't normal and need to be. + vector_3 z_row = vector_3(-target.x, -target.y, -target.z).get_normal(); + vector_3 x_row = vector_3::cross(up, z_row).get_normal(); + vector_3 y_row = vector_3::cross(z_row, x_row).get_normal(); + + //x_row.debug("x_row"); + //y_row.debug("y_row"); + //z_row.debug("z_row"); + + matrix_3x3 rot = matrix_3x3::create_from_rows(vector_3(x_row.x, y_row.x, z_row.x), + vector_3(x_row.y, y_row.y, z_row.y), + vector_3(x_row.z, y_row.z, z_row.z)); + + //rot.debug("rot"); + return rot; +} + +matrix_3x3 matrix_3x3::create_inverse(matrix_3x3 original) +{ + //original.debug("original"); + float* A = original.matrix; + float determinant = + + A[0 * 3 + 0] * (A[1 * 3 + 1] * A[2 * 3 + 2] - A[2 * 3 + 1] * A[1 * 3 + 2]) + - A[0 * 3 + 1] * (A[1 * 3 + 0] * A[2 * 3 + 2] - A[1 * 3 + 2] * A[2 * 3 + 0]) + + A[0 * 3 + 2] * (A[1 * 3 + 0] * A[2 * 3 + 1] - A[1 * 3 + 1] * A[2 * 3 + 0]); + matrix_3x3 inverse; + inverse.matrix[0 * 3 + 0] = +(A[1 * 3 + 1] * A[2 * 3 + 2] - A[2 * 3 + 1] * A[1 * 3 + 2]) / determinant; + inverse.matrix[0 * 3 + 1] = -(A[0 * 3 + 1] * A[2 * 3 + 2] - A[0 * 3 + 2] * A[2 * 3 + 1]) / determinant; + inverse.matrix[0 * 3 + 2] = +(A[0 * 3 + 1] * A[1 * 3 + 2] - A[0 * 3 + 2] * A[1 * 3 + 1]) / determinant; + inverse.matrix[1 * 3 + 0] = -(A[1 * 3 + 0] * A[2 * 3 + 2] - A[1 * 3 + 2] * A[2 * 3 + 0]) / determinant; + inverse.matrix[1 * 3 + 1] = +(A[0 * 3 + 0] * A[2 * 3 + 2] - A[0 * 3 + 2] * A[2 * 3 + 0]) / determinant; + inverse.matrix[1 * 3 + 2] = -(A[0 * 3 + 0] * A[1 * 3 + 2] - A[1 * 3 + 0] * A[0 * 3 + 2]) / determinant; + inverse.matrix[2 * 3 + 0] = +(A[1 * 3 + 0] * A[2 * 3 + 1] - A[2 * 3 + 0] * A[1 * 3 + 1]) / determinant; + inverse.matrix[2 * 3 + 1] = -(A[0 * 3 + 0] * A[2 * 3 + 1] - A[2 * 3 + 0] * A[0 * 3 + 1]) / determinant; + inverse.matrix[2 * 3 + 2] = +(A[0 * 3 + 0] * A[1 * 3 + 1] - A[1 * 3 + 0] * A[0 * 3 + 1]) / determinant; + + vector_3 row0 = vector_3(inverse.matrix[0 * 3 + 0], inverse.matrix[0 * 3 + 1], inverse.matrix[0 * 3 + 2]); + vector_3 row1 = vector_3(inverse.matrix[1 * 3 + 0], inverse.matrix[1 * 3 + 1], inverse.matrix[1 * 3 + 2]); + vector_3 row2 = vector_3(inverse.matrix[2 * 3 + 0], inverse.matrix[2 * 3 + 1], inverse.matrix[2 * 3 + 2]); + + row0.normalize(); + row1.normalize(); + row2.normalize(); + + inverse = matrix_3x3::create_from_rows(row0, row1, row2); + + //inverse.debug("inverse"); + return inverse; +} + +void matrix_3x3::debug(char* title) +{ + SERIAL_PROTOCOL(title); + SERIAL_PROTOCOL("\n"); + int count = 0; + for(int i=0; i<3; i++) + { + for(int j=0; j<3; j++) + { + SERIAL_PROTOCOL(matrix[count]); + SERIAL_PROTOCOLPGM(" "); + count++; + } + + SERIAL_PROTOCOLPGM("\n"); + } +} + +#endif // #ifdef ENABLE_AUTO_BED_LEVELING + diff --git a/Marlin/vector_3.h b/Marlin/vector_3.h new file mode 100644 index 0000000000..b08c336e8f --- /dev/null +++ b/Marlin/vector_3.h @@ -0,0 +1,62 @@ +/* + vector_3.cpp - Vector library for bed leveling + Copyright (c) 2012 Lars Brubaker. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef VECTOR_3_H +#define VECTOR_3_H + +#ifdef ENABLE_AUTO_BED_LEVELING +class matrix_3x3; + +struct vector_3 +{ + float x, y, z; + + vector_3(); + vector_3(float x, float y, float z); + + static vector_3 cross(vector_3 a, vector_3 b); + + vector_3 operator+(vector_3 v); + vector_3 operator-(vector_3 v); + void normalize(); + float get_length(); + vector_3 get_normal(); + + void debug(char* title); + + void apply_rotation(matrix_3x3 matrix); +}; + +struct matrix_3x3 +{ + float matrix[9]; + + static matrix_3x3 create_from_rows(vector_3 row_0, vector_3 row_1, vector_3 row_2); + static matrix_3x3 create_look_at(vector_3 target, vector_3 up); + static matrix_3x3 create_inverse(matrix_3x3 original); + + void set_to_identity(); + + void debug(char* title); +}; + + +void apply_rotation_xyz(matrix_3x3 rotationMatrix, float &x, float& y, float& z); +#endif // ENABLE_AUTO_BED_LEVELING + +#endif // VECTOR_3_H diff --git a/README.md b/README.md index 0b0b74e085..de5528f053 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ Features: * Configurable serial port to support connection of wireless adaptors. * Automatic operation of extruder/cold-end cooling fans based on nozzle temperature * RC Servo Support, specify angle or duration for continuous rotation servos. +* Bed Auto Leveling. The default baudrate is 250000. This baudrate has less jitter and hence errors than the usual 115200 baud, but is less supported by drivers and host-environments. @@ -142,6 +143,8 @@ Implemented G Codes: * G10 - retract filament according to settings of M207 * G11 - retract recover filament according to settings of M208 * G28 - Home all Axis +* G29 - Detailed Z-Probe, probes the bed at 3 points. You must de at the home position for this to work correctly. +* G30 - Single Z Probe, probes bed at current XY location. * G90 - Use Absolute Coordinates * G91 - Use Relative Coordinates * G92 - Set current position to cordinates given @@ -210,6 +213,8 @@ M Codes * M303 - PID relay autotune S sets the target temperature. (default target temperature = 150C) * M304 - Set bed PID parameters P I and D * M400 - Finish all moves +* M401 - Lower z-probe if present +* M402 - Raise z-probe if present * M500 - stores paramters in EEPROM * M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily). * M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to. @@ -249,6 +254,69 @@ If all goes well the firmware is uploading That's ok. Enjoy Silky Smooth Printing. +=============================================== +Instructions for configuring Bed Auto Leveling +=============================================== +Uncomment the "ENABLE_AUTO_BED_LEVELING" define (commented by default) + +You will probably need a swivel Z-MIN endstop in the extruder. A rc servo do a great job. +Check the system working here: http://www.youtube.com/watch?v=3IKMeOYz-1Q (Enable English subtitles) +Teasing ;-) video: http://www.youtube.com/watch?v=x8eqSQNAyro + +In order to get the servo working, you need to enable: + +* \#define NUM_SERVOS 1 // Servo index starts with 0 for M280 command + +* \#define SERVO_ENDSTOPS {-1, -1, 0} // Servo index for X, Y, Z. Disable with -1 + +* \#define SERVO_ENDSTOP_ANGLES {0,0, 0,0, 165,60} // X,Y,Z Axis Extend and Retract angles + + +The first define tells firmware how many servos you have. +The second tells what axis this servo will be attached to. In the example above, we have a servo in Z axis. +The third one tells the angle in 2 situations: Probing (165º) and resting (60º). Check this with command M280 P0 S{angle} + +Next you need to define the Z endstop (probe) offset from hotend. +My preferred method: + +* a) Make a small mark in the bed with a marker/felt-tip pen. +* b) Place the hotend tip as *exactly* as possible on the mark, touching the bed. Raise the hotend 0.1mm (a regular paper thickness) and zero all axis (G92 X0 Y0 Z0); +* d) Raise the hotend 10mm (or more) for probe clearance, lower the Z probe (Z-Endstop) with M401 and place it just on that mark by moving X, Y and Z; +* e) Lower the Z in 0.1mm steps, with the probe always touching the mark (it may be necessary to adjust X and Y as well) until you hear the "click" meaning the mechanical endstop was trigged. You can confirm with M119; +* f) Now you have the probe in the same place as your hotend tip was before. Perform a M114 and write down the values, for example: X:24.3 Y:-31.4 Z:5.1; +* g) You can raise the z probe with M402 command; +* h) Fill the defines bellow multiplying the values by "-1" (just change the signal) + + +* \#define X_PROBE_OFFSET_FROM_EXTRUDER -24.3 +* \#define Y_PROBE_OFFSET_FROM_EXTRUDER 31.4 +* \#define Z_PROBE_OFFSET_FROM_EXTRUDER -5.1 + + +The following options define the probing positions. These are good starting values. +I recommend to keep a better clearance from borders in the first run and then make the probes as close as possible to borders: + +* \#define LEFT_PROBE_BED_POSITION 30 +* \#define RIGHT_PROBE_BED_POSITION 140 +* \#define BACK_PROBE_BED_POSITION 140 +* \#define FRONT_PROBE_BED_POSITION 30 + +A few more options: + +* \#define XY_TRAVEL_SPEED 6000 + +X and Y axis travel speed between probes, in mm/min. +Bear in mind that really fast moves may render step skipping. 6000 mm/min (100mm/s) is a good value. + +* \#define Z_RAISE_BEFORE_PROBING 10 +* \#define Z_RAISE_BETWEEN_PROBINGS 10 + +The Z axis is lifted when traveling to the first probe point by Z_RAISE_BEFORE_PROBING value +and then lifted when traveling from first to second and second to third point by Z_RAISE_BETWEEN_PROBINGS. +All values are in mm as usual. + +That's it.. enjoy never having to calibrate your Z endstop neither leveling your bed by hand anymore ;-) + From bca353cc126a5f189ebd9c9e3e0e284f3bb23747 Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Thu, 3 Oct 2013 19:24:53 +0200 Subject: [PATCH 055/256] Fixed duplicate define in fastio.h --- Marlin/fastio.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Marlin/fastio.h b/Marlin/fastio.h index b7fec27e10..f26a9f845f 100644 --- a/Marlin/fastio.h +++ b/Marlin/fastio.h @@ -1415,11 +1415,11 @@ pins #define DIO74_DDR DDRJ #define DIO74_PWM NULL -#define DIO73_PIN PINJ4 -#define DIO73_RPORT PINJ -#define DIO73_WPORT PORTJ -#define DIO73_DDR DDRJ -#define DIO73_PWM NULL +#define DIO75_PIN PINJ4 +#define DIO75_RPORT PINJ +#define DIO75_WPORT PORTJ +#define DIO75_DDR DDRJ +#define DIO75_PWM NULL #define DIO76_PIN PINJ5 #define DIO76_RPORT PINJ From d147a057ac75e52421c8d277655e2e48ca0376a3 Mon Sep 17 00:00:00 2001 From: bkubicek Date: Sun, 6 Oct 2013 21:14:51 +0200 Subject: [PATCH 056/256] Add the socalled "Babystepping" feature. It is a realtime control over the head position via the LCD menu system that works _while_ printing. Using it, one can e.g. tune the z-position in realtime, while printing the first layer. Also, lost steps can be manually added/removed, but thats not the prime feature. Stuff is placed into the Tune->Babystep * It is not possible to have realtime control via gcode sending due to the buffering, so I did not include a gcode yet. However, it could be added, but it movements will not be realtime then. Historically, a very similar thing was implemented for the "Kaamermaker" project, while Joris was babysitting his offspring, hence the name. say goodby to fuddling around with the z-axis. --- Marlin/Configuration_adv.h | 11 ++++ Marlin/stepper.cpp | 110 +++++++++++++++++++++++++++++++++++++ Marlin/stepper.h | 6 ++ Marlin/temperature.cpp | 25 ++++++++- Marlin/temperature.h | 5 ++ Marlin/ultralcd.cpp | 70 +++++++++++++++++++++++ 6 files changed, 226 insertions(+), 1 deletion(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 3cbe131c95..b47233a027 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -270,6 +270,17 @@ // Enable the option to stop SD printing when hitting and endstops, needs to be enabled from the LCD menu when this option is enabled. //#define ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED +// Babystepping enables the user to control the axis in tiny amounts, independently from the normal printing process +// it can e.g. be used to change z-positions in the print startup phase in realtime +// does not respect endstops! + +//#define BABYSTEPPING +//#define BABYSTEP_XY //not only z, but also XY + +#ifdef COREXY + #error BABYSTEPPING not implemented for COREXY yet. +#endif + // extruder advance constant (s2/mm3) // // advance (steps) = STEPS_PER_CUBIC_MM_E * EXTUDER_ADVANCE_K * cubic mm per second ^ 2 diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index 8b39a41d64..1dc3902b3e 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -997,6 +997,116 @@ void quickStop() ENABLE_STEPPER_DRIVER_INTERRUPT(); } +#ifdef BABYSTEPPING + + +void babystep(const uint8_t axis,const bool direction) +{ + //MUST ONLY BE CALLED BY A ISR, it depends on that no other ISR interrupts this + //store initial pin states + switch(axis) + { + case X_AXIS: + { + enable_x(); + uint8_t old_x_dir_pin= READ(X_DIR_PIN); //if dualzstepper, both point to same direction. + + //setup new step + WRITE(X_DIR_PIN,(INVERT_X_DIR)^direction); + #ifdef DUAL_X_CARRIAGE + WRITE(X2_DIR_PIN,(INVERT_X_DIR)^direction); + #endif + + //perform step + WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); + #ifdef DUAL_X_CARRIAGE + WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN); + #endif + { + float x=1./float(axis+1)/float(axis+2); //wait a tiny bit + } + WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); + #ifdef DUAL_X_CARRIAGE + WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN); + #endif + + //get old pin state back. + WRITE(X_DIR_PIN,old_x_dir_pin); + #ifdef DUAL_X_CARRIAGE + WRITE(X2_DIR_PIN,old_x_dir_pin); + #endif + + } + break; + case Y_AXIS: + { + enable_y(); + uint8_t old_y_dir_pin= READ(Y_DIR_PIN); //if dualzstepper, both point to same direction. + + //setup new step + WRITE(Y_DIR_PIN,(INVERT_Y_DIR)^direction); + #ifdef DUAL_Y_CARRIAGE + WRITE(Y2_DIR_PIN,(INVERT_Y_DIR)^direction); + #endif + + //perform step + WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN); + #ifdef DUAL_Y_CARRIAGE + WRITE(Y2_STEP_PIN, !INVERT_Y_STEP_PIN); + #endif + { + float x=1./float(axis+1)/float(axis+2); //wait a tiny bit + } + WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN); + #ifdef DUAL_Y_CARRIAGE + WRITE(Y2_STEP_PIN, INVERT_Y_STEP_PIN); + #endif + + //get old pin state back. + WRITE(Y_DIR_PIN,old_y_dir_pin); + #ifdef DUAL_Y_CARRIAGE + WRITE(Y2_DIR_PIN,old_y_dir_pin); + #endif + + } + break; + case Z_AXIS: + { + enable_z(); + uint8_t old_z_dir_pin= READ(Z_DIR_PIN); //if dualzstepper, both point to same direction. + //setup new step + WRITE(Z_DIR_PIN,(INVERT_Z_DIR)^direction); + #ifdef Z_DUAL_STEPPER_DRIVERS + WRITE(Z2_DIR_PIN,(INVERT_Z_DIR)^direction); + #endif + //perform step + WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); + #ifdef Z_DUAL_STEPPER_DRIVERS + WRITE(Z2_STEP_PIN, !INVERT_Z_STEP_PIN); + #endif + //wait a tiny bit + { + float x=1./float(axis+1); //absolutely useless + } + WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN); + #ifdef Z_DUAL_STEPPER_DRIVERS + WRITE(Z2_STEP_PIN, INVERT_Z_STEP_PIN); + #endif + + //get old pin state back. + WRITE(Z_DIR_PIN,old_z_dir_pin); + #ifdef Z_DUAL_STEPPER_DRIVERS + WRITE(Z2_DIR_PIN,old_z_dir_pin); + #endif + + } + break; + + default: break; + } +} +#endif //BABYSTEPPING + void digitalPotWrite(int address, int value) // From Arduino DigitalPotControl example { #if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1 diff --git a/Marlin/stepper.h b/Marlin/stepper.h index 82b41c90de..3a1cb0b5d9 100644 --- a/Marlin/stepper.h +++ b/Marlin/stepper.h @@ -92,4 +92,10 @@ void digipot_current(uint8_t driver, int current); void microstep_init(); void microstep_readings(); +#ifdef BABYSTEPPING + void babystep(const uint8_t axis,const bool direction); // perform a short step with a single stepper motor, outside of any convention +#endif + + + #endif diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index 9d87c54bbd..decab104d5 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -66,6 +66,10 @@ float current_temperature_bed = 0.0; unsigned char fanSpeedSoftPwm; #endif +#ifdef BABYSTEPPING + volatile int babystepsTodo[3]={0,0,0}; +#endif + //=========================================================================== //=============================private variables============================ //=========================================================================== @@ -1252,7 +1256,26 @@ ISR(TIMER0_COMPB_vect) bed_max_temp_error(); } #endif - } + } + +#ifdef BABYSTEPPING + for(uint8_t axis=0;axis<3;axis++) + { + int curTodo=babystepsTodo[axis]; //get rid of volatile for performance + + if(curTodo>0) + { + babystep(axis,/*fwd*/true); + babystepsTodo[axis]--; //less to do next time + } + else + if(curTodo<0) + { + babystep(axis,/*fwd*/false); + babystepsTodo[axis]++; //less to do next time + } + } +#endif //BABYSTEPPING } #ifdef PIDTEMP diff --git a/Marlin/temperature.h b/Marlin/temperature.h index 75ffcd06bf..a5974241c4 100644 --- a/Marlin/temperature.h +++ b/Marlin/temperature.h @@ -53,6 +53,11 @@ extern float current_temperature_bed; extern float bedKp,bedKi,bedKd; #endif + +#ifdef BABYSTEPPING + extern volatile int babystepsTodo[3]; +#endif + //high level conversion routines, for use outside of temperature.cpp //inline so that there is no performance decrease. //deg=degreeCelsius diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 05ace2d491..0a0df8f9e0 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -322,6 +322,68 @@ static void lcd_cooldown() lcd_return_to_status(); } +#ifdef BABYSTEPPING +static void lcd_babystep_x() +{ + if (encoderPosition != 0) + { + babystepsTodo[X_AXIS]+=(int)encoderPosition; + encoderPosition=0; + lcdDrawUpdate = 1; + } + if (lcdDrawUpdate) + { + lcd_implementation_drawedit(PSTR("Babystepping X"),""); + } + if (LCD_CLICKED) + { + lcd_quick_feedback(); + currentMenu = lcd_tune_menu; + encoderPosition = 0; + } +} + +static void lcd_babystep_y() +{ + if (encoderPosition != 0) + { + babystepsTodo[Y_AXIS]+=(int)encoderPosition; + encoderPosition=0; + lcdDrawUpdate = 1; + } + if (lcdDrawUpdate) + { + lcd_implementation_drawedit(PSTR("Babystepping Y"),""); + } + if (LCD_CLICKED) + { + lcd_quick_feedback(); + currentMenu = lcd_tune_menu; + encoderPosition = 0; + } +} + +static void lcd_babystep_z() +{ + if (encoderPosition != 0) + { + babystepsTodo[Z_AXIS]+=(int)encoderPosition; + encoderPosition=0; + lcdDrawUpdate = 1; + } + if (lcdDrawUpdate) + { + lcd_implementation_drawedit(PSTR("Babystepping Z"),""); + } + if (LCD_CLICKED) + { + lcd_quick_feedback(); + currentMenu = lcd_tune_menu; + encoderPosition = 0; + } +} +#endif //BABYSTEPPING + static void lcd_tune_menu() { START_MENU(); @@ -339,6 +401,14 @@ static void lcd_tune_menu() #endif MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &fanSpeed, 0, 255); MENU_ITEM_EDIT(int3, MSG_FLOW, &extrudemultiply, 10, 999); + +#ifdef BABYSTEPPING + #ifdef BABYSTEP_XY + MENU_ITEM(submenu, "Babystep X", lcd_babystep_x); + MENU_ITEM(submenu, "Babystep Y", lcd_babystep_y); + #endif //BABYSTEP_XY + MENU_ITEM(submenu, "Babystep Z", lcd_babystep_z); +#endif #ifdef FILAMENTCHANGEENABLE MENU_ITEM(gcode, MSG_FILAMENTCHANGE, PSTR("M600")); #endif From c38b0855c87639d0d2a16cb39649b2461158ee34 Mon Sep 17 00:00:00 2001 From: bkubicek Date: Sun, 6 Oct 2013 21:20:26 +0200 Subject: [PATCH 057/256] I think that filament change is ready for the masses. I have tested very often with my ultimaker. I strongly vote for it being a single gcode, because otherwise the triggering from the menu is terrible. --- Marlin/Configuration_adv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index b47233a027..614b2552c5 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -362,7 +362,7 @@ const unsigned int dropsegments=5; //everything with less than this number of st //adds support for experimental filament exchange support M600; requires display #ifdef ULTIPANEL - //#define FILAMENTCHANGEENABLE + #define FILAMENTCHANGEENABLE #ifdef FILAMENTCHANGEENABLE #define FILAMENTCHANGE_XPOS 3 #define FILAMENTCHANGE_YPOS 3 From b832f5b9f638060bf642a56fe38aca881ebc679b Mon Sep 17 00:00:00 2001 From: bkubicek Date: Mon, 7 Oct 2013 09:14:04 +0200 Subject: [PATCH 058/256] added delta tower babystepping. Its untested, but hopefully florian horsch will be able to try. also, removed some trouble for compilation with corexy. I think that babystepping is only possible in z for a delta tower. not sure if it would be usefull to step individual motors on a delta, i don't own one --- Marlin/Configuration_adv.h | 17 +++++++++++---- Marlin/stepper.cpp | 43 +++++++++++++++++++++++++++++++++++--- Marlin/ultralcd.cpp | 2 +- 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 614b2552c5..0392acaac7 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -273,12 +273,21 @@ // Babystepping enables the user to control the axis in tiny amounts, independently from the normal printing process // it can e.g. be used to change z-positions in the print startup phase in realtime // does not respect endstops! - //#define BABYSTEPPING -//#define BABYSTEP_XY //not only z, but also XY - -#ifdef COREXY +#ifdef BABYSTEPPING + #define BABYSTEP_XY //not only z, but also XY in the menu. more clutter, more functions + #define BABYSTEP_INVERT_Z false //true for inverse movements in Z + #define BABYSTEP_Z_MULTIPLICATOR 2 //faster z movements + + #ifdef COREXY #error BABYSTEPPING not implemented for COREXY yet. + #endif + + #ifdef DELTA + #ifdef BABYSTEP_XY + #error BABYSTEPPING only implemented for Z axis on deltabots. + #endif + #endif #endif // extruder advance constant (s2/mm3) diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index 1dc3902b3e..4f11ae9e37 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -1069,15 +1069,17 @@ void babystep(const uint8_t axis,const bool direction) #endif } - break; + break; + +#ifndef DELTA case Z_AXIS: { enable_z(); uint8_t old_z_dir_pin= READ(Z_DIR_PIN); //if dualzstepper, both point to same direction. //setup new step - WRITE(Z_DIR_PIN,(INVERT_Z_DIR)^direction); + WRITE(Z_DIR_PIN,(INVERT_Z_DIR)^direction^BABYSTEP_INVERT_Z); #ifdef Z_DUAL_STEPPER_DRIVERS - WRITE(Z2_DIR_PIN,(INVERT_Z_DIR)^direction); + WRITE(Z2_DIR_PIN,(INVERT_Z_DIR)^direction^BABYSTEP_INVERT_Z); #endif //perform step WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); @@ -1101,6 +1103,41 @@ void babystep(const uint8_t axis,const bool direction) } break; +#else //DELTA + case Z_AXIS: + { + enable_x(); + enable_y(); + enable_z(); + uint8_t old_x_dir_pin= READ(X_DIR_PIN); + uint8_t old_y_dir_pin= READ(Y_DIR_PIN); + uint8_t old_z_dir_pin= READ(Z_DIR_PIN); + //setup new step + WRITE(X_DIR_PIN,(INVERT_X_DIR)^direction^BABYSTEP_INVERT_Z); + WRITE(Y_DIR_PIN,(INVERT_Y_DIR)^direction^BABYSTEP_INVERT_Z); + WRITE(Z_DIR_PIN,(INVERT_Z_DIR)^direction^BABYSTEP_INVERT_Z); + + //perform step + WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); + WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN); + WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); + + //wait a tiny bit + { + float x=1./float(axis+1); //absolutely useless + } + WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); + WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN); + WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN); + + //get old pin state back. + WRITE(X_DIR_PIN,old_x_dir_pin); + WRITE(Y_DIR_PIN,old_y_dir_pin); + WRITE(Z_DIR_PIN,old_z_dir_pin); + + } + break; +#endif default: break; } diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 0a0df8f9e0..0e8c8697d4 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -367,7 +367,7 @@ static void lcd_babystep_z() { if (encoderPosition != 0) { - babystepsTodo[Z_AXIS]+=(int)encoderPosition; + babystepsTodo[Z_AXIS]+=BABYSTEP_Z_MULTIPLICATOR*(int)encoderPosition; encoderPosition=0; lcdDrawUpdate = 1; } From 73c82e7ad8ae286786f8a4d944a29ef0056c0966 Mon Sep 17 00:00:00 2001 From: alexborro Date: Tue, 8 Oct 2013 10:15:09 -0300 Subject: [PATCH 059/256] Clarifying M280 command in Bed Auto Leveling section. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index de5528f053..de8cde5f61 100644 --- a/README.md +++ b/README.md @@ -274,7 +274,7 @@ In order to get the servo working, you need to enable: The first define tells firmware how many servos you have. The second tells what axis this servo will be attached to. In the example above, we have a servo in Z axis. -The third one tells the angle in 2 situations: Probing (165º) and resting (60º). Check this with command M280 P0 S{angle} +The third one tells the angle in 2 situations: Probing (165º) and resting (60º). Check this with command M280 P0 S{angle} (example: M280 P0 S60 moves the servo to 60º) Next you need to define the Z endstop (probe) offset from hotend. My preferred method: From 7fad13a1e2cc35e577420801cd82e5feaa5d9c27 Mon Sep 17 00:00:00 2001 From: bkubicek Date: Sat, 12 Oct 2013 13:24:55 +0200 Subject: [PATCH 060/256] Reverse SD card file name order. This is _not_ automatically the cronological, since deleting a file will free the filesystem descriptor for it, which then will be used by the next file copied on it. Since this makes the auto0.g file very inaccessible, I put the option back, to have it in the prepare menu. this should satisfy https://github.com/ErikZalm/Marlin/pull/373 as a reminder, auto0.g will be executed every time after a boot with sd card present and file present. thereafter, if there is a file auto1.g this will be done. Thats IMHO the best place to put settings, and prepare heating. I also execute again after each (now again via the prepare menu) before starting a new print/ after a failed one. It for me 100% replaces any start.gcode form the slicers. --- Marlin/Configuration_adv.h | 11 +++++++++++ Marlin/ultralcd.cpp | 10 ++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 0392acaac7..23ca5efec8 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -257,6 +257,11 @@ #define SD_FINISHED_STEPPERRELEASE true //if sd support and the file is finished: disable steppers? #define SD_FINISHED_RELEASECOMMAND "M84 X Y Z E" // You might want to keep the z enabled so your bed stays in place. +#define SDCARD_RATHERRECENTFIRST //reverse file order of sd card menu display. Its sorted practically after the filesystem block order. +// if a file is deleted, it frees a block. hence, the order is not purely cronological. To still have auto0.g accessible, there is again the option to do that. +// using: +//#define MENU_ADDAUTOSTART + // The hardware watchdog should reset the Microcontroller disabling all outputs, in case the firmware gets stuck and doesn't do temperature regulation. //#define USE_WATCHDOG @@ -380,6 +385,12 @@ const unsigned int dropsegments=5; //everything with less than this number of st #define FILAMENTCHANGE_FINALRETRACT -100 #endif #endif + +#ifdef FILAMENTCHANGEENABLE + #ifdef EXTRUDER_RUNOUT_PREVENT + #error EXTRUDER_RUNOUT_PREVENT currently incompatible with FILAMENTCHANGE + #endif +#endif //=========================================================================== //============================= Define Defines ============================ diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 0e8c8697d4..12a9e23bc3 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -420,7 +420,9 @@ static void lcd_prepare_menu() START_MENU(); MENU_ITEM(back, MSG_MAIN, lcd_main_menu); #ifdef SDSUPPORT - //MENU_ITEM(function, MSG_AUTOSTART, lcd_autostart_sd); + #ifdef MENU_ADDAUTOSTART + MENU_ITEM(function, MSG_AUTOSTART, lcd_autostart_sd); + #endif #endif MENU_ITEM(gcode, MSG_DISABLE_STEPPERS, PSTR("M84")); MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28")); @@ -792,7 +794,11 @@ void lcd_sdcard_menu() { if (_menuItemNr == _lineNr) { - card.getfilename(i); + #ifndef SDCARD_RATHERRECENTFIRST + card.getfilename(i); + #else + card.getfilename(fileCnt-1-i); + #endif if (card.filenameIsDir) { MENU_ITEM(sddirectory, MSG_CARD_MENU, card.filename, card.longFilename); From dd3086d3f22337fd144672b85344d40777073ade Mon Sep 17 00:00:00 2001 From: Alex Borro Date: Sat, 12 Oct 2013 10:41:23 -0300 Subject: [PATCH 061/256] Show Temperature ADC values If "SHOW_TEMP_ADC_VALUES" is defined in Configuration_adv.h, the M105 command will present, after tradicional temperatures, the ADC value read from temp sensors. This is great for adjusting thermistor tables with thermocouple. From Pronterface you can see the ADC value and compare with a thermocouple reading.. then you just need to create your own thermistor table. Since this merge doesnt change the original information, it doesnt mess with PC software parsing (tested under Pronterface and Repetier-Host). --- Marlin/Configuration_adv.h | 4 ++++ Marlin/Marlin_main.cpp | 17 +++++++++++++++++ Marlin/temperature.h | 14 ++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 23ca5efec8..220458d918 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -40,6 +40,10 @@ #define AUTOTEMP_OLDWEIGHT 0.98 #endif +//Show Temperature ADC value +//The M105 command return, besides traditional information, the ADC value read from temperature sensors. +//#define SHOW_TEMP_ADC_VALUES + // extruder run-out prevention. //if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded //#define EXTRUDER_RUNOUT_PREVENT diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 932af13552..dc7edd0a5c 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1570,6 +1570,23 @@ void process_commands() SERIAL_PROTOCOLPGM(" B@:"); SERIAL_PROTOCOL(getHeaterPower(-1)); + #ifdef SHOW_TEMP_ADC_VALUES + #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1 + SERIAL_PROTOCOLPGM(" ADC B:"); + SERIAL_PROTOCOL_F(degBed(),1); + SERIAL_PROTOCOLPGM("C->"); + SERIAL_PROTOCOL_F(rawBedTemp()/OVERSAMPLENR,0); + #endif + for (int8_t cur_extruder = 0; cur_extruder < EXTRUDERS; ++cur_extruder) { + SERIAL_PROTOCOLPGM(" T"); + SERIAL_PROTOCOL(cur_extruder); + SERIAL_PROTOCOLPGM(":"); + SERIAL_PROTOCOL_F(degHotend(cur_extruder),1); + SERIAL_PROTOCOLPGM("C->"); + SERIAL_PROTOCOL_F(rawHotendTemp(cur_extruder)/OVERSAMPLENR,0); + } + #endif + SERIAL_PROTOCOLLN(""); return; break; diff --git a/Marlin/temperature.h b/Marlin/temperature.h index a5974241c4..1bf47e02ed 100644 --- a/Marlin/temperature.h +++ b/Marlin/temperature.h @@ -35,6 +35,10 @@ void manage_heater(); //it is critical that this is called periodically. // do not use these routines and variables outside of temperature.cpp extern int target_temperature[EXTRUDERS]; extern float current_temperature[EXTRUDERS]; +#ifdef SHOW_TEMP_ADC_VALUES + extern int current_temperature_raw[EXTRUDERS]; + extern int current_temperature_bed_raw; +#endif extern int target_temperature_bed; extern float current_temperature_bed; #ifdef TEMP_SENSOR_1_AS_REDUNDANT @@ -66,6 +70,16 @@ FORCE_INLINE float degHotend(uint8_t extruder) { return current_temperature[extruder]; }; +#ifdef SHOW_TEMP_ADC_VALUES + FORCE_INLINE float rawHotendTemp(uint8_t extruder) { + return current_temperature_raw[extruder]; + }; + + FORCE_INLINE float rawBedTemp() { + return current_temperature_bed_raw; + }; +#endif + FORCE_INLINE float degBed() { return current_temperature_bed; }; From 6f85a8c7aa95474c653e326a3727e252d280d057 Mon Sep 17 00:00:00 2001 From: Alex Borro Date: Sat, 12 Oct 2013 17:28:11 -0300 Subject: [PATCH 062/256] Bed auto Leveling change: Raise Z before homing - Added "Z_RAISE_BEFORE_HOMING" for raising Z the defined distance before homing. This is useful to avoid Z-Probe collision when hotend is near bed. - Fixed the issue of Z not going bellow Z_PROBE_OFFSET when "min_software_endstops" is true. Now the Z_PROBE_OFFSET is not set in Z_MIN_POS, it is added after homing. --- Marlin/Configuration.h | 10 ++++------ Marlin/Marlin_main.cpp | 24 ++++++++++++++++++------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 502ebd4389..459640fbc3 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -309,7 +309,10 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #define X_PROBE_OFFSET_FROM_EXTRUDER -25 #define Y_PROBE_OFFSET_FROM_EXTRUDER -29 #define Z_PROBE_OFFSET_FROM_EXTRUDER -12.35 - + + #define Z_RAISE_BEFORE_HOMING 4 // (in mm) Raise Z before homing (G28) for Probe Clearance. + // Be sure you have this distance over your Z_MAX_POS in case + #define XY_TRAVEL_SPEED 8000 // X and Y axis travel speed between probes, in mm/min #define Z_RAISE_BEFORE_PROBING 15 //How much the extruder will be raised before traveling to the first probing point. @@ -330,12 +333,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #define Y_MAX_POS 205 #define Y_MIN_POS 0 #define Z_MAX_POS 200 - -#ifndef ENABLE_AUTO_BED_LEVELING #define Z_MIN_POS 0 -#else -#define Z_MIN_POS (-1*Z_PROBE_OFFSET_FROM_EXTRUDER) //With Auto Bed Leveling, the Z_MIN MUST have the same distance as Z_PROBE -#endif #define X_MAX_LENGTH (X_MAX_POS - X_MIN_POS) #define Y_MAX_LENGTH (Y_MAX_POS - Y_MIN_POS) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index dc7edd0a5c..2a3534221e 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -920,19 +920,28 @@ static void homeaxis(int axis) { axis_home_dir = x_home_dir(active_extruder); #endif + current_position[axis] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + // Engage Servo endstop if enabled #ifdef SERVO_ENDSTOPS -#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) - if (axis==Z_AXIS) engage_z_probe(); - else -#endif + #if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) + if (axis==Z_AXIS) { + #if defined (Z_RAISE_BEFORE_HOMING) && (Z_RAISE_BEFORE_HOMING > 0) + destination[axis] = Z_RAISE_BEFORE_HOMING * axis_home_dir * (-1); // Set destination away from bed + feedrate = max_feedrate[axis]; + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate, active_extruder); + st_synchronize(); + #endif + engage_z_probe(); + } + else + #endif if (servo_endstops[axis] > -1) { servos[servo_endstops[axis]].write(servo_endstop_angles[axis * 2]); } #endif - current_position[axis] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); destination[axis] = 1.5 * max_length(axis) * axis_home_dir; feedrate = homing_feedrate[axis]; plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); @@ -1198,6 +1207,9 @@ void process_commands() current_position[Z_AXIS]=code_value()+add_homeing[2]; } } + #ifdef ENABLE_AUTO_BED_LEVELING + current_position[Z_AXIS] -= Z_PROBE_OFFSET_FROM_EXTRUDER; //Add Z_Probe offset (the distance is negative) + #endif plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); #endif // else DELTA From 87e28c059980bcf85633cc1f5ccfdf0b3a6d088d Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Sun, 20 Oct 2013 09:55:15 +0200 Subject: [PATCH 063/256] Added ifdefs to blinkm --- Marlin/BlinkM.cpp | 4 ++++ Marlin/Marlin_main.cpp | 2 ++ 2 files changed, 6 insertions(+) diff --git a/Marlin/BlinkM.cpp b/Marlin/BlinkM.cpp index 7b8a7867c2..52a45859ff 100644 --- a/Marlin/BlinkM.cpp +++ b/Marlin/BlinkM.cpp @@ -2,6 +2,8 @@ BlinkM.cpp - Library for controlling a BlinkM over i2c Created by Tim Koster, August 21 2013. */ +#ifdef BLINKM + #if (ARDUINO >= 100) # include "Arduino.h" #else @@ -22,3 +24,5 @@ void SendColors(byte red, byte grn, byte blu) Wire.endTransmission(); } +#endif //BLINKM + diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index d62c2f6b90..d0262d30e0 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -44,8 +44,10 @@ #include "language.h" #include "pins_arduino.h" +#ifdef BLINKM #include "BlinkM.h" #include "Wire.h" +#endif #if NUM_SERVOS > 0 #include "Servo.h" From bf27e79e7498b48c945807091aa4be98da749453 Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Sun, 20 Oct 2013 10:06:02 +0200 Subject: [PATCH 064/256] Small BlinkM fix --- Marlin/BlinkM.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Marlin/BlinkM.cpp b/Marlin/BlinkM.cpp index 52a45859ff..de604ecd35 100644 --- a/Marlin/BlinkM.cpp +++ b/Marlin/BlinkM.cpp @@ -2,6 +2,7 @@ BlinkM.cpp - Library for controlling a BlinkM over i2c Created by Tim Koster, August 21 2013. */ +#include "Marlin.h" #ifdef BLINKM #if (ARDUINO >= 100) From 667d278f54aad426316775807e558c9dcc187c90 Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Sun, 20 Oct 2013 10:16:46 +0200 Subject: [PATCH 065/256] Revert "Fix for Viki display" This reverts commit 314fd13c39e1a5420adfbc9127339da80a1039aa. --- Marlin/ultralcd.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 12a9e23bc3..895c3ed4e9 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -104,6 +104,7 @@ static void menu_action_setting_edit_callback_long5(const char* pstr, unsigned l if (encoderPosition > 0x8000) encoderPosition = 0; \ if (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM < currentMenuViewOffset) currentMenuViewOffset = encoderPosition / ENCODER_STEPS_PER_MENU_ITEM;\ uint8_t _lineNr = currentMenuViewOffset, _menuItemNr; \ + bool wasClicked = LCD_CLICKED;\ for(uint8_t _drawLineNr = 0; _drawLineNr < LCD_HEIGHT; _drawLineNr++, _lineNr++) { \ _menuItemNr = 0; #define MENU_ITEM(type, label, args...) do { \ @@ -142,7 +143,6 @@ uint8_t currentMenuViewOffset; /* scroll offset in the current menu uint32_t blocking_enc; uint8_t lastEncoderBits; uint32_t encoderPosition; -bool wasClicked; #if (SDCARDDETECT > 0) bool lcd_oldcardstatus; #endif @@ -1042,7 +1042,6 @@ void lcd_update() if (lcd_next_update_millis < millis()) { - wasClicked = LCD_CLICKED; #ifdef ULTIPANEL #ifdef REPRAPWORLD_KEYPAD if (REPRAPWORLD_KEYPAD_MOVE_Z_UP) { From 8a08cca0f2c16d6863bacefa41966cee17ee5b26 Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Sun, 20 Oct 2013 12:12:35 +0200 Subject: [PATCH 066/256] Added temperature status less. Hopefully fixed viky button handling without braking other boards --- Marlin/Configuration.h | 5 + Marlin/Marlin_main.cpp | 38 +- Marlin/pins.h | 7 + .../ultralcd_implementation_hitachi_HD44780.h | 1511 +++++++++-------- 4 files changed, 810 insertions(+), 751 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 974709ff44..8496a8b24b 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -540,6 +540,11 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of // Increase the FAN pwm frequency. Removes the PWM noise but increases heating in the FET/Arduino //#define FAST_PWM_FAN +// Temperature status leds that display the hotend and bet temperature. +// If alle hotends and bed temperature and temperature setpoint are < 54C then the BLUE led is on. +// Otherwise the RED led is on. There is 1C hysteresis. +//#define TEMP_STAT_LEDS + // Use software PWM to drive the fan, as for the heaters. This uses a very low frequency // which is not ass annoying as with the hardware PWM. On the other hand, if this frequency // is too low, you should also increment SOFT_PWM_SCALE. diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index d0262d30e0..e431ad6c12 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -2938,6 +2938,39 @@ void controllerFan() } #endif +#ifdef TEMP_STAT_LEDS +static bool blue_led = false; +static bool red_led = false; +static uint32_t stat_update = 0; + +void handle_status_leds(void) { + float max_temp = 0.0; + if(millis() > stat_update) { + stat_update += 500; // Update every 0.5s + for (int8_t cur_extruder = 0; cur_extruder < EXTRUDERS; ++cur_extruder) { + max_temp = max(max_temp, degHotend(cur_extruder)); + max_temp = max(max_temp, degTargetHotend(cur_extruder)); + } + #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1 + max_temp = max(max_temp, degTargetBed()); + max_temp = max(max_temp, degBed()); + #endif + if((max_temp > 55.0) && (red_led == false)) { + digitalWrite(STAT_LED_RED, 1); + digitalWrite(STAT_LED_BLUE, 0); + red_led = true; + blue_led = false; + } + if((max_temp < 54.0) && (blue_led == false)) { + digitalWrite(STAT_LED_RED, 0); + digitalWrite(STAT_LED_BLUE, 1); + red_led = false; + blue_led = true; + } + } +} +#endif + void manage_inactivity() { if( (millis() - previous_millis_cmd) > max_inactive_time ) @@ -2991,7 +3024,10 @@ void manage_inactivity() memcpy(destination,current_position,sizeof(destination)); prepare_move(); } - #endif + #endif + #ifdef TEMP_STAT_LEDS + handle_status_leds(); + #endif check_axes_activity(); } diff --git a/Marlin/pins.h b/Marlin/pins.h index 1ae3cb486b..12dd931346 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -544,6 +544,13 @@ #endif #endif + #ifdef TEMP_STAT_LEDS + #if MOTHERBOARD == 67 + #define STAT_LED_RED 6 + #define STAT_LED_BLUE 11 + #endif + #endif + #ifdef ULTRA_LCD #ifdef NEWPANEL diff --git a/Marlin/ultralcd_implementation_hitachi_HD44780.h b/Marlin/ultralcd_implementation_hitachi_HD44780.h index ac397f6753..36462d8872 100644 --- a/Marlin/ultralcd_implementation_hitachi_HD44780.h +++ b/Marlin/ultralcd_implementation_hitachi_HD44780.h @@ -1,750 +1,761 @@ -#ifndef ULTRA_LCD_IMPLEMENTATION_HITACHI_HD44780_H -#define ULTRA_LCD_IMPLEMENTATION_HITACHI_HD44780_H - -/** -* Implementation of the LCD display routines for a hitachi HD44780 display. These are common LCD character displays. -* When selecting the rusian language, a slightly different LCD implementation is used to handle UTF8 characters. -**/ - -#ifndef REPRAPWORLD_KEYPAD -extern volatile uint8_t buttons; //the last checked buttons in a bit array. -#else -extern volatile uint16_t buttons; //an extended version of the last checked buttons in a bit array. -#endif - -//////////////////////////////////// -// Setup button and encode mappings for each panel (into 'buttons' variable -// -// This is just to map common functions (across different panels) onto the same -// macro name. The mapping is independent of whether the button is directly connected or -// via a shift/i2c register. - -#ifdef ULTIPANEL -// All Ultipanels might have an encoder - so this is always be mapped onto first two bits -#define BLEN_B 1 -#define BLEN_A 0 - -#define EN_B (1< -1 - // encoder click is directly connected - #define BLEN_C 2 - #define EN_C (1< -1 - // the pause/stop/restart button is connected to BTN_ENC when used - #define B_ST (EN_C) // Map the pause/stop/resume button into its normalized functional name - #define LCD_CLICKED (buttons&(B_MI|B_RI|B_ST)) // pause/stop button also acts as click until we implement proper pause/stop. - #else - #define LCD_CLICKED (buttons&(B_MI|B_RI)) - #endif - - // I2C buttons take too long to read inside an interrupt context and so we read them during lcd_update - #define LCD_HAS_SLOW_BUTTONS - -#elif defined(LCD_I2C_PANELOLU2) - // encoder click can be read through I2C if not directly connected - #if BTN_ENC <= 0 - #define B_I2C_BTN_OFFSET 3 // (the first three bit positions reserved for EN_A, EN_B, EN_C) - - #define B_MI (PANELOLU2_ENCODER_C< - #include - #include - #define LCD_CLASS LiquidCrystal_I2C - LCD_CLASS lcd(LCD_I2C_ADDRESS,LCD_I2C_PIN_EN,LCD_I2C_PIN_RW,LCD_I2C_PIN_RS,LCD_I2C_PIN_D4,LCD_I2C_PIN_D5,LCD_I2C_PIN_D6,LCD_I2C_PIN_D7); - -#elif defined(LCD_I2C_TYPE_MCP23017) - //for the LED indicators (which maybe mapped to different things in lcd_implementation_update_indicators()) - #define LED_A 0x04 //100 - #define LED_B 0x02 //010 - #define LED_C 0x01 //001 - - #define LCD_HAS_STATUS_INDICATORS - - #include - #include - #define LCD_CLASS LiquidTWI2 - LCD_CLASS lcd(LCD_I2C_ADDRESS); - -#elif defined(LCD_I2C_TYPE_MCP23008) - #include - #include - #define LCD_CLASS LiquidTWI2 - LCD_CLASS lcd(LCD_I2C_ADDRESS); - -#elif defined(LCD_I2C_TYPE_PCA8574) - #include - #define LCD_CLASS LiquidCrystal_I2C - LCD_CLASS lcd(LCD_I2C_ADDRESS, LCD_WIDTH, LCD_HEIGHT); - -#else - // Standard directly connected LCD implementations - #if LANGUAGE_CHOICE == 6 - #include "LiquidCrystalRus.h" - #define LCD_CLASS LiquidCrystalRus - #else - #include - #define LCD_CLASS LiquidCrystal - #endif - LCD_CLASS lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5,LCD_PINS_D6,LCD_PINS_D7); //RS,Enable,D4,D5,D6,D7 -#endif - -/* Custom characters defined in the first 8 characters of the LCD */ -#define LCD_STR_BEDTEMP "\x00" -#define LCD_STR_DEGREE "\x01" -#define LCD_STR_THERMOMETER "\x02" -#define LCD_STR_UPLEVEL "\x03" -#define LCD_STR_REFRESH "\x04" -#define LCD_STR_FOLDER "\x05" -#define LCD_STR_FEEDRATE "\x06" -#define LCD_STR_CLOCK "\x07" -#define LCD_STR_ARROW_RIGHT "\x7E" /* from the default character set */ - -static void lcd_implementation_init() -{ - byte bedTemp[8] = - { - B00000, - B11111, - B10101, - B10001, - B10101, - B11111, - B00000, - B00000 - }; //thanks Sonny Mounicou - byte degree[8] = - { - B01100, - B10010, - B10010, - B01100, - B00000, - B00000, - B00000, - B00000 - }; - byte thermometer[8] = - { - B00100, - B01010, - B01010, - B01010, - B01010, - B10001, - B10001, - B01110 - }; - byte uplevel[8]={ - B00100, - B01110, - B11111, - B00100, - B11100, - B00000, - B00000, - B00000 - }; //thanks joris - byte refresh[8]={ - B00000, - B00110, - B11001, - B11000, - B00011, - B10011, - B01100, - B00000, - }; //thanks joris - byte folder [8]={ - B00000, - B11100, - B11111, - B10001, - B10001, - B11111, - B00000, - B00000 - }; //thanks joris - byte feedrate [8]={ - B11100, - B10000, - B11000, - B10111, - B00101, - B00110, - B00101, - B00000 - }; //thanks Sonny Mounicou - byte clock [8]={ - B00000, - B01110, - B10011, - B10101, - B10001, - B01110, - B00000, - B00000 - }; //thanks Sonny Mounicou - -#if defined(LCDI2C_TYPE_PCF8575) - lcd.begin(LCD_WIDTH, LCD_HEIGHT); - #ifdef LCD_I2C_PIN_BL - lcd.setBacklightPin(LCD_I2C_PIN_BL,POSITIVE); - lcd.setBacklight(HIGH); - #endif - -#elif defined(LCD_I2C_TYPE_MCP23017) - lcd.setMCPType(LTI_TYPE_MCP23017); - lcd.begin(LCD_WIDTH, LCD_HEIGHT); - lcd.setBacklight(0); //set all the LEDs off to begin with - -#elif defined(LCD_I2C_TYPE_MCP23008) - lcd.setMCPType(LTI_TYPE_MCP23008); - lcd.begin(LCD_WIDTH, LCD_HEIGHT); - -#elif defined(LCD_I2C_TYPE_PCA8574) - lcd.init(); - lcd.backlight(); - -#else - lcd.begin(LCD_WIDTH, LCD_HEIGHT); -#endif - - lcd.createChar(LCD_STR_BEDTEMP[0], bedTemp); - lcd.createChar(LCD_STR_DEGREE[0], degree); - lcd.createChar(LCD_STR_THERMOMETER[0], thermometer); - lcd.createChar(LCD_STR_UPLEVEL[0], uplevel); - lcd.createChar(LCD_STR_REFRESH[0], refresh); - lcd.createChar(LCD_STR_FOLDER[0], folder); - lcd.createChar(LCD_STR_FEEDRATE[0], feedrate); - lcd.createChar(LCD_STR_CLOCK[0], clock); - lcd.clear(); -} -static void lcd_implementation_clear() -{ - lcd.clear(); -} -/* Arduino < 1.0.0 is missing a function to print PROGMEM strings, so we need to implement our own */ -static void lcd_printPGM(const char* str) -{ - char c; - while((c = pgm_read_byte(str++)) != '\0') - { - lcd.write(c); - } -} -/* -Possible status screens: -16x2 |0123456789012345| - |000/000 B000/000| - |Status line.....| - -16x4 |0123456789012345| - |000/000 B000/000| - |SD100% Z000.0| - |F100% T--:--| - |Status line.....| - -20x2 |01234567890123456789| - |T000/000D B000/000D | - |Status line.........| - -20x4 |01234567890123456789| - |T000/000D B000/000D | - |X+000.0 Y+000.0 Z+000.0| - |F100% SD100% T--:--| - |Status line.........| - -20x4 |01234567890123456789| - |T000/000D B000/000D | - |T000/000D Z000.0| - |F100% SD100% T--:--| - |Status line.........| -*/ -static void lcd_implementation_status_screen() -{ - int tHotend=int(degHotend(0) + 0.5); - int tTarget=int(degTargetHotend(0) + 0.5); - -#if LCD_WIDTH < 20 - lcd.setCursor(0, 0); - lcd.print(itostr3(tHotend)); - lcd.print('/'); - lcd.print(itostr3left(tTarget)); - -# if EXTRUDERS > 1 || TEMP_SENSOR_BED != 0 - //If we have an 2nd extruder or heated bed, show that in the top right corner - lcd.setCursor(8, 0); -# if EXTRUDERS > 1 - tHotend = int(degHotend(1) + 0.5); - tTarget = int(degTargetHotend(1) + 0.5); - lcd.print(LCD_STR_THERMOMETER[0]); -# else//Heated bed - tHotend=int(degBed() + 0.5); - tTarget=int(degTargetBed() + 0.5); - lcd.print(LCD_STR_BEDTEMP[0]); -# endif - lcd.print(itostr3(tHotend)); - lcd.print('/'); - lcd.print(itostr3left(tTarget)); -# endif//EXTRUDERS > 1 || TEMP_SENSOR_BED != 0 - -#else//LCD_WIDTH > 19 - lcd.setCursor(0, 0); - lcd.print(LCD_STR_THERMOMETER[0]); - lcd.print(itostr3(tHotend)); - lcd.print('/'); - lcd.print(itostr3left(tTarget)); - lcd_printPGM(PSTR(LCD_STR_DEGREE " ")); - if (tTarget < 10) - lcd.print(' '); - -# if EXTRUDERS > 1 || TEMP_SENSOR_BED != 0 - //If we have an 2nd extruder or heated bed, show that in the top right corner - lcd.setCursor(10, 0); -# if EXTRUDERS > 1 - tHotend = int(degHotend(1) + 0.5); - tTarget = int(degTargetHotend(1) + 0.5); - lcd.print(LCD_STR_THERMOMETER[0]); -# else//Heated bed - tHotend=int(degBed() + 0.5); - tTarget=int(degTargetBed() + 0.5); - lcd.print(LCD_STR_BEDTEMP[0]); -# endif - lcd.print(itostr3(tHotend)); - lcd.print('/'); - lcd.print(itostr3left(tTarget)); - lcd_printPGM(PSTR(LCD_STR_DEGREE " ")); - if (tTarget < 10) - lcd.print(' '); -# endif//EXTRUDERS > 1 || TEMP_SENSOR_BED != 0 -#endif//LCD_WIDTH > 19 - -#if LCD_HEIGHT > 2 -//Lines 2 for 4 line LCD -# if LCD_WIDTH < 20 -# ifdef SDSUPPORT - lcd.setCursor(0, 2); - lcd_printPGM(PSTR("SD")); - if (IS_SD_PRINTING) - lcd.print(itostr3(card.percentDone())); - else - lcd_printPGM(PSTR("---")); - lcd.print('%'); -# endif//SDSUPPORT -# else//LCD_WIDTH > 19 -# if EXTRUDERS > 1 && TEMP_SENSOR_BED != 0 - //If we both have a 2nd extruder and a heated bed, show the heated bed temp on the 2nd line on the left, as the first line is filled with extruder temps - tHotend=int(degBed() + 0.5); - tTarget=int(degTargetBed() + 0.5); - - lcd.setCursor(0, 1); - lcd.print(LCD_STR_BEDTEMP[0]); - lcd.print(itostr3(tHotend)); - lcd.print('/'); - lcd.print(itostr3left(tTarget)); - lcd_printPGM(PSTR(LCD_STR_DEGREE " ")); - if (tTarget < 10) - lcd.print(' '); -# else - lcd.setCursor(0,1); - lcd.print('X'); - lcd.print(ftostr3(current_position[X_AXIS])); - lcd_printPGM(PSTR(" Y")); - lcd.print(ftostr3(current_position[Y_AXIS])); -# endif//EXTRUDERS > 1 || TEMP_SENSOR_BED != 0 -# endif//LCD_WIDTH > 19 - lcd.setCursor(LCD_WIDTH - 8, 1); - lcd.print('Z'); - lcd.print(ftostr32(current_position[Z_AXIS])); -#endif//LCD_HEIGHT > 2 - -#if LCD_HEIGHT > 3 - lcd.setCursor(0, 2); - lcd.print(LCD_STR_FEEDRATE[0]); - lcd.print(itostr3(feedmultiply)); - lcd.print('%'); -# if LCD_WIDTH > 19 -# ifdef SDSUPPORT - lcd.setCursor(7, 2); - lcd_printPGM(PSTR("SD")); - if (IS_SD_PRINTING) - lcd.print(itostr3(card.percentDone())); - else - lcd_printPGM(PSTR("---")); - lcd.print('%'); -# endif//SDSUPPORT -# endif//LCD_WIDTH > 19 - lcd.setCursor(LCD_WIDTH - 6, 2); - lcd.print(LCD_STR_CLOCK[0]); - if(starttime != 0) - { - uint16_t time = millis()/60000 - starttime/60000; - lcd.print(itostr2(time/60)); - lcd.print(':'); - lcd.print(itostr2(time%60)); - }else{ - lcd_printPGM(PSTR("--:--")); - } -#endif - - //Status message line on the last line - lcd.setCursor(0, LCD_HEIGHT - 1); - lcd.print(lcd_status_message); -} -static void lcd_implementation_drawmenu_generic(uint8_t row, const char* pstr, char pre_char, char post_char) -{ - char c; - //Use all characters in narrow LCDs - #if LCD_WIDTH < 20 - uint8_t n = LCD_WIDTH - 1 - 1; - #else - uint8_t n = LCD_WIDTH - 1 - 2; - #endif - lcd.setCursor(0, row); - lcd.print(pre_char); - while( ((c = pgm_read_byte(pstr)) != '\0') && (n>0) ) - { - lcd.print(c); - pstr++; - n--; - } - while(n--) - lcd.print(' '); - lcd.print(post_char); - lcd.print(' '); -} -static void lcd_implementation_drawmenu_setting_edit_generic(uint8_t row, const char* pstr, char pre_char, char* data) -{ - char c; - //Use all characters in narrow LCDs - #if LCD_WIDTH < 20 - uint8_t n = LCD_WIDTH - 1 - 1 - strlen(data); - #else - uint8_t n = LCD_WIDTH - 1 - 2 - strlen(data); - #endif - lcd.setCursor(0, row); - lcd.print(pre_char); - while( ((c = pgm_read_byte(pstr)) != '\0') && (n>0) ) - { - lcd.print(c); - pstr++; - n--; - } - lcd.print(':'); - while(n--) - lcd.print(' '); - lcd.print(data); -} -static void lcd_implementation_drawmenu_setting_edit_generic_P(uint8_t row, const char* pstr, char pre_char, const char* data) -{ - char c; - //Use all characters in narrow LCDs - #if LCD_WIDTH < 20 - uint8_t n = LCD_WIDTH - 1 - 1 - strlen_P(data); - #else - uint8_t n = LCD_WIDTH - 1 - 2 - strlen_P(data); - #endif - lcd.setCursor(0, row); - lcd.print(pre_char); - while( ((c = pgm_read_byte(pstr)) != '\0') && (n>0) ) - { - lcd.print(c); - pstr++; - n--; - } - lcd.print(':'); - while(n--) - lcd.print(' '); - lcd_printPGM(data); -} -#define lcd_implementation_drawmenu_setting_edit_int3_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', itostr3(*(data))) -#define lcd_implementation_drawmenu_setting_edit_int3(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', itostr3(*(data))) -#define lcd_implementation_drawmenu_setting_edit_float3_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr3(*(data))) -#define lcd_implementation_drawmenu_setting_edit_float3(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr3(*(data))) -#define lcd_implementation_drawmenu_setting_edit_float32_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr32(*(data))) -#define lcd_implementation_drawmenu_setting_edit_float32(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr32(*(data))) -#define lcd_implementation_drawmenu_setting_edit_float5_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr5(*(data))) -#define lcd_implementation_drawmenu_setting_edit_float5(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr5(*(data))) -#define lcd_implementation_drawmenu_setting_edit_float52_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr52(*(data))) -#define lcd_implementation_drawmenu_setting_edit_float52(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr52(*(data))) -#define lcd_implementation_drawmenu_setting_edit_float51_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr51(*(data))) -#define lcd_implementation_drawmenu_setting_edit_float51(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr51(*(data))) -#define lcd_implementation_drawmenu_setting_edit_long5_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr5(*(data))) -#define lcd_implementation_drawmenu_setting_edit_long5(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr5(*(data))) -#define lcd_implementation_drawmenu_setting_edit_bool_selected(row, pstr, pstr2, data) lcd_implementation_drawmenu_setting_edit_generic_P(row, pstr, '>', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF)) -#define lcd_implementation_drawmenu_setting_edit_bool(row, pstr, pstr2, data) lcd_implementation_drawmenu_setting_edit_generic_P(row, pstr, ' ', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF)) - -//Add version for callback functions -#define lcd_implementation_drawmenu_setting_edit_callback_int3_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', itostr3(*(data))) -#define lcd_implementation_drawmenu_setting_edit_callback_int3(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', itostr3(*(data))) -#define lcd_implementation_drawmenu_setting_edit_callback_float3_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr3(*(data))) -#define lcd_implementation_drawmenu_setting_edit_callback_float3(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr3(*(data))) -#define lcd_implementation_drawmenu_setting_edit_callback_float32_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr32(*(data))) -#define lcd_implementation_drawmenu_setting_edit_callback_float32(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr32(*(data))) -#define lcd_implementation_drawmenu_setting_edit_callback_float5_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr5(*(data))) -#define lcd_implementation_drawmenu_setting_edit_callback_float5(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr5(*(data))) -#define lcd_implementation_drawmenu_setting_edit_callback_float52_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr52(*(data))) -#define lcd_implementation_drawmenu_setting_edit_callback_float52(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr52(*(data))) -#define lcd_implementation_drawmenu_setting_edit_callback_float51_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr51(*(data))) -#define lcd_implementation_drawmenu_setting_edit_callback_float51(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr51(*(data))) -#define lcd_implementation_drawmenu_setting_edit_callback_long5_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr5(*(data))) -#define lcd_implementation_drawmenu_setting_edit_callback_long5(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr5(*(data))) -#define lcd_implementation_drawmenu_setting_edit_callback_bool_selected(row, pstr, pstr2, data, callback) lcd_implementation_drawmenu_setting_edit_generic_P(row, pstr, '>', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF)) -#define lcd_implementation_drawmenu_setting_edit_callback_bool(row, pstr, pstr2, data, callback) lcd_implementation_drawmenu_setting_edit_generic_P(row, pstr, ' ', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF)) - - -void lcd_implementation_drawedit(const char* pstr, char* value) -{ - lcd.setCursor(1, 1); - lcd_printPGM(pstr); - lcd.print(':'); - #if LCD_WIDTH < 20 - lcd.setCursor(LCD_WIDTH - strlen(value), 1); - #else - lcd.setCursor(LCD_WIDTH -1 - strlen(value), 1); - #endif - lcd.print(value); -} -static void lcd_implementation_drawmenu_sdfile_selected(uint8_t row, const char* pstr, const char* filename, char* longFilename) -{ - char c; - uint8_t n = LCD_WIDTH - 1; - lcd.setCursor(0, row); - lcd.print('>'); - if (longFilename[0] != '\0') - { - filename = longFilename; - longFilename[LCD_WIDTH-1] = '\0'; - } - while( ((c = *filename) != '\0') && (n>0) ) - { - lcd.print(c); - filename++; - n--; - } - while(n--) - lcd.print(' '); -} -static void lcd_implementation_drawmenu_sdfile(uint8_t row, const char* pstr, const char* filename, char* longFilename) -{ - char c; - uint8_t n = LCD_WIDTH - 1; - lcd.setCursor(0, row); - lcd.print(' '); - if (longFilename[0] != '\0') - { - filename = longFilename; - longFilename[LCD_WIDTH-1] = '\0'; - } - while( ((c = *filename) != '\0') && (n>0) ) - { - lcd.print(c); - filename++; - n--; - } - while(n--) - lcd.print(' '); -} -static void lcd_implementation_drawmenu_sddirectory_selected(uint8_t row, const char* pstr, const char* filename, char* longFilename) -{ - char c; - uint8_t n = LCD_WIDTH - 2; - lcd.setCursor(0, row); - lcd.print('>'); - lcd.print(LCD_STR_FOLDER[0]); - if (longFilename[0] != '\0') - { - filename = longFilename; - longFilename[LCD_WIDTH-2] = '\0'; - } - while( ((c = *filename) != '\0') && (n>0) ) - { - lcd.print(c); - filename++; - n--; - } - while(n--) - lcd.print(' '); -} -static void lcd_implementation_drawmenu_sddirectory(uint8_t row, const char* pstr, const char* filename, char* longFilename) -{ - char c; - uint8_t n = LCD_WIDTH - 2; - lcd.setCursor(0, row); - lcd.print(' '); - lcd.print(LCD_STR_FOLDER[0]); - if (longFilename[0] != '\0') - { - filename = longFilename; - longFilename[LCD_WIDTH-2] = '\0'; - } - while( ((c = *filename) != '\0') && (n>0) ) - { - lcd.print(c); - filename++; - n--; - } - while(n--) - lcd.print(' '); -} -#define lcd_implementation_drawmenu_back_selected(row, pstr, data) lcd_implementation_drawmenu_generic(row, pstr, LCD_STR_UPLEVEL[0], LCD_STR_UPLEVEL[0]) -#define lcd_implementation_drawmenu_back(row, pstr, data) lcd_implementation_drawmenu_generic(row, pstr, ' ', LCD_STR_UPLEVEL[0]) -#define lcd_implementation_drawmenu_submenu_selected(row, pstr, data) lcd_implementation_drawmenu_generic(row, pstr, '>', LCD_STR_ARROW_RIGHT[0]) -#define lcd_implementation_drawmenu_submenu(row, pstr, data) lcd_implementation_drawmenu_generic(row, pstr, ' ', LCD_STR_ARROW_RIGHT[0]) -#define lcd_implementation_drawmenu_gcode_selected(row, pstr, gcode) lcd_implementation_drawmenu_generic(row, pstr, '>', ' ') -#define lcd_implementation_drawmenu_gcode(row, pstr, gcode) lcd_implementation_drawmenu_generic(row, pstr, ' ', ' ') -#define lcd_implementation_drawmenu_function_selected(row, pstr, data) lcd_implementation_drawmenu_generic(row, pstr, '>', ' ') -#define lcd_implementation_drawmenu_function(row, pstr, data) lcd_implementation_drawmenu_generic(row, pstr, ' ', ' ') - -static void lcd_implementation_quick_feedback() -{ -#ifdef LCD_USE_I2C_BUZZER - lcd.buzz(60,1000/6); -#elif defined(BEEPER) && BEEPER > -1 - SET_OUTPUT(BEEPER); - for(int8_t i=0;i<10;i++) - { - WRITE(BEEPER,HIGH); - delayMicroseconds(100); - WRITE(BEEPER,LOW); - delayMicroseconds(100); - } -#endif -} - -#ifdef LCD_HAS_STATUS_INDICATORS -static void lcd_implementation_update_indicators() -{ - #if defined(LCD_I2C_PANELOLU2) || defined(LCD_I2C_VIKI) - //set the LEDS - referred to as backlights by the LiquidTWI2 library - static uint8_t ledsprev = 0; - uint8_t leds = 0; - if (target_temperature_bed > 0) leds |= LED_A; - if (target_temperature[0] > 0) leds |= LED_B; - if (fanSpeed) leds |= LED_C; - #if EXTRUDERS > 1 - if (target_temperature[1] > 0) leds |= LED_C; - #endif - if (leds != ledsprev) { - lcd.setBacklight(leds); - ledsprev = leds; - } - #endif -} -#endif - -#ifdef LCD_HAS_SLOW_BUTTONS -static uint8_t lcd_implementation_read_slow_buttons() -{ - #ifdef LCD_I2C_TYPE_MCP23017 - // Reading these buttons this is likely to be too slow to call inside interrupt context - // so they are called during normal lcd_update - return lcd.readButtons() << B_I2C_BTN_OFFSET; - #endif -} -#endif - -#endif//ULTRA_LCD_IMPLEMENTATION_HITACHI_HD44780_H +#ifndef ULTRA_LCD_IMPLEMENTATION_HITACHI_HD44780_H +#define ULTRA_LCD_IMPLEMENTATION_HITACHI_HD44780_H + +/** +* Implementation of the LCD display routines for a hitachi HD44780 display. These are common LCD character displays. +* When selecting the rusian language, a slightly different LCD implementation is used to handle UTF8 characters. +**/ + +#ifndef REPRAPWORLD_KEYPAD +extern volatile uint8_t buttons; //the last checked buttons in a bit array. +#else +extern volatile uint16_t buttons; //an extended version of the last checked buttons in a bit array. +#endif + +//////////////////////////////////// +// Setup button and encode mappings for each panel (into 'buttons' variable +// +// This is just to map common functions (across different panels) onto the same +// macro name. The mapping is independent of whether the button is directly connected or +// via a shift/i2c register. + +#ifdef ULTIPANEL +// All Ultipanels might have an encoder - so this is always be mapped onto first two bits +#define BLEN_B 1 +#define BLEN_A 0 + +#define EN_B (1< -1 + // encoder click is directly connected + #define BLEN_C 2 + #define EN_C (1< -1 + // the pause/stop/restart button is connected to BTN_ENC when used + #define B_ST (EN_C) // Map the pause/stop/resume button into its normalized functional name + #define LCD_CLICKED (buttons&(B_MI|B_RI|B_ST)) // pause/stop button also acts as click until we implement proper pause/stop. + #else + #define LCD_CLICKED (buttons&(B_MI|B_RI)) + #endif + + // I2C buttons take too long to read inside an interrupt context and so we read them during lcd_update + #define LCD_HAS_SLOW_BUTTONS + +#elif defined(LCD_I2C_PANELOLU2) + // encoder click can be read through I2C if not directly connected + #if BTN_ENC <= 0 + #define B_I2C_BTN_OFFSET 3 // (the first three bit positions reserved for EN_A, EN_B, EN_C) + + #define B_MI (PANELOLU2_ENCODER_C< + #include + #include + #define LCD_CLASS LiquidCrystal_I2C + LCD_CLASS lcd(LCD_I2C_ADDRESS,LCD_I2C_PIN_EN,LCD_I2C_PIN_RW,LCD_I2C_PIN_RS,LCD_I2C_PIN_D4,LCD_I2C_PIN_D5,LCD_I2C_PIN_D6,LCD_I2C_PIN_D7); + +#elif defined(LCD_I2C_TYPE_MCP23017) + //for the LED indicators (which maybe mapped to different things in lcd_implementation_update_indicators()) + #define LED_A 0x04 //100 + #define LED_B 0x02 //010 + #define LED_C 0x01 //001 + + #define LCD_HAS_STATUS_INDICATORS + + #include + #include + #define LCD_CLASS LiquidTWI2 + LCD_CLASS lcd(LCD_I2C_ADDRESS); + +#elif defined(LCD_I2C_TYPE_MCP23008) + #include + #include + #define LCD_CLASS LiquidTWI2 + LCD_CLASS lcd(LCD_I2C_ADDRESS); + +#elif defined(LCD_I2C_TYPE_PCA8574) + #include + #define LCD_CLASS LiquidCrystal_I2C + LCD_CLASS lcd(LCD_I2C_ADDRESS, LCD_WIDTH, LCD_HEIGHT); + +#else + // Standard directly connected LCD implementations + #if LANGUAGE_CHOICE == 6 + #include "LiquidCrystalRus.h" + #define LCD_CLASS LiquidCrystalRus + #else + #include + #define LCD_CLASS LiquidCrystal + #endif + LCD_CLASS lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5,LCD_PINS_D6,LCD_PINS_D7); //RS,Enable,D4,D5,D6,D7 +#endif + +/* Custom characters defined in the first 8 characters of the LCD */ +#define LCD_STR_BEDTEMP "\x00" +#define LCD_STR_DEGREE "\x01" +#define LCD_STR_THERMOMETER "\x02" +#define LCD_STR_UPLEVEL "\x03" +#define LCD_STR_REFRESH "\x04" +#define LCD_STR_FOLDER "\x05" +#define LCD_STR_FEEDRATE "\x06" +#define LCD_STR_CLOCK "\x07" +#define LCD_STR_ARROW_RIGHT "\x7E" /* from the default character set */ + +static void lcd_implementation_init() +{ + byte bedTemp[8] = + { + B00000, + B11111, + B10101, + B10001, + B10101, + B11111, + B00000, + B00000 + }; //thanks Sonny Mounicou + byte degree[8] = + { + B01100, + B10010, + B10010, + B01100, + B00000, + B00000, + B00000, + B00000 + }; + byte thermometer[8] = + { + B00100, + B01010, + B01010, + B01010, + B01010, + B10001, + B10001, + B01110 + }; + byte uplevel[8]={ + B00100, + B01110, + B11111, + B00100, + B11100, + B00000, + B00000, + B00000 + }; //thanks joris + byte refresh[8]={ + B00000, + B00110, + B11001, + B11000, + B00011, + B10011, + B01100, + B00000, + }; //thanks joris + byte folder [8]={ + B00000, + B11100, + B11111, + B10001, + B10001, + B11111, + B00000, + B00000 + }; //thanks joris + byte feedrate [8]={ + B11100, + B10000, + B11000, + B10111, + B00101, + B00110, + B00101, + B00000 + }; //thanks Sonny Mounicou + byte clock [8]={ + B00000, + B01110, + B10011, + B10101, + B10001, + B01110, + B00000, + B00000 + }; //thanks Sonny Mounicou + +#if defined(LCDI2C_TYPE_PCF8575) + lcd.begin(LCD_WIDTH, LCD_HEIGHT); + #ifdef LCD_I2C_PIN_BL + lcd.setBacklightPin(LCD_I2C_PIN_BL,POSITIVE); + lcd.setBacklight(HIGH); + #endif + +#elif defined(LCD_I2C_TYPE_MCP23017) + lcd.setMCPType(LTI_TYPE_MCP23017); + lcd.begin(LCD_WIDTH, LCD_HEIGHT); + lcd.setBacklight(0); //set all the LEDs off to begin with + +#elif defined(LCD_I2C_TYPE_MCP23008) + lcd.setMCPType(LTI_TYPE_MCP23008); + lcd.begin(LCD_WIDTH, LCD_HEIGHT); + +#elif defined(LCD_I2C_TYPE_PCA8574) + lcd.init(); + lcd.backlight(); + +#else + lcd.begin(LCD_WIDTH, LCD_HEIGHT); +#endif + + lcd.createChar(LCD_STR_BEDTEMP[0], bedTemp); + lcd.createChar(LCD_STR_DEGREE[0], degree); + lcd.createChar(LCD_STR_THERMOMETER[0], thermometer); + lcd.createChar(LCD_STR_UPLEVEL[0], uplevel); + lcd.createChar(LCD_STR_REFRESH[0], refresh); + lcd.createChar(LCD_STR_FOLDER[0], folder); + lcd.createChar(LCD_STR_FEEDRATE[0], feedrate); + lcd.createChar(LCD_STR_CLOCK[0], clock); + lcd.clear(); +} +static void lcd_implementation_clear() +{ + lcd.clear(); +} +/* Arduino < 1.0.0 is missing a function to print PROGMEM strings, so we need to implement our own */ +static void lcd_printPGM(const char* str) +{ + char c; + while((c = pgm_read_byte(str++)) != '\0') + { + lcd.write(c); + } +} +/* +Possible status screens: +16x2 |0123456789012345| + |000/000 B000/000| + |Status line.....| + +16x4 |0123456789012345| + |000/000 B000/000| + |SD100% Z000.0| + |F100% T--:--| + |Status line.....| + +20x2 |01234567890123456789| + |T000/000D B000/000D | + |Status line.........| + +20x4 |01234567890123456789| + |T000/000D B000/000D | + |X+000.0 Y+000.0 Z+000.0| + |F100% SD100% T--:--| + |Status line.........| + +20x4 |01234567890123456789| + |T000/000D B000/000D | + |T000/000D Z000.0| + |F100% SD100% T--:--| + |Status line.........| +*/ +static void lcd_implementation_status_screen() +{ + int tHotend=int(degHotend(0) + 0.5); + int tTarget=int(degTargetHotend(0) + 0.5); + +#if LCD_WIDTH < 20 + lcd.setCursor(0, 0); + lcd.print(itostr3(tHotend)); + lcd.print('/'); + lcd.print(itostr3left(tTarget)); + +# if EXTRUDERS > 1 || TEMP_SENSOR_BED != 0 + //If we have an 2nd extruder or heated bed, show that in the top right corner + lcd.setCursor(8, 0); +# if EXTRUDERS > 1 + tHotend = int(degHotend(1) + 0.5); + tTarget = int(degTargetHotend(1) + 0.5); + lcd.print(LCD_STR_THERMOMETER[0]); +# else//Heated bed + tHotend=int(degBed() + 0.5); + tTarget=int(degTargetBed() + 0.5); + lcd.print(LCD_STR_BEDTEMP[0]); +# endif + lcd.print(itostr3(tHotend)); + lcd.print('/'); + lcd.print(itostr3left(tTarget)); +# endif//EXTRUDERS > 1 || TEMP_SENSOR_BED != 0 + +#else//LCD_WIDTH > 19 + lcd.setCursor(0, 0); + lcd.print(LCD_STR_THERMOMETER[0]); + lcd.print(itostr3(tHotend)); + lcd.print('/'); + lcd.print(itostr3left(tTarget)); + lcd_printPGM(PSTR(LCD_STR_DEGREE " ")); + if (tTarget < 10) + lcd.print(' '); + +# if EXTRUDERS > 1 || TEMP_SENSOR_BED != 0 + //If we have an 2nd extruder or heated bed, show that in the top right corner + lcd.setCursor(10, 0); +# if EXTRUDERS > 1 + tHotend = int(degHotend(1) + 0.5); + tTarget = int(degTargetHotend(1) + 0.5); + lcd.print(LCD_STR_THERMOMETER[0]); +# else//Heated bed + tHotend=int(degBed() + 0.5); + tTarget=int(degTargetBed() + 0.5); + lcd.print(LCD_STR_BEDTEMP[0]); +# endif + lcd.print(itostr3(tHotend)); + lcd.print('/'); + lcd.print(itostr3left(tTarget)); + lcd_printPGM(PSTR(LCD_STR_DEGREE " ")); + if (tTarget < 10) + lcd.print(' '); +# endif//EXTRUDERS > 1 || TEMP_SENSOR_BED != 0 +#endif//LCD_WIDTH > 19 + +#if LCD_HEIGHT > 2 +//Lines 2 for 4 line LCD +# if LCD_WIDTH < 20 +# ifdef SDSUPPORT + lcd.setCursor(0, 2); + lcd_printPGM(PSTR("SD")); + if (IS_SD_PRINTING) + lcd.print(itostr3(card.percentDone())); + else + lcd_printPGM(PSTR("---")); + lcd.print('%'); +# endif//SDSUPPORT +# else//LCD_WIDTH > 19 +# if EXTRUDERS > 1 && TEMP_SENSOR_BED != 0 + //If we both have a 2nd extruder and a heated bed, show the heated bed temp on the 2nd line on the left, as the first line is filled with extruder temps + tHotend=int(degBed() + 0.5); + tTarget=int(degTargetBed() + 0.5); + + lcd.setCursor(0, 1); + lcd.print(LCD_STR_BEDTEMP[0]); + lcd.print(itostr3(tHotend)); + lcd.print('/'); + lcd.print(itostr3left(tTarget)); + lcd_printPGM(PSTR(LCD_STR_DEGREE " ")); + if (tTarget < 10) + lcd.print(' '); +# else + lcd.setCursor(0,1); + lcd.print('X'); + lcd.print(ftostr3(current_position[X_AXIS])); + lcd_printPGM(PSTR(" Y")); + lcd.print(ftostr3(current_position[Y_AXIS])); +# endif//EXTRUDERS > 1 || TEMP_SENSOR_BED != 0 +# endif//LCD_WIDTH > 19 + lcd.setCursor(LCD_WIDTH - 8, 1); + lcd.print('Z'); + lcd.print(ftostr32(current_position[Z_AXIS])); +#endif//LCD_HEIGHT > 2 + +#if LCD_HEIGHT > 3 + lcd.setCursor(0, 2); + lcd.print(LCD_STR_FEEDRATE[0]); + lcd.print(itostr3(feedmultiply)); + lcd.print('%'); +# if LCD_WIDTH > 19 +# ifdef SDSUPPORT + lcd.setCursor(7, 2); + lcd_printPGM(PSTR("SD")); + if (IS_SD_PRINTING) + lcd.print(itostr3(card.percentDone())); + else + lcd_printPGM(PSTR("---")); + lcd.print('%'); +# endif//SDSUPPORT +# endif//LCD_WIDTH > 19 + lcd.setCursor(LCD_WIDTH - 6, 2); + lcd.print(LCD_STR_CLOCK[0]); + if(starttime != 0) + { + uint16_t time = millis()/60000 - starttime/60000; + lcd.print(itostr2(time/60)); + lcd.print(':'); + lcd.print(itostr2(time%60)); + }else{ + lcd_printPGM(PSTR("--:--")); + } +#endif + + //Status message line on the last line + lcd.setCursor(0, LCD_HEIGHT - 1); + lcd.print(lcd_status_message); +} +static void lcd_implementation_drawmenu_generic(uint8_t row, const char* pstr, char pre_char, char post_char) +{ + char c; + //Use all characters in narrow LCDs + #if LCD_WIDTH < 20 + uint8_t n = LCD_WIDTH - 1 - 1; + #else + uint8_t n = LCD_WIDTH - 1 - 2; + #endif + lcd.setCursor(0, row); + lcd.print(pre_char); + while( ((c = pgm_read_byte(pstr)) != '\0') && (n>0) ) + { + lcd.print(c); + pstr++; + n--; + } + while(n--) + lcd.print(' '); + lcd.print(post_char); + lcd.print(' '); +} +static void lcd_implementation_drawmenu_setting_edit_generic(uint8_t row, const char* pstr, char pre_char, char* data) +{ + char c; + //Use all characters in narrow LCDs + #if LCD_WIDTH < 20 + uint8_t n = LCD_WIDTH - 1 - 1 - strlen(data); + #else + uint8_t n = LCD_WIDTH - 1 - 2 - strlen(data); + #endif + lcd.setCursor(0, row); + lcd.print(pre_char); + while( ((c = pgm_read_byte(pstr)) != '\0') && (n>0) ) + { + lcd.print(c); + pstr++; + n--; + } + lcd.print(':'); + while(n--) + lcd.print(' '); + lcd.print(data); +} +static void lcd_implementation_drawmenu_setting_edit_generic_P(uint8_t row, const char* pstr, char pre_char, const char* data) +{ + char c; + //Use all characters in narrow LCDs + #if LCD_WIDTH < 20 + uint8_t n = LCD_WIDTH - 1 - 1 - strlen_P(data); + #else + uint8_t n = LCD_WIDTH - 1 - 2 - strlen_P(data); + #endif + lcd.setCursor(0, row); + lcd.print(pre_char); + while( ((c = pgm_read_byte(pstr)) != '\0') && (n>0) ) + { + lcd.print(c); + pstr++; + n--; + } + lcd.print(':'); + while(n--) + lcd.print(' '); + lcd_printPGM(data); +} +#define lcd_implementation_drawmenu_setting_edit_int3_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', itostr3(*(data))) +#define lcd_implementation_drawmenu_setting_edit_int3(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', itostr3(*(data))) +#define lcd_implementation_drawmenu_setting_edit_float3_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr3(*(data))) +#define lcd_implementation_drawmenu_setting_edit_float3(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr3(*(data))) +#define lcd_implementation_drawmenu_setting_edit_float32_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr32(*(data))) +#define lcd_implementation_drawmenu_setting_edit_float32(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr32(*(data))) +#define lcd_implementation_drawmenu_setting_edit_float5_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr5(*(data))) +#define lcd_implementation_drawmenu_setting_edit_float5(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr5(*(data))) +#define lcd_implementation_drawmenu_setting_edit_float52_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr52(*(data))) +#define lcd_implementation_drawmenu_setting_edit_float52(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr52(*(data))) +#define lcd_implementation_drawmenu_setting_edit_float51_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr51(*(data))) +#define lcd_implementation_drawmenu_setting_edit_float51(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr51(*(data))) +#define lcd_implementation_drawmenu_setting_edit_long5_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr5(*(data))) +#define lcd_implementation_drawmenu_setting_edit_long5(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr5(*(data))) +#define lcd_implementation_drawmenu_setting_edit_bool_selected(row, pstr, pstr2, data) lcd_implementation_drawmenu_setting_edit_generic_P(row, pstr, '>', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF)) +#define lcd_implementation_drawmenu_setting_edit_bool(row, pstr, pstr2, data) lcd_implementation_drawmenu_setting_edit_generic_P(row, pstr, ' ', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF)) + +//Add version for callback functions +#define lcd_implementation_drawmenu_setting_edit_callback_int3_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', itostr3(*(data))) +#define lcd_implementation_drawmenu_setting_edit_callback_int3(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', itostr3(*(data))) +#define lcd_implementation_drawmenu_setting_edit_callback_float3_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr3(*(data))) +#define lcd_implementation_drawmenu_setting_edit_callback_float3(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr3(*(data))) +#define lcd_implementation_drawmenu_setting_edit_callback_float32_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr32(*(data))) +#define lcd_implementation_drawmenu_setting_edit_callback_float32(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr32(*(data))) +#define lcd_implementation_drawmenu_setting_edit_callback_float5_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr5(*(data))) +#define lcd_implementation_drawmenu_setting_edit_callback_float5(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr5(*(data))) +#define lcd_implementation_drawmenu_setting_edit_callback_float52_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr52(*(data))) +#define lcd_implementation_drawmenu_setting_edit_callback_float52(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr52(*(data))) +#define lcd_implementation_drawmenu_setting_edit_callback_float51_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr51(*(data))) +#define lcd_implementation_drawmenu_setting_edit_callback_float51(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr51(*(data))) +#define lcd_implementation_drawmenu_setting_edit_callback_long5_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr5(*(data))) +#define lcd_implementation_drawmenu_setting_edit_callback_long5(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr5(*(data))) +#define lcd_implementation_drawmenu_setting_edit_callback_bool_selected(row, pstr, pstr2, data, callback) lcd_implementation_drawmenu_setting_edit_generic_P(row, pstr, '>', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF)) +#define lcd_implementation_drawmenu_setting_edit_callback_bool(row, pstr, pstr2, data, callback) lcd_implementation_drawmenu_setting_edit_generic_P(row, pstr, ' ', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF)) + + +void lcd_implementation_drawedit(const char* pstr, char* value) +{ + lcd.setCursor(1, 1); + lcd_printPGM(pstr); + lcd.print(':'); + #if LCD_WIDTH < 20 + lcd.setCursor(LCD_WIDTH - strlen(value), 1); + #else + lcd.setCursor(LCD_WIDTH -1 - strlen(value), 1); + #endif + lcd.print(value); +} +static void lcd_implementation_drawmenu_sdfile_selected(uint8_t row, const char* pstr, const char* filename, char* longFilename) +{ + char c; + uint8_t n = LCD_WIDTH - 1; + lcd.setCursor(0, row); + lcd.print('>'); + if (longFilename[0] != '\0') + { + filename = longFilename; + longFilename[LCD_WIDTH-1] = '\0'; + } + while( ((c = *filename) != '\0') && (n>0) ) + { + lcd.print(c); + filename++; + n--; + } + while(n--) + lcd.print(' '); +} +static void lcd_implementation_drawmenu_sdfile(uint8_t row, const char* pstr, const char* filename, char* longFilename) +{ + char c; + uint8_t n = LCD_WIDTH - 1; + lcd.setCursor(0, row); + lcd.print(' '); + if (longFilename[0] != '\0') + { + filename = longFilename; + longFilename[LCD_WIDTH-1] = '\0'; + } + while( ((c = *filename) != '\0') && (n>0) ) + { + lcd.print(c); + filename++; + n--; + } + while(n--) + lcd.print(' '); +} +static void lcd_implementation_drawmenu_sddirectory_selected(uint8_t row, const char* pstr, const char* filename, char* longFilename) +{ + char c; + uint8_t n = LCD_WIDTH - 2; + lcd.setCursor(0, row); + lcd.print('>'); + lcd.print(LCD_STR_FOLDER[0]); + if (longFilename[0] != '\0') + { + filename = longFilename; + longFilename[LCD_WIDTH-2] = '\0'; + } + while( ((c = *filename) != '\0') && (n>0) ) + { + lcd.print(c); + filename++; + n--; + } + while(n--) + lcd.print(' '); +} +static void lcd_implementation_drawmenu_sddirectory(uint8_t row, const char* pstr, const char* filename, char* longFilename) +{ + char c; + uint8_t n = LCD_WIDTH - 2; + lcd.setCursor(0, row); + lcd.print(' '); + lcd.print(LCD_STR_FOLDER[0]); + if (longFilename[0] != '\0') + { + filename = longFilename; + longFilename[LCD_WIDTH-2] = '\0'; + } + while( ((c = *filename) != '\0') && (n>0) ) + { + lcd.print(c); + filename++; + n--; + } + while(n--) + lcd.print(' '); +} +#define lcd_implementation_drawmenu_back_selected(row, pstr, data) lcd_implementation_drawmenu_generic(row, pstr, LCD_STR_UPLEVEL[0], LCD_STR_UPLEVEL[0]) +#define lcd_implementation_drawmenu_back(row, pstr, data) lcd_implementation_drawmenu_generic(row, pstr, ' ', LCD_STR_UPLEVEL[0]) +#define lcd_implementation_drawmenu_submenu_selected(row, pstr, data) lcd_implementation_drawmenu_generic(row, pstr, '>', LCD_STR_ARROW_RIGHT[0]) +#define lcd_implementation_drawmenu_submenu(row, pstr, data) lcd_implementation_drawmenu_generic(row, pstr, ' ', LCD_STR_ARROW_RIGHT[0]) +#define lcd_implementation_drawmenu_gcode_selected(row, pstr, gcode) lcd_implementation_drawmenu_generic(row, pstr, '>', ' ') +#define lcd_implementation_drawmenu_gcode(row, pstr, gcode) lcd_implementation_drawmenu_generic(row, pstr, ' ', ' ') +#define lcd_implementation_drawmenu_function_selected(row, pstr, data) lcd_implementation_drawmenu_generic(row, pstr, '>', ' ') +#define lcd_implementation_drawmenu_function(row, pstr, data) lcd_implementation_drawmenu_generic(row, pstr, ' ', ' ') + +static void lcd_implementation_quick_feedback() +{ +#ifdef LCD_USE_I2C_BUZZER + lcd.buzz(60,1000/6); +#elif defined(BEEPER) && BEEPER > -1 + SET_OUTPUT(BEEPER); + for(int8_t i=0;i<10;i++) + { + WRITE(BEEPER,HIGH); + delayMicroseconds(100); + WRITE(BEEPER,LOW); + delayMicroseconds(100); + } +#endif +} + +#ifdef LCD_HAS_STATUS_INDICATORS +static void lcd_implementation_update_indicators() +{ + #if defined(LCD_I2C_PANELOLU2) || defined(LCD_I2C_VIKI) + //set the LEDS - referred to as backlights by the LiquidTWI2 library + static uint8_t ledsprev = 0; + uint8_t leds = 0; + if (target_temperature_bed > 0) leds |= LED_A; + if (target_temperature[0] > 0) leds |= LED_B; + if (fanSpeed) leds |= LED_C; + #if EXTRUDERS > 1 + if (target_temperature[1] > 0) leds |= LED_C; + #endif + if (leds != ledsprev) { + lcd.setBacklight(leds); + ledsprev = leds; + } + #endif +} +#endif + +#ifdef LCD_HAS_SLOW_BUTTONS +extern uint32_t blocking_enc; + +static uint8_t lcd_implementation_read_slow_buttons() +{ + #ifdef LCD_I2C_TYPE_MCP23017 + uint8_t slow_buttons; + // Reading these buttons this is likely to be too slow to call inside interrupt context + // so they are called during normal lcd_update + slow_buttons = lcd.readButtons() << B_I2C_BTN_OFFSET; + #if defined(LCD_I2C_VIKI) + if(slow_buttons & (B_MI|B_RI)) { //LCD clicked + if(blocking_enc > millis()) { + slow_buttons &= ~(B_MI|B_RI); // Disable LCD clicked buttons if screen is updated + } + } + #endif + return slow_buttons; + #endif +} +#endif + +#endif//ULTRA_LCD_IMPLEMENTATION_HITACHI_HD44780_H From b2cc27e5ea89510f0ff845827677652141f55a02 Mon Sep 17 00:00:00 2001 From: bkubicek Date: Tue, 22 Oct 2013 09:54:13 +0200 Subject: [PATCH 067/256] Added a magic character for sd buffering. if a '#' is read now the buffer will be emptied before reading ahead. This is so one can execute files from within gcode files, without messing the buffer with preread characters from the caller file. # can not occure in sd files imho, because it should only occure within checksums in ther serial communication. Yes, thats a lame argument. If you have a better idea please tell me. It has to be a character that one can type on a keyboard manually. --- Marlin/Marlin_main.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 932af13552..c53a5b5830 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -620,11 +620,20 @@ void get_command() if(!card.sdprinting || serial_count!=0){ return; } - while( !card.eof() && buflen < BUFSIZE) { + + //'#' stops reading from sd to the buffer prematurely, so procedural macro calls are possible + // if it occures, stop_buffering is triggered and the buffer is ran dry. + // this character _can_ occure in serial com, due to checksums. however, no checksums are used in sd printing + + static bool stop_buffering=false; + if(buflen==0) stop_buffering=false; + + while( !card.eof() && buflen < BUFSIZE && !stop_buffering) { int16_t n=card.get(); - serial_char = (char)n; + serial_char = (char)n; if(serial_char == '\n' || serial_char == '\r' || + serial_char == '#' || (serial_char == ':' && comment_mode == false) || serial_count >= (MAX_CMD_SIZE - 1)||n==-1) { @@ -644,6 +653,9 @@ void get_command() card.checkautostart(true); } + if(serial_char=='#') + stop_buffering=true; + if(!serial_count) { comment_mode = false; //for new command From ab965376ff70b3f80b180a47db67ee6dea33d5a6 Mon Sep 17 00:00:00 2001 From: bkubicek Date: Tue, 22 Oct 2013 10:02:18 +0200 Subject: [PATCH 068/256] Sub-file calls. by overloading M32 it is now possible to execute gcode files from other gcode files, with a fixed recursion level. This can be used e.g. for having a real start.g and end.g somewhere on the sd card, which are then called from the normal print file. Another usecase would be to have macro-files for nozzle-change and layerchange. I have not tested the speedwise performance. The testing was done with pronterface. syntax: normal call from sd card will open the new file and continue executing there. M32 !/path/filename# this however will call the new file and return to the caller file. M32 P !/path/filename# with the optional "S" the file starting position can be set. this is for continuing prints from a previous location. --- Marlin/Marlin_main.cpp | 43 +++++++++++++++----- Marlin/cardreader.cpp | 89 +++++++++++++++++++++++++++++++++++++----- Marlin/cardreader.h | 9 ++++- 3 files changed, 121 insertions(+), 20 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index c53a5b5830..4bea72b158 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -90,7 +90,10 @@ // M29 - Stop SD write // M30 - Delete file from SD (M30 filename.g) // M31 - Output time since last M109 or SD card start to serial -// M32 - Select file and start SD print (Can be used when printing from SD card) +// M32 - Select file and start SD print (Can be used _while_ printing from SD card files): +// syntax "M32 /path/filename#", or "M32 S !filename#" +// Call gcode file : "M32 P !filename#" and return to caller file after finishing (simiarl to #include). +// The '#' is necessary when calling from within sd files, as it stops buffer prereading // M42 - Change pin status via gcode Use M42 Px Sy to set pin x to value y, when omitting Px the onboard led will be used. // M80 - Turn on Power Supply // M81 - Turn off Power Supply @@ -1467,19 +1470,41 @@ void process_commands() card.removeFile(strchr_pointer + 4); } break; - case 32: //M32 - Select file and start SD print + case 32: //M32 - Select file and start SD print + { if(card.sdprinting) { st_synchronize(); - card.closefile(); - card.sdprinting = false; + } - starpos = (strchr(strchr_pointer + 4,'*')); + starpos = (strchr(strchr_pointer + 4,'*')); + + char* namestartpos = (strchr(strchr_pointer + 4,'!')); //find ! to indicate filename string start. + if(namestartpos==NULL) + { + namestartpos=strchr_pointer + 4; //default name position, 4 letters after the M + } + else + namestartpos++; //to skip the '!' + if(starpos!=NULL) *(starpos-1)='\0'; - card.openFile(strchr_pointer + 4,true); - card.startFileprint(); - starttime=millis(); - break; + + bool call_procedure=(code_seen('P')); + + if(strchr_pointer>namestartpos) + call_procedure=false; //false alert, 'P' found within filename + + if( card.cardOK ) + { + card.openFile(namestartpos,true,!call_procedure); + if(code_seen('S')) + if(strchr_pointer(int)SD_PROCEDURE_DEPTH-1) + { + SERIAL_ERROR_START; + SERIAL_ERRORPGM("trying to call sub-gcode files with too many levels. MAX level is:"); + SERIAL_ERRORLN(SD_PROCEDURE_DEPTH); + kill(); + return; + } + + SERIAL_ECHO_START; + SERIAL_ECHOPGM("SUBROUTINE CALL target:\""); + SERIAL_ECHO(name); + SERIAL_ECHOPGM("\" parent:\""); + + //store current filename and position + getAbsFilename(filenames[file_subcall_ctr]); + + SERIAL_ECHO(filenames[file_subcall_ctr]); + SERIAL_ECHOPGM("\" pos"); + SERIAL_ECHOLN(sdpos); + filespos[file_subcall_ctr]=sdpos; + file_subcall_ctr++; + } + else + { + SERIAL_ECHO_START; + SERIAL_ECHOPGM("Now doing file: "); + SERIAL_ECHOLN(name); + } + file.close(); + } + else //opening fresh file + { + file_subcall_ctr=0; //resetting procedure depth in case user cancels print while in procedure + SERIAL_ECHO_START; + SERIAL_ECHOPGM("Now fresh file: "); + SERIAL_ECHOLN(name); + } sdprinting = false; - + SdFile myDir; curDir=&root; char *fname=name; @@ -547,14 +605,25 @@ void CardReader::updir() void CardReader::printingHasFinished() { st_synchronize(); - quickStop(); - file.close(); - sdprinting = false; - if(SD_FINISHED_STEPPERRELEASE) + if(file_subcall_ctr>0) //heading up to a parent file that called current as a procedure. + { + file.close(); + file_subcall_ctr--; + openFile(filenames[file_subcall_ctr],true,true); + setIndex(filespos[file_subcall_ctr]); + startFileprint(); + } + else { - //finishAndDisableSteppers(); - enquecommand_P(PSTR(SD_FINISHED_RELEASECOMMAND)); + quickStop(); + file.close(); + sdprinting = false; + if(SD_FINISHED_STEPPERRELEASE) + { + //finishAndDisableSteppers(); + enquecommand_P(PSTR(SD_FINISHED_RELEASECOMMAND)); + } + autotempShutdown(); } - autotempShutdown(); } #endif //SDSUPPORT diff --git a/Marlin/cardreader.h b/Marlin/cardreader.h index 6e59645295..07c7090ce9 100644 --- a/Marlin/cardreader.h +++ b/Marlin/cardreader.h @@ -18,7 +18,7 @@ public: //this is to delay autostart and hence the initialisaiton of the sd card to some seconds after the normal init, so the device is available quick after a reset void checkautostart(bool x); - void openFile(char* name,bool read); + void openFile(char* name,bool read,bool replace_current=true); void openLogFile(char* name); void removeFile(char* name); void closefile(); @@ -31,6 +31,8 @@ public: void getfilename(const uint8_t nr); uint16_t getnrfilenames(); + void getAbsFilename(char *t); + void ls(); void chdir(const char * relpath); @@ -60,6 +62,11 @@ private: Sd2Card card; SdVolume volume; SdFile file; + #define SD_PROCEDURE_DEPTH 1 + #define MAXPATHNAMELENGTH (13*MAX_DIR_DEPTH+MAX_DIR_DEPTH+1) + uint8_t file_subcall_ctr; + uint32_t filespos[SD_PROCEDURE_DEPTH]; + char filenames[SD_PROCEDURE_DEPTH][MAXPATHNAMELENGTH]; uint32_t filesize; //int16_t n; unsigned long autostart_atmillis; From 39d88bcccbfdf57b868ba111c36ab1464735a842 Mon Sep 17 00:00:00 2001 From: bkubicek Date: Tue, 22 Oct 2013 10:04:08 +0200 Subject: [PATCH 069/256] preparation for hibernation If a print is stopped, it would be nice in the future to write a file with the printer state, the filename of the print, and the position within the print. this file could be read, to continue a previously stopped print. not finished yet. --- Marlin/cardreader.cpp | 11 ++++++++++- Marlin/cardreader.h | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index f01f4606ee..e5c3108961 100644 --- a/Marlin/cardreader.cpp +++ b/Marlin/cardreader.cpp @@ -535,12 +535,21 @@ void CardReader::checkautostart(bool force) lastnr++; } -void CardReader::closefile() +void CardReader::closefile(bool store_location) { file.sync(); file.close(); saving = false; logging = false; + + if(store_location) + { + //future: store printer state, filename and position for continueing a stoped print + // so one can unplug the printer and continue printing the next day. + + } + + } void CardReader::getfilename(const uint8_t nr) diff --git a/Marlin/cardreader.h b/Marlin/cardreader.h index 07c7090ce9..78f7148b1f 100644 --- a/Marlin/cardreader.h +++ b/Marlin/cardreader.h @@ -21,7 +21,7 @@ public: void openFile(char* name,bool read,bool replace_current=true); void openLogFile(char* name); void removeFile(char* name); - void closefile(); + void closefile(bool store_location=false); void release(); void startFileprint(); void pauseSDPrint(); From d69822ed51cfe36ffcbba555b90d010e9685dd3e Mon Sep 17 00:00:00 2001 From: bkubicek Date: Tue, 22 Oct 2013 10:34:51 +0200 Subject: [PATCH 070/256] Fix '#' since it can occure in comments. --- Marlin/Marlin_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 698caa8d3b..8778f602a0 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -642,7 +642,7 @@ void get_command() serial_char = (char)n; if(serial_char == '\n' || serial_char == '\r' || - serial_char == '#' || + (serial_char == '#' && comment_mode == false) || (serial_char == ':' && comment_mode == false) || serial_count >= (MAX_CMD_SIZE - 1)||n==-1) { From 5b8b939a1f13c62955388f3373e96aa9deaf2454 Mon Sep 17 00:00:00 2001 From: alexborro Date: Tue, 22 Oct 2013 10:38:33 -0200 Subject: [PATCH 071/256] Add comments about RAMPS 5V rail for servos. --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index de8cde5f61..322c30de88 100644 --- a/README.md +++ b/README.md @@ -276,6 +276,13 @@ The first define tells firmware how many servos you have. The second tells what axis this servo will be attached to. In the example above, we have a servo in Z axis. The third one tells the angle in 2 situations: Probing (165º) and resting (60º). Check this with command M280 P0 S{angle} (example: M280 P0 S60 moves the servo to 60º) +*For RAMPS users:* +By default, RAMPS have no power on servo bus (if you happen to have a multimeter, check the voltage on servo power pins). +In order to get the servo working, you need to supply 5V to 5V pin.. You can do it using your power supply (if it has a 5V output) or jumping the "Vcc" from Arduino to the 5V RAMPS rail. +These 2 pins are located just between the Reset Button and the yellow fuses... There are marks in the board showing 5V and VCC.. just connect them.. +If jumping the arduino Vcc do RAMPS 5V rail, take care to not use a power hungry servo, otherwise you will cause a blackout in the arduino board ;-) + + Next you need to define the Z endstop (probe) offset from hotend. My preferred method: From c79e3967b317375d3bb7ce47a335024c0c94f9bb Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Thu, 24 Oct 2013 18:58:42 -0700 Subject: [PATCH 072/256] Make G11 not horribly broken --- Marlin/Marlin_main.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 8778f602a0..56edf7db83 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1072,15 +1072,14 @@ void process_commands() } break; - case 11: // G10 retract_recover - if(!retracted) + case 11: // G11 retract_recover + if(retracted) { destination[X_AXIS]=current_position[X_AXIS]; destination[Y_AXIS]=current_position[Y_AXIS]; destination[Z_AXIS]=current_position[Z_AXIS]; - current_position[Z_AXIS]+=retract_zlift; - current_position[E_AXIS]+=-retract_recover_length; + destination[E_AXIS]=current_position[E_AXIS]+retract_length+retract_recover_length; feedrate=retract_recover_feedrate; retracted=false; prepare_move(); From f9412031725192c2a7c1b7709d72f01bf76b765e Mon Sep 17 00:00:00 2001 From: dumle29 Date: Tue, 29 Oct 2013 18:44:56 +0100 Subject: [PATCH 073/256] PS_ON configurable boot state Allows the user to select wheter or not the PSU should be turned on or kept in standby when marlin boots --- Marlin/Configuration.h | 3 +++ Marlin/Marlin_main.cpp | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 8496a8b24b..d6164a9047 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -79,6 +79,9 @@ #define POWER_SUPPLY 1 +// Define this to have the electronics keep the powersupply off on startup. If you don't know what this is leave it. +// #define PS_DEFAULT_OFF + //=========================================================================== //=============================Thermal Settings ============================ //=========================================================================== diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 56edf7db83..fc53ebacd8 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -366,7 +366,11 @@ void setup_powerhold() #endif #if defined(PS_ON_PIN) && PS_ON_PIN > -1 SET_OUTPUT(PS_ON_PIN); - WRITE(PS_ON_PIN, PS_ON_AWAKE); + #if defined(PS_DEFAULT_OFF) + WRITE(PS_ON_PIN, PS_ON_ASLEEP); + #else + WRITE(PS_ON_PIN, PS_ON_AWAKE); + #endif #endif } From b5a964fcc54ecfe8badeae120282037a7692852e Mon Sep 17 00:00:00 2001 From: fmalpartida Date: Wed, 30 Oct 2013 11:45:32 +0100 Subject: [PATCH 074/256] Initial SAV MkI (RepRap CloneWars board) integration. Included support for BT dongle on AT90USB boards. Added LCD Shift Register LCD control Included support for RepRap Clone Wars project board (SAV MKI). --- Marlin/{BlinkM.cpp => BlinkM.__cpp} | 0 Marlin/{BlinkM.h => BlinkM.__h} | 0 Marlin/Configuration.h | 26 +++++- Marlin/Configuration_adv.h | 2 +- Marlin/Marlin.h | 13 +++ Marlin/MarlinSerial.cpp | 6 ++ Marlin/MarlinSerial.h | 5 ++ Marlin/Sd2PinMap.h | 8 +- Marlin/pins.h | 86 +++++++++++++++++++ Marlin/ultralcd.cpp | 20 +++-- .../ultralcd_implementation_hitachi_HD44780.h | 11 ++- 11 files changed, 162 insertions(+), 15 deletions(-) rename Marlin/{BlinkM.cpp => BlinkM.__cpp} (100%) rename Marlin/{BlinkM.h => BlinkM.__h} (100%) diff --git a/Marlin/BlinkM.cpp b/Marlin/BlinkM.__cpp similarity index 100% rename from Marlin/BlinkM.cpp rename to Marlin/BlinkM.__cpp diff --git a/Marlin/BlinkM.h b/Marlin/BlinkM.__h similarity index 100% rename from Marlin/BlinkM.h rename to Marlin/BlinkM.__h diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 8496a8b24b..39032f1fb0 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -22,10 +22,21 @@ // This allows the connection of wireless adapters (for instance) to non-default port pins. // Serial port 0 is still used by the Arduino bootloader regardless of this setting. #define SERIAL_PORT 0 +//#define SERIAL_PORT 1 // Define serial port 1 for bluetooth configuration in AT90USB configurations +// This determines the communication speed of the printer // This determines the communication speed of the printer #define BAUDRATE 250000 -//#define BAUDRATE 115200 + +// This enables the serial port associated to the Bluetooth interface +//#define BTENABLED // Enable BT interface + + +// SERIAL_PORT selects which serial port should be used for communication with the host. +// This allows the connection of wireless adapters (for instance) to non-default port pins. +// Serial port 0 is still used by the Arduino bootloader regardless of this setting. +#define SERIAL_PORT 0 + //// The following define selects which electronics board you have. Please choose the one that matches your setup // 10 = Gen7 custom (Alfons3 Version) "https://github.com/Alfons3/Generation_7_Electronics" @@ -54,6 +65,7 @@ // 80 = Rumba // 81 = Printrboard (AT90USB1286) // 82 = Brainwave (AT90USB646) +// 83 = SAV Mk-I (AT90USB1286) // 9 = Gen3+ // 70 = Megatronics // 701= Megatronics v2.0 @@ -64,7 +76,8 @@ // 21 = Elefu Ra Board (v3) #ifndef MOTHERBOARD -#define MOTHERBOARD 7 +//[FMC]#define MOTHERBOARD 7 +#define MOTHERBOARD 83 #endif // Define this to set a custom name for your generic Mendel, @@ -507,6 +520,15 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #define ULTIPANEL #endif +// Shift register panels +// --------------------- +//#define SR_LCD +#ifdef SR_LCD + #define SR_LCD_2W_NL // Non latching 2 wire shiftregister + //#define NEWPANEL +#endif + + #ifdef ULTIPANEL // #define NEWPANEL //enable this if you have a click-encoder panel #define SDSUPPORT diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 06101f00c7..246eb3252e 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -163,7 +163,7 @@ #ifdef Z_DUAL_STEPPER_DRIVERS && Y_DUAL_STEPPER_DRIVERS #error "You cannot have dual drivers for both Y and Z" -#endif +#endif // Enable this for dual x-carriage printers. // A dual x-carriage design has the advantage that the inactive extruder can be parked which diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index fe1e751d97..ef0fa70836 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -34,6 +34,10 @@ # define analogInputToDigitalPin(p) ((p) + A0) #endif +#ifdef AT90USB +#include "HardwareSerial.h" +#endif + #include "MarlinSerial.h" #ifndef cbi @@ -45,6 +49,15 @@ #include "WString.h" +#ifdef AT90USB + #ifdef BTENABLED + extern HardwareSerial bt; + #define MYSERIAL bt + #else + #define MYSERIAL Serial + #endif // BTENABLED +#endif + #ifdef AT90USB #define MYSERIAL Serial #else diff --git a/Marlin/MarlinSerial.cpp b/Marlin/MarlinSerial.cpp index 1358f38590..0433df2d32 100644 --- a/Marlin/MarlinSerial.cpp +++ b/Marlin/MarlinSerial.cpp @@ -320,3 +320,9 @@ MarlinSerial MSerial; #endif // whole file #endif // !AT90USB + +// For AT90USB targets use the UART for BT interfacing +#if defined(AT90USB) && defined (BTENABLED) + HardwareSerial bt; +#endif + diff --git a/Marlin/MarlinSerial.h b/Marlin/MarlinSerial.h index 9514730fa0..7ccdfd6a0e 100644 --- a/Marlin/MarlinSerial.h +++ b/Marlin/MarlinSerial.h @@ -181,4 +181,9 @@ class MarlinSerial //: public Stream extern MarlinSerial MSerial; #endif // !AT90USB +// Use the UART for BT in AT90USB configurations +#if defined(AT90USB) && defined (BTENABLED) + extern HardwareSerial bt; +#endif + #endif diff --git a/Marlin/Sd2PinMap.h b/Marlin/Sd2PinMap.h index a40729df2d..93ab943cef 100644 --- a/Marlin/Sd2PinMap.h +++ b/Marlin/Sd2PinMap.h @@ -222,10 +222,10 @@ uint8_t const SDA_PIN = 1; // D1 uint8_t const SCL_PIN = 0; // D0 // SPI port -uint8_t const SS_PIN = 20; // B0 -uint8_t const MOSI_PIN = 22; // B2 -uint8_t const MISO_PIN = 23; // B3 -uint8_t const SCK_PIN = 21; // B1 +uint8_t const SS_PIN = 20; // B0 +uint8_t const MOSI_PIN = 22; // B2 +uint8_t const MISO_PIN = 23; // B3 +uint8_t const SCK_PIN = 21; // B1 static const pin_map_t digitalPinMap[] = { {&DDRD, &PIND, &PORTD, 0}, // D0 0 diff --git a/Marlin/pins.h b/Marlin/pins.h index 12dd931346..2fd9216807 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -1541,6 +1541,92 @@ #endif // MOTHERBOARD == 82 (Brainwave) +// +// SAV Mk-I +// ----------------------------------------------------------------------------------- +/**************************************************************************************** +* SAV MkI pin assignments (AT90USB1286) +* Requires the Teensyduino software with Teensy++ 2.0 selected in Arduino IDE! + http://www.pjrc.com/teensy/teensyduino.html + RepRap Clone Wars project board. +****************************************************************************************/ +#if MOTHERBOARD == 83 // SAV Mk-I +#define KNOWN_BOARD 1 +#define AT90USB 1286 // Disable MarlinSerial etc. + +#ifndef __AVR_AT90USB1286__ +#error Oops! Make sure you have 'Teensy++ 2.0' selected from the 'Tools -> Boards' menu. +#endif + +#define LARGE_FLASH true + + +#define X_STEP_PIN 0 +#define X_DIR_PIN 1 +#define X_ENABLE_PIN 39 + +#define Y_STEP_PIN 2 +#define Y_DIR_PIN 3 +#define Y_ENABLE_PIN 38 + +#define Z_STEP_PIN 4 +#define Z_DIR_PIN 5 +#define Z_ENABLE_PIN 23 + +#define E0_STEP_PIN 6 +#define E0_DIR_PIN 7 +#define E0_ENABLE_PIN 19 + +#define HEATER_0_PIN 21 // Extruder +#define HEATER_1_PIN -1 +#define HEATER_2_PIN -1 +#define HEATER_BED_PIN 20 // Bed +#define FAN_PIN 16 // Fan -- from Teensyduino environment. + // For the fan and Teensyduino uses a different pin mapping. + + #define X_STOP_PIN 13 + #define Y_STOP_PIN 14 + #define Z_STOP_PIN 15 + #define TEMP_0_PIN 7 // Extruder / Analog pin numbering + #define TEMP_BED_PIN 6 // Bed / Analog pin numbering + +#define TEMP_1_PIN -1 +#define TEMP_2_PIN -1 + +#define SDPOWER -1 +#define SDSS 20 // PB0 - 8 in marlin env. +#define LED_PIN -1 +#define PS_ON_PIN -1 +#define KILL_PIN -1 +#define ALARM_PIN -1 +#define SDCARDDETECT -1 + + +#ifndef SDSUPPORT + // these pins are defined in the SD library if building with SD support + #define SCK_PIN 9 + #define MISO_PIN 11 + #define MOSI_PIN 10 +#endif + +#define BEEPER -1 +#define LCD_PINS_RS -1 +#define LCD_PINS_ENABLE -1 +#define LCD_PINS_D4 -1 +#define LCD_PINS_D5 -1 +#define LCD_PINS_D6 -1 +#define LCD_PINS_D7 -1 +#define BTN_EN1 -1 +#define BTN_EN2 -1 +#define BTN_ENC -1 + +// For LCD SHIFT register LCD +#define SR_DATA_PIN 0 +#define SR_CLK_PIN 1 + +#endif // MOTHERBOARD == 83 + + /**************************************************************************************** * Gen3+ pin assignment * diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 895c3ed4e9..3e3cabc1e7 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -992,14 +992,20 @@ void lcd_init() WRITE(SHIFT_LD,HIGH); #endif #else - 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); + #ifdef SR_LCD_2W_NL + pinMode (SR_DATA_PIN, OUTPUT); + pinMode (SR_CLK_PIN, OUTPUT); + #else + 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 (SDCARDDETECT > 0) WRITE(SDCARDDETECT, HIGH); lcd_oldcardstatus = IS_SD_INSERTED; diff --git a/Marlin/ultralcd_implementation_hitachi_HD44780.h b/Marlin/ultralcd_implementation_hitachi_HD44780.h index 36462d8872..c0d4989c3b 100644 --- a/Marlin/ultralcd_implementation_hitachi_HD44780.h +++ b/Marlin/ultralcd_implementation_hitachi_HD44780.h @@ -178,7 +178,16 @@ extern volatile uint16_t buttons; //an extended version of the last checked but #include #define LCD_CLASS LiquidCrystal_I2C LCD_CLASS lcd(LCD_I2C_ADDRESS, LCD_WIDTH, LCD_HEIGHT); - + +// 2 wire Non-latching LCD SR from: +// https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/schematics#!shiftregister-connection +#elif defined(SR_LCD_2W_NL) + + #include + #include + #define LCD_CLASS LiquidCrystal_SR + LCD_CLASS lcd(SR_DATA_PIN, SR_CLK_PIN); + #else // Standard directly connected LCD implementations #if LANGUAGE_CHOICE == 6 From c886f5cb132320341f8997f1708dc2d207fd0c7a Mon Sep 17 00:00:00 2001 From: Daniel Benamy Date: Wed, 30 Oct 2013 13:26:49 -0400 Subject: [PATCH 075/256] Made instructions more clear. Not sure what happened to my last commit so this includes that one + reordering the steps. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 322c30de88..5e42b43b61 100644 --- a/README.md +++ b/README.md @@ -235,13 +235,13 @@ Configuring and compilation: Install the arduino software IDE/toolset v23 (Some configurations also work with 1.x.x) http://www.arduino.cc/en/Main/Software +Download the Marlin firmware + https://github.com/ErikZalm/Marlin/tree/Marlin_v1 + Use the "Download Zip" button on the right. + For gen6/gen7 and sanguinololu the Sanguino directory in the Marlin dir needs to be copied to the arduino environment. copy ArduinoAddons\Arduino_x.x.x\sanguino \hardware\Sanguino -Copy the Marlin firmware - https://github.com/ErikZalm/Marlin/tree/Marlin_v1 - (Use the download button) - Start the arduino IDE. Select Tools -> Board -> Arduino Mega 2560 or your microcontroller Select the correct serial port in Tools ->Serial Port From 62d0b79023a4a700057583a568ab6615a47602e7 Mon Sep 17 00:00:00 2001 From: Justus Perlwitz Date: Wed, 30 Oct 2013 20:58:38 +0100 Subject: [PATCH 076/256] Fix servo control for Melzi --- Marlin/Servo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Servo.h b/Marlin/Servo.h index f2e0be1a9c..35e040c657 100644 --- a/Marlin/Servo.h +++ b/Marlin/Servo.h @@ -77,7 +77,7 @@ typedef enum { _timer3, _Nbr_16timers } timer16_Sequence_t ; //typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t ; typedef enum { _timer3, _Nbr_16timers } timer16_Sequence_t ; -#elif defined(__AVR_ATmega128__) ||defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__) +#elif defined(__AVR_ATmega128__) ||defined(__AVR_ATmega1281__) || defined(__AVR_ATmega1284P__) ||defined(__AVR_ATmega2561__) #define _useTimer3 //#define _useTimer1 //typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t ; From 5b3f60ea2e15bd2b37d3f94052da084f5e0a8178 Mon Sep 17 00:00:00 2001 From: fmalpartida Date: Wed, 30 Oct 2013 21:52:46 +0100 Subject: [PATCH 077/256] Corrected LCD only error If only an LCD is defined and no menu or keyboard defined, there is a compilation error. Added conditional compilation. --- Marlin/{BlinkM.__cpp => BlinkM.cpp} | 0 Marlin/{BlinkM.__h => BlinkM.h} | 0 Marlin/ultralcd.cpp | 3 +++ 3 files changed, 3 insertions(+) rename Marlin/{BlinkM.__cpp => BlinkM.cpp} (100%) rename Marlin/{BlinkM.__h => BlinkM.h} (100%) diff --git a/Marlin/BlinkM.__cpp b/Marlin/BlinkM.cpp similarity index 100% rename from Marlin/BlinkM.__cpp rename to Marlin/BlinkM.cpp diff --git a/Marlin/BlinkM.__h b/Marlin/BlinkM.h similarity index 100% rename from Marlin/BlinkM.__h rename to Marlin/BlinkM.h diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 3e3cabc1e7..e3e2556fab 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -19,7 +19,10 @@ int absPreheatHotendTemp; int absPreheatHPBTemp; int absPreheatFanSpeed; +#ifdef ULTIPANEL static float manual_feedrate[] = MANUAL_FEEDRATE; +#endif // ULTIPANEL + /* !Configuration settings */ //Function pointer to menu functions. From cab84e0e5bf403121dc7ba0fe90fd518993ad514 Mon Sep 17 00:00:00 2001 From: Daniel Benamy Date: Wed, 30 Oct 2013 22:44:20 -0400 Subject: [PATCH 078/256] Add (correct) missing pin definitions for Y2 I tested this and it works. --- Marlin/pins.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Marlin/pins.h b/Marlin/pins.h index 12dd931346..9f9e76938b 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -414,6 +414,10 @@ #define Z_MIN_PIN 18 #define Z_MAX_PIN -1 + #define Y2_STEP_PIN 36 + #define Y2_DIR_PIN 34 + #define Y2_ENABLE_PIN 30 + #define Z2_STEP_PIN 36 #define Z2_DIR_PIN 34 #define Z2_ENABLE_PIN 30 @@ -452,6 +456,10 @@ #define Z_MIN_PIN 18 #define Z_MAX_PIN 19 + #define Y2_STEP_PIN 36 + #define Y2_DIR_PIN 34 + #define Y2_ENABLE_PIN 30 + #define Z2_STEP_PIN 36 #define Z2_DIR_PIN 34 #define Z2_ENABLE_PIN 30 From a5e8575829ef6fb7db37ba921627c7d76d8e0bc3 Mon Sep 17 00:00:00 2001 From: Kaz Walker Date: Fri, 1 Nov 2013 14:51:50 -0600 Subject: [PATCH 079/256] Add UUID support to M115 responses. --- Marlin/Configuration.h | 8 ++++++-- Marlin/language.h | 21 ++++++++++++--------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index d6164a9047..cb5d5a9c7f 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -70,6 +70,10 @@ // Define this to set a custom name for your generic Mendel, // #define CUSTOM_MENDEL_NAME "This Mendel" +// Define this to set a unique identifier for this printer, (Used by some programs to differentiate between machines) +// You can use an online service to generate a random UUID. (eg http://www.uuidgenerator.net/version4) +// #define MACHINE_UUID "00000000-0000-0000-0000-000000000000" + // This defines the number of extruders #define EXTRUDERS 1 @@ -96,7 +100,7 @@ // 2 is 200k thermistor - ATC Semitec 204GT-2 (4.7k pullup) // 3 is mendel-parts thermistor (4.7k pullup) // 4 is 10k thermistor !! do not use it for a hotend. It gives bad resolution at high temp. !! -// 5 is 100K thermistor - ATC Semitec 104GT-2 (Used in ParCan) (4.7k pullup) +// 5 is 100K thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (4.7k pullup) // 6 is 100k EPCOS - Not as accurate as table 1 (created using a fluke thermocouple) (4.7k pullup) // 7 is 100k Honeywell thermistor 135-104LAG-J01 (4.7k pullup) // 71 is 100k Honeywell thermistor 135-104LAF-J01 (4.7k pullup) @@ -109,7 +113,7 @@ // (but gives greater accuracy and more stable PID) // 51 is 100k thermistor - EPCOS (1k pullup) // 52 is 200k thermistor - ATC Semitec 204GT-2 (1k pullup) -// 55 is 100k thermistor - ATC Semitec 104GT-2 (Used in ParCan) (1k pullup) +// 55 is 100k thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (1k pullup) #define TEMP_SENSOR_0 -1 #define TEMP_SENSOR_1 -1 diff --git a/Marlin/language.h b/Marlin/language.h index 39e459f94d..4e7a10fa92 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -38,6 +38,9 @@ #else #define MACHINE_NAME "Mendel" #endif + #ifndef MACHINE_UUID + #define MACHINE_UUID "00000000-0000-0000-0000-000000000000" + #endif #define FIRMWARE_URL "http://www.mendel-parts.com" #endif @@ -163,7 +166,7 @@ #define MSG_HEATING_COMPLETE "Heating done." #define MSG_BED_HEATING "Bed Heating." #define MSG_BED_DONE "Bed done." - #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) "\n" + #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" #define MSG_COUNT_X " Count X: " #define MSG_ERR_KILLED "Printer halted. kill() called!" #define MSG_ERR_STOPPED "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)" @@ -328,7 +331,7 @@ #define MSG_HEATING_COMPLETE "Nagrzewanie ekstrudera zakonczone." #define MSG_BED_HEATING "Nagrzewanie loza..." #define MSG_BED_DONE "Nagrzewanie loza zakonczone." - #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) "\n" + #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" #define MSG_COUNT_X " Liczenie X: " #define MSG_ERR_KILLED "Drukarka zatrzymana. Wywolano kill()" #define MSG_ERR_STOPPED "Drukarka zatrzymana z powodu bledu. Usun problem i zrestartuj drukartke komenda M999. (temperatura zostala zresetowana; ustaw temperature po restarcie)" @@ -492,7 +495,7 @@ #define MSG_HEATING_COMPLETE "Chauffe terminee." #define MSG_BED_HEATING "Chauffe du lit." #define MSG_BED_DONE "Chauffe du lit terminee." - #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) "\n" + #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" #define MSG_COUNT_X " Compteur X: " #define MSG_ERR_KILLED "Impression arretee. kill() appelee!" #define MSG_ERR_STOPPED "Impression arretee a cause d'erreurs. Corriger les erreurs et utiliser M999 pour la reprendre. (Temperature remise a zero. Reactivez la apres redemarrage)" @@ -659,7 +662,7 @@ #define MSG_HEATING_COMPLETE "Heating done." #define MSG_BED_HEATING "Bed Heating." #define MSG_BED_DONE "Bed done." - #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) "\n" + #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" #define MSG_COUNT_X " Count X:" #define MSG_ERR_KILLED "Printer halted. kill() called !!" #define MSG_ERR_STOPPED "Printer stopped due to errors. Fix the error and use M999 to restart!" @@ -830,7 +833,7 @@ #define MSG_HEATING_COMPLETE "Calentamiento Hecho." #define MSG_BED_HEATING "Calentando la base." #define MSG_BED_DONE "Base Caliente." - #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) "\n" + #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" #define MSG_COUNT_X " Cuenta X:" #define MSG_ERR_KILLED "¡¡Impresora Parada con kill()!!" #define MSG_ERR_STOPPED "¡Impresora parada por errores. Arregle el error y use M999 Para reiniciar!. (La temperatura se reestablece. Ajustela antes de continuar)" @@ -991,7 +994,7 @@ #define MSG_HEATING_COMPLETE "Наргето. " #define MSG_BED_HEATING "Нагрев стола... " #define MSG_BED_DONE "Стол нагрет. " - #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) "\n" + #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" #define MSG_COUNT_X " Count X:" #define MSG_ERR_KILLED "Принтер остановлен. вызов kill() !!" #define MSG_ERR_STOPPED "Ошибка принтера, останов. Устраните неисправность и используйте M999 для перезагрузки!. (Температура недоступна. Проверьте датчики)" @@ -1152,7 +1155,7 @@ #define MSG_HEATING_COMPLETE "Stampante Calda." #define MSG_BED_HEATING "Riscaldamento Piatto." #define MSG_BED_DONE "Piatto Pronto." - #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) "\n" + #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" #define MSG_COUNT_X " Calcola X: " #define MSG_ERR_KILLED "Stampante Calda. kill() chiamata !!" #define MSG_ERR_STOPPED "Stampante fermata a causa di errori. Risolvi l'errore e usa M999 per ripartire!. (Reset temperatura. Impostala prima di ripartire)" @@ -1322,7 +1325,7 @@ #define MSG_HEATING_COMPLETE "Aquecido." #define MSG_BED_HEATING "Aquecendo a Base." #define MSG_BED_DONE "Base quente." - #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) "\n" + #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" #define MSG_COUNT_X " Conta X:" #define MSG_ERR_KILLED "Impressora parada com kill() !!" #define MSG_ERR_STOPPED "Impressora parada por erros. Coserte o erro e use M999 para recomeçar!. (Temperatura reiniciada. Ajuste antes de recomeçar)" @@ -1488,7 +1491,7 @@ #define MSG_HEATING_COMPLETE "Lammitys valmis." #define MSG_BED_HEATING "Alusta lampiaa." #define MSG_BED_DONE "Alusta valmis." - #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) "\n" + #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" #define MSG_COUNT_X " Laskuri X: " #define MSG_ERR_KILLED "Tulostin pysaytetty. kill():ia kutsuttu!" #define MSG_ERR_STOPPED "Tulostin pysaytetty virheiden vuoksi. Korjaa virheet ja kayta M999 kaynnistaaksesi uudelleen. (Lampotila nollattiin. Aseta lampotila sen jalkeen kun jatkat.)" From 7b556d2e96b3ac9504c74951b9e795c5dd1fa91b Mon Sep 17 00:00:00 2001 From: fmalpartida Date: Sun, 3 Nov 2013 19:57:06 +0100 Subject: [PATCH 080/256] Added BT support on AT90USB devices Added AT90USB device BT connectivity support using second UART. --- Marlin/Configuration.h | 14 ++++---------- Marlin/Marlin.h | 7 ------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 39032f1fb0..129cf74778 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -22,20 +22,13 @@ // This allows the connection of wireless adapters (for instance) to non-default port pins. // Serial port 0 is still used by the Arduino bootloader regardless of this setting. #define SERIAL_PORT 0 -//#define SERIAL_PORT 1 // Define serial port 1 for bluetooth configuration in AT90USB configurations // This determines the communication speed of the printer // This determines the communication speed of the printer #define BAUDRATE 250000 // This enables the serial port associated to the Bluetooth interface -//#define BTENABLED // Enable BT interface - - -// SERIAL_PORT selects which serial port should be used for communication with the host. -// This allows the connection of wireless adapters (for instance) to non-default port pins. -// Serial port 0 is still used by the Arduino bootloader regardless of this setting. -#define SERIAL_PORT 0 +//#define BTENABLED // Enable BT interface on AT90USB devices //// The following define selects which electronics board you have. Please choose the one that matches your setup @@ -76,8 +69,7 @@ // 21 = Elefu Ra Board (v3) #ifndef MOTHERBOARD -//[FMC]#define MOTHERBOARD 7 -#define MOTHERBOARD 83 +//#define MOTHERBOARD 7 #endif // Define this to set a custom name for your generic Mendel, @@ -522,6 +514,8 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of // Shift register panels // --------------------- +// 2 wire Non-latching LCD SR from: +// https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/schematics#!shiftregister-connection //#define SR_LCD #ifdef SR_LCD #define SR_LCD_2W_NL // Non latching 2 wire shiftregister diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index ef0fa70836..ef59f3f3f4 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -51,19 +51,12 @@ #ifdef AT90USB #ifdef BTENABLED - extern HardwareSerial bt; #define MYSERIAL bt #else #define MYSERIAL Serial #endif // BTENABLED #endif -#ifdef AT90USB - #define MYSERIAL Serial -#else - #define MYSERIAL MSerial -#endif - #define SERIAL_PROTOCOL(x) (MYSERIAL.print(x)) #define SERIAL_PROTOCOL_F(x,y) (MYSERIAL.print(x,y)) #define SERIAL_PROTOCOLPGM(x) (serialprintPGM(PSTR(x))) From c244eb860c0d3b6bfd3f9269bc370b9761e03417 Mon Sep 17 00:00:00 2001 From: Charles R Date: Mon, 4 Nov 2013 12:04:04 +0100 Subject: [PATCH 081/256] If you have a switch on suicide pin, this is useful if you want to start another print with suicide feature after a print without suicide... --- Marlin/Marlin_main.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index fc53ebacd8..c22133a461 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1825,6 +1825,15 @@ void process_commands() case 80: // M80 - Turn on Power Supply SET_OUTPUT(PS_ON_PIN); //GND WRITE(PS_ON_PIN, PS_ON_AWAKE); + + // If you have a switch on suicide pin, this is useful + // if you want to start another print with suicide feature after + // a print without suicide... + #if defined SUICIDE_PIN && SUICIDE_PIN > -1 + SET_OUTPUT(SUICIDE_PIN); + WRITE(SUICIDE_PIN, HIGH); + #endif + #ifdef ULTIPANEL powersupply = true; LCD_MESSAGEPGM(WELCOME_MSG); From dc887ef99baa7179852ad534963ba9513e293849 Mon Sep 17 00:00:00 2001 From: Richard Miles Date: Sat, 9 Nov 2013 00:55:23 +0000 Subject: [PATCH 082/256] Implement M226 - GCode Initiated Pause Implemented M226 as described here: http://reprap.org/wiki/G-code#M226:_Gcode_Initiated_Pause Waits for pin to be become either HIGH, LOW or the inverse of what it was before. Allows printing to pause until user interaction --- Marlin/Marlin_main.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index fc53ebacd8..d30c847cae 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -139,6 +139,7 @@ // M218 - set hotend offset (in mm): T X Y // M220 S- set speed factor override percentage // M221 S- set extrude factor override percentage +// M226 P S- Wait until the specified pin reaches the state required // M240 - Trigger a camera to take a photograph // M250 - Set LCD contrast C (value 0..63) // M280 - set servo position absolute. P: servo index, S: angle or microseconds @@ -2147,6 +2148,57 @@ void process_commands() } } break; + + case 226: // M226 P S- Wait until the specified pin reaches the state required + { + if(code_seen('P')){ + int pin_number = code_value(); // pin number + int pin_state = -1; // required pin state - default is inverted + + if(code_seen('S')) pin_state = code_value(); // required pin state + + if(pin_state >= -1 && pin_state <= 1){ + + for(int8_t i = 0; i < (int8_t)sizeof(sensitive_pins); i++) + { + if (sensitive_pins[i] == pin_number) + { + pin_number = -1; + break; + } + } + + if (pin_number > -1) + { + st_synchronize(); + + pinMode(pin_number, INPUT); + + int target; + switch(pin_state){ + case 1: + target = HIGH; + break; + + case 0: + target = LOW; + break; + + case -1: + target = !digitalRead(pin_number); + break; + } + + while(digitalRead(pin_number) != target){ + manage_heater(); + manage_inactivity(); + lcd_update(); + } + } + } + } + } + break; #if NUM_SERVOS > 0 case 280: // M280 - set servo position absolute. P: servo index, S: angle or microseconds From 48a185d0044336eb71663f9271d9e9f7f4515120 Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Sun, 10 Nov 2013 16:36:37 +0100 Subject: [PATCH 083/256] Fixed compile errors from bad commits. --- Marlin/Configuration.h | 2 +- Marlin/Marlin.h | 2 ++ Marlin/language.h | 8 +++++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 7380b134e0..14afa75ea3 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -69,7 +69,7 @@ // 21 = Elefu Ra Board (v3) #ifndef MOTHERBOARD -//#define MOTHERBOARD 7 +#define MOTHERBOARD 7 #endif // Define this to set a custom name for your generic Mendel, diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index ef59f3f3f4..f8fa556a00 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -55,6 +55,8 @@ #else #define MYSERIAL Serial #endif // BTENABLED +#else + #define MYSERIAL MSerial #endif #define SERIAL_PROTOCOL(x) (MYSERIAL.print(x)) diff --git a/Marlin/language.h b/Marlin/language.h index 4e7a10fa92..5ebbd3fa14 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -38,12 +38,14 @@ #else #define MACHINE_NAME "Mendel" #endif - #ifndef MACHINE_UUID - #define MACHINE_UUID "00000000-0000-0000-0000-000000000000" - #endif + #define FIRMWARE_URL "http://www.mendel-parts.com" #endif +#ifndef MACHINE_UUID + #define MACHINE_UUID "00000000-0000-0000-0000-000000000000" +#endif + #define STRINGIFY_(n) #n #define STRINGIFY(n) STRINGIFY_(n) From 69af392554718a14cceef2d9271a6b461dac58a4 Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Sun, 17 Nov 2013 13:29:02 +0100 Subject: [PATCH 084/256] Added HEATERS_PARALLEL (Request from reifsnyderb) This allows a hot end with two heaters and a FET for each heater. This is useful if the FET is not capable of heating two heaters. --- Marlin/Configuration_adv.h | 7 +++++++ Marlin/temperature.cpp | 16 +++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 246eb3252e..103bb538f0 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -365,6 +365,9 @@ const unsigned int dropsegments=5; //everything with less than this number of st #define PS_ON_ASLEEP LOW #endif +// Control heater 0 and heater 1 in parallel. +#define HEATERS_PARALLEL + //=========================================================================== //=============================Buffers ============================ //=========================================================================== @@ -418,6 +421,10 @@ const unsigned int dropsegments=5; //everything with less than this number of st #error "You cannot use TEMP_SENSOR_1_AS_REDUNDANT if EXTRUDERS > 1" #endif +#if EXTRUDERS > 1 && defined HEATERS_PARALLEL + #error "You cannot use HEATERS_PARALLEL if EXTRUDERS > 1" +#endif + #if TEMP_SENSOR_0 > 0 #define THERMISTORHEATER_0 TEMP_SENSOR_0 #define HEATER_0_USES_THERMISTOR diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index decab104d5..651a816752 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -1040,7 +1040,7 @@ ISR(TIMER0_COMPB_vect) static unsigned char temp_state = 0; static unsigned char pwm_count = (1 << SOFT_PWM_SCALE); static unsigned char soft_pwm_0; - #if EXTRUDERS > 1 + #if (EXTRUDERS > 1) || defined(HEATERS_PARALLEL) static unsigned char soft_pwm_1; #endif #if EXTRUDERS > 2 @@ -1052,7 +1052,12 @@ ISR(TIMER0_COMPB_vect) if(pwm_count == 0){ soft_pwm_0 = soft_pwm[0]; - if(soft_pwm_0 > 0) WRITE(HEATER_0_PIN,1); + if(soft_pwm_0 > 0) { + WRITE(HEATER_0_PIN,1); + #ifdef HEATERS_PARALLEL + WRITE(HEATER_1_PIN,1); + #endif + } #if EXTRUDERS > 1 soft_pwm_1 = soft_pwm[1]; if(soft_pwm_1 > 0) WRITE(HEATER_1_PIN,1); @@ -1070,7 +1075,12 @@ ISR(TIMER0_COMPB_vect) if(soft_pwm_fan > 0) WRITE(FAN_PIN,1); #endif } - if(soft_pwm_0 <= pwm_count) WRITE(HEATER_0_PIN,0); + if(soft_pwm_0 <= pwm_count) { + WRITE(HEATER_0_PIN,0); + #ifdef HEATERS_PARALLEL + WRITE(HEATER_1_PIN,0); + #endif + } #if EXTRUDERS > 1 if(soft_pwm_1 <= pwm_count) WRITE(HEATER_1_PIN,0); #endif From a94e58876522bc0f8cb856f91c5609722ffb08df Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Sun, 17 Nov 2013 17:41:30 +0100 Subject: [PATCH 085/256] Changed slow buttons behavior. --- Marlin/Configuration_adv.h | 2 +- Marlin/ultralcd.cpp | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 103bb538f0..7b3ef4aede 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -366,7 +366,7 @@ const unsigned int dropsegments=5; //everything with less than this number of st #endif // Control heater 0 and heater 1 in parallel. -#define HEATERS_PARALLEL +//#define HEATERS_PARALLEL //=========================================================================== //=============================Buffers ============================ diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index e3e2556fab..163c881e16 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -142,6 +142,9 @@ volatile uint8_t buttons;//Contains the bits of the currently pressed buttons. #else volatile uint8_t buttons_reprapworld_keypad; // to store the reprapworld_keypad shiftregister values #endif +#ifdef LCD_HAS_SLOW_BUTTONS +volatile uint8_t slow_buttons;//Contains the bits of the currently pressed buttons. +#endif uint8_t currentMenuViewOffset; /* scroll offset in the current menu */ uint32_t blocking_enc; uint8_t lastEncoderBits; @@ -1013,6 +1016,9 @@ void lcd_init() WRITE(SDCARDDETECT, HIGH); lcd_oldcardstatus = IS_SD_INSERTED; #endif//(SDCARDDETECT > 0) + #ifdef LCD_HAS_SLOW_BUTTONS + slow_buttons = 0; + #endif lcd_buttons_update(); #ifdef ULTIPANEL encoderDiff = 0; @@ -1023,12 +1029,12 @@ void lcd_update() { static unsigned long timeoutToStatus = 0; - lcd_buttons_update(); - #ifdef LCD_HAS_SLOW_BUTTONS - buttons |= lcd_implementation_read_slow_buttons(); // buttons which take too long to read in interrupt context + slow_buttons = lcd_implementation_read_slow_buttons(); // buttons which take too long to read in interrupt context #endif + lcd_buttons_update(); + #if (SDCARDDETECT > 0) if((IS_SD_INSERTED != lcd_oldcardstatus)) { @@ -1170,6 +1176,9 @@ void lcd_buttons_update() newbutton |= EN_C; #endif buttons = newbutton; + #ifdef LCD_HAS_SLOW_BUTTONS + buttons |= slow_buttons; + #endif #ifdef REPRAPWORLD_KEYPAD // for the reprapworld_keypad uint8_t newbutton_reprapworld_keypad=0; From ad588e8990527db0bc06fd46f5d5f884beda36eb Mon Sep 17 00:00:00 2001 From: hcker2000 Date: Mon, 18 Nov 2013 15:49:36 -0500 Subject: [PATCH 086/256] Added new board for those of us with sanguinololu boards with ceramic resonators --- .../Arduino_1.x.x/Sanguino/boards.txt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/boards.txt b/ArduinoAddons/Arduino_1.x.x/Sanguino/boards.txt index ca2d74baf3..c1a1f08ab6 100644 --- a/ArduinoAddons/Arduino_1.x.x/Sanguino/boards.txt +++ b/ArduinoAddons/Arduino_1.x.x/Sanguino/boards.txt @@ -61,3 +61,25 @@ atmega1284.build.f_cpu=16000000L atmega1284.build.core=arduino atmega1284.build.variant=standard # + +############################################################## + +atmega1284.name=Sanguino W/ ATmega1284p 16mhz ceramic resonator + +atmega1284.upload.protocol=stk500 +atmega1284.upload.maximum_size=131072 +atmega1284.upload.speed=57600 + +atmega1284.bootloader.low_fuses=0xD6 +atmega1284.bootloader.high_fuses=0xDC +atmega1284.bootloader.extended_fuses=0xFD +atmega1284.bootloader.path=atmega +atmega1284.bootloader.file=ATmegaBOOT_168_atmega1284p.hex +atmega1284.bootloader.unlock_bits=0x3F +atmega1284.bootloader.lock_bits=0x0F + +atmega1284.build.mcu=atmega1284p +atmega1284.build.f_cpu=16000000L +atmega1284.build.core=arduino +atmega1284.build.variant=standard +# From 35905ea4f971c653a3251a7e0d8399c488adbaca Mon Sep 17 00:00:00 2001 From: Alex Borro Date: Wed, 27 Nov 2013 18:13:38 -0200 Subject: [PATCH 087/256] Allow heaters to stay full On when PWM=127 In previous version, even with PWM = 127, the system turns the FET off and then on in the next cycle. This bevavior may increase the FET heat dissipation. It was fixed keeping the FET always On when PWM=127. --- Marlin/temperature.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index 651a816752..48960488b8 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -1057,41 +1057,42 @@ ISR(TIMER0_COMPB_vect) #ifdef HEATERS_PARALLEL WRITE(HEATER_1_PIN,1); #endif - } + } else WRITE(HEATER_0_PIN,0); + #if EXTRUDERS > 1 soft_pwm_1 = soft_pwm[1]; - if(soft_pwm_1 > 0) WRITE(HEATER_1_PIN,1); + if(soft_pwm_1 > 0) WRITE(HEATER_1_PIN,1); else WRITE(HEATER_1_PIN,0); #endif #if EXTRUDERS > 2 soft_pwm_2 = soft_pwm[2]; - if(soft_pwm_2 > 0) WRITE(HEATER_2_PIN,1); + if(soft_pwm_2 > 0) WRITE(HEATER_2_PIN,1); else WRITE(HEATER_2_PIN,0); #endif #if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 soft_pwm_b = soft_pwm_bed; - if(soft_pwm_b > 0) WRITE(HEATER_BED_PIN,1); + if(soft_pwm_b > 0) WRITE(HEATER_BED_PIN,1); else WRITE(HEATER_BED_PIN,0); #endif #ifdef FAN_SOFT_PWM soft_pwm_fan = fanSpeedSoftPwm / 2; - if(soft_pwm_fan > 0) WRITE(FAN_PIN,1); + if(soft_pwm_fan > 0) WRITE(FAN_PIN,1); else WRITE(FAN_PIN,0); #endif } - if(soft_pwm_0 <= pwm_count) { + if(soft_pwm_0 < pwm_count) { WRITE(HEATER_0_PIN,0); #ifdef HEATERS_PARALLEL WRITE(HEATER_1_PIN,0); #endif } #if EXTRUDERS > 1 - if(soft_pwm_1 <= pwm_count) WRITE(HEATER_1_PIN,0); + if(soft_pwm_1 < pwm_count) WRITE(HEATER_1_PIN,0); #endif #if EXTRUDERS > 2 - if(soft_pwm_2 <= pwm_count) WRITE(HEATER_2_PIN,0); + if(soft_pwm_2 < pwm_count) WRITE(HEATER_2_PIN,0); #endif #if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 - if(soft_pwm_b <= pwm_count) WRITE(HEATER_BED_PIN,0); + if(soft_pwm_b < pwm_count) WRITE(HEATER_BED_PIN,0); #endif #ifdef FAN_SOFT_PWM - if(soft_pwm_fan <= pwm_count) WRITE(FAN_PIN,0); + if(soft_pwm_fan < pwm_count) WRITE(FAN_PIN,0); #endif pwm_count += (1 << SOFT_PWM_SCALE); From b33375d438aa300bd705eb0d2fb16dd8e287221a Mon Sep 17 00:00:00 2001 From: Alex Borro Date: Wed, 27 Nov 2013 22:37:35 -0200 Subject: [PATCH 088/256] Z Axis Safe Homing when using Z Probe Recommended for those who are using the Z Probe for Z Homing (as Z-Endstop) This feature has two changes: 1) Allow user to choose where the Z Probe will touch the bed when homing all axis together (G28) by setting below defines: Z_SAFE_HOMING_X_POINT Z_SAFE_HOMING_Y_POINT 2) Prevents the user to perform Z Axis Homing when the Z Probe is outsite bed. --- Marlin/Configuration.h | 40 +++++++++++++----- Marlin/Marlin.h | 13 +++--- Marlin/Marlin_main.cpp | 92 +++++++++++++++++++++++++++++++++--------- Marlin/language.h | 18 +++++++++ 4 files changed, 128 insertions(+), 35 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 14afa75ea3..c5b96b280b 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -305,6 +305,17 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #define min_software_endstops true // If true, axis won't move to coordinates less than HOME_POS. #define max_software_endstops true // If true, axis won't move to coordinates greater than the defined lengths below. +// Travel limits after homing +#define X_MAX_POS 205 +#define X_MIN_POS 0 +#define Y_MAX_POS 205 +#define Y_MIN_POS 0 +#define Z_MAX_POS 200 +#define Z_MIN_POS 0 + +#define X_MAX_LENGTH (X_MAX_POS - X_MIN_POS) +#define Y_MAX_LENGTH (Y_MAX_POS - Y_MIN_POS) +#define Z_MAX_LENGTH (Z_MAX_POS - Z_MIN_POS) //============================= Bed Auto Leveling =========================== //#define ENABLE_AUTO_BED_LEVELING // Delete the comment to enable (remove // at the start of the line) @@ -336,20 +347,27 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of // You MUST HAVE the SERVO_ENDSTOPS defined to use here a value higher than zero otherwise your code will not compile. // #define PROBE_SERVO_DEACTIVATION_DELAY 300 + + +//If you have enabled the Bed Auto Levelling and are using the same Z Probe for Z Homing, +//it is highly recommended you let this Z_SAFE_HOMING enabled!!! + + #define Z_SAFE_HOMING // This feature is meant to avoid Z homing with probe outside the bed area. + // When defined, it will: + // - Allow Z homing only after X and Y homing AND stepper drivers still enabled + // - If stepper drivers timeout, it will need X and Y homing again before Z homing + // - Position the probe in a defined XY point before Z Homing when homing all axis (G28) + // - Block Z homing only when the probe is outside bed area. + + #ifdef Z_SAFE_HOMING + + #define Z_SAFE_HOMING_X_POINT (X_MAX_LENGTH/2) // X point for Z homing when homing all axis (G28) + #define Z_SAFE_HOMING_Y_POINT (Y_MAX_LENGTH/2) // Y point for Z homing when homing all axis (G28) + + #endif #endif -// Travel limits after homing -#define X_MAX_POS 205 -#define X_MIN_POS 0 -#define Y_MAX_POS 205 -#define Y_MIN_POS 0 -#define Z_MAX_POS 200 -#define Z_MIN_POS 0 - -#define X_MAX_LENGTH (X_MAX_POS - X_MIN_POS) -#define Y_MAX_LENGTH (Y_MAX_POS - Y_MIN_POS) -#define Z_MAX_LENGTH (Z_MAX_POS - Z_MIN_POS) // The position of the homing switches //#define MANUAL_HOME_POSITIONS // If defined, MANUAL_*_HOME_POS below will be used diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index f8fa556a00..be4115e068 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -107,10 +107,10 @@ void manage_inactivity(); #if defined(DUAL_X_CARRIAGE) && defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1 \ && defined(X2_ENABLE_PIN) && X2_ENABLE_PIN > -1 #define enable_x() do { WRITE(X_ENABLE_PIN, X_ENABLE_ON); WRITE(X2_ENABLE_PIN, X_ENABLE_ON); } while (0) - #define disable_x() do { WRITE(X_ENABLE_PIN,!X_ENABLE_ON); WRITE(X2_ENABLE_PIN,!X_ENABLE_ON); } while (0) + #define disable_x() do { WRITE(X_ENABLE_PIN,!X_ENABLE_ON); WRITE(X2_ENABLE_PIN,!X_ENABLE_ON); axis_known_position[X_AXIS] = false; } while (0) #elif defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1 #define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) - #define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON) + #define disable_x() { WRITE(X_ENABLE_PIN,!X_ENABLE_ON); axis_known_position[X_AXIS] = false; } #else #define enable_x() ; #define disable_x() ; @@ -119,10 +119,10 @@ void manage_inactivity(); #if defined(Y_ENABLE_PIN) && Y_ENABLE_PIN > -1 #ifdef Y_DUAL_STEPPER_DRIVERS #define enable_y() { WRITE(Y_ENABLE_PIN, Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, Y_ENABLE_ON); } - #define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, !Y_ENABLE_ON); } + #define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); WRITE(Y2_ENABLE_PIN, !Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; } #else #define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON) - #define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON) + #define disable_y() { WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; } #endif #else #define enable_y() ; @@ -132,10 +132,10 @@ void manage_inactivity(); #if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1 #ifdef Z_DUAL_STEPPER_DRIVERS #define enable_z() { WRITE(Z_ENABLE_PIN, Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN, Z_ENABLE_ON); } - #define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); } + #define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; } #else #define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON) - #define disable_z() WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON) + #define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; } #endif #else #define enable_z() ; @@ -209,6 +209,7 @@ extern float endstop_adj[3]; #endif extern float min_pos[3]; extern float max_pos[3]; +extern bool axis_known_position[3]; extern int fanSpeed; #ifdef BARICUDA extern int ValvePressure; diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 47c5b1ab44..1537d3199a 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -43,6 +43,7 @@ #include "ConfigurationStore.h" #include "language.h" #include "pins_arduino.h" +#include "math.h" #ifdef BLINKM #include "BlinkM.h" @@ -191,6 +192,7 @@ float endstop_adj[3]={0,0,0}; #endif float min_pos[3] = { X_MIN_POS, Y_MIN_POS, Z_MIN_POS }; float max_pos[3] = { X_MAX_POS, Y_MAX_POS, Z_MAX_POS }; +bool axis_known_position[3] = {false, false, false}; // Extruder offset #if EXTRUDERS > 1 @@ -949,16 +951,11 @@ static void homeaxis(int axis) { current_position[axis] = 0; plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + // Engage Servo endstop if enabled #ifdef SERVO_ENDSTOPS #if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) if (axis==Z_AXIS) { - #if defined (Z_RAISE_BEFORE_HOMING) && (Z_RAISE_BEFORE_HOMING > 0) - destination[axis] = Z_RAISE_BEFORE_HOMING * axis_home_dir * (-1); // Set destination away from bed - feedrate = max_feedrate[axis]; - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate, active_extruder); - st_synchronize(); - #endif engage_z_probe(); } else @@ -1000,6 +997,7 @@ static void homeaxis(int axis) { destination[axis] = current_position[axis]; feedrate = 0.0; endstops_hit_on_purpose(); + axis_known_position[axis] = true; // Retract Servo endstop if enabled #ifdef SERVO_ENDSTOPS @@ -1208,12 +1206,6 @@ void process_commands() HOMEAXIS(Y); } - #if Z_HOME_DIR < 0 // If homing towards BED do Z last - if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { - HOMEAXIS(Z); - } - #endif - if(code_seen(axis_codes[X_AXIS])) { if(code_value_long() != 0) { @@ -1226,14 +1218,74 @@ void process_commands() current_position[Y_AXIS]=code_value()+add_homeing[1]; } } + + #if Z_HOME_DIR < 0 // If homing towards BED do Z last + #ifndef Z_SAFE_HOMING + if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { + #if defined (Z_RAISE_BEFORE_HOMING) && (Z_RAISE_BEFORE_HOMING > 0) + destination[Z_AXIS] = Z_RAISE_BEFORE_HOMING * home_dir(Z_AXIS) * (-1); // Set destination away from bed + feedrate = max_feedrate[Z_AXIS]; + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate, active_extruder); + st_synchronize(); + #endif + HOMEAXIS(Z); + } + #else // Z Safe mode activated. + if(home_all_axis) { + destination[X_AXIS] = round(Z_SAFE_HOMING_X_POINT - X_PROBE_OFFSET_FROM_EXTRUDER); + destination[Y_AXIS] = round(Z_SAFE_HOMING_Y_POINT - Y_PROBE_OFFSET_FROM_EXTRUDER); + destination[Z_AXIS] = Z_RAISE_BEFORE_HOMING * home_dir(Z_AXIS) * (-1); // Set destination away from bed + feedrate = XY_TRAVEL_SPEED; + current_position[Z_AXIS] = 0; + + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate, active_extruder); + st_synchronize(); + current_position[X_AXIS] = destination[X_AXIS]; + current_position[Y_AXIS] = destination[Y_AXIS]; + HOMEAXIS(Z); + } + // Let's see if X and Y are homed and probe is inside bed area. + if(code_seen(axis_codes[Z_AXIS])) { + if ( (axis_known_position[X_AXIS]) && (axis_known_position[Y_AXIS]) \ + && (current_position[X_AXIS]+X_PROBE_OFFSET_FROM_EXTRUDER >= X_MIN_POS) \ + && (current_position[X_AXIS]+X_PROBE_OFFSET_FROM_EXTRUDER <= X_MAX_POS) \ + && (current_position[Y_AXIS]+Y_PROBE_OFFSET_FROM_EXTRUDER >= Y_MIN_POS) \ + && (current_position[Y_AXIS]+Y_PROBE_OFFSET_FROM_EXTRUDER <= Y_MAX_POS)) { + + current_position[Z_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + destination[Z_AXIS] = Z_RAISE_BEFORE_HOMING * home_dir(Z_AXIS) * (-1); // Set destination away from bed + feedrate = max_feedrate[Z_AXIS]; + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate, active_extruder); + st_synchronize(); + + HOMEAXIS(Z); + } else if (!((axis_known_position[X_AXIS]) && (axis_known_position[Y_AXIS]))) { + LCD_MESSAGEPGM(MSG_POSITION_UNKNOWN); + SERIAL_ECHO_START; + SERIAL_ECHOLNPGM(MSG_POSITION_UNKNOWN); + } else { + LCD_MESSAGEPGM(MSG_ZPROBE_OUT); + SERIAL_ECHO_START; + SERIAL_ECHOLNPGM(MSG_ZPROBE_OUT); + } + } + #endif + #endif + + + if(code_seen(axis_codes[Z_AXIS])) { if(code_value_long() != 0) { current_position[Z_AXIS]=code_value()+add_homeing[2]; } } #ifdef ENABLE_AUTO_BED_LEVELING - current_position[Z_AXIS] -= Z_PROBE_OFFSET_FROM_EXTRUDER; //Add Z_Probe offset (the distance is negative) + if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { + current_position[Z_AXIS] -= Z_PROBE_OFFSET_FROM_EXTRUDER; //Add Z_Probe offset (the distance is negative) + } #endif plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); #endif // else DELTA @@ -1275,9 +1327,9 @@ void process_commands() do_blocking_move_to(LEFT_PROBE_BED_POSITION - X_PROBE_OFFSET_FROM_EXTRUDER, BACK_PROBE_BED_POSITION - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]); engage_z_probe(); // Engage Z Servo endstop if available - run_z_probe(); float z_at_xLeft_yBack = current_position[Z_AXIS]; + retract_z_probe(); SERIAL_PROTOCOLPGM("Bed x: "); SERIAL_PROTOCOL(LEFT_PROBE_BED_POSITION); @@ -1290,9 +1342,12 @@ void process_commands() // prob 2 do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); do_blocking_move_to(LEFT_PROBE_BED_POSITION - X_PROBE_OFFSET_FROM_EXTRUDER, FRONT_PROBE_BED_POSITION - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]); + + engage_z_probe(); // Engage Z Servo endstop if available run_z_probe(); float z_at_xLeft_yFront = current_position[Z_AXIS]; - + retract_z_probe(); + SERIAL_PROTOCOLPGM("Bed x: "); SERIAL_PROTOCOL(LEFT_PROBE_BED_POSITION); SERIAL_PROTOCOLPGM(" y: "); @@ -1305,9 +1360,12 @@ void process_commands() do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); // the current position will be updated by the blocking move so the head will not lower on this next call. do_blocking_move_to(RIGHT_PROBE_BED_POSITION - X_PROBE_OFFSET_FROM_EXTRUDER, FRONT_PROBE_BED_POSITION - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]); + + engage_z_probe(); // Engage Z Servo endstop if available run_z_probe(); float z_at_xRight_yFront = current_position[Z_AXIS]; - + retract_z_probe(); // Retract Z Servo endstop if available + SERIAL_PROTOCOLPGM("Bed x: "); SERIAL_PROTOCOL(RIGHT_PROBE_BED_POSITION); SERIAL_PROTOCOLPGM(" y: "); @@ -1320,8 +1378,6 @@ void process_commands() set_bed_level_equation(z_at_xLeft_yFront, z_at_xRight_yFront, z_at_xLeft_yBack); - retract_z_probe(); // Retract Z Servo endstop if available - st_synchronize(); // The following code correct the Z height difference from z-probe position and hotend tip position. diff --git a/Marlin/language.h b/Marlin/language.h index 5ebbd3fa14..48cd4118a0 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -136,6 +136,8 @@ #define MSG_FILAMENTCHANGE "Change filament" #define MSG_INIT_SDCARD "Init. SD-Card" #define MSG_CNG_SDCARD "Change SD-Card" + #define MSG_ZPROBE_OUT "ZProbe Outside Bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" // Serial Console Messages @@ -301,6 +303,8 @@ #define MSG_FILAMENTCHANGE "Change filament" #define MSG_INIT_SDCARD "Init. SD-Card" #define MSG_CNG_SDCARD "Change SD-Card" + #define MSG_ZPROBE_OUT "ZProbe Outside Bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" // Serial Console Messages @@ -465,6 +469,8 @@ #define MSG_FILAMENTCHANGE "Changer filament" #define MSG_INIT_SDCARD "Init. la carte SD" #define MSG_CNG_SDCARD "Changer de carte SD" + #define MSG_ZPROBE_OUT "ZProbe Outside Bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" // Serial Console Messages @@ -632,6 +638,8 @@ #define MSG_FILAMENTCHANGE "Filament wechseln" #define MSG_INIT_SDCARD "Init. SD-Card" #define MSG_CNG_SDCARD "Change SD-Card" + #define MSG_ZPROBE_OUT "ZProbe Outside Bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" // Serial Console Messages @@ -803,6 +811,8 @@ #define MSG_RETRACT_ARROW "Retraer" #define MSG_PART_RELEASE "Desacople Parcial" #define MSG_STEPPER_RELEASED "Desacoplada." + #define MSG_ZPROBE_OUT "ZProbe Outside Bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" // Serial Console Messages @@ -964,6 +974,8 @@ #define MSG_FILAMENTCHANGE "Change filament" #define MSG_INIT_SDCARD "Init. SD-Card" #define MSG_CNG_SDCARD "Change SD-Card" + #define MSG_ZPROBE_OUT "ZProbe Outside Bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" // Serial Console Messages @@ -1125,6 +1137,8 @@ #define MSG_FILAMENTCHANGE "Cambia filamento" #define MSG_INIT_SDCARD "Iniz. SD-Card" #define MSG_CNG_SDCARD "Cambia SD-Card" + #define MSG_ZPROBE_OUT "ZProbe Outside Bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" // Serial Console Messages @@ -1295,6 +1309,8 @@ #define MSG_FILAMENTCHANGE "Change filament" #define MSG_INIT_SDCARD "Init. SD-Card" #define MSG_CNG_SDCARD "Change SD-Card" + #define MSG_ZPROBE_OUT "Sonda fora da mesa" + #define MSG_POSITION_UNKNOWN "Home X/Y antes de Z" // Serial Console Messages @@ -1461,6 +1477,8 @@ #define MSG_FILAMENTCHANGE "Change filament" #define MSG_INIT_SDCARD "Init. SD-Card" #define MSG_CNG_SDCARD "Change SD-Card" + #define MSG_ZPROBE_OUT "ZProbe Outside Bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" // Serial Console Messages From 5c44f6c434073180b10859d24bcec45e64b98fcd Mon Sep 17 00:00:00 2001 From: Alex Borro Date: Wed, 27 Nov 2013 23:23:06 -0200 Subject: [PATCH 089/256] Bed Heater monitoring in Controller Fan In some cases the Bed Heater FET heats up more then stepper drivers, so this change add the bed monitoring to the controller fan. As soon as the bed heater is turned on, the controller fan will run as well. --- Marlin/Marlin_main.cpp | 2 +- Marlin/temperature.cpp | 4 +++- Marlin/temperature.h | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 1537d3199a..8993ca6955 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -3065,7 +3065,7 @@ void controllerFan() { lastMotorCheck = millis(); - if(!READ(X_ENABLE_PIN) || !READ(Y_ENABLE_PIN) || !READ(Z_ENABLE_PIN) + if(!READ(X_ENABLE_PIN) || !READ(Y_ENABLE_PIN) || !READ(Z_ENABLE_PIN) || (soft_pwm_bed > 0) #if EXTRUDERS > 2 || !READ(E2_ENABLE_PIN) #endif diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index 48960488b8..29050b84f5 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -65,6 +65,8 @@ float current_temperature_bed = 0.0; #ifdef FAN_SOFT_PWM unsigned char fanSpeedSoftPwm; #endif + +unsigned char soft_pwm_bed; #ifdef BABYSTEPPING volatile int babystepsTodo[3]={0,0,0}; @@ -105,7 +107,7 @@ static volatile bool temp_meas_ready = false; static unsigned long previous_millis_bed_heater; #endif //PIDTEMPBED static unsigned char soft_pwm[EXTRUDERS]; - static unsigned char soft_pwm_bed; + #ifdef FAN_SOFT_PWM static unsigned char soft_pwm_fan; #endif diff --git a/Marlin/temperature.h b/Marlin/temperature.h index 1bf47e02ed..82de2402f0 100644 --- a/Marlin/temperature.h +++ b/Marlin/temperature.h @@ -45,6 +45,10 @@ extern float current_temperature_bed; extern float redundant_temperature; #endif +#if defined(CONTROLLERFAN_PIN) && CONTROLLERFAN_PIN > -1 + extern unsigned char soft_pwm_bed; +#endif + #ifdef PIDTEMP extern float Kp,Ki,Kd,Kc; float scalePID_i(float i); From b64661070ed15cefa12f34bf8e9dc7d4661fa8ed Mon Sep 17 00:00:00 2001 From: fsantini Date: Fri, 6 Dec 2013 21:32:21 +0100 Subject: [PATCH 090/256] Fixed the plane vector equation to a simpler one (only dependent on the normal) Removed the calculation of the inverse matrix since the rotation matrix is orthogonal, therefore inverted == transposed. Much simpler and mathematically robust. --- Marlin/Marlin_main.cpp | 5 ++- Marlin/planner.cpp | 2 +- Marlin/vector_3.cpp | 73 +++++++++++++++--------------------------- Marlin/vector_3.h | 4 +-- 4 files changed, 30 insertions(+), 54 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 8993ca6955..6c662e5099 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -807,11 +807,11 @@ static void set_bed_level_equation(float z_at_xLeft_yFront, float z_at_xRight_yF vector_3 xPositive = (xRightyFront - xLeftyFront).get_normal(); vector_3 yPositive = (xLeftyBack - xLeftyFront).get_normal(); - vector_3 planeNormal = vector_3::cross(yPositive, xPositive).get_normal(); + vector_3 planeNormal = vector_3::cross(xPositive, yPositive).get_normal(); //planeNormal.debug("planeNormal"); //yPositive.debug("yPositive"); - matrix_3x3 bedLevel = matrix_3x3::create_look_at(planeNormal, yPositive); + plan_bed_level_matrix = matrix_3x3::create_look_at(planeNormal); //bedLevel.debug("bedLevel"); //plan_bed_level_matrix.debug("bed level before"); @@ -819,7 +819,6 @@ static void set_bed_level_equation(float z_at_xLeft_yFront, float z_at_xRight_yF //uncorrected_position.debug("position before"); // and set our bed level equation to do the right thing - plan_bed_level_matrix = matrix_3x3::create_inverse(bedLevel); //plan_bed_level_matrix.debug("bed level after"); vector_3 corrected_position = plan_get_position(); diff --git a/Marlin/planner.cpp b/Marlin/planner.cpp index 008c8d257f..d9299c4a7e 100644 --- a/Marlin/planner.cpp +++ b/Marlin/planner.cpp @@ -942,7 +942,7 @@ vector_3 plan_get_position() { //position.debug("in plan_get position"); //plan_bed_level_matrix.debug("in plan_get bed_level"); - matrix_3x3 inverse = matrix_3x3::create_inverse(plan_bed_level_matrix); + matrix_3x3 inverse = matrix_3x3::transpose(plan_bed_level_matrix); //inverse.debug("in plan_get inverse"); position.apply_rotation(inverse); //position.debug("after rotation"); diff --git a/Marlin/vector_3.cpp b/Marlin/vector_3.cpp index 8c8a0e1dc7..c9f4803231 100644 --- a/Marlin/vector_3.cpp +++ b/Marlin/vector_3.cpp @@ -127,57 +127,34 @@ void matrix_3x3::set_to_identity() matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; } -matrix_3x3 matrix_3x3::create_look_at(vector_3 target, vector_3 up) -{ - // There are lots of examples of look at code on the internet that don't do all these noramize and also find the position - // through several dot products. The problem with them is that they have a bit of error in that all the vectors arn't normal and need to be. - vector_3 z_row = vector_3(-target.x, -target.y, -target.z).get_normal(); - vector_3 x_row = vector_3::cross(up, z_row).get_normal(); - vector_3 y_row = vector_3::cross(z_row, x_row).get_normal(); - - //x_row.debug("x_row"); - //y_row.debug("y_row"); - //z_row.debug("z_row"); - - matrix_3x3 rot = matrix_3x3::create_from_rows(vector_3(x_row.x, y_row.x, z_row.x), - vector_3(x_row.y, y_row.y, z_row.y), - vector_3(x_row.z, y_row.z, z_row.z)); - - //rot.debug("rot"); +matrix_3x3 matrix_3x3::create_look_at(vector_3 target) +{ + vector_3 z_row = vector_3(target.x, target.y, target.z).get_normal(); + vector_3 x_row = vector_3(1, 0, -target.x/target.z).get_normal(); + vector_3 y_row = vector_3(0, 1, -target.y/target.z).get_normal(); + + // x_row.debug("x_row"); + // y_row.debug("y_row"); + // z_row.debug("z_row"); + + + // create the matrix already correctly transposed + matrix_3x3 rot = matrix_3x3::create_from_rows(vector_3(x_row.x, x_row.y, x_row.z), + vector_3(y_row.x, y_row.y, y_row.z), + vector_3(z_row.x, z_row.y, z_row.z)); + + // rot.debug("rot"); return rot; } -matrix_3x3 matrix_3x3::create_inverse(matrix_3x3 original) -{ - //original.debug("original"); - float* A = original.matrix; - float determinant = - + A[0 * 3 + 0] * (A[1 * 3 + 1] * A[2 * 3 + 2] - A[2 * 3 + 1] * A[1 * 3 + 2]) - - A[0 * 3 + 1] * (A[1 * 3 + 0] * A[2 * 3 + 2] - A[1 * 3 + 2] * A[2 * 3 + 0]) - + A[0 * 3 + 2] * (A[1 * 3 + 0] * A[2 * 3 + 1] - A[1 * 3 + 1] * A[2 * 3 + 0]); - matrix_3x3 inverse; - inverse.matrix[0 * 3 + 0] = +(A[1 * 3 + 1] * A[2 * 3 + 2] - A[2 * 3 + 1] * A[1 * 3 + 2]) / determinant; - inverse.matrix[0 * 3 + 1] = -(A[0 * 3 + 1] * A[2 * 3 + 2] - A[0 * 3 + 2] * A[2 * 3 + 1]) / determinant; - inverse.matrix[0 * 3 + 2] = +(A[0 * 3 + 1] * A[1 * 3 + 2] - A[0 * 3 + 2] * A[1 * 3 + 1]) / determinant; - inverse.matrix[1 * 3 + 0] = -(A[1 * 3 + 0] * A[2 * 3 + 2] - A[1 * 3 + 2] * A[2 * 3 + 0]) / determinant; - inverse.matrix[1 * 3 + 1] = +(A[0 * 3 + 0] * A[2 * 3 + 2] - A[0 * 3 + 2] * A[2 * 3 + 0]) / determinant; - inverse.matrix[1 * 3 + 2] = -(A[0 * 3 + 0] * A[1 * 3 + 2] - A[1 * 3 + 0] * A[0 * 3 + 2]) / determinant; - inverse.matrix[2 * 3 + 0] = +(A[1 * 3 + 0] * A[2 * 3 + 1] - A[2 * 3 + 0] * A[1 * 3 + 1]) / determinant; - inverse.matrix[2 * 3 + 1] = -(A[0 * 3 + 0] * A[2 * 3 + 1] - A[2 * 3 + 0] * A[0 * 3 + 1]) / determinant; - inverse.matrix[2 * 3 + 2] = +(A[0 * 3 + 0] * A[1 * 3 + 1] - A[1 * 3 + 0] * A[0 * 3 + 1]) / determinant; - - vector_3 row0 = vector_3(inverse.matrix[0 * 3 + 0], inverse.matrix[0 * 3 + 1], inverse.matrix[0 * 3 + 2]); - vector_3 row1 = vector_3(inverse.matrix[1 * 3 + 0], inverse.matrix[1 * 3 + 1], inverse.matrix[1 * 3 + 2]); - vector_3 row2 = vector_3(inverse.matrix[2 * 3 + 0], inverse.matrix[2 * 3 + 1], inverse.matrix[2 * 3 + 2]); - - row0.normalize(); - row1.normalize(); - row2.normalize(); - - inverse = matrix_3x3::create_from_rows(row0, row1, row2); - - //inverse.debug("inverse"); - return inverse; + +matrix_3x3 matrix_3x3::transpose(matrix_3x3 original) +{ + matrix_3x3 new_matrix; + new_matrix.matrix[0] = original.matrix[0]; new_matrix.matrix[1] = original.matrix[3]; new_matrix.matrix[2] = original.matrix[6]; + new_matrix.matrix[3] = original.matrix[1]; new_matrix.matrix[4] = original.matrix[4]; new_matrix.matrix[5] = original.matrix[7]; + new_matrix.matrix[6] = original.matrix[2]; new_matrix.matrix[7] = original.matrix[5]; new_matrix.matrix[8] = original.matrix[8]; + return new_matrix; } void matrix_3x3::debug(char* title) diff --git a/Marlin/vector_3.h b/Marlin/vector_3.h index b08c336e8f..0b9decafad 100644 --- a/Marlin/vector_3.h +++ b/Marlin/vector_3.h @@ -47,8 +47,8 @@ struct matrix_3x3 float matrix[9]; static matrix_3x3 create_from_rows(vector_3 row_0, vector_3 row_1, vector_3 row_2); - static matrix_3x3 create_look_at(vector_3 target, vector_3 up); - static matrix_3x3 create_inverse(matrix_3x3 original); + static matrix_3x3 create_look_at(vector_3 target); + static matrix_3x3 transpose(matrix_3x3 original); void set_to_identity(); From cc2925b70527728009a863c976017f0eeb42fe9b Mon Sep 17 00:00:00 2001 From: fsantini Date: Fri, 6 Dec 2013 21:46:25 +0100 Subject: [PATCH 091/256] Implemented a least squares fit of the bed equation for auto bed leveling. The code for the LSQ solver (qr_solve) is copyrighted by John Burkardt and released under LGPL here: http://people.sc.fsu.edu/~%20jburkardt/c_src/qr_solve/qr_solve.html (see qr_solve.cpp for further copyright information) --- Marlin/Configuration.h | 9 + Marlin/Marlin_main.cpp | 114 ++- Marlin/qr_solve.cpp | 1932 ++++++++++++++++++++++++++++++++++++++++ Marlin/qr_solve.h | 22 + 4 files changed, 2075 insertions(+), 2 deletions(-) create mode 100644 Marlin/qr_solve.cpp create mode 100644 Marlin/qr_solve.h diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index c5b96b280b..8cb0a141c3 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -366,6 +366,15 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #endif + // with accurate bed leveling, the bed is sampled in a ACCURATE_BED_LEVELING_POINTSxACCURATE_BED_LEVELING_POINTS grid and least squares solution is calculated + // Note: this feature occupies 10'206 byte + #define ACCURATE_BED_LEVELING + + #ifdef ACCURATE_BED_LEVELING + // I wouldn't see a reason to go above 3 (=9 probing points on the bed) + #define ACCURATE_BED_LEVELING_POINTS 2 + #endif + #endif diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 6c662e5099..db9686f3ed 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -31,6 +31,9 @@ #ifdef ENABLE_AUTO_BED_LEVELING #include "vector_3.h" + #ifdef ACCURATE_BED_LEVELING + #include "qr_solve.h" + #endif #endif // ENABLE_AUTO_BED_LEVELING #include "ultralcd.h" @@ -798,6 +801,35 @@ static void axis_is_at_home(int axis) { } #ifdef ENABLE_AUTO_BED_LEVELING +#ifdef ACCURATE_BED_LEVELING +static void set_bed_level_equation_lsq(double *plane_equation_coefficients) +{ + vector_3 planeNormal = vector_3(-plane_equation_coefficients[0], -plane_equation_coefficients[1], 1); + planeNormal.debug("planeNormal"); + plan_bed_level_matrix = matrix_3x3::create_look_at(planeNormal); + //bedLevel.debug("bedLevel"); + + plan_bed_level_matrix.debug("bed level before"); + //vector_3 uncorrected_position = plan_get_position_mm(); + //uncorrected_position.debug("position before"); + + // and set our bed level equation to do the right thing +// plan_bed_level_matrix = matrix_3x3::create_inverse(bedLevel); +// plan_bed_level_matrix.debug("bed level after"); + + vector_3 corrected_position = plan_get_position(); +// corrected_position.debug("position after"); + current_position[X_AXIS] = corrected_position.x; + current_position[Y_AXIS] = corrected_position.y; + current_position[Z_AXIS] = corrected_position.z; + + // but the bed at 0 so we don't go below it. + current_position[Z_AXIS] = -Z_PROBE_OFFSET_FROM_EXTRUDER; // in the lsq we reach here after raising the extruder due to the loop structure + + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); +} + +#else static void set_bed_level_equation(float z_at_xLeft_yFront, float z_at_xRight_yFront, float z_at_xLeft_yBack) { plan_bed_level_matrix.set_to_identity(); @@ -832,6 +864,7 @@ static void set_bed_level_equation(float z_at_xLeft_yFront, float z_at_xRight_yF plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); } +#endif // ACCURATE_BED_LEVELING static void run_z_probe() { plan_bed_level_matrix.set_to_identity(); @@ -1320,7 +1353,82 @@ void process_commands() setup_for_endstop_move(); feedrate = homing_feedrate[Z_AXIS]; - +#ifdef ACCURATE_BED_LEVELING + + int xGridSpacing = (RIGHT_PROBE_BED_POSITION - LEFT_PROBE_BED_POSITION) / (ACCURATE_BED_LEVELING_POINTS-1); + int yGridSpacing = (BACK_PROBE_BED_POSITION - FRONT_PROBE_BED_POSITION) / (ACCURATE_BED_LEVELING_POINTS-1); + + + // solve the plane equation ax + by + d = z + // A is the matrix with rows [x y 1] for all the probed points + // B is the vector of the Z positions + // the normal vector to the plane is formed by the coefficients of the plane equation in the standard form, which is Vx*x+Vy*y+Vz*z+d = 0 + // so Vx = -a Vy = -b Vz = 1 (we want the vector facing towards positive Z + + // "A" matrix of the linear system of equations + double eqnAMatrix[ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS*3]; + // "B" vector of Z points + double eqnBVector[ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS]; + + + int probePointCounter = 0; + + for (int xProbe=LEFT_PROBE_BED_POSITION; xProbe <= RIGHT_PROBE_BED_POSITION; xProbe += xGridSpacing) + { + for (int yProbe=FRONT_PROBE_BED_POSITION; yProbe <= BACK_PROBE_BED_POSITION; yProbe += yGridSpacing) + { + if (probePointCounter == 0) + { + // raise before probing + do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], Z_RAISE_BEFORE_PROBING); + } else + { + // raise extruder + do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); + } + + + do_blocking_move_to(xProbe - X_PROBE_OFFSET_FROM_EXTRUDER, yProbe - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]); + + engage_z_probe(); // Engage Z Servo endstop if available + run_z_probe(); + eqnBVector[probePointCounter] = current_position[Z_AXIS]; + retract_z_probe(); + + SERIAL_PROTOCOLPGM("Bed x: "); + SERIAL_PROTOCOL(xProbe); + SERIAL_PROTOCOLPGM(" y: "); + SERIAL_PROTOCOL(yProbe); + SERIAL_PROTOCOLPGM(" z: "); + SERIAL_PROTOCOL(current_position[Z_AXIS]); + SERIAL_PROTOCOLPGM("\n"); + + eqnAMatrix[probePointCounter + 0*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = xProbe; + eqnAMatrix[probePointCounter + 1*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = yProbe; + eqnAMatrix[probePointCounter + 2*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = 1; + probePointCounter++; + } + } + clean_up_after_endstop_move(); + + // solve lsq problem + double *plane_equation_coefficients = qr_solve(ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS, 3, eqnAMatrix, eqnBVector); + + SERIAL_PROTOCOLPGM("Eqn coefficients: a: "); + SERIAL_PROTOCOL(plane_equation_coefficients[0]); + SERIAL_PROTOCOLPGM(" b: "); + SERIAL_PROTOCOL(plane_equation_coefficients[1]); + SERIAL_PROTOCOLPGM(" d: "); + SERIAL_PROTOCOLLN(plane_equation_coefficients[2]); + + + set_bed_level_equation_lsq(plane_equation_coefficients); + + free(plane_equation_coefficients); + +#else // ACCURATE_BED_LEVELING not defined + + // prob 1 do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], Z_RAISE_BEFORE_PROBING); do_blocking_move_to(LEFT_PROBE_BED_POSITION - X_PROBE_OFFSET_FROM_EXTRUDER, BACK_PROBE_BED_POSITION - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]); @@ -1376,7 +1484,9 @@ void process_commands() clean_up_after_endstop_move(); set_bed_level_equation(z_at_xLeft_yFront, z_at_xRight_yFront, z_at_xLeft_yBack); - + + +#endif // ACCURATE_BED_LEVELING st_synchronize(); // The following code correct the Z height difference from z-probe position and hotend tip position. diff --git a/Marlin/qr_solve.cpp b/Marlin/qr_solve.cpp new file mode 100644 index 0000000000..0a491281c5 --- /dev/null +++ b/Marlin/qr_solve.cpp @@ -0,0 +1,1932 @@ +#include "qr_solve.h" + +#ifdef ACCURATE_BED_LEVELING + +#include +#include +#include + + +//# include "r8lib.h" + +int i4_min ( int i1, int i2 ) + +/******************************************************************************/ +/* + Purpose: + + I4_MIN returns the smaller of two I4's. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 29 August 2006 + + Author: + + John Burkardt + + Parameters: + + Input, int I1, I2, two integers to be compared. + + Output, int I4_MIN, the smaller of I1 and I2. +*/ +{ + int value; + + if ( i1 < i2 ) + { + value = i1; + } + else + { + value = i2; + } + return value; +} + +double r8_epsilon ( void ) + +/******************************************************************************/ +/* + Purpose: + + R8_EPSILON returns the R8 round off unit. + + Discussion: + + R8_EPSILON is a number R which is a power of 2 with the property that, + to the precision of the computer's arithmetic, + 1 < 1 + R + but + 1 = ( 1 + R / 2 ) + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 01 September 2012 + + Author: + + John Burkardt + + Parameters: + + Output, double R8_EPSILON, the R8 round-off unit. +*/ +{ + const double value = 2.220446049250313E-016; + + return value; +} + +double r8_max ( double x, double y ) + +/******************************************************************************/ +/* + Purpose: + + R8_MAX returns the maximum of two R8's. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 07 May 2006 + + Author: + + John Burkardt + + Parameters: + + Input, double X, Y, the quantities to compare. + + Output, double R8_MAX, the maximum of X and Y. +*/ +{ + double value; + + if ( y < x ) + { + value = x; + } + else + { + value = y; + } + return value; +} + +double r8_abs ( double x ) + +/******************************************************************************/ +/* + Purpose: + + R8_ABS returns the absolute value of an R8. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 07 May 2006 + + Author: + + John Burkardt + + Parameters: + + Input, double X, the quantity whose absolute value is desired. + + Output, double R8_ABS, the absolute value of X. +*/ +{ + double value; + + if ( 0.0 <= x ) + { + value = + x; + } + else + { + value = - x; + } + return value; +} + +double r8_sign ( double x ) + +/******************************************************************************/ +/* + Purpose: + + R8_SIGN returns the sign of an R8. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 08 May 2006 + + Author: + + John Burkardt + + Parameters: + + Input, double X, the number whose sign is desired. + + Output, double R8_SIGN, the sign of X. +*/ +{ + double value; + + if ( x < 0.0 ) + { + value = - 1.0; + } + else + { + value = + 1.0; + } + return value; +} + +double r8mat_amax ( int m, int n, double a[] ) + +/******************************************************************************/ +/* + Purpose: + + R8MAT_AMAX returns the maximum absolute value entry of an R8MAT. + + Discussion: + + An R8MAT is a doubly dimensioned array of R8 values, stored as a vector + in column-major order. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 07 September 2012 + + Author: + + John Burkardt + + Parameters: + + Input, int M, the number of rows in A. + + Input, int N, the number of columns in A. + + Input, double A[M*N], the M by N matrix. + + Output, double R8MAT_AMAX, the maximum absolute value entry of A. +*/ +{ + int i; + int j; + double value; + + value = r8_abs ( a[0+0*m] ); + + for ( j = 0; j < n; j++ ) + { + for ( i = 0; i < m; i++ ) + { + if ( value < r8_abs ( a[i+j*m] ) ) + { + value = r8_abs ( a[i+j*m] ); + } + } + } + return value; +} + +double *r8mat_copy_new ( int m, int n, double a1[] ) + +/******************************************************************************/ +/* + Purpose: + + R8MAT_COPY_NEW copies one R8MAT to a "new" R8MAT. + + Discussion: + + An R8MAT is a doubly dimensioned array of R8 values, stored as a vector + in column-major order. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 26 July 2008 + + Author: + + John Burkardt + + Parameters: + + Input, int M, N, the number of rows and columns. + + Input, double A1[M*N], the matrix to be copied. + + Output, double R8MAT_COPY_NEW[M*N], the copy of A1. +*/ +{ + double *a2; + int i; + int j; + + a2 = ( double * ) malloc ( m * n * sizeof ( double ) ); + + for ( j = 0; j < n; j++ ) + { + for ( i = 0; i < m; i++ ) + { + a2[i+j*m] = a1[i+j*m]; + } + } + + return a2; +} + +/******************************************************************************/ + +void daxpy ( int n, double da, double dx[], int incx, double dy[], int incy ) + +/******************************************************************************/ +/* + Purpose: + + DAXPY computes constant times a vector plus a vector. + + Discussion: + + This routine uses unrolled loops for increments equal to one. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 30 March 2007 + + Author: + + C version by John Burkardt + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart, + LINPACK User's Guide, + SIAM, 1979. + + Charles Lawson, Richard Hanson, David Kincaid, Fred Krogh, + Basic Linear Algebra Subprograms for Fortran Usage, + Algorithm 539, + ACM Transactions on Mathematical Software, + Volume 5, Number 3, September 1979, pages 308-323. + + Parameters: + + Input, int N, the number of elements in DX and DY. + + Input, double DA, the multiplier of DX. + + Input, double DX[*], the first vector. + + Input, int INCX, the increment between successive entries of DX. + + Input/output, double DY[*], the second vector. + On output, DY[*] has been replaced by DY[*] + DA * DX[*]. + + Input, int INCY, the increment between successive entries of DY. +*/ +{ + int i; + int ix; + int iy; + int m; + + if ( n <= 0 ) + { + return; + } + + if ( da == 0.0 ) + { + return; + } +/* + Code for unequal increments or equal increments + not equal to 1. +*/ + if ( incx != 1 || incy != 1 ) + { + if ( 0 <= incx ) + { + ix = 0; + } + else + { + ix = ( - n + 1 ) * incx; + } + + if ( 0 <= incy ) + { + iy = 0; + } + else + { + iy = ( - n + 1 ) * incy; + } + + for ( i = 0; i < n; i++ ) + { + dy[iy] = dy[iy] + da * dx[ix]; + ix = ix + incx; + iy = iy + incy; + } + } +/* + Code for both increments equal to 1. +*/ + else + { + m = n % 4; + + for ( i = 0; i < m; i++ ) + { + dy[i] = dy[i] + da * dx[i]; + } + + for ( i = m; i < n; i = i + 4 ) + { + dy[i ] = dy[i ] + da * dx[i ]; + dy[i+1] = dy[i+1] + da * dx[i+1]; + dy[i+2] = dy[i+2] + da * dx[i+2]; + dy[i+3] = dy[i+3] + da * dx[i+3]; + } + } + return; +} +/******************************************************************************/ + +double ddot ( int n, double dx[], int incx, double dy[], int incy ) + +/******************************************************************************/ +/* + Purpose: + + DDOT forms the dot product of two vectors. + + Discussion: + + This routine uses unrolled loops for increments equal to one. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 30 March 2007 + + Author: + + C version by John Burkardt + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart, + LINPACK User's Guide, + SIAM, 1979. + + Charles Lawson, Richard Hanson, David Kincaid, Fred Krogh, + Basic Linear Algebra Subprograms for Fortran Usage, + Algorithm 539, + ACM Transactions on Mathematical Software, + Volume 5, Number 3, September 1979, pages 308-323. + + Parameters: + + Input, int N, the number of entries in the vectors. + + Input, double DX[*], the first vector. + + Input, int INCX, the increment between successive entries in DX. + + Input, double DY[*], the second vector. + + Input, int INCY, the increment between successive entries in DY. + + Output, double DDOT, the sum of the product of the corresponding + entries of DX and DY. +*/ +{ + double dtemp; + int i; + int ix; + int iy; + int m; + + dtemp = 0.0; + + if ( n <= 0 ) + { + return dtemp; + } +/* + Code for unequal increments or equal increments + not equal to 1. +*/ + if ( incx != 1 || incy != 1 ) + { + if ( 0 <= incx ) + { + ix = 0; + } + else + { + ix = ( - n + 1 ) * incx; + } + + if ( 0 <= incy ) + { + iy = 0; + } + else + { + iy = ( - n + 1 ) * incy; + } + + for ( i = 0; i < n; i++ ) + { + dtemp = dtemp + dx[ix] * dy[iy]; + ix = ix + incx; + iy = iy + incy; + } + } +/* + Code for both increments equal to 1. +*/ + else + { + m = n % 5; + + for ( i = 0; i < m; i++ ) + { + dtemp = dtemp + dx[i] * dy[i]; + } + + for ( i = m; i < n; i = i + 5 ) + { + dtemp = dtemp + dx[i ] * dy[i ] + + dx[i+1] * dy[i+1] + + dx[i+2] * dy[i+2] + + dx[i+3] * dy[i+3] + + dx[i+4] * dy[i+4]; + } + } + return dtemp; +} +/******************************************************************************/ + +double dnrm2 ( int n, double x[], int incx ) + +/******************************************************************************/ +/* + Purpose: + + DNRM2 returns the euclidean norm of a vector. + + Discussion: + + DNRM2 ( X ) = sqrt ( X' * X ) + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 30 March 2007 + + Author: + + C version by John Burkardt + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart, + LINPACK User's Guide, + SIAM, 1979. + + Charles Lawson, Richard Hanson, David Kincaid, Fred Krogh, + Basic Linear Algebra Subprograms for Fortran Usage, + Algorithm 539, + ACM Transactions on Mathematical Software, + Volume 5, Number 3, September 1979, pages 308-323. + + Parameters: + + Input, int N, the number of entries in the vector. + + Input, double X[*], the vector whose norm is to be computed. + + Input, int INCX, the increment between successive entries of X. + + Output, double DNRM2, the Euclidean norm of X. +*/ +{ + double absxi; + int i; + int ix; + double norm; + double scale; + double ssq; + double value; + + if ( n < 1 || incx < 1 ) + { + norm = 0.0; + } + else if ( n == 1 ) + { + norm = r8_abs ( x[0] ); + } + else + { + scale = 0.0; + ssq = 1.0; + ix = 0; + + for ( i = 0; i < n; i++ ) + { + if ( x[ix] != 0.0 ) + { + absxi = r8_abs ( x[ix] ); + if ( scale < absxi ) + { + ssq = 1.0 + ssq * ( scale / absxi ) * ( scale / absxi ); + scale = absxi; + } + else + { + ssq = ssq + ( absxi / scale ) * ( absxi / scale ); + } + } + ix = ix + incx; + } + + norm = scale * sqrt ( ssq ); + } + + return norm; +} +/******************************************************************************/ + +void dqrank ( double a[], int lda, int m, int n, double tol, int *kr, + int jpvt[], double qraux[] ) + +/******************************************************************************/ +/* + Purpose: + + DQRANK computes the QR factorization of a rectangular matrix. + + Discussion: + + This routine is used in conjunction with DQRLSS to solve + overdetermined, underdetermined and singular linear systems + in a least squares sense. + + DQRANK uses the LINPACK subroutine DQRDC to compute the QR + factorization, with column pivoting, of an M by N matrix A. + The numerical rank is determined using the tolerance TOL. + + Note that on output, ABS ( A(1,1) ) / ABS ( A(KR,KR) ) is an estimate + of the condition number of the matrix of independent columns, + and of R. This estimate will be <= 1/TOL. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 21 April 2012 + + Author: + + C version by John Burkardt. + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart, + LINPACK User's Guide, + SIAM, 1979, + ISBN13: 978-0-898711-72-1, + LC: QA214.L56. + + Parameters: + + Input/output, double A[LDA*N]. On input, the matrix whose + decomposition is to be computed. On output, the information from DQRDC. + The triangular matrix R of the QR factorization is contained in the + upper triangle and information needed to recover the orthogonal + matrix Q is stored below the diagonal in A and in the vector QRAUX. + + Input, int LDA, the leading dimension of A, which must + be at least M. + + Input, int M, the number of rows of A. + + Input, int N, the number of columns of A. + + Input, double TOL, a relative tolerance used to determine the + numerical rank. The problem should be scaled so that all the elements + of A have roughly the same absolute accuracy, EPS. Then a reasonable + value for TOL is roughly EPS divided by the magnitude of the largest + element. + + Output, int *KR, the numerical rank. + + Output, int JPVT[N], the pivot information from DQRDC. + Columns JPVT(1), ..., JPVT(KR) of the original matrix are linearly + independent to within the tolerance TOL and the remaining columns + are linearly dependent. + + Output, double QRAUX[N], will contain extra information defining + the QR factorization. +*/ +{ + int i; + int j; + int job; + int k; + double *work; + + for ( i = 0; i < n; i++ ) + { + jpvt[i] = 0; + } + + work = ( double * ) malloc ( n * sizeof ( double ) ); + job = 1; + + dqrdc ( a, lda, m, n, qraux, jpvt, work, job ); + + *kr = 0; + k = i4_min ( m, n ); + + for ( j = 0; j < k; j++ ) + { + if ( r8_abs ( a[j+j*lda] ) <= tol * r8_abs ( a[0+0*lda] ) ) + { + return; + } + *kr = j + 1; + } + + free ( work ); + + return; +} +/******************************************************************************/ + +void dqrdc ( double a[], int lda, int n, int p, double qraux[], int jpvt[], + double work[], int job ) + +/******************************************************************************/ +/* + Purpose: + + DQRDC computes the QR factorization of a real rectangular matrix. + + Discussion: + + DQRDC uses Householder transformations. + + Column pivoting based on the 2-norms of the reduced columns may be + performed at the user's option. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 07 June 2005 + + Author: + + C version by John Burkardt. + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, + LINPACK User's Guide, + SIAM, (Society for Industrial and Applied Mathematics), + 3600 University City Science Center, + Philadelphia, PA, 19104-2688. + ISBN 0-89871-172-X + + Parameters: + + Input/output, double A(LDA,P). On input, the N by P matrix + whose decomposition is to be computed. On output, A contains in + its upper triangle the upper triangular matrix R of the QR + factorization. Below its diagonal A contains information from + which the orthogonal part of the decomposition can be recovered. + Note that if pivoting has been requested, the decomposition is not that + of the original matrix A but that of A with its columns permuted + as described by JPVT. + + Input, int LDA, the leading dimension of the array A. LDA must + be at least N. + + Input, int N, the number of rows of the matrix A. + + Input, int P, the number of columns of the matrix A. + + Output, double QRAUX[P], contains further information required + to recover the orthogonal part of the decomposition. + + Input/output, integer JPVT[P]. On input, JPVT contains integers that + control the selection of the pivot columns. The K-th column A(*,K) of A + is placed in one of three classes according to the value of JPVT(K). + > 0, then A(K) is an initial column. + = 0, then A(K) is a free column. + < 0, then A(K) is a final column. + Before the decomposition is computed, initial columns are moved to + the beginning of the array A and final columns to the end. Both + initial and final columns are frozen in place during the computation + and only free columns are moved. At the K-th stage of the + reduction, if A(*,K) is occupied by a free column it is interchanged + with the free column of largest reduced norm. JPVT is not referenced + if JOB == 0. On output, JPVT(K) contains the index of the column of the + original matrix that has been interchanged into the K-th column, if + pivoting was requested. + + Workspace, double WORK[P]. WORK is not referenced if JOB == 0. + + Input, int JOB, initiates column pivoting. + 0, no pivoting is done. + nonzero, pivoting is done. +*/ +{ + int j; + int jp; + int l; + int lup; + int maxj; + double maxnrm; + double nrmxl; + int pl; + int pu; + int swapj; + double t; + double tt; + + pl = 1; + pu = 0; +/* + If pivoting is requested, rearrange the columns. +*/ + if ( job != 0 ) + { + for ( j = 1; j <= p; j++ ) + { + swapj = ( 0 < jpvt[j-1] ); + + if ( jpvt[j-1] < 0 ) + { + jpvt[j-1] = -j; + } + else + { + jpvt[j-1] = j; + } + + if ( swapj ) + { + if ( j != pl ) + { + dswap ( n, a+0+(pl-1)*lda, 1, a+0+(j-1), 1 ); + } + jpvt[j-1] = jpvt[pl-1]; + jpvt[pl-1] = j; + pl = pl + 1; + } + } + pu = p; + + for ( j = p; 1 <= j; j-- ) + { + if ( jpvt[j-1] < 0 ) + { + jpvt[j-1] = -jpvt[j-1]; + + if ( j != pu ) + { + dswap ( n, a+0+(pu-1)*lda, 1, a+0+(j-1)*lda, 1 ); + jp = jpvt[pu-1]; + jpvt[pu-1] = jpvt[j-1]; + jpvt[j-1] = jp; + } + pu = pu - 1; + } + } + } +/* + Compute the norms of the free columns. +*/ + for ( j = pl; j <= pu; j++ ) + { + qraux[j-1] = dnrm2 ( n, a+0+(j-1)*lda, 1 ); + } + + for ( j = pl; j <= pu; j++ ) + { + work[j-1] = qraux[j-1]; + } +/* + Perform the Householder reduction of A. +*/ + lup = i4_min ( n, p ); + + for ( l = 1; l <= lup; l++ ) + { +/* + Bring the column of largest norm into the pivot position. +*/ + if ( pl <= l && l < pu ) + { + maxnrm = 0.0; + maxj = l; + for ( j = l; j <= pu; j++ ) + { + if ( maxnrm < qraux[j-1] ) + { + maxnrm = qraux[j-1]; + maxj = j; + } + } + + if ( maxj != l ) + { + dswap ( n, a+0+(l-1)*lda, 1, a+0+(maxj-1)*lda, 1 ); + qraux[maxj-1] = qraux[l-1]; + work[maxj-1] = work[l-1]; + jp = jpvt[maxj-1]; + jpvt[maxj-1] = jpvt[l-1]; + jpvt[l-1] = jp; + } + } +/* + Compute the Householder transformation for column L. +*/ + qraux[l-1] = 0.0; + + if ( l != n ) + { + nrmxl = dnrm2 ( n-l+1, a+l-1+(l-1)*lda, 1 ); + + if ( nrmxl != 0.0 ) + { + if ( a[l-1+(l-1)*lda] != 0.0 ) + { + nrmxl = nrmxl * r8_sign ( a[l-1+(l-1)*lda] ); + } + + dscal ( n-l+1, 1.0 / nrmxl, a+l-1+(l-1)*lda, 1 ); + a[l-1+(l-1)*lda] = 1.0 + a[l-1+(l-1)*lda]; +/* + Apply the transformation to the remaining columns, updating the norms. +*/ + for ( j = l + 1; j <= p; j++ ) + { + t = -ddot ( n-l+1, a+l-1+(l-1)*lda, 1, a+l-1+(j-1)*lda, 1 ) + / a[l-1+(l-1)*lda]; + daxpy ( n-l+1, t, a+l-1+(l-1)*lda, 1, a+l-1+(j-1)*lda, 1 ); + + if ( pl <= j && j <= pu ) + { + if ( qraux[j-1] != 0.0 ) + { + tt = 1.0 - pow ( r8_abs ( a[l-1+(j-1)*lda] ) / qraux[j-1], 2 ); + tt = r8_max ( tt, 0.0 ); + t = tt; + tt = 1.0 + 0.05 * tt * pow ( qraux[j-1] / work[j-1], 2 ); + + if ( tt != 1.0 ) + { + qraux[j-1] = qraux[j-1] * sqrt ( t ); + } + else + { + qraux[j-1] = dnrm2 ( n-l, a+l+(j-1)*lda, 1 ); + work[j-1] = qraux[j-1]; + } + } + } + } +/* + Save the transformation. +*/ + qraux[l-1] = a[l-1+(l-1)*lda]; + a[l-1+(l-1)*lda] = -nrmxl; + } + } + } + return; +} +/******************************************************************************/ + +int dqrls ( double a[], int lda, int m, int n, double tol, int *kr, double b[], + double x[], double rsd[], int jpvt[], double qraux[], int itask ) + +/******************************************************************************/ +/* + Purpose: + + DQRLS factors and solves a linear system in the least squares sense. + + Discussion: + + The linear system may be overdetermined, underdetermined or singular. + The solution is obtained using a QR factorization of the + coefficient matrix. + + DQRLS can be efficiently used to solve several least squares + problems with the same matrix A. The first system is solved + with ITASK = 1. The subsequent systems are solved with + ITASK = 2, to avoid the recomputation of the matrix factors. + The parameters KR, JPVT, and QRAUX must not be modified + between calls to DQRLS. + + DQRLS is used to solve in a least squares sense + overdetermined, underdetermined and singular linear systems. + The system is A*X approximates B where A is M by N. + B is a given M-vector, and X is the N-vector to be computed. + A solution X is found which minimimzes the sum of squares (2-norm) + of the residual, A*X - B. + + The numerical rank of A is determined using the tolerance TOL. + + DQRLS uses the LINPACK subroutine DQRDC to compute the QR + factorization, with column pivoting, of an M by N matrix A. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 10 September 2012 + + Author: + + C version by John Burkardt. + + Reference: + + David Kahaner, Cleve Moler, Steven Nash, + Numerical Methods and Software, + Prentice Hall, 1989, + ISBN: 0-13-627258-4, + LC: TA345.K34. + + Parameters: + + Input/output, double A[LDA*N], an M by N matrix. + On input, the matrix whose decomposition is to be computed. + In a least squares data fitting problem, A(I,J) is the + value of the J-th basis (model) function at the I-th data point. + On output, A contains the output from DQRDC. The triangular matrix R + of the QR factorization is contained in the upper triangle and + information needed to recover the orthogonal matrix Q is stored + below the diagonal in A and in the vector QRAUX. + + Input, int LDA, the leading dimension of A. + + Input, int M, the number of rows of A. + + Input, int N, the number of columns of A. + + Input, double TOL, a relative tolerance used to determine the + numerical rank. The problem should be scaled so that all the elements + of A have roughly the same absolute accuracy EPS. Then a reasonable + value for TOL is roughly EPS divided by the magnitude of the largest + element. + + Output, int *KR, the numerical rank. + + Input, double B[M], the right hand side of the linear system. + + Output, double X[N], a least squares solution to the linear + system. + + Output, double RSD[M], the residual, B - A*X. RSD may + overwrite B. + + Workspace, int JPVT[N], required if ITASK = 1. + Columns JPVT(1), ..., JPVT(KR) of the original matrix are linearly + independent to within the tolerance TOL and the remaining columns + are linearly dependent. ABS ( A(1,1) ) / ABS ( A(KR,KR) ) is an estimate + of the condition number of the matrix of independent columns, + and of R. This estimate will be <= 1/TOL. + + Workspace, double QRAUX[N], required if ITASK = 1. + + Input, int ITASK. + 1, DQRLS factors the matrix A and solves the least squares problem. + 2, DQRLS assumes that the matrix A was factored with an earlier + call to DQRLS, and only solves the least squares problem. + + Output, int DQRLS, error code. + 0: no error + -1: LDA < M (fatal error) + -2: N < 1 (fatal error) + -3: ITASK < 1 (fatal error) +*/ +{ + int ind; + + if ( lda < m ) + { + /*fprintf ( stderr, "\n" ); + fprintf ( stderr, "DQRLS - Fatal error!\n" ); + fprintf ( stderr, " LDA < M.\n" );*/ + ind = -1; + return ind; + } + + if ( n <= 0 ) + { + /*fprintf ( stderr, "\n" ); + fprintf ( stderr, "DQRLS - Fatal error!\n" ); + fprintf ( stderr, " N <= 0.\n" );*/ + ind = -2; + return ind; + } + + if ( itask < 1 ) + { + /*fprintf ( stderr, "\n" ); + fprintf ( stderr, "DQRLS - Fatal error!\n" ); + fprintf ( stderr, " ITASK < 1.\n" );*/ + ind = -3; + return ind; + } + + ind = 0; +/* + Factor the matrix. +*/ + if ( itask == 1 ) + { + dqrank ( a, lda, m, n, tol, kr, jpvt, qraux ); + } +/* + Solve the least-squares problem. +*/ + dqrlss ( a, lda, m, n, *kr, b, x, rsd, jpvt, qraux ); + + return ind; +} +/******************************************************************************/ + +void dqrlss ( double a[], int lda, int m, int n, int kr, double b[], double x[], + double rsd[], int jpvt[], double qraux[] ) + +/******************************************************************************/ +/* + Purpose: + + DQRLSS solves a linear system in a least squares sense. + + Discussion: + + DQRLSS must be preceeded by a call to DQRANK. + + The system is to be solved is + A * X = B + where + A is an M by N matrix with rank KR, as determined by DQRANK, + B is a given M-vector, + X is the N-vector to be computed. + + A solution X, with at most KR nonzero components, is found which + minimizes the 2-norm of the residual (A*X-B). + + Once the matrix A has been formed, DQRANK should be + called once to decompose it. Then, for each right hand + side B, DQRLSS should be called once to obtain the + solution and residual. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 10 September 2012 + + Author: + + C version by John Burkardt + + Parameters: + + Input, double A[LDA*N], the QR factorization information + from DQRANK. The triangular matrix R of the QR factorization is + contained in the upper triangle and information needed to recover + the orthogonal matrix Q is stored below the diagonal in A and in + the vector QRAUX. + + Input, int LDA, the leading dimension of A, which must + be at least M. + + Input, int M, the number of rows of A. + + Input, int N, the number of columns of A. + + Input, int KR, the rank of the matrix, as estimated by DQRANK. + + Input, double B[M], the right hand side of the linear system. + + Output, double X[N], a least squares solution to the + linear system. + + Output, double RSD[M], the residual, B - A*X. RSD may + overwite B. + + Input, int JPVT[N], the pivot information from DQRANK. + Columns JPVT[0], ..., JPVT[KR-1] of the original matrix are linearly + independent to within the tolerance TOL and the remaining columns + are linearly dependent. + + Input, double QRAUX[N], auxiliary information from DQRANK + defining the QR factorization. +*/ +{ + int i; + int info; + int j; + int job; + int k; + double t; + + if ( kr != 0 ) + { + job = 110; + info = dqrsl ( a, lda, m, kr, qraux, b, rsd, rsd, x, rsd, rsd, job ); + } + + for ( i = 0; i < n; i++ ) + { + jpvt[i] = - jpvt[i]; + } + + for ( i = kr; i < n; i++ ) + { + x[i] = 0.0; + } + + for ( j = 1; j <= n; j++ ) + { + if ( jpvt[j-1] <= 0 ) + { + k = - jpvt[j-1]; + jpvt[j-1] = k; + + while ( k != j ) + { + t = x[j-1]; + x[j-1] = x[k-1]; + x[k-1] = t; + jpvt[k-1] = -jpvt[k-1]; + k = jpvt[k-1]; + } + } + } + return; +} +/******************************************************************************/ + +int dqrsl ( double a[], int lda, int n, int k, double qraux[], double y[], + double qy[], double qty[], double b[], double rsd[], double ab[], int job ) + +/******************************************************************************/ +/* + Purpose: + + DQRSL computes transformations, projections, and least squares solutions. + + Discussion: + + DQRSL requires the output of DQRDC. + + For K <= min(N,P), let AK be the matrix + + AK = ( A(JPVT[0]), A(JPVT(2)), ..., A(JPVT(K)) ) + + formed from columns JPVT[0], ..., JPVT(K) of the original + N by P matrix A that was input to DQRDC. If no pivoting was + done, AK consists of the first K columns of A in their + original order. DQRDC produces a factored orthogonal matrix Q + and an upper triangular matrix R such that + + AK = Q * (R) + (0) + + This information is contained in coded form in the arrays + A and QRAUX. + + The parameters QY, QTY, B, RSD, and AB are not referenced + if their computation is not requested and in this case + can be replaced by dummy variables in the calling program. + To save storage, the user may in some cases use the same + array for different parameters in the calling sequence. A + frequently occuring example is when one wishes to compute + any of B, RSD, or AB and does not need Y or QTY. In this + case one may identify Y, QTY, and one of B, RSD, or AB, while + providing separate arrays for anything else that is to be + computed. + + Thus the calling sequence + + dqrsl ( a, lda, n, k, qraux, y, dum, y, b, y, dum, 110, info ) + + will result in the computation of B and RSD, with RSD + overwriting Y. More generally, each item in the following + list contains groups of permissible identifications for + a single calling sequence. + + 1. (Y,QTY,B) (RSD) (AB) (QY) + + 2. (Y,QTY,RSD) (B) (AB) (QY) + + 3. (Y,QTY,AB) (B) (RSD) (QY) + + 4. (Y,QY) (QTY,B) (RSD) (AB) + + 5. (Y,QY) (QTY,RSD) (B) (AB) + + 6. (Y,QY) (QTY,AB) (B) (RSD) + + In any group the value returned in the array allocated to + the group corresponds to the last member of the group. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 07 June 2005 + + Author: + + C version by John Burkardt. + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart, + LINPACK User's Guide, + SIAM, (Society for Industrial and Applied Mathematics), + 3600 University City Science Center, + Philadelphia, PA, 19104-2688. + ISBN 0-89871-172-X + + Parameters: + + Input, double A[LDA*P], contains the output of DQRDC. + + Input, int LDA, the leading dimension of the array A. + + Input, int N, the number of rows of the matrix AK. It must + have the same value as N in DQRDC. + + Input, int K, the number of columns of the matrix AK. K + must not be greater than min(N,P), where P is the same as in the + calling sequence to DQRDC. + + Input, double QRAUX[P], the auxiliary output from DQRDC. + + Input, double Y[N], a vector to be manipulated by DQRSL. + + Output, double QY[N], contains Q * Y, if requested. + + Output, double QTY[N], contains Q' * Y, if requested. + + Output, double B[K], the solution of the least squares problem + minimize norm2 ( Y - AK * B), + if its computation has been requested. Note that if pivoting was + requested in DQRDC, the J-th component of B will be associated with + column JPVT(J) of the original matrix A that was input into DQRDC. + + Output, double RSD[N], the least squares residual Y - AK * B, + if its computation has been requested. RSD is also the orthogonal + projection of Y onto the orthogonal complement of the column space + of AK. + + Output, double AB[N], the least squares approximation Ak * B, + if its computation has been requested. AB is also the orthogonal + projection of Y onto the column space of A. + + Input, integer JOB, specifies what is to be computed. JOB has + the decimal expansion ABCDE, with the following meaning: + + if A != 0, compute QY. + if B != 0, compute QTY. + if C != 0, compute QTY and B. + if D != 0, compute QTY and RSD. + if E != 0, compute QTY and AB. + + Note that a request to compute B, RSD, or AB automatically triggers + the computation of QTY, for which an array must be provided in the + calling sequence. + + Output, int DQRSL, is zero unless the computation of B has + been requested and R is exactly singular. In this case, INFO is the + index of the first zero diagonal element of R, and B is left unaltered. +*/ +{ + int cab; + int cb; + int cqty; + int cqy; + int cr; + int i; + int info; + int j; + int jj; + int ju; + double t; + double temp; +/* + Set INFO flag. +*/ + info = 0; +/* + Determine what is to be computed. +*/ + cqy = ( job / 10000 != 0 ); + cqty = ( ( job % 10000 ) != 0 ); + cb = ( ( job % 1000 ) / 100 != 0 ); + cr = ( ( job % 100 ) / 10 != 0 ); + cab = ( ( job % 10 ) != 0 ); + + ju = i4_min ( k, n-1 ); +/* + Special action when N = 1. +*/ + if ( ju == 0 ) + { + if ( cqy ) + { + qy[0] = y[0]; + } + + if ( cqty ) + { + qty[0] = y[0]; + } + + if ( cab ) + { + ab[0] = y[0]; + } + + if ( cb ) + { + if ( a[0+0*lda] == 0.0 ) + { + info = 1; + } + else + { + b[0] = y[0] / a[0+0*lda]; + } + } + + if ( cr ) + { + rsd[0] = 0.0; + } + return info; + } +/* + Set up to compute QY or QTY. +*/ + if ( cqy ) + { + for ( i = 1; i <= n; i++ ) + { + qy[i-1] = y[i-1]; + } + } + + if ( cqty ) + { + for ( i = 1; i <= n; i++ ) + { + qty[i-1] = y[i-1]; + } + } +/* + Compute QY. +*/ + if ( cqy ) + { + for ( jj = 1; jj <= ju; jj++ ) + { + j = ju - jj + 1; + + if ( qraux[j-1] != 0.0 ) + { + temp = a[j-1+(j-1)*lda]; + a[j-1+(j-1)*lda] = qraux[j-1]; + t = -ddot ( n-j+1, a+j-1+(j-1)*lda, 1, qy+j-1, 1 ) / a[j-1+(j-1)*lda]; + daxpy ( n-j+1, t, a+j-1+(j-1)*lda, 1, qy+j-1, 1 ); + a[j-1+(j-1)*lda] = temp; + } + } + } +/* + Compute Q'*Y. +*/ + if ( cqty ) + { + for ( j = 1; j <= ju; j++ ) + { + if ( qraux[j-1] != 0.0 ) + { + temp = a[j-1+(j-1)*lda]; + a[j-1+(j-1)*lda] = qraux[j-1]; + t = -ddot ( n-j+1, a+j-1+(j-1)*lda, 1, qty+j-1, 1 ) / a[j-1+(j-1)*lda]; + daxpy ( n-j+1, t, a+j-1+(j-1)*lda, 1, qty+j-1, 1 ); + a[j-1+(j-1)*lda] = temp; + } + } + } +/* + Set up to compute B, RSD, or AB. +*/ + if ( cb ) + { + for ( i = 1; i <= k; i++ ) + { + b[i-1] = qty[i-1]; + } + } + + if ( cab ) + { + for ( i = 1; i <= k; i++ ) + { + ab[i-1] = qty[i-1]; + } + } + + if ( cr && k < n ) + { + for ( i = k+1; i <= n; i++ ) + { + rsd[i-1] = qty[i-1]; + } + } + + if ( cab && k+1 <= n ) + { + for ( i = k+1; i <= n; i++ ) + { + ab[i-1] = 0.0; + } + } + + if ( cr ) + { + for ( i = 1; i <= k; i++ ) + { + rsd[i-1] = 0.0; + } + } +/* + Compute B. +*/ + if ( cb ) + { + for ( jj = 1; jj <= k; jj++ ) + { + j = k - jj + 1; + + if ( a[j-1+(j-1)*lda] == 0.0 ) + { + info = j; + break; + } + + b[j-1] = b[j-1] / a[j-1+(j-1)*lda]; + + if ( j != 1 ) + { + t = -b[j-1]; + daxpy ( j-1, t, a+0+(j-1)*lda, 1, b, 1 ); + } + } + } +/* + Compute RSD or AB as required. +*/ + if ( cr || cab ) + { + for ( jj = 1; jj <= ju; jj++ ) + { + j = ju - jj + 1; + + if ( qraux[j-1] != 0.0 ) + { + temp = a[j-1+(j-1)*lda]; + a[j-1+(j-1)*lda] = qraux[j-1]; + + if ( cr ) + { + t = -ddot ( n-j+1, a+j-1+(j-1)*lda, 1, rsd+j-1, 1 ) + / a[j-1+(j-1)*lda]; + daxpy ( n-j+1, t, a+j-1+(j-1)*lda, 1, rsd+j-1, 1 ); + } + + if ( cab ) + { + t = -ddot ( n-j+1, a+j-1+(j-1)*lda, 1, ab+j-1, 1 ) + / a[j-1+(j-1)*lda]; + daxpy ( n-j+1, t, a+j-1+(j-1)*lda, 1, ab+j-1, 1 ); + } + a[j-1+(j-1)*lda] = temp; + } + } + } + + return info; +} +/******************************************************************************/ + +/******************************************************************************/ + +void dscal ( int n, double sa, double x[], int incx ) + +/******************************************************************************/ +/* + Purpose: + + DSCAL scales a vector by a constant. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 30 March 2007 + + Author: + + C version by John Burkardt + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart, + LINPACK User's Guide, + SIAM, 1979. + + Charles Lawson, Richard Hanson, David Kincaid, Fred Krogh, + Basic Linear Algebra Subprograms for Fortran Usage, + Algorithm 539, + ACM Transactions on Mathematical Software, + Volume 5, Number 3, September 1979, pages 308-323. + + Parameters: + + Input, int N, the number of entries in the vector. + + Input, double SA, the multiplier. + + Input/output, double X[*], the vector to be scaled. + + Input, int INCX, the increment between successive entries of X. +*/ +{ + int i; + int ix; + int m; + + if ( n <= 0 ) + { + } + else if ( incx == 1 ) + { + m = n % 5; + + for ( i = 0; i < m; i++ ) + { + x[i] = sa * x[i]; + } + + for ( i = m; i < n; i = i + 5 ) + { + x[i] = sa * x[i]; + x[i+1] = sa * x[i+1]; + x[i+2] = sa * x[i+2]; + x[i+3] = sa * x[i+3]; + x[i+4] = sa * x[i+4]; + } + } + else + { + if ( 0 <= incx ) + { + ix = 0; + } + else + { + ix = ( - n + 1 ) * incx; + } + + for ( i = 0; i < n; i++ ) + { + x[ix] = sa * x[ix]; + ix = ix + incx; + } + } + return; +} +/******************************************************************************/ + + +void dswap ( int n, double x[], int incx, double y[], int incy ) + +/******************************************************************************/ +/* + Purpose: + + DSWAP interchanges two vectors. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 30 March 2007 + + Author: + + C version by John Burkardt + + Reference: + + Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart, + LINPACK User's Guide, + SIAM, 1979. + + Charles Lawson, Richard Hanson, David Kincaid, Fred Krogh, + Basic Linear Algebra Subprograms for Fortran Usage, + Algorithm 539, + ACM Transactions on Mathematical Software, + Volume 5, Number 3, September 1979, pages 308-323. + + Parameters: + + Input, int N, the number of entries in the vectors. + + Input/output, double X[*], one of the vectors to swap. + + Input, int INCX, the increment between successive entries of X. + + Input/output, double Y[*], one of the vectors to swap. + + Input, int INCY, the increment between successive elements of Y. +*/ +{ + int i; + int ix; + int iy; + int m; + double temp; + + if ( n <= 0 ) + { + } + else if ( incx == 1 && incy == 1 ) + { + m = n % 3; + + for ( i = 0; i < m; i++ ) + { + temp = x[i]; + x[i] = y[i]; + y[i] = temp; + } + + for ( i = m; i < n; i = i + 3 ) + { + temp = x[i]; + x[i] = y[i]; + y[i] = temp; + + temp = x[i+1]; + x[i+1] = y[i+1]; + y[i+1] = temp; + + temp = x[i+2]; + x[i+2] = y[i+2]; + y[i+2] = temp; + } + } + else + { + if ( 0 <= incx ) + { + ix = 0; + } + else + { + ix = ( - n + 1 ) * incx; + } + + if ( 0 <= incy ) + { + iy = 0; + } + else + { + iy = ( - n + 1 ) * incy; + } + + for ( i = 0; i < n; i++ ) + { + temp = x[ix]; + x[ix] = y[iy]; + y[iy] = temp; + ix = ix + incx; + iy = iy + incy; + } + + } + + return; +} +/******************************************************************************/ + +/******************************************************************************/ + +double *qr_solve ( int m, int n, double a[], double b[] ) + +/******************************************************************************/ +/* + Purpose: + + QR_SOLVE solves a linear system in the least squares sense. + + Discussion: + + If the matrix A has full column rank, then the solution X should be the + unique vector that minimizes the Euclidean norm of the residual. + + If the matrix A does not have full column rank, then the solution is + not unique; the vector X will minimize the residual norm, but so will + various other vectors. + + Licensing: + + This code is distributed under the GNU LGPL license. + + Modified: + + 11 September 2012 + + Author: + + John Burkardt + + Reference: + + David Kahaner, Cleve Moler, Steven Nash, + Numerical Methods and Software, + Prentice Hall, 1989, + ISBN: 0-13-627258-4, + LC: TA345.K34. + + Parameters: + + Input, int M, the number of rows of A. + + Input, int N, the number of columns of A. + + Input, double A[M*N], the matrix. + + Input, double B[M], the right hand side. + + Output, double QR_SOLVE[N], the least squares solution. +*/ +{ + double *a_qr; + int ind; + int itask; + int *jpvt; + int kr; + int lda; + double *qraux; + double *r; + double tol; + double *x; + + a_qr = r8mat_copy_new ( m, n, a ); + lda = m; + tol = r8_epsilon ( ) / r8mat_amax ( m, n, a_qr ); + x = ( double * ) malloc ( n * sizeof ( double ) ); + jpvt = ( int * ) malloc ( n * sizeof ( int ) ); + qraux = ( double * ) malloc ( n * sizeof ( double ) ); + r = ( double * ) malloc ( m * sizeof ( double ) ); + itask = 1; + + ind = dqrls ( a_qr, lda, m, n, tol, &kr, b, x, r, jpvt, qraux, itask ); + + free ( a_qr ); + free ( jpvt ); + free ( qraux ); + free ( r ); + + return x; +} +/******************************************************************************/ + +#endif diff --git a/Marlin/qr_solve.h b/Marlin/qr_solve.h new file mode 100644 index 0000000000..b756d1e1b5 --- /dev/null +++ b/Marlin/qr_solve.h @@ -0,0 +1,22 @@ +#include "Configuration.h" + +#ifdef ACCURATE_BED_LEVELING + +void daxpy ( int n, double da, double dx[], int incx, double dy[], int incy ); +double ddot ( int n, double dx[], int incx, double dy[], int incy ); +double dnrm2 ( int n, double x[], int incx ); +void dqrank ( double a[], int lda, int m, int n, double tol, int *kr, + int jpvt[], double qraux[] ); +void dqrdc ( double a[], int lda, int n, int p, double qraux[], int jpvt[], + double work[], int job ); +int dqrls ( double a[], int lda, int m, int n, double tol, int *kr, double b[], + double x[], double rsd[], int jpvt[], double qraux[], int itask ); +void dqrlss ( double a[], int lda, int m, int n, int kr, double b[], double x[], + double rsd[], int jpvt[], double qraux[] ); +int dqrsl ( double a[], int lda, int n, int k, double qraux[], double y[], + double qy[], double qty[], double b[], double rsd[], double ab[], int job ); +void dscal ( int n, double sa, double x[], int incx ); +void dswap ( int n, double x[], int incx, double y[], int incy ); +double *qr_solve ( int m, int n, double a[], double b[] ); + +#endif From e8786bf110b940f145e9789c09d2284118c0b5d5 Mon Sep 17 00:00:00 2001 From: Michal Dyntar Date: Sat, 7 Dec 2013 13:29:47 +0100 Subject: [PATCH 092/256] Added support for Cheaptronic v1 electronic --- Marlin/Configuration.h | 1 + Marlin/pins.h | 101 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index c5b96b280b..d5b7621a1f 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -36,6 +36,7 @@ // 11 = Gen7 v1.1, v1.2 = 11 // 12 = Gen7 v1.3 // 13 = Gen7 v1.4 +// 2 = Cheaptronic v1.0 // 20 = Sethi 3D_1 // 3 = MEGA/RAMPS up to 1.2 = 3 // 33 = RAMPS 1.3 / 1.4 (Power outputs: Extruder, Fan, Bed) diff --git a/Marlin/pins.h b/Marlin/pins.h index ba73a3ccc2..b7cbac4fd7 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -2288,6 +2288,107 @@ #endif +/**************************************************************************************** +* Cheaptronic v1.0 +* +****************************************************************************************/ +#if MOTHERBOARD == 2 + #define KNOWN_BOARD 1 + + #ifndef __AVR_ATmega2560__ + #error Oops! Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu. + #endif + + #define LARGE_FLASH true + + //X motor stepper + #define X_STEP_PIN 14 + #define X_DIR_PIN 15 + #define X_ENABLE_PIN 24 + + //X endstop + #define X_MIN_PIN 3 + #define X_MAX_PIN -1 + + //Y motor stepper + #define Y_STEP_PIN 35 + #define Y_DIR_PIN 36 + #define Y_ENABLE_PIN 31 + + //Y endstop + #define Y_MIN_PIN 2 + #define Y_MAX_PIN -1 + + //Z motor stepper + #define Z_STEP_PIN 40 + #define Z_DIR_PIN 41 + #define Z_ENABLE_PIN 37 + + //Z endstop + #define Z_MIN_PIN 5 + #define Z_MAX_PIN -1 + + //Extruder 0 stepper + #define E0_STEP_PIN 26 + #define E0_DIR_PIN 28 + #define E0_ENABLE_PIN 25 + + //Extruder 1 stepper + #define E1_STEP_PIN 33 + #define E1_DIR_PIN 34 + #define E1_ENABLE_PIN 30 + + #define SDPOWER -1 + #define SDSS -1 + #define LED_PIN -1 + + //FAN + #define FAN_PIN -1 + + #define PS_ON_PIN -1 + #define KILL_PIN -1 + + #define HEATER_0_PIN 19 // EXTRUDER 1 + #define HEATER_1_PIN 23 // EXTRUDER 2 + //HeatedBad + #define HEATER_BED_PIN 22 + //Cheaptronic v1.0 hasent EXTRUDER 3 + #define HEATER_2_PIN -1 + + //Temperature sensors + #define TEMP_0_PIN 15 + #define TEMP_1_PIN 14 + #define TEMP_2_PIN -1 + #define TEMP_BED_PIN 13 + + //Cheaptronic v1.0 dont support LCD + #define LCD_PINS_RS -1 + #define LCD_PINS_ENABLE -1 + #define LCD_PINS_D4 -1 + #define LCD_PINS_D5 -1 + #define LCD_PINS_D6 -1 + #define LCD_PINS_D7 -1 + + //Cheaptronic v1.0 dont support keypad + #define BTN_EN1 -1 + #define BTN_EN2 -1 + #define BTN_ENC -1 + + #define BLEN_C 2 + #define BLEN_B 1 + #define BLEN_A 0 + + //Cheaptronic v1.0 does not use this port + #define SDCARDDETECT -1 + + //encoder rotation values + #define encrot0 0 + #define encrot1 2 + #define encrot2 3 + #define encrot3 1 + +#endif + #ifndef KNOWN_BOARD From b7eadb9f37971a9a2cb0b55a3cca0d013d4e6351 Mon Sep 17 00:00:00 2001 From: - <-> Date: Sun, 8 Dec 2013 21:30:42 +0100 Subject: [PATCH 093/256] Made numbering of heat bed thermistor more logical as D8 is bed, D9 is Extruder 2 and D10 is Extruder 1, so T0 should be E1, T1 E1 and T2 bed to be sequential as MOSFET-Outputs --- Marlin/pins.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/pins.h b/Marlin/pins.h index b7cbac4fd7..4572c83992 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -520,7 +520,7 @@ #endif #define TEMP_0_PIN 13 // ANALOG NUMBERING - #define TEMP_1_PIN 15 // ANALOG NUMBERING + #define TEMP_1_PIN 14 // ANALOG NUMBERING #define TEMP_2_PIN -1 // ANALOG NUMBERING #if MOTHERBOARD == 35 @@ -532,7 +532,7 @@ #define HEATER_BED_PIN 8 // BED #endif #endif - #define TEMP_BED_PIN 14 // ANALOG NUMBERING + #define TEMP_BED_PIN 15 // ANALOG NUMBERING From e5d3044801a5c248386380fca188f56ebbea45c5 Mon Sep 17 00:00:00 2001 From: - <-> Date: Sun, 8 Dec 2013 21:34:56 +0100 Subject: [PATCH 094/256] Added posibility to set ENCODER_STEPS_PER_MENU_ITEM in Configuration.h like ENCODER_PULSES_PER_STEP as it depends on it for usability --- Marlin/Configuration.h | 27 ++++++++++---------- Marlin/ultralcd.cpp | 58 ++++++++++++++++++++++-------------------- 2 files changed, 45 insertions(+), 40 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index d5b7621a1f..b4acbac946 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -8,9 +8,9 @@ //=========================================================================== //============================= DELTA Printer =============================== //=========================================================================== -// For a Delta printer rplace the configuration files wilth the files in the +// For a Delta printer rplace the configuration files wilth the files in the // example_configurations/delta directory. -// +// // User-specified version info of this build to display in [Pronterface, etc] terminal window during // startup. Implementation of an idea by Prof Braino to inform user that any changes made to this @@ -37,7 +37,7 @@ // 12 = Gen7 v1.3 // 13 = Gen7 v1.4 // 2 = Cheaptronic v1.0 -// 20 = Sethi 3D_1 +// 20 = Sethi 3D_1 // 3 = MEGA/RAMPS up to 1.2 = 3 // 33 = RAMPS 1.3 / 1.4 (Power outputs: Extruder, Fan, Bed) // 34 = RAMPS 1.3 / 1.4 (Power outputs: Extruder0, Extruder1, Bed) @@ -336,9 +336,9 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #define Z_RAISE_BEFORE_HOMING 4 // (in mm) Raise Z before homing (G28) for Probe Clearance. // Be sure you have this distance over your Z_MAX_POS in case - + #define XY_TRAVEL_SPEED 8000 // X and Y axis travel speed between probes, in mm/min - + #define Z_RAISE_BEFORE_PROBING 15 //How much the extruder will be raised before traveling to the first probing point. #define Z_RAISE_BETWEEN_PROBINGS 5 //How much the extruder will be raised when traveling from between next probing points @@ -347,26 +347,26 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of //The value is the delay to turn the servo off after powered on - depends on the servo speed; 300ms is good value, but you can try lower it. // You MUST HAVE the SERVO_ENDSTOPS defined to use here a value higher than zero otherwise your code will not compile. -// #define PROBE_SERVO_DEACTIVATION_DELAY 300 +// #define PROBE_SERVO_DEACTIVATION_DELAY 300 -//If you have enabled the Bed Auto Levelling and are using the same Z Probe for Z Homing, +//If you have enabled the Bed Auto Levelling and are using the same Z Probe for Z Homing, //it is highly recommended you let this Z_SAFE_HOMING enabled!!! - #define Z_SAFE_HOMING // This feature is meant to avoid Z homing with probe outside the bed area. + #define Z_SAFE_HOMING // This feature is meant to avoid Z homing with probe outside the bed area. // When defined, it will: // - Allow Z homing only after X and Y homing AND stepper drivers still enabled // - If stepper drivers timeout, it will need X and Y homing again before Z homing // - Position the probe in a defined XY point before Z Homing when homing all axis (G28) // - Block Z homing only when the probe is outside bed area. - + #ifdef Z_SAFE_HOMING - + #define Z_SAFE_HOMING_X_POINT (X_MAX_LENGTH/2) // X point for Z homing when homing all axis (G28) #define Z_SAFE_HOMING_Y_POINT (Y_MAX_LENGTH/2) // Y point for Z homing when homing all axis (G28) - + #endif - + #endif @@ -435,6 +435,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of //#define SDSUPPORT // Enable SD Card Support in Hardware Console //#define SDSLOW // Use slower SD transfer mode (not normally needed - uncomment if you're getting volume init error) //#define ENCODER_PULSES_PER_STEP 1 // Increase if you have a high resolution encoder +//#define ENCODER_STEPS_PER_MENU_ITEM 5 // Set according to ENCODER_PULSES_PER_STEP or your liking //#define ULTIMAKERCONTROLLER //as available from the ultimaker online store. //#define ULTIPANEL //the ultipanel as on thingiverse @@ -541,7 +542,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of // Shift register panels // --------------------- // 2 wire Non-latching LCD SR from: -// https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/schematics#!shiftregister-connection +// https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/schematics#!shiftregister-connection //#define SR_LCD #ifdef SR_LCD #define SR_LCD_2W_NL // Non latching 2 wire shiftregister diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 163c881e16..fe8cab0860 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -90,12 +90,16 @@ static void menu_action_setting_edit_callback_long5(const char* pstr, unsigned l #define ENCODER_FEEDRATE_DEADZONE 10 #if !defined(LCD_I2C_VIKI) - #define ENCODER_STEPS_PER_MENU_ITEM 5 + #ifndef ENCODER_STEPS_PER_MENU_ITEM + #define ENCODER_STEPS_PER_MENU_ITEM 5 + #endif #ifndef ENCODER_PULSES_PER_STEP #define ENCODER_PULSES_PER_STEP 1 #endif #else - #define ENCODER_STEPS_PER_MENU_ITEM 2 // VIKI LCD rotary encoder uses a different number of steps per rotation + #ifndef 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 #ifndef ENCODER_PULSES_PER_STEP #define ENCODER_PULSES_PER_STEP 1 #endif @@ -207,7 +211,7 @@ static void lcd_status_screen() else if (feedmultiply == 100 && int(encoderPosition) < -ENCODER_FEEDRATE_DEADZONE) { feedmultiply += int(encoderPosition) + ENCODER_FEEDRATE_DEADZONE; - encoderPosition = 0; + encoderPosition = 0; } else if (feedmultiply != 100) { @@ -407,7 +411,7 @@ static void lcd_tune_menu() #endif MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &fanSpeed, 0, 255); MENU_ITEM_EDIT(int3, MSG_FLOW, &extrudemultiply, 10, 999); - + #ifdef BABYSTEPPING #ifdef BABYSTEP_XY MENU_ITEM(submenu, "Babystep X", lcd_babystep_x); @@ -719,7 +723,7 @@ static void lcd_control_motion_menu() 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); - MENU_ITEM_EDIT(float51, MSG_ESTEPS, &axis_steps_per_unit[E_AXIS], 5, 9999); + MENU_ITEM_EDIT(float51, MSG_ESTEPS, &axis_steps_per_unit[E_AXIS], 5, 9999); #ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED MENU_ITEM_EDIT(bool, "Endstop abort", &abort_on_endstop_hit); #endif @@ -781,7 +785,7 @@ static void lcd_sd_updir() void lcd_sdcard_menu() { - if (lcdDrawUpdate == 0 && LCD_CLICKED == 0) + if (lcdDrawUpdate == 0 && LCD_CLICKED == 0) return; // nothing to do (so don't thrash the SD card) uint16_t fileCnt = card.getnrfilenames(); START_MENU(); @@ -795,7 +799,7 @@ void lcd_sdcard_menu() }else{ MENU_ITEM(function, LCD_STR_FOLDER "..", lcd_sd_updir); } - + for(uint16_t i=0;i 0 - pinMode(BTN_ENC,INPUT); + pinMode(BTN_ENC,INPUT); WRITE(BTN_ENC,HIGH); - #endif + #endif #ifdef REPRAPWORLD_KEYPAD pinMode(SHIFT_CLK,OUTPUT); pinMode(SHIFT_LD,OUTPUT); @@ -1007,9 +1011,9 @@ void lcd_init() pinMode(SHIFT_EN,OUTPUT); pinMode(SHIFT_OUT,INPUT); WRITE(SHIFT_OUT,HIGH); - WRITE(SHIFT_LD,HIGH); + WRITE(SHIFT_LD,HIGH); WRITE(SHIFT_EN,LOW); - #endif // SR_LCD_2W_NL + #endif // SR_LCD_2W_NL #endif//!NEWPANEL #if (SDCARDDETECT > 0) @@ -1020,28 +1024,28 @@ void lcd_init() slow_buttons = 0; #endif lcd_buttons_update(); -#ifdef ULTIPANEL +#ifdef ULTIPANEL encoderDiff = 0; -#endif +#endif } void lcd_update() { static unsigned long timeoutToStatus = 0; - + #ifdef 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 (SDCARDDETECT > 0) if((IS_SD_INSERTED != lcd_oldcardstatus)) { lcdDrawUpdate = 2; lcd_oldcardstatus = IS_SD_INSERTED; lcd_implementation_init(); // to maybe revive the lcd if static electricty killed it. - + if(lcd_oldcardstatus) { card.initsd(); @@ -1054,7 +1058,7 @@ void lcd_update() } } #endif//CARDINSERTED - + if (lcd_next_update_millis < millis()) { #ifdef ULTIPANEL @@ -1095,7 +1099,7 @@ void lcd_update() #ifdef DOGLCD // Changes due to different driver architecture of the DOGM display blink++; // Variable for fan animation and alive dot u8g.firstPage(); - do + do { u8g.setFont(u8g_font_6x10_marlin); u8g.setPrintPos(125,0); @@ -1105,7 +1109,7 @@ void lcd_update() (*currentMenu)(); if (!lcdDrawUpdate) break; // Terminate display update, when nothing new to draw. This must be done before the last dogm.next() } while( u8g.nextPage() ); -#else +#else (*currentMenu)(); #endif @@ -1159,7 +1163,7 @@ void lcd_reset_alert_level() void lcd_setcontrast(uint8_t value) { lcd_contrast = value & 63; - u8g.setContrast(lcd_contrast); + u8g.setContrast(lcd_contrast); } #endif @@ -1199,7 +1203,7 @@ void lcd_buttons_update() WRITE(SHIFT_LD,HIGH); unsigned char tmp_buttons=0; for(int8_t i=0;i<8;i++) - { + { newbutton = newbutton>>1; if(READ(SHIFT_OUT)) newbutton|=(1<<7); @@ -1249,14 +1253,14 @@ void lcd_buttons_update() } void lcd_buzz(long duration, uint16_t freq) -{ +{ #ifdef LCD_USE_I2C_BUZZER lcd.buzz(duration,freq); -#endif +#endif } -bool lcd_clicked() -{ +bool lcd_clicked() +{ return LCD_CLICKED; } #endif//ULTIPANEL From 20faff59353fff7af843cfd624d79c7e17e1ce94 Mon Sep 17 00:00:00 2001 From: - <-> Date: Sun, 8 Dec 2013 21:35:57 +0100 Subject: [PATCH 095/256] Incorporate PS_DEFAULT_OFF for starting state on LCD menu entry --- Marlin/Marlin_main.cpp | 186 +++++++++++++++++++++-------------------- 1 file changed, 95 insertions(+), 91 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 8993ca6955..db072b9e02 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -47,7 +47,7 @@ #ifdef BLINKM #include "BlinkM.h" -#include "Wire.h" +#include "Wire.h" #endif #if NUM_SERVOS > 0 @@ -96,7 +96,7 @@ // M29 - Stop SD write // M30 - Delete file from SD (M30 filename.g) // M31 - Output time since last M109 or SD card start to serial -// M32 - Select file and start SD print (Can be used _while_ printing from SD card files): +// M32 - Select file and start SD print (Can be used _while_ printing from SD card files): // syntax "M32 /path/filename#", or "M32 S !filename#" // Call gcode file : "M32 P !filename#" and return to caller file after finishing (simiarl to #include). // The '#' is necessary when calling from within sd files, as it stops buffer prereading @@ -226,7 +226,11 @@ int EtoPPressure=0; #endif #ifdef ULTIPANEL - bool powersupply = true; + #ifdef PS_DEFAULT_OFF + bool powersupply = false; + #else + bool powersupply = true; + #endif #endif #ifdef DELTA @@ -415,7 +419,7 @@ void servo_init() #if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) delay(PROBE_SERVO_DEACTIVATION_DELAY); - servos[servo_endstops[Z_AXIS]].detach(); + servos[servo_endstops[Z_AXIS]].detach(); #endif } @@ -636,17 +640,17 @@ void get_command() if(!card.sdprinting || serial_count!=0){ return; } - + //'#' stops reading from sd to the buffer prematurely, so procedural macro calls are possible - // if it occures, stop_buffering is triggered and the buffer is ran dry. + // if it occures, stop_buffering is triggered and the buffer is ran dry. // this character _can_ occure in serial com, due to checksums. however, no checksums are used in sd printing - + static bool stop_buffering=false; if(buflen==0) stop_buffering=false; - - while( !card.eof() && buflen < BUFSIZE && !stop_buffering) { + + while( !card.eof() && buflen < BUFSIZE && !stop_buffering) { int16_t n=card.get(); - serial_char = (char)n; + serial_char = (char)n; if(serial_char == '\n' || serial_char == '\r' || (serial_char == '#' && comment_mode == false) || @@ -671,7 +675,7 @@ void get_command() } if(serial_char=='#') stop_buffering=true; - + if(!serial_count) { comment_mode = false; //for new command @@ -743,13 +747,13 @@ XYZ_CONSTS_FROM_CONFIG(signed char, home_dir, HOME_DIR); #endif #if X_HOME_DIR != -1 || X2_HOME_DIR != 1 #error "Please use canonical x-carriage assignment" // the x-carriages are defined by their homing directions - #endif + #endif #define DXC_FULL_CONTROL_MODE 0 #define DXC_AUTO_PARK_MODE 1 #define DXC_DUPLICATION_MODE 2 static int dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; - + static float x_home_pos(int extruder) { if (extruder == 0) return base_home_pos(X_AXIS) + add_homeing[X_AXIS]; @@ -767,12 +771,12 @@ static int x_home_dir(int extruder) { static float inactive_extruder_x_pos = X2_MAX_POS; // used in mode 0 & 1 static bool active_extruder_parked = false; // used in mode 1 & 2 -static float raised_parked_position[NUM_AXIS]; // used in mode 1 -static unsigned long delayed_move_time = 0; // used in mode 1 +static float raised_parked_position[NUM_AXIS]; // used in mode 1 +static unsigned long delayed_move_time = 0; // used in mode 1 static float duplicate_extruder_x_offset = DEFAULT_DUPLICATION_X_OFFSET; // used in mode 2 static float duplicate_extruder_temp_offset = 0; // used in mode 2 bool extruder_duplication_enabled = false; // used in mode 2 -#endif //DUAL_X_CARRIAGE +#endif //DUAL_X_CARRIAGE static void axis_is_at_home(int axis) { #ifdef DUAL_X_CARRIAGE @@ -785,8 +789,8 @@ static void axis_is_at_home(int axis) { } else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && active_extruder == 0) { current_position[X_AXIS] = base_home_pos(X_AXIS) + add_homeing[X_AXIS]; - min_pos[X_AXIS] = base_min_pos(X_AXIS) + add_homeing[X_AXIS]; - max_pos[X_AXIS] = min(base_max_pos(X_AXIS) + add_homeing[X_AXIS], + min_pos[X_AXIS] = base_min_pos(X_AXIS) + add_homeing[X_AXIS]; + max_pos[X_AXIS] = min(base_max_pos(X_AXIS) + add_homeing[X_AXIS], max(extruder_offset[X_AXIS][1], X2_MAX_POS) - duplicate_extruder_x_offset); return; } @@ -853,7 +857,7 @@ static void run_z_probe() { st_synchronize(); // move back down slowly to find bed - feedrate = homing_feedrate[Z_AXIS]/4; + feedrate = homing_feedrate[Z_AXIS]/4; zPosition -= home_retract_mm(Z_AXIS) * 2; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], zPosition, current_position[E_AXIS], feedrate/60, active_extruder); st_synchronize(); @@ -950,7 +954,7 @@ static void homeaxis(int axis) { current_position[axis] = 0; plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - + // Engage Servo endstop if enabled #ifdef SERVO_ENDSTOPS @@ -1008,7 +1012,7 @@ static void homeaxis(int axis) { #if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) if (axis==Z_AXIS) retract_z_probe(); #endif - + } } #define HOMEAXIS(LETTER) homeaxis(LETTER##_AXIS) @@ -1082,7 +1086,7 @@ void process_commands() destination[Y_AXIS]=current_position[Y_AXIS]; destination[Z_AXIS]=current_position[Z_AXIS]; current_position[Z_AXIS]+=retract_zlift; - destination[E_AXIS]=current_position[E_AXIS]+retract_length+retract_recover_length; + destination[E_AXIS]=current_position[E_AXIS]+retract_length+retract_recover_length; feedrate=retract_recover_feedrate; retracted=false; prepare_move(); @@ -1196,10 +1200,10 @@ void process_commands() // reset state used by the different modes memcpy(raised_parked_position, current_position, sizeof(raised_parked_position)); delayed_move_time = 0; - active_extruder_parked = true; - #else + active_extruder_parked = true; + #else HOMEAXIS(X); - #endif + #endif } if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) { @@ -1218,7 +1222,7 @@ void process_commands() current_position[Y_AXIS]=code_value()+add_homeing[1]; } } - + #if Z_HOME_DIR < 0 // If homing towards BED do Z last #ifndef Z_SAFE_HOMING if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { @@ -1230,14 +1234,14 @@ void process_commands() #endif HOMEAXIS(Z); } - #else // Z Safe mode activated. + #else // Z Safe mode activated. if(home_all_axis) { destination[X_AXIS] = round(Z_SAFE_HOMING_X_POINT - X_PROBE_OFFSET_FROM_EXTRUDER); destination[Y_AXIS] = round(Z_SAFE_HOMING_Y_POINT - Y_PROBE_OFFSET_FROM_EXTRUDER); destination[Z_AXIS] = Z_RAISE_BEFORE_HOMING * home_dir(Z_AXIS) * (-1); // Set destination away from bed feedrate = XY_TRAVEL_SPEED; current_position[Z_AXIS] = 0; - + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate, active_extruder); st_synchronize(); @@ -1255,7 +1259,7 @@ void process_commands() && (current_position[Y_AXIS]+Y_PROBE_OFFSET_FROM_EXTRUDER <= Y_MAX_POS)) { current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); destination[Z_AXIS] = Z_RAISE_BEFORE_HOMING * home_dir(Z_AXIS) * (-1); // Set destination away from bed feedrate = max_feedrate[Z_AXIS]; plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate, active_extruder); @@ -1275,8 +1279,8 @@ void process_commands() #endif #endif - - + + if(code_seen(axis_codes[Z_AXIS])) { if(code_value_long() != 0) { current_position[Z_AXIS]=code_value()+add_homeing[2]; @@ -1347,7 +1351,7 @@ void process_commands() run_z_probe(); float z_at_xLeft_yFront = current_position[Z_AXIS]; retract_z_probe(); - + SERIAL_PROTOCOLPGM("Bed x: "); SERIAL_PROTOCOL(LEFT_PROBE_BED_POSITION); SERIAL_PROTOCOLPGM(" y: "); @@ -1365,7 +1369,7 @@ void process_commands() run_z_probe(); float z_at_xRight_yFront = current_position[Z_AXIS]; retract_z_probe(); // Retract Z Servo endstop if available - + SERIAL_PROTOCOLPGM("Bed x: "); SERIAL_PROTOCOL(RIGHT_PROBE_BED_POSITION); SERIAL_PROTOCOLPGM(" y: "); @@ -1378,10 +1382,10 @@ void process_commands() set_bed_level_equation(z_at_xLeft_yFront, z_at_xRight_yFront, z_at_xLeft_yBack); - st_synchronize(); + st_synchronize(); // The following code correct the Z height difference from z-probe position and hotend tip position. - // The Z height on homing is measured by Z-Probe, but the probe is quite far from the hotend. + // The Z height on homing is measured by Z-Probe, but the probe is quite far from the hotend. // When the bed is uneven, this height must be corrected. real_z = float(st_get_position(Z_AXIS))/axis_steps_per_unit[Z_AXIS]; //get the real Z (since the auto bed leveling is already correcting the plane) x_tmp = current_position[X_AXIS] + X_PROBE_OFFSET_FROM_EXTRUDER; @@ -1393,11 +1397,11 @@ void process_commands() plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); } break; - + case 30: // G30 Single Z Probe { engage_z_probe(); // Engage Z Servo endstop if available - + st_synchronize(); // TODO: make sure the bed_level_rotation_matrix is identity or the planner will get set incorectly setup_for_endstop_move(); @@ -1548,14 +1552,14 @@ void process_commands() card.removeFile(strchr_pointer + 4); } break; - case 32: //M32 - Select file and start SD print + case 32: //M32 - Select file and start SD print { if(card.sdprinting) { st_synchronize(); } - starpos = (strchr(strchr_pointer + 4,'*')); - + starpos = (strchr(strchr_pointer + 4,'*')); + char* namestartpos = (strchr(strchr_pointer + 4,'!')); //find ! to indicate filename string start. if(namestartpos==NULL) { @@ -1563,16 +1567,16 @@ void process_commands() } else namestartpos++; //to skip the '!' - + if(starpos!=NULL) *(starpos-1)='\0'; - + bool call_procedure=(code_seen('P')); - - if(strchr_pointer>namestartpos) + + if(strchr_pointer>namestartpos) call_procedure=false; //false alert, 'P' found within filename - - if( card.cardOK ) + + if( card.cardOK ) { card.openFile(namestartpos,true,!call_procedure); if(code_seen('S')) @@ -1645,7 +1649,7 @@ void process_commands() #ifdef DUAL_X_CARRIAGE if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0) setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset); -#endif +#endif setWatch(); break; case 140: // M140 set bed temp @@ -1701,7 +1705,7 @@ void process_commands() SERIAL_PROTOCOL_F(rawHotendTemp(cur_extruder)/OVERSAMPLENR,0); } #endif - + SERIAL_PROTOCOLLN(""); return; break; @@ -1719,14 +1723,14 @@ void process_commands() #ifdef DUAL_X_CARRIAGE if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0) setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset); -#endif +#endif CooldownNoWait = true; } else if (code_seen('R')) { setTargetHotend(code_value(), tmp_extruder); #ifdef DUAL_X_CARRIAGE if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0) setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset); -#endif +#endif CooldownNoWait = false; } #ifdef AUTOTEMP @@ -1890,7 +1894,7 @@ void process_commands() SET_OUTPUT(SUICIDE_PIN); WRITE(SUICIDE_PIN, HIGH); #endif - + #ifdef ULTIPANEL powersupply = true; LCD_MESSAGEPGM(WELCOME_MSG); @@ -2047,18 +2051,18 @@ void process_commands() #endif break; //TODO: update for all axis, use for loop - #ifdef BLINKM + #ifdef BLINKM case 150: // M150 { byte red; byte grn; byte blu; - + if(code_seen('R')) red = code_value(); if(code_seen('U')) grn = code_value(); if(code_seen('B')) blu = code_value(); - - SendColors(red,grn,blu); + + SendColors(red,grn,blu); } break; #endif //BLINKM @@ -2180,7 +2184,7 @@ void process_commands() { extruder_offset[Z_AXIS][tmp_extruder] = code_value(); } - #endif + #endif SERIAL_ECHO_START; SERIAL_ECHOPGM(MSG_HOTEND_OFFSET); for(tmp_extruder = 0; tmp_extruder < EXTRUDERS; tmp_extruder++) @@ -2213,17 +2217,17 @@ void process_commands() } } break; - + case 226: // M226 P S- Wait until the specified pin reaches the state required { if(code_seen('P')){ int pin_number = code_value(); // pin number int pin_state = -1; // required pin state - default is inverted - + if(code_seen('S')) pin_state = code_value(); // required pin state - + if(pin_state >= -1 && pin_state <= 1){ - + for(int8_t i = 0; i < (int8_t)sizeof(sensitive_pins); i++) { if (sensitive_pins[i] == pin_number) @@ -2232,28 +2236,28 @@ void process_commands() break; } } - + if (pin_number > -1) { st_synchronize(); - + pinMode(pin_number, INPUT); - + int target; switch(pin_state){ case 1: target = HIGH; break; - + case 0: target = LOW; break; - + case -1: target = !digitalRead(pin_number); break; } - + while(digitalRead(pin_number) != target){ manage_heater(); manage_inactivity(); @@ -2263,7 +2267,7 @@ void process_commands() } } } - break; + break; #if NUM_SERVOS > 0 case 280: // M280 - set servo position absolute. P: servo index, S: angle or microseconds @@ -2439,13 +2443,13 @@ void process_commands() engage_z_probe(); // Engage Z Servo endstop if available } break; - + case 402: { retract_z_probe(); // Retract Z Servo endstop if enabled } break; -#endif +#endif case 500: // M500 Store settings in EEPROM { Config_StoreSettings(); @@ -2603,14 +2607,14 @@ void process_commands() // M605 S0: Full control mode. The slicer has full control over x-carriage movement // M605 S1: Auto-park mode. The inactive head will auto park/unpark without slicer involvement // M605 S2 [Xnnn] [Rmmm]: Duplication mode. The second extruder will duplicate the first with nnn - // millimeters x-offset and an optional differential hotend temperature of + // millimeters x-offset and an optional differential hotend temperature of // mmm degrees. E.g., with "M605 S2 X100 R2" the second extruder will duplicate // the first with a spacing of 100mm in the x direction and 2 degrees hotter. // // Note: the X axis should be homed after changing dual x-carriage mode. { st_synchronize(); - + if (code_seen('S')) dual_x_carriage_mode = code_value(); @@ -2621,7 +2625,7 @@ void process_commands() if (code_seen('R')) duplicate_extruder_temp_offset = code_value(); - + SERIAL_ECHO_START; SERIAL_ECHOPGM(MSG_HOTEND_OFFSET); SERIAL_ECHO(" "); @@ -2637,13 +2641,13 @@ void process_commands() { dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; } - + active_extruder_parked = false; extruder_duplication_enabled = false; delayed_move_time = 0; } break; - #endif //DUAL_X_CARRIAGE + #endif //DUAL_X_CARRIAGE case 907: // M907 Set digital trimpot motor current using axis codes. { @@ -2724,19 +2728,19 @@ void process_commands() // Save current position to return to after applying extruder offset memcpy(destination, current_position, sizeof(destination)); #ifdef DUAL_X_CARRIAGE - if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE && Stopped == false && + if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE && Stopped == false && (delayed_move_time != 0 || current_position[X_AXIS] != x_home_pos(active_extruder))) { // Park old head: 1) raise 2) move to park position 3) lower - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); - plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, + plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, current_position[E_AXIS], max_feedrate[X_AXIS], active_extruder); - plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS], + plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); st_synchronize(); } - + // apply Y & Z extruder offset (x offset is already used in determining home pos) current_position[Y_AXIS] = current_position[Y_AXIS] - extruder_offset[Y_AXIS][active_extruder] + @@ -2744,7 +2748,7 @@ void process_commands() current_position[Z_AXIS] = current_position[Z_AXIS] - extruder_offset[Z_AXIS][active_extruder] + extruder_offset[Z_AXIS][tmp_extruder]; - + active_extruder = tmp_extruder; // This function resets the max/min values - the current position may be overwritten below. @@ -2752,18 +2756,18 @@ void process_commands() if (dual_x_carriage_mode == DXC_FULL_CONTROL_MODE) { - current_position[X_AXIS] = inactive_extruder_x_pos; + current_position[X_AXIS] = inactive_extruder_x_pos; inactive_extruder_x_pos = destination[X_AXIS]; } else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE) { active_extruder_parked = (active_extruder == 0); // this triggers the second extruder to move into the duplication position if (active_extruder == 0 || active_extruder_parked) - current_position[X_AXIS] = inactive_extruder_x_pos; + current_position[X_AXIS] = inactive_extruder_x_pos; else - current_position[X_AXIS] = destination[X_AXIS] + duplicate_extruder_x_offset; + current_position[X_AXIS] = destination[X_AXIS] + duplicate_extruder_x_offset; inactive_extruder_x_pos = destination[X_AXIS]; - extruder_duplication_enabled = false; + extruder_duplication_enabled = false; } else { @@ -2773,7 +2777,7 @@ void process_commands() active_extruder_parked = true; delayed_move_time = 0; } - #else + #else // Offset extruder (only by XY) int i; for(i = 0; i < 2; i++) { @@ -2986,13 +2990,13 @@ void prepare_move() { // move duplicate extruder into correct duplication position. plan_set_position(inactive_extruder_x_pos, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - plan_buffer_line(current_position[X_AXIS] + duplicate_extruder_x_offset, current_position[Y_AXIS], current_position[Z_AXIS], + plan_buffer_line(current_position[X_AXIS] + duplicate_extruder_x_offset, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], max_feedrate[X_AXIS], 1); plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); st_synchronize(); extruder_duplication_enabled = true; active_extruder_parked = false; - } + } else if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE) // handle unparking of head { if (current_position[E_AXIS] == destination[E_AXIS]) @@ -3001,7 +3005,7 @@ void prepare_move() // be used as start of first non-travel move) if (delayed_move_time != 0xFFFFFFFFUL) { - memcpy(current_position, destination, sizeof(current_position)); + memcpy(current_position, destination, sizeof(current_position)); if (destination[Z_AXIS] > raised_parked_position[Z_AXIS]) raised_parked_position[Z_AXIS] = destination[Z_AXIS]; delayed_move_time = millis(); @@ -3011,9 +3015,9 @@ void prepare_move() delayed_move_time = 0; // unpark extruder: 1) raise, 2) move into starting XY position, 3) lower plan_buffer_line(raised_parked_position[X_AXIS], raised_parked_position[Y_AXIS], raised_parked_position[Z_AXIS], current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], raised_parked_position[Z_AXIS], + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], raised_parked_position[Z_AXIS], current_position[E_AXIS], min(max_feedrate[X_AXIS],max_feedrate[Y_AXIS]), active_extruder); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); active_extruder_parked = false; } @@ -3179,7 +3183,7 @@ void manage_inactivity() // travel moves have been received so enact them delayed_move_time = 0xFFFFFFFFUL; // force moves to be done memcpy(destination,current_position,sizeof(destination)); - prepare_move(); + prepare_move(); } #endif #ifdef TEMP_STAT_LEDS From 5bde7fcb28601eda609611f2590f3f056c8e4b34 Mon Sep 17 00:00:00 2001 From: fsantini Date: Wed, 11 Dec 2013 21:27:43 +0100 Subject: [PATCH 096/256] Minor code and comment polishing --- Marlin/Marlin_main.cpp | 8 ++------ Marlin/vector_3.cpp | 6 ++---- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index db9686f3ed..daeb65ffa6 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -809,14 +809,10 @@ static void set_bed_level_equation_lsq(double *plane_equation_coefficients) plan_bed_level_matrix = matrix_3x3::create_look_at(planeNormal); //bedLevel.debug("bedLevel"); - plan_bed_level_matrix.debug("bed level before"); + //plan_bed_level_matrix.debug("bed level before"); //vector_3 uncorrected_position = plan_get_position_mm(); //uncorrected_position.debug("position before"); - // and set our bed level equation to do the right thing -// plan_bed_level_matrix = matrix_3x3::create_inverse(bedLevel); -// plan_bed_level_matrix.debug("bed level after"); - vector_3 corrected_position = plan_get_position(); // corrected_position.debug("position after"); current_position[X_AXIS] = corrected_position.x; @@ -824,7 +820,7 @@ static void set_bed_level_equation_lsq(double *plane_equation_coefficients) current_position[Z_AXIS] = corrected_position.z; // but the bed at 0 so we don't go below it. - current_position[Z_AXIS] = -Z_PROBE_OFFSET_FROM_EXTRUDER; // in the lsq we reach here after raising the extruder due to the loop structure + current_position[Z_AXIS] = -Z_PROBE_OFFSET_FROM_EXTRUDER; plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); } diff --git a/Marlin/vector_3.cpp b/Marlin/vector_3.cpp index c9f4803231..c143e012ec 100644 --- a/Marlin/vector_3.cpp +++ b/Marlin/vector_3.cpp @@ -129,7 +129,7 @@ void matrix_3x3::set_to_identity() matrix_3x3 matrix_3x3::create_look_at(vector_3 target) { - vector_3 z_row = vector_3(target.x, target.y, target.z).get_normal(); + vector_3 z_row = target.get_normal(); vector_3 x_row = vector_3(1, 0, -target.x/target.z).get_normal(); vector_3 y_row = vector_3(0, 1, -target.y/target.z).get_normal(); @@ -139,9 +139,7 @@ matrix_3x3 matrix_3x3::create_look_at(vector_3 target) // create the matrix already correctly transposed - matrix_3x3 rot = matrix_3x3::create_from_rows(vector_3(x_row.x, x_row.y, x_row.z), - vector_3(y_row.x, y_row.y, y_row.z), - vector_3(z_row.x, z_row.y, z_row.z)); + matrix_3x3 rot = matrix_3x3::create_from_rows(x_row, y_row, z_row); // rot.debug("rot"); return rot; From d29615dc0c82f02df2f91b8e0a4d4e20e85f2e60 Mon Sep 17 00:00:00 2001 From: RicardoGA Date: Wed, 11 Dec 2013 14:37:43 -0600 Subject: [PATCH 097/256] Z and Y dual stepper drivers error if you try to enable Z_DUAL_STEPPER_DRIVERS the error "You cannot have dual drivers for both Y and Z" shows even if you don't have defined Y_DUAL_STEPPER_DRIVERS and don't let you compile the firmware to solve this problem i change this line: #ifdef Z_DUAL_STEPPER_DRIVERS && Y_DUAL_STEPPER_DRIVERS to: #if defined (Z_DUAL_STEPPER_DRIVERS) && defined (Y_DUAL_STEPPER_DRIVERS) now the error only show if you define both Z_DUAL_STEPPER_DRIVERS and Y_DUAL_STEPPER_DRIVERS --- Marlin/Configuration_adv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 7b3ef4aede..4e5d829114 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -161,7 +161,7 @@ #define EXTRUDERS 1 #endif -#ifdef Z_DUAL_STEPPER_DRIVERS && Y_DUAL_STEPPER_DRIVERS +#if defined (Z_DUAL_STEPPER_DRIVERS) && defined (Y_DUAL_STEPPER_DRIVERS) #error "You cannot have dual drivers for both Y and Z" #endif From da2a6f9a312dd7cae3fb450784630a6051d7bbdf Mon Sep 17 00:00:00 2001 From: Francesco Santini Date: Fri, 13 Dec 2013 10:31:19 +0100 Subject: [PATCH 098/256] Accurate bed leveling: x loop inside y and zigzag motion --- Marlin/Marlin_main.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index daeb65ffa6..e37c3e1de7 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1368,10 +1368,26 @@ void process_commands() int probePointCounter = 0; + bool zig = true; - for (int xProbe=LEFT_PROBE_BED_POSITION; xProbe <= RIGHT_PROBE_BED_POSITION; xProbe += xGridSpacing) + for (int yProbe=FRONT_PROBE_BED_POSITION; yProbe <= BACK_PROBE_BED_POSITION; yProbe += yGridSpacing) { - for (int yProbe=FRONT_PROBE_BED_POSITION; yProbe <= BACK_PROBE_BED_POSITION; yProbe += yGridSpacing) + int xProbe, xInc; + if (zig) + { + xProbe = LEFT_PROBE_BED_POSITION; + //xEnd = RIGHT_PROBE_BED_POSITION; + xInc = xGridSpacing; + zig = false; + } else // zag + { + xProbe = RIGHT_PROBE_BED_POSITION; + //xEnd = LEFT_PROBE_BED_POSITION; + xInc = -xGridSpacing; + zig = true; + } + + for (int xCount=0; xCount < ACCURATE_BED_LEVELING_POINTS; xCount++) { if (probePointCounter == 0) { @@ -1403,6 +1419,7 @@ void process_commands() eqnAMatrix[probePointCounter + 1*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = yProbe; eqnAMatrix[probePointCounter + 2*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = 1; probePointCounter++; + xProbe += xInc; } } clean_up_after_endstop_move(); From 8349fc89a4a80ce1ce7b1016c002f70285fad330 Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Mon, 16 Dec 2013 11:40:23 +0100 Subject: [PATCH 099/256] Fixed planner bug --- Marlin/planner.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/planner.cpp b/Marlin/planner.cpp index 008c8d257f..457988dab5 100644 --- a/Marlin/planner.cpp +++ b/Marlin/planner.cpp @@ -186,9 +186,9 @@ void calculate_trapezoid_for_block(block_t *block, float entry_factor, float exi long acceleration = block->acceleration_st; int32_t accelerate_steps = - ceil(estimate_acceleration_distance(block->initial_rate, block->nominal_rate, acceleration)); + ceil(estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration)); int32_t decelerate_steps = - floor(estimate_acceleration_distance(block->nominal_rate, block->final_rate, -acceleration)); + floor(estimate_acceleration_distance(block->nominal_rate, final_rate, -acceleration)); // Calculate the size of Plateau of Nominal Rate. int32_t plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps; @@ -197,7 +197,7 @@ void calculate_trapezoid_for_block(block_t *block, float entry_factor, float exi // have to use intersection_distance() to calculate when to abort acceleration and start braking // in order to reach the final_rate exactly at the end of this block. if (plateau_steps < 0) { - accelerate_steps = ceil(intersection_distance(block->initial_rate, block->final_rate, acceleration, block->step_event_count)); + accelerate_steps = ceil(intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count)); accelerate_steps = max(accelerate_steps,0); // Check limits due to numerical round-off accelerate_steps = min((uint32_t)accelerate_steps,block->step_event_count);//(We can cast here to unsigned, because the above line ensures that we are above zero) plateau_steps = 0; From eed053dffbcd8ad9a5c4b22e53e74a6f34aebdfb Mon Sep 17 00:00:00 2001 From: - <-> Date: Mon, 16 Dec 2013 12:22:06 +0100 Subject: [PATCH 100/256] Revert "Made numbering of heat bed thermistor more logical as D8 is bed, D9 is Extruder 2 and D10 is Extruder 1, so T0 should be E1, T1 E1 and T2 bed to be sequential as MOSFET-Outputs" This reverts commit b7eadb9f37971a9a2cb0b55a3cca0d013d4e6351. --- Marlin/pins.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/pins.h b/Marlin/pins.h index 4572c83992..b7cbac4fd7 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -520,7 +520,7 @@ #endif #define TEMP_0_PIN 13 // ANALOG NUMBERING - #define TEMP_1_PIN 14 // ANALOG NUMBERING + #define TEMP_1_PIN 15 // ANALOG NUMBERING #define TEMP_2_PIN -1 // ANALOG NUMBERING #if MOTHERBOARD == 35 @@ -532,7 +532,7 @@ #define HEATER_BED_PIN 8 // BED #endif #endif - #define TEMP_BED_PIN 15 // ANALOG NUMBERING + #define TEMP_BED_PIN 14 // ANALOG NUMBERING From 8e48e24c7f1b819a5417a3d37469ed93eea40ceb Mon Sep 17 00:00:00 2001 From: Joseivaldo Benito Junior Date: Tue, 17 Dec 2013 23:57:01 -0200 Subject: [PATCH 101/256] Update Delta example files Signed-off-by: Joseivaldo Benito Junior --- .../delta/Configuration.h | 122 +++++++++++++++--- .../delta/Configuration_adv.h | 90 ++++++++++++- 2 files changed, 189 insertions(+), 23 deletions(-) diff --git a/Marlin/example_configurations/delta/Configuration.h b/Marlin/example_configurations/delta/Configuration.h index dbd2892b4b..8d6dd6acfd 100644 --- a/Marlin/example_configurations/delta/Configuration.h +++ b/Marlin/example_configurations/delta/Configuration.h @@ -5,6 +5,13 @@ // Advanced settings can be found in Configuration_adv.h // BASIC SETTINGS: select your board type, temperature sensor type, axis scaling, and endstop configuration +//=========================================================================== +//============================= DELTA Printer =============================== +//=========================================================================== +// For a Delta printer rplace the configuration files wilth the files in the +// example_configurations/delta directory. +// + // User-specified version info of this build to display in [Pronterface, etc] terminal window during // startup. Implementation of an idea by Prof Braino to inform user that any changes made to this // build by the user have been successfully uploaded into firmware. @@ -18,13 +25,18 @@ // This determines the communication speed of the printer #define BAUDRATE 250000 -//#define BAUDRATE 115200 + +// This enables the serial port associated to the Bluetooth interface +//#define BTENABLED // Enable BT interface on AT90USB devices + //// The following define selects which electronics board you have. Please choose the one that matches your setup // 10 = Gen7 custom (Alfons3 Version) "https://github.com/Alfons3/Generation_7_Electronics" // 11 = Gen7 v1.1, v1.2 = 11 // 12 = Gen7 v1.3 // 13 = Gen7 v1.4 +// 2 = Cheaptronic v1.0 +// 20 = Sethi 3D_1 // 3 = MEGA/RAMPS up to 1.2 = 3 // 33 = RAMPS 1.3 / 1.4 (Power outputs: Extruder, Fan, Bed) // 34 = RAMPS 1.3 / 1.4 (Power outputs: Extruder0, Extruder1, Bed) @@ -38,6 +50,7 @@ // 64 = STB V1.1 // 65 = Azteeg X1 // 66 = Melzi with ATmega1284 (MaKr3d version) +// 67 = Azteeg X3 // 7 = Ultimaker // 71 = Ultimaker (Older electronics. Pre 1.5.4. This is rare) // 77 = 3Drag Controller @@ -45,6 +58,7 @@ // 80 = Rumba // 81 = Printrboard (AT90USB1286) // 82 = Brainwave (AT90USB646) +// 83 = SAV Mk-I (AT90USB1286) // 9 = Gen3+ // 70 = Megatronics // 701= Megatronics v2.0 @@ -61,6 +75,10 @@ // Define this to set a custom name for your generic Mendel, // #define CUSTOM_MENDEL_NAME "This Mendel" +// Define this to set a unique identifier for this printer, (Used by some programs to differentiate between machines) +// You can use an online service to generate a random UUID. (eg http://www.uuidgenerator.net/version4) +// #define MACHINE_UUID "00000000-0000-0000-0000-000000000000" + // This defines the number of extruders #define EXTRUDERS 1 @@ -70,6 +88,8 @@ #define POWER_SUPPLY 1 +// Define this to have the electronics keep the powersupply off on startup. If you don't know what this is leave it. +// #define PS_DEFAULT_OFF //=========================================================================== //============================== Delta Settings ============================= @@ -82,8 +102,6 @@ // and processor overload (too many expensive sqrt calls). #define DELTA_SEGMENTS_PER_SECOND 200 -// NOTE NB all values for DELTA_* values MOUST be floating point, so always have a decimal point in them - // Center-to-center distance of the holes in the diagonal push rods. #define DELTA_DIAGONAL_ROD 250.0 // mm @@ -99,8 +117,6 @@ // Effective horizontal distance bridged by diagonal push rods. #define DELTA_RADIUS (DELTA_SMOOTH_ROD_OFFSET-DELTA_EFFECTOR_OFFSET-DELTA_CARRIAGE_OFFSET) -#define DELTA_DIAGONAL_ROD_2 sq(DELTA_DIAGONAL_ROD) - // Effective X/Y positions of the three vertical towers. #define SIN_60 0.8660254037844386 #define COS_60 0.5 @@ -125,9 +141,10 @@ // 2 is 200k thermistor - ATC Semitec 204GT-2 (4.7k pullup) // 3 is mendel-parts thermistor (4.7k pullup) // 4 is 10k thermistor !! do not use it for a hotend. It gives bad resolution at high temp. !! -// 5 is 100K thermistor - ATC Semitec 104GT-2 (Used in ParCan) (4.7k pullup) +// 5 is 100K thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (4.7k pullup) // 6 is 100k EPCOS - Not as accurate as table 1 (created using a fluke thermocouple) (4.7k pullup) // 7 is 100k Honeywell thermistor 135-104LAG-J01 (4.7k pullup) +// 71 is 100k Honeywell thermistor 135-104LAF-J01 (4.7k pullup) // 8 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup) // 9 is 100k GE Sensing AL03006-58.2K-97-G1 (4.7k pullup) // 10 is 100k RS thermistor 198-961 (4.7k pullup) @@ -137,7 +154,7 @@ // (but gives greater accuracy and more stable PID) // 51 is 100k thermistor - EPCOS (1k pullup) // 52 is 200k thermistor - ATC Semitec 204GT-2 (1k pullup) -// 55 is 100k thermistor - ATC Semitec 104GT-2 (Used in ParCan) (1k pullup) +// 55 is 100k thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (1k pullup) #define TEMP_SENSOR_0 -1 #define TEMP_SENSOR_1 -1 @@ -282,16 +299,15 @@ #endif // The pullups are needed if you directly connect a mechanical endswitch between the signal and ground pins. -const bool X_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop. -const bool Y_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop. -const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop. -const bool X_MAX_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop. -const bool Y_MAX_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop. -const bool Z_MAX_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop. - -// deltas never have min endstops +const bool X_MIN_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop. +const bool Y_MIN_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop. +const bool Z_MIN_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop. +const bool X_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop. +const bool Y_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop. +const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop. +//#define DISABLE_MAX_ENDSTOPS +// Deltas never have min endstops #define DISABLE_MIN_ENDSTOPS - // Disable max endstops for compatibility with endstop checking routine #if defined(COREXY) && !defined(DISABLE_MAX_ENDSTOPS) #define DISABLE_MAX_ENDSTOPS @@ -338,6 +354,58 @@ const bool Z_MAX_ENDSTOP_INVERTING = false; // set to true to invert the logic o #define X_MAX_LENGTH (X_MAX_POS - X_MIN_POS) #define Y_MAX_LENGTH (Y_MAX_POS - Y_MIN_POS) #define Z_MAX_LENGTH (Z_MAX_POS - Z_MIN_POS) +//============================= Bed Auto Leveling =========================== + +//#define ENABLE_AUTO_BED_LEVELING // Delete the comment to enable (remove // at the start of the line) + +#ifdef ENABLE_AUTO_BED_LEVELING + + // these are the positions on the bed to do the probing + #define LEFT_PROBE_BED_POSITION 15 + #define RIGHT_PROBE_BED_POSITION 170 + #define BACK_PROBE_BED_POSITION 180 + #define FRONT_PROBE_BED_POSITION 20 + + // these are the offsets to the prob relative to the extruder tip (Hotend - Probe) + #define X_PROBE_OFFSET_FROM_EXTRUDER -25 + #define Y_PROBE_OFFSET_FROM_EXTRUDER -29 + #define Z_PROBE_OFFSET_FROM_EXTRUDER -12.35 + + #define Z_RAISE_BEFORE_HOMING 4 // (in mm) Raise Z before homing (G28) for Probe Clearance. + // Be sure you have this distance over your Z_MAX_POS in case + + #define XY_TRAVEL_SPEED 8000 // X and Y axis travel speed between probes, in mm/min + + #define Z_RAISE_BEFORE_PROBING 15 //How much the extruder will be raised before traveling to the first probing point. + #define Z_RAISE_BETWEEN_PROBINGS 5 //How much the extruder will be raised when traveling from between next probing points + + + //If defined, the Probe servo will be turned on only during movement and then turned off to avoid jerk + //The value is the delay to turn the servo off after powered on - depends on the servo speed; 300ms is good value, but you can try lower it. + // You MUST HAVE the SERVO_ENDSTOPS defined to use here a value higher than zero otherwise your code will not compile. + +// #define PROBE_SERVO_DEACTIVATION_DELAY 300 + + +//If you have enabled the Bed Auto Levelling and are using the same Z Probe for Z Homing, +//it is highly recommended you let this Z_SAFE_HOMING enabled!!! + + #define Z_SAFE_HOMING // This feature is meant to avoid Z homing with probe outside the bed area. + // When defined, it will: + // - Allow Z homing only after X and Y homing AND stepper drivers still enabled + // - If stepper drivers timeout, it will need X and Y homing again before Z homing + // - Position the probe in a defined XY point before Z Homing when homing all axis (G28) + // - Block Z homing only when the probe is outside bed area. + + #ifdef Z_SAFE_HOMING + + #define Z_SAFE_HOMING_X_POINT (X_MAX_LENGTH/2) // X point for Z homing when homing all axis (G28) + #define Z_SAFE_HOMING_Y_POINT (Y_MAX_LENGTH/2) // Y point for Z homing when homing all axis (G28) + + #endif + +#endif + // The position of the homing switches //#define MANUAL_HOME_POSITIONS // If defined, MANUAL_*_HOME_POS below will be used @@ -406,7 +474,8 @@ const bool Z_MAX_ENDSTOP_INVERTING = false; // set to true to invert the logic o //#define DOGLCD // Support for SPI LCD 128x64 (Controller ST7565R graphic Display Family) //#define SDSUPPORT // Enable SD Card Support in Hardware Console //#define SDSLOW // Use slower SD transfer mode (not normally needed - uncomment if you're getting volume init error) - +//#define ENCODER_PULSES_PER_STEP 1 // Increase if you have a high resolution encoder +//#define ENCODER_STEPS_PER_MENU_ITEM 5 // Set according to ENCODER_PULSES_PER_STEP or your liking //#define ULTIMAKERCONTROLLER //as available from the ultimaker online store. //#define ULTIPANEL //the ultipanel as on thingiverse @@ -510,6 +579,17 @@ const bool Z_MAX_ENDSTOP_INVERTING = false; // set to true to invert the logic o #define ULTIPANEL #endif +// Shift register panels +// --------------------- +// 2 wire Non-latching LCD SR from: +// https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/schematics#!shiftregister-connection +//#define SR_LCD +#ifdef SR_LCD + #define SR_LCD_2W_NL // Non latching 2 wire shiftregister + //#define NEWPANEL +#endif + + #ifdef ULTIPANEL // #define NEWPANEL //enable this if you have a click-encoder panel #define SDSUPPORT @@ -543,6 +623,11 @@ const bool Z_MAX_ENDSTOP_INVERTING = false; // set to true to invert the logic o // Increase the FAN pwm frequency. Removes the PWM noise but increases heating in the FET/Arduino //#define FAST_PWM_FAN +// Temperature status leds that display the hotend and bet temperature. +// If alle hotends and bed temperature and temperature setpoint are < 54C then the BLUE led is on. +// Otherwise the RED led is on. There is 1C hysteresis. +//#define TEMP_STAT_LEDS + // Use software PWM to drive the fan, as for the heaters. This uses a very low frequency // which is not ass annoying as with the hardware PWM. On the other hand, if this frequency // is too low, you should also increment SOFT_PWM_SCALE. @@ -564,6 +649,9 @@ const bool Z_MAX_ENDSTOP_INVERTING = false; // set to true to invert the logic o // Support for the BariCUDA Paste Extruder. //#define BARICUDA +//define BlinkM/CyzRgb Support +//#define BLINKM + /*********************************************************************\ * R/C SERVO support * Sponsored by TrinityLabs, Reworked by codexmas diff --git a/Marlin/example_configurations/delta/Configuration_adv.h b/Marlin/example_configurations/delta/Configuration_adv.h index d3c2d1939b..fcf6ff570f 100644 --- a/Marlin/example_configurations/delta/Configuration_adv.h +++ b/Marlin/example_configurations/delta/Configuration_adv.h @@ -40,6 +40,10 @@ #define AUTOTEMP_OLDWEIGHT 0.98 #endif +//Show Temperature ADC value +//The M105 command return, besides traditional information, the ADC value read from temperature sensors. +//#define SHOW_TEMP_ADC_VALUES + // extruder run-out prevention. //if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded //#define EXTRUDER_RUNOUT_PREVENT @@ -146,6 +150,21 @@ #define EXTRUDERS 1 #endif +// Same again but for Y Axis. +//#define Y_DUAL_STEPPER_DRIVERS + +// Define if the two Y drives need to rotate in opposite directions +#define INVERT_Y2_VS_Y_DIR true + +#ifdef Y_DUAL_STEPPER_DRIVERS + #undef EXTRUDERS + #define EXTRUDERS 1 +#endif + +#if defined (Z_DUAL_STEPPER_DRIVERS) && defined (Y_DUAL_STEPPER_DRIVERS) + #error "You cannot have dual drivers for both Y and Z" +#endif + // Enable this for dual x-carriage printers. // A dual x-carriage design has the advantage that the inactive extruder can be parked which // prevents hot-end ooze contaminating the print. It also reduces the weight of each x-carriage @@ -155,8 +174,8 @@ // Configuration for second X-carriage // Note: the first x-carriage is defined as the x-carriage which homes to the minimum endstop; // the second x-carriage always homes to the maximum endstop. -#define X2_MIN_POS 88 // set minimum to ensure second x-carriage doesn't hit the parked first X-carriage -#define X2_MAX_POS 350.45 // set maximum to the distance between toolheads when both heads are homed +#define X2_MIN_POS 80 // set minimum to ensure second x-carriage doesn't hit the parked first X-carriage +#define X2_MAX_POS 353 // set maximum to the distance between toolheads when both heads are homed #define X2_HOME_DIR 1 // the second X-carriage always homes to the maximum endstop position #define X2_HOME_POS X2_MAX_POS // default home position is the maximum carriage position // However: In this mode the EXTRUDER_OFFSET_X value for the second extruder provides a software @@ -169,14 +188,35 @@ #define X2_STEP_PIN 25 #define X2_DIR_PIN 23 -#endif // DUAL_X_CARRIAGE +// There are a few selectable movement modes for dual x-carriages using M605 S +// Mode 0: Full control. The slicer has full control over both x-carriages and can achieve optimal travel results +// as long as it supports dual x-carriages. (M605 S0) +// Mode 1: Auto-park mode. The firmware will automatically park and unpark the x-carriages on tool changes so +// that additional slicer support is not required. (M605 S1) +// Mode 2: Duplication mode. The firmware will transparently make the second x-carriage and extruder copy all +// actions of the first x-carriage. This allows the printer to print 2 arbitrary items at +// once. (2nd extruder x offset and temp offset are set using: M605 S2 [Xnnn] [Rmmm]) + +// This is the default power-up mode which can be later using M605. +#define DEFAULT_DUAL_X_CARRIAGE_MODE 0 + +// As the x-carriages are independent we can now account for any relative Z offset +#define EXTRUDER1_Z_OFFSET 0.0 // z offset relative to extruder 0 + +// Default settings in "Auto-park Mode" +#define TOOLCHANGE_PARK_ZLIFT 0.2 // the distance to raise Z axis when parking an extruder +#define TOOLCHANGE_UNPARK_ZLIFT 1 // the distance to raise Z axis when unparking an extruder + +// Default x offset in duplication mode (typically set to half print bed width) +#define DEFAULT_DUPLICATION_X_OFFSET 100 + +#endif //DUAL_X_CARRIAGE //homing hits the endstop, then retracts by this distance, before it tries to slowly bump again: #define X_HOME_RETRACT_MM 5 -#define Y_HOME_RETRACT_MM 5 +#define Y_HOME_RETRACT_MM 5 #define Z_HOME_RETRACT_MM 5 // deltas need the same for all three axis - //#define QUICK_HOME //if this is defined, if both x and y are to be homed, a diagonal move will be performed initially. #define AXIS_RELATIVE_MODES {false, false, false, false} @@ -238,6 +278,11 @@ #define SD_FINISHED_STEPPERRELEASE true //if sd support and the file is finished: disable steppers? #define SD_FINISHED_RELEASECOMMAND "M84 X Y Z E" // You might want to keep the z enabled so your bed stays in place. +#define SDCARD_RATHERRECENTFIRST //reverse file order of sd card menu display. Its sorted practically after the filesystem block order. +// if a file is deleted, it frees a block. hence, the order is not purely cronological. To still have auto0.g accessible, there is again the option to do that. +// using: +//#define MENU_ADDAUTOSTART + // The hardware watchdog should reset the Microcontroller disabling all outputs, in case the firmware gets stuck and doesn't do temperature regulation. //#define USE_WATCHDOG @@ -251,6 +296,26 @@ // Enable the option to stop SD printing when hitting and endstops, needs to be enabled from the LCD menu when this option is enabled. //#define ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED +// Babystepping enables the user to control the axis in tiny amounts, independently from the normal printing process +// it can e.g. be used to change z-positions in the print startup phase in realtime +// does not respect endstops! +//#define BABYSTEPPING +#ifdef BABYSTEPPING + #define BABYSTEP_XY //not only z, but also XY in the menu. more clutter, more functions + #define BABYSTEP_INVERT_Z false //true for inverse movements in Z + #define BABYSTEP_Z_MULTIPLICATOR 2 //faster z movements + + #ifdef COREXY + #error BABYSTEPPING not implemented for COREXY yet. + #endif + + #ifdef DELTA + #ifdef BABYSTEP_XY + #error BABYSTEPPING only implemented for Z axis on deltabots. + #endif + #endif +#endif + // extruder advance constant (s2/mm3) // // advance (steps) = STEPS_PER_CUBIC_MM_E * EXTUDER_ADVANCE_K * cubic mm per second ^ 2 @@ -302,6 +367,9 @@ const unsigned int dropsegments=5; //everything with less than this number of st #define PS_ON_ASLEEP LOW #endif +// Control heater 0 and heater 1 in parallel. +//#define HEATERS_PARALLEL + //=========================================================================== //=============================Buffers ============================ //=========================================================================== @@ -332,7 +400,7 @@ const unsigned int dropsegments=5; //everything with less than this number of st //adds support for experimental filament exchange support M600; requires display #ifdef ULTIPANEL - //#define FILAMENTCHANGEENABLE + #define FILAMENTCHANGEENABLE #ifdef FILAMENTCHANGEENABLE #define FILAMENTCHANGE_XPOS 3 #define FILAMENTCHANGE_YPOS 3 @@ -341,6 +409,12 @@ const unsigned int dropsegments=5; //everything with less than this number of st #define FILAMENTCHANGE_FINALRETRACT -100 #endif #endif + +#ifdef FILAMENTCHANGEENABLE + #ifdef EXTRUDER_RUNOUT_PREVENT + #error EXTRUDER_RUNOUT_PREVENT currently incompatible with FILAMENTCHANGE + #endif +#endif //=========================================================================== //============================= Define Defines ============================ @@ -349,6 +423,10 @@ const unsigned int dropsegments=5; //everything with less than this number of st #error "You cannot use TEMP_SENSOR_1_AS_REDUNDANT if EXTRUDERS > 1" #endif +#if EXTRUDERS > 1 && defined HEATERS_PARALLEL + #error "You cannot use HEATERS_PARALLEL if EXTRUDERS > 1" +#endif + #if TEMP_SENSOR_0 > 0 #define THERMISTORHEATER_0 TEMP_SENSOR_0 #define HEATER_0_USES_THERMISTOR From ce8b9c4fc525e6b65eb62780f2371d097d3311aa Mon Sep 17 00:00:00 2001 From: Joseivaldo Benito Junior Date: Thu, 19 Dec 2013 00:50:44 -0200 Subject: [PATCH 102/256] Correct missing parameter from last upmerge Signed-off-by: Joseivaldo Benito Junior --- Marlin/example_configurations/delta/Configuration.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Marlin/example_configurations/delta/Configuration.h b/Marlin/example_configurations/delta/Configuration.h index 8d6dd6acfd..0d232d372f 100644 --- a/Marlin/example_configurations/delta/Configuration.h +++ b/Marlin/example_configurations/delta/Configuration.h @@ -102,6 +102,8 @@ // and processor overload (too many expensive sqrt calls). #define DELTA_SEGMENTS_PER_SECOND 200 +// NOTE NB all values for DELTA_* values MOUST be floating point, so always have a decimal point in them + // Center-to-center distance of the holes in the diagonal push rods. #define DELTA_DIAGONAL_ROD 250.0 // mm @@ -117,6 +119,8 @@ // Effective horizontal distance bridged by diagonal push rods. #define DELTA_RADIUS (DELTA_SMOOTH_ROD_OFFSET-DELTA_EFFECTOR_OFFSET-DELTA_CARRIAGE_OFFSET) +#define DELTA_DIAGONAL_ROD_2 sq(DELTA_DIAGONAL_ROD) + // Effective X/Y positions of the three vertical towers. #define SIN_60 0.8660254037844386 #define COS_60 0.5 From 17d6d965dce2cda2ede4ef78a9885a4bf37716c1 Mon Sep 17 00:00:00 2001 From: Phil Wise Date: Thu, 19 Dec 2013 21:21:46 +0000 Subject: [PATCH 103/256] Use C++ initialization list This is the recommended approach for object initialization. The change doesn't affect binary size (although in theory it could make it smaller). --- Marlin/vector_3.cpp | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/Marlin/vector_3.cpp b/Marlin/vector_3.cpp index 8c8a0e1dc7..4538251abf 100644 --- a/Marlin/vector_3.cpp +++ b/Marlin/vector_3.cpp @@ -22,19 +22,9 @@ #ifdef ENABLE_AUTO_BED_LEVELING #include "vector_3.h" -vector_3::vector_3() -{ - this->x = 0; - this->y = 0; - this->z = 0; -} +vector_3::vector_3() : x(0), y(0), z(0) { } -vector_3::vector_3(float x, float y, float z) -{ - this->x = x; - this->y = y; - this->z = z; -} +vector_3::vector_3(float x_, float y_, float z_) : x(x_), y(y_), z(z_) { } vector_3 vector_3::cross(vector_3 left, vector_3 right) { @@ -62,7 +52,7 @@ vector_3 vector_3::get_normal() float vector_3::get_length() { - float length = sqrt((x * x) + (y * y) + (z * z)); + float length = sqrt((x * x) + (y * y) + (z * z)); return length; } From 380144c20faaf495d1967591d03885619bd0baf3 Mon Sep 17 00:00:00 2001 From: daid Date: Mon, 6 Jan 2014 11:05:02 +0100 Subject: [PATCH 104/256] Add Ultiboard2 electronics. With PWM current settings. For the few people that have this new board as experiment in their UM-Original. --- Marlin/Marlin_main.cpp | 9 +++++ Marlin/pins.h | 83 ++++++++++++++++++++++++++++++++++++++++++ Marlin/stepper.cpp | 18 +++++++++ 3 files changed, 110 insertions(+) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 8f006406a9..c3b75516af 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -2778,6 +2778,15 @@ void process_commands() if(code_seen('B')) digipot_current(4,code_value()); if(code_seen('S')) for(int i=0;i<=4;i++) digipot_current(i,code_value()); #endif + #ifdef MOTOR_CURRENT_PWM_XY_PIN + if(code_seen('X')) digipot_current(0, code_value()); + #endif + #ifdef MOTOR_CURRENT_PWM_Z_PIN + if(code_seen('Z')) digipot_current(1, code_value()); + #endif + #ifdef MOTOR_CURRENT_PWM_E_PIN + if(code_seen('E')) digipot_current(2, code_value()); + #endif } break; case 908: // M908 Control digital trimpot directly. diff --git a/Marlin/pins.h b/Marlin/pins.h index b7cbac4fd7..ac76f43471 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -1295,6 +1295,89 @@ #endif +#if MOTHERBOARD == 72 +#define KNOWN_BOARD +/***************************************************************** +* Ultiboard v2.0 pin assignment +******************************************************************/ + +#ifndef __AVR_ATmega2560__ + #error Oops! Make sure you have 'Arduino Mega 2560' selected from the 'Tools -> Boards' menu. +#endif + +#define X_STEP_PIN 25 +#define X_DIR_PIN 23 +#define X_STOP_PIN 22 +#define X_ENABLE_PIN 27 + +#define Y_STEP_PIN 32 +#define Y_DIR_PIN 33 +#define Y_STOP_PIN 26 +#define Y_ENABLE_PIN 31 + +#define Z_STEP_PIN 35 +#define Z_DIR_PIN 36 +#define Z_STOP_PIN 29 +#define Z_ENABLE_PIN 34 + +#define HEATER_BED_PIN 4 +#define TEMP_BED_PIN 10 + +#define HEATER_0_PIN 2 +#define TEMP_0_PIN 8 + +#define HEATER_1_PIN 3 +#define TEMP_1_PIN 9 + +#define HEATER_2_PIN -1 +#define TEMP_2_PIN -1 + +#define E0_STEP_PIN 42 +#define E0_DIR_PIN 43 +#define E0_ENABLE_PIN 37 + +#define E1_STEP_PIN 49 +#define E1_DIR_PIN 47 +#define E1_ENABLE_PIN 48 + +#define SDPOWER -1 +#define SDSS 53 +#define LED_PIN 8 +#define FAN_PIN 7 +#define PS_ON_PIN 12 +#define KILL_PIN -1 +#define SUICIDE_PIN -1 //PIN that has to be turned on right after start, to keep power flowing. +#define SAFETY_TRIGGERED_PIN 28 //PIN to detect the safety circuit has triggered +#define MAIN_VOLTAGE_MEASURE_PIN 14 //Analogue PIN to measure the main voltage, with a 100k - 4k7 resitor divider. + +#define MOTOR_CURRENT_PWM_XY_PIN 44 +#define MOTOR_CURRENT_PWM_Z_PIN 45 +#define MOTOR_CURRENT_PWM_E_PIN 46 +//Motor current PWM conversion, PWM value = MotorCurrentSetting * 255 / range +#define MOTOR_CURRENT_PWM_RANGE 2000 + +//arduino pin witch triggers an piezzo beeper +#define BEEPER 18 + +#define LCD_PINS_RS 20 +#define LCD_PINS_ENABLE 15 +#define LCD_PINS_D4 14 +#define LCD_PINS_D5 21 +#define LCD_PINS_D6 5 +#define LCD_PINS_D7 6 + +//buttons are directly attached +#define BTN_EN1 40 +#define BTN_EN2 41 +#define BTN_ENC 19 //the click + +#define BLEN_C 2 +#define BLEN_B 1 +#define BLEN_A 0 + +#define SDCARDDETECT 39 + +#endif//MOTHERBOARD == 72 /**************************************************************************************** * RUMBA pin assignment diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index f45ef7d405..eaba4362dc 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -72,6 +72,9 @@ static volatile bool endstop_z_hit=false; #ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED bool abort_on_endstop_hit = false; #endif +#ifdef MOTOR_CURRENT_PWM_XY_PIN + int motor_current_setting[3] = DEFAULT_PWM_MOTOR_CURRENT; +#endif static bool old_x_min_endstop=false; static bool old_x_max_endstop=false; @@ -1198,6 +1201,16 @@ void digipot_init() //Initialize Digipot Motor Current //digitalPotWrite(digipot_ch[i], digipot_motor_current[i]); digipot_current(i,digipot_motor_current[i]); #endif + #ifdef MOTOR_CURRENT_PWM_XY_PIN + pinMode(MOTOR_CURRENT_PWM_XY_PIN, OUTPUT); + pinMode(MOTOR_CURRENT_PWM_Z_PIN, OUTPUT); + pinMode(MOTOR_CURRENT_PWM_E_PIN, OUTPUT); + digipot_current(0, motor_current_setting[0]); + digipot_current(1, motor_current_setting[1]); + digipot_current(2, motor_current_setting[2]); + //Set timer5 to 31khz so the PWM of the motor power is as constant as possible. (removes a buzzing noise) + TCCR5B = (TCCR5B & ~(_BV(CS50) | _BV(CS51) | _BV(CS52))) | _BV(CS50); + #endif } void digipot_current(uint8_t driver, int current) @@ -1206,6 +1219,11 @@ void digipot_current(uint8_t driver, int current) const uint8_t digipot_ch[] = DIGIPOT_CHANNELS; digitalPotWrite(digipot_ch[driver], current); #endif + #ifdef MOTOR_CURRENT_PWM_XY_PIN + if (driver == 0) analogWrite(MOTOR_CURRENT_PWM_XY_PIN, (long)current * 255L / (long)MOTOR_CURRENT_PWM_RANGE); + if (driver == 1) analogWrite(MOTOR_CURRENT_PWM_Z_PIN, (long)current * 255L / (long)MOTOR_CURRENT_PWM_RANGE); + if (driver == 2) analogWrite(MOTOR_CURRENT_PWM_E_PIN, (long)current * 255L / (long)MOTOR_CURRENT_PWM_RANGE); + #endif } void microstep_init() From df194f75e1e4377d047e838edbc2dbfc08853c5e Mon Sep 17 00:00:00 2001 From: daid Date: Mon, 6 Jan 2014 11:20:03 +0100 Subject: [PATCH 105/256] Added PT100 support for Ultiboard2 --- Marlin/language.h | 2 +- Marlin/pins.h | 3 +- Marlin/temperature.cpp | 5 ++- Marlin/thermistortables.h | 72 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 3 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index 48cd4118a0..d1527d5e9d 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -23,7 +23,7 @@ #define PROTOCOL_VERSION "1.0" -#if MOTHERBOARD == 7 || MOTHERBOARD == 71 +#if MOTHERBOARD == 7 || MOTHERBOARD == 71 || MOTHERBOARD == 72 #define MACHINE_NAME "Ultimaker" #define FIRMWARE_URL "http://firmware.ultimaker.com" #elif MOTHERBOARD == 80 diff --git a/Marlin/pins.h b/Marlin/pins.h index ac76f43471..d896bca2eb 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -1354,7 +1354,8 @@ #define MOTOR_CURRENT_PWM_Z_PIN 45 #define MOTOR_CURRENT_PWM_E_PIN 46 //Motor current PWM conversion, PWM value = MotorCurrentSetting * 255 / range -#define MOTOR_CURRENT_PWM_RANGE 2000 +#define MOTOR_CURRENT_PWM_RANGE 2000 +#define DEFAULT_PWM_MOTOR_CURRENT {1300, 1300, 1250} //arduino pin witch triggers an piezzo beeper #define BEEPER 18 diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index 29050b84f5..308ac5efc8 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -1039,7 +1039,7 @@ ISR(TIMER0_COMPB_vect) static unsigned long raw_temp_1_value = 0; static unsigned long raw_temp_2_value = 0; static unsigned long raw_temp_bed_value = 0; - static unsigned char temp_state = 0; + static unsigned char temp_state = 8; static unsigned char pwm_count = (1 << SOFT_PWM_SCALE); static unsigned char soft_pwm_0; #if (EXTRUDERS > 1) || defined(HEATERS_PARALLEL) @@ -1181,6 +1181,9 @@ ISR(TIMER0_COMPB_vect) temp_state = 0; temp_count++; break; + case 8: //Startup, delay initial temp reading a tiny bit so the hardware can settle. + temp_state = 0; + break; // default: // SERIAL_ERROR_START; // SERIAL_ERRORLNPGM("Temp measurement error!"); diff --git a/Marlin/thermistortables.h b/Marlin/thermistortables.h index ecac95fe30..58a2466fee 100644 --- a/Marlin/thermistortables.h +++ b/Marlin/thermistortables.h @@ -563,6 +563,78 @@ const short temptable_10[][2] PROGMEM = { {1016*OVERSAMPLENR, 0} }; #endif + +#if (THERMISTORHEATER_0 == 20) || (THERMISTORHEATER_1 == 20) || (THERMISTORHEATER_2 == 20) || (THERMISTORBED == 20) // PT100 with INA826 amp on Ultimaker v2.0 electronics +/* The PT100 in the Ultimaker v2.0 electronics has a high sample value for a high temperature. +This does not match the normal thermistor behaviour so we need to set the following defines */ +#if (THERMISTORHEATER_0 == 20) +# define HEATER_0_RAW_HI_TEMP 16383 +# define HEATER_0_RAW_LO_TEMP 0 +#endif +#if (THERMISTORHEATER_1 == 20) +# define HEATER_1_RAW_HI_TEMP 16383 +# define HEATER_1_RAW_LO_TEMP 0 +#endif +#if (THERMISTORHEATER_2 == 20) +# define HEATER_2_RAW_HI_TEMP 16383 +# define HEATER_2_RAW_LO_TEMP 0 +#endif +#if (THERMISTORBED == 20) +# define HEATER_BED_RAW_HI_TEMP 16383 +# define HEATER_BED_RAW_LO_TEMP 0 +#endif +const short temptable_20[][2] PROGMEM = { +{ 0*OVERSAMPLENR , 0 }, +{ 227*OVERSAMPLENR , 1 }, +{ 236*OVERSAMPLENR , 10 }, +{ 245*OVERSAMPLENR , 20 }, +{ 253*OVERSAMPLENR , 30 }, +{ 262*OVERSAMPLENR , 40 }, +{ 270*OVERSAMPLENR , 50 }, +{ 279*OVERSAMPLENR , 60 }, +{ 287*OVERSAMPLENR , 70 }, +{ 295*OVERSAMPLENR , 80 }, +{ 304*OVERSAMPLENR , 90 }, +{ 312*OVERSAMPLENR , 100 }, +{ 320*OVERSAMPLENR , 110 }, +{ 329*OVERSAMPLENR , 120 }, +{ 337*OVERSAMPLENR , 130 }, +{ 345*OVERSAMPLENR , 140 }, +{ 353*OVERSAMPLENR , 150 }, +{ 361*OVERSAMPLENR , 160 }, +{ 369*OVERSAMPLENR , 170 }, +{ 377*OVERSAMPLENR , 180 }, +{ 385*OVERSAMPLENR , 190 }, +{ 393*OVERSAMPLENR , 200 }, +{ 401*OVERSAMPLENR , 210 }, +{ 409*OVERSAMPLENR , 220 }, +{ 417*OVERSAMPLENR , 230 }, +{ 424*OVERSAMPLENR , 240 }, +{ 432*OVERSAMPLENR , 250 }, +{ 440*OVERSAMPLENR , 260 }, +{ 447*OVERSAMPLENR , 270 }, +{ 455*OVERSAMPLENR , 280 }, +{ 463*OVERSAMPLENR , 290 }, +{ 470*OVERSAMPLENR , 300 }, +{ 478*OVERSAMPLENR , 310 }, +{ 485*OVERSAMPLENR , 320 }, +{ 493*OVERSAMPLENR , 330 }, +{ 500*OVERSAMPLENR , 340 }, +{ 507*OVERSAMPLENR , 350 }, +{ 515*OVERSAMPLENR , 360 }, +{ 522*OVERSAMPLENR , 370 }, +{ 529*OVERSAMPLENR , 380 }, +{ 537*OVERSAMPLENR , 390 }, +{ 544*OVERSAMPLENR , 400 }, +{ 614*OVERSAMPLENR , 500 }, +{ 681*OVERSAMPLENR , 600 }, +{ 744*OVERSAMPLENR , 700 }, +{ 805*OVERSAMPLENR , 800 }, +{ 862*OVERSAMPLENR , 900 }, +{ 917*OVERSAMPLENR , 1000 }, +{ 968*OVERSAMPLENR , 1100 } +}; +#endif #if (THERMISTORHEATER_0 == 51) || (THERMISTORHEATER_1 == 51) || (THERMISTORHEATER_2 == 51) || (THERMISTORBED == 51) // 100k EPCOS (WITH 1kohm RESISTOR FOR PULLUP, R9 ON SANGUINOLOLU! NOT FOR 4.7kohm PULLUP! THIS IS NOT NORMAL!) From 75f39fadfc2ae925ce6e1b0ac3fba56b05f2e3c9 Mon Sep 17 00:00:00 2001 From: David Forrest Date: Thu, 16 Jan 2014 10:58:35 -0500 Subject: [PATCH 106/256] Makefile: Update for Arduino 1.0.5 and Teensyduino dependent boards (HARDWARE_MOTHERBOARD=={8,81,82,83,84}) --- Marlin/Makefile | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Marlin/Makefile b/Marlin/Makefile index 59ec4d4f7e..29a5578211 100644 --- a/Marlin/Makefile +++ b/Marlin/Makefile @@ -14,7 +14,7 @@ # # 1. Modify the line containg "ARDUINO_INSTALL_DIR" to point to the directory that # contains the Arduino installation (for example, under Mac OS X, this -# might be /Applications/arduino-0012). +# might be /Applications/Arduino.app/Contents/Resources/Java). # # 2. Modify the line containing "UPLOAD_PORT" to refer to the filename # representing the USB or serial connection to your Arduino board @@ -40,8 +40,8 @@ HARDWARE_MOTHERBOARD ?= 11 # Arduino source install directory, and version number -ARDUINO_INSTALL_DIR ?= ../../arduino-0022 -ARDUINO_VERSION ?= 22 +ARDUINO_INSTALL_DIR ?= /Applications/Arduino.app/Contents/Resources/Java +ARDUINO_VERSION ?= 105 # You can optionally set a path to the avr-gcc tools. Requires a trailing slash. (ex: /usr/local/avr-gcc/bin) AVR_TOOLS_PATH ?= @@ -142,6 +142,12 @@ MCU ?= at90usb1286 else ifeq ($(HARDWARE_MOTHERBOARD),82) HARDWARE_VARIANT ?= Teensy MCU ?= at90usb646 +else ifeq ($(HARDWARE_MOTHERBOARD),83) +HARDWARE_VARIANT ?= Teensy +MCU ?= at90usb1286 +else ifeq ($(HARDWARE_MOTHERBOARD),84) +HARDWARE_VARIANT ?= Teensy +MCU ?= at90usb1286 #Gen3+ else ifeq ($(HARDWARE_MOTHERBOARD),9) @@ -227,6 +233,10 @@ SRC = wiring.c \ wiring_analog.c wiring_digital.c \ wiring_pulse.c \ wiring_shift.c WInterrupts.c +ifeq ($(HARDWARE_VARIANT), Teensy) +SRC = wiring.c +VPATH += $(ARDUINO_INSTALL_DIR)/hardware/teensy/cores/teensy +endif CXXSRC = WMath.cpp WString.cpp Print.cpp Marlin_main.cpp \ MarlinSerial.cpp Sd2Card.cpp SdBaseFile.cpp SdFatUtil.cpp \ SdFile.cpp SdVolume.cpp motion_control.cpp planner.cpp \ From e8e0697e4897f3542fb7894d2df5c275602ab88a Mon Sep 17 00:00:00 2001 From: David Forrest Date: Thu, 16 Jan 2014 11:23:29 -0500 Subject: [PATCH 107/256] fastio.h: Add AT90USBxx_TEENSYPP_ASSIGNMENTS for teensyduino/Lincomatic/Printrboard compatibility. --- Marlin/fastio.h | 652 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 651 insertions(+), 1 deletion(-) diff --git a/Marlin/fastio.h b/Marlin/fastio.h index f26a9f845f..a969d56ab9 100644 --- a/Marlin/fastio.h +++ b/Marlin/fastio.h @@ -2035,6 +2035,10 @@ pins /* pins */ + +//#define AT90USBxx_TEENSYPP_ASSIGNMENTS // Use Teensy++ 2.0 assignments +#ifndef AT90USBxx_TEENSYPP_ASSIGNMENTS // Use traditional Marlin pin assignments + #define DIO0_PIN PINA0 #define DIO0_RPORT PINA #define DIO0_WPORT PORTA @@ -2667,7 +2671,653 @@ pins #define PF7_WPORT PORTF #define PF7_PWM NULL #define PF7_DDR DDRF -#endif + +#else // AT90USBxx_TEENSYPP_ASSIGNMENTS -- Use Teensyduino Teensy++2.0 assignments. + +/* + +AT90USB 51 50 49 48 47 46 45 44 10 11 12 13 14 15 16 17 35 36 37 38 39 40 41 42 25 26 27 28 29 30 31 32 33 34 43 09 18 19 01 02 61 60 59 58 57 56 55 54 +Port A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 B2 B3 B4 B5 B6 B7 C0 C1 C2 C3 C4 C5 C6 C7 D0 D1 D2 D3 D4 D5 D6 D7 E0 E1 E2 E3 E4 E5 E6 E7 F0 F1 F2 F3 F4 F5 F6 F7 +Marlin 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 +Teensy 28 29 30 31 32 33 34 35 20 21 22 23 24 25 26 27 10 11 12 13 14 15 16 17 00 01 02 03 04 05 06 07 08 09(46*47)36 37 18 19 38 39 40 41 42 43 44 45 + The pins 46 and 47 are not supported by Teensyduino, but are supported below. +*/ + +#define DIO0_PIN PIND0 +#define DIO0_RPORT PIND +#define DIO0_WPORT PORTD +#define DIO0_PWM NULL +#define DIO0_DDR DDRD + +#define DIO1_PIN PIND1 +#define DIO1_RPORT PIND +#define DIO1_WPORT PORTD +#define DIO1_PWM NULL +#define DIO1_DDR DDRD + +#define DIO2_PIN PIND2 +#define DIO2_RPORT PIND +#define DIO2_WPORT PORTD +#define DIO2_PWM NULL +#define DIO2_DDR DDRD + +#define DIO3_PIN PIND3 +#define DIO3_RPORT PIND +#define DIO3_WPORT PORTD +#define DIO3_PWM NULL +#define DIO3_DDR DDRD + +#define DIO4_PIN PIND4 +#define DIO4_RPORT PIND +#define DIO4_WPORT PORTD +#define DIO4_PWM NULL +#define DIO4_DDR DDRD + +#define DIO5_PIN PIND5 +#define DIO5_RPORT PIND +#define DIO5_WPORT PORTD +#define DIO5_PWM NULL +#define DIO5_DDR DDRD + +#define DIO6_PIN PIND6 +#define DIO6_RPORT PIND +#define DIO6_WPORT PORTD +#define DIO6_PWM NULL +#define DIO6_DDR DDRD + +#define DIO7_PIN PIND7 +#define DIO7_RPORT PIND +#define DIO7_WPORT PORTD +#define DIO7_PWM NULL +#define DIO7_DDR DDRD + +#define DIO8_PIN PINE0 +#define DIO8_RPORT PINE +#define DIO8_WPORT PORTE +#define DIO8_PWM NULL +#define DIO8_DDR DDRE + +#define DIO9_PIN PINE1 +#define DIO9_RPORT PINE +#define DIO9_WPORT PORTE +#define DIO9_PWM NULL +#define DIO9_DDR DDRE + +#define DIO10_PIN PINC0 +#define DIO10_RPORT PINC +#define DIO10_WPORT PORTC +#define DIO10_PWM NULL +#define DIO10_DDR DDRC + +#define DIO11_PIN PINC1 +#define DIO11_RPORT PINC +#define DIO11_WPORT PORTC +#define DIO11_PWM NULL +#define DIO11_DDR DDRC + +#define DIO12_PIN PINC2 +#define DIO12_RPORT PINC +#define DIO12_WPORT PORTC +#define DIO12_PWM NULL +#define DIO12_DDR DDRC + +#define DIO13_PIN PINC3 +#define DIO13_RPORT PINC +#define DIO13_WPORT PORTC +#define DIO13_PWM NULL +#define DIO13_DDR DDRC + +#define DIO14_PIN PINC4 +#define DIO14_RPORT PINC +#define DIO14_WPORT PORTC +#define DIO14_PWM NULL +#define DIO14_DDR DDRC + +#define DIO15_PIN PINC5 +#define DIO15_RPORT PINC +#define DIO15_WPORT PORTC +#define DIO15_PWM NULL +#define DIO15_DDR DDRC + +#define DIO16_PIN PINC6 +#define DIO16_RPORT PINC +#define DIO16_WPORT PORTC +#define DIO16_PWM NULL +#define DIO16_DDR DDRC + +#define DIO17_PIN PINC7 +#define DIO17_RPORT PINC +#define DIO17_WPORT PORTC +#define DIO17_PWM NULL +#define DIO17_DDR DDRC + +#define DIO18_PIN PINE6 +#define DIO18_RPORT PINE +#define DIO18_WPORT PORTE +#define DIO18_PWM NULL +#define DIO18_DDR DDRE + +#define DIO19_PIN PINE7 +#define DIO19_RPORT PINE +#define DIO19_WPORT PORTE +#define DIO19_PWM NULL +#define DIO19_DDR DDRE + +#define DIO20_PIN PINB0 +#define DIO20_RPORT PINB +#define DIO20_WPORT PORTB +#define DIO20_PWM NULL +#define DIO20_DDR DDRB + +#define DIO21_PIN PINB1 +#define DIO21_RPORT PINB +#define DIO21_WPORT PORTB +#define DIO21_PWM NULL +#define DIO21_DDR DDRB + +#define DIO22_PIN PINB2 +#define DIO22_RPORT PINB +#define DIO22_WPORT PORTB +#define DIO22_PWM NULL +#define DIO22_DDR DDRB + +#define DIO23_PIN PINB3 +#define DIO23_RPORT PINB +#define DIO23_WPORT PORTB +#define DIO23_PWM NULL +#define DIO23_DDR DDRB + +#define DIO24_PIN PINB4 +#define DIO24_RPORT PINB +#define DIO24_WPORT PORTB +#define DIO24_PWM NULL +#define DIO24_DDR DDRB + +#define DIO25_PIN PINB5 +#define DIO25_RPORT PINB +#define DIO25_WPORT PORTB +#define DIO25_PWM NULL +#define DIO25_DDR DDRB + +#define DIO26_PIN PINB6 +#define DIO26_RPORT PINB +#define DIO26_WPORT PORTB +#define DIO26_PWM NULL +#define DIO26_DDR DDRB + +#define DIO27_PIN PINB7 +#define DIO27_RPORT PINB +#define DIO27_WPORT PORTB +#define DIO27_PWM NULL +#define DIO27_DDR DDRB + +#define DIO28_PIN PINA0 +#define DIO28_RPORT PINA +#define DIO28_WPORT PORTA +#define DIO28_PWM NULL +#define DIO28_DDR DDRA + +#define DIO29_PIN PINA1 +#define DIO29_RPORT PINA +#define DIO29_WPORT PORTA +#define DIO29_PWM NULL +#define DIO29_DDR DDRA + +#define DIO30_PIN PINA2 +#define DIO30_RPORT PINA +#define DIO30_WPORT PORTA +#define DIO30_PWM NULL +#define DIO30_DDR DDRA + +#define DIO31_PIN PINA3 +#define DIO31_RPORT PINA +#define DIO31_WPORT PORTA +#define DIO31_PWM NULL +#define DIO31_DDR DDRA + +#define DIO32_PIN PINA4 +#define DIO32_RPORT PINA +#define DIO32_WPORT PORTA +#define DIO32_PWM NULL +#define DIO32_DDR DDRA + +#define DIO33_PIN PINA5 +#define DIO33_RPORT PINA +#define DIO33_WPORT PORTA +#define DIO33_PWM NULL +#define DIO33_DDR DDRA + +#define DIO34_PIN PINA6 +#define DIO34_RPORT PINA +#define DIO34_WPORT PORTA +#define DIO34_PWM NULL +#define DIO34_DDR DDRA + +#define DIO35_PIN PINA7 +#define DIO35_RPORT PINA +#define DIO35_WPORT PORTA +#define DIO35_PWM NULL +#define DIO35_DDR DDRA + +#define DIO36_PIN PINE4 +#define DIO36_RPORT PINE +#define DIO36_WPORT PORTE +#define DIO36_PWM NULL +#define DIO36_DDR DDRE + +#define DIO37_PIN PINE5 +#define DIO37_RPORT PINE +#define DIO37_WPORT PORTE +#define DIO37_PWM NULL +#define DIO37_DDR DDRE + +#define DIO38_PIN PINF0 +#define DIO38_RPORT PINF +#define DIO38_WPORT PORTF +#define DIO38_PWM NULL +#define DIO38_DDR DDRF + +#define DIO39_PIN PINF1 +#define DIO39_RPORT PINF +#define DIO39_WPORT PORTF +#define DIO39_PWM NULL +#define DIO39_DDR DDRF + +#define DIO40_PIN PINF2 +#define DIO40_RPORT PINF +#define DIO40_WPORT PORTF +#define DIO40_PWM NULL +#define DIO40_DDR DDRF + +#define DIO41_PIN PINF3 +#define DIO41_RPORT PINF +#define DIO41_WPORT PORTF +#define DIO41_PWM NULL +#define DIO41_DDR DDRF + +#define DIO42_PIN PINF4 +#define DIO42_RPORT PINF +#define DIO42_WPORT PORTF +#define DIO42_PWM NULL +#define DIO42_DDR DDRF + +#define DIO43_PIN PINF5 +#define DIO43_RPORT PINF +#define DIO43_WPORT PORTF +#define DIO43_PWM NULL +#define DIO43_DDR DDRF + +#define DIO44_PIN PINF6 +#define DIO44_RPORT PINF +#define DIO44_WPORT PORTF +#define DIO44_PWM NULL +#define DIO44_DDR DDRF + +#define DIO45_PIN PINF7 +#define DIO45_RPORT PINF +#define DIO45_WPORT PORTF +#define DIO45_PWM NULL +#define DIO45_DDR DDRF + +#define AIO0_PIN PINF0 +#define AIO0_RPORT PINF +#define AIO0_WPORT PORTF +#define AIO0_PWM NULL +#define AIO0_DDR DDRF + +#define AIO1_PIN PINF1 +#define AIO1_RPORT PINF +#define AIO1_WPORT PORTF +#define AIO1_PWM NULL +#define AIO1_DDR DDRF + +#define AIO2_PIN PINF2 +#define AIO2_RPORT PINF +#define AIO2_WPORT PORTF +#define AIO2_PWM NULL +#define AIO2_DDR DDRF + +#define AIO3_PIN PINF3 +#define AIO3_RPORT PINF +#define AIO3_WPORT PORTF +#define AIO3_PWM NULL +#define AIO3_DDR DDRF + +#define AIO4_PIN PINF4 +#define AIO4_RPORT PINF +#define AIO4_WPORT PORTF +#define AIO4_PWM NULL +#define AIO4_DDR DDRF + +#define AIO5_PIN PINF5 +#define AIO5_RPORT PINF +#define AIO5_WPORT PORTF +#define AIO5_PWM NULL +#define AIO5_DDR DDRF + +#define AIO6_PIN PINF6 +#define AIO6_RPORT PINF +#define AIO6_WPORT PORTF +#define AIO6_PWM NULL +#define AIO6_DDR DDRF + +#define AIO7_PIN PINF7 +#define AIO7_RPORT PINF +#define AIO7_WPORT PORTF +#define AIO7_PWM NULL +#define AIO7_DDR DDRF + +//-- Begin not supported by Teensyduino +//-- don't use Arduino functions on these pins pinMode/digitalWrite/etc +#define DIO46_PIN PINE2 +#define DIO46_RPORT PINE +#define DIO46_WPORT PORTE +#define DIO46_PWM NULL +#define DIO46_DDR DDRE + +#define DIO47_PIN PINE3 +#define DIO47_RPORT PINE +#define DIO47_WPORT PORTE +#define DIO47_PWM NULL +#define DIO47_DDR DDRE +//-- end not supported by Teensyduino + +#undef PA0 +#define PA0_PIN PINA0 +#define PA0_RPORT PINA +#define PA0_WPORT PORTA +#define PA0_PWM NULL +#define PA0_DDR DDRA +#undef PA1 +#define PA1_PIN PINA1 +#define PA1_RPORT PINA +#define PA1_WPORT PORTA +#define PA1_PWM NULL +#define PA1_DDR DDRA +#undef PA2 +#define PA2_PIN PINA2 +#define PA2_RPORT PINA +#define PA2_WPORT PORTA +#define PA2_PWM NULL +#define PA2_DDR DDRA +#undef PA3 +#define PA3_PIN PINA3 +#define PA3_RPORT PINA +#define PA3_WPORT PORTA +#define PA3_PWM NULL +#define PA3_DDR DDRA +#undef PA4 +#define PA4_PIN PINA4 +#define PA4_RPORT PINA +#define PA4_WPORT PORTA +#define PA4_PWM NULL +#define PA4_DDR DDRA +#undef PA5 +#define PA5_PIN PINA5 +#define PA5_RPORT PINA +#define PA5_WPORT PORTA +#define PA5_PWM NULL +#define PA5_DDR DDRA +#undef PA6 +#define PA6_PIN PINA6 +#define PA6_RPORT PINA +#define PA6_WPORT PORTA +#define PA6_PWM NULL +#define PA6_DDR DDRA +#undef PA7 +#define PA7_PIN PINA7 +#define PA7_RPORT PINA +#define PA7_WPORT PORTA +#define PA7_PWM NULL +#define PA7_DDR DDRA + +#undef PB0 +#define PB0_PIN PINB0 +#define PB0_RPORT PINB +#define PB0_WPORT PORTB +#define PB0_PWM NULL +#define PB0_DDR DDRB +#undef PB1 +#define PB1_PIN PINB1 +#define PB1_RPORT PINB +#define PB1_WPORT PORTB +#define PB1_PWM NULL +#define PB1_DDR DDRB +#undef PB2 +#define PB2_PIN PINB2 +#define PB2_RPORT PINB +#define PB2_WPORT PORTB +#define PB2_PWM NULL +#define PB2_DDR DDRB +#undef PB3 +#define PB3_PIN PINB3 +#define PB3_RPORT PINB +#define PB3_WPORT PORTB +#define PB3_PWM NULL +#define PB3_DDR DDRB +#undef PB4 +#define PB4_PIN PINB4 +#define PB4_RPORT PINB +#define PB4_WPORT PORTB +#define PB4_PWM NULL +#define PB4_DDR DDRB +#undef PB5 +#define PB5_PIN PINB5 +#define PB5_RPORT PINB +#define PB5_WPORT PORTB +#define PB5_PWM NULL +#define PB5_DDR DDRB +#undef PB6 +#define PB6_PIN PINB6 +#define PB6_RPORT PINB +#define PB6_WPORT PORTB +#define PB6_PWM NULL +#define PB6_DDR DDRB +#undef PB7 +#define PB7_PIN PINB7 +#define PB7_RPORT PINB +#define PB7_WPORT PORTB +#define PB7_PWM NULL +#define PB7_DDR DDRB + +#undef PC0 +#define PC0_PIN PINC0 +#define PC0_RPORT PINC +#define PC0_WPORT PORTC +#define PC0_PWM NULL +#define PC0_DDR DDRC +#undef PC1 +#define PC1_PIN PINC1 +#define PC1_RPORT PINC +#define PC1_WPORT PORTC +#define PC1_PWM NULL +#define PC1_DDR DDRC +#undef PC2 +#define PC2_PIN PINC2 +#define PC2_RPORT PINC +#define PC2_WPORT PORTC +#define PC2_PWM NULL +#define PC2_DDR DDRC +#undef PC3 +#define PC3_PIN PINC3 +#define PC3_RPORT PINC +#define PC3_WPORT PORTC +#define PC3_PWM NULL +#define PC3_DDR DDRC +#undef PC4 +#define PC4_PIN PINC4 +#define PC4_RPORT PINC +#define PC4_WPORT PORTC +#define PC4_PWM NULL +#define PC4_DDR DDRC +#undef PC5 +#define PC5_PIN PINC5 +#define PC5_RPORT PINC +#define PC5_WPORT PORTC +#define PC5_PWM NULL +#define PC5_DDR DDRC +#undef PC6 +#define PC6_PIN PINC6 +#define PC6_RPORT PINC +#define PC6_WPORT PORTC +#define PC6_PWM NULL +#define PC6_DDR DDRC +#undef PC7 +#define PC7_PIN PINC7 +#define PC7_RPORT PINC +#define PC7_WPORT PORTC +#define PC7_PWM NULL +#define PC7_DDR DDRC + +#undef PD0 +#define PD0_PIN PIND0 +#define PD0_RPORT PIND +#define PD0_WPORT PORTD +#define PD0_PWM NULL +#define PD0_DDR DDRD +#undef PD1 +#define PD1_PIN PIND1 +#define PD1_RPORT PIND +#define PD1_WPORT PORTD +#define PD1_PWM NULL +#define PD1_DDR DDRD +#undef PD2 +#define PD2_PIN PIND2 +#define PD2_RPORT PIND +#define PD2_WPORT PORTD +#define PD2_PWM NULL +#define PD2_DDR DDRD +#undef PD3 +#define PD3_PIN PIND3 +#define PD3_RPORT PIND +#define PD3_WPORT PORTD +#define PD3_PWM NULL +#define PD3_DDR DDRD +#undef PD4 +#define PD4_PIN PIND4 +#define PD4_RPORT PIND +#define PD4_WPORT PORTD +#define PD4_PWM NULL +#define PD4_DDR DDRD +#undef PD5 +#define PD5_PIN PIND5 +#define PD5_RPORT PIND +#define PD5_WPORT PORTD +#define PD5_PWM NULL +#define PD5_DDR DDRD +#undef PD6 +#define PD6_PIN PIND6 +#define PD6_RPORT PIND +#define PD6_WPORT PORTD +#define PD6_PWM NULL +#define PD6_DDR DDRD +#undef PD7 +#define PD7_PIN PIND7 +#define PD7_RPORT PIND +#define PD7_WPORT PORTD +#define PD7_PWM NULL +#define PD7_DDR DDRD + +#undef PE0 +#define PE0_PIN PINE0 +#define PE0_RPORT PINE +#define PE0_WPORT PORTE +#define PE0_PWM NULL +#define PE0_DDR DDRE +#undef PE1 +#define PE1_PIN PINE1 +#define PE1_RPORT PINE +#define PE1_WPORT PORTE +#define PE1_PWM NULL +#define PE1_DDR DDRE +#undef PE2 +#define PE2_PIN PINE2 +#define PE2_RPORT PINE +#define PE2_WPORT PORTE +#define PE2_PWM NULL +#define PE2_DDR DDRE +#undef PE3 +#define PE3_PIN PINE3 +#define PE3_RPORT PINE +#define PE3_WPORT PORTE +#define PE3_PWM NULL +#define PE3_DDR DDRE +#undef PE4 +#define PE4_PIN PINE4 +#define PE4_RPORT PINE +#define PE4_WPORT PORTE +#define PE4_PWM NULL +#define PE4_DDR DDRE +#undef PE5 +#define PE5_PIN PINE5 +#define PE5_RPORT PINE +#define PE5_WPORT PORTE +#define PE5_PWM NULL +#define PE5_DDR DDRE +#undef PE6 +#define PE6_PIN PINE6 +#define PE6_RPORT PINE +#define PE6_WPORT PORTE +#define PE6_PWM NULL +#define PE6_DDR DDRE +#undef PE7 +#define PE7_PIN PINE7 +#define PE7_RPORT PINE +#define PE7_WPORT PORTE +#define PE7_PWM NULL +#define PE7_DDR DDRE + +#undef PF0 +#define PF0_PIN PINF0 +#define PF0_RPORT PINF +#define PF0_WPORT PORTF +#define PF0_PWM NULL +#define PF0_DDR DDRF +#undef PF1 +#define PF1_PIN PINF1 +#define PF1_RPORT PINF +#define PF1_WPORT PORTF +#define PF1_PWM NULL +#define PF1_DDR DDRF +#undef PF2 +#define PF2_PIN PINF2 +#define PF2_RPORT PINF +#define PF2_WPORT PORTF +#define PF2_PWM NULL +#define PF2_DDR DDRF +#undef PF3 +#define PF3_PIN PINF3 +#define PF3_RPORT PINF +#define PF3_WPORT PORTF +#define PF3_PWM NULL +#define PF3_DDR DDRF +#undef PF4 +#define PF4_PIN PINF4 +#define PF4_RPORT PINF +#define PF4_WPORT PORTF +#define PF4_PWM NULL +#define PF4_DDR DDRF +#undef PF5 +#define PF5_PIN PINF5 +#define PF5_RPORT PINF +#define PF5_WPORT PORTF +#define PF5_PWM NULL +#define PF5_DDR DDRF +#undef PF6 +#define PF6_PIN PINF6 +#define PF6_RPORT PINF +#define PF6_WPORT PORTF +#define PF6_PWM NULL +#define PF6_DDR DDRF +#undef PF7 +#define PF7_PIN PINF7 +#define PF7_RPORT PINF +#define PF7_WPORT PORTF +#define PF7_PWM NULL +#define PF7_DDR DDRF + +#endif // AT90USBxx_TEENSYPP_ASSIGNMENTS Teensyduino assignments +#endif // __AVR_AT90usbxxx__ #if defined (__AVR_ATmega1281__) || defined (__AVR_ATmega2561__) From 7216583b8be5617ecde6aaee4d209f6510baebed Mon Sep 17 00:00:00 2001 From: David Forrest Date: Thu, 16 Jan 2014 12:40:15 -0500 Subject: [PATCH 108/256] createTemperatureLookupMarlin.py: Add resolution comments and format for Marlin. --- Marlin/createTemperatureLookupMarlin.py | 30 +++++++++++++++++++------ 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/Marlin/createTemperatureLookupMarlin.py b/Marlin/createTemperatureLookupMarlin.py index e09294e4bd..592dae53d4 100644 --- a/Marlin/createTemperatureLookupMarlin.py +++ b/Marlin/createTemperatureLookupMarlin.py @@ -54,9 +54,25 @@ class Thermistor: self.c2 = c2 self.c3 = c3 + def res(self,adc): + "Convert ADC reading into a resolution" + res = self.temp(adc)-self.temp(adc+1) + return res + + def v(self,adc): + "Convert ADC reading into a Voltage" + v = adc * self.vadc / (1024 ) # convert the 10 bit ADC value to a voltage + return v + + def r(self,adc): + "Convert ADC reading into a resistance in Ohms" + v = adc * self.vadc / (1024 ) # convert the 10 bit ADC value to a voltage + r = self.rp * v / (self.vcc - v) # resistance of thermistor + return r + def temp(self,adc): "Convert ADC reading into a temperature in Celcius" - v = adc * self.vadc / (1024 * 16) # convert the 10 bit ADC value to a voltage + v = adc * self.vadc / (1024 ) # convert the 10 bit ADC value to a voltage r = self.rp * v / (self.vcc - v) # resistance of thermistor lnr = log(r) Tinv = self.c1 + (self.c2*lnr) + (self.c3*pow(lnr,3)) @@ -67,7 +83,7 @@ class Thermistor: y = (self.c1 - (1/(temp+273.15))) / (2*self.c3) x = sqrt(pow(self.c2 / (3*self.c3),3) + pow(y,2)) r = exp(pow(x-y,1.0/3) - pow(x+y,1.0/3)) # resistance of thermistor - return (r / (self.rp + r)) * (1024*16) + return (r / (self.rp + r)) * (1024) def main(argv): @@ -107,7 +123,7 @@ def main(argv): elif opt == "--num-temps": num_temps = int(arg) - max_adc = (1024 * 16) - 1 + max_adc = (1024 ) - 1 min_temp = 0 max_temp = 350 increment = int(max_adc/(num_temps-1)); @@ -119,16 +135,16 @@ def main(argv): print "// Thermistor lookup table for Marlin" print "// ./createTemperatureLookup.py --rp=%s --t1=%s:%s --t2=%s:%s --t3=%s:%s --num-temps=%s" % (rp, t1, r1, t2, r2, t3, r3, num_temps) - print "#define NUMTEMPS %s" % (len(temps)) - print "short temptable[NUMTEMPS][2] = {" + print "//#define NUMTEMPS %s" % (len(temps)) + print "const short temptable[NUMTEMPS][2] PROGMEM = {" counter = 0 for temp in temps: counter = counter +1 if counter == len(temps): - print " {%s, %s}" % (int(t.adc(temp)), temp) + print " {%s*OVERSAMPLENR, %s} // v=%s r=%s res=%s C/count" % (int(t.adc(temp)), temp, t.v(t.adc(temp)), t.r(t.adc(temp)),t.res(t.adc(temp))) else: - print " {%s, %s}," % (int(t.adc(temp)), temp) + print " {%s*OVERSAMPLENR, %s}, // v=%s r=%s res=%s C/count" % (int(t.adc(temp)), temp, t.v(t.adc(temp)), t.r(t.adc(temp)),t.res(t.adc(temp))) print "};" def usage(): From 05932e445883c4fdf5620f90d503a3745639ffbc Mon Sep 17 00:00:00 2001 From: Alex Borro Date: Thu, 16 Jan 2014 18:13:46 -0200 Subject: [PATCH 109/256] Add Z Probe Offset to EEPROM and Ultra LCD --- Marlin/ConfigurationStore.cpp | 5 +- Marlin/Marlin.h | 1 + Marlin/Marlin_main.cpp | 160 +++++++++++++++++----------------- Marlin/language.h | 10 ++- Marlin/ultralcd.cpp | 2 + 5 files changed, 97 insertions(+), 81 deletions(-) diff --git a/Marlin/ConfigurationStore.cpp b/Marlin/ConfigurationStore.cpp index 1fb72450c6..0b169fe7a4 100644 --- a/Marlin/ConfigurationStore.cpp +++ b/Marlin/ConfigurationStore.cpp @@ -37,7 +37,7 @@ void _EEPROM_readData(int &pos, uint8_t* value, uint8_t size) // the default values are used whenever there is a change to the data, to prevent // wrong data being written to the variables. // ALSO: always make sure the variables in the Store and retrieve sections are in the same order. -#define EEPROM_VERSION "V09" +#define EEPROM_VERSION "V10" #ifdef EEPROM_SETTINGS void Config_StoreSettings() @@ -70,6 +70,7 @@ void Config_StoreSettings() EEPROM_WRITE_VAR(i,absPreheatHotendTemp); EEPROM_WRITE_VAR(i,absPreheatHPBTemp); EEPROM_WRITE_VAR(i,absPreheatFanSpeed); + EEPROM_WRITE_VAR(i,zprobe_zoffset); #ifdef PIDTEMP EEPROM_WRITE_VAR(i,Kp); EEPROM_WRITE_VAR(i,Ki); @@ -210,6 +211,7 @@ void Config_RetrieveSettings() EEPROM_READ_VAR(i,absPreheatHotendTemp); EEPROM_READ_VAR(i,absPreheatHPBTemp); EEPROM_READ_VAR(i,absPreheatFanSpeed); + EEPROM_READ_VAR(i,zprobe_zoffset); #ifndef PIDTEMP float Kp,Ki,Kd; #endif @@ -272,6 +274,7 @@ void Config_ResetDefault() absPreheatHPBTemp = ABS_PREHEAT_HPB_TEMP; absPreheatFanSpeed = ABS_PREHEAT_FAN_SPEED; #endif + zprobe_zoffset = -Z_PROBE_OFFSET_FROM_EXTRUDER; #ifdef DOGLCD lcd_contrast = DEFAULT_LCD_CONTRAST; #endif diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index be4115e068..af3325be41 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -210,6 +210,7 @@ extern float endstop_adj[3]; extern float min_pos[3]; extern float max_pos[3]; extern bool axis_known_position[3]; +extern float zprobe_zoffset; extern int fanSpeed; #ifdef BARICUDA extern int ValvePressure; diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index c3b75516af..26bc66f7de 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -196,6 +196,7 @@ float endstop_adj[3]={0,0,0}; float min_pos[3] = { X_MIN_POS, Y_MIN_POS, Z_MIN_POS }; float max_pos[3] = { X_MAX_POS, Y_MAX_POS, Z_MAX_POS }; bool axis_known_position[3] = {false, false, false}; +float zprobe_zoffset; // Extruder offset #if EXTRUDERS > 1 @@ -240,6 +241,7 @@ int EtoPPressure=0; float delta[3] = {0.0, 0.0, 0.0}; #endif + //=========================================================================== //=============================private variables============================= //=========================================================================== @@ -779,7 +781,7 @@ static unsigned long delayed_move_time = 0; // used in mode 1 static float duplicate_extruder_x_offset = DEFAULT_DUPLICATION_X_OFFSET; // used in mode 2 static float duplicate_extruder_temp_offset = 0; // used in mode 2 bool extruder_duplication_enabled = false; // used in mode 2 -#endif //DUAL_X_CARRIAGE +#endif //DUAL_X_CARRIAGE static void axis_is_at_home(int axis) { #ifdef DUAL_X_CARRIAGE @@ -792,8 +794,8 @@ static void axis_is_at_home(int axis) { } else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && active_extruder == 0) { current_position[X_AXIS] = base_home_pos(X_AXIS) + add_homeing[X_AXIS]; - min_pos[X_AXIS] = base_min_pos(X_AXIS) + add_homeing[X_AXIS]; - max_pos[X_AXIS] = min(base_max_pos(X_AXIS) + add_homeing[X_AXIS], + min_pos[X_AXIS] = base_min_pos(X_AXIS) + add_homeing[X_AXIS]; + max_pos[X_AXIS] = min(base_max_pos(X_AXIS) + add_homeing[X_AXIS], max(extruder_offset[X_AXIS][1], X2_MAX_POS) - duplicate_extruder_x_offset); return; } @@ -824,7 +826,7 @@ static void set_bed_level_equation_lsq(double *plane_equation_coefficients) current_position[Z_AXIS] = corrected_position.z; // but the bed at 0 so we don't go below it. - current_position[Z_AXIS] = -Z_PROBE_OFFSET_FROM_EXTRUDER; + current_position[Z_AXIS] = zprobe_zoffset; // in the lsq we reach here after raising the extruder due to the loop structure plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); } @@ -860,7 +862,7 @@ static void set_bed_level_equation(float z_at_xLeft_yFront, float z_at_xRight_yF current_position[Z_AXIS] = corrected_position.z; // but the bed at 0 so we don't go below it. - current_position[Z_AXIS] = -Z_PROBE_OFFSET_FROM_EXTRUDER; + current_position[Z_AXIS] = zprobe_zoffset; plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); } @@ -885,7 +887,7 @@ static void run_z_probe() { st_synchronize(); // move back down slowly to find bed - feedrate = homing_feedrate[Z_AXIS]/4; + feedrate = homing_feedrate[Z_AXIS]/4; zPosition -= home_retract_mm(Z_AXIS) * 2; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], zPosition, current_position[E_AXIS], feedrate/60, active_extruder); st_synchronize(); @@ -982,7 +984,7 @@ static void homeaxis(int axis) { current_position[axis] = 0; plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - + // Engage Servo endstop if enabled #ifdef SERVO_ENDSTOPS @@ -1040,7 +1042,7 @@ static void homeaxis(int axis) { #if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) if (axis==Z_AXIS) retract_z_probe(); #endif - + } } #define HOMEAXIS(LETTER) homeaxis(LETTER##_AXIS) @@ -1114,7 +1116,7 @@ void process_commands() destination[Y_AXIS]=current_position[Y_AXIS]; destination[Z_AXIS]=current_position[Z_AXIS]; current_position[Z_AXIS]+=retract_zlift; - destination[E_AXIS]=current_position[E_AXIS]+retract_length+retract_recover_length; + destination[E_AXIS]=current_position[E_AXIS]+retract_length+retract_recover_length; feedrate=retract_recover_feedrate; retracted=false; prepare_move(); @@ -1228,10 +1230,10 @@ void process_commands() // reset state used by the different modes memcpy(raised_parked_position, current_position, sizeof(raised_parked_position)); delayed_move_time = 0; - active_extruder_parked = true; - #else + active_extruder_parked = true; + #else HOMEAXIS(X); - #endif + #endif } if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) { @@ -1250,7 +1252,7 @@ void process_commands() current_position[Y_AXIS]=code_value()+add_homeing[1]; } } - + #if Z_HOME_DIR < 0 // If homing towards BED do Z last #ifndef Z_SAFE_HOMING if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { @@ -1262,14 +1264,14 @@ void process_commands() #endif HOMEAXIS(Z); } - #else // Z Safe mode activated. + #else // Z Safe mode activated. if(home_all_axis) { destination[X_AXIS] = round(Z_SAFE_HOMING_X_POINT - X_PROBE_OFFSET_FROM_EXTRUDER); destination[Y_AXIS] = round(Z_SAFE_HOMING_Y_POINT - Y_PROBE_OFFSET_FROM_EXTRUDER); destination[Z_AXIS] = Z_RAISE_BEFORE_HOMING * home_dir(Z_AXIS) * (-1); // Set destination away from bed feedrate = XY_TRAVEL_SPEED; current_position[Z_AXIS] = 0; - + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate, active_extruder); st_synchronize(); @@ -1287,7 +1289,7 @@ void process_commands() && (current_position[Y_AXIS]+Y_PROBE_OFFSET_FROM_EXTRUDER <= Y_MAX_POS)) { current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); destination[Z_AXIS] = Z_RAISE_BEFORE_HOMING * home_dir(Z_AXIS) * (-1); // Set destination away from bed feedrate = max_feedrate[Z_AXIS]; plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate, active_extruder); @@ -1307,8 +1309,8 @@ void process_commands() #endif #endif - - + + if(code_seen(axis_codes[Z_AXIS])) { if(code_value_long() != 0) { current_position[Z_AXIS]=code_value()+add_homeing[2]; @@ -1316,7 +1318,7 @@ void process_commands() } #ifdef ENABLE_AUTO_BED_LEVELING if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { - current_position[Z_AXIS] -= Z_PROBE_OFFSET_FROM_EXTRUDER; //Add Z_Probe offset (the distance is negative) + current_position[Z_AXIS] += zprobe_zoffset; //Add Z_Probe offset (the distance is negative) } #endif plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); @@ -1471,7 +1473,7 @@ void process_commands() run_z_probe(); float z_at_xLeft_yFront = current_position[Z_AXIS]; retract_z_probe(); - + SERIAL_PROTOCOLPGM("Bed x: "); SERIAL_PROTOCOL(LEFT_PROBE_BED_POSITION); SERIAL_PROTOCOLPGM(" y: "); @@ -1489,7 +1491,7 @@ void process_commands() run_z_probe(); float z_at_xRight_yFront = current_position[Z_AXIS]; retract_z_probe(); // Retract Z Servo endstop if available - + SERIAL_PROTOCOLPGM("Bed x: "); SERIAL_PROTOCOL(RIGHT_PROBE_BED_POSITION); SERIAL_PROTOCOLPGM(" y: "); @@ -1504,10 +1506,10 @@ void process_commands() #endif // ACCURATE_BED_LEVELING - st_synchronize(); + st_synchronize(); // The following code correct the Z height difference from z-probe position and hotend tip position. - // The Z height on homing is measured by Z-Probe, but the probe is quite far from the hotend. + // The Z height on homing is measured by Z-Probe, but the probe is quite far from the hotend. // When the bed is uneven, this height must be corrected. real_z = float(st_get_position(Z_AXIS))/axis_steps_per_unit[Z_AXIS]; //get the real Z (since the auto bed leveling is already correcting the plane) x_tmp = current_position[X_AXIS] + X_PROBE_OFFSET_FROM_EXTRUDER; @@ -1519,11 +1521,11 @@ void process_commands() plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); } break; - + case 30: // G30 Single Z Probe { engage_z_probe(); // Engage Z Servo endstop if available - + st_synchronize(); // TODO: make sure the bed_level_rotation_matrix is identity or the planner will get set incorectly setup_for_endstop_move(); @@ -1674,14 +1676,14 @@ void process_commands() card.removeFile(strchr_pointer + 4); } break; - case 32: //M32 - Select file and start SD print + case 32: //M32 - Select file and start SD print { if(card.sdprinting) { st_synchronize(); } - starpos = (strchr(strchr_pointer + 4,'*')); - + starpos = (strchr(strchr_pointer + 4,'*')); + char* namestartpos = (strchr(strchr_pointer + 4,'!')); //find ! to indicate filename string start. if(namestartpos==NULL) { @@ -1689,16 +1691,16 @@ void process_commands() } else namestartpos++; //to skip the '!' - + if(starpos!=NULL) *(starpos-1)='\0'; - + bool call_procedure=(code_seen('P')); - - if(strchr_pointer>namestartpos) + + if(strchr_pointer>namestartpos) call_procedure=false; //false alert, 'P' found within filename - - if( card.cardOK ) + + if( card.cardOK ) { card.openFile(namestartpos,true,!call_procedure); if(code_seen('S')) @@ -1771,7 +1773,7 @@ void process_commands() #ifdef DUAL_X_CARRIAGE if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0) setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset); -#endif +#endif setWatch(); break; case 140: // M140 set bed temp @@ -1827,7 +1829,7 @@ void process_commands() SERIAL_PROTOCOL_F(rawHotendTemp(cur_extruder)/OVERSAMPLENR,0); } #endif - + SERIAL_PROTOCOLLN(""); return; break; @@ -1845,14 +1847,14 @@ void process_commands() #ifdef DUAL_X_CARRIAGE if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0) setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset); -#endif +#endif CooldownNoWait = true; } else if (code_seen('R')) { setTargetHotend(code_value(), tmp_extruder); #ifdef DUAL_X_CARRIAGE if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0) setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset); -#endif +#endif CooldownNoWait = false; } #ifdef AUTOTEMP @@ -2016,7 +2018,7 @@ void process_commands() SET_OUTPUT(SUICIDE_PIN); WRITE(SUICIDE_PIN, HIGH); #endif - + #ifdef ULTIPANEL powersupply = true; LCD_MESSAGEPGM(WELCOME_MSG); @@ -2173,18 +2175,18 @@ void process_commands() #endif break; //TODO: update for all axis, use for loop - #ifdef BLINKM + #ifdef BLINKM case 150: // M150 { byte red; byte grn; byte blu; - + if(code_seen('R')) red = code_value(); if(code_seen('U')) grn = code_value(); if(code_seen('B')) blu = code_value(); - - SendColors(red,grn,blu); + + SendColors(red,grn,blu); } break; #endif //BLINKM @@ -2306,7 +2308,7 @@ void process_commands() { extruder_offset[Z_AXIS][tmp_extruder] = code_value(); } - #endif + #endif SERIAL_ECHO_START; SERIAL_ECHOPGM(MSG_HOTEND_OFFSET); for(tmp_extruder = 0; tmp_extruder < EXTRUDERS; tmp_extruder++) @@ -2339,17 +2341,17 @@ void process_commands() } } break; - + case 226: // M226 P S- Wait until the specified pin reaches the state required { if(code_seen('P')){ int pin_number = code_value(); // pin number int pin_state = -1; // required pin state - default is inverted - + if(code_seen('S')) pin_state = code_value(); // required pin state - + if(pin_state >= -1 && pin_state <= 1){ - + for(int8_t i = 0; i < (int8_t)sizeof(sensitive_pins); i++) { if (sensitive_pins[i] == pin_number) @@ -2358,28 +2360,28 @@ void process_commands() break; } } - + if (pin_number > -1) { st_synchronize(); - + pinMode(pin_number, INPUT); - + int target; switch(pin_state){ case 1: target = HIGH; break; - + case 0: target = LOW; break; - + case -1: target = !digitalRead(pin_number); break; } - + while(digitalRead(pin_number) != target){ manage_heater(); manage_inactivity(); @@ -2389,7 +2391,7 @@ void process_commands() } } } - break; + break; #if NUM_SERVOS > 0 case 280: // M280 - set servo position absolute. P: servo index, S: angle or microseconds @@ -2565,13 +2567,13 @@ void process_commands() engage_z_probe(); // Engage Z Servo endstop if available } break; - + case 402: { retract_z_probe(); // Retract Z Servo endstop if enabled } break; -#endif +#endif case 500: // M500 Store settings in EEPROM { Config_StoreSettings(); @@ -2729,14 +2731,14 @@ void process_commands() // M605 S0: Full control mode. The slicer has full control over x-carriage movement // M605 S1: Auto-park mode. The inactive head will auto park/unpark without slicer involvement // M605 S2 [Xnnn] [Rmmm]: Duplication mode. The second extruder will duplicate the first with nnn - // millimeters x-offset and an optional differential hotend temperature of + // millimeters x-offset and an optional differential hotend temperature of // mmm degrees. E.g., with "M605 S2 X100 R2" the second extruder will duplicate // the first with a spacing of 100mm in the x direction and 2 degrees hotter. // // Note: the X axis should be homed after changing dual x-carriage mode. { st_synchronize(); - + if (code_seen('S')) dual_x_carriage_mode = code_value(); @@ -2747,7 +2749,7 @@ void process_commands() if (code_seen('R')) duplicate_extruder_temp_offset = code_value(); - + SERIAL_ECHO_START; SERIAL_ECHOPGM(MSG_HOTEND_OFFSET); SERIAL_ECHO(" "); @@ -2763,13 +2765,13 @@ void process_commands() { dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; } - + active_extruder_parked = false; extruder_duplication_enabled = false; delayed_move_time = 0; } break; - #endif //DUAL_X_CARRIAGE + #endif //DUAL_X_CARRIAGE case 907: // M907 Set digital trimpot motor current using axis codes. { @@ -2859,19 +2861,19 @@ void process_commands() // Save current position to return to after applying extruder offset memcpy(destination, current_position, sizeof(destination)); #ifdef DUAL_X_CARRIAGE - if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE && Stopped == false && + if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE && Stopped == false && (delayed_move_time != 0 || current_position[X_AXIS] != x_home_pos(active_extruder))) { // Park old head: 1) raise 2) move to park position 3) lower - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); - plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, + plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT, current_position[E_AXIS], max_feedrate[X_AXIS], active_extruder); - plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS], + plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); st_synchronize(); } - + // apply Y & Z extruder offset (x offset is already used in determining home pos) current_position[Y_AXIS] = current_position[Y_AXIS] - extruder_offset[Y_AXIS][active_extruder] + @@ -2879,7 +2881,7 @@ void process_commands() current_position[Z_AXIS] = current_position[Z_AXIS] - extruder_offset[Z_AXIS][active_extruder] + extruder_offset[Z_AXIS][tmp_extruder]; - + active_extruder = tmp_extruder; // This function resets the max/min values - the current position may be overwritten below. @@ -2887,18 +2889,18 @@ void process_commands() if (dual_x_carriage_mode == DXC_FULL_CONTROL_MODE) { - current_position[X_AXIS] = inactive_extruder_x_pos; + current_position[X_AXIS] = inactive_extruder_x_pos; inactive_extruder_x_pos = destination[X_AXIS]; } else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE) { active_extruder_parked = (active_extruder == 0); // this triggers the second extruder to move into the duplication position if (active_extruder == 0 || active_extruder_parked) - current_position[X_AXIS] = inactive_extruder_x_pos; + current_position[X_AXIS] = inactive_extruder_x_pos; else - current_position[X_AXIS] = destination[X_AXIS] + duplicate_extruder_x_offset; + current_position[X_AXIS] = destination[X_AXIS] + duplicate_extruder_x_offset; inactive_extruder_x_pos = destination[X_AXIS]; - extruder_duplication_enabled = false; + extruder_duplication_enabled = false; } else { @@ -2908,7 +2910,7 @@ void process_commands() active_extruder_parked = true; delayed_move_time = 0; } - #else + #else // Offset extruder (only by XY) int i; for(i = 0; i < 2; i++) { @@ -3121,13 +3123,13 @@ void prepare_move() { // move duplicate extruder into correct duplication position. plan_set_position(inactive_extruder_x_pos, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - plan_buffer_line(current_position[X_AXIS] + duplicate_extruder_x_offset, current_position[Y_AXIS], current_position[Z_AXIS], + plan_buffer_line(current_position[X_AXIS] + duplicate_extruder_x_offset, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], max_feedrate[X_AXIS], 1); plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); st_synchronize(); extruder_duplication_enabled = true; active_extruder_parked = false; - } + } else if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE) // handle unparking of head { if (current_position[E_AXIS] == destination[E_AXIS]) @@ -3136,7 +3138,7 @@ void prepare_move() // be used as start of first non-travel move) if (delayed_move_time != 0xFFFFFFFFUL) { - memcpy(current_position, destination, sizeof(current_position)); + memcpy(current_position, destination, sizeof(current_position)); if (destination[Z_AXIS] > raised_parked_position[Z_AXIS]) raised_parked_position[Z_AXIS] = destination[Z_AXIS]; delayed_move_time = millis(); @@ -3146,9 +3148,9 @@ void prepare_move() delayed_move_time = 0; // unpark extruder: 1) raise, 2) move into starting XY position, 3) lower plan_buffer_line(raised_parked_position[X_AXIS], raised_parked_position[Y_AXIS], raised_parked_position[Z_AXIS], current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], raised_parked_position[Z_AXIS], + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], raised_parked_position[Z_AXIS], current_position[E_AXIS], min(max_feedrate[X_AXIS],max_feedrate[Y_AXIS]), active_extruder); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); active_extruder_parked = false; } @@ -3314,7 +3316,7 @@ void manage_inactivity() // travel moves have been received so enact them delayed_move_time = 0xFFFFFFFFUL; // force moves to be done memcpy(destination,current_position,sizeof(destination)); - prepare_move(); + prepare_move(); } #endif #ifdef TEMP_STAT_LEDS diff --git a/Marlin/language.h b/Marlin/language.h index d1527d5e9d..52b1b16059 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -138,7 +138,7 @@ #define MSG_CNG_SDCARD "Change SD-Card" #define MSG_ZPROBE_OUT "ZProbe Outside Bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" - + #define MSG_ZPROBE_ZOFFSET "Z Offset" // Serial Console Messages #define MSG_Enqueing "enqueing \"" @@ -305,6 +305,7 @@ #define MSG_CNG_SDCARD "Change SD-Card" #define MSG_ZPROBE_OUT "ZProbe Outside Bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" // Serial Console Messages @@ -471,6 +472,7 @@ #define MSG_CNG_SDCARD "Changer de carte SD" #define MSG_ZPROBE_OUT "ZProbe Outside Bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" // Serial Console Messages @@ -640,6 +642,7 @@ #define MSG_CNG_SDCARD "Change SD-Card" #define MSG_ZPROBE_OUT "ZProbe Outside Bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" // Serial Console Messages @@ -813,6 +816,7 @@ #define MSG_STEPPER_RELEASED "Desacoplada." #define MSG_ZPROBE_OUT "ZProbe Outside Bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" // Serial Console Messages @@ -976,6 +980,7 @@ #define MSG_CNG_SDCARD "Change SD-Card" #define MSG_ZPROBE_OUT "ZProbe Outside Bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" // Serial Console Messages @@ -1139,6 +1144,7 @@ #define MSG_CNG_SDCARD "Cambia SD-Card" #define MSG_ZPROBE_OUT "ZProbe Outside Bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" // Serial Console Messages @@ -1311,6 +1317,7 @@ #define MSG_CNG_SDCARD "Change SD-Card" #define MSG_ZPROBE_OUT "Sonda fora da mesa" #define MSG_POSITION_UNKNOWN "Home X/Y antes de Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" // Serial Console Messages @@ -1479,6 +1486,7 @@ #define MSG_CNG_SDCARD "Change SD-Card" #define MSG_ZPROBE_OUT "ZProbe Outside Bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" // Serial Console Messages diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index fe8cab0860..77be8e8e35 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -19,6 +19,7 @@ int absPreheatHotendTemp; int absPreheatHPBTemp; int absPreheatFanSpeed; + #ifdef ULTIPANEL static float manual_feedrate[] = MANUAL_FEEDRATE; #endif // ULTIPANEL @@ -705,6 +706,7 @@ static void lcd_control_motion_menu() { START_MENU(); MENU_ITEM(back, MSG_CONTROL, lcd_control_menu); + MENU_ITEM_EDIT(float32, MSG_ZPROBE_ZOFFSET, &zprobe_zoffset, 0.5, 50); MENU_ITEM_EDIT(float5, MSG_ACC, &acceleration, 500, 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); From fdac8f6cece835664bb97ff2f53d8fba74e37fc7 Mon Sep 17 00:00:00 2001 From: "l.lefebvre" Date: Fri, 17 Jan 2014 16:09:58 +0100 Subject: [PATCH 110/256] Update ConfigurationStore.cpp Unable to compile if ENABLE_AUTO_BED_LEVELING is not set (not set by default). --- Marlin/ConfigurationStore.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Marlin/ConfigurationStore.cpp b/Marlin/ConfigurationStore.cpp index 0b169fe7a4..3409ade705 100644 --- a/Marlin/ConfigurationStore.cpp +++ b/Marlin/ConfigurationStore.cpp @@ -274,7 +274,9 @@ void Config_ResetDefault() absPreheatHPBTemp = ABS_PREHEAT_HPB_TEMP; absPreheatFanSpeed = ABS_PREHEAT_FAN_SPEED; #endif +#ifdef ENABLE_AUTO_BED_LEVELING zprobe_zoffset = -Z_PROBE_OFFSET_FROM_EXTRUDER; +#endif #ifdef DOGLCD lcd_contrast = DEFAULT_LCD_CONTRAST; #endif From 61a7256d42b7c8bc718f5ac137d88b9b62646f28 Mon Sep 17 00:00:00 2001 From: David Forrest Date: Fri, 17 Jan 2014 17:00:47 -0500 Subject: [PATCH 111/256] Enable basic ULTRA_LCD screen w/o encoders and menus. --- Marlin/ultralcd.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index fe8cab0860..96f8229b36 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -987,7 +987,6 @@ void lcd_init() #ifdef NEWPANEL pinMode(BTN_EN1,INPUT); pinMode(BTN_EN2,INPUT); - pinMode(SDCARDDETECT,INPUT); WRITE(BTN_EN1,HIGH); WRITE(BTN_EN2,HIGH); #if BTN_ENC > 0 @@ -1001,11 +1000,11 @@ void lcd_init() WRITE(SHIFT_OUT,HIGH); WRITE(SHIFT_LD,HIGH); #endif -#else - #ifdef SR_LCD_2W_NL +#else // Not NEWPANEL + #ifdef SR_LCD_2W_NL // Non latching 2 wire shiftregister pinMode (SR_DATA_PIN, OUTPUT); pinMode (SR_CLK_PIN, OUTPUT); - #else + #elif defined(SHIFT_CLK) pinMode(SHIFT_CLK,OUTPUT); pinMode(SHIFT_LD,OUTPUT); pinMode(SHIFT_EN,OUTPUT); @@ -1013,16 +1012,21 @@ void lcd_init() WRITE(SHIFT_OUT,HIGH); WRITE(SHIFT_LD,HIGH); WRITE(SHIFT_EN,LOW); - #endif // SR_LCD_2W_NL + #else + #ifdef ULTIPANEL + #error ULTIPANEL requires an encoder + #endif + #endif // SR_LCD_2W_NL #endif//!NEWPANEL -#if (SDCARDDETECT > 0) +#if defined (SDSUPPORT) && defined(SDCARDDETECT) && (SDCARDDETECT > 0) + pinMode(SDCARDDETECT,INPUT); WRITE(SDCARDDETECT, HIGH); lcd_oldcardstatus = IS_SD_INSERTED; #endif//(SDCARDDETECT > 0) - #ifdef LCD_HAS_SLOW_BUTTONS +#ifdef LCD_HAS_SLOW_BUTTONS slow_buttons = 0; - #endif +#endif lcd_buttons_update(); #ifdef ULTIPANEL encoderDiff = 0; From 8a5eaa3c9b53548337306f34077d27aed0a69391 Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Sun, 19 Jan 2014 19:11:51 -0800 Subject: [PATCH 112/256] Fix crash after home bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes a bug in the Extruder Runout Prevention feature that caused the extruder to move back to “current_position” after a move if it was activated while the move was in progress. For long home moves (which are longer than the dimensions of the machine’s working area), this would cause the machine to crash into the far end of its travel after homing. This usually occurred on the Z axis, which could result in damage to the machine if you don’t hit the reset button in time. --- Marlin/Marlin_main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 26bc66f7de..920aed00c4 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -3298,8 +3298,8 @@ void manage_inactivity() enable_e0(); float oldepos=current_position[E_AXIS]; float oldedes=destination[E_AXIS]; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], - current_position[E_AXIS]+EXTRUDER_RUNOUT_EXTRUDE*EXTRUDER_RUNOUT_ESTEPS/axis_steps_per_unit[E_AXIS], + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], + destination[E_AXIS]+EXTRUDER_RUNOUT_EXTRUDE*EXTRUDER_RUNOUT_ESTEPS/axis_steps_per_unit[E_AXIS], EXTRUDER_RUNOUT_SPEED/60.*EXTRUDER_RUNOUT_ESTEPS/axis_steps_per_unit[E_AXIS], active_extruder); current_position[E_AXIS]=oldepos; destination[E_AXIS]=oldedes; From b1f8f492c6908c62604833c4062e101f2490ebd6 Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Sun, 19 Jan 2014 19:22:08 -0800 Subject: [PATCH 113/256] Remove previous_millis_cmd update from extruder runout prevention code This seems to defeat the purpose of previous_millis_cmd, preventing the time elapsed from previous_millis_cmd from ever reaching max_inactive_time or stepper_inactive_time while the heat was on. --- Marlin/Marlin_main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 920aed00c4..524b82161d 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -3304,7 +3304,6 @@ void manage_inactivity() current_position[E_AXIS]=oldepos; destination[E_AXIS]=oldedes; plan_set_e_position(oldepos); - previous_millis_cmd=millis(); st_synchronize(); WRITE(E0_ENABLE_PIN,oldstatus); } From f08bb8bb6a587b326222af9b678dae3922619493 Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Sun, 19 Jan 2014 22:06:45 -0800 Subject: [PATCH 114/256] Previous commit borked. --- Marlin/Marlin_main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 524b82161d..920aed00c4 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -3304,6 +3304,7 @@ void manage_inactivity() current_position[E_AXIS]=oldepos; destination[E_AXIS]=oldedes; plan_set_e_position(oldepos); + previous_millis_cmd=millis(); st_synchronize(); WRITE(E0_ENABLE_PIN,oldstatus); } From 5bf73b86ff70f55b5ca57240d61bac5331e663e9 Mon Sep 17 00:00:00 2001 From: Dan Lipsitt Date: Mon, 20 Jan 2014 18:04:06 -0800 Subject: [PATCH 115/256] Format README.md with subsections Having actual section headers instead of just bold text makes those parts of the document individually linkable. --- README.md | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 5e42b43b61..e85be7c3eb 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Lampmaker, Bradley Feldman, and others... Features: +========= * Interrupt based movement with real linear acceleration * High steprate @@ -56,7 +57,8 @@ The default baudrate is 250000. This baudrate has less jitter and hence errors t Differences and additions to the already good Sprinter firmware: ================================================================ -*Look-ahead:* +Look-ahead: +----------- Marlin has look-ahead. While sprinter has to break and re-accelerate at each corner, lookahead will only decelerate and accelerate to a velocity, @@ -64,18 +66,21 @@ so that the change in vectorial velocity magnitude is less than the xy_jerk_velo This is only possible, if some future moves are already processed, hence the name. It leads to less over-deposition at corners, especially at flat angles. -*Arc support:* +Arc support: +------------ Slic3r can find curves that, although broken into segments, were ment to describe an arc. Marlin is able to print those arcs. The advantage is the firmware can choose the resolution, and can perform the arc with nearly constant velocity, resulting in a nice finish. Also, less serial communication is needed. -*Temperature Oversampling:* +Temperature Oversampling: +------------------------- To reduce noise and make the PID-differential term more useful, 16 ADC conversion results are averaged. -*AutoTemp:* +AutoTemp: +--------- If your gcode contains a wide spread of extruder velocities, or you realtime change the building speed, the temperature should be changed accordingly. Usually, higher speed requires higher temperature. @@ -88,36 +93,42 @@ The wanted temperature then will be set to t=tempmin+factor*maxerate, while bein If the target temperature is set manually or by gcode to a value less then tempmin, it will be kept without change. Ideally, your gcode can be completely free of temperature controls, apart from a M109 S T F in the start.gcode, and a M109 S0 in the end.gcode. -*EEPROM:* +EEPROM: +------- If you know your PID values, the acceleration and max-velocities of your unique machine, you can set them, and finally store them in the EEPROM. After each reboot, it will magically load them from EEPROM, independent what your Configuration.h says. -*LCD Menu:* +LCD Menu: +--------- If your hardware supports it, you can build yourself a LCD-CardReader+Click+encoder combination. It will enable you to realtime tune temperatures, accelerations, velocities, flow rates, select and print files from the SD card, preheat, disable the steppers, and do other fancy stuff. One working hardware is documented here: http://www.thingiverse.com/thing:12663 Also, with just a 20x4 or 16x2 display, useful data is shown. -*SD card folders:* +SD card folders: +---------------- If you have an SD card reader attached to your controller, also folders work now. Listing the files in pronterface will show "/path/subpath/file.g". You can write to file in a subfolder by specifying a similar text using small letters in the path. Also, backup copies of various operating systems are hidden, as well as files not ending with ".g". -*SD card folders:* +SD card folders: +---------------- If you place a file auto[0-9].g into the root of the sd card, it will be automatically executed if you boot the printer. The same file will be executed by selecting "Autostart" from the menu. First *0 will be performed, than *1 and so on. That way, you can heat up or even print automatically without user interaction. -*Endstop trigger reporting:* +Endstop trigger reporting: +-------------------------- If an endstop is hit while moving towards the endstop, the location at which the firmware thinks that the endstop was triggered is outputed on the serial port. This is useful, because the user gets a warning message. However, also tools like QTMarlin can use this for finding acceptable combinations of velocity+acceleration. -*Coding paradigm:* +Coding paradigm: +---------------- Not relevant from a user side, but Marlin was split into thematic junks, and has tried to partially enforced private variables. This is intended to make it clearer, what interacts which what, and leads to a higher level of modularization. @@ -127,7 +138,8 @@ In the serial communication, a #define based level of abstraction was enforced, some transfer is information (usually beginning with "echo:"), an error "error:", or just normal protocol, necessary for backwards compatibility. -*Interrupt based temperature measurements:* +Interrupt based temperature measurements: +----------------------------------------- An interrupt is used to manage ADC conversions, and enforce checking for critical temperatures. This leads to less blocking in the heater management routine. @@ -276,7 +288,9 @@ The first define tells firmware how many servos you have. The second tells what axis this servo will be attached to. In the example above, we have a servo in Z axis. The third one tells the angle in 2 situations: Probing (165º) and resting (60º). Check this with command M280 P0 S{angle} (example: M280 P0 S60 moves the servo to 60º) -*For RAMPS users:* +For RAMPS users: +---------------- + By default, RAMPS have no power on servo bus (if you happen to have a multimeter, check the voltage on servo power pins). In order to get the servo working, you need to supply 5V to 5V pin.. You can do it using your power supply (if it has a 5V output) or jumping the "Vcc" from Arduino to the 5V RAMPS rail. These 2 pins are located just between the Reset Button and the yellow fuses... There are marks in the board showing 5V and VCC.. just connect them.. From 476c7193d843d78c4b234d187238a9bf1fb47282 Mon Sep 17 00:00:00 2001 From: David Forrest Date: Tue, 21 Jan 2014 16:49:03 -0500 Subject: [PATCH 116/256] temperature.cpp: Use OVERSAMPLENR in oversampling calculation. --- Marlin/temperature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index 29050b84f5..74c3684894 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -1187,7 +1187,7 @@ ISR(TIMER0_COMPB_vect) // break; } - if(temp_count >= 16) // 8 ms * 16 = 128ms. + if(temp_count >= OVERSAMPLENR) // 8 * 16 * 1/(16000000/64/256) = 131ms. { if (!temp_meas_ready) //Only update the raw values if they have been read. Else we could be updating them during reading. { From 76cf07c3f75708316f128f52d904115358cb8b23 Mon Sep 17 00:00:00 2001 From: David Forrest Date: Tue, 21 Jan 2014 23:25:51 -0500 Subject: [PATCH 117/256] Configuration.h: Use OVERSAMPLENR in dT_PID definition. --- Marlin/Configuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 33a1c3a160..1da62fc2ad 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -168,7 +168,7 @@ // is more then PID_FUNCTIONAL_RANGE then the PID will be shut off and the heater will be set to min/max. #define PID_INTEGRAL_DRIVE_MAX 255 //limit for the integral term #define K1 0.95 //smoothing factor within the PID - #define PID_dT ((16.0 * 8.0)/(F_CPU / 64.0 / 256.0)) //sampling period of the temperature routine + #define PID_dT ((OVERSAMPLENR * 8.0)/(F_CPU / 64.0 / 256.0)) //sampling period of the temperature routine // If you are using a preconfigured hotend then you can use one of the value sets by uncommenting it // Ultimaker From f5b5dd8038c806efadc24de6ed85bbcd189f2e0b Mon Sep 17 00:00:00 2001 From: David Forrest Date: Wed, 29 Jan 2014 22:45:10 -0500 Subject: [PATCH 118/256] createTemperatureLookupMarlin.py: Add output of Steinhart-Hart coefficients. --- Marlin/createTemperatureLookupMarlin.py | 1 + 1 file changed, 1 insertion(+) mode change 100644 => 100755 Marlin/createTemperatureLookupMarlin.py diff --git a/Marlin/createTemperatureLookupMarlin.py b/Marlin/createTemperatureLookupMarlin.py old mode 100644 new mode 100755 index 592dae53d4..bf24dc6524 --- a/Marlin/createTemperatureLookupMarlin.py +++ b/Marlin/createTemperatureLookupMarlin.py @@ -135,6 +135,7 @@ def main(argv): print "// Thermistor lookup table for Marlin" print "// ./createTemperatureLookup.py --rp=%s --t1=%s:%s --t2=%s:%s --t3=%s:%s --num-temps=%s" % (rp, t1, r1, t2, r2, t3, r3, num_temps) + print "// Steinhart-Hart Coefficients: %.15g, %.15g, %.15g " % (t.c1, t.c2, t.c3) print "//#define NUMTEMPS %s" % (len(temps)) print "const short temptable[NUMTEMPS][2] PROGMEM = {" From 50f44d92490b1a39d471a01333a2a12e90023eda Mon Sep 17 00:00:00 2001 From: David Forrest Date: Wed, 29 Jan 2014 23:23:18 -0500 Subject: [PATCH 119/256] createTemperatureLookupMarlin.py: Truncate to short after application of OVERSAMPLENR for improved resolution. --- Marlin/createTemperatureLookupMarlin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/createTemperatureLookupMarlin.py b/Marlin/createTemperatureLookupMarlin.py index bf24dc6524..d19430b829 100755 --- a/Marlin/createTemperatureLookupMarlin.py +++ b/Marlin/createTemperatureLookupMarlin.py @@ -143,9 +143,9 @@ def main(argv): for temp in temps: counter = counter +1 if counter == len(temps): - print " {%s*OVERSAMPLENR, %s} // v=%s r=%s res=%s C/count" % (int(t.adc(temp)), temp, t.v(t.adc(temp)), t.r(t.adc(temp)),t.res(t.adc(temp))) + print " {(short)(%.2f*OVERSAMPLENR), %s} // v=%s r=%s res=%s C/count" % ((t.adc(temp)), temp, t.v(t.adc(temp)), t.r(t.adc(temp)),t.res(t.adc(temp))) else: - print " {%s*OVERSAMPLENR, %s}, // v=%s r=%s res=%s C/count" % (int(t.adc(temp)), temp, t.v(t.adc(temp)), t.r(t.adc(temp)),t.res(t.adc(temp))) + print " {(short)(%.2f*OVERSAMPLENR), %s}, // v=%s r=%s res=%s C/count" % ((t.adc(temp)), temp, t.v(t.adc(temp)), t.r(t.adc(temp)),t.res(t.adc(temp))) print "};" def usage(): From f0b8d5ba3d25328f79eb5b3830f64771eb90e23a Mon Sep 17 00:00:00 2001 From: David Forrest Date: Wed, 29 Jan 2014 23:34:22 -0500 Subject: [PATCH 120/256] createTemperatureLookupMarlin.py: Change comment to refer to actual program name. --- Marlin/createTemperatureLookupMarlin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/createTemperatureLookupMarlin.py b/Marlin/createTemperatureLookupMarlin.py index d19430b829..77187b8099 100755 --- a/Marlin/createTemperatureLookupMarlin.py +++ b/Marlin/createTemperatureLookupMarlin.py @@ -134,7 +134,7 @@ def main(argv): temps = range(max_temp, min_temp + tmp, tmp); print "// Thermistor lookup table for Marlin" - print "// ./createTemperatureLookup.py --rp=%s --t1=%s:%s --t2=%s:%s --t3=%s:%s --num-temps=%s" % (rp, t1, r1, t2, r2, t3, r3, num_temps) + print "// ./createTemperatureLookupMarlin.py --rp=%s --t1=%s:%s --t2=%s:%s --t3=%s:%s --num-temps=%s" % (rp, t1, r1, t2, r2, t3, r3, num_temps) print "// Steinhart-Hart Coefficients: %.15g, %.15g, %.15g " % (t.c1, t.c2, t.c3) print "//#define NUMTEMPS %s" % (len(temps)) print "const short temptable[NUMTEMPS][2] PROGMEM = {" From d24df7af2cd7a9fcf7ae4c28c399e6cb31b2ebb5 Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Fri, 31 Jan 2014 00:54:19 -0800 Subject: [PATCH 121/256] M200 implementation --- Marlin/Marlin.h | 1 + Marlin/Marlin_main.cpp | 35 +++++++++++++++++++++++++++++++++++ Marlin/language.h | 9 +++++++++ Marlin/planner.cpp | 3 ++- 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index af3325be41..57d0c04b3f 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -202,6 +202,7 @@ extern float homing_feedrate[]; extern bool axis_relative_modes[]; extern int feedmultiply; extern int extrudemultiply; // Sets extrude multiply factor (in percent) +extern float filament_area[EXTRUDERS]; // cross-sectional area of filament (in cubic millimeters) extern float current_position[NUM_AXIS] ; extern float add_homeing[3]; #ifdef DELTA diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 920aed00c4..065abf1030 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -188,6 +188,14 @@ bool axis_relative_modes[] = AXIS_RELATIVE_MODES; int feedmultiply=100; //100->1 200->2 int saved_feedmultiply; int extrudemultiply=100; //100->1 200->2 +float filament_area[EXTRUDERS] = {1.0 + #if EXTRUDERS > 1 + , 1.0 + #if EXTRUDERS > 2 + , 1.0 + #endif + #endif +}; float current_position[NUM_AXIS] = { 0.0, 0.0, 0.0, 0.0 }; float add_homeing[3]={0,0,0}; #ifdef DELTA @@ -2190,6 +2198,33 @@ void process_commands() } break; #endif //BLINKM + case 200: // M200 S set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters). + { + float area; + if(code_seen('S')) { + float radius = code_value() / 2; + if(radius == 0) { + area = 1; + } else { + area = M_PI * pow(radius, 2); + } + } else { + //reserved for setting filament diameter via UFID or filament measuring device + break; + } + tmp_extruder = active_extruder; + if(code_seen('T')) { + tmp_extruder = code_value(); + if(tmp_extruder >= EXTRUDERS) { + SERIAL_ECHO_START; + SERIAL_ECHO(MSG_M200_INVALID_EXTRUDER); + } + SERIAL_ECHOLN(tmp_extruder); + break; + } + filament_area[tmp_extruder] = area; + } + break; case 201: // M201 for(int8_t i=0; i < NUM_AXIS; i++) { diff --git a/Marlin/language.h b/Marlin/language.h index 52b1b16059..2d97cc3522 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -163,6 +163,7 @@ #define MSG_END_FILE_LIST "End file list" #define MSG_M104_INVALID_EXTRUDER "M104 Invalid extruder " #define MSG_M105_INVALID_EXTRUDER "M105 Invalid extruder " + #define MSG_M200_INVALID_EXTRUDER "M200 Invalid extruder " #define MSG_M218_INVALID_EXTRUDER "M218 Invalid extruder " #define MSG_ERR_NO_THERMISTORS "No thermistors - no temperature" #define MSG_M109_INVALID_EXTRUDER "M109 Invalid extruder " @@ -331,6 +332,7 @@ #define MSG_END_FILE_LIST "Koniec listy plikow" #define MSG_M104_INVALID_EXTRUDER "M104 Niepoprawny ekstruder " #define MSG_M105_INVALID_EXTRUDER "M105 Niepoprawny ekstruder " + #define MSG_M200_INVALID_EXTRUDER "M200 Niepoprawny ekstruder " #define MSG_M218_INVALID_EXTRUDER "M218 Niepoprawny ekstruder " #define MSG_ERR_NO_THERMISTORS "Brak termistorow - brak temperatury :(" #define MSG_M109_INVALID_EXTRUDER "M109 Niepoprawny ekstruder " @@ -498,6 +500,7 @@ #define MSG_END_FILE_LIST "Fin de la liste de fichiers" #define MSG_M104_INVALID_EXTRUDER "M104 Extruder invalide" #define MSG_M105_INVALID_EXTRUDER "M105 Extruder invalide" + #define MSG_M200_INVALID_EXTRUDER "M200 Extruder invalide" #define MSG_M218_INVALID_EXTRUDER "M218 Extruder invalide" #define MSG_ERR_NO_THERMISTORS "Pas de thermistor, pas de temperature" #define MSG_M109_INVALID_EXTRUDER "M109 Extruder invalide " @@ -668,6 +671,7 @@ #define MSG_END_FILE_LIST "End file list" #define MSG_M104_INVALID_EXTRUDER "M104 Invalid extruder " #define MSG_M105_INVALID_EXTRUDER "M105 Invalid extruder " + #define MSG_M200_INVALID_EXTRUDER "M200 Invalid extruder " #define MSG_M218_INVALID_EXTRUDER "M218 Invalid extruder " #define MSG_ERR_NO_THERMISTORS "No thermistors - no temp" #define MSG_M109_INVALID_EXTRUDER "M109 Invalid extruder " @@ -842,6 +846,7 @@ #define MSG_END_FILE_LIST "Fin de la lista de archivos" #define MSG_M104_INVALID_EXTRUDER "M104 Extrusor Invalido " #define MSG_M105_INVALID_EXTRUDER "M105 Extrusor Invalido " + #define MSG_M200_INVALID_EXTRUDER "M200 Extrusor Invalido " #define MSG_M218_INVALID_EXTRUDER "M218 Extrusor Invalido " #define MSG_ERR_NO_THERMISTORS "No hay termistores - no temp" #define MSG_M109_INVALID_EXTRUDER "M109 Extrusor Invalido " @@ -1006,6 +1011,7 @@ #define MSG_END_FILE_LIST "Конец списка файлов" #define MSG_M104_INVALID_EXTRUDER "M104 ошибка экструдера " #define MSG_M105_INVALID_EXTRUDER "M105 ошибка экструдера " + #define MSG_M200_INVALID_EXTRUDER "M200 ошибка экструдера " #define MSG_M218_INVALID_EXTRUDER "M218 ошибка экструдера " #define MSG_ERR_NO_THERMISTORS "Нет термистра - нет температуры" #define MSG_M109_INVALID_EXTRUDER "M109 ошибка экструдера " @@ -1170,6 +1176,7 @@ #define MSG_END_FILE_LIST "Fine Lista File" #define MSG_M104_INVALID_EXTRUDER "M104 Estrusore non valido " #define MSG_M105_INVALID_EXTRUDER "M105 Estrusore non valido " + #define MSG_M200_INVALID_EXTRUDER "M200 Estrusore non valido " #define MSG_M218_INVALID_EXTRUDER "M218 Estrusore non valido " #define MSG_ERR_NO_THERMISTORS "Nessun Termistore - nessuna temperatura" #define MSG_M109_INVALID_EXTRUDER "M109 Estrusore non valido " @@ -1343,6 +1350,7 @@ #define MSG_END_FILE_LIST "Fim da lista de arquivos" #define MSG_M104_INVALID_EXTRUDER "M104 Extrusor inválido " #define MSG_M105_INVALID_EXTRUDER "M105 Extrusor inválido " + #define MSG_M200_INVALID_EXTRUDER "M200 Extrusor inválido " #define MSG_M218_INVALID_EXTRUDER "M218 Extrusor inválido " #define MSG_ERR_NO_THERMISTORS "Nao ha termistor - no temp" #define MSG_M109_INVALID_EXTRUDER "M109 Extrusor inválido " @@ -1512,6 +1520,7 @@ #define MSG_END_FILE_LIST "Tiedostolistauksen loppu" #define MSG_M104_INVALID_EXTRUDER "M104 Virheellinen suutin " #define MSG_M105_INVALID_EXTRUDER "M105 Virheellinen suutin " + #define MSG_M200_INVALID_EXTRUDER "M200 Virheellinen suutin " #define MSG_M218_INVALID_EXTRUDER "M218 Virheellinen suutin " #define MSG_ERR_NO_THERMISTORS "Ei termistoreja - ei lampotiloja" #define MSG_M109_INVALID_EXTRUDER "M109 Virheellinen suutin " diff --git a/Marlin/planner.cpp b/Marlin/planner.cpp index a9da533c77..00693d84a7 100644 --- a/Marlin/planner.cpp +++ b/Marlin/planner.cpp @@ -593,6 +593,7 @@ block->steps_y = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-positi #endif block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]); block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); + block->steps_e *= filament_area[active_extruder]; block->steps_e *= extrudemultiply; block->steps_e /= 100; block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); @@ -682,7 +683,7 @@ block->steps_y = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-positi delta_mm[Y_AXIS] = ((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-position[Y_AXIS]))/axis_steps_per_unit[Y_AXIS]; #endif delta_mm[Z_AXIS] = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]; - delta_mm[E_AXIS] = ((target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS])*extrudemultiply/100.0; + delta_mm[E_AXIS] = ((target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS])*filament_area[active_extruder]*extrudemultiply/100.0; if ( block->steps_x <=dropsegments && block->steps_y <=dropsegments && block->steps_z <=dropsegments ) { block->millimeters = fabs(delta_mm[E_AXIS]); From 856edfcc0d844800b887b3b2eaca78ac337656af Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Fri, 31 Jan 2014 08:43:11 -0800 Subject: [PATCH 122/256] Fixed math This is why I wanted to sleep on the code I wrote while falling asleep rather than immediately submitting a pull request. --- Marlin/Marlin.h | 2 +- Marlin/Marlin_main.cpp | 4 ++-- Marlin/planner.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index 57d0c04b3f..6b54aafb6c 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -202,7 +202,7 @@ extern float homing_feedrate[]; extern bool axis_relative_modes[]; extern int feedmultiply; extern int extrudemultiply; // Sets extrude multiply factor (in percent) -extern float filament_area[EXTRUDERS]; // cross-sectional area of filament (in cubic millimeters) +extern float volumetric_multiplier[EXTRUDERS]; // reciprocal of cross-sectional area of filament (in square millimeters), stored this way to reduce computational burden in planner extern float current_position[NUM_AXIS] ; extern float add_homeing[3]; #ifdef DELTA diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 065abf1030..b5e4e85193 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -188,7 +188,7 @@ bool axis_relative_modes[] = AXIS_RELATIVE_MODES; int feedmultiply=100; //100->1 200->2 int saved_feedmultiply; int extrudemultiply=100; //100->1 200->2 -float filament_area[EXTRUDERS] = {1.0 +float volumetric_multiplier[EXTRUDERS] = {1.0 #if EXTRUDERS > 1 , 1.0 #if EXTRUDERS > 2 @@ -2222,7 +2222,7 @@ void process_commands() SERIAL_ECHOLN(tmp_extruder); break; } - filament_area[tmp_extruder] = area; + volumetric_multiplier[tmp_extruder] = 1 / area; } break; case 201: // M201 diff --git a/Marlin/planner.cpp b/Marlin/planner.cpp index 00693d84a7..bfc71323fe 100644 --- a/Marlin/planner.cpp +++ b/Marlin/planner.cpp @@ -593,7 +593,7 @@ block->steps_y = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-positi #endif block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]); block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); - block->steps_e *= filament_area[active_extruder]; + block->steps_e *= volumetric_multiplier[active_extruder]; block->steps_e *= extrudemultiply; block->steps_e /= 100; block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); @@ -683,7 +683,7 @@ block->steps_y = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-positi delta_mm[Y_AXIS] = ((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-position[Y_AXIS]))/axis_steps_per_unit[Y_AXIS]; #endif delta_mm[Z_AXIS] = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS]; - delta_mm[E_AXIS] = ((target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS])*filament_area[active_extruder]*extrudemultiply/100.0; + delta_mm[E_AXIS] = ((target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS])*volumetric_multiplier[active_extruder]*extrudemultiply/100.0; if ( block->steps_x <=dropsegments && block->steps_y <=dropsegments && block->steps_z <=dropsegments ) { block->millimeters = fabs(delta_mm[E_AXIS]); From 28aca76c4d6fcc59e5c26cb04fb29e202b33da67 Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Sat, 1 Feb 2014 12:22:37 -0800 Subject: [PATCH 123/256] Group hardware files for Arduino 1.x.x into hardware folder --- .../{ => hardware}/Sanguino/boards.txt | 0 .../Sanguino/bootloaders/atmega/ATmegaBOOT_168.c | 0 .../atmega/ATmegaBOOT_168_atmega1284p.hex | 0 .../atmega/ATmegaBOOT_168_atmega1284p_8m.hex | 0 .../atmega/ATmegaBOOT_168_atmega644p.hex | 0 .../Sanguino/bootloaders/atmega/Makefile | 0 .../Sanguino/bootloaders/atmega644p/ATmegaBOOT.c | 0 .../bootloaders/atmega644p/ATmegaBOOT.c.tst | 0 .../bootloaders/atmega644p/ATmegaBOOT_644P.elf | Bin .../bootloaders/atmega644p/ATmegaBOOT_644P.hex | 0 .../Sanguino/bootloaders/atmega644p/Makefile | 0 .../Sanguino/bootloaders/atmega644p/README.txt | 0 .../{ => hardware}/Sanguino/cores/arduino/Arduino.h | 0 .../{ => hardware}/Sanguino/cores/arduino/CDC.cpp | 0 .../{ => hardware}/Sanguino/cores/arduino/Client.h | 0 .../{ => hardware}/Sanguino/cores/arduino/HID.cpp | 0 .../Sanguino/cores/arduino/HardwareSerial.cpp | 0 .../Sanguino/cores/arduino/HardwareSerial.h | 0 .../Sanguino/cores/arduino/IPAddress.cpp | 0 .../Sanguino/cores/arduino/IPAddress.h | 0 .../Sanguino/cores/arduino/Platform.h | 0 .../{ => hardware}/Sanguino/cores/arduino/Print.cpp | 0 .../{ => hardware}/Sanguino/cores/arduino/Print.h | 0 .../Sanguino/cores/arduino/Printable.h | 0 .../{ => hardware}/Sanguino/cores/arduino/Server.h | 0 .../Sanguino/cores/arduino/Stream.cpp | 0 .../{ => hardware}/Sanguino/cores/arduino/Stream.h | 0 .../{ => hardware}/Sanguino/cores/arduino/Tone.cpp | 0 .../{ => hardware}/Sanguino/cores/arduino/USBAPI.h | 0 .../Sanguino/cores/arduino/USBCore.cpp | 0 .../{ => hardware}/Sanguino/cores/arduino/USBCore.h | 0 .../{ => hardware}/Sanguino/cores/arduino/USBDesc.h | 0 .../{ => hardware}/Sanguino/cores/arduino/Udp.h | 0 .../Sanguino/cores/arduino/WCharacter.h | 0 .../Sanguino/cores/arduino/WInterrupts.c | 0 .../{ => hardware}/Sanguino/cores/arduino/WMath.cpp | 0 .../Sanguino/cores/arduino/WString.cpp | 0 .../{ => hardware}/Sanguino/cores/arduino/WString.h | 0 .../{ => hardware}/Sanguino/cores/arduino/binary.h | 0 .../{ => hardware}/Sanguino/cores/arduino/main.cpp | 0 .../{ => hardware}/Sanguino/cores/arduino/new.cpp | 0 .../{ => hardware}/Sanguino/cores/arduino/new.h | 0 .../{ => hardware}/Sanguino/cores/arduino/wiring.c | 0 .../Sanguino/cores/arduino/wiring_analog.c | 0 .../Sanguino/cores/arduino/wiring_digital.c | 0 .../Sanguino/cores/arduino/wiring_private.h | 0 .../Sanguino/cores/arduino/wiring_pulse.c | 0 .../Sanguino/cores/arduino/wiring_shift.c | 0 .../Sanguino/variants/standard/pins_arduino.h | 0 .../Arduino_1.x.x/{ => hardware}/rambo/boards.txt | 0 .../{ => hardware}/rambo/cores/arduino/Arduino.h | 0 .../{ => hardware}/rambo/cores/arduino/CDC.cpp | 0 .../{ => hardware}/rambo/cores/arduino/Client.h | 0 .../{ => hardware}/rambo/cores/arduino/HID.cpp | 0 .../rambo/cores/arduino/HardwareSerial.cpp | 0 .../rambo/cores/arduino/HardwareSerial.h | 0 .../rambo/cores/arduino/IPAddress.cpp | 0 .../{ => hardware}/rambo/cores/arduino/IPAddress.h | 0 .../{ => hardware}/rambo/cores/arduino/Platform.h | 0 .../{ => hardware}/rambo/cores/arduino/Print.cpp | 0 .../{ => hardware}/rambo/cores/arduino/Print.h | 0 .../{ => hardware}/rambo/cores/arduino/Printable.h | 0 .../{ => hardware}/rambo/cores/arduino/Server.h | 0 .../{ => hardware}/rambo/cores/arduino/Stream.cpp | 0 .../{ => hardware}/rambo/cores/arduino/Stream.h | 0 .../{ => hardware}/rambo/cores/arduino/Tone.cpp | 0 .../{ => hardware}/rambo/cores/arduino/USBAPI.h | 0 .../{ => hardware}/rambo/cores/arduino/USBCore.cpp | 0 .../{ => hardware}/rambo/cores/arduino/USBCore.h | 0 .../{ => hardware}/rambo/cores/arduino/USBDesc.h | 0 .../{ => hardware}/rambo/cores/arduino/Udp.h | 0 .../{ => hardware}/rambo/cores/arduino/WCharacter.h | 0 .../rambo/cores/arduino/WInterrupts.c | 0 .../{ => hardware}/rambo/cores/arduino/WMath.cpp | 0 .../{ => hardware}/rambo/cores/arduino/WString.cpp | 0 .../{ => hardware}/rambo/cores/arduino/WString.h | 0 .../{ => hardware}/rambo/cores/arduino/binary.h | 0 .../{ => hardware}/rambo/cores/arduino/main.cpp | 0 .../{ => hardware}/rambo/cores/arduino/new.cpp | 0 .../{ => hardware}/rambo/cores/arduino/new.h | 0 .../{ => hardware}/rambo/cores/arduino/wiring.c | 0 .../rambo/cores/arduino/wiring_analog.c | 0 .../rambo/cores/arduino/wiring_digital.c | 0 .../rambo/cores/arduino/wiring_private.h | 0 .../rambo/cores/arduino/wiring_pulse.c | 0 .../rambo/cores/arduino/wiring_shift.c | 0 .../rambo/variants/standard/pins_arduino.h | 0 87 files changed, 0 insertions(+), 0 deletions(-) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/boards.txt (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/bootloaders/atmega/ATmegaBOOT_168.c (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p.hex (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p_8m.hex (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega644p.hex (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/bootloaders/atmega/Makefile (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/bootloaders/atmega644p/ATmegaBOOT.c (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/bootloaders/atmega644p/ATmegaBOOT.c.tst (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.elf (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.hex (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/bootloaders/atmega644p/Makefile (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/bootloaders/atmega644p/README.txt (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/Arduino.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/CDC.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/Client.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/HID.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/HardwareSerial.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/HardwareSerial.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/IPAddress.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/IPAddress.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/Platform.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/Print.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/Print.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/Printable.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/Server.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/Stream.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/Stream.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/Tone.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/USBAPI.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/USBCore.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/USBCore.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/USBDesc.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/Udp.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/WCharacter.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/WInterrupts.c (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/WMath.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/WString.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/WString.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/binary.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/main.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/new.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/new.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/wiring.c (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/wiring_analog.c (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/wiring_digital.c (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/wiring_private.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/wiring_pulse.c (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/cores/arduino/wiring_shift.c (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/Sanguino/variants/standard/pins_arduino.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/boards.txt (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/Arduino.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/CDC.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/Client.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/HID.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/HardwareSerial.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/HardwareSerial.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/IPAddress.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/IPAddress.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/Platform.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/Print.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/Print.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/Printable.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/Server.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/Stream.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/Stream.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/Tone.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/USBAPI.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/USBCore.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/USBCore.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/USBDesc.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/Udp.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/WCharacter.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/WInterrupts.c (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/WMath.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/WString.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/WString.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/binary.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/main.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/new.cpp (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/new.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/wiring.c (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/wiring_analog.c (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/wiring_digital.c (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/wiring_private.h (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/wiring_pulse.c (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/cores/arduino/wiring_shift.c (100%) rename ArduinoAddons/Arduino_1.x.x/{ => hardware}/rambo/variants/standard/pins_arduino.h (100%) diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/boards.txt b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/boards.txt similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/boards.txt rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/boards.txt diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/ATmegaBOOT_168.c b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega/ATmegaBOOT_168.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/ATmegaBOOT_168.c rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega/ATmegaBOOT_168.c diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p.hex b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p.hex similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p.hex rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p.hex diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p_8m.hex b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p_8m.hex similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p_8m.hex rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega1284p_8m.hex diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega644p.hex b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega644p.hex similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega644p.hex rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega/ATmegaBOOT_168_atmega644p.hex diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/Makefile b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega/Makefile similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega/Makefile rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega/Makefile diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/ATmegaBOOT.c b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega644p/ATmegaBOOT.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/ATmegaBOOT.c rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega644p/ATmegaBOOT.c diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/ATmegaBOOT.c.tst b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega644p/ATmegaBOOT.c.tst similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/ATmegaBOOT.c.tst rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega644p/ATmegaBOOT.c.tst diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.elf b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.elf similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.elf rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.elf diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.hex b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.hex similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.hex rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega644p/ATmegaBOOT_644P.hex diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/Makefile b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega644p/Makefile similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/Makefile rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega644p/Makefile diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/README.txt b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega644p/README.txt similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/bootloaders/atmega644p/README.txt rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/bootloaders/atmega644p/README.txt diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Arduino.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Arduino.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Arduino.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Arduino.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/CDC.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/CDC.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/CDC.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/CDC.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Client.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Client.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Client.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Client.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/HID.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/HID.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/HID.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/HID.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/HardwareSerial.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/HardwareSerial.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/HardwareSerial.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/HardwareSerial.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/HardwareSerial.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/HardwareSerial.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/HardwareSerial.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/HardwareSerial.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/IPAddress.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/IPAddress.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/IPAddress.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/IPAddress.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/IPAddress.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/IPAddress.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/IPAddress.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/IPAddress.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Platform.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Platform.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Platform.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Platform.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Print.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Print.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Print.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Print.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Print.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Print.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Print.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Print.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Printable.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Printable.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Printable.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Printable.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Server.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Server.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Server.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Server.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Stream.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Stream.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Stream.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Stream.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Stream.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Stream.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Stream.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Stream.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Tone.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Tone.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Tone.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Tone.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/USBAPI.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/USBAPI.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/USBAPI.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/USBAPI.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/USBCore.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/USBCore.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/USBCore.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/USBCore.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/USBCore.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/USBCore.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/USBCore.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/USBCore.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/USBDesc.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/USBDesc.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/USBDesc.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/USBDesc.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Udp.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Udp.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/Udp.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/Udp.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WCharacter.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/WCharacter.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WCharacter.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/WCharacter.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WInterrupts.c b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/WInterrupts.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WInterrupts.c rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/WInterrupts.c diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WMath.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/WMath.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WMath.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/WMath.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WString.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/WString.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WString.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/WString.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WString.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/WString.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/WString.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/WString.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/binary.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/binary.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/binary.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/binary.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/main.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/main.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/main.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/main.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/new.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/new.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/new.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/new.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/new.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/new.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/new.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/new.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring.c b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/wiring.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring.c rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/wiring.c diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_analog.c b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/wiring_analog.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_analog.c rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/wiring_analog.c diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_digital.c b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/wiring_digital.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_digital.c rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/wiring_digital.c diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_private.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/wiring_private.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_private.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/wiring_private.h diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_pulse.c b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/wiring_pulse.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_pulse.c rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/wiring_pulse.c diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_shift.c b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/wiring_shift.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/cores/arduino/wiring_shift.c rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/cores/arduino/wiring_shift.c diff --git a/ArduinoAddons/Arduino_1.x.x/Sanguino/variants/standard/pins_arduino.h b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/variants/standard/pins_arduino.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/Sanguino/variants/standard/pins_arduino.h rename to ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/variants/standard/pins_arduino.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/boards.txt b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/boards.txt similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/boards.txt rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/boards.txt diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Arduino.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Arduino.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Arduino.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Arduino.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/CDC.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/CDC.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/CDC.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/CDC.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Client.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Client.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Client.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Client.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HID.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/HID.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HID.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/HID.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HardwareSerial.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/HardwareSerial.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HardwareSerial.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/HardwareSerial.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HardwareSerial.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/HardwareSerial.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/HardwareSerial.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/HardwareSerial.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/IPAddress.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/IPAddress.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/IPAddress.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/IPAddress.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/IPAddress.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/IPAddress.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/IPAddress.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/IPAddress.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Platform.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Platform.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Platform.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Platform.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Print.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Print.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Print.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Print.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Print.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Print.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Print.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Print.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Printable.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Printable.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Printable.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Printable.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Server.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Server.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Server.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Server.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Stream.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Stream.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Stream.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Stream.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Stream.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Stream.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Stream.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Stream.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Tone.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Tone.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Tone.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Tone.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBAPI.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/USBAPI.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBAPI.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/USBAPI.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBCore.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/USBCore.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBCore.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/USBCore.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBCore.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/USBCore.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBCore.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/USBCore.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBDesc.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/USBDesc.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/USBDesc.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/USBDesc.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Udp.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Udp.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/Udp.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/Udp.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WCharacter.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/WCharacter.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WCharacter.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/WCharacter.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WInterrupts.c b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/WInterrupts.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WInterrupts.c rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/WInterrupts.c diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WMath.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/WMath.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WMath.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/WMath.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WString.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/WString.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WString.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/WString.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WString.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/WString.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/WString.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/WString.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/binary.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/binary.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/binary.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/binary.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/main.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/main.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/main.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/main.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/new.cpp b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/new.cpp similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/new.cpp rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/new.cpp diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/new.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/new.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/new.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/new.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring.c b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/wiring.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring.c rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/wiring.c diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_analog.c b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/wiring_analog.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_analog.c rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/wiring_analog.c diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_digital.c b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/wiring_digital.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_digital.c rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/wiring_digital.c diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_private.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/wiring_private.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_private.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/wiring_private.h diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_pulse.c b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/wiring_pulse.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_pulse.c rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/wiring_pulse.c diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_shift.c b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/wiring_shift.c similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/cores/arduino/wiring_shift.c rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/cores/arduino/wiring_shift.c diff --git a/ArduinoAddons/Arduino_1.x.x/rambo/variants/standard/pins_arduino.h b/ArduinoAddons/Arduino_1.x.x/hardware/rambo/variants/standard/pins_arduino.h similarity index 100% rename from ArduinoAddons/Arduino_1.x.x/rambo/variants/standard/pins_arduino.h rename to ArduinoAddons/Arduino_1.x.x/hardware/rambo/variants/standard/pins_arduino.h From b2c11ba980f3004550ab7317c849e029370682b1 Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Sat, 1 Feb 2014 18:49:25 -0800 Subject: [PATCH 124/256] Change diameter code to 'D' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For some reason that I can’t figure out, the decimal is dropped when using ’S’ for the code. Also some minor code improvements to M200. --- Marlin/Marlin_main.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index b5e4e85193..d33f0ff548 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -130,7 +130,7 @@ // M150 - Set BlinkM Colour Output R: Red<0-255> U(!): Green<0-255> B: Blue<0-255> over i2c, G for green does not work. // M190 - Sxxx Wait for bed current temp to reach target temp. Waits only when heating // Rxxx Wait for bed current temp to reach target temp. Waits when heating and cooling -// M200 - Set filament diameter +// M200 D- set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters). // M201 - Set max acceleration in units/s^2 for print moves (M201 X1000 Y1000) // M202 - Set max acceleration in units/s^2 for travel moves (M202 X1000 Y1000) Unused in Marlin!! // M203 - Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in mm/sec @@ -2198,11 +2198,12 @@ void process_commands() } break; #endif //BLINKM - case 200: // M200 S set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters). + case 200: // M200 D set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters). { - float area; - if(code_seen('S')) { - float radius = code_value() / 2; + float area = .0; + float radius = .0; + if(code_seen('D')) { + radius = (float)code_value() * .5; if(radius == 0) { area = 1; } else { From f303129fb62159caefa8d151b56c7a2194a65fb5 Mon Sep 17 00:00:00 2001 From: Ronald Date: Sun, 2 Feb 2014 13:13:15 +0000 Subject: [PATCH 125/256] Changed 1284p fuse setting for 8, 16 and 20 Mhz Symtopns: - X axis move in one direction - limit switches fail to trigger - unable to reprogram the device via bootloader - stops working when the reset switch is pressed. - device fails to bootup when power by a slow raise power supply. Solution: - Disabled the jtag - set the correct clock selection bit - set the correct bootloader memory size - enable brown-out setting - enable clock power up delay --- ArduinoAddons/Arduino_0.xx/Sanguino/boards.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ArduinoAddons/Arduino_0.xx/Sanguino/boards.txt b/ArduinoAddons/Arduino_0.xx/Sanguino/boards.txt index f18a5ffa30..4e4d214b15 100644 --- a/ArduinoAddons/Arduino_0.xx/Sanguino/boards.txt +++ b/ArduinoAddons/Arduino_0.xx/Sanguino/boards.txt @@ -44,9 +44,9 @@ atmega12848m.upload.protocol=stk500 atmega12848m.upload.maximum_size=131072 atmega12848m.upload.speed=19200 -atmega12848m.bootloader.low_fuses=0xFD -atmega12848m.bootloader.high_fuses=0x9A -atmega12848m.bootloader.extended_fuses=0xFF +atmega12848m.bootloader.low_fuses=0xD6 +atmega12848m.bootloader.high_fuses=0xDA +atmega12848m.bootloader.extended_fuses=0xFD atmega12848m.bootloader.path=atmega atmega12848m.bootloader.file=ATmegaBOOT_168_atmega1284p_8m.hex atmega12848m.bootloader.unlock_bits=0x3F @@ -64,9 +64,9 @@ atmega1284.upload.protocol=stk500 atmega1284.upload.maximum_size=131072 atmega1284.upload.speed=57600 -atmega1284.bootloader.low_fuses=0xFF -atmega1284.bootloader.high_fuses=0x9A -atmega1284.bootloader.extended_fuses=0xFF +atmega1284.bootloader.low_fuses=0xD6 +atmega1284.bootloader.high_fuses=0xDA +atmega1284.bootloader.extended_fuses=0xFD atmega1284.bootloader.path=atmega atmega1284.bootloader.file=ATmegaBOOT_168_atmega1284p.hex atmega1284.bootloader.unlock_bits=0x3F @@ -85,9 +85,9 @@ atmega1284s.upload.protocol=stk500 atmega1284s.upload.maximum_size=131072 atmega1284s.upload.speed=57600 -atmega1284s.bootloader.low_fuses=0xFF -atmega1284s.bootloader.high_fuses=0x9A -atmega1284s.bootloader.extended_fuses=0xFF +atmega1284s.bootloader.low_fuses=0xD6 +atmega1284s.bootloader.high_fuses=0xDA +atmega1284s.bootloader.extended_fuses=0xFD atmega1284s.bootloader.path=atmega atmega1284s.bootloader.file=ATmegaBOOT_168_atmega1284p.hex atmega1284s.bootloader.unlock_bits=0x3F From 8d162e5bd75ef221dc79a5cf79f9db3185345591 Mon Sep 17 00:00:00 2001 From: Ronald Date: Mon, 3 Feb 2014 07:45:03 +0000 Subject: [PATCH 126/256] Improved support for panelolu2 encoder and buzzer I added #define for LCD_FEEDBACK_FREQUENCY_HZ and LCD_FEEDBACK_FREQUENCY_DURATION_MS which is used to alter the default buzzer sound. When selecting Panelolu2 in configuration.h: - it automatically sets the correct ENCODER_PULSES_PER_STEP and ENCODER_STEPS_PER_MENU_ITEM. - if LCD_USE_I2C_BUZZER is defined it will also set the default LCD_FEEDBACK_FREQUENCY_HZ and LCD_FEEDBACK_FREQUENCY_DURATION_MS When selecting the sanguinololu 1284p the following is true: - its now enables LARGE_FLASH - It enables the gcode M300 when the panelolu2 LCD_USE_I2C_BUZZER is defined --- Marlin/Configuration.h | 17 +++++++++++++++++ Marlin/Marlin_main.cpp | 12 +++++++++--- Marlin/pins.h | 4 ++++ .../ultralcd_implementation_hitachi_HD44780.h | 6 +++++- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 1da62fc2ad..1dd76d4116 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -447,6 +447,8 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of //#define ENCODER_STEPS_PER_MENU_ITEM 5 // Set according to ENCODER_PULSES_PER_STEP or your liking //#define ULTIMAKERCONTROLLER //as available from the ultimaker online store. //#define ULTIPANEL //the ultipanel as on thingiverse +//#define LCD_FEEDBACK_FREQUENCY_HZ 1000 // this is the tone frequency the buzzer plays when on UI feedback. ie Screen Click +//#define LCD_FEEDBACK_FREQUENCY_DURATION_MS 100 // the duration the buzzer plays the UI feedback sound. ie Screen Click // The MaKr3d Makr-Panel with graphic controller and SD support // http://reprap.org/wiki/MaKr3d_MaKrPanel @@ -532,6 +534,21 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #define LCD_USE_I2C_BUZZER //comment out to disable buzzer on LCD #define NEWPANEL #define ULTIPANEL + + #ifndef ENCODER_PULSES_PER_STEP + #define ENCODER_PULSES_PER_STEP 4 + #endif + + #ifndef ENCODER_STEPS_PER_MENU_ITEM + #define ENCODER_STEPS_PER_MENU_ITEM 1 + #endif + + + #ifdef LCD_USE_I2C_BUZZER + #define LCD_FEEDBACK_FREQUENCY_HZ 1000 + #define LCD_FEEDBACK_FREQUENCY_DURATION_MS 100 + #endif + #endif // Panucatt VIKI LCD with status LEDs, integrated click & L/R/U/P buttons, separate encoder inputs diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index b5e4e85193..cc0c64a1f1 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -2466,7 +2466,7 @@ void process_commands() break; #endif // NUM_SERVOS > 0 - #if LARGE_FLASH == true && ( BEEPER > 0 || defined(ULTRALCD) ) + #if (LARGE_FLASH == true && ( BEEPER > 0 || defined(ULTRALCD) || defined(LCD_USE_I2C_BUZZER))) case 300: // M300 { int beepS = code_seen('S') ? code_value() : 110; @@ -2478,7 +2478,9 @@ void process_commands() delay(beepP); noTone(BEEPER); #elif defined(ULTRALCD) - lcd_buzz(beepS, beepP); + lcd_buzz(beepS, beepP); + #elif defined(LCD_USE_I2C_BUZZER) + lcd_buzz(beepP, beepS); #endif } else @@ -2736,7 +2738,11 @@ void process_commands() WRITE(BEEPER,LOW); delay(3); #else - lcd_buzz(1000/6,100); + #if !defined(LCD_FEEDBACK_FREQUENCY_HZ) || !defined(LCD_FEEDBACK_FREQUENCY_DURATION_MS) + lcd_buzz(1000/6,100); + #else + lcd_buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS,LCD_FEEDBACK_FREQUENCY_HZ); + #endif #endif } } diff --git a/Marlin/pins.h b/Marlin/pins.h index d896bca2eb..1576d529bb 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -971,6 +971,10 @@ #undef MOTHERBOARD #define MOTHERBOARD 6 #define SANGUINOLOLU_V_1_2 + +#if defined(__AVR_ATmega1284P__) + #define LARGE_FLASH true +#endif #endif #if MOTHERBOARD == 6 #define KNOWN_BOARD 1 diff --git a/Marlin/ultralcd_implementation_hitachi_HD44780.h b/Marlin/ultralcd_implementation_hitachi_HD44780.h index c0d4989c3b..afc9c5c476 100644 --- a/Marlin/ultralcd_implementation_hitachi_HD44780.h +++ b/Marlin/ultralcd_implementation_hitachi_HD44780.h @@ -711,7 +711,11 @@ static void lcd_implementation_drawmenu_sddirectory(uint8_t row, const char* pst static void lcd_implementation_quick_feedback() { #ifdef LCD_USE_I2C_BUZZER - lcd.buzz(60,1000/6); + #if !defined(LCD_FEEDBACK_FREQUENCY_HZ) || !defined(LCD_FEEDBACK_FREQUENCY_DURATION_MS) + lcd_buzz(1000/6,100); + #else + lcd_buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS,LCD_FEEDBACK_FREQUENCY_HZ); + #endif #elif defined(BEEPER) && BEEPER > -1 SET_OUTPUT(BEEPER); for(int8_t i=0;i<10;i++) From c2b3e88787c00476d00ec897d9337d80183d93f8 Mon Sep 17 00:00:00 2001 From: Ronald Date: Mon, 3 Feb 2014 15:35:23 +0000 Subject: [PATCH 127/256] Changed 1284p fuse setting for Arduino_1.x.x - Remove the two version of 16mHz. Crystal and resonator use the same fuse setting. Also, Arduino IDE only showed the first one 16Mhz as a board option. - Added 20Mhz board option. Symptoms for incorrect fuse setting: - X axis move in one direction - limit switches fail to trigger - unable to reprogram the device via bootloader - stops working when the reset switch is pressed. - device fails to bootup when power by a slow raise power supply. Solution: - Disabled the jtag - set the correct clock selection bit - set the correct bootloader memory size - enable brown-out setting - enable clock power up delay --- .../hardware/Sanguino/boards.txt | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/boards.txt b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/boards.txt index c1a1f08ab6..2bec14eab3 100644 --- a/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/boards.txt +++ b/ArduinoAddons/Arduino_1.x.x/hardware/Sanguino/boards.txt @@ -27,9 +27,9 @@ atmega12848m.upload.protocol=stk500 atmega12848m.upload.maximum_size=131072 atmega12848m.upload.speed=19200 -atmega12848m.bootloader.low_fuses=0xFD -atmega12848m.bootloader.high_fuses=0x9A -atmega12848m.bootloader.extended_fuses=0xFF +atmega1284.bootloader.low_fuses=0xD6 +atmega1284.bootloader.high_fuses=0xDA +atmega1284.bootloader.extended_fuses=0xFD atmega12848m.bootloader.path=atmega atmega12848m.bootloader.file=ATmegaBOOT_168_atmega1284p_8m.hex atmega12848m.bootloader.unlock_bits=0x3F @@ -48,9 +48,9 @@ atmega1284.upload.protocol=stk500 atmega1284.upload.maximum_size=131072 atmega1284.upload.speed=57600 -atmega1284.bootloader.low_fuses=0xFF -atmega1284.bootloader.high_fuses=0x9A -atmega1284.bootloader.extended_fuses=0xFF +atmega1284.bootloader.low_fuses=0xD6 +atmega1284.bootloader.high_fuses=0xDA +atmega1284.bootloader.extended_fuses=0xFD atmega1284.bootloader.path=atmega atmega1284.bootloader.file=ATmegaBOOT_168_atmega1284p.hex atmega1284.bootloader.unlock_bits=0x3F @@ -60,26 +60,24 @@ atmega1284.build.mcu=atmega1284p atmega1284.build.f_cpu=16000000L atmega1284.build.core=arduino atmega1284.build.variant=standard -# - ############################################################## -atmega1284.name=Sanguino W/ ATmega1284p 16mhz ceramic resonator +atmega1284m.name=Sanguino W/ ATmega1284p 20mhz -atmega1284.upload.protocol=stk500 -atmega1284.upload.maximum_size=131072 -atmega1284.upload.speed=57600 +atmega1284m.upload.protocol=stk500 +atmega1284m.upload.maximum_size=131072 +atmega1284m.upload.speed=57600 -atmega1284.bootloader.low_fuses=0xD6 -atmega1284.bootloader.high_fuses=0xDC -atmega1284.bootloader.extended_fuses=0xFD -atmega1284.bootloader.path=atmega -atmega1284.bootloader.file=ATmegaBOOT_168_atmega1284p.hex -atmega1284.bootloader.unlock_bits=0x3F -atmega1284.bootloader.lock_bits=0x0F +atmega1284m.bootloader.low_fuses=0xD6 +atmega1284m.bootloader.high_fuses=0xDA +atmega1284m.bootloader.extended_fuses=0xFD +atmega1284m.bootloader.path=atmega +atmega1284m.bootloader.file=ATmegaBOOT_168_atmega1284p.hex +atmega1284m.bootloader.unlock_bits=0x3F +atmega1284m.bootloader.lock_bits=0x0F -atmega1284.build.mcu=atmega1284p -atmega1284.build.f_cpu=16000000L -atmega1284.build.core=arduino -atmega1284.build.variant=standard +atmega1284m.build.mcu=atmega1284p +atmega1284m.build.f_cpu=20000000L +atmega1284m.build.core=arduino +atmega1284m.build.variant=standard # From a5f53f0cf31fe8650ea25e274ee6b206ff01d930 Mon Sep 17 00:00:00 2001 From: David Forrest Date: Mon, 3 Feb 2014 14:46:09 -0500 Subject: [PATCH 128/256] Heater wattage reporting for M105 using EXTRUDER_WATTS and BED_WATTS --- Marlin/Configuration.h | 4 ++++ Marlin/Marlin_main.cpp | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 1da62fc2ad..fe03e03186 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -156,6 +156,10 @@ // HEATER_BED_DUTY_CYCLE_DIVIDER intervals. //#define HEATER_BED_DUTY_CYCLE_DIVIDER 4 +// If you want the M105 heater power reported in watts, define the BED_WATTS, and (shared for all extruders) EXTRUDER_WATTS +//#define EXTRUDER_WATTS (12.0*12.0/6.7) // P=I^2/R +//#define BED_WATTS (12.0*12.0/1.1) // P=I^2/R + // PID settings: // Comment the following line to disable PID and enable bang-bang. #define PIDTEMP diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index d33f0ff548..aecaf1275b 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1816,10 +1816,20 @@ void process_commands() #endif SERIAL_PROTOCOLPGM(" @:"); + #ifdef EXTRUDER_WATTS + SERIAL_PROTOCOL((EXTRUDER_WATTS * getHeaterPower(tmp_extruder))/127); + SERIAL_PROTOCOLPGM("W"); + #else SERIAL_PROTOCOL(getHeaterPower(tmp_extruder)); + #endif SERIAL_PROTOCOLPGM(" B@:"); + #ifdef BED_WATTS + SERIAL_PROTOCOL((BED_WATTS * getHeaterPower(-1))/127); + SERIAL_PROTOCOLPGM("W"); + #else SERIAL_PROTOCOL(getHeaterPower(-1)); + #endif #ifdef SHOW_TEMP_ADC_VALUES #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1 From b819fc53caf66bd4610dc05301c8b9fbe39ced98 Mon Sep 17 00:00:00 2001 From: Jim Morris Date: Wed, 5 Feb 2014 01:47:12 -0800 Subject: [PATCH 129/256] Add Azteeg X3 Pro as motherboard 68 Add digipot i2c control for MCP4451 Allow M907 to set i2c digipot currents in amps Fix Makefile to allow Azteeg motherboards Fix Makefile to allow Wire libraries only Add beeper pin for Azteeg X3 Pro --- Marlin/Configuration.h | 21 ++-- Marlin/Configuration_adv.h | 74 ++++++------ Marlin/Makefile | 28 ++++- Marlin/Marlin.h | 5 + Marlin/Marlin.ino | 14 ++- Marlin/Marlin.pde | 14 ++- Marlin/Marlin_main.cpp | 216 +++++++++++++++++---------------- Marlin/digipot_mcp4451.cpp | 54 +++++++++ Marlin/pins.h | 238 +++++++++++++++++++------------------ 9 files changed, 387 insertions(+), 277 deletions(-) create mode 100644 Marlin/digipot_mcp4451.cpp diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 8d39bd95d1..696b4ca9d6 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -52,6 +52,7 @@ // 65 = Azteeg X1 // 66 = Melzi with ATmega1284 (MaKr3d version) // 67 = Azteeg X3 +// 68 = Azteeg X3 Pro // 7 = Ultimaker // 71 = Ultimaker (Older electronics. Pre 1.5.4. This is rare) // 77 = 3Drag Controller @@ -156,8 +157,8 @@ // HEATER_BED_DUTY_CYCLE_DIVIDER intervals. //#define HEATER_BED_DUTY_CYCLE_DIVIDER 4 -// If you want the M105 heater power reported in watts, define the BED_WATTS, and (shared for all extruders) EXTRUDER_WATTS -//#define EXTRUDER_WATTS (12.0*12.0/6.7) // P=I^2/R +// If you want the M105 heater power reported in watts, define the BED_WATTS, and (shared for all extruders) EXTRUDER_WATTS +//#define EXTRUDER_WATTS (12.0*12.0/6.7) // P=I^2/R //#define BED_WATTS (12.0*12.0/1.1) // P=I^2/R // PID settings: @@ -374,12 +375,12 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of // with accurate bed leveling, the bed is sampled in a ACCURATE_BED_LEVELING_POINTSxACCURATE_BED_LEVELING_POINTS grid and least squares solution is calculated // Note: this feature occupies 10'206 byte #define ACCURATE_BED_LEVELING - + #ifdef ACCURATE_BED_LEVELING // I wouldn't see a reason to go above 3 (=9 probing points on the bed) #define ACCURATE_BED_LEVELING_POINTS 2 #endif - + #endif @@ -538,21 +539,21 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #define LCD_USE_I2C_BUZZER //comment out to disable buzzer on LCD #define NEWPANEL #define ULTIPANEL - + #ifndef ENCODER_PULSES_PER_STEP #define ENCODER_PULSES_PER_STEP 4 - #endif + #endif #ifndef ENCODER_STEPS_PER_MENU_ITEM #define ENCODER_STEPS_PER_MENU_ITEM 1 - #endif - - + #endif + + #ifdef LCD_USE_I2C_BUZZER #define LCD_FEEDBACK_FREQUENCY_HZ 1000 #define LCD_FEEDBACK_FREQUENCY_DURATION_MS 100 #endif - + #endif // Panucatt VIKI LCD with status LEDs, integrated click & L/R/U/P buttons, separate encoder inputs diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 4e5d829114..21b270b224 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -12,7 +12,7 @@ //// Heating sanity check: // This waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature -// If the temperature has not increased at the end of that period, the target temperature is set to zero. +// If the temperature has not increased at the end of that period, the target temperature is set to zero. // It can be reset with another M104/M109. This check is also only triggered if the target temperature and the current temperature // differ by at least 2x WATCH_TEMP_INCREASE //#define WATCH_TEMP_PERIOD 40000 //40 seconds @@ -21,7 +21,7 @@ #ifdef PIDTEMP // this adds an experimental additional term to the heatingpower, proportional to the extrusion speed. // if Kc is choosen well, the additional required power due to increased melting should be compensated. - #define PID_ADD_EXTRUSION_RATE + #define PID_ADD_EXTRUSION_RATE #ifdef PID_ADD_EXTRUSION_RATE #define DEFAULT_Kc (1) //heatingpower=Kc*(e_speed) #endif @@ -44,10 +44,10 @@ //The M105 command return, besides traditional information, the ADC value read from temperature sensors. //#define SHOW_TEMP_ADC_VALUES -// extruder run-out prevention. +// extruder run-out prevention. //if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded -//#define EXTRUDER_RUNOUT_PREVENT -#define EXTRUDER_RUNOUT_MINTEMP 190 +//#define EXTRUDER_RUNOUT_PREVENT +#define EXTRUDER_RUNOUT_MINTEMP 190 #define EXTRUDER_RUNOUT_SECONDS 30. #define EXTRUDER_RUNOUT_ESTEPS 14. //mm filament #define EXTRUDER_RUNOUT_SPEED 1500. //extrusion speed @@ -73,7 +73,7 @@ // Extruder cooling fans // Configure fan pin outputs to automatically turn on/off when the associated // extruder temperature is above/below EXTRUDER_AUTO_FAN_TEMPERATURE. -// Multiple extruders can be assigned to the same pin in which case +// Multiple extruders can be assigned to the same pin in which case // the fan will turn on when any selected extruder is above the threshold. #define EXTRUDER_0_AUTO_FAN_PIN -1 #define EXTRUDER_1_AUTO_FAN_PIN -1 @@ -103,14 +103,14 @@ #else #define X_HOME_POS X_MIN_POS #endif //BED_CENTER_AT_0_0 - #else + #else #ifdef BED_CENTER_AT_0_0 #define X_HOME_POS X_MAX_LENGTH * 0.5 #else #define X_HOME_POS X_MAX_POS #endif //BED_CENTER_AT_0_0 #endif //X_HOME_DIR == -1 - + //Y axis #if Y_HOME_DIR == -1 #ifdef BED_CENTER_AT_0_0 @@ -118,18 +118,18 @@ #else #define Y_HOME_POS Y_MIN_POS #endif //BED_CENTER_AT_0_0 - #else + #else #ifdef BED_CENTER_AT_0_0 #define Y_HOME_POS Y_MAX_LENGTH * 0.5 #else #define Y_HOME_POS Y_MAX_POS #endif //BED_CENTER_AT_0_0 #endif //Y_HOME_DIR == -1 - + // Z axis #if Z_HOME_DIR == -1 //BED_CENTER_AT_0_0 not used #define Z_HOME_POS Z_MIN_POS - #else + #else #define Z_HOME_POS Z_MAX_POS #endif //Z_HOME_DIR == -1 #endif //End auto min/max positions @@ -165,7 +165,7 @@ #error "You cannot have dual drivers for both Y and Z" #endif -// Enable this for dual x-carriage printers. +// Enable this for dual x-carriage printers. // A dual x-carriage design has the advantage that the inactive extruder can be parked which // prevents hot-end ooze contaminating the print. It also reduces the weight of each x-carriage // allowing faster printing speeds. @@ -175,10 +175,10 @@ // Note: the first x-carriage is defined as the x-carriage which homes to the minimum endstop; // the second x-carriage always homes to the maximum endstop. #define X2_MIN_POS 80 // set minimum to ensure second x-carriage doesn't hit the parked first X-carriage -#define X2_MAX_POS 353 // set maximum to the distance between toolheads when both heads are homed +#define X2_MAX_POS 353 // set maximum to the distance between toolheads when both heads are homed #define X2_HOME_DIR 1 // the second X-carriage always homes to the maximum endstop position -#define X2_HOME_POS X2_MAX_POS // default home position is the maximum carriage position - // However: In this mode the EXTRUDER_OFFSET_X value for the second extruder provides a software +#define X2_HOME_POS X2_MAX_POS // default home position is the maximum carriage position + // However: In this mode the EXTRUDER_OFFSET_X value for the second extruder provides a software // override for X2_HOME_POS. This also allow recalibration of the distance between the two endstops // without modifying the firmware (through the "M218 T1 X???" command). // Remember: you should set the second extruder x-offset to 0 in your slicer. @@ -193,17 +193,17 @@ // as long as it supports dual x-carriages. (M605 S0) // Mode 1: Auto-park mode. The firmware will automatically park and unpark the x-carriages on tool changes so // that additional slicer support is not required. (M605 S1) -// Mode 2: Duplication mode. The firmware will transparently make the second x-carriage and extruder copy all +// Mode 2: Duplication mode. The firmware will transparently make the second x-carriage and extruder copy all // actions of the first x-carriage. This allows the printer to print 2 arbitrary items at // once. (2nd extruder x offset and temp offset are set using: M605 S2 [Xnnn] [Rmmm]) -// This is the default power-up mode which can be later using M605. -#define DEFAULT_DUAL_X_CARRIAGE_MODE 0 +// This is the default power-up mode which can be later using M605. +#define DEFAULT_DUAL_X_CARRIAGE_MODE 0 // As the x-carriages are independent we can now account for any relative Z offset #define EXTRUDER1_Z_OFFSET 0.0 // z offset relative to extruder 0 -// Default settings in "Auto-park Mode" +// Default settings in "Auto-park Mode" #define TOOLCHANGE_PARK_ZLIFT 0.2 // the distance to raise Z axis when parking an extruder #define TOOLCHANGE_UNPARK_ZLIFT 1 // the distance to raise Z axis when unparking an extruder @@ -211,11 +211,11 @@ #define DEFAULT_DUPLICATION_X_OFFSET 100 #endif //DUAL_X_CARRIAGE - + //homing hits the endstop, then retracts by this distance, before it tries to slowly bump again: -#define X_HOME_RETRACT_MM 5 -#define Y_HOME_RETRACT_MM 5 -#define Z_HOME_RETRACT_MM 1 +#define X_HOME_RETRACT_MM 5 +#define Y_HOME_RETRACT_MM 5 +#define Z_HOME_RETRACT_MM 1 //#define QUICK_HOME //if this is defined, if both x and y are to be homed, a diagonal move will be performed initially. #define AXIS_RELATIVE_MODES {false, false, false, false} @@ -268,6 +268,12 @@ // Motor Current setting (Only functional when motor driver current ref pins are connected to a digital trimpot on supported boards) #define DIGIPOT_MOTOR_CURRENT {135,135,135,135,135} // Values 0-255 (RAMBO 135 = ~0.75A, 185 = ~1A) +// uncomment to enable an I2C based DIGIPOT like on the Azteeg X3 Pro +#define DIGIPOT_I2C +// Number of channels available for I2C digipot, For Azteeg X3 Pro we have 8 +#define DIGIPOT_I2C_NUM_CHANNELS 8 +// actual motor currents in Amps, need as many here as DIGIPOT_I2C_NUM_CHANNELS +#define DIGIPOT_I2C_MOTOR_CURRENTS {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0} //=========================================================================== //=============================Additional Features=========================== @@ -276,7 +282,7 @@ #define SD_FINISHED_STEPPERRELEASE true //if sd support and the file is finished: disable steppers? #define SD_FINISHED_RELEASECOMMAND "M84 X Y Z E" // You might want to keep the z enabled so your bed stays in place. -#define SDCARD_RATHERRECENTFIRST //reverse file order of sd card menu display. Its sorted practically after the filesystem block order. +#define SDCARD_RATHERRECENTFIRST //reverse file order of sd card menu display. Its sorted practically after the filesystem block order. // if a file is deleted, it frees a block. hence, the order is not purely cronological. To still have auto0.g accessible, there is again the option to do that. // using: //#define MENU_ADDAUTOSTART @@ -302,7 +308,7 @@ #define BABYSTEP_XY //not only z, but also XY in the menu. more clutter, more functions #define BABYSTEP_INVERT_Z false //true for inverse movements in Z #define BABYSTEP_Z_MULTIPLICATOR 2 //faster z movements - + #ifdef COREXY #error BABYSTEPPING not implemented for COREXY yet. #endif @@ -340,10 +346,10 @@ const unsigned int dropsegments=5; //everything with less than this number of steps will be ignored as move and joined with the next movement // If you are using a RAMPS board or cheap E-bay purchased boards that do not detect when an SD card is inserted -// You can get round this by connecting a push button or single throw switch to the pin defined as SDCARDCARDDETECT +// You can get round this by connecting a push button or single throw switch to the pin defined as SDCARDCARDDETECT // in the pins.h file. When using a push button pulling the pin to ground this will need inverted. This setting should // be commented out otherwise -#define SDCARDDETECTINVERTED +#define SDCARDDETECTINVERTED #ifdef ULTIPANEL #undef SDCARDDETECTINVERTED @@ -355,12 +361,12 @@ const unsigned int dropsegments=5; //everything with less than this number of st #define POWER_SUPPLY 1 #endif // 1 = ATX -#if (POWER_SUPPLY == 1) +#if (POWER_SUPPLY == 1) #define PS_ON_AWAKE LOW #define PS_ON_ASLEEP HIGH #endif // 2 = X-Box 360 203W -#if (POWER_SUPPLY == 2) +#if (POWER_SUPPLY == 2) #define PS_ON_AWAKE HIGH #define PS_ON_ASLEEP LOW #endif @@ -372,7 +378,7 @@ const unsigned int dropsegments=5; //everything with less than this number of st //=============================Buffers ============================ //=========================================================================== -// The number of linear motions that can be in the plan at any give time. +// The number of linear motions that can be in the plan at any give time. // THE BLOCK_BUFFER_SIZE NEEDS TO BE A POWER OF 2, i.g. 8,16,32 because shifts and ors are used to do the ringbuffering. #if defined SDSUPPORT #define BLOCK_BUFFER_SIZE 16 // SD,LCD,Buttons take more memory, block buffer needs to be smaller @@ -387,9 +393,9 @@ const unsigned int dropsegments=5; //everything with less than this number of st // Firmware based and LCD controled retract -// M207 and M208 can be used to define parameters for the retraction. +// M207 and M208 can be used to define parameters for the retraction. // The retraction can be called by the slicer using G10 and G11 -// until then, intended retractions can be detected by moves that only extrude and the direction. +// until then, intended retractions can be detected by moves that only extrude and the direction. // the moves are than replaced by the firmware controlled ones. // #define FWRETRACT //ONLY PARTIALLY TESTED @@ -411,9 +417,9 @@ const unsigned int dropsegments=5; //everything with less than this number of st #ifdef FILAMENTCHANGEENABLE #ifdef EXTRUDER_RUNOUT_PREVENT #error EXTRUDER_RUNOUT_PREVENT currently incompatible with FILAMENTCHANGE - #endif + #endif #endif - + //=========================================================================== //============================= Define Defines ============================ //=========================================================================== diff --git a/Marlin/Makefile b/Marlin/Makefile index 29a5578211..9c26c3cc0a 100644 --- a/Marlin/Makefile +++ b/Marlin/Makefile @@ -55,7 +55,10 @@ UPLOAD_PORT ?= /dev/arduino BUILD_DIR ?= applet # This defines whether Liquid_TWI2 support will be built -LIQUID_TWI2 ?= 0 +LIQUID_TWI2 ?= 0 + +# this defines if Wire is needed +WIRE ?= 0 ############################################################################ # Below here nothing should be changed... @@ -174,6 +177,14 @@ else ifeq ($(HARDWARE_MOTHERBOARD),301) HARDWARE_VARIANT ?= arduino MCU ?= atmega2560 +# Azteeg +else ifeq ($(HARDWARE_MOTHERBOARD),67) +HARDWARE_VARIANT ?= arduino +MCU ?= atmega2560 +else ifeq ($(HARDWARE_MOTHERBOARD),68) +HARDWARE_VARIANT ?= arduino +MCU ?= atmega2560 + endif # Be sure to regenerate speed_lookuptable.h with create_speed_lookuptable.py @@ -213,6 +224,10 @@ VPATH += $(ARDUINO_INSTALL_DIR)/libraries/Wire VPATH += $(ARDUINO_INSTALL_DIR)/libraries/Wire/utility VPATH += $(ARDUINO_INSTALL_DIR)/libraries/LiquidTWI2 endif +ifeq ($(WIRE), 1) +VPATH += $(ARDUINO_INSTALL_DIR)/libraries/Wire +VPATH += $(ARDUINO_INSTALL_DIR)/libraries/Wire/utility +endif else VPATH += $(HARDWARE_DIR)/libraries/LiquidCrystal VPATH += $(HARDWARE_DIR)/libraries/SPI @@ -221,6 +236,10 @@ VPATH += $(HARDWARE_DIR)/libraries/Wire VPATH += $(HARDWARE_DIR)/libraries/Wire/utility VPATH += $(HARDWARE_DIR)/libraries/LiquidTWI2 endif +ifeq ($(WIRE, 1) +VPATH += $(HARDWARE_DIR)/libraries/Wire +VPATH += $(HARDWARE_DIR)/libraries/Wire/utility +endif endif ifeq ($(HARDWARE_VARIANT), arduino) HARDWARE_SUB_VARIANT ?= mega @@ -241,7 +260,7 @@ CXXSRC = WMath.cpp WString.cpp Print.cpp Marlin_main.cpp \ MarlinSerial.cpp Sd2Card.cpp SdBaseFile.cpp SdFatUtil.cpp \ SdFile.cpp SdVolume.cpp motion_control.cpp planner.cpp \ stepper.cpp temperature.cpp cardreader.cpp ConfigurationStore.cpp \ - watchdog.cpp SPI.cpp Servo.cpp Tone.cpp ultralcd.cpp + watchdog.cpp SPI.cpp Servo.cpp Tone.cpp ultralcd.cpp digipot_mcp4451.cpp ifeq ($(LIQUID_TWI2), 0) CXXSRC += LiquidCrystal.cpp else @@ -249,6 +268,11 @@ SRC += twi.c CXXSRC += Wire.cpp LiquidTWI2.cpp endif +ifeq ($(WIRE), 1) +SRC += twi.c +CXXSRC += Wire.cpp +endif + #Check for Arduino 1.0.0 or higher and use the correct sourcefiles for that version ifeq ($(shell [ $(ARDUINO_VERSION) -ge 100 ] && echo true), true) CXXSRC += main.cpp diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index 6b54aafb6c..a28393e7b8 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -235,4 +235,9 @@ extern unsigned long stoptime; // Handling multiple extruders pins extern uint8_t active_extruder; +#ifdef DIGIPOT_I2C +extern void digipot_i2c_set_current( int channel, float current ); +extern void digipot_i2c_init(); +#endif + #endif diff --git a/Marlin/Marlin.ino b/Marlin/Marlin.ino index 2d6211c971..79c934bf0f 100644 --- a/Marlin/Marlin.ino +++ b/Marlin/Marlin.ino @@ -3,17 +3,17 @@ /* Reprap firmware based on Sprinter and grbl. Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm - + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -22,8 +22,8 @@ This firmware is a mashup between Sprinter and grbl. (https://github.com/kliment/Sprinter) (https://github.com/simen/grbl/tree) - - It has preliminary support for Matthew Roberts advance algorithm + + It has preliminary support for Matthew Roberts advance algorithm http://reprap.org/pipermail/reprap-dev/2011-May/003323.html */ @@ -50,3 +50,7 @@ #if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1 #include #endif + +#if defined(DIGIPOT_I2C) + #include +#endif diff --git a/Marlin/Marlin.pde b/Marlin/Marlin.pde index 2d6211c971..79c934bf0f 100644 --- a/Marlin/Marlin.pde +++ b/Marlin/Marlin.pde @@ -3,17 +3,17 @@ /* Reprap firmware based on Sprinter and grbl. Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm - + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -22,8 +22,8 @@ This firmware is a mashup between Sprinter and grbl. (https://github.com/kliment/Sprinter) (https://github.com/simen/grbl/tree) - - It has preliminary support for Matthew Roberts advance algorithm + + It has preliminary support for Matthew Roberts advance algorithm http://reprap.org/pipermail/reprap-dev/2011-May/003323.html */ @@ -50,3 +50,7 @@ #if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1 #include #endif + +#if defined(DIGIPOT_I2C) + #include +#endif diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 8601502719..b567e2b093 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -249,7 +249,7 @@ int EtoPPressure=0; float delta[3] = {0.0, 0.0, 0.0}; #endif - + //=========================================================================== //=============================private variables============================= //=========================================================================== @@ -492,6 +492,10 @@ void setup() #if defined(CONTROLLERFAN_PIN) && CONTROLLERFAN_PIN > -1 SET_OUTPUT(CONTROLLERFAN_PIN); //Set pin used for driver cooling fan #endif + + #ifdef DIGIPOT_I2C + digipot_i2c_init(); + #endif } @@ -789,7 +793,7 @@ static unsigned long delayed_move_time = 0; // used in mode 1 static float duplicate_extruder_x_offset = DEFAULT_DUPLICATION_X_OFFSET; // used in mode 2 static float duplicate_extruder_temp_offset = 0; // used in mode 2 bool extruder_duplication_enabled = false; // used in mode 2 -#endif //DUAL_X_CARRIAGE +#endif //DUAL_X_CARRIAGE static void axis_is_at_home(int axis) { #ifdef DUAL_X_CARRIAGE @@ -802,8 +806,8 @@ static void axis_is_at_home(int axis) { } else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && active_extruder == 0) { current_position[X_AXIS] = base_home_pos(X_AXIS) + add_homeing[X_AXIS]; - min_pos[X_AXIS] = base_min_pos(X_AXIS) + add_homeing[X_AXIS]; - max_pos[X_AXIS] = min(base_max_pos(X_AXIS) + add_homeing[X_AXIS], + min_pos[X_AXIS] = base_min_pos(X_AXIS) + add_homeing[X_AXIS]; + max_pos[X_AXIS] = min(base_max_pos(X_AXIS) + add_homeing[X_AXIS], max(extruder_offset[X_AXIS][1], X2_MAX_POS) - duplicate_extruder_x_offset); return; } @@ -895,7 +899,7 @@ static void run_z_probe() { st_synchronize(); // move back down slowly to find bed - feedrate = homing_feedrate[Z_AXIS]/4; + feedrate = homing_feedrate[Z_AXIS]/4; zPosition -= home_retract_mm(Z_AXIS) * 2; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], zPosition, current_position[E_AXIS], feedrate/60, active_extruder); st_synchronize(); @@ -992,7 +996,7 @@ static void homeaxis(int axis) { current_position[axis] = 0; plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - + // Engage Servo endstop if enabled #ifdef SERVO_ENDSTOPS @@ -1050,7 +1054,7 @@ static void homeaxis(int axis) { #if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) if (axis==Z_AXIS) retract_z_probe(); #endif - + } } #define HOMEAXIS(LETTER) homeaxis(LETTER##_AXIS) @@ -1124,7 +1128,7 @@ void process_commands() destination[Y_AXIS]=current_position[Y_AXIS]; destination[Z_AXIS]=current_position[Z_AXIS]; current_position[Z_AXIS]+=retract_zlift; - destination[E_AXIS]=current_position[E_AXIS]+retract_length+retract_recover_length; + destination[E_AXIS]=current_position[E_AXIS]+retract_length+retract_recover_length; feedrate=retract_recover_feedrate; retracted=false; prepare_move(); @@ -1238,10 +1242,10 @@ void process_commands() // reset state used by the different modes memcpy(raised_parked_position, current_position, sizeof(raised_parked_position)); delayed_move_time = 0; - active_extruder_parked = true; - #else + active_extruder_parked = true; + #else HOMEAXIS(X); - #endif + #endif } if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) { @@ -1260,7 +1264,7 @@ void process_commands() current_position[Y_AXIS]=code_value()+add_homeing[1]; } } - + #if Z_HOME_DIR < 0 // If homing towards BED do Z last #ifndef Z_SAFE_HOMING if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { @@ -1272,14 +1276,14 @@ void process_commands() #endif HOMEAXIS(Z); } - #else // Z Safe mode activated. + #else // Z Safe mode activated. if(home_all_axis) { destination[X_AXIS] = round(Z_SAFE_HOMING_X_POINT - X_PROBE_OFFSET_FROM_EXTRUDER); destination[Y_AXIS] = round(Z_SAFE_HOMING_Y_POINT - Y_PROBE_OFFSET_FROM_EXTRUDER); destination[Z_AXIS] = Z_RAISE_BEFORE_HOMING * home_dir(Z_AXIS) * (-1); // Set destination away from bed feedrate = XY_TRAVEL_SPEED; current_position[Z_AXIS] = 0; - + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate, active_extruder); st_synchronize(); @@ -1297,7 +1301,7 @@ void process_commands() && (current_position[Y_AXIS]+Y_PROBE_OFFSET_FROM_EXTRUDER <= Y_MAX_POS)) { current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); destination[Z_AXIS] = Z_RAISE_BEFORE_HOMING * home_dir(Z_AXIS) * (-1); // Set destination away from bed feedrate = max_feedrate[Z_AXIS]; plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate, active_extruder); @@ -1317,8 +1321,8 @@ void process_commands() #endif #endif - - + + if(code_seen(axis_codes[Z_AXIS])) { if(code_value_long() != 0) { current_position[Z_AXIS]=code_value()+add_homeing[2]; @@ -1364,26 +1368,26 @@ void process_commands() feedrate = homing_feedrate[Z_AXIS]; #ifdef ACCURATE_BED_LEVELING - + int xGridSpacing = (RIGHT_PROBE_BED_POSITION - LEFT_PROBE_BED_POSITION) / (ACCURATE_BED_LEVELING_POINTS-1); int yGridSpacing = (BACK_PROBE_BED_POSITION - FRONT_PROBE_BED_POSITION) / (ACCURATE_BED_LEVELING_POINTS-1); - - + + // solve the plane equation ax + by + d = z // A is the matrix with rows [x y 1] for all the probed points // B is the vector of the Z positions // the normal vector to the plane is formed by the coefficients of the plane equation in the standard form, which is Vx*x+Vy*y+Vz*z+d = 0 // so Vx = -a Vy = -b Vz = 1 (we want the vector facing towards positive Z - + // "A" matrix of the linear system of equations double eqnAMatrix[ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS*3]; // "B" vector of Z points double eqnBVector[ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS]; - - + + int probePointCounter = 0; bool zig = true; - + for (int yProbe=FRONT_PROBE_BED_POSITION; yProbe <= BACK_PROBE_BED_POSITION; yProbe += yGridSpacing) { int xProbe, xInc; @@ -1400,7 +1404,7 @@ void process_commands() xInc = -xGridSpacing; zig = true; } - + for (int xCount=0; xCount < ACCURATE_BED_LEVELING_POINTS; xCount++) { if (probePointCounter == 0) @@ -1408,19 +1412,19 @@ void process_commands() // raise before probing do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], Z_RAISE_BEFORE_PROBING); } else - { + { // raise extruder do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); } - - + + do_blocking_move_to(xProbe - X_PROBE_OFFSET_FROM_EXTRUDER, yProbe - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]); - + engage_z_probe(); // Engage Z Servo endstop if available run_z_probe(); eqnBVector[probePointCounter] = current_position[Z_AXIS]; retract_z_probe(); - + SERIAL_PROTOCOLPGM("Bed x: "); SERIAL_PROTOCOL(xProbe); SERIAL_PROTOCOLPGM(" y: "); @@ -1428,7 +1432,7 @@ void process_commands() SERIAL_PROTOCOLPGM(" z: "); SERIAL_PROTOCOL(current_position[Z_AXIS]); SERIAL_PROTOCOLPGM("\n"); - + eqnAMatrix[probePointCounter + 0*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = xProbe; eqnAMatrix[probePointCounter + 1*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = yProbe; eqnAMatrix[probePointCounter + 2*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = 1; @@ -1437,25 +1441,25 @@ void process_commands() } } clean_up_after_endstop_move(); - + // solve lsq problem double *plane_equation_coefficients = qr_solve(ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS, 3, eqnAMatrix, eqnBVector); - + SERIAL_PROTOCOLPGM("Eqn coefficients: a: "); SERIAL_PROTOCOL(plane_equation_coefficients[0]); SERIAL_PROTOCOLPGM(" b: "); SERIAL_PROTOCOL(plane_equation_coefficients[1]); SERIAL_PROTOCOLPGM(" d: "); SERIAL_PROTOCOLLN(plane_equation_coefficients[2]); - - + + set_bed_level_equation_lsq(plane_equation_coefficients); - + free(plane_equation_coefficients); - + #else // ACCURATE_BED_LEVELING not defined - - + + // prob 1 do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], Z_RAISE_BEFORE_PROBING); do_blocking_move_to(LEFT_PROBE_BED_POSITION - X_PROBE_OFFSET_FROM_EXTRUDER, BACK_PROBE_BED_POSITION - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]); @@ -1481,7 +1485,7 @@ void process_commands() run_z_probe(); float z_at_xLeft_yFront = current_position[Z_AXIS]; retract_z_probe(); - + SERIAL_PROTOCOLPGM("Bed x: "); SERIAL_PROTOCOL(LEFT_PROBE_BED_POSITION); SERIAL_PROTOCOLPGM(" y: "); @@ -1499,7 +1503,7 @@ void process_commands() run_z_probe(); float z_at_xRight_yFront = current_position[Z_AXIS]; retract_z_probe(); // Retract Z Servo endstop if available - + SERIAL_PROTOCOLPGM("Bed x: "); SERIAL_PROTOCOL(RIGHT_PROBE_BED_POSITION); SERIAL_PROTOCOLPGM(" y: "); @@ -1511,13 +1515,13 @@ void process_commands() clean_up_after_endstop_move(); set_bed_level_equation(z_at_xLeft_yFront, z_at_xRight_yFront, z_at_xLeft_yBack); - - + + #endif // ACCURATE_BED_LEVELING - st_synchronize(); + st_synchronize(); // The following code correct the Z height difference from z-probe position and hotend tip position. - // The Z height on homing is measured by Z-Probe, but the probe is quite far from the hotend. + // The Z height on homing is measured by Z-Probe, but the probe is quite far from the hotend. // When the bed is uneven, this height must be corrected. real_z = float(st_get_position(Z_AXIS))/axis_steps_per_unit[Z_AXIS]; //get the real Z (since the auto bed leveling is already correcting the plane) x_tmp = current_position[X_AXIS] + X_PROBE_OFFSET_FROM_EXTRUDER; @@ -1529,11 +1533,11 @@ void process_commands() plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); } break; - + case 30: // G30 Single Z Probe { engage_z_probe(); // Engage Z Servo endstop if available - + st_synchronize(); // TODO: make sure the bed_level_rotation_matrix is identity or the planner will get set incorectly setup_for_endstop_move(); @@ -1684,14 +1688,14 @@ void process_commands() card.removeFile(strchr_pointer + 4); } break; - case 32: //M32 - Select file and start SD print + case 32: //M32 - Select file and start SD print { if(card.sdprinting) { st_synchronize(); } - starpos = (strchr(strchr_pointer + 4,'*')); - + starpos = (strchr(strchr_pointer + 4,'*')); + char* namestartpos = (strchr(strchr_pointer + 4,'!')); //find ! to indicate filename string start. if(namestartpos==NULL) { @@ -1699,16 +1703,16 @@ void process_commands() } else namestartpos++; //to skip the '!' - + if(starpos!=NULL) *(starpos-1)='\0'; - + bool call_procedure=(code_seen('P')); - - if(strchr_pointer>namestartpos) + + if(strchr_pointer>namestartpos) call_procedure=false; //false alert, 'P' found within filename - - if( card.cardOK ) + + if( card.cardOK ) { card.openFile(namestartpos,true,!call_procedure); if(code_seen('S')) @@ -1781,7 +1785,7 @@ void process_commands() #ifdef DUAL_X_CARRIAGE if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0) setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset); -#endif +#endif setWatch(); break; case 140: // M140 set bed temp @@ -1847,7 +1851,7 @@ void process_commands() SERIAL_PROTOCOL_F(rawHotendTemp(cur_extruder)/OVERSAMPLENR,0); } #endif - + SERIAL_PROTOCOLLN(""); return; break; @@ -1865,14 +1869,14 @@ void process_commands() #ifdef DUAL_X_CARRIAGE if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0) setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset); -#endif +#endif CooldownNoWait = true; } else if (code_seen('R')) { setTargetHotend(code_value(), tmp_extruder); #ifdef DUAL_X_CARRIAGE if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && tmp_extruder == 0) setTargetHotend1(code_value() == 0.0 ? 0.0 : code_value() + duplicate_extruder_temp_offset); -#endif +#endif CooldownNoWait = false; } #ifdef AUTOTEMP @@ -2036,7 +2040,7 @@ void process_commands() SET_OUTPUT(SUICIDE_PIN); WRITE(SUICIDE_PIN, HIGH); #endif - + #ifdef ULTIPANEL powersupply = true; LCD_MESSAGEPGM(WELCOME_MSG); @@ -2193,18 +2197,18 @@ void process_commands() #endif break; //TODO: update for all axis, use for loop - #ifdef BLINKM + #ifdef BLINKM case 150: // M150 { byte red; byte grn; byte blu; - + if(code_seen('R')) red = code_value(); if(code_seen('U')) grn = code_value(); if(code_seen('B')) blu = code_value(); - - SendColors(red,grn,blu); + + SendColors(red,grn,blu); } break; #endif //BLINKM @@ -2354,7 +2358,7 @@ void process_commands() { extruder_offset[Z_AXIS][tmp_extruder] = code_value(); } - #endif + #endif SERIAL_ECHO_START; SERIAL_ECHOPGM(MSG_HOTEND_OFFSET); for(tmp_extruder = 0; tmp_extruder < EXTRUDERS; tmp_extruder++) @@ -2387,17 +2391,17 @@ void process_commands() } } break; - + case 226: // M226 P S- Wait until the specified pin reaches the state required { if(code_seen('P')){ int pin_number = code_value(); // pin number int pin_state = -1; // required pin state - default is inverted - + if(code_seen('S')) pin_state = code_value(); // required pin state - + if(pin_state >= -1 && pin_state <= 1){ - + for(int8_t i = 0; i < (int8_t)sizeof(sensitive_pins); i++) { if (sensitive_pins[i] == pin_number) @@ -2406,28 +2410,28 @@ void process_commands() break; } } - + if (pin_number > -1) { st_synchronize(); - + pinMode(pin_number, INPUT); - + int target; switch(pin_state){ case 1: target = HIGH; break; - + case 0: target = LOW; break; - + case -1: target = !digitalRead(pin_number); break; } - + while(digitalRead(pin_number) != target){ manage_heater(); manage_inactivity(); @@ -2437,7 +2441,7 @@ void process_commands() } } } - break; + break; #if NUM_SERVOS > 0 case 280: // M280 - set servo position absolute. P: servo index, S: angle or microseconds @@ -2615,13 +2619,13 @@ void process_commands() engage_z_probe(); // Engage Z Servo endstop if available } break; - + case 402: { retract_z_probe(); // Retract Z Servo endstop if enabled } break; -#endif +#endif case 500: // M500 Store settings in EEPROM { Config_StoreSettings(); @@ -2783,14 +2787,14 @@ void process_commands() // M605 S0: Full control mode. The slicer has full control over x-carriage movement // M605 S1: Auto-park mode. The inactive head will auto park/unpark without slicer involvement // M605 S2 [Xnnn] [Rmmm]: Duplication mode. The second extruder will duplicate the first with nnn - // millimeters x-offset and an optional differential hotend temperature of + // millimeters x-offset and an optional differential hotend temperature of // mmm degrees. E.g., with "M605 S2 X100 R2" the second extruder will duplicate // the first with a spacing of 100mm in the x direction and 2 degrees hotter. // // Note: the X axis should be homed after changing dual x-carriage mode. { st_synchronize(); - + if (code_seen('S')) dual_x_carriage_mode = code_value(); @@ -2801,7 +2805,7 @@ void process_commands() if (code_seen('R')) duplicate_extruder_temp_offset = code_value(); - + SERIAL_ECHO_START; SERIAL_ECHOPGM(MSG_HOTEND_OFFSET); SERIAL_ECHO(" "); @@ -2817,13 +2821,13 @@ void process_commands() { dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; } - + active_extruder_parked = false; extruder_duplication_enabled = false; delayed_move_time = 0; } break; - #endif //DUAL_X_CARRIAGE + #endif //DUAL_X_CARRIAGE case 907: // M907 Set digital trimpot motor current using axis codes. { @@ -2841,6 +2845,12 @@ void process_commands() #ifdef MOTOR_CURRENT_PWM_E_PIN if(code_seen('E')) digipot_current(2, code_value()); #endif + #ifdef DIGIPOT_I2C + // this one uses actual amps in floating point + for(int i=0;i raised_parked_position[Z_AXIS]) raised_parked_position[Z_AXIS] = destination[Z_AXIS]; delayed_move_time = millis(); @@ -3200,9 +3210,9 @@ void prepare_move() delayed_move_time = 0; // unpark extruder: 1) raise, 2) move into starting XY position, 3) lower plan_buffer_line(raised_parked_position[X_AXIS], raised_parked_position[Y_AXIS], raised_parked_position[Z_AXIS], current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], raised_parked_position[Z_AXIS], + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], raised_parked_position[Z_AXIS], current_position[E_AXIS], min(max_feedrate[X_AXIS],max_feedrate[Y_AXIS]), active_extruder); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); active_extruder_parked = false; } @@ -3350,8 +3360,8 @@ void manage_inactivity() enable_e0(); float oldepos=current_position[E_AXIS]; float oldedes=destination[E_AXIS]; - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], - destination[E_AXIS]+EXTRUDER_RUNOUT_EXTRUDE*EXTRUDER_RUNOUT_ESTEPS/axis_steps_per_unit[E_AXIS], + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], + destination[E_AXIS]+EXTRUDER_RUNOUT_EXTRUDE*EXTRUDER_RUNOUT_ESTEPS/axis_steps_per_unit[E_AXIS], EXTRUDER_RUNOUT_SPEED/60.*EXTRUDER_RUNOUT_ESTEPS/axis_steps_per_unit[E_AXIS], active_extruder); current_position[E_AXIS]=oldepos; destination[E_AXIS]=oldedes; @@ -3368,7 +3378,7 @@ void manage_inactivity() // travel moves have been received so enact them delayed_move_time = 0xFFFFFFFFUL; // force moves to be done memcpy(destination,current_position,sizeof(destination)); - prepare_move(); + prepare_move(); } #endif #ifdef TEMP_STAT_LEDS diff --git a/Marlin/digipot_mcp4451.cpp b/Marlin/digipot_mcp4451.cpp new file mode 100644 index 0000000000..11ee684223 --- /dev/null +++ b/Marlin/digipot_mcp4451.cpp @@ -0,0 +1,54 @@ +#include "Configuration.h" + +#ifdef DIGIPOT_I2C +#include "Stream.h" +#include "utility/twi.h" +#include "Wire.h" + +// Settings for the I2C based DIGIPOT (MCP4451) on Azteeg X3 Pro +#define DIGIPOT_I2C_FACTOR 106.7 +#define DIGIPOT_I2C_MAX_CURRENT 2.5 + +static byte current_to_wiper( float current ){ + return byte(ceil(float((DIGIPOT_I2C_FACTOR*current)))); +} + +static void i2c_send(byte addr, byte a, byte b) +{ + Wire.beginTransmission(addr); + Wire.write(a); + Wire.write(b); + Wire.endTransmission(); +} + +// This is for the MCP4451 I2C based digipot +void digipot_i2c_set_current( int channel, float current ) +{ + current = min( (float) max( current, 0.0f ), DIGIPOT_I2C_MAX_CURRENT); + // these addresses are specific to Azteeg X3 Pro, can be set to others, + // In this case first digipot is at address A0=0, A1= 0, second one is at A0=0, A1= 1 + byte addr= 0x2C; // channel 0-3 + if(channel >= 4) { + addr= 0x2E; // channel 4-7 + channel-= 4; + } + + // Initial setup + i2c_send( addr, 0x40, 0xff ); + i2c_send( addr, 0xA0, 0xff ); + + // Set actual wiper value + byte addresses[4] = { 0x00, 0x10, 0x60, 0x70 }; + i2c_send( addr, addresses[channel], current_to_wiper(current) ); +} + +void digipot_i2c_init() +{ + const float digipot_motor_current[] = DIGIPOT_I2C_MOTOR_CURRENTS; + Wire.begin(); + // setup initial currents as defined in Configuration_adv.h + for(int i=0;i<=sizeof(digipot_motor_current)/sizeof(float);i++) { + digipot_i2c_set_current(i, digipot_motor_current[i]); + } +} +#endif diff --git a/Marlin/pins.h b/Marlin/pins.h index 1576d529bb..f027d5a3d4 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -375,7 +375,7 @@ * Arduino Mega pin assignment * ****************************************************************************************/ -#if MOTHERBOARD == 3 || MOTHERBOARD == 33 || MOTHERBOARD == 34 || MOTHERBOARD == 35 || MOTHERBOARD == 77 || MOTHERBOARD == 67 +#if MOTHERBOARD == 3 || MOTHERBOARD == 33 || MOTHERBOARD == 34 || MOTHERBOARD == 35 || MOTHERBOARD == 77 || MOTHERBOARD == 67 || MOTHERBOARD == 68 #define KNOWN_BOARD 1 //////////////////FIX THIS////////////// @@ -391,10 +391,10 @@ // #define RAMPS_V_1_0 -#if MOTHERBOARD == 33 || MOTHERBOARD == 34 || MOTHERBOARD == 35 || MOTHERBOARD == 77 || MOTHERBOARD == 67 +#if MOTHERBOARD == 33 || MOTHERBOARD == 34 || MOTHERBOARD == 35 || MOTHERBOARD == 77 || MOTHERBOARD == 67 || MOTHERBOARD == 68 #define LARGE_FLASH true - + #if MOTHERBOARD == 77 #define X_STEP_PIN 54 #define X_DIR_PIN 55 @@ -434,7 +434,7 @@ #define SDSS 25//53 #define LED_PIN 13 - #define BEEPER 33 + #define BEEPER 33 #else @@ -477,16 +477,16 @@ #define LED_PIN 13 #endif - #if MOTHERBOARD == 33 || MOTHERBOARD == 35 || MOTHERBOARD == 67 + #if MOTHERBOARD == 33 || MOTHERBOARD == 35 || MOTHERBOARD == 67 || MOTHERBOARD == 68 #define FAN_PIN 9 // (Sprinter config) #else #define FAN_PIN 4 // IO pin. Buffer needed #endif #if MOTHERBOARD == 77 - #define FAN_PIN 8 + #define FAN_PIN 8 #endif - + #if MOTHERBOARD == 35 #define CONTROLLERFAN_PIN 10 //Pin used for the fan to cool controller #endif @@ -511,12 +511,12 @@ #define HEATER_1_PIN 9 // EXTRUDER 2 (FAN On Sprinter) #endif - #define HEATER_2_PIN -1 + #define HEATER_2_PIN -1 #if MOTHERBOARD == 77 - #define HEATER_0_PIN 10 - #define HEATER_1_PIN 12 - #define HEATER_2_PIN 6 + #define HEATER_0_PIN 10 + #define HEATER_1_PIN 12 + #define HEATER_2_PIN 6 #endif #define TEMP_0_PIN 13 // ANALOG NUMBERING @@ -534,8 +534,6 @@ #endif #define TEMP_BED_PIN 14 // ANALOG NUMBERING - - #ifdef NUM_SERVOS #define SERVO0_PIN 11 @@ -552,20 +550,24 @@ #endif #endif + #if MOTHERBOARD == 68 + #define BEEPER 33 + #endif + #ifdef TEMP_STAT_LEDS #if MOTHERBOARD == 67 #define STAT_LED_RED 6 #define STAT_LED_BLUE 11 #endif #endif - + #ifdef ULTRA_LCD #ifdef NEWPANEL - #define LCD_PINS_RS 16 + #define LCD_PINS_RS 16 #define LCD_PINS_ENABLE 17 #define LCD_PINS_D4 23 - #define LCD_PINS_D5 25 + #define LCD_PINS_D5 25 #define LCD_PINS_D6 27 #define LCD_PINS_D7 29 @@ -613,25 +615,25 @@ #else #define SDCARDDETECT -1 // Ramps does not use this port #endif - + #endif - - #if MOTHERBOARD == 77 - #define BEEPER -1 - - #define LCD_PINS_RS 27 - #define LCD_PINS_ENABLE 29 - #define LCD_PINS_D4 37 - #define LCD_PINS_D5 35 - #define LCD_PINS_D6 33 - #define LCD_PINS_D7 31 - - //buttons - #define BTN_EN1 16 - #define BTN_EN2 17 - #define BTN_ENC 23 //the click - - #endif + + #if MOTHERBOARD == 77 + #define BEEPER -1 + + #define LCD_PINS_RS 27 + #define LCD_PINS_ENABLE 29 + #define LCD_PINS_D4 37 + #define LCD_PINS_D5 35 + #define LCD_PINS_D6 33 + #define LCD_PINS_D7 31 + + //buttons + #define BTN_EN1 16 + #define BTN_EN2 17 + #define BTN_ENC 23 //the click + + #endif #else //old style panel with shift register //arduino pin witch triggers an piezzo beeper #define BEEPER 33 //No Beeper added @@ -642,14 +644,14 @@ //#define SHIFT_LD 42 //#define SHIFT_OUT 40 //#define SHIFT_EN 17 - - #define LCD_PINS_RS 16 + + #define LCD_PINS_RS 16 #define LCD_PINS_ENABLE 17 #define LCD_PINS_D4 23 - #define LCD_PINS_D5 25 + #define LCD_PINS_D5 25 #define LCD_PINS_D6 27 #define LCD_PINS_D7 29 - #endif + #endif #endif //ULTRA_LCD #else // RAMPS_V_1_1 or RAMPS_V_1_2 as default (MOTHERBOARD == 3) @@ -694,16 +696,16 @@ #define HEATER_1_PIN -1 #define HEATER_2_PIN -1 #define TEMP_0_PIN 2 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! -#define TEMP_1_PIN -1 -#define TEMP_2_PIN -1 +#define TEMP_1_PIN -1 +#define TEMP_2_PIN -1 #define TEMP_BED_PIN 1 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! #endif // MOTHERBOARD == 33 || MOTHERBOARD == 34 || MOTHERBOARD == 35 || MOTHERBOARD == 77 -// SPI for Max6675 Thermocouple +// SPI for Max6675 Thermocouple #ifndef SDSUPPORT -// these pins are defined in the SD library if building with SD support +// these pins are defined in the SD library if building with SD support #define MAX_SCK_PIN 52 #define MAX_MISO_PIN 50 #define MAX_MOSI_PIN 51 @@ -837,17 +839,17 @@ #define BTN_EN1 14 #define BTN_EN2 39 #define BTN_ENC 15 //the click - + #define BLEN_C 2 #define BLEN_B 1 #define BLEN_A 0 - + //encoder rotation values #define encrot0 0 #define encrot1 2 #define encrot2 3 #define encrot3 1 - + #endif //RA_CONTROL_PANEL #ifdef RA_DISCO @@ -861,7 +863,7 @@ //This currently only works with the RA Board. #define TLC_CLOCK_BIT 3 //bit 3 on port A #define TLC_CLOCK_PORT &PORTA //bit 3 on port A - + #define TLC_BLANK_BIT 1 //bit 1 on port A #define TLC_BLANK_PORT &PORTA //bit 1 on port A @@ -871,12 +873,12 @@ #define TLC_XLAT_BIT 0 //bit 0 on port A #define TLC_XLAT_PORT &PORTA //bit 0 on port A - //change this to match your situation. Lots of TLCs takes up the arduino SRAM very quickly, so be careful + //change this to match your situation. Lots of TLCs takes up the arduino SRAM very quickly, so be careful //Leave it at at least 1 if you have enabled RA_LIGHTING //The number of TLC5947 boards chained together for use with the animation, additional ones will repeat the animation on them, but are not individually addressable and mimic those before them. You can leave the default at 2 even if you only have 1 TLC5947 module. - #define NUM_TLCS 2 + #define NUM_TLCS 2 - //These TRANS_ARRAY values let you change the order the LEDs on the lighting modules will animate for chase functions. + //These TRANS_ARRAY values let you change the order the LEDs on the lighting modules will animate for chase functions. //Modify them according to your specific situation. //NOTE: the array should be 8 long for every TLC you have. These defaults assume (2) TLCs. #define TRANS_ARRAY {0, 1, 2, 3, 4, 5, 6, 7, 15, 14, 13, 12, 11, 10, 9, 8} //forwards @@ -1085,8 +1087,8 @@ #define LCD_PINS_D7 27 #endif //The encoder and click button - #define BTN_EN1 11 - #define BTN_EN2 10 + #define BTN_EN1 11 + #define BTN_EN2 10 #ifdef LCD_I2C_PANELOLU2 #ifdef MELZI #define BTN_ENC 29 //the click switch @@ -1098,8 +1100,8 @@ #define BTN_ENC 16 //the click switch #endif //Panelolu2 //not connected to a pin - #define SDCARDDETECT -1 - + #define SDCARDDETECT -1 + #endif //Newpanel #endif //Ultipanel @@ -1121,7 +1123,7 @@ #define BTN_EN2 10 #define BTN_ENC 16 //the click switch //not connected to a pin - #define SDCARDDETECT -1 + #define SDCARDDETECT -1 #endif //Makrpanel #endif @@ -1204,9 +1206,9 @@ #define BTN_EN1 40 #define BTN_EN2 42 #define BTN_ENC 19 //the click - + #define SDCARDDETECT 38 - + #else //old style panel with shift register //arduino pin witch triggers an piezzo beeper #define BEEPER 18 @@ -1223,9 +1225,9 @@ #define LCD_PINS_D5 21 #define LCD_PINS_D6 20 #define LCD_PINS_D7 19 - + #define SDCARDDETECT -1 - #endif + #endif #endif //ULTRA_LCD #endif @@ -1358,7 +1360,7 @@ #define MOTOR_CURRENT_PWM_Z_PIN 45 #define MOTOR_CURRENT_PWM_E_PIN 46 //Motor current PWM conversion, PWM value = MotorCurrentSetting * 255 / range -#define MOTOR_CURRENT_PWM_RANGE 2000 +#define MOTOR_CURRENT_PWM_RANGE 2000 #define DEFAULT_PWM_MOTOR_CURRENT {1300, 1300, 1250} //arduino pin witch triggers an piezzo beeper @@ -1443,7 +1445,7 @@ #else #define TEMP_0_PIN 15 // ANALOG NUMBERING - default connector for thermistor *T0* on rumba board is used #endif -#endif +#endif #if (TEMP_SENSOR_1==0) #define TEMP_1_PIN -1 @@ -2153,13 +2155,13 @@ #define BTN_EN1 59 #define BTN_EN2 64 #define BTN_ENC 43 //the click - + #define BLEN_C 2 #define BLEN_B 1 #define BLEN_A 0 - + #define SDCARDDETECT -1 // Ramps does not use this port - + //encoder rotation values #define encrot0 0 #define encrot1 2 @@ -2176,102 +2178,102 @@ ****************************************************************************************/ #if MOTHERBOARD == 701 #define KNOWN_BOARD 1 - - + + #ifndef __AVR_ATmega2560__ #error Oops! Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu. #endif - + #define LARGE_FLASH true - + #define X_STEP_PIN 26 #define X_DIR_PIN 27 #define X_ENABLE_PIN 25 #define X_MIN_PIN 37 #define X_MAX_PIN 40 //2 //Max endstops default to disabled "-1", set to commented value to enable. - + #define Y_STEP_PIN 4 // A6 #define Y_DIR_PIN 54 // A0 #define Y_ENABLE_PIN 5 #define Y_MIN_PIN 41 #define Y_MAX_PIN 38 //15 - + #define Z_STEP_PIN 56 // A2 #define Z_DIR_PIN 60 // A6 #define Z_ENABLE_PIN 55 // A1 #define Z_MIN_PIN 18 #define Z_MAX_PIN 19 - + #define E0_STEP_PIN 35 #define E0_DIR_PIN 36 #define E0_ENABLE_PIN 34 - + #define E1_STEP_PIN 29 #define E1_DIR_PIN 39 #define E1_ENABLE_PIN 28 - + #define E2_STEP_PIN 23 #define E2_DIR_PIN 24 #define E2_ENABLE_PIN 22 - + #define SDPOWER -1 #define SDSS 53 #define LED_PIN 13 - + #define FAN_PIN 7 #define FAN2_PIN 6 #define PS_ON_PIN 12 #define KILL_PIN -1 - + #define HEATER_0_PIN 9 // EXTRUDER 1 #define HEATER_1_PIN 8 // EXTRUDER 2 #define HEATER_2_PIN -1 - + #if TEMP_SENSOR_0 == -1 #define TEMP_0_PIN 4 // ANALOG NUMBERING #else #define TEMP_0_PIN 13 // ANALOG NUMBERING #endif - - + + #if TEMP_SENSOR_1 == -1 #define TEMP_1_PIN 8 // ANALOG NUMBERING #else #define TEMP_1_PIN 15 // ANALOG NUMBERING #endif - + #define TEMP_2_PIN -1 // ANALOG NUMBERING - + #define HEATER_BED_PIN 10 // BED - + #if TEMP_SENSOR_BED == -1 #define TEMP_BED_PIN 8 // ANALOG NUMBERING - #else + #else #define TEMP_BED_PIN 14 // ANALOG NUMBERING #endif - - #define BEEPER 64 - - + + #define BEEPER 64 + + #define LCD_PINS_RS 14 #define LCD_PINS_ENABLE 15 #define LCD_PINS_D4 30 #define LCD_PINS_D5 31 #define LCD_PINS_D6 32 #define LCD_PINS_D7 33 - - + + //buttons are directly attached using keypad #define BTN_EN1 61 #define BTN_EN2 59 #define BTN_ENC 43 //the click - + #define BLEN_C 2 #define BLEN_B 1 #define BLEN_A 0 - + #define SDCARDDETECT -1 // Megatronics does not use this port - + //encoder rotation values #define encrot0 0 #define encrot1 2 @@ -2287,87 +2289,87 @@ ****************************************************************************************/ #if MOTHERBOARD == 702 #define KNOWN_BOARD 1 - - + + #ifndef __AVR_ATmega1281__ #error Oops! Make sure you have 'Minitronics ' selected from the 'Tools -> Boards' menu. #endif - + #define LARGE_FLASH true - + #define X_STEP_PIN 48 #define X_DIR_PIN 47 #define X_ENABLE_PIN 49 #define X_MIN_PIN 5 #define X_MAX_PIN -1 //2 //Max endstops default to disabled "-1", set to commented value to enable. - + #define Y_STEP_PIN 39 // A6 #define Y_DIR_PIN 40 // A0 #define Y_ENABLE_PIN 38 #define Y_MIN_PIN 2 #define Y_MAX_PIN -1 //15 - + #define Z_STEP_PIN 42 // A2 #define Z_DIR_PIN 43 // A6 #define Z_ENABLE_PIN 41 // A1 #define Z_MIN_PIN 6 #define Z_MAX_PIN -1 - + #define E0_STEP_PIN 45 #define E0_DIR_PIN 44 #define E0_ENABLE_PIN 27 - + #define E1_STEP_PIN 36 #define E1_DIR_PIN 35 #define E1_ENABLE_PIN 37 - + #define E2_STEP_PIN -1 #define E2_DIR_PIN -1 #define E2_ENABLE_PIN -1 - + #define SDPOWER -1 #define SDSS 16 #define LED_PIN 46 - + #define FAN_PIN 9 #define FAN2_PIN -1 #define PS_ON_PIN -1 #define KILL_PIN -1 - + #define HEATER_0_PIN 7 // EXTRUDER 1 #define HEATER_1_PIN 8 // EXTRUDER 2 #define HEATER_2_PIN -1 - + #define TEMP_0_PIN 7 // ANALOG NUMBERING #define TEMP_1_PIN 6 // ANALOG NUMBERING #define TEMP_2_PIN -1 // ANALOG NUMBERING - + #define HEATER_BED_PIN 3 // BED #define TEMP_BED_PIN 6 // ANALOG NUMBERING - - #define BEEPER -1 - - + + #define BEEPER -1 + + #define LCD_PINS_RS -1 #define LCD_PINS_ENABLE -1 #define LCD_PINS_D4 -1 #define LCD_PINS_D5 -1 #define LCD_PINS_D6 -1 #define LCD_PINS_D7 -1 - - + + //buttons are directly attached using keypad #define BTN_EN1 -1 #define BTN_EN2 -1 #define BTN_ENC -1 //the click - + #define BLEN_C 2 #define BLEN_B 1 #define BLEN_A 0 - + #define SDCARDDETECT -1 // Megatronics does not use this port - + //encoder rotation values #define encrot0 0 #define encrot1 2 @@ -2393,7 +2395,7 @@ #define X_STEP_PIN 14 #define X_DIR_PIN 15 #define X_ENABLE_PIN 24 - + //X endstop #define X_MIN_PIN 3 #define X_MAX_PIN -1 @@ -2406,7 +2408,7 @@ //Y endstop #define Y_MIN_PIN 2 #define Y_MAX_PIN -1 - + //Z motor stepper #define Z_STEP_PIN 40 #define Z_DIR_PIN 41 @@ -2415,7 +2417,7 @@ //Z endstop #define Z_MIN_PIN 5 #define Z_MAX_PIN -1 - + //Extruder 0 stepper #define E0_STEP_PIN 26 #define E0_DIR_PIN 28 @@ -2442,7 +2444,7 @@ #define HEATER_BED_PIN 22 //Cheaptronic v1.0 hasent EXTRUDER 3 #define HEATER_2_PIN -1 - + //Temperature sensors #define TEMP_0_PIN 15 #define TEMP_1_PIN 14 From 5097c57d3a02be43dfdf79f3ecb8821644682270 Mon Sep 17 00:00:00 2001 From: Jim Morris Date: Wed, 5 Feb 2014 14:25:42 -0800 Subject: [PATCH 130/256] Added pins for Azteeg X3 Pro under motherboard 68 --- Marlin/pins.h | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/Marlin/pins.h b/Marlin/pins.h index f027d5a3d4..52ca2844df 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -472,6 +472,20 @@ #define E1_DIR_PIN 34 #define E1_ENABLE_PIN 30 + #if MOTHERBOARD == 68 + #define E2_STEP_PIN 23 + #define E2_DIR_PIN 25 + #define E2_ENABLE_PIN 40 + + #define E3_STEP_PIN 27 + #define E3_DIR_PIN 29 + #define E3_ENABLE_PIN 41 + + #define E4_STEP_PIN 43 + #define E4_DIR_PIN 37 + #define E4_ENABLE_PIN 42 + #endif + #define SDPOWER -1 #define SDSS 53 #define LED_PIN 13 @@ -511,17 +525,33 @@ #define HEATER_1_PIN 9 // EXTRUDER 2 (FAN On Sprinter) #endif - #define HEATER_2_PIN -1 #if MOTHERBOARD == 77 #define HEATER_0_PIN 10 #define HEATER_1_PIN 12 #define HEATER_2_PIN 6 + #elif MOTHERBOARD == 68 + #define HEATER_2_PIN 16 + #define HEATER_3_PIN 17 + #define HEATER_4_PIN 4 + #define HEATER_5_PIN 5 + #define HEATER_6_PIN 6 + #define HEATER_7_PIN 11 + #else + #define HEATER_2_PIN -1 #endif #define TEMP_0_PIN 13 // ANALOG NUMBERING #define TEMP_1_PIN 15 // ANALOG NUMBERING - #define TEMP_2_PIN -1 // ANALOG NUMBERING + #if MOTHERBOARD == 68 + #define TEMP_2_PIN 12 // ANALOG NUMBERING + #define TEMP_3_PIN 11 // ANALOG NUMBERING + #define TEMP_4_PIN 10 // ANALOG NUMBERING + #define TC1 4 // ANALOG NUMBERING Thermo couple on Azteeg X3Pro + #define TC2 5 // ANALOG NUMBERING Thermo couple on Azteeg X3Pro + #else + #define TEMP_2_PIN -1 // ANALOG NUMBERING + #endif #if MOTHERBOARD == 35 #define HEATER_BED_PIN -1 // NO BED @@ -532,6 +562,7 @@ #define HEATER_BED_PIN 8 // BED #endif #endif + #define TEMP_BED_PIN 14 // ANALOG NUMBERING #ifdef NUM_SERVOS From 8a1fd2536340d2282c2371df7d42d0d08fba3cd1 Mon Sep 17 00:00:00 2001 From: Jim Morris Date: Wed, 5 Feb 2014 14:28:23 -0800 Subject: [PATCH 131/256] Default is to not define digipot_i2c --- Marlin/Configuration_adv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 21b270b224..14e7f78156 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -269,7 +269,7 @@ #define DIGIPOT_MOTOR_CURRENT {135,135,135,135,135} // Values 0-255 (RAMBO 135 = ~0.75A, 185 = ~1A) // uncomment to enable an I2C based DIGIPOT like on the Azteeg X3 Pro -#define DIGIPOT_I2C +//#define DIGIPOT_I2C // Number of channels available for I2C digipot, For Azteeg X3 Pro we have 8 #define DIGIPOT_I2C_NUM_CHANNELS 8 // actual motor currents in Amps, need as many here as DIGIPOT_I2C_NUM_CHANNELS @@ -278,7 +278,7 @@ //=========================================================================== //=============================Additional Features=========================== //=========================================================================== - +. #define SD_FINISHED_STEPPERRELEASE true //if sd support and the file is finished: disable steppers? #define SD_FINISHED_RELEASECOMMAND "M84 X Y Z E" // You might want to keep the z enabled so your bed stays in place. From d485988becdc5e70e2913f3f629cc9dd825a7f28 Mon Sep 17 00:00:00 2001 From: Jim Morris Date: Wed, 5 Feb 2014 14:39:45 -0800 Subject: [PATCH 132/256] fix typo --- Marlin/Configuration_adv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 14e7f78156..dc986fae4a 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -278,7 +278,7 @@ //=========================================================================== //=============================Additional Features=========================== //=========================================================================== -. + #define SD_FINISHED_STEPPERRELEASE true //if sd support and the file is finished: disable steppers? #define SD_FINISHED_RELEASECOMMAND "M84 X Y Z E" // You might want to keep the z enabled so your bed stays in place. From 1781031f2dc1a710a9f8507dd10d16c41e3c6a92 Mon Sep 17 00:00:00 2001 From: Cylindric Date: Fri, 7 Feb 2014 01:52:44 +0000 Subject: [PATCH 133/256] Update LCD Menu Tree with current options, based on ultralcd.cpp and language.h. --- Marlin/LCD Menu Tree.pdf | Bin 217464 -> 17373 bytes Marlin/Menu Plans.xlsx | Bin 51386 -> 28860 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Marlin/LCD Menu Tree.pdf b/Marlin/LCD Menu Tree.pdf index 5e29d049509ca89c600be33a1ea21b2edbc7d1e4..aa95bbc1dd6b5ac841a9bdd8904d35ab0f4c5236 100644 GIT binary patch literal 17373 zcmc(n2|QHq-}li^*~^w)(_+gqbI#aCmXIxL)?}%{SPFx&OC%{vNJ5B^6xk&rME0^I zk&-Q2$sQ`{KBHg%|F2yC`@Wyo>v>+!FwQyOb8VmNd**td?{%&rU~oiT9FmY?q!W06 zycp>q6b41KIn78XFON3%b0eTt@t$~Rq669h??51-VC1wRS_kjyAWU!-*H95bp^ZE} zylg#daRzXhrTV0!VpjC-p zu1Gm(Z6`aD1xk`!qZR6(`LO@Ur|jkFNc0dU*MZW+BNcksA#GCiAmBZnh^|NQo&@0| zaxeyx#K0ICWFreNk!ov1 z@U%c9mjv3F;OmLjazT8q@^hp5bE8G}1X`D1=Y&@w`dT1aF(?SaVI(9`vXYR5EY1q) ze54Yjfh3gFW*r(HL@zg_(#@-B^8jsxHuk`~lHABbZ2i!xM(861Zzo%Vp@s@lx-s5{ zge3WSUHueGLSg>dFXV!M^^3ZbvnRm=t?rEIK0>f1+7Zw?1Xl-7M-&$EI5`)|6S*2( z80madvn|YtJgv;oT7PJ;&W6&wM22bRh`DHowcl{t{s7ivo|=B222ZBv zDz*sXj0QbV9mecX_}u%&>ofF2L1DxiGb!hiw5x{n*e2S?)K^gFA-A6X#ut-SH~$w3 zm9sS)Ut9CqIn1nnJeL{l$!ni&eORcw>Kf?(0-HzZYpCt5>S4_Yu=jMpIpmHhIOzGz z2W7d$`mFX&hr@9qS1-9W$G_QQV<4`^G|iPr(O$7IZ?;?zD#K)bmFuKt(?}oxIeymc zxhq<9v9{ift16gczlPIIU)&G!JdeM3H?=ADppk7!oV$*(2T{{hgZ9o@wVRS*p%J#4 z!mZOfwA%#ZZZRmYP(WwJD9nv~T_l~gbU#Ucl)>dQv@Cv0o`9GGi8_Wcyw}E$x0ca7ZCQ-DRaJ1lmUur8oiK8FiiaX-r~dhd0-w7EB@%78cD#r4x%{sn;p?kBJp6QwFY>j=NqJ>D0h%aN(h~qjM-RcpA zFE=!PpCqPnM(`lJDq@JY^FB@0iij|eX1iY>{4!QdZTXq*xZZBnE3F>>opyw{z0C)3 z^>1<&b!}7eC8PX!lbQaz(5-~~b}?PNW~gP(UaWbz+`}T%{wZ7eSKGC8E%nB^2kSZS zd=g}0@)sgX6TLgFt-Qxihb#Hvf_(d)E2b-n?FlO_^Y-^A`7gf5U1GC+j2(Q=C-yYN zAH`9hb#>){#D3S^w{&+57Y!`BKj;k%@L%ki={@W9lAybEtIY1+_gVOi%9*-dA_FU0_MVvEdj`^wHomU-?T)sw&k25Azso zd-+Av2_+=e65Dpj?iv*f|Nf`XxqM1vcB+;o)ESsC&_BN=wzn>Loapej^TP`%u5M`0 z=_it95`o8Q)XF$^(s)0ddG&Bt$qu^CmkQhSaF$i^6uV+dN%I^c1Ey*`h4nh6?1MKG z@wL{BdnQETNlW$vxE9|U*4db;%wZwJ8sg_p^^IuiLM4U$AJ@#a$ zl1)XQs?X#4q&F?@F$dmB;$|+{N6K(>Yt`!*)z{P>EnQJv+7^DyA$UfPdfonLU!ctW zhTBE5Z9ZQ7Ej6MPK9@g}q zFPHpchw{%{%S#fx5N^IR=C2A-$jCufY}aB#QL@rG%ibI%=s6>6&&g~s7CdmRE>67-tg%nt4Ng|^Nq*audf)zIt%T1 zN6d2j!hf+jH9#iVrvp7H3eVXc5^+AiqKV&VpZnN6vQ5FLMNY;pi2d-%m-8+55nYNi z^+ZQaln`}Y!G{WaQ(@&MK8+66l1knFV*56CJMDcR165X1>2qkt_eq#e?mwe-$RsCt z=COEJ=xWQfO0NhippYVYng6xaT{!`}tozE_`NRhfEoW&3FHzqQ&(PW@By1uS={&Z3 z^=`P86nbyjF<A_#ws6v`{Ho-&8*2XcV(MdPc;T=K8UUlk0137fhxQ5 zh);E{H9qA{5g*j(V7PuiEl3dm@#R%k!0orKvt8f-T z8S1}CE4v=j41U9J^jpqfd^K-s>7Wt^M$AG_6e82dF^T&;9%dRI*v*_~Cor6bK zMjrWn%Lrb}eAOwr%HDR-sJFU|v;M%_!!&m)GlX|BefQF`kt8b396xsBsqRujRtXiO z@ak#09ai#zy7iK)bkxt3Y2+-0X`!n98Of_WM0u_T4-aui4&akg ztFt9CnuX>fvG*K2x@bTAkxTj*$6wPyc)bzSp=GrIB-&9i^tH)Hmnd5sv zNzAFVJ6&~j!1qQr#k<#Q0qb5`0UpU_Q-Qgv7AZN_Z{Dg37m${dW&E5;t3~_2w}^C? zUpu;|Ad=T^IOh29$MZAhE;sc{#Hrh$GX?>Yk;D1&^U2G;f#auQc7%jd<`xXT?fxt7 zt@-e5zn^=+p;*6>WSlL1x8k)*`?y#M%YK~qv8m*T`{{zy?TPhFi*u7dqD3Bm-5K6p zof+FS#+dfwlBpGzekPbYNhU*w=gR3>=ytj9Hlg$v3QhY_$x2q(oimz2*uTbIOukHn zsT{oElaaZWm}oZm37&P&pEwg|Yq{jw!1OewQU126#_aXAiR%~Q>3nuG(TrD7irsn$ zon0Em?>Jy@D1G6+>yY)J%BV>Rniw7!aFfFzplMxsUzr(hr_W@0lW@njuJ-YDmq_tX z0@kQcuT_RRoY1p1L;h!kYG3VzJ3HSy^NVgMe!B9uyX({SlPW@E+?+!)#Jx0={ZpT^ zWMuNb5cxtVS-Va>7en1|9DL(JUl2~`J9M^3>u}52wDaiXgYm1+51`8GQ&Iz7w8o7D zE=^<@g!q-BZ`K@rDbrUS%UgIcx=d*@Pwv=ajUR`yTj#o7$GMoW;qI=lTH_~lhAdYy zeO{-g+bflAdzq(5>84b&@~xQhc4bXvk8jQjM!0hzIQe6$MdR0-F9LQa93l4kuG(z0 zvpgh_iyMB1IVE^DUiFuZGZf2v*N^bwG!mO=ZgS1yl zxnH-edOJ~YyKrQ;(ZWpK!1w3&(ZQe1%lEgR(~ESqrxxOj(yRZ$fHO0Cbc5EpGpc_i zB`B2Q0`*{eM~BO&IJ<_y#^-+L)-)vtil}jJ-9!5N-ptN%T;n6xzjwWeL~)j|{xzy$ z&W%nKU6&tLR5Xy551w3IxbBw7!LNCCUXf{ZI>ny-DQ9>ewfL-li*Qp@z+xEg+Pgm_sXM}PD5^~t+oN@qr; zg+1jK|H8r$Tig8%%Z~P26pkBXq@3m>9V>L(Mjyn(_1VKW<{f8|rVHD(wdeOkI_TCP zndpR^RPLGa+tX;^AHMzscTVO^V2+(zJC#z)@cm{UJXNh}ZS#&1I!49IoNIIylqZ?@ zo#zy;sAqC$aarQKN;t1X4^q=;&RC3NI$(mO050JdB&Z- z6tsm;cXO%xG-+{;SzH={ zCH5oKIdqNlDctL2R&&BlMs&k8ZU?`<>gkT>X+*Wl*%HdxKdU5;?2s}qzI`{s-)~u> zhB+{qt>LTp-lZn?p0(>N2L)S~IdV0z7&RM0<2psDvcNh&6h^maSo(37h}eLLu`2iZ z97B=kD0MuCDN4=xg$`|`B7-4=P7XfhRgcphANs>5qHhlEn>b`#%PjGQVUI97|8Wbp z;Ie&J+rBOHu|7RGyOSu1H9V!CPFME<)!40wO*xgjMlJEOOECG?`Q7~2MAeL%cMLST zh3%Io&|5F^ifGX5)VW}!%3liZ=y^I6^0M7^`Gs#>CPUZbA-fwhZ0AUKq^IZVx7}E- z&pK`=DjF$dUzKC67r!{@Fc=! z3S|!`q%<{GBv^8CbwHarxhlJooc?u8PIH7nvh{Fs^CWtpWH+NYbtey!r>Y~~0|~2; z`2X*H2!@gDcAkzT#Jm}9{j1&?j{@fRbAq+Ax;igG&a&YuS$-uH`Wp9VghM*)RA!NqE_vZmDEiJWK zjoHtXk{As7_}{r;DGU-R;>lfr!eWtdli*^C?>4h; zY36@)-p_XZU-F;~?w=k+oJ;PZzdb1PKYCE+HxI(H|D6Y6^8CebD)ntn8+p2*^-x#{ z`?KRvu&kssviqN=86+_>o1e;GA8Fsz2bP1;f)AJiiZx6f?H8FG0rY(02l z%CYJ}L_pxjnR_meGlyu3edU$U_O~aXl-@teE~BP((yl;LueR^r=c&V$&R$Ej(A<@L zP;oD(ifYr&r~~m`>Q%k5LOuWATo#I6HbKVHrA4)}N`cL&YIMi$Rin4e0l zD;^1OTx05?i5D$1j^PxT*}j+BRk;cP-Vdl}k*KheENsmUJ6aUbt7p%l4L=LBxPgHGg%DNItKgB_Ho71x zaH+d#wnF`vDKo>bUH7SHbZou;yqiQ>PBouEufF{Nm2l|3tG%~;f*szgo6m>76^V3x zDMJ5_N_)w)QEgKE*%{QnZYSm_k-AF}6xx(>>^j0vu0$R!+jfL@NaZ%#OEHyFl#1tO z0?Qi4UqbTWu9F9?IIK-hXOk%M7?p9QS zD&DoQJ+%}adGrLufZ^@*5w5Siyi9AiCs~pzOL4obr!404PT<2S7-7Z`@OoxdM^?$)R}n~dj`3C{~n6H}F}m*&fBST7~@A%Er{cHCpS zUZc#*vaDjh_F_Ll>Jcp=qcBaFerzthWY}JTWI5lEhLfnvlbaN?wh&&oPvjP z+LzP!(-rB^@PHgf%GGyHs%uR0k?J#-O1mRwymM#?Ig>QwPtfic52-BA-j>KH2*}jT zbk=__Tdv`AO7zjwG#(3s?M_xqmn33Eogef)3s&Y5FQO($!j`h@*f>>@EG+z&|5RH4 zsGDunxZB0UoV4pKuG*EiY1VcHOfNgN2{2K*uc*Z6#%sUa7UAgbFE>s{U~5yjn`t0H z8H2N@Z*x3kVW57fGIc}3+1*$1OVaT=itdnt^Z1NLoUV0mv6|4y8E0kFmK);2S#^3UKdw@>K-Ixm)U?~-d%5Y=xpS0HRiAcNZbB8dFpJXi?^Vp?g{FsjpG9!^<~{FJATZ}P)A3JHuZYU>kj9hKdaVv zB17W*P8Iy2{voRN_R- z)R1P#^wh=g*=;nP92nSv~YYbVwpcU@@)!$x|?dw4m{Ykm=_uKrk z<{Z=;F9fx92yh10VkGDSYh$za2R`Z&(x)0{II>8ovg_53v`BX74$I^X1)tJ7 z^3{B&)81ZeXp(LO@v=0}&dYDFvZGt5Xm#xxhg*-D*;%FL;76ga8A(SlwOt31?BRNw@P2aS3pQtW@khroUTHj`z zq%HpB!0YQp(^2Ar8>wCRkNB{RTfG+Vta^1%=nR@D=zmxIR^0Nw@p_RHrcI*tuWOuU z^>@UsStZa4X6J|MPCB0tCLO(0e2FV8bids zOnP6=A}x?Q${OA3DvIyHS?nEVsLT14tDohXsP<=*^rrj|EYV4pmAg!HLXE8InXe6+ z))y3<(-)0d*!f)NrWGn&D^BW*oc?*^?`p+baY#WeCRTTtuN~m1ABcC_UFv?qFDl5< z-mB;AUpHp@*H?3-)eK0g2}v^*EYhF9PK1d;uiXWlxl5AuA;Cihp;lJh=|*x<3ePZX zW&R&sTOtGxc?Y@o<#Y@U#zfItJa;|H-zmoG#J$(MQMkr?w2J3JX6v;xeoHb1 zgZh(6#+C6L1z`nvSE&oR4l8VDkKCwk*VR0^gu5NW^CV6y;f$Y=^l;NXq0aa1532Ks z)(vk@Z#U^Qt#34jTN4k}6imR)@oP>h*JS$^3+(Bd=S{>dZ1-pje%ZdT z%RL;HdnV;~1WVnMApWfxA>WsuMmg!>xr*r!(Szv4L!b) zPshtlroV40amFqiz8gQDpf0ApKjC@L(B3aeB{$^6ZM4&D4=RYW#) z)}(#+tZj>(^J@;0Tqi->4SGpFm13hAQdQvU{p2I!P@e}sFRL@NHuqk$=ROHayy_=m z5%R6z)y%=(?CQL#65F-h1d+F$c$unKChL6KHzteJ&WhbQTb1C$r43^w(RI5QAUn9c z#YS)PiyiYGRp}v#ajT|S1_s>q*XJrdOSuk7On9d0CrsJ4OuRvQg)?HC>JsmxHTIrC z`4CgH52ka`5d=E58Rm%c~WxF<&HJmdRw*YiQN}_q>a!>kzK-2g5Rv=x~2C+ za+92}-Tdt##U%mS$oIj81o zCShjMULA5`o#lfoX+3kzEcNZe(H;@k?25S+{KMAAYv@`-iFBG24q|)eE&qpODq8d= zg}d*zR-ZeuPW7Sa4JH1Vqu3JnhwNO^z`b*n8?Mc9kA~0tNi8it?O(Tg*J*TVkZGUS zf=3|knE2AuvbFH(qBjc;S4DQCv5yVB_(f8Jh8-Sm)BoJ_<3)k%jaGR+iRVhS#c!az zF9DjP@59V;J8Z9?)Zz0!bo_x@QF5OV+T^h&DM*ig;mn-|SBV#Kts?+od(~0KxX-gA+L1re0_IalhGL7UO%Q9AV#^}!} zw)f|-jLnwnye%xzN#$_XP|aVq_CRHVFfwI!BsQtCx_ z;Z>#;+Lj98ebIVXmsNWGJib}AcUlMi_&E05)Tc!BdsM>8>^$kjz_;p7N2fg!XHB&O zCYN#IpZK0lmX)pUOYeE{&g86~c7WL&PF(2ou1-fkF4dLdVxL1i=(*ZJTN!!!JCY4I zJ7P*r9S(Sn$#$Phh>YT{IOb^51l5#U@i>Hc2vw!U$r7VK1m(N*MY!iTzxrUC@7GJG zoj=+00m?Ud(Z-qot?R?~!G^w@wu2nKgGz&>7kuo4GF>wj6TwnF_rAzKKjGx6j^$6* z?@IIvWPR1A6L_hI<3QlIuI$GJDPG6?*YDk0BE8)+!K=N;%FMCr)#bY*>Xnw^i)*Ea zCMPSDRsu$8^Ts+qrKV@q;$vhn%!Fm72~nolBl%N5wz+W6Z7j^MjiHs^y6Ov#eh8Ae zwwfIHZGJxMb?&-G-fEif7vHMD@ALDXtDhTE-f*lc5pDM`=6!2^^JZ*TnyI-c#izZ& z$EUXX`^xf{Ppjfl1xl(XiF?vqeNHYm=MZbZjkRmbfBn>e+$Xperp<16SN)h>@wG0! zV*TU$r<6V-5q+*ACv3g(bNYTfYHnQkGUZ1b(rR?s*bOhfvJ*v9O{~jKe!M3@v8CX1T z+UZJ31@xVq!e!(5G}9NQO8$Zx`j4h?EDG5fIYP@iA!+Pg+~@Ky_Z{`hNA>wT=U;pE zm5{&v)j_NLwB8fO`OLioy7{3m>D2OhU&_hn$Moc4^SAeKi{=Nuh}f6E+)c-u@6avB zn*XjVmoDF=i<@fjP2WwA!6&Z*@q>lERtAGNUn(dKM)vSY4EnwJ&O7MPJxD)j(q;L0 zqDu;!?{`u+_jHqC&-vstJx3Dk!zHP+zA)c~#ira#t=tt1I zjrj{f+g5awCxO#=KPSO9CloADunc(uZ0nDdEO}iA7K`0XK~5zlCH>obYo1>gX=xc0 z`7Hy(oA1rz&AA$~4ew9G3?_aG# z=DvRI|Fg9)xkltIg`6jE$u<5;N8bL_xOw)M#?4u@pE<~O_IwCELQ^w)2(voVjGHNoasu)>mH7rgFQdL#_pHm>^|L0jQX({;kwKP(%9QyUW zIO`TjXEb5{8&^XOTRK|q-gbI$$xz+CJdEw2%F(K*UE$kxGgR!%+Dx^w@dEoZk0@+( zOiowJrhoLYnmk9E%UAa<{GkPJ@<5He@OZQ>$yhs8snQH_CrN{Rr80uZO|*HWL9kVY}6_9 z)}_ma)-G^F4`Vizr8gRCMKXLde6RMXH`0HncVW1K{QXYfi2O(~WHXSr@Usb4l^%pt!}uK%(@FtWhxPn#?v_`@a%A)oO-ZPHuIlO_*kzo)}ski1*6#ow%PzXqyajl z0Xk#=I%EJkWB@v306JsZ(HjC=)eJV-~c*s03EokIv|A5 zf7T0Ow(5W|TXjH~tvVpgRvi##s}2aWRR@IGssqAo)d67uI*{l8TXc{Eg+KfT0q#{G z0M8-h9%O4?fDQn0ga560 z0XhIYhX6c>06d2PJcqCVe*kz6VF5Y-Jcj^0hX6cBzTmP|FM#I|faef^=MaGB5P;_p zfaef^=g2p20PO?#1Hf|#z;g(|a|pn52*7g)z;g(|a|pn52*7g)z;g(|a|pn52*7g) zz;g(|a|pn52*7iQJiYVh_yXWL1mHOY;5h`~IRxN21mHOY;5h`~IRxN21mHOY;5h`~ zIRxN21mHOY;5h`~IRxN2Bnud?06d2PJcj^0C&zsR^cn$;Na~QyL7{GHFz;hVDa~QyL7{GHFz;hVDa~QyL7{GHFz;hVDa~QyL7{GHF zz;hVDa~QyL7{GHFz;hT7pChYmxB3^ra~QyL7{GHFz;hVDa~QyL7{GHFz;hVDa~QyL z7{GHFz;hVDa~QyL7{GI61@qSa1MnOM@Eiv490u?l2JjpP@Eiv490u?l2JjpP@Eiv4 zocsV~%Xk3bISk-A4B$Bo;5iK7IkL!iYrO!T!vLPc0G`7Dp2Gm1!vLPc0G`7Dp2Gm1 z!vLPc0G`7Dp2Gm1!vLPc0G?w3JjVifjs?W$SOCwl0G?w3@i`X2b1Z=8SU`M^1@IgT z;5in+b1Z=8$dd6b*AN!Kb1Z=8SOCwl0G?w3JjVifj(qujYg+(3#{zhc1@IgT;5in+ zbL0`kpY`G}2;csAHi5$;WAUFhY2-Tim(9}y@8nGI*!)Kne?JPv{l9+x`SS@U-ox|f z(<5Y#NDBG7j(~ugzB=;n1O9%Zgkhxn|Is$Ifd|1G`ELzKlhEYn!^pQ3P&lN={%o@h Ka`*msoBs;~2SV@w literal 217464 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μ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 diff --git a/Marlin/Menu Plans.xlsx b/Marlin/Menu Plans.xlsx index 45a58e40352d441bd581361d358cee07df009ed5..240b2a210136d97fa9bd23834416466c29ddbb74 100644 GIT binary patch literal 28860 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�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 literal 51386 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 QU_t&ek?spd{qM8?0*~k1G5`Po From 36086d3ca4830a7c05bcceaac98c8369a6abbcf1 Mon Sep 17 00:00:00 2001 From: MatixYo Date: Fri, 7 Feb 2014 19:15:51 +0100 Subject: [PATCH 134/256] Update language.h Updated Polish translations. --- Marlin/language.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index 2d97cc3522..2ef725f9ff 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -220,7 +220,7 @@ #define WELCOME_MSG MACHINE_NAME " Gotowe." #define MSG_SD_INSERTED "Karta wlozona" #define MSG_SD_REMOVED "Karta usunieta" - #define MSG_MAIN "Main" + #define MSG_MAIN "Menu glowne" #define MSG_AUTOSTART "Autostart" #define MSG_DISABLE_STEPPERS "Wylacz silniki" #define MSG_AUTO_HOME "Auto. poz. zerowa" @@ -230,8 +230,8 @@ #define MSG_PREHEAT_ABS "Rozgrzej ABS" #define MSG_PREHEAT_ABS_SETTINGS "Ustawienia roz. ABS" #define MSG_COOLDOWN "Chlodzenie" - #define MSG_SWITCH_PS_ON "Switch Power On" - #define MSG_SWITCH_PS_OFF "Switch Power Off" + #define MSG_SWITCH_PS_ON "Wl. zasilacz" + #define MSG_SWITCH_PS_OFF "Wyl. zasilacz" #define MSG_EXTRUDE "Ekstruzja" #define MSG_RETRACT "Cofanie" #define MSG_MOVE_AXIS "Ruch osi" @@ -273,19 +273,19 @@ #define MSG_RECTRACT "Wycofanie" #define MSG_TEMPERATURE "Temperatura" #define MSG_MOTION "Ruch" - #define MSG_CONTRAST "LCD contrast" + #define MSG_CONTRAST "Kontrast LCD" #define MSG_STORE_EPROM "Zapisz w pamieci" #define MSG_LOAD_EPROM "Wczytaj z pamieci" - #define MSG_RESTORE_FAILSAFE " Ustawienia fabryczne" + #define MSG_RESTORE_FAILSAFE "Ustawienia fabryczne" #define MSG_REFRESH "\004Odswiez" - #define MSG_WATCH "Obserwuj" + #define MSG_WATCH "Ekran glowny" #define MSG_PREPARE "Przygotuj" - #define MSG_CONTROL "Kontroluj" + #define MSG_CONTROL "Ustawienia" #define MSG_TUNE "Strojenie" #define MSG_PAUSE_PRINT "Pauza" #define MSG_RESUME_PRINT "Wznowienie" #define MSG_STOP_PRINT "Stop" - #define MSG_CARD_MENU "Menu SDCard" + #define MSG_CARD_MENU "Menu karty SD" #define MSG_NO_CARD "Brak karty" #define MSG_DWELL "Uspij..." #define MSG_USERWAIT "Czekaj na uzytkownika..." @@ -301,11 +301,11 @@ #define MSG_CONTROL_RETRACT_RECOVER "Cof. wycof. +mm" #define MSG_CONTROL_RETRACT_RECOVERF "Cof. wycof. F" #define MSG_AUTORETRACT "Auto. wycofanie" - #define MSG_FILAMENTCHANGE "Change filament" - #define MSG_INIT_SDCARD "Init. SD-Card" - #define MSG_CNG_SDCARD "Change SD-Card" - #define MSG_ZPROBE_OUT "ZProbe Outside Bed" - #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_FILAMENTCHANGE "Zmien filament" + #define MSG_INIT_SDCARD "Uruchom karte SD" + #define MSG_CNG_SDCARD "Zmien karte SD" + #define MSG_ZPROBE_OUT "Probkuj Z poza lozem" + #define MSG_POSITION_UNKNOWN "Domuj X/Y przed Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" // Serial Console Messages @@ -316,7 +316,7 @@ #define MSG_BROWNOUT_RESET " Reset (spadek napiecia)" #define MSG_WATCHDOG_RESET " Reset (watchdog)" #define MSG_SOFTWARE_RESET " Reset (programowy)" - #define MSG_MARLIN "Marlin " + #define MSG_MARLIN "Marlin" #define MSG_AUTHOR " | Autor: " #define MSG_CONFIGURATION_VER " Ostatnia aktualizacja: " #define MSG_FREE_MEMORY " Wolna pamiec: " @@ -355,8 +355,8 @@ #define MSG_Z_MIN "z_min: " #define MSG_Z_MAX "z_max: " #define MSG_M119_REPORT "Zgloszenie statusu wylacznikow krancowych" - #define MSG_ENDSTOP_HIT "WYZWOLONY" - #define MSG_ENDSTOP_OPEN "otwarty" + #define MSG_ENDSTOP_HIT "Wyzwolony" + #define MSG_ENDSTOP_OPEN "Otwarty" #define MSG_HOTEND_OFFSET "Hotend offsets:" #define MSG_SD_CANT_OPEN_SUBDIR "Nie mozna otworzyc podkatalogu" From 8b67f6f3e89666cafe3b0cadc92e3ece2378a4ed Mon Sep 17 00:00:00 2001 From: Daniel Martinez Date: Sun, 9 Feb 2014 12:54:05 +0100 Subject: [PATCH 135/256] Add Aragonese translation --- Marlin/language.h | 174 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) diff --git a/Marlin/language.h b/Marlin/language.h index 2d97cc3522..66c5c53687 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -16,6 +16,7 @@ // 7 Italian // 8 Portuguese // 9 Finnish +// 10 Aragonese #ifndef LANGUAGE_CHOICE #define LANGUAGE_CHOICE 1 // Pick your language from the list above @@ -1568,5 +1569,178 @@ #define MSG_ERR_COLD_EXTRUDE_STOP " kylmana pursotus estetty" #define MSG_ERR_LONG_EXTRUDE_STOP " liian pitka pursotus estetty" +#endif + +#if LANGUAGE_CHOICE == 10 + +// LCD Menu Messages + #define WELCOME_MSG MACHINE_NAME " Parada." + #define MSG_SD_INSERTED "Tarcheta SD Colocada" + #define MSG_SD_REMOVETZ "Tarcheta SD Retirada" + #define MSG_MAIN "Menu Prencipal" + #define MSG_AUTOSTART " Autostart" + #define MSG_DISABLE_STEPPERS "Amortar Motors" + #define MSG_AUTO_HOME "Levar a l'Orichen" // "Levar Eixes a o Zero" + #define MSG_SET_ORIGIN "Establir Zero" + #define MSG_PREHEAT_PLA "Precalentar PLA" + #define MSG_PREHEAT_PLA_SETTINGS "Achustar temp. PLA" + #define MSG_PREHEAT_ABS "Precalentar ABS" + #define MSG_PREHEAT_ABS_SETTINGS "Achustar temp. ABS" + #define MSG_COOLDOWN "Enfriar" + #define MSG_SWITCH_PS_ON "Enchegar Fuent" + #define MSG_SWITCH_PS_OFF "Desenchegar Fuent" + #define MSG_EXTRUDE "Extruir" + #define MSG_RETRACT "Retraer" + #define MSG_MOVE_AXIS "Mover Eixes" + #define MSG_SPEED "Velocidat" + #define MSG_NOZZLE "Nozzle" + #define MSG_NOZZLE1 "Nozzle2" + #define MSG_NOZZLE2 "Nozzle3" + #define MSG_BED "Base" + #define MSG_FAN_SPEED "Ixoriador" + #define MSG_FLOW "Fluxo" + #define MSG_CONTROL "Control" + #define MSG_MIN "\002 Min" + #define MSG_MAX "\002 Max" + #define MSG_FACTOR "\002 Fact" + #define MSG_AUTOTEMP "Autotemp" + #define MSG_ON "On" + #define MSG_OFF "Off" + #define MSG_PID_P "PID-P" + #define MSG_PID_I "PID-I" + #define MSG_PID_D "PID-D" + #define MSG_PID_C "PID-C" + #define MSG_ACC "Acel" + #define MSG_VXY_JERK "Vxy-jerk" + #define MSG_VZ_JERK "Vz-jerk" + #define MSG_VES_JERK "Ves-jerk" + #define MSG_VMAX "Vmax" + #define MSG_X "x" + #define MSG_Y "y" + #define MSG_Z "z" + #define MSG_Y "y" + #define MSG_VMIN "Vmin" + #define MSG_VTRAV_MIN "VTrav min" + #define MSG_AMAX "Amax" + #define MSG_A_RETRACT "A-retrac." + #define MSG_XSTEPS "X trangos/mm" + #define MSG_YSTEPS "Y trangos/mm" + #define MSG_ZSTEPS "Z trangos/mm" + #define MSG_ESTEPS "Y trangos/mm" + #define MSG_RECTRACT "Retraer" + #define MSG_TEMPERATURE "Temperatura" + #define MSG_MOTION "Movimiento" + #define MSG_STORE_EPROM "Alzar Memoria" + #define MSG_LOBATZ_EPROM "Cargar Memoria" + #define MSG_RESTORE_FAILSAFE "Rest. d'emerchencia" + #define MSG_REFRESH "Tornar a cargar" + #define MSG_WATCH "Monitorizar" + #define MSG_PREPARE "Preparar" + #define MSG_TUNE "Achustar" + #define MSG_PAUSE_PRINT "Pausar Impresion" + #define MSG_RESUME_PRINT "Continar Impresion" + #define MSG_STOP_PRINT "Detener Impresion" + #define MSG_CARD_MENU "Menu de SD" + #define MSG_NO_CARD "No i hai Tarcheta SD" + #define MSG_DWELL "Reposo..." + #define MSG_USERWAIT "Asperando Ordines..." + #define MSG_RESUMING "Continando Impresion" + #define MSG_NO_MOVE "Sin movimiento" + #define MSG_KILLED "ATURADA D'EMERCHENCIA. " + #define MSG_STOPPED "ATURADA." + #define MSG_CONTROL_RETRACT "Retraer mm" + #define MSG_CONTROL_RETRACTF "Retraer F" + #define MSG_CONTROL_RETRACT_ZLIFT "Devantar mm" + #define MSG_CONTROL_RETRACT_RECOVER "DesRet +mm" + #define MSG_CONTROL_RETRACT_RECOVERF "DesRet F" + #define MSG_AUTORETRACT "AutoRetr." + #define MSG_FILAMENTCHANGE "Change filament" + #define MSG_INIT_SDCARD "Encetando. Tarcheta-SD" + #define MSG_CNG_SDCARD "Cambiar Tarcheta-SD" + #define MSG_RECTRACT_WIDE "Retraer" + #define MSG_TEMPERATURE_WIDE "Temperatura" + #define MSG_TEMPERATURE_RTN "Temperatura" + #define MSG_MAIN_WIDE "Menu Prencipal" + #define MSG_MOTION_WIDE "Movimiento" + #define MSG_PREPARE_ALT "Preparar" + #define MSG_CONTROL_ARROW "Control" + #define MSG_RETRACT_ARROW "Retraer" + #define MSG_PART_RELEASE "Desacople Parcial" + #define MSG_STEPPER_RELEASED "Desacoplada." + #define MSG_ZPROBE_OUT "ZProbe Outside Bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" + +// Serial Console Messages + + #define MSG_Enqueing "En coda \"" + #define MSG_POWERUP "PowerUp" + #define MSG_EXTERNAL_RESET " Reset Externo" + #define MSG_BROWNOUT_RESET " Reset por Voltaje Incorrecto" + #define MSG_WATCHDOG_RESET " Reset por Bloqueo" + #define MSG_SOFTWARE_RESET " Reset por Software" + #define MSG_MARLIN "Marlin " + #define MSG_AUTHOR " | Autor: " + #define MSG_CONFIGURATION_VEYER " Zaguer esvielle: " + #define MSG_FREE_MEMORY " Memoria libre: " + #define MSG_PLANNER_BUFFER_BYTES " PlannerBufferBytes: " + #define MSG_OK "ok" + #define MSG_FILE_SAVED "Guardau." + #define MSG_ERR_LINE_NO "O Numero de Linea no ye igual a l'Ultimo Numero de Linea+1, Ultima Linea:" + #define MSG_ERR_CHECKSUM_MISMATCH "o checksum no coincide, Ultima Linea:" + #define MSG_ERR_NO_CHECKSUM "No se podió trobar o Checksum con o numero de linea, Ultima Linea:" + #define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No se trobo o Numero de Linea con o Checksum, Ultima Linea:" + #define MSG_FILE_PRINTED "Impresion rematada" + #define MSG_BEGIN_FILE_LIST "Prencipio d'a lista de fichero" + #define MSG_END_FILE_LIST "Fin d'a lista de fichero" + #define MSG_M104_INVALID_EXTRUDER "M104 Extrusor Invalido " + #define MSG_M105_INVALID_EXTRUDER "M105 Extrusor Invalido " + #define MSG_M200_INVALID_EXTRUDER "M200 Extrusor Invalido " + #define MSG_M218_INVALID_EXTRUDER "M218 Extrusor Invalido " + #define MSG_ERR_NO_THERMISTORS "No i hai termistores - no temp" + #define MSG_M109_INVALID_EXTRUDER "M109 Extrusor Invalido " + #define MSG_HEATING "Calentando..." + #define MSG_HEATING_COMPLETE "Calentamiento Feito." + #define MSG_BED_HEATING "Calentando la base." + #define MSG_BED_DONE "Base Calient." + #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" + #define MSG_COUNT_X " Cuenta X:" + #define MSG_ERR_KILLED "Impresora Aturada con kill()!!" + #define MSG_ERR_STOPPED "Impresora aturada por errors. Apanye a error y use M999 Ta reiniciar!. (a temperatura se reestablece. Ajustela antes de continar)" + #define MSG_RESEND "Reninviar:" + #define MSG_UNKNOWN_COMMAND "Comando Desconoixiu:\"" + #define MSG_ACTIVE_EXTRUDER "Extrusor Activo: " + #define MSG_INVALID_EXTRUDER "Extrusor Invalido" + #define MSG_X_MIN "x_min: " + #define MSG_X_MAX "x_max: " + #define MSG_Y_MIN "y_min: " + #define MSG_Y_MAX "y_max: " + #define MSG_Z_MIN "z_min: " + #define MSG_Z_MAX "z_max: " + #define MSG_M119_REPORT "Comprobando fins de corrida." + #define MSG_ENDSTOP_HIT "PULSAU" + #define MSG_ENDSTOP_OPEN "ubierto" + #define MSG_HOTEND_OFFSET "Hotend offsets:" + #define MSG_SD_CANT_OPEN_SUBDIR "No se podió ubrir a subcarpeta." + #define MSG_SD_INIT_FAIL "Fallo en encetar a SD" + #define MSG_SD_VOL_INIT_FAIL "Fallo en amontar o volumen" + #define MSG_SD_OPENROOT_FAIL "Fallo en ubrir a carpeta raiz" + #define MSG_SD_CARD_OK "Tarcheta SD OK" + #define MSG_SD_WORKDIR_FAIL "Fallo en ubrir a carpeta de treballo" + #define MSG_SD_OPEN_FILE_FAIL "Error en ubrir, Fichero: " + #define MSG_SD_FILE_OPENED "Fichero ubierto:" + #define MSG_SD_SIZE " Grandaria:" + #define MSG_SD_FILE_SELECTED "Fichero Seleccionau" + #define MSG_SD_WRITE_TO_FILE "Escribindo en o fichero: " + #define MSG_SD_PRINTING_BYTE "SD imprentando o byte " + #define MSG_SD_NOT_PRINTING "No se ye imprentando con SD" + #define MSG_SD_ERR_WRITE_TO_FILE "Error en escribir en o fichero" + #define MSG_SD_CANT_ENTER_SUBDIR "No se puede ubrir a carpeta:" + + #define MSG_STEPPER_TOO_HIGH "Steprate masiau alto : " + #define MSG_ENDSTOPS_HIT "S'ha tocau a fin de carril: " + #define MSG_ERR_COLD_EXTRUDE_STOP " extrusion fria privada" + #define MSG_ERR_LONG_EXTRUDE_STOP " extrusion masiau larga privada" + #endif #endif // ifndef LANGUAGE_H From 19530c99459b0db67975a66a5dc70e22e994c472 Mon Sep 17 00:00:00 2001 From: nothinman Date: Sun, 9 Feb 2014 16:21:00 +0000 Subject: [PATCH 136/256] Revert "Merge pull request #756 from danielmartinez/aragones" This reverts commit 6f76066ab3cf386e50777fb4a612dd39b25cc62b, reversing changes made to e1ae7952ebff25094196f93baa6b53c2c12193f7. --- Marlin/language.h | 174 ---------------------------------------------- 1 file changed, 174 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index 66c5c53687..2d97cc3522 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -16,7 +16,6 @@ // 7 Italian // 8 Portuguese // 9 Finnish -// 10 Aragonese #ifndef LANGUAGE_CHOICE #define LANGUAGE_CHOICE 1 // Pick your language from the list above @@ -1569,178 +1568,5 @@ #define MSG_ERR_COLD_EXTRUDE_STOP " kylmana pursotus estetty" #define MSG_ERR_LONG_EXTRUDE_STOP " liian pitka pursotus estetty" -#endif - -#if LANGUAGE_CHOICE == 10 - -// LCD Menu Messages - #define WELCOME_MSG MACHINE_NAME " Parada." - #define MSG_SD_INSERTED "Tarcheta SD Colocada" - #define MSG_SD_REMOVETZ "Tarcheta SD Retirada" - #define MSG_MAIN "Menu Prencipal" - #define MSG_AUTOSTART " Autostart" - #define MSG_DISABLE_STEPPERS "Amortar Motors" - #define MSG_AUTO_HOME "Levar a l'Orichen" // "Levar Eixes a o Zero" - #define MSG_SET_ORIGIN "Establir Zero" - #define MSG_PREHEAT_PLA "Precalentar PLA" - #define MSG_PREHEAT_PLA_SETTINGS "Achustar temp. PLA" - #define MSG_PREHEAT_ABS "Precalentar ABS" - #define MSG_PREHEAT_ABS_SETTINGS "Achustar temp. ABS" - #define MSG_COOLDOWN "Enfriar" - #define MSG_SWITCH_PS_ON "Enchegar Fuent" - #define MSG_SWITCH_PS_OFF "Desenchegar Fuent" - #define MSG_EXTRUDE "Extruir" - #define MSG_RETRACT "Retraer" - #define MSG_MOVE_AXIS "Mover Eixes" - #define MSG_SPEED "Velocidat" - #define MSG_NOZZLE "Nozzle" - #define MSG_NOZZLE1 "Nozzle2" - #define MSG_NOZZLE2 "Nozzle3" - #define MSG_BED "Base" - #define MSG_FAN_SPEED "Ixoriador" - #define MSG_FLOW "Fluxo" - #define MSG_CONTROL "Control" - #define MSG_MIN "\002 Min" - #define MSG_MAX "\002 Max" - #define MSG_FACTOR "\002 Fact" - #define MSG_AUTOTEMP "Autotemp" - #define MSG_ON "On" - #define MSG_OFF "Off" - #define MSG_PID_P "PID-P" - #define MSG_PID_I "PID-I" - #define MSG_PID_D "PID-D" - #define MSG_PID_C "PID-C" - #define MSG_ACC "Acel" - #define MSG_VXY_JERK "Vxy-jerk" - #define MSG_VZ_JERK "Vz-jerk" - #define MSG_VES_JERK "Ves-jerk" - #define MSG_VMAX "Vmax" - #define MSG_X "x" - #define MSG_Y "y" - #define MSG_Z "z" - #define MSG_Y "y" - #define MSG_VMIN "Vmin" - #define MSG_VTRAV_MIN "VTrav min" - #define MSG_AMAX "Amax" - #define MSG_A_RETRACT "A-retrac." - #define MSG_XSTEPS "X trangos/mm" - #define MSG_YSTEPS "Y trangos/mm" - #define MSG_ZSTEPS "Z trangos/mm" - #define MSG_ESTEPS "Y trangos/mm" - #define MSG_RECTRACT "Retraer" - #define MSG_TEMPERATURE "Temperatura" - #define MSG_MOTION "Movimiento" - #define MSG_STORE_EPROM "Alzar Memoria" - #define MSG_LOBATZ_EPROM "Cargar Memoria" - #define MSG_RESTORE_FAILSAFE "Rest. d'emerchencia" - #define MSG_REFRESH "Tornar a cargar" - #define MSG_WATCH "Monitorizar" - #define MSG_PREPARE "Preparar" - #define MSG_TUNE "Achustar" - #define MSG_PAUSE_PRINT "Pausar Impresion" - #define MSG_RESUME_PRINT "Continar Impresion" - #define MSG_STOP_PRINT "Detener Impresion" - #define MSG_CARD_MENU "Menu de SD" - #define MSG_NO_CARD "No i hai Tarcheta SD" - #define MSG_DWELL "Reposo..." - #define MSG_USERWAIT "Asperando Ordines..." - #define MSG_RESUMING "Continando Impresion" - #define MSG_NO_MOVE "Sin movimiento" - #define MSG_KILLED "ATURADA D'EMERCHENCIA. " - #define MSG_STOPPED "ATURADA." - #define MSG_CONTROL_RETRACT "Retraer mm" - #define MSG_CONTROL_RETRACTF "Retraer F" - #define MSG_CONTROL_RETRACT_ZLIFT "Devantar mm" - #define MSG_CONTROL_RETRACT_RECOVER "DesRet +mm" - #define MSG_CONTROL_RETRACT_RECOVERF "DesRet F" - #define MSG_AUTORETRACT "AutoRetr." - #define MSG_FILAMENTCHANGE "Change filament" - #define MSG_INIT_SDCARD "Encetando. Tarcheta-SD" - #define MSG_CNG_SDCARD "Cambiar Tarcheta-SD" - #define MSG_RECTRACT_WIDE "Retraer" - #define MSG_TEMPERATURE_WIDE "Temperatura" - #define MSG_TEMPERATURE_RTN "Temperatura" - #define MSG_MAIN_WIDE "Menu Prencipal" - #define MSG_MOTION_WIDE "Movimiento" - #define MSG_PREPARE_ALT "Preparar" - #define MSG_CONTROL_ARROW "Control" - #define MSG_RETRACT_ARROW "Retraer" - #define MSG_PART_RELEASE "Desacople Parcial" - #define MSG_STEPPER_RELEASED "Desacoplada." - #define MSG_ZPROBE_OUT "ZProbe Outside Bed" - #define MSG_POSITION_UNKNOWN "Home X/Y before Z" - #define MSG_ZPROBE_ZOFFSET "Z Offset" - -// Serial Console Messages - - #define MSG_Enqueing "En coda \"" - #define MSG_POWERUP "PowerUp" - #define MSG_EXTERNAL_RESET " Reset Externo" - #define MSG_BROWNOUT_RESET " Reset por Voltaje Incorrecto" - #define MSG_WATCHDOG_RESET " Reset por Bloqueo" - #define MSG_SOFTWARE_RESET " Reset por Software" - #define MSG_MARLIN "Marlin " - #define MSG_AUTHOR " | Autor: " - #define MSG_CONFIGURATION_VEYER " Zaguer esvielle: " - #define MSG_FREE_MEMORY " Memoria libre: " - #define MSG_PLANNER_BUFFER_BYTES " PlannerBufferBytes: " - #define MSG_OK "ok" - #define MSG_FILE_SAVED "Guardau." - #define MSG_ERR_LINE_NO "O Numero de Linea no ye igual a l'Ultimo Numero de Linea+1, Ultima Linea:" - #define MSG_ERR_CHECKSUM_MISMATCH "o checksum no coincide, Ultima Linea:" - #define MSG_ERR_NO_CHECKSUM "No se podió trobar o Checksum con o numero de linea, Ultima Linea:" - #define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No se trobo o Numero de Linea con o Checksum, Ultima Linea:" - #define MSG_FILE_PRINTED "Impresion rematada" - #define MSG_BEGIN_FILE_LIST "Prencipio d'a lista de fichero" - #define MSG_END_FILE_LIST "Fin d'a lista de fichero" - #define MSG_M104_INVALID_EXTRUDER "M104 Extrusor Invalido " - #define MSG_M105_INVALID_EXTRUDER "M105 Extrusor Invalido " - #define MSG_M200_INVALID_EXTRUDER "M200 Extrusor Invalido " - #define MSG_M218_INVALID_EXTRUDER "M218 Extrusor Invalido " - #define MSG_ERR_NO_THERMISTORS "No i hai termistores - no temp" - #define MSG_M109_INVALID_EXTRUDER "M109 Extrusor Invalido " - #define MSG_HEATING "Calentando..." - #define MSG_HEATING_COMPLETE "Calentamiento Feito." - #define MSG_BED_HEATING "Calentando la base." - #define MSG_BED_DONE "Base Calient." - #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" - #define MSG_COUNT_X " Cuenta X:" - #define MSG_ERR_KILLED "Impresora Aturada con kill()!!" - #define MSG_ERR_STOPPED "Impresora aturada por errors. Apanye a error y use M999 Ta reiniciar!. (a temperatura se reestablece. Ajustela antes de continar)" - #define MSG_RESEND "Reninviar:" - #define MSG_UNKNOWN_COMMAND "Comando Desconoixiu:\"" - #define MSG_ACTIVE_EXTRUDER "Extrusor Activo: " - #define MSG_INVALID_EXTRUDER "Extrusor Invalido" - #define MSG_X_MIN "x_min: " - #define MSG_X_MAX "x_max: " - #define MSG_Y_MIN "y_min: " - #define MSG_Y_MAX "y_max: " - #define MSG_Z_MIN "z_min: " - #define MSG_Z_MAX "z_max: " - #define MSG_M119_REPORT "Comprobando fins de corrida." - #define MSG_ENDSTOP_HIT "PULSAU" - #define MSG_ENDSTOP_OPEN "ubierto" - #define MSG_HOTEND_OFFSET "Hotend offsets:" - #define MSG_SD_CANT_OPEN_SUBDIR "No se podió ubrir a subcarpeta." - #define MSG_SD_INIT_FAIL "Fallo en encetar a SD" - #define MSG_SD_VOL_INIT_FAIL "Fallo en amontar o volumen" - #define MSG_SD_OPENROOT_FAIL "Fallo en ubrir a carpeta raiz" - #define MSG_SD_CARD_OK "Tarcheta SD OK" - #define MSG_SD_WORKDIR_FAIL "Fallo en ubrir a carpeta de treballo" - #define MSG_SD_OPEN_FILE_FAIL "Error en ubrir, Fichero: " - #define MSG_SD_FILE_OPENED "Fichero ubierto:" - #define MSG_SD_SIZE " Grandaria:" - #define MSG_SD_FILE_SELECTED "Fichero Seleccionau" - #define MSG_SD_WRITE_TO_FILE "Escribindo en o fichero: " - #define MSG_SD_PRINTING_BYTE "SD imprentando o byte " - #define MSG_SD_NOT_PRINTING "No se ye imprentando con SD" - #define MSG_SD_ERR_WRITE_TO_FILE "Error en escribir en o fichero" - #define MSG_SD_CANT_ENTER_SUBDIR "No se puede ubrir a carpeta:" - - #define MSG_STEPPER_TOO_HIGH "Steprate masiau alto : " - #define MSG_ENDSTOPS_HIT "S'ha tocau a fin de carril: " - #define MSG_ERR_COLD_EXTRUDE_STOP " extrusion fria privada" - #define MSG_ERR_LONG_EXTRUDE_STOP " extrusion masiau larga privada" - #endif #endif // ifndef LANGUAGE_H From f64592e3628e5df9b46439bb48cefca597fae499 Mon Sep 17 00:00:00 2001 From: Daniel Martinez Date: Sun, 9 Feb 2014 18:19:37 +0100 Subject: [PATCH 137/256] Add Aragonese translation --- Marlin/language.h | 175 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 174 insertions(+), 1 deletion(-) diff --git a/Marlin/language.h b/Marlin/language.h index 2ef725f9ff..7f534718db 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -18,7 +18,7 @@ // 9 Finnish #ifndef LANGUAGE_CHOICE -#define LANGUAGE_CHOICE 1 // Pick your language from the list above +#define LANGUAGE_CHOICE 10 // Pick your language from the list above #endif #define PROTOCOL_VERSION "1.0" @@ -1568,5 +1568,178 @@ #define MSG_ERR_COLD_EXTRUDE_STOP " kylmana pursotus estetty" #define MSG_ERR_LONG_EXTRUDE_STOP " liian pitka pursotus estetty" +#endif + +#if LANGUAGE_CHOICE == 10 + +// LCD Menu Messages + #define WELCOME_MSG MACHINE_NAME " Parada." + #define MSG_SD_INSERTED "Tarcheta SD Colocada" + #define MSG_SD_REMOVED "Tarcheta SD Retirada" + #define MSG_MAIN "Menu Prencipal" + #define MSG_AUTOSTART " Autostart" + #define MSG_DISABLE_STEPPERS "Amortar Motors" + #define MSG_AUTO_HOME "Levar a l'Orichen" // "Levar Eixes a o Zero" + #define MSG_SET_ORIGIN "Establir Zero" + #define MSG_PREHEAT_PLA "Precalentar PLA" + #define MSG_PREHEAT_PLA_SETTINGS "Achustar temp. PLA" + #define MSG_PREHEAT_ABS "Precalentar ABS" + #define MSG_PREHEAT_ABS_SETTINGS "Achustar temp. ABS" + #define MSG_COOLDOWN "Enfriar" + #define MSG_SWITCH_PS_ON "Enchegar Fuent" + #define MSG_SWITCH_PS_OFF "Desenchegar Fuent" + #define MSG_EXTRUDE "Extruir" + #define MSG_RETRACT "Retraer" + #define MSG_MOVE_AXIS "Mover Eixes" + #define MSG_SPEED "Velocidat" + #define MSG_NOZZLE "Nozzle" + #define MSG_NOZZLE1 "Nozzle2" + #define MSG_NOZZLE2 "Nozzle3" + #define MSG_BED "Base" + #define MSG_FAN_SPEED "Ixoriador" + #define MSG_FLOW "Fluxo" + #define MSG_CONTROL "Control" + #define MSG_MIN "\002 Min" + #define MSG_MAX "\002 Max" + #define MSG_FACTOR "\002 Fact" + #define MSG_AUTOTEMP "Autotemp" + #define MSG_ON "On" + #define MSG_OFF "Off" + #define MSG_PID_P "PID-P" + #define MSG_PID_I "PID-I" + #define MSG_PID_D "PID-D" + #define MSG_PID_C "PID-C" + #define MSG_ACC "Acel" + #define MSG_VXY_JERK "Vxy-jerk" + #define MSG_VZ_JERK "Vz-jerk" + #define MSG_VE_JERK "Ves-jerk" + #define MSG_VMAX "Vmax" + #define MSG_X "x" + #define MSG_Y "y" + #define MSG_Z "z" + #define MSG_E "y" + #define MSG_VMIN "Vmin" + #define MSG_VTRAV_MIN "VTrav min" + #define MSG_AMAX "Amax" + #define MSG_A_RETRACT "A-retrac." + #define MSG_XSTEPS "X trangos/mm" + #define MSG_YSTEPS "Y trangos/mm" + #define MSG_ZSTEPS "Z trangos/mm" + #define MSG_ESTEPS "E trangos/mm" + #define MSG_RECTRACT "Retraer" + #define MSG_TEMPERATURE "Temperatura" + #define MSG_MOTION "Movimiento" + #define MSG_STORE_EPROM "Alzar Memoria" + #define MSG_LOAD_EPROM "Cargar Memoria" + #define MSG_RESTORE_FAILSAFE "Rest. d'emerchencia" + #define MSG_REFRESH "Tornar a cargar" + #define MSG_WATCH "Monitorizar" + #define MSG_PREPARE "Preparar" + #define MSG_TUNE "Achustar" + #define MSG_PAUSE_PRINT "Pausar Impresion" + #define MSG_RESUME_PRINT "Continar Impresion" + #define MSG_STOP_PRINT "Detener Impresion" + #define MSG_CARD_MENU "Menu de SD" + #define MSG_NO_CARD "No i hai Tarcheta SD" + #define MSG_DWELL "Reposo..." + #define MSG_USERWAIT "Asperando Ordines..." + #define MSG_RESUMING "Continando Impresion" + #define MSG_NO_MOVE "Sin movimiento" + #define MSG_KILLED "ATURADA D'EMERCHENCIA. " + #define MSG_STOPPED "ATURADA." + #define MSG_CONTROL_RETRACT "Retraer mm" + #define MSG_CONTROL_RETRACTF "Retraer F" + #define MSG_CONTROL_RETRACT_ZLIFT "Devantar mm" + #define MSG_CONTROL_RETRACT_RECOVER "DesRet +mm" + #define MSG_CONTROL_RETRACT_RECOVERF "DesRet F" + #define MSG_AUTORETRACT "AutoRetr." + #define MSG_FILAMENTCHANGE "Cambear" + #define MSG_INIT_SDCARD "Encetando. Tarcheta-SD" + #define MSG_CNG_SDCARD "Cambiar Tarcheta-SD" + #define MSG_RECTRACT_WIDE "Retraer" + #define MSG_TEMPERATURE_WIDE "Temperatura" + #define MSG_TEMPERATURE_RTN "Temperatura" + #define MSG_MAIN_WIDE "Menu Prencipal" + #define MSG_MOTION_WIDE "Movimiento" + #define MSG_PREPARE_ALT "Preparar" + #define MSG_CONTROL_ARROW "Control" + #define MSG_RETRACT_ARROW "Retraer" + #define MSG_PART_RELEASE "Desacople Parcial" + #define MSG_STEPPER_RELEASED "Desacoplada." + #define MSG_ZPROBE_OUT "ZProbe Outside Bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" + +// Serial Console Messages + + #define MSG_Enqueing "En coda \"" + #define MSG_POWERUP "PowerUp" + #define MSG_EXTERNAL_RESET " Reset Externo" + #define MSG_BROWNOUT_RESET " Reset por Voltaje Incorrecto" + #define MSG_WATCHDOG_RESET " Reset por Bloqueo" + #define MSG_SOFTWARE_RESET " Reset por Software" + #define MSG_MARLIN "Marlin " + #define MSG_AUTHOR " | Autor: " + #define MSG_CONFIGURATION_VER " Zaguer esvielle: " + #define MSG_FREE_MEMORY " Memoria libre: " + #define MSG_PLANNER_BUFFER_BYTES " PlannerBufferBytes: " + #define MSG_OK "ok" + #define MSG_FILE_SAVED "Guardau." + #define MSG_ERR_LINE_NO "O Numero de Linea no ye igual a l'Ultimo Numero de Linea+1, Ultima Linea:" + #define MSG_ERR_CHECKSUM_MISMATCH "o checksum no coincide, Ultima Linea:" + #define MSG_ERR_NO_CHECKSUM "No se podió trobar o Checksum con o numero de linea, Ultima Linea:" + #define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No se trobo o Numero de Linea con o Checksum, Ultima Linea:" + #define MSG_FILE_PRINTED "Impresion rematada" + #define MSG_BEGIN_FILE_LIST "Prencipio d'a lista de fichero" + #define MSG_END_FILE_LIST "Fin d'a lista de fichero" + #define MSG_M104_INVALID_EXTRUDER "M104 Extrusor Invalido " + #define MSG_M105_INVALID_EXTRUDER "M105 Extrusor Invalido " + #define MSG_M200_INVALID_EXTRUDER "M200 Extrusor Invalido " + #define MSG_M218_INVALID_EXTRUDER "M218 Extrusor Invalido " + #define MSG_ERR_NO_THERMISTORS "No i hai termistores - no temp" + #define MSG_M109_INVALID_EXTRUDER "M109 Extrusor Invalido " + #define MSG_HEATING "Calentando..." + #define MSG_HEATING_COMPLETE "Calentamiento Feito." + #define MSG_BED_HEATING "Calentando la base." + #define MSG_BED_DONE "Base Calient." + #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" + #define MSG_COUNT_X " Cuenta X:" + #define MSG_ERR_KILLED "Impresora Aturada con kill()!!" + #define MSG_ERR_STOPPED "Impresora aturada por errors. Apanye a error y use M999 Ta reiniciar!. (a temperatura se reestablece. Ajustela antes de continar)" + #define MSG_RESEND "Reninviar:" + #define MSG_UNKNOWN_COMMAND "Comando Desconoixiu:\"" + #define MSG_ACTIVE_EXTRUDER "Extrusor Activo: " + #define MSG_INVALID_EXTRUDER "Extrusor Invalido" + #define MSG_X_MIN "x_min: " + #define MSG_X_MAX "x_max: " + #define MSG_Y_MIN "y_min: " + #define MSG_Y_MAX "y_max: " + #define MSG_Z_MIN "z_min: " + #define MSG_Z_MAX "z_max: " + #define MSG_M119_REPORT "Comprobando fins de corrida." + #define MSG_ENDSTOP_HIT "PULSAU" + #define MSG_ENDSTOP_OPEN "ubierto" + #define MSG_HOTEND_OFFSET "Hotend offsets:" + #define MSG_SD_CANT_OPEN_SUBDIR "No se podió ubrir a subcarpeta." + #define MSG_SD_INIT_FAIL "Fallo en encetar a SD" + #define MSG_SD_VOL_INIT_FAIL "Fallo en amontar o volumen" + #define MSG_SD_OPENROOT_FAIL "Fallo en ubrir a carpeta raiz" + #define MSG_SD_CARD_OK "Tarcheta SD OK" + #define MSG_SD_WORKDIR_FAIL "Fallo en ubrir a carpeta de treballo" + #define MSG_SD_OPEN_FILE_FAIL "Error en ubrir, Fichero: " + #define MSG_SD_FILE_OPENED "Fichero ubierto:" + #define MSG_SD_SIZE " Grandaria:" + #define MSG_SD_FILE_SELECTED "Fichero Seleccionau" + #define MSG_SD_WRITE_TO_FILE "Escribindo en o fichero: " + #define MSG_SD_PRINTING_BYTE "SD imprentando o byte " + #define MSG_SD_NOT_PRINTING "No se ye imprentando con SD" + #define MSG_SD_ERR_WRITE_TO_FILE "Error en escribir en o fichero" + #define MSG_SD_CANT_ENTER_SUBDIR "No se puede ubrir a carpeta:" + + #define MSG_STEPPER_TOO_HIGH "Steprate masiau alto : " + #define MSG_ENDSTOPS_HIT "S'ha tocau a fin de carril: " + #define MSG_ERR_COLD_EXTRUDE_STOP " extrusion fria privada" + #define MSG_ERR_LONG_EXTRUDE_STOP " extrusion masiau larga privada" + #endif #endif // ifndef LANGUAGE_H From c8e5a82d49b7365f3dc1956535ce590dc47637e0 Mon Sep 17 00:00:00 2001 From: Daniel Martinez Date: Sun, 9 Feb 2014 18:24:24 +0100 Subject: [PATCH 138/256] keep English as default lang. --- Marlin/language.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Marlin/language.h b/Marlin/language.h index 7f534718db..d092726d2b 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -16,9 +16,10 @@ // 7 Italian // 8 Portuguese // 9 Finnish +// 10 Aragonese #ifndef LANGUAGE_CHOICE -#define LANGUAGE_CHOICE 10 // Pick your language from the list above +#define LANGUAGE_CHOICE 1 // Pick your language from the list above #endif #define PROTOCOL_VERSION "1.0" From bdd0211aeb336f8453155cbf2a0ce24819a7ec96 Mon Sep 17 00:00:00 2001 From: Mark Hanford Date: Tue, 11 Feb 2014 13:54:43 +0000 Subject: [PATCH 139/256] Move strings in ultralcd.cpp into language.h. --- Marlin/language.h | 140 +++++++++++++++++++++++++++++++++++++++++++- Marlin/ultralcd.cpp | 30 +++++----- 2 files changed, 154 insertions(+), 16 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index 2ef725f9ff..717b0d7b5e 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -70,6 +70,13 @@ #define MSG_EXTRUDE "Extrude" #define MSG_RETRACT "Retract" #define MSG_MOVE_AXIS "Move Axis" + #define MSG_MOVE_X "Move X" + #define MSG_MOVE_Y "Move Y" + #define MSG_MOVE_Z "Move Z" + #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_01MM "Move 0.1mm" + #define MSG_MOVE_1MM "Move 1mm" + #define MSG_MOVE_10MM "Move 10mm" #define MSG_SPEED "Speed" #define MSG_NOZZLE "Nozzle" #define MSG_NOZZLE1 "Nozzle2" @@ -139,6 +146,12 @@ #define MSG_ZPROBE_OUT "ZProbe Outside Bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_BABYSTEP_X "Babystep X" + #define MSG_BABYSTEP_Y "Babystep Y" + #define MSG_BABYSTEP_Z "Babystep Z" + #define MSG_ENDSTOP_ABORT "Endstop abort" + #define MSG_CONTRAST "Contrast" + // Serial Console Messages #define MSG_Enqueing "enqueing \"" @@ -210,6 +223,9 @@ #define MSG_ENDSTOPS_HIT "endstops hit: " #define MSG_ERR_COLD_EXTRUDE_STOP " cold extrusion prevented" #define MSG_ERR_LONG_EXTRUDE_STOP " too long extrusion prevented" + #define MSG_BABYSTEPPING_X "Babystepping X" + #define MSG_BABYSTEPPING_Y "Babystepping Y" + #define MSG_BABYSTEPPING_Z "Babystepping Z" #endif @@ -235,6 +251,13 @@ #define MSG_EXTRUDE "Ekstruzja" #define MSG_RETRACT "Cofanie" #define MSG_MOVE_AXIS "Ruch osi" + #define MSG_MOVE_X "Move X" + #define MSG_MOVE_Y "Move Y" + #define MSG_MOVE_Z "Move Z" + #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_01MM "Move 0.1mm" + #define MSG_MOVE_1MM "Move 1mm" + #define MSG_MOVE_10MM "Move 10mm" #define MSG_SPEED "Predkosc" #define MSG_NOZZLE "Dysza" #define MSG_NOZZLE1 "Dysza2" @@ -307,6 +330,11 @@ #define MSG_ZPROBE_OUT "Probkuj Z poza lozem" #define MSG_POSITION_UNKNOWN "Domuj X/Y przed Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_BABYSTEP_X "Babystep X" + #define MSG_BABYSTEP_Y "Babystep Y" + #define MSG_BABYSTEP_Z "Babystep Z" + #define MSG_ENDSTOP_ABORT "Endstop abort" + #define MSG_CONTRAST "Contrast" // Serial Console Messages @@ -379,6 +407,9 @@ #define MSG_ENDSTOPS_HIT "Wylacznik krancowy zostal wyzwolony na pozycji: " #define MSG_ERR_COLD_EXTRUDE_STOP " uniemozliwiono zimna ekstruzje" #define MSG_ERR_LONG_EXTRUDE_STOP " uniemozliwiono zbyt dluga ekstruzje" + #define MSG_BABYSTEPPING_X "Babystepping X" + #define MSG_BABYSTEPPING_Y "Babystepping Y" + #define MSG_BABYSTEPPING_Z "Babystepping Z" #endif @@ -405,6 +436,13 @@ #define MSG_PREHEAT_PLA "Prechauffage PLA" #define MSG_PREHEAT_ABS "Prechauffage ABS" #define MSG_MOVE_AXIS "Deplacer un axe" + #define MSG_MOVE_X "Move X" + #define MSG_MOVE_Y "Move Y" + #define MSG_MOVE_Z "Move Z" + #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_01MM "Move 0.1mm" + #define MSG_MOVE_1MM "Move 1mm" + #define MSG_MOVE_10MM "Move 10mm" #define MSG_SPEED " Vitesse" #define MSG_NOZZLE "Buse" #define MSG_NOZZLE1 "Buse2" @@ -475,6 +513,11 @@ #define MSG_ZPROBE_OUT "ZProbe Outside Bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_BABYSTEP_X "Babystep X" + #define MSG_BABYSTEP_Y "Babystep Y" + #define MSG_BABYSTEP_Z "Babystep Z" + #define MSG_ENDSTOP_ABORT "Endstop abort" + #define MSG_CONTRAST "Contrast" // Serial Console Messages @@ -547,6 +590,9 @@ #define MSG_ENDSTOPS_HIT "Fin de course atteint: " #define MSG_ERR_COLD_EXTRUDE_STOP " Extrusion a froid evitee" #define MSG_ERR_LONG_EXTRUDE_STOP " Extrusion longue evitee" + #define MSG_BABYSTEPPING_X "Babystepping X" + #define MSG_BABYSTEPPING_Y "Babystepping Y" + #define MSG_BABYSTEPPING_Z "Babystepping Z" #endif @@ -574,6 +620,13 @@ #define MSG_EXTRUDE "Extrude" #define MSG_RETRACT "Retract" #define MSG_MOVE_AXIS "Achsen bewegen" + #define MSG_MOVE_X "X bewegen" + #define MSG_MOVE_Y "Y bewegen" + #define MSG_MOVE_Z "Z bewegen" + #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_01MM "0.1mm bewegen" + #define MSG_MOVE_1MM "1mm bewegen" + #define MSG_MOVE_10MM "10mm bewegen" #define MSG_SPEED "Geschw" #define MSG_NOZZLE "Düse" #define MSG_NOZZLE1 "Düse2" @@ -646,6 +699,11 @@ #define MSG_ZPROBE_OUT "ZProbe Outside Bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_BABYSTEP_X "Babystep X" + #define MSG_BABYSTEP_Y "Babystep Y" + #define MSG_BABYSTEP_Z "Babystep Z" + #define MSG_ENDSTOP_ABORT "Endstop abort" + #define MSG_CONTRAST "Contrast" // Serial Console Messages @@ -718,6 +776,9 @@ #define MSG_ENDSTOPS_HIT "endstops hit: " #define MSG_ERR_COLD_EXTRUDE_STOP " cold extrusion prevented" #define MSG_ERR_LONG_EXTRUDE_STOP " too long extrusion prevented" + #define MSG_BABYSTEPPING_X "Babystepping X" + #define MSG_BABYSTEPPING_Y "Babystepping Y" + #define MSG_BABYSTEPPING_Z "Babystepping Z" #endif @@ -743,6 +804,13 @@ #define MSG_EXTRUDE "Extruir" #define MSG_RETRACT "Retraer" #define MSG_MOVE_AXIS "Mover Ejes" + #define MSG_MOVE_X "Move X" + #define MSG_MOVE_Y "Move Y" + #define MSG_MOVE_Z "Move Z" + #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_01MM "Move 0.1mm" + #define MSG_MOVE_1MM "Move 1mm" + #define MSG_MOVE_10MM "Move 10mm" #define MSG_SPEED "Velocidad" #define MSG_NOZZLE "Nozzle" #define MSG_NOZZLE1 "Nozzle2" @@ -821,6 +889,11 @@ #define MSG_ZPROBE_OUT "ZProbe Outside Bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_BABYSTEP_X "Babystep X" + #define MSG_BABYSTEP_Y "Babystep Y" + #define MSG_BABYSTEP_Z "Babystep Z" + #define MSG_ENDSTOP_ABORT "Endstop abort" + #define MSG_CONTRAST "Contrast" // Serial Console Messages @@ -892,6 +965,9 @@ #define MSG_ENDSTOPS_HIT "Se ha tocado el fin de carril: " #define MSG_ERR_COLD_EXTRUDE_STOP " extrusion fria evitada" #define MSG_ERR_LONG_EXTRUDE_STOP " extrusion demasiado larga evitada" + #define MSG_BABYSTEPPING_X "Babystepping X" + #define MSG_BABYSTEPPING_Y "Babystepping Y" + #define MSG_BABYSTEPPING_Z "Babystepping Z" #endif @@ -916,6 +992,13 @@ #define MSG_EXTRUDE " Экструзия " #define MSG_RETRACT " Откат" #define MSG_MOVE_AXIS " Движение по осям \x7E" + #define MSG_MOVE_X "Move X" + #define MSG_MOVE_Y "Move Y" + #define MSG_MOVE_Z "Move Z" + #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_01MM "Move 0.1mm" + #define MSG_MOVE_1MM "Move 1mm" + #define MSG_MOVE_10MM "Move 10mm" #define MSG_SPEED " Скорость:" #define MSG_NOZZLE " \002 Фильера:" #define MSG_NOZZLE1 " \002 Фильера2:" @@ -986,6 +1069,11 @@ #define MSG_ZPROBE_OUT "ZProbe Outside Bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_BABYSTEP_X "Babystep X" + #define MSG_BABYSTEP_Y "Babystep Y" + #define MSG_BABYSTEP_Z "Babystep Z" + #define MSG_ENDSTOP_ABORT "Endstop abort" + #define MSG_CONTRAST "Contrast" // Serial Console Messages @@ -1056,6 +1144,9 @@ #define MSG_ENDSTOPS_HIT "концевик сработал: " #define MSG_ERR_COLD_EXTRUDE_STOP " защита холодной экструзии" #define MSG_ERR_LONG_EXTRUDE_STOP " защита превышения длинны экструзии" + #define MSG_BABYSTEPPING_X "Babystepping X" + #define MSG_BABYSTEPPING_Y "Babystepping Y" + #define MSG_BABYSTEPPING_Z "Babystepping Z" #endif @@ -1081,6 +1172,13 @@ #define MSG_EXTRUDE "Estrudi" #define MSG_RETRACT "Ritrai" #define MSG_MOVE_AXIS "Muovi Asse" + #define MSG_MOVE_X "Move X" + #define MSG_MOVE_Y "Move Y" + #define MSG_MOVE_Z "Move Z" + #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_01MM "Move 0.1mm" + #define MSG_MOVE_1MM "Move 1mm" + #define MSG_MOVE_10MM "Move 10mm" #define MSG_SPEED "Velcità" #define MSG_NOZZLE "Ugello" #define MSG_NOZZLE1 "Ugello2" @@ -1151,6 +1249,11 @@ #define MSG_ZPROBE_OUT "ZProbe Outside Bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_BABYSTEP_X "Babystep X" + #define MSG_BABYSTEP_Y "Babystep Y" + #define MSG_BABYSTEP_Z "Babystep Z" + #define MSG_ENDSTOP_ABORT "Endstop abort" + #define MSG_CONTRAST "Contrast" // Serial Console Messages @@ -1223,6 +1326,9 @@ #define MSG_ENDSTOPS_HIT "Raggiunto il fondo carrello: " #define MSG_ERR_COLD_EXTRUDE_STOP " prevenuta estrusione fredda" #define MSG_ERR_LONG_EXTRUDE_STOP " prevenuta estrusione troppo lunga" + #define MSG_BABYSTEPPING_X "Babystepping X" + #define MSG_BABYSTEPPING_Y "Babystepping Y" + #define MSG_BABYSTEPPING_Z "Babystepping Z" #endif @@ -1250,6 +1356,13 @@ #define MSG_PREHEAT_PLA " pre-aquecer PLA" #define MSG_PREHEAT_ABS " pre-aquecer ABS" #define MSG_MOVE_AXIS " Mover eixo \x7E" + #define MSG_MOVE_X "Move X" + #define MSG_MOVE_Y "Move Y" + #define MSG_MOVE_Z "Move Z" + #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_01MM "Move 0.1mm" + #define MSG_MOVE_1MM "Move 1mm" + #define MSG_MOVE_10MM "Move 10mm" #define MSG_SPEED " Velocidade:" #define MSG_NOZZLE " \002Nozzle:" #define MSG_NOZZLE1 " \002Nozzle2:" @@ -1325,6 +1438,11 @@ #define MSG_ZPROBE_OUT "Sonda fora da mesa" #define MSG_POSITION_UNKNOWN "Home X/Y antes de Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_BABYSTEP_X "Babystep X" + #define MSG_BABYSTEP_Y "Babystep Y" + #define MSG_BABYSTEP_Z "Babystep Z" + #define MSG_ENDSTOP_ABORT "Endstop abort" + #define MSG_CONTRAST "Contrast" // Serial Console Messages @@ -1397,7 +1515,9 @@ #define MSG_ENDSTOPS_HIT "O ponto final foi tocado: " #define MSG_ERR_COLD_EXTRUDE_STOP " Extrusao a frio evitada" #define MSG_ERR_LONG_EXTRUDE_STOP " Extrusao muito larga evitada" - + #define MSG_BABYSTEPPING_X "Babystepping X" + #define MSG_BABYSTEPPING_Y "Babystepping Y" + #define MSG_BABYSTEPPING_Z "Babystepping Z" #endif @@ -1426,6 +1546,13 @@ #define MSG_EXTRUDE "Pursota" #define MSG_RETRACT "Veda takaisin" #define MSG_MOVE_AXIS "Liikuta akseleita" + #define MSG_MOVE_X "Move X" + #define MSG_MOVE_Y "Move Y" + #define MSG_MOVE_Z "Move Z" + #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_01MM "Move 0.1mm" + #define MSG_MOVE_1MM "Move 1mm" + #define MSG_MOVE_10MM "Move 10mm" #define MSG_SPEED "Nopeus" #define MSG_NOZZLE "Suutin" #define MSG_NOZZLE1 "Suutin2" @@ -1495,6 +1622,11 @@ #define MSG_ZPROBE_OUT "ZProbe Outside Bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_BABYSTEP_X "Babystep X" + #define MSG_BABYSTEP_Y "Babystep Y" + #define MSG_BABYSTEP_Z "Babystep Z" + #define MSG_ENDSTOP_ABORT "Endstop abort" + #define MSG_CONTRAST "Contrast" // Serial Console Messages @@ -1567,6 +1699,12 @@ #define MSG_ENDSTOPS_HIT "paatyrajat aktivoitu: " #define MSG_ERR_COLD_EXTRUDE_STOP " kylmana pursotus estetty" #define MSG_ERR_LONG_EXTRUDE_STOP " liian pitka pursotus estetty" + #define MSG_BABYSTEPPING_X "Babystepping X" + #define MSG_BABYSTEPPING_Y "Babystepping Y" + #define MSG_BABYSTEPPING_Z "Babystepping Z" + #define MSG_ENDSTOP_ABORT "Endstop abort" + #define MSG_CONTRAST "Contrast" #endif + #endif // ifndef LANGUAGE_H diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 84a3ebf7fc..269becf8ef 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -344,7 +344,7 @@ static void lcd_babystep_x() } if (lcdDrawUpdate) { - lcd_implementation_drawedit(PSTR("Babystepping X"),""); + lcd_implementation_drawedit(PSTR(MSG_BABYSTEPPING_X),""); } if (LCD_CLICKED) { @@ -364,7 +364,7 @@ static void lcd_babystep_y() } if (lcdDrawUpdate) { - lcd_implementation_drawedit(PSTR("Babystepping Y"),""); + lcd_implementation_drawedit(PSTR(MSG_BABYSTEPPING_Y),""); } if (LCD_CLICKED) { @@ -384,7 +384,7 @@ static void lcd_babystep_z() } if (lcdDrawUpdate) { - lcd_implementation_drawedit(PSTR("Babystepping Z"),""); + lcd_implementation_drawedit(PSTR(MSG_BABYSTEPPING_Z),""); } if (LCD_CLICKED) { @@ -415,10 +415,10 @@ static void lcd_tune_menu() #ifdef BABYSTEPPING #ifdef BABYSTEP_XY - MENU_ITEM(submenu, "Babystep X", lcd_babystep_x); - MENU_ITEM(submenu, "Babystep Y", lcd_babystep_y); + MENU_ITEM(submenu, MSG_BABYSTEP_X, lcd_babystep_x); + MENU_ITEM(submenu, MSG_BABYSTEP_Y, lcd_babystep_y); #endif //BABYSTEP_XY - MENU_ITEM(submenu, "Babystep Z", lcd_babystep_z); + MENU_ITEM(submenu, MSG_BABYSTEP_Z, lcd_babystep_z); #endif #ifdef FILAMENTCHANGEENABLE MENU_ITEM(gcode, MSG_FILAMENTCHANGE, PSTR("M600")); @@ -573,12 +573,12 @@ static void lcd_move_menu_axis() { START_MENU(); MENU_ITEM(back, MSG_MOVE_AXIS, lcd_move_menu); - MENU_ITEM(submenu, "Move X", lcd_move_x); - MENU_ITEM(submenu, "Move Y", lcd_move_y); + MENU_ITEM(submenu, MSG_MOVE_X, lcd_move_x); + MENU_ITEM(submenu, MSG_MOVE_Y, lcd_move_y); if (move_menu_scale < 10.0) { - MENU_ITEM(submenu, "Move Z", lcd_move_z); - MENU_ITEM(submenu, "Extruder", lcd_move_e); + MENU_ITEM(submenu, MSG_MOVE_Z, lcd_move_z); + MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_e); } END_MENU(); } @@ -603,9 +603,9 @@ static void lcd_move_menu() { START_MENU(); MENU_ITEM(back, MSG_PREPARE, lcd_prepare_menu); - MENU_ITEM(submenu, "Move 10mm", lcd_move_menu_10mm); - MENU_ITEM(submenu, "Move 1mm", lcd_move_menu_1mm); - MENU_ITEM(submenu, "Move 0.1mm", lcd_move_menu_01mm); + 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(); } @@ -727,7 +727,7 @@ static void lcd_control_motion_menu() MENU_ITEM_EDIT(float51, MSG_ZSTEPS, &axis_steps_per_unit[Z_AXIS], 5, 9999); MENU_ITEM_EDIT(float51, MSG_ESTEPS, &axis_steps_per_unit[E_AXIS], 5, 9999); #ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED - MENU_ITEM_EDIT(bool, "Endstop abort", &abort_on_endstop_hit); + MENU_ITEM_EDIT(bool, MSG_ENDSTOP_ABORT, &abort_on_endstop_hit); #endif END_MENU(); } @@ -746,7 +746,7 @@ static void lcd_set_contrast() } if (lcdDrawUpdate) { - lcd_implementation_drawedit(PSTR("Contrast"), itostr2(lcd_contrast)); + lcd_implementation_drawedit(PSTR(MSG_CONTRAST), itostr2(lcd_contrast)); } if (LCD_CLICKED) { From 0778f5f028b3dc811b431702a5aba1aab11796e5 Mon Sep 17 00:00:00 2001 From: Mark Hanford Date: Tue, 11 Feb 2014 14:40:53 +0000 Subject: [PATCH 140/256] Add missing entries to the new Aragonian language. --- Marlin/language.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Marlin/language.h b/Marlin/language.h index 3136f62901..c5a3d50082 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -1729,6 +1729,13 @@ #define MSG_EXTRUDE "Extruir" #define MSG_RETRACT "Retraer" #define MSG_MOVE_AXIS "Mover Eixes" + #define MSG_MOVE_X "Move X" + #define MSG_MOVE_Y "Move Y" + #define MSG_MOVE_Z "Move Z" + #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_01MM "Move 0.1mm" + #define MSG_MOVE_1MM "Move 1mm" + #define MSG_MOVE_10MM "Move 10mm" #define MSG_SPEED "Velocidat" #define MSG_NOZZLE "Nozzle" #define MSG_NOZZLE1 "Nozzle2" @@ -1807,6 +1814,11 @@ #define MSG_ZPROBE_OUT "ZProbe Outside Bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_BABYSTEP_X "Babystep X" + #define MSG_BABYSTEP_Y "Babystep Y" + #define MSG_BABYSTEP_Z "Babystep Z" + #define MSG_ENDSTOP_ABORT "Endstop abort" + #define MSG_CONTRAST "Contrast" // Serial Console Messages @@ -1878,6 +1890,9 @@ #define MSG_ENDSTOPS_HIT "S'ha tocau a fin de carril: " #define MSG_ERR_COLD_EXTRUDE_STOP " extrusion fria privada" #define MSG_ERR_LONG_EXTRUDE_STOP " extrusion masiau larga privada" + #define MSG_BABYSTEPPING_X "Babystepping X" + #define MSG_BABYSTEPPING_Y "Babystepping Y" + #define MSG_BABYSTEPPING_Z "Babystepping Z" #endif From 5f797ca29f10f3d345d8d7415e39884dbecc514b Mon Sep 17 00:00:00 2001 From: nothinman Date: Tue, 11 Feb 2014 22:38:01 +0000 Subject: [PATCH 141/256] Updated Polish, changed default firmware URL to Marlin. --- Marlin/language.h | 62 +++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index c5a3d50082..26fd1a26e5 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -40,16 +40,20 @@ #define MACHINE_NAME "Mendel" #endif - #define FIRMWARE_URL "http://www.mendel-parts.com" +// Default firmware set to Mendel + #define FIRMWARE_URL "https://github.com/ErikZalm/Marlin/" #endif + #ifndef MACHINE_UUID #define MACHINE_UUID "00000000-0000-0000-0000-000000000000" #endif + #define STRINGIFY_(n) #n #define STRINGIFY(n) STRINGIFY_(n) + #if LANGUAGE_CHOICE == 1 // LCD Menu Messages @@ -234,7 +238,7 @@ #if LANGUAGE_CHOICE == 2 // LCD Menu Messages - #define WELCOME_MSG MACHINE_NAME " Gotowe." + #define WELCOME_MSG MACHINE_NAME " gotowy." #define MSG_SD_INSERTED "Karta wlozona" #define MSG_SD_REMOVED "Karta usunieta" #define MSG_MAIN "Menu glowne" @@ -247,22 +251,22 @@ #define MSG_PREHEAT_ABS "Rozgrzej ABS" #define MSG_PREHEAT_ABS_SETTINGS "Ustawienia roz. ABS" #define MSG_COOLDOWN "Chlodzenie" - #define MSG_SWITCH_PS_ON "Wl. zasilacz" - #define MSG_SWITCH_PS_OFF "Wyl. zasilacz" + #define MSG_SWITCH_PS_ON "Wlacz zasilacz" + #define MSG_SWITCH_PS_OFF "Wylacz zasilacz" #define MSG_EXTRUDE "Ekstruzja" #define MSG_RETRACT "Cofanie" #define MSG_MOVE_AXIS "Ruch osi" - #define MSG_MOVE_X "Move X" - #define MSG_MOVE_Y "Move Y" - #define MSG_MOVE_Z "Move Z" - #define MSG_MOVE_E "Extruder" - #define MSG_MOVE_01MM "Move 0.1mm" - #define MSG_MOVE_1MM "Move 1mm" - #define MSG_MOVE_10MM "Move 10mm" + #define MSG_MOVE_X "Przesun w X" + #define MSG_MOVE_Y "Przesun w Y" + #define MSG_MOVE_Z "Przesun w Z" + #define MSG_MOVE_E "Ekstruzja (os E)" + #define MSG_MOVE_01MM "Przesuwaj co 0.1mm" + #define MSG_MOVE_1MM "Przesuwaj co 1mm" + #define MSG_MOVE_10MM "Przesuwaj co 10mm" #define MSG_SPEED "Predkosc" #define MSG_NOZZLE "Dysza" - #define MSG_NOZZLE1 "Dysza2" - #define MSG_NOZZLE2 "Dysza3" + #define MSG_NOZZLE1 "Dysza 2" + #define MSG_NOZZLE2 "Dysza 3" #define MSG_BED "Loze" #define MSG_FAN_SPEED "Obroty wiatraka" #define MSG_FLOW "Przeplyw" @@ -270,14 +274,14 @@ #define MSG_MIN " \002 Min" #define MSG_MAX " \002 Max" #define MSG_FACTOR " \002 Mnoznik" - #define MSG_AUTOTEMP "Auto. temp." + #define MSG_AUTOTEMP "Auto. temperatura" #define MSG_ON "Wl. " #define MSG_OFF "Wyl." #define MSG_PID_P "PID-P" #define MSG_PID_I "PID-I" #define MSG_PID_D "PID-D" #define MSG_PID_C "PID-C" - #define MSG_ACC "Acc" + #define MSG_ACC "Przyspieszenie" #define MSG_VXY_JERK "Zryw Vxy" #define MSG_VZ_JERK "Zryw Vz" #define MSG_VE_JERK "Zryw Ve" @@ -312,7 +316,7 @@ #define MSG_CARD_MENU "Menu karty SD" #define MSG_NO_CARD "Brak karty" #define MSG_DWELL "Uspij..." - #define MSG_USERWAIT "Czekaj na uzytkownika..." + #define MSG_USERWAIT "Czekam na uzytkownika..." #define MSG_RESUMING "Wznawiam drukowanie" #define MSG_NO_MOVE "Brak ruchu." #define MSG_PART_RELEASE "Czesciowe zwolnienie" @@ -326,16 +330,16 @@ #define MSG_CONTROL_RETRACT_RECOVERF "Cof. wycof. F" #define MSG_AUTORETRACT "Auto. wycofanie" #define MSG_FILAMENTCHANGE "Zmien filament" - #define MSG_INIT_SDCARD "Uruchom karte SD" - #define MSG_CNG_SDCARD "Zmien karte SD" + #define MSG_INIT_SDCARD "Inicjalizacja karty" + #define MSG_CNG_SDCARD "Zmiana karty SD" #define MSG_ZPROBE_OUT "Probkuj Z poza lozem" - #define MSG_POSITION_UNKNOWN "Domuj X/Y przed Z" - #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_POSITION_UNKNOWN "Powrot w X/Y przed Z" + #define MSG_ZPROBE_ZOFFSET "Offset Z" #define MSG_BABYSTEP_X "Babystep X" #define MSG_BABYSTEP_Y "Babystep Y" #define MSG_BABYSTEP_Z "Babystep Z" - #define MSG_ENDSTOP_ABORT "Endstop abort" - #define MSG_CONTRAST "Contrast" + #define MSG_ENDSTOP_ABORT "Blad wyl. krancowego" + #define MSG_CONTRAST "Kontrast" // Serial Console Messages @@ -350,7 +354,7 @@ #define MSG_CONFIGURATION_VER " Ostatnia aktualizacja: " #define MSG_FREE_MEMORY " Wolna pamiec: " #define MSG_PLANNER_BUFFER_BYTES " Bufor planisty krokow (w bajtach): " - #define MSG_OK "ok" + #define MSG_OK "OK" #define MSG_FILE_SAVED "Plik zapisany." #define MSG_ERR_LINE_NO "Numer linijki nie jest ostatnim numerem linijki+1; ostatnia linijka:" #define MSG_ERR_CHECKSUM_MISMATCH "Niezgodna suma kontrolna; ostatnia linijka: " @@ -370,7 +374,7 @@ #define MSG_BED_HEATING "Nagrzewanie loza..." #define MSG_BED_DONE "Nagrzewanie loza zakonczone." #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" - #define MSG_COUNT_X " Liczenie X: " + #define MSG_COUNT_X " Licznik X: " #define MSG_ERR_KILLED "Drukarka zatrzymana. Wywolano kill()" #define MSG_ERR_STOPPED "Drukarka zatrzymana z powodu bledu. Usun problem i zrestartuj drukartke komenda M999. (temperatura zostala zresetowana; ustaw temperature po restarcie)" #define MSG_RESEND "Wyslij ponownie: " @@ -386,7 +390,7 @@ #define MSG_M119_REPORT "Zgloszenie statusu wylacznikow krancowych" #define MSG_ENDSTOP_HIT "Wyzwolony" #define MSG_ENDSTOP_OPEN "Otwarty" - #define MSG_HOTEND_OFFSET "Hotend offsets:" + #define MSG_HOTEND_OFFSET "Offsety dysz:" #define MSG_SD_CANT_OPEN_SUBDIR "Nie mozna otworzyc podkatalogu" #define MSG_SD_INIT_FAIL "Blad inicjalizacji karty SD" @@ -401,16 +405,16 @@ #define MSG_SD_WRITE_TO_FILE "Zapisywanie do pliku: " #define MSG_SD_PRINTING_BYTE "Drukowanie z karty SD, bajt " #define MSG_SD_NOT_PRINTING "Nie trwa drukowanie z karty SD" - #define MSG_SD_ERR_WRITE_TO_FILE "blad podczas zapisu do pliku" + #define MSG_SD_ERR_WRITE_TO_FILE "Wystapil blad podczas zapisu do pliku" #define MSG_SD_CANT_ENTER_SUBDIR "Nie mozna odczytac podkatalogu: " #define MSG_STEPPER_TOO_HIGH "Za duza czestotliwosc krokow: " #define MSG_ENDSTOPS_HIT "Wylacznik krancowy zostal wyzwolony na pozycji: " #define MSG_ERR_COLD_EXTRUDE_STOP " uniemozliwiono zimna ekstruzje" #define MSG_ERR_LONG_EXTRUDE_STOP " uniemozliwiono zbyt dluga ekstruzje" - #define MSG_BABYSTEPPING_X "Babystepping X" - #define MSG_BABYSTEPPING_Y "Babystepping Y" - #define MSG_BABYSTEPPING_Z "Babystepping Z" + #define MSG_BABYSTEPPING_X "Babystepping w osi X" + #define MSG_BABYSTEPPING_Y "Babystepping w osi Y" + #define MSG_BABYSTEPPING_Z "Babystepping w osi Z" #endif From 3f6d44d40b00fe0636c31a24feb00441ea748dd3 Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Tue, 11 Feb 2014 18:50:11 -0800 Subject: [PATCH 142/256] Keep FWRETRACT values in terms of millimeters when using M200 for volumetric E units --- Marlin/Marlin_main.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index b5e4e85193..1b213f9516 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -137,7 +137,7 @@ // M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) im mm/sec^2 also sets minimum segment time in ms (B20000) to prevent buffer underruns and M20 minimum feedrate // M205 - advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk, E=maximum E jerk // M206 - set additional homeing offset -// M207 - set retract length S[positive mm] F[feedrate mm/sec] Z[additional zlift/hop] +// M207 - set retract length S[positive mm] F[feedrate mm/sec] Z[additional zlift/hop], stays in mm regardless of M200 setting // M208 - set recover=unretract length S[positive mm surplus to the M207 S*] F[feedrate mm/sec] // M209 - S<1=true/0=false> enable automatic retract detect if the slicer did not support G10/11: every normal extrude-only move will be classified as retract depending on the direction. // M218 - set hotend offset (in mm): T X Y @@ -1109,11 +1109,13 @@ void process_commands() destination[X_AXIS]=current_position[X_AXIS]; destination[Y_AXIS]=current_position[Y_AXIS]; destination[Z_AXIS]=current_position[Z_AXIS]; - current_position[Z_AXIS]+=-retract_zlift; - destination[E_AXIS]=current_position[E_AXIS]-retract_length; + current_position[Z_AXIS]-=retract_zlift; + destination[E_AXIS]=current_position[E_AXIS]-retract_length/volumetric_multiplier[active_extruder]; + float oldFeedrate = feedrate; feedrate=retract_feedrate; retracted=true; prepare_move(); + feedrate = oldFeedrate; } break; @@ -1124,10 +1126,12 @@ void process_commands() destination[Y_AXIS]=current_position[Y_AXIS]; destination[Z_AXIS]=current_position[Z_AXIS]; current_position[Z_AXIS]+=retract_zlift; - destination[E_AXIS]=current_position[E_AXIS]+retract_length+retract_recover_length; + destination[E_AXIS]=current_position[E_AXIS]+(retract_length+retract_recover_length)/volumetric_multiplier[active_extruder]; + float oldFeedrate = feedrate; feedrate=retract_recover_feedrate; retracted=false; prepare_move(); + feedrate = oldFeedrate; } break; #endif //FWRETRACT From 78e7654601f93638f32fed52b6b2d9bdb20845d7 Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Tue, 11 Feb 2014 19:05:35 -0800 Subject: [PATCH 143/256] Keep FWRETRACT values in terms of millimeters when using M200 for volumetric E units --- Marlin/Marlin_main.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index b567e2b093..985fde7dfd 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -137,7 +137,7 @@ // M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) im mm/sec^2 also sets minimum segment time in ms (B20000) to prevent buffer underruns and M20 minimum feedrate // M205 - advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk, E=maximum E jerk // M206 - set additional homeing offset -// M207 - set retract length S[positive mm] F[feedrate mm/sec] Z[additional zlift/hop] +// M207 - set retract length S[positive mm] F[feedrate mm/sec] Z[additional zlift/hop], stays in mm regardless of M200 setting // M208 - set recover=unretract length S[positive mm surplus to the M207 S*] F[feedrate mm/sec] // M209 - S<1=true/0=false> enable automatic retract detect if the slicer did not support G10/11: every normal extrude-only move will be classified as retract depending on the direction. // M218 - set hotend offset (in mm): T X Y @@ -1128,10 +1128,12 @@ void process_commands() destination[Y_AXIS]=current_position[Y_AXIS]; destination[Z_AXIS]=current_position[Z_AXIS]; current_position[Z_AXIS]+=retract_zlift; - destination[E_AXIS]=current_position[E_AXIS]+retract_length+retract_recover_length; + destination[E_AXIS]=current_position[E_AXIS]+(retract_length+retract_recover_length)/volumetric_multiplier[active_extruder]; + float oldFeedrate = feedrate; feedrate=retract_recover_feedrate; retracted=false; prepare_move(); + feedrate = oldFeedrate; } break; #endif //FWRETRACT From 0b9ecf38242bb4847d15e3c341114d6f25101a27 Mon Sep 17 00:00:00 2001 From: Martin Lukasik Date: Wed, 12 Feb 2014 13:21:26 +0000 Subject: [PATCH 144/256] Language cleanup, part 1. --- Marlin/language.h | 391 ++++++++++++++++++++++++---------------------- 1 file changed, 205 insertions(+), 186 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index 26fd1a26e5..ab3bf63558 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -19,7 +19,7 @@ // 10 Aragonese #ifndef LANGUAGE_CHOICE -#define LANGUAGE_CHOICE 1 // Pick your language from the list above + #define LANGUAGE_CHOICE 1 // Pick your language from the list above #endif #define PROTOCOL_VERSION "1.0" @@ -54,27 +54,37 @@ #define STRINGIFY(n) STRINGIFY_(n) +// Common LCD messages +/* nothing here as of yet */ + +// Common serial messages +#define MSG_MARLIN "Marlin" + + + #if LANGUAGE_CHOICE == 1 // LCD Menu Messages - #define WELCOME_MSG MACHINE_NAME " Ready." +// Please note these are limited to 17 characters! + + #define WELCOME_MSG MACHINE_NAME " ready." #define MSG_SD_INSERTED "Card inserted" #define MSG_SD_REMOVED "Card removed" #define MSG_MAIN "Main" #define MSG_AUTOSTART "Autostart" - #define MSG_DISABLE_STEPPERS "Disable Steppers" - #define MSG_AUTO_HOME "Auto Home" - #define MSG_SET_ORIGIN "Set Origin" + #define MSG_DISABLE_STEPPERS "Disable steppers" + #define MSG_AUTO_HOME "Auto home" + #define MSG_SET_ORIGIN "Set origin" #define MSG_PREHEAT_PLA "Preheat PLA" - #define MSG_PREHEAT_PLA_SETTINGS "Preheat PLA Conf" + #define MSG_PREHEAT_PLA_SETTINGS "Preheat PLA conf" #define MSG_PREHEAT_ABS "Preheat ABS" - #define MSG_PREHEAT_ABS_SETTINGS "Preheat ABS Conf" + #define MSG_PREHEAT_ABS_SETTINGS "Preheat ABS conf" #define MSG_COOLDOWN "Cooldown" - #define MSG_SWITCH_PS_ON "Switch Power On" - #define MSG_SWITCH_PS_OFF "Switch Power Off" + #define MSG_SWITCH_PS_ON "Switch power on" + #define MSG_SWITCH_PS_OFF "Switch power off" #define MSG_EXTRUDE "Extrude" #define MSG_RETRACT "Retract" - #define MSG_MOVE_AXIS "Move Axis" + #define MSG_MOVE_AXIS "Move axis" #define MSG_MOVE_X "Move X" #define MSG_MOVE_Y "Move Y" #define MSG_MOVE_Z "Move Z" @@ -123,16 +133,16 @@ #define MSG_CONTRAST "LCD contrast" #define MSG_STORE_EPROM "Store memory" #define MSG_LOAD_EPROM "Load memory" - #define MSG_RESTORE_FAILSAFE "Restore Failsafe" + #define MSG_RESTORE_FAILSAFE "Restore failsafe" #define MSG_REFRESH "Refresh" #define MSG_WATCH "Info screen" #define MSG_PREPARE "Prepare" #define MSG_TUNE "Tune" - #define MSG_PAUSE_PRINT "Pause Print" - #define MSG_RESUME_PRINT "Resume Print" - #define MSG_STOP_PRINT "Stop Print" + #define MSG_PAUSE_PRINT "Pause print" + #define MSG_RESUME_PRINT "Resume print" + #define MSG_STOP_PRINT "Stop print" #define MSG_CARD_MENU "Print from SD" - #define MSG_NO_CARD "No Card" + #define MSG_NO_CARD "No SD card" #define MSG_DWELL "Sleep..." #define MSG_USERWAIT "Wait for user..." #define MSG_RESUMING "Resuming print" @@ -146,9 +156,9 @@ #define MSG_CONTROL_RETRACT_RECOVERF "UnRet F" #define MSG_AUTORETRACT "AutoRetr." #define MSG_FILAMENTCHANGE "Change filament" - #define MSG_INIT_SDCARD "Init. SD-Card" - #define MSG_CNG_SDCARD "Change SD-Card" - #define MSG_ZPROBE_OUT "ZProbe Outside Bed" + #define MSG_INIT_SDCARD "Init. SD card" + #define MSG_CNG_SDCARD "Change SD card" + #define MSG_ZPROBE_OUT "Z probe out. bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" #define MSG_BABYSTEP_X "Babystep X" @@ -165,7 +175,6 @@ #define MSG_BROWNOUT_RESET " Brown out Reset" #define MSG_WATCHDOG_RESET " Watchdog Reset" #define MSG_SOFTWARE_RESET " Software Reset" - #define MSG_MARLIN "Marlin " #define MSG_AUTHOR " | Author: " #define MSG_CONFIGURATION_VER " Last Updated: " #define MSG_FREE_MEMORY " Free Memory: " @@ -231,13 +240,17 @@ #define MSG_BABYSTEPPING_X "Babystepping X" #define MSG_BABYSTEPPING_Y "Babystepping Y" #define MSG_BABYSTEPPING_Z "Babystepping Z" + #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Error in menu structure" #endif #if LANGUAGE_CHOICE == 2 + // LCD Menu Messages +// Please note these are limited to 17 characters! + #define WELCOME_MSG MACHINE_NAME " gotowy." #define MSG_SD_INSERTED "Karta wlozona" #define MSG_SD_REMOVED "Karta usunieta" @@ -245,11 +258,11 @@ #define MSG_AUTOSTART "Autostart" #define MSG_DISABLE_STEPPERS "Wylacz silniki" #define MSG_AUTO_HOME "Auto. poz. zerowa" - #define MSG_SET_ORIGIN "Ustaw punkt zerowy" + #define MSG_SET_ORIGIN "Ustaw punkt zero" #define MSG_PREHEAT_PLA "Rozgrzej PLA" - #define MSG_PREHEAT_PLA_SETTINGS "Ustawienia roz. PLA" + #define MSG_PREHEAT_PLA_SETTINGS "Ustaw. rozg. PLA" #define MSG_PREHEAT_ABS "Rozgrzej ABS" - #define MSG_PREHEAT_ABS_SETTINGS "Ustawienia roz. ABS" + #define MSG_PREHEAT_ABS_SETTINGS "Ustaw. rozg. ABS" #define MSG_COOLDOWN "Chlodzenie" #define MSG_SWITCH_PS_ON "Wlacz zasilacz" #define MSG_SWITCH_PS_OFF "Wylacz zasilacz" @@ -260,7 +273,7 @@ #define MSG_MOVE_Y "Przesun w Y" #define MSG_MOVE_Z "Przesun w Z" #define MSG_MOVE_E "Ekstruzja (os E)" - #define MSG_MOVE_01MM "Przesuwaj co 0.1mm" + #define MSG_MOVE_01MM "Przesuwaj co .1mm" #define MSG_MOVE_1MM "Przesuwaj co 1mm" #define MSG_MOVE_10MM "Przesuwaj co 10mm" #define MSG_SPEED "Predkosc" @@ -304,7 +317,7 @@ #define MSG_CONTRAST "Kontrast LCD" #define MSG_STORE_EPROM "Zapisz w pamieci" #define MSG_LOAD_EPROM "Wczytaj z pamieci" - #define MSG_RESTORE_FAILSAFE "Ustawienia fabryczne" + #define MSG_RESTORE_FAILSAFE "Ustaw. fabryczne" #define MSG_REFRESH "\004Odswiez" #define MSG_WATCH "Ekran glowny" #define MSG_PREPARE "Przygotuj" @@ -316,10 +329,9 @@ #define MSG_CARD_MENU "Menu karty SD" #define MSG_NO_CARD "Brak karty" #define MSG_DWELL "Uspij..." - #define MSG_USERWAIT "Czekam na uzytkownika..." - #define MSG_RESUMING "Wznawiam drukowanie" - #define MSG_NO_MOVE "Brak ruchu." - #define MSG_PART_RELEASE "Czesciowe zwolnienie" + #define MSG_USERWAIT "Oczekiwanie..." + #define MSG_RESUMING "Wznawianie druku" + #define MSG_NO_MOVE "Brak ruchu" #define MSG_KILLED "Ubity. " #define MSG_STOPPED "Zatrzymany. " #define MSG_STEPPER_RELEASED "Zwolniony." @@ -330,15 +342,15 @@ #define MSG_CONTROL_RETRACT_RECOVERF "Cof. wycof. F" #define MSG_AUTORETRACT "Auto. wycofanie" #define MSG_FILAMENTCHANGE "Zmien filament" - #define MSG_INIT_SDCARD "Inicjalizacja karty" + #define MSG_INIT_SDCARD "Inicjal. karty SD" #define MSG_CNG_SDCARD "Zmiana karty SD" - #define MSG_ZPROBE_OUT "Probkuj Z poza lozem" - #define MSG_POSITION_UNKNOWN "Powrot w X/Y przed Z" + #define MSG_ZPROBE_OUT "Sonda Z za lozem" + #define MSG_POSITION_UNKNOWN "Wroc w XY przed Z" #define MSG_ZPROBE_ZOFFSET "Offset Z" #define MSG_BABYSTEP_X "Babystep X" #define MSG_BABYSTEP_Y "Babystep Y" #define MSG_BABYSTEP_Z "Babystep Z" - #define MSG_ENDSTOP_ABORT "Blad wyl. krancowego" + #define MSG_ENDSTOP_ABORT "Blad wyl. kranc." #define MSG_CONTRAST "Kontrast" // Serial Console Messages @@ -349,7 +361,6 @@ #define MSG_BROWNOUT_RESET " Reset (spadek napiecia)" #define MSG_WATCHDOG_RESET " Reset (watchdog)" #define MSG_SOFTWARE_RESET " Reset (programowy)" - #define MSG_MARLIN "Marlin" #define MSG_AUTHOR " | Autor: " #define MSG_CONFIGURATION_VER " Ostatnia aktualizacja: " #define MSG_FREE_MEMORY " Wolna pamiec: " @@ -415,12 +426,16 @@ #define MSG_BABYSTEPPING_X "Babystepping w osi X" #define MSG_BABYSTEPPING_Y "Babystepping w osi Y" #define MSG_BABYSTEPPING_Z "Babystepping w osi Z" + #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Error in menu structure" #endif #if LANGUAGE_CHOICE == 3 +// LCD Menu Messages +// Please note these are limited to 17 characters! + #define WELCOME_MSG MACHINE_NAME " prete." #define MSG_SD_INSERTED "Carte inseree" #define MSG_SD_REMOVED "Carte retiree" @@ -430,9 +445,9 @@ #define MSG_AUTO_HOME "Home auto." #define MSG_SET_ORIGIN "Regler origine" #define MSG_PREHEAT_PLA " Prechauffage PLA" - #define MSG_PREHEAT_PLA_SETTINGS " Regl. prechauffe PLA" + #define MSG_PREHEAT_PLA_SETTINGS " Regl. prech. PLA" #define MSG_PREHEAT_ABS "Prechauffage ABS" - #define MSG_PREHEAT_ABS_SETTINGS "Regl. prechauffe ABS" + #define MSG_PREHEAT_ABS_SETTINGS "Regl. prech. ABS" #define MSG_COOLDOWN "Refroidir" #define MSG_SWITCH_PS_ON "Allumer alim." #define MSG_SWITCH_PS_OFF "Eteindre alim." @@ -453,7 +468,7 @@ #define MSG_NOZZLE1 "Buse2" #define MSG_NOZZLE2 "Buse3" #define MSG_BED "Plateau" - #define MSG_FAN_SPEED "Vitesse ventilateur" + #define MSG_FAN_SPEED "Vite. ventilateur" #define MSG_FLOW "Flux" #define MSG_CONTROL "Controler" #define MSG_MIN " \002 Min" @@ -499,10 +514,9 @@ #define MSG_CARD_MENU "Impr. depuis SD" #define MSG_NO_CARD "Pas de carte" #define MSG_DWELL "Repos..." - #define MSG_USERWAIT "Attente de l'utilisateur..." - #define MSG_RESUMING "Reprise de l'impression" + #define MSG_USERWAIT "Atten. de l'util." + #define MSG_RESUMING "Repri. de l'impr." #define MSG_NO_MOVE "Aucun mouvement." - #define MSG_PART_RELEASE "Relache partielle" #define MSG_KILLED "MORT." #define MSG_STOPPED "STOPPE." #define MSG_STEPPER_RELEASED "RELACHE." @@ -514,14 +528,14 @@ #define MSG_AUTORETRACT "Retract. Auto." #define MSG_FILAMENTCHANGE "Changer filament" #define MSG_INIT_SDCARD "Init. la carte SD" - #define MSG_CNG_SDCARD "Changer de carte SD" - #define MSG_ZPROBE_OUT "ZProbe Outside Bed" - #define MSG_POSITION_UNKNOWN "Home X/Y before Z" - #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_CNG_SDCARD "Changer de carte" + #define MSG_ZPROBE_OUT "Z sonde exte. lit" + #define MSG_POSITION_UNKNOWN "Rev. dans XY av.Z" + #define MSG_ZPROBE_ZOFFSET "Offset Z" #define MSG_BABYSTEP_X "Babystep X" #define MSG_BABYSTEP_Y "Babystep Y" #define MSG_BABYSTEP_Z "Babystep Z" - #define MSG_ENDSTOP_ABORT "Endstop abort" + #define MSG_ENDSTOP_ABORT "Butee abandon" #define MSG_CONTRAST "Contrast" // Serial Console Messages @@ -532,7 +546,6 @@ #define MSG_BROWNOUT_RESET " RAZ defaut alim." #define MSG_WATCHDOG_RESET " RAZ Watchdog" #define MSG_SOFTWARE_RESET " RAZ logicielle" - #define MSG_MARLIN "Marlin " #define MSG_AUTHOR " | Auteur: " #define MSG_CONFIGURATION_VER " Derniere MaJ: " #define MSG_FREE_MEMORY " Memoire libre: " @@ -598,6 +611,7 @@ #define MSG_BABYSTEPPING_X "Babystepping X" #define MSG_BABYSTEPPING_Y "Babystepping Y" #define MSG_BABYSTEPPING_Z "Babystepping Z" + #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Error in menu structure" #endif @@ -605,6 +619,7 @@ #if LANGUAGE_CHOICE == 4 // LCD Menu Messages +// Please note these are limited to 17 characters! #define WELCOME_MSG MACHINE_NAME " Bereit." @@ -612,13 +627,13 @@ #define MSG_SD_REMOVED "SDKarte entfernt" #define MSG_MAIN "Hauptmenü" #define MSG_AUTOSTART "Autostart" - #define MSG_DISABLE_STEPPERS "Stepper abschalten" + #define MSG_DISABLE_STEPPERS "Stepper abschalt." #define MSG_AUTO_HOME "Auto Nullpunkt" #define MSG_SET_ORIGIN "Setze Nullpunkt" #define MSG_PREHEAT_PLA "Vorwärmen PLA" - #define MSG_PREHEAT_PLA_SETTINGS "Vorwärmen PLA Einstellungen" + #define MSG_PREHEAT_PLA_SETTINGS "Vorwärm. PLA Ein." #define MSG_PREHEAT_ABS "Vorwärmen ABS" - #define MSG_PREHEAT_ABS_SETTINGS "Vorwärmen ABS Einstellungen" + #define MSG_PREHEAT_ABS_SETTINGS "Vorwärm. ABS Ein." #define MSG_COOLDOWN "Abkühlen" #define MSG_SWITCH_PS_ON "Switch Power On" #define MSG_SWITCH_PS_OFF "Switch Power Off" @@ -685,10 +700,9 @@ #define MSG_CARD_MENU "SDKarten Menü" #define MSG_NO_CARD "Keine SDKarte" #define MSG_DWELL "Warten..." - #define MSG_USERWAIT "Warte auf Nutzer..." + #define MSG_USERWAIT "Warte auf Nutzer" #define MSG_RESUMING "Druck fortsetzung" #define MSG_NO_MOVE "Kein Zug." - #define MSG_PART_RELEASE "Stepper tlw frei" #define MSG_KILLED "KILLED" #define MSG_STOPPED "GESTOPPT" #define MSG_STEPPER_RELEASED "Stepper frei" @@ -701,7 +715,7 @@ #define MSG_FILAMENTCHANGE "Filament wechseln" #define MSG_INIT_SDCARD "Init. SD-Card" #define MSG_CNG_SDCARD "Change SD-Card" - #define MSG_ZPROBE_OUT "ZProbe Outside Bed" + #define MSG_ZPROBE_OUT "Z probe out. bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" #define MSG_BABYSTEP_X "Babystep X" @@ -718,7 +732,6 @@ #define MSG_BROWNOUT_RESET " Brown out Reset" #define MSG_WATCHDOG_RESET " Watchdog Reset" #define MSG_SOFTWARE_RESET " Software Reset" - #define MSG_MARLIN "Marlin: " #define MSG_AUTHOR " | Author: " #define MSG_CONFIGURATION_VER " Last Updated: " #define MSG_FREE_MEMORY " Free Memory: " @@ -784,6 +797,7 @@ #define MSG_BABYSTEPPING_X "Babystepping X" #define MSG_BABYSTEPPING_Y "Babystepping Y" #define MSG_BABYSTEPPING_Z "Babystepping Z" + #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Error in menu structure" #endif @@ -791,14 +805,16 @@ #if LANGUAGE_CHOICE == 5 // LCD Menu Messages - #define WELCOME_MSG MACHINE_NAME "Lista." - #define MSG_SD_INSERTED "Tarjeta SD Colocada" - #define MSG_SD_REMOVED "Tarjeta SD Retirada" - #define MSG_MAIN "Menu Principal" +// Please note these are limited to 17 characters! + + #define WELCOME_MSG MACHINE_NAME " lista." + #define MSG_SD_INSERTED "Tarjeta colocada" + #define MSG_SD_REMOVED "Tarjeta retirada" + #define MSG_MAIN "Menu principal" #define MSG_AUTOSTART " Autostart" - #define MSG_DISABLE_STEPPERS "Apagar Motores" - #define MSG_AUTO_HOME "Llevar al Origen" // "Llevar Ejes al Cero" - #define MSG_SET_ORIGIN "Establecer Cero" + #define MSG_DISABLE_STEPPERS "Apagar motores" + #define MSG_AUTO_HOME "Llevar al origen" + #define MSG_SET_ORIGIN "Establecer cero" #define MSG_PREHEAT_PLA "Precalentar PLA" #define MSG_PREHEAT_PLA_SETTINGS "Ajustar temp. PLA" #define MSG_PREHEAT_ABS "Precalentar ABS" @@ -808,7 +824,7 @@ #define MSG_SWITCH_PS_OFF "Switch Power Off" #define MSG_EXTRUDE "Extruir" #define MSG_RETRACT "Retraer" - #define MSG_MOVE_AXIS "Mover Ejes" + #define MSG_MOVE_AXIS "Mover ejes" #define MSG_MOVE_X "Move X" #define MSG_MOVE_Y "Move Y" #define MSG_MOVE_Z "Move Z" @@ -854,24 +870,24 @@ #define MSG_RECTRACT "Retraer" #define MSG_TEMPERATURE "Temperatura" #define MSG_MOTION "Movimiento" - #define MSG_STORE_EPROM "Guardar Memoria" - #define MSG_LOAD_EPROM "Cargar Memoria" - #define MSG_RESTORE_FAILSAFE "Rest. de emergencia" + #define MSG_STORE_EPROM "Guardar memoria" + #define MSG_LOAD_EPROM "Cargar memoria" + #define MSG_RESTORE_FAILSAFE "Rest. de emergen." #define MSG_REFRESH "Volver a cargar" #define MSG_WATCH "Monitorizar" #define MSG_PREPARE "Preparar" #define MSG_TUNE "Ajustar" - #define MSG_PAUSE_PRINT "Pausar Impresion" - #define MSG_RESUME_PRINT "Reanudar Impresion" - #define MSG_STOP_PRINT "Detener Impresion" + #define MSG_PAUSE_PRINT "Pausar impresion" + #define MSG_RESUME_PRINT "Reanudar impres." + #define MSG_STOP_PRINT "Detener impresion" #define MSG_CARD_MENU "Menu de SD" - #define MSG_NO_CARD "No hay Tarjeta SD" + #define MSG_NO_CARD "No hay tarjeta SD" #define MSG_DWELL "Reposo..." - #define MSG_USERWAIT "Esperando Ordenes..." - #define MSG_RESUMING "Resumiendo Impresion" + #define MSG_USERWAIT "Esperando ordenes" + #define MSG_RESUMING "Resumiendo impre." #define MSG_NO_MOVE "Sin movimiento" - #define MSG_KILLED "PARADA DE EMERGENCIA. " - #define MSG_STOPPED "PARADA." + #define MSG_KILLED "PARADA DE EMERG." + #define MSG_STOPPED "PARADA" #define MSG_CONTROL_RETRACT "Retraer mm" #define MSG_CONTROL_RETRACTF "Retraer F" #define MSG_CONTROL_RETRACT_ZLIFT "Levantar mm" @@ -879,19 +895,18 @@ #define MSG_CONTROL_RETRACT_RECOVERF "DesRet F" #define MSG_AUTORETRACT "AutoRetr." #define MSG_FILAMENTCHANGE "Change filament" - #define MSG_INIT_SDCARD "Iniciando. Tarjeta-SD" - #define MSG_CNG_SDCARD "Cambiar Tarjeta-SD" + #define MSG_INIT_SDCARD "Iniciando tarjeta" + #define MSG_CNG_SDCARD "Cambiar tarjeta" #define MSG_RECTRACT_WIDE "Retraer" #define MSG_TEMPERATURE_WIDE "Temperatura" #define MSG_TEMPERATURE_RTN "Temperatura" - #define MSG_MAIN_WIDE "Menu Principal" + #define MSG_MAIN_WIDE "Menu principal" #define MSG_MOTION_WIDE "Movimiento" #define MSG_PREPARE_ALT "Preparar" #define MSG_CONTROL_ARROW "Control" #define MSG_RETRACT_ARROW "Retraer" - #define MSG_PART_RELEASE "Desacople Parcial" #define MSG_STEPPER_RELEASED "Desacoplada." - #define MSG_ZPROBE_OUT "ZProbe Outside Bed" + #define MSG_ZPROBE_OUT "Z probe out. bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" #define MSG_BABYSTEP_X "Babystep X" @@ -908,7 +923,6 @@ #define MSG_BROWNOUT_RESET " Reset por Voltaje Incorrecto" #define MSG_WATCHDOG_RESET " Reset por Bloqueo" #define MSG_SOFTWARE_RESET " Reset por Software" - #define MSG_MARLIN "Marlin " #define MSG_AUTHOR " | Autor: " #define MSG_CONFIGURATION_VER " Ultima actualizacion: " #define MSG_FREE_MEMORY " Memoria libre: " @@ -973,13 +987,17 @@ #define MSG_BABYSTEPPING_X "Babystepping X" #define MSG_BABYSTEPPING_Y "Babystepping Y" #define MSG_BABYSTEPPING_Z "Babystepping Z" + #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Error in menu structure" #endif #if LANGUAGE_CHOICE == 6 - // LCD Menu Messages - #define WELCOME_MSG MACHINE_NAME " Готов" + +// LCD Menu Messages +// Please note these are limited to 17 characters! + + #define WELCOME_MSG MACHINE_NAME " Готов." #define MSG_SD_INSERTED "Карта вставлена" #define MSG_SD_REMOVED "Карта извлечена" #define MSG_MAIN " Меню \003" @@ -1042,7 +1060,7 @@ #define MSG_RECTRACT " Откат подачи \x7E" #define MSG_TEMPERATURE " Температура \x7E" #define MSG_MOTION " Скорости \x7E" - #define MSG_CONTRAST "LCD contrast" + #define MSG_CONTRAST "LCD contrast" #define MSG_STORE_EPROM " Сохранить настройки" #define MSG_LOAD_EPROM " Загрузить настройки" #define MSG_RESTORE_FAILSAFE " Сброс настроек " @@ -1059,7 +1077,6 @@ #define MSG_USERWAIT "Нажмите для продолж." #define MSG_RESUMING "Resuming print" #define MSG_NO_MOVE "Нет движения. " - #define MSG_PART_RELEASE " Извлечение принта " #define MSG_KILLED "УБИТО. " #define MSG_STOPPED "ОСТАНОВЛЕНО. " #define MSG_CONTROL_RETRACT " Откат mm:" @@ -1071,7 +1088,7 @@ #define MSG_FILAMENTCHANGE "Change filament" #define MSG_INIT_SDCARD "Init. SD-Card" #define MSG_CNG_SDCARD "Change SD-Card" - #define MSG_ZPROBE_OUT "ZProbe Outside Bed" + #define MSG_ZPROBE_OUT "Z probe out. bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" #define MSG_BABYSTEP_X "Babystep X" @@ -1088,7 +1105,6 @@ #define MSG_BROWNOUT_RESET " Brown out сброс" #define MSG_WATCHDOG_RESET " Watchdog сброс" #define MSG_SOFTWARE_RESET " программный сброс" - #define MSG_MARLIN "Marlin " #define MSG_AUTHOR " | Автор: " #define MSG_CONFIGURATION_VER " Последнее обновление: " #define MSG_FREE_MEMORY " Памяти свободно: " @@ -1152,14 +1168,17 @@ #define MSG_BABYSTEPPING_X "Babystepping X" #define MSG_BABYSTEPPING_Y "Babystepping Y" #define MSG_BABYSTEPPING_Z "Babystepping Z" + #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Error in menu structure" #endif #if LANGUAGE_CHOICE == 7 - // LCD Menu Messages - #define WELCOME_MSG MACHINE_NAME " Pronta" +// LCD Menu Messages +// Please note these are limited to 17 characters! + + #define WELCOME_MSG MACHINE_NAME " pronto." #define MSG_SD_INSERTED "SD Card inserita" #define MSG_SD_REMOVED "SD Card rimossa" #define MSG_MAIN "Menu principale" @@ -1247,11 +1266,10 @@ #define MSG_CONTROL_RETRACT_RECOVER "UnRet +mm" #define MSG_CONTROL_RETRACT_RECOVERF "UnRet F" #define MSG_AUTORETRACT "AutoArretramento" - #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Qualcosa non va in MenuStructure." #define MSG_FILAMENTCHANGE "Cambia filamento" #define MSG_INIT_SDCARD "Iniz. SD-Card" #define MSG_CNG_SDCARD "Cambia SD-Card" - #define MSG_ZPROBE_OUT "ZProbe Outside Bed" + #define MSG_ZPROBE_OUT "Z probe out. bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" #define MSG_BABYSTEP_X "Babystep X" @@ -1260,7 +1278,7 @@ #define MSG_ENDSTOP_ABORT "Endstop abort" #define MSG_CONTRAST "Contrast" - // Serial Console Messages +// Serial Console Messages #define MSG_Enqueing "accodamento \"" #define MSG_POWERUP "Accensione" @@ -1268,7 +1286,6 @@ #define MSG_BROWNOUT_RESET " Brown out Reset" #define MSG_WATCHDOG_RESET " Watchdog Reset" #define MSG_SOFTWARE_RESET " Software Reset" - #define MSG_MARLIN "Marlin " #define MSG_AUTHOR " | Autore: " #define MSG_CONFIGURATION_VER " Ultimo Aggiornamento: " #define MSG_FREE_MEMORY " Memoria Libera: " @@ -1334,6 +1351,7 @@ #define MSG_BABYSTEPPING_X "Babystepping X" #define MSG_BABYSTEPPING_Y "Babystepping Y" #define MSG_BABYSTEPPING_Z "Babystepping Z" + #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Qualcosa non va in MenuStructure." #endif @@ -1341,26 +1359,28 @@ #if LANGUAGE_CHOICE == 8 // LCD Menu Messages - #define WELCOME_MSG MACHINE_NAME " Pronta." - #define MSG_SD_INSERTED "Cartao SD inserido" - #define MSG_SD_REMOVED "Cartao SD removido" - #define MSG_MAIN " Menu Principal \003" - #define MSG_AUTOSTART " Autostart" - #define MSG_DISABLE_STEPPERS " Apagar Motores" - #define MSG_AUTO_HOME " Ir para Origen" - #define MSG_SET_ORIGIN " Estabelecer Origen" - #define MSG_PREHEAT_PLA " pre-aquecer PLA" - #define MSG_PREHEAT_PLA_SETTINGS " pre-aquecer PLA Setting" - #define MSG_PREHEAT_ABS " pre-aquecer ABS" - #define MSG_PREHEAT_ABS_SETTINGS " pre-aquecer ABS Setting" - #define MSG_COOLDOWN " Esfriar" +// Please note these are limited to 17 characters! + + #define WELCOME_MSG MACHINE_NAME " pronto." + #define MSG_SD_INSERTED "Cartao inserido" + #define MSG_SD_REMOVED "Cartao removido" + #define MSG_MAIN " Menu principal \003" + #define MSG_AUTOSTART "Autostart" + #define MSG_DISABLE_STEPPERS " Apagar motores" + #define MSG_AUTO_HOME "Ir para origen" + #define MSG_SET_ORIGIN "Estabelecer orig." + #define MSG_PREHEAT_PLA "Pre-aquecer PLA" + #define MSG_PREHEAT_PLA_SETTINGS "PLA setting" + #define MSG_PREHEAT_ABS "Pre-aquecer ABS" + #define MSG_PREHEAT_ABS_SETTINGS "ABS setting" + #define MSG_COOLDOWN "Esfriar" #define MSG_SWITCH_PS_ON "Switch Power On" #define MSG_SWITCH_PS_OFF "Switch Power Off" - #define MSG_EXTRUDE " Extrudar" - #define MSG_RETRACT " Retrair" - #define MSG_PREHEAT_PLA " pre-aquecer PLA" - #define MSG_PREHEAT_ABS " pre-aquecer ABS" - #define MSG_MOVE_AXIS " Mover eixo \x7E" + #define MSG_EXTRUDE "Extrudar" + #define MSG_RETRACT "Retrair" + #define MSG_PREHEAT_PLA "Pre-aquecer PLA" + #define MSG_PREHEAT_ABS "Pre-aquecer ABS" + #define MSG_MOVE_AXIS "Mover eixo \x7E" #define MSG_MOVE_X "Move X" #define MSG_MOVE_Y "Move Y" #define MSG_MOVE_Z "Move Z" @@ -1368,26 +1388,26 @@ #define MSG_MOVE_01MM "Move 0.1mm" #define MSG_MOVE_1MM "Move 1mm" #define MSG_MOVE_10MM "Move 10mm" - #define MSG_SPEED " Velocidade:" - #define MSG_NOZZLE " \002Nozzle:" - #define MSG_NOZZLE1 " \002Nozzle2:" - #define MSG_NOZZLE2 " \002Nozzle3:" - #define MSG_BED " \002Base:" - #define MSG_FAN_SPEED " Velocidade Ventoinha:" - #define MSG_FLOW " Fluxo:" - #define MSG_CONTROL " Controle \003" - #define MSG_MIN " \002 Min:" - #define MSG_MAX " \002 Max:" - #define MSG_FACTOR " \002 Fact:" - #define MSG_AUTOTEMP " Autotemp:" + #define MSG_SPEED "Velocidade:" + #define MSG_NOZZLE "\002Nozzle:" + #define MSG_NOZZLE1 "\002Nozzle2:" + #define MSG_NOZZLE2 "\002Nozzle3:" + #define MSG_BED "\002Base:" + #define MSG_FAN_SPEED "Velocidade vento." + #define MSG_FLOW "Fluxo:" + #define MSG_CONTROL "Controle \003" + #define MSG_MIN "\002 Min:" + #define MSG_MAX "\002 Max:" + #define MSG_FACTOR "\002 Fact:" + #define MSG_AUTOTEMP "Autotemp:" #define MSG_ON "On " #define MSG_OFF "Off" - #define MSG_PID_P " PID-P: " - #define MSG_PID_I " PID-I: " - #define MSG_PID_D " PID-D: " - #define MSG_PID_C " PID-C: " - #define MSG_ACC " Acc:" - #define MSG_VXY_JERK " Vxy-jerk: " + #define MSG_PID_P "PID-P: " + #define MSG_PID_I "PID-I: " + #define MSG_PID_D "PID-D: " + #define MSG_PID_C "PID-C: " + #define MSG_ACC "Acc:" + #define MSG_VXY_JERK "Vxy-jerk: " #define MSG_VZ_JERK "Vz-jerk" #define MSG_VE_JERK "Ve-jerk" #define MSG_VMAX " Vmax " @@ -1395,39 +1415,38 @@ #define MSG_Y "y:" #define MSG_Z "z:" #define MSG_E "e:" - #define MSG_VMIN " Vmin:" - #define MSG_VTRAV_MIN " VTrav min:" - #define MSG_AMAX " Amax " - #define MSG_A_RETRACT " A-retract:" - #define MSG_XSTEPS " Xpasso/mm:" - #define MSG_YSTEPS " Ypasso/mm:" - #define MSG_ZSTEPS " Zpasso/mm:" - #define MSG_ESTEPS " Epasso/mm:" - #define MSG_MAIN_WIDE " Menu Principal \003" + #define MSG_VMIN "Vmin:" + #define MSG_VTRAV_MIN "VTrav min:" + #define MSG_AMAX "Amax " + #define MSG_A_RETRACT "A-retract:" + #define MSG_XSTEPS "Xpasso/mm:" + #define MSG_YSTEPS "Ypasso/mm:" + #define MSG_ZSTEPS "Zpasso/mm:" + #define MSG_ESTEPS "Epasso/mm:" + #define MSG_MAIN_WIDE "Menu Principal \003" #define MSG_RECTRACT "Retrair" #define MSG_TEMPERATURE "Temperatura" #define MSG_MOTION "Movimento" - #define MSG_STORE_EPROM " Guardar memoria" - #define MSG_LOAD_EPROM " Carregar memoria" - #define MSG_RESTORE_FAILSAFE " Rest. de emergencia" + #define MSG_STORE_EPROM "Guardar memoria" + #define MSG_LOAD_EPROM "Carregar memoria" + #define MSG_RESTORE_FAILSAFE "Rest. de emergen." #define MSG_REFRESH "\004Recarregar" - #define MSG_WATCH " Monitorar \003" - #define MSG_PREPARE " Preparar \x7E" - #define MSG_PREPARE_ALT " Preparar \003" - #define MSG_CONTROL_ARROW " Controle \x7E" - #define MSG_RETRACT_ARROW " Retrair \x7E" - #define MSG_TUNE " Tune \x7E" - #define MSG_PAUSE_PRINT " Pausar Impressao \x7E" - #define MSG_RESUME_PRINT " Resumir Impressao \x7E" - #define MSG_STOP_PRINT " Parar Impressao \x7E" - #define MSG_CARD_MENU " Menu cartao SD \x7E" - #define MSG_NO_CARD " Sem cartao SD" + #define MSG_WATCH "Monitorar \003" + #define MSG_PREPARE "Preparar \x7E" + #define MSG_PREPARE_ALT "Preparar \003" + #define MSG_CONTROL_ARROW "Controle \x7E" + #define MSG_RETRACT_ARROW "Retrair \x7E" + #define MSG_TUNE "Tune \x7E" + #define MSG_PAUSE_PRINT "Pausar impressao" + #define MSG_RESUME_PRINT "Resumir impressao" + #define MSG_STOP_PRINT "Parar impressao" + #define MSG_CARD_MENU "Menu cartao SD" + #define MSG_NO_CARD "Sem cartao SD" #define MSG_DWELL "Repouso..." - #define MSG_USERWAIT "Esperando Ordem..." + #define MSG_USERWAIT "Esperando ordem" #define MSG_RESUMING "Resuming print" - #define MSG_NO_MOVE "Sem movimento." - #define MSG_PART_RELEASE "Lancamento Parcial" - #define MSG_KILLED "PARADA DE EMERGENCIA. " + #define MSG_NO_MOVE "Sem movimento" + #define MSG_KILLED "PARADA DE EMERG." #define MSG_STOPPED "PARADA. " #define MSG_STEPPER_RELEASED "Lancado." #define MSG_CONTROL_RETRACT " Retrair mm:" @@ -1436,12 +1455,11 @@ #define MSG_CONTROL_RETRACT_RECOVER " DesRet +mm:" #define MSG_CONTROL_RETRACT_RECOVERF " DesRet F:" #define MSG_AUTORETRACT " AutoRetr.:" - #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Algo esta errado na estrutura do Menu." #define MSG_FILAMENTCHANGE "Change filament" #define MSG_INIT_SDCARD "Init. SD-Card" #define MSG_CNG_SDCARD "Change SD-Card" - #define MSG_ZPROBE_OUT "Sonda fora da mesa" - #define MSG_POSITION_UNKNOWN "Home X/Y antes de Z" + #define MSG_ZPROBE_OUT "Son. fora da mesa" + #define MSG_POSITION_UNKNOWN "XY antes de Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" #define MSG_BABYSTEP_X "Babystep X" #define MSG_BABYSTEP_Y "Babystep Y" @@ -1457,7 +1475,6 @@ #define MSG_BROWNOUT_RESET " Reset por voltagem incorreta" #define MSG_WATCHDOG_RESET " Reset por Bloqueio" #define MSG_SOFTWARE_RESET " Reset por Software" - #define MSG_MARLIN "Marlin " #define MSG_AUTHOR " | Author: " #define MSG_CONFIGURATION_VER " Ultima atualizacao: " #define MSG_FREE_MEMORY " memoria Livre: " @@ -1523,6 +1540,7 @@ #define MSG_BABYSTEPPING_X "Babystepping X" #define MSG_BABYSTEPPING_Y "Babystepping Y" #define MSG_BABYSTEPPING_Z "Babystepping Z" + #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Algo esta errado na estrutura do Menu." #endif @@ -1530,10 +1548,10 @@ #if LANGUAGE_CHOICE == 9 -// Finnish - // LCD Menu Messages - #define WELCOME_MSG MACHINE_NAME " valmis" +// Please note these are limited to 17 characters! + + #define WELCOME_MSG MACHINE_NAME " valmis." #define MSG_SD_INSERTED "Kortti asetettu" #define MSG_SD_REMOVED "Kortti poistettu" #define MSG_MAIN "Palaa" @@ -1542,9 +1560,9 @@ #define MSG_AUTO_HOME "Aja referenssiin" #define MSG_SET_ORIGIN "Aseta origo" #define MSG_PREHEAT_PLA "Esilammita PLA" - #define MSG_PREHEAT_PLA_SETTINGS "Esilammita PLA konf" + #define MSG_PREHEAT_PLA_SETTINGS "Esilamm. PLA konf" #define MSG_PREHEAT_ABS "Esilammita ABS" - #define MSG_PREHEAT_ABS_SETTINGS "Esilammita ABS konf" + #define MSG_PREHEAT_ABS_SETTINGS "Esilamm. ABS konf" #define MSG_COOLDOWN "Jaahdyta" #define MSG_SWITCH_PS_ON "Switch Power On" #define MSG_SWITCH_PS_OFF "Switch Power Off" @@ -1610,8 +1628,8 @@ #define MSG_CARD_MENU "Korttivalikko" #define MSG_NO_CARD "Ei korttia" #define MSG_DWELL "Nukkumassa..." - #define MSG_USERWAIT "Odotetaan valintaa..." - #define MSG_RESUMING "Jatketaan tulostusta" + #define MSG_USERWAIT "Odotet. valintaa" + #define MSG_RESUMING "Jatke. tulostusta" #define MSG_NO_MOVE "Ei liiketta." #define MSG_KILLED "KILLED. " #define MSG_STOPPED "STOPPED. " @@ -1624,7 +1642,7 @@ #define MSG_FILAMENTCHANGE "Change filament" #define MSG_INIT_SDCARD "Init. SD-Card" #define MSG_CNG_SDCARD "Change SD-Card" - #define MSG_ZPROBE_OUT "ZProbe Outside Bed" + #define MSG_ZPROBE_OUT "Z probe out. bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" #define MSG_BABYSTEP_X "Babystep X" @@ -1641,7 +1659,6 @@ #define MSG_BROWNOUT_RESET " Alajannite Reset" #define MSG_WATCHDOG_RESET " Vahtikoira Reset" #define MSG_SOFTWARE_RESET " Ohjelmisto Reset" - #define MSG_MARLIN "Marlin " #define MSG_AUTHOR " | Author: " #define MSG_CONFIGURATION_VER " Paivitetty viimeksi: " #define MSG_FREE_MEMORY " Vapaata muistia: " @@ -1709,24 +1726,27 @@ #define MSG_BABYSTEPPING_Z "Babystepping Z" #define MSG_ENDSTOP_ABORT "Endstop abort" #define MSG_CONTRAST "Contrast" + #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Error in menu structure" #endif #if LANGUAGE_CHOICE == 10 // LCD Menu Messages - #define WELCOME_MSG MACHINE_NAME " Parada." - #define MSG_SD_INSERTED "Tarcheta SD Colocada" - #define MSG_SD_REMOVED "Tarcheta SD Retirada" - #define MSG_MAIN "Menu Prencipal" +// Please note these are limited to 17 characters! + + #define WELCOME_MSG MACHINE_NAME " parada." + #define MSG_SD_INSERTED "Tarcheta colocada" + #define MSG_SD_REMOVED "Tarcheta retirada" + #define MSG_MAIN "Menu prencipal" #define MSG_AUTOSTART " Autostart" - #define MSG_DISABLE_STEPPERS "Amortar Motors" - #define MSG_AUTO_HOME "Levar a l'Orichen" // "Levar Eixes a o Zero" - #define MSG_SET_ORIGIN "Establir Zero" + #define MSG_DISABLE_STEPPERS "Amortar motors" + #define MSG_AUTO_HOME "Levar a l'orichen" + #define MSG_SET_ORIGIN "Establir zero" #define MSG_PREHEAT_PLA "Precalentar PLA" - #define MSG_PREHEAT_PLA_SETTINGS "Achustar temp. PLA" + #define MSG_PREHEAT_PLA_SETTINGS "Achustar tem. PLA" #define MSG_PREHEAT_ABS "Precalentar ABS" - #define MSG_PREHEAT_ABS_SETTINGS "Achustar temp. ABS" + #define MSG_PREHEAT_ABS_SETTINGS "Achustar tem. ABS" #define MSG_COOLDOWN "Enfriar" #define MSG_SWITCH_PS_ON "Enchegar Fuent" #define MSG_SWITCH_PS_OFF "Desenchegar Fuent" @@ -1780,21 +1800,21 @@ #define MSG_MOTION "Movimiento" #define MSG_STORE_EPROM "Alzar Memoria" #define MSG_LOAD_EPROM "Cargar Memoria" - #define MSG_RESTORE_FAILSAFE "Rest. d'emerchencia" + #define MSG_RESTORE_FAILSAFE "Rest. d'emerchen." #define MSG_REFRESH "Tornar a cargar" #define MSG_WATCH "Monitorizar" #define MSG_PREPARE "Preparar" #define MSG_TUNE "Achustar" - #define MSG_PAUSE_PRINT "Pausar Impresion" - #define MSG_RESUME_PRINT "Continar Impresion" + #define MSG_PAUSE_PRINT "Pausar impresion" + #define MSG_RESUME_PRINT "Contin. impresion" #define MSG_STOP_PRINT "Detener Impresion" #define MSG_CARD_MENU "Menu de SD" - #define MSG_NO_CARD "No i hai Tarcheta SD" + #define MSG_NO_CARD "No i hai tarcheta" #define MSG_DWELL "Reposo..." - #define MSG_USERWAIT "Asperando Ordines..." - #define MSG_RESUMING "Continando Impresion" + #define MSG_USERWAIT "Asperan. ordines" + #define MSG_RESUMING "Contin. impresion" #define MSG_NO_MOVE "Sin movimiento" - #define MSG_KILLED "ATURADA D'EMERCHENCIA. " + #define MSG_KILLED "ATURADA D'EMERCH." #define MSG_STOPPED "ATURADA." #define MSG_CONTROL_RETRACT "Retraer mm" #define MSG_CONTROL_RETRACTF "Retraer F" @@ -1803,8 +1823,8 @@ #define MSG_CONTROL_RETRACT_RECOVERF "DesRet F" #define MSG_AUTORETRACT "AutoRetr." #define MSG_FILAMENTCHANGE "Cambear" - #define MSG_INIT_SDCARD "Encetando. Tarcheta-SD" - #define MSG_CNG_SDCARD "Cambiar Tarcheta-SD" + #define MSG_INIT_SDCARD "Encetan. tarcheta" + #define MSG_CNG_SDCARD "Cambiar tarcheta" #define MSG_RECTRACT_WIDE "Retraer" #define MSG_TEMPERATURE_WIDE "Temperatura" #define MSG_TEMPERATURE_RTN "Temperatura" @@ -1813,9 +1833,8 @@ #define MSG_PREPARE_ALT "Preparar" #define MSG_CONTROL_ARROW "Control" #define MSG_RETRACT_ARROW "Retraer" - #define MSG_PART_RELEASE "Desacople Parcial" #define MSG_STEPPER_RELEASED "Desacoplada." - #define MSG_ZPROBE_OUT "ZProbe Outside Bed" + #define MSG_ZPROBE_OUT "Z probe out. bed" #define MSG_POSITION_UNKNOWN "Home X/Y before Z" #define MSG_ZPROBE_ZOFFSET "Z Offset" #define MSG_BABYSTEP_X "Babystep X" @@ -1832,7 +1851,6 @@ #define MSG_BROWNOUT_RESET " Reset por Voltaje Incorrecto" #define MSG_WATCHDOG_RESET " Reset por Bloqueo" #define MSG_SOFTWARE_RESET " Reset por Software" - #define MSG_MARLIN "Marlin " #define MSG_AUTHOR " | Autor: " #define MSG_CONFIGURATION_VER " Zaguer esvielle: " #define MSG_FREE_MEMORY " Memoria libre: " @@ -1897,6 +1915,7 @@ #define MSG_BABYSTEPPING_X "Babystepping X" #define MSG_BABYSTEPPING_Y "Babystepping Y" #define MSG_BABYSTEPPING_Z "Babystepping Z" + #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Error in menu structure" #endif From d6c5c503d4d72a6d08314967f2996e83d1b05f4d Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Wed, 12 Feb 2014 12:59:50 -0800 Subject: [PATCH 145/256] correct feedrate units in comments for M207/M208 --- Marlin/Marlin_main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 5f8f86f784..ab14f9907f 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -137,8 +137,8 @@ // M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) im mm/sec^2 also sets minimum segment time in ms (B20000) to prevent buffer underruns and M20 minimum feedrate // M205 - advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk, E=maximum E jerk // M206 - set additional homeing offset -// M207 - set retract length S[positive mm] F[feedrate mm/sec] Z[additional zlift/hop], stays in mm regardless of M200 setting -// M208 - set recover=unretract length S[positive mm surplus to the M207 S*] F[feedrate mm/sec] +// M207 - set retract length S[positive mm] F[feedrate mm/min] Z[additional zlift/hop], stays in mm regardless of M200 setting +// M208 - set recover=unretract length S[positive mm surplus to the M207 S*] F[feedrate mm/min] // M209 - S<1=true/0=false> enable automatic retract detect if the slicer did not support G10/11: every normal extrude-only move will be classified as retract depending on the direction. // M218 - set hotend offset (in mm): T X Y // M220 S- set speed factor override percentage From 6e433985094874f3c3fbf70becd577b8ea2115eb Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Wed, 12 Feb 2014 13:01:19 -0800 Subject: [PATCH 146/256] G10/G11 bugfixes Previous version was broken by using G92 E0 between retract and recover. --- Marlin/Marlin_main.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index ab14f9907f..7c7a0b0442 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1114,7 +1114,9 @@ void process_commands() destination[Y_AXIS]=current_position[Y_AXIS]; destination[Z_AXIS]=current_position[Z_AXIS]; current_position[Z_AXIS]-=retract_zlift; - destination[E_AXIS]=current_position[E_AXIS]-retract_length/volumetric_multiplier[active_extruder]; + destination[E_AXIS]=current_position[E_AXIS]; + current_position[E_AXIS]+=retract_length/volumetric_multiplier[active_extruder]; + plan_set_e_position(current_position[E_AXIS]); float oldFeedrate = feedrate; feedrate=retract_feedrate; retracted=true; @@ -1130,7 +1132,9 @@ void process_commands() destination[Y_AXIS]=current_position[Y_AXIS]; destination[Z_AXIS]=current_position[Z_AXIS]; current_position[Z_AXIS]+=retract_zlift; - destination[E_AXIS]=current_position[E_AXIS]+(retract_length+retract_recover_length)/volumetric_multiplier[active_extruder]; + destination[E_AXIS]=current_position[E_AXIS]; + current_position[E_AXIS]-=(retract_length+retract_recover_length)/volumetric_multiplier[active_extruder]; + plan_set_e_position(current_position[E_AXIS]); float oldFeedrate = feedrate; feedrate=retract_recover_feedrate; retracted=false; From 9b7d87e885d8add20cae536e26d8d0317e1dea1f Mon Sep 17 00:00:00 2001 From: daid Date: Thu, 13 Feb 2014 10:50:17 +0100 Subject: [PATCH 147/256] Remove duplicate contrast define. --- Marlin/language.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Marlin/language.h b/Marlin/language.h index ab3bf63558..4b00d19c2f 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -165,7 +165,6 @@ #define MSG_BABYSTEP_Y "Babystep Y" #define MSG_BABYSTEP_Z "Babystep Z" #define MSG_ENDSTOP_ABORT "Endstop abort" - #define MSG_CONTRAST "Contrast" // Serial Console Messages From 71bb3a81334e2948caa4fade4b61f28aec0d60f9 Mon Sep 17 00:00:00 2001 From: daid Date: Thu, 13 Feb 2014 10:53:46 +0100 Subject: [PATCH 148/256] Add comments for Ultimainboard 2.0 configuration. --- Marlin/Configuration.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 696b4ca9d6..6a2c43ba3c 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -55,6 +55,7 @@ // 68 = Azteeg X3 Pro // 7 = Ultimaker // 71 = Ultimaker (Older electronics. Pre 1.5.4. This is rare) +// 72 = Ultimainboard 2.x (Uses TEMP_SENSOR 20) // 77 = 3Drag Controller // 8 = Teensylu // 80 = Rumba @@ -114,6 +115,7 @@ // 8 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup) // 9 is 100k GE Sensing AL03006-58.2K-97-G1 (4.7k pullup) // 10 is 100k RS thermistor 198-961 (4.7k pullup) +// 20 is the PT100 circuit found in the Ultimainboard V2.x // 60 is 100k Maker's Tool Works Kapton Bed Thermister // // 1k ohm pullup tables - This is not normal, you would have to have changed out your 4.7k for 1k From d16a770855fc6faef8e73470c81e610dd5ab3d4d Mon Sep 17 00:00:00 2001 From: daid Date: Thu, 13 Feb 2014 10:57:03 +0100 Subject: [PATCH 149/256] Ultimainboard 2.x does not has a PS_ON pin. --- Marlin/pins.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/pins.h b/Marlin/pins.h index 52ca2844df..995fa54c5f 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -1381,7 +1381,7 @@ #define SDSS 53 #define LED_PIN 8 #define FAN_PIN 7 -#define PS_ON_PIN 12 +#define PS_ON_PIN -1 #define KILL_PIN -1 #define SUICIDE_PIN -1 //PIN that has to be turned on right after start, to keep power flowing. #define SAFETY_TRIGGERED_PIN 28 //PIN to detect the safety circuit has triggered From 46f5bea19f1cc2f6f96a0bb3d24b6ff13a0eb32a Mon Sep 17 00:00:00 2001 From: daid Date: Thu, 13 Feb 2014 11:17:33 +0100 Subject: [PATCH 150/256] Add configurable beep for UltiPanel. --- Marlin/ultralcd_implementation_hitachi_HD44780.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Marlin/ultralcd_implementation_hitachi_HD44780.h b/Marlin/ultralcd_implementation_hitachi_HD44780.h index afc9c5c476..ccb820b49f 100644 --- a/Marlin/ultralcd_implementation_hitachi_HD44780.h +++ b/Marlin/ultralcd_implementation_hitachi_HD44780.h @@ -718,13 +718,23 @@ static void lcd_implementation_quick_feedback() #endif #elif defined(BEEPER) && BEEPER > -1 SET_OUTPUT(BEEPER); + #if !defined(LCD_FEEDBACK_FREQUENCY_HZ) || !defined(LCD_FEEDBACK_FREQUENCY_DURATION_MS) for(int8_t i=0;i<10;i++) { WRITE(BEEPER,HIGH); delayMicroseconds(100); WRITE(BEEPER,LOW); delayMicroseconds(100); - } + } + #else + for(int8_t i=0;i<(LCD_FEEDBACK_FREQUENCY_DURATION_MS / (1000 / LCD_FEEDBACK_FREQUENCY_HZ));i++) + { + WRITE(BEEPER,HIGH); + delayMicroseconds(1000000 / LCD_FEEDBACK_FREQUENCY_HZ / 2); + WRITE(BEEPER,LOW); + delayMicroseconds(1000000 / LCD_FEEDBACK_FREQUENCY_HZ / 2); + } + #endif #endif } From c31bb2b7ad934a0ed4485ebad5376924bb336efe Mon Sep 17 00:00:00 2001 From: daid Date: Thu, 13 Feb 2014 11:48:55 +0100 Subject: [PATCH 151/256] Only show the ZProbe offset when auto-bed-leveling is enabled. --- Marlin/ultralcd.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 269becf8ef..d3f4e32ca2 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -705,8 +705,10 @@ static void lcd_control_temperature_preheat_abs_settings_menu() static void lcd_control_motion_menu() { START_MENU(); - MENU_ITEM(back, MSG_CONTROL, lcd_control_menu); - MENU_ITEM_EDIT(float32, MSG_ZPROBE_ZOFFSET, &zprobe_zoffset, 0.5, 50); + MENU_ITEM(back, MSG_CONTROL, lcd_control_menu); +#ifdef ENABLE_AUTO_BED_LEVELING + MENU_ITEM_EDIT(float32, MSG_ZPROBE_ZOFFSET, &zprobe_zoffset, 0.5, 50); +#endif MENU_ITEM_EDIT(float5, MSG_ACC, &acceleration, 500, 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); From 7dcd350941fa139ecab43b7f49c99d3e565849df Mon Sep 17 00:00:00 2001 From: nothinman Date: Thu, 13 Feb 2014 11:58:14 +0000 Subject: [PATCH 152/256] A few changes to Russian, changed LCD strings to be <=17 characters. --- Marlin/language.h | 156 +++++++++++++++++++++++----------------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index 4b00d19c2f..2126f7fb5f 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -999,21 +999,21 @@ #define WELCOME_MSG MACHINE_NAME " Готов." #define MSG_SD_INSERTED "Карта вставлена" #define MSG_SD_REMOVED "Карта извлечена" - #define MSG_MAIN " Меню \003" - #define MSG_AUTOSTART " Автостарт " - #define MSG_DISABLE_STEPPERS " Выключить двигатели" - #define MSG_AUTO_HOME " Парковка " - #define MSG_SET_ORIGIN " Запомнить ноль " - #define MSG_PREHEAT_PLA " Преднагрев PLA " - #define MSG_PREHEAT_PLA_SETTINGS " Настр. преднагр.PLA" - #define MSG_PREHEAT_ABS " Преднагрев ABS " - #define MSG_PREHEAT_ABS_SETTINGS " Настр. преднагр.ABS" - #define MSG_COOLDOWN " Охлаждение " + #define MSG_MAIN "Меню \003" + #define MSG_AUTOSTART "Автостарт" + #define MSG_DISABLE_STEPPERS "Выкл. двигатели" + #define MSG_AUTO_HOME "Парковка" + #define MSG_SET_ORIGIN "Запомнить ноль" + #define MSG_PREHEAT_PLA "Преднагрев PLA" + #define MSG_PREHEAT_PLA_SETTINGS "Настройки PLA" + #define MSG_PREHEAT_ABS "Преднагрев ABS" + #define MSG_PREHEAT_ABS_SETTINGS "Настройки ABS" + #define MSG_COOLDOWN "Охлаждение" #define MSG_SWITCH_PS_ON "Switch Power On" #define MSG_SWITCH_PS_OFF "Switch Power Off" - #define MSG_EXTRUDE " Экструзия " - #define MSG_RETRACT " Откат" - #define MSG_MOVE_AXIS " Движение по осям \x7E" + #define MSG_EXTRUDE "Экструзия" + #define MSG_RETRACT "Откат" + #define MSG_MOVE_AXIS "Движение по осям" #define MSG_MOVE_X "Move X" #define MSG_MOVE_Y "Move Y" #define MSG_MOVE_Z "Move Z" @@ -1021,80 +1021,80 @@ #define MSG_MOVE_01MM "Move 0.1mm" #define MSG_MOVE_1MM "Move 1mm" #define MSG_MOVE_10MM "Move 10mm" - #define MSG_SPEED " Скорость:" - #define MSG_NOZZLE " \002 Фильера:" - #define MSG_NOZZLE1 " \002 Фильера2:" - #define MSG_NOZZLE2 " \002 Фильера3:" - #define MSG_BED " \002 Кровать:" - #define MSG_FAN_SPEED " Куллер:" - #define MSG_FLOW " Поток:" - #define MSG_CONTROL " Настройки \003" - #define MSG_MIN " \002 Минимум:" - #define MSG_MAX " \002 Максимум:" - #define MSG_FACTOR " \002 Фактор:" - #define MSG_AUTOTEMP " Autotemp:" + #define MSG_SPEED "Скорость:" + #define MSG_NOZZLE "\002 Фильера:" + #define MSG_NOZZLE1 "\002 Фильера2:" + #define MSG_NOZZLE2 "\002 Фильера3:" + #define MSG_BED "\002 Кровать:" + #define MSG_FAN_SPEED "Куллер:" + #define MSG_FLOW "Поток:" + #define MSG_CONTROL "Настройки \003" + #define MSG_MIN "\002 Минимум:" + #define MSG_MAX "\002 Максимум:" + #define MSG_FACTOR "\002 Фактор:" + #define MSG_AUTOTEMP "Autotemp:" #define MSG_ON "Вкл. " #define MSG_OFF "Выкл. " - #define MSG_PID_P " PID-P: " - #define MSG_PID_I " PID-I: " - #define MSG_PID_D " PID-D: " - #define MSG_PID_C " PID-C: " - #define MSG_ACC " Acc:" - #define MSG_VXY_JERK " Vxy-jerk: " + #define MSG_PID_P "PID-P: " + #define MSG_PID_I "PID-I: " + #define MSG_PID_D "PID-D: " + #define MSG_PID_C "PID-C: " + #define MSG_ACC "Acc:" + #define MSG_VXY_JERK "Vxy-jerk: " #define MSG_VZ_JERK "Vz-jerk" #define MSG_VE_JERK "Ve-jerk" - #define MSG_VMAX " Vmax " + #define MSG_VMAX "Vmax " #define MSG_X "x:" #define MSG_Y "y:" #define MSG_Z "z:" #define MSG_E "e:" - #define MSG_VMIN " Vmin:" - #define MSG_VTRAV_MIN " VTrav min:" - #define MSG_AMAX " Amax " - #define MSG_A_RETRACT " A-retract:" - #define MSG_XSTEPS " X шаг/mm:" - #define MSG_YSTEPS " Y шаг/mm:" - #define MSG_ZSTEPS " Z шаг/mm:" - #define MSG_ESTEPS " E шаг/mm:" - #define MSG_RECTRACT " Откат подачи \x7E" - #define MSG_TEMPERATURE " Температура \x7E" - #define MSG_MOTION " Скорости \x7E" - #define MSG_CONTRAST "LCD contrast" - #define MSG_STORE_EPROM " Сохранить настройки" - #define MSG_LOAD_EPROM " Загрузить настройки" - #define MSG_RESTORE_FAILSAFE " Сброс настроек " - #define MSG_REFRESH "\004Обновить " - #define MSG_WATCH " Обзор \003" - #define MSG_PREPARE " Действия \x7E" - #define MSG_TUNE " Настройки \x7E" - #define MSG_PAUSE_PRINT " Пауза печати \x7E" - #define MSG_RESUME_PRINT " Продолжить печать \x7E" - #define MSG_STOP_PRINT " Остановить печать \x7E" - #define MSG_CARD_MENU " Меню карты \x7E" - #define MSG_NO_CARD " Нет карты" + #define MSG_VMIN "Vmin:" + #define MSG_VTRAV_MIN "VTrav min:" + #define MSG_AMAX "Amax " + #define MSG_A_RETRACT "A-retract:" + #define MSG_XSTEPS "X шаг/mm:" + #define MSG_YSTEPS "Y шаг/mm:" + #define MSG_ZSTEPS "Z шаг/mm:" + #define MSG_ESTEPS "E шаг/mm:" + #define MSG_RECTRACT "Откат подачи \x7E" + #define MSG_TEMPERATURE "Температура \x7E" + #define MSG_MOTION "Скорости \x7E" + #define MSG_CONTRAST "LCD contrast" + #define MSG_STORE_EPROM "Сохранить в EPROM" + #define MSG_LOAD_EPROM "Загруз. из EPROM" + #define MSG_RESTORE_FAILSAFE "Сброс настроек" + #define MSG_REFRESH "\004Обновить" + #define MSG_WATCH "Обзор \003" + #define MSG_PREPARE "Действия \x7E" + #define MSG_TUNE "Настройки \x7E" + #define MSG_RESUME_PRINT "Продолжить печать" + #define MSG_RESUME_PRINT "Продолжить печать" + #define MSG_STOP_PRINT "Остановить печать" + #define MSG_CARD_MENU "Меню карты \x7E" + #define MSG_NO_CARD "Нет карты" #define MSG_DWELL "Сон..." - #define MSG_USERWAIT "Нажмите для продолж." - #define MSG_RESUMING "Resuming print" - #define MSG_NO_MOVE "Нет движения. " - #define MSG_KILLED "УБИТО. " - #define MSG_STOPPED "ОСТАНОВЛЕНО. " - #define MSG_CONTROL_RETRACT " Откат mm:" - #define MSG_CONTROL_RETRACTF " Откат F:" - #define MSG_CONTROL_RETRACT_ZLIFT " Прыжок mm:" - #define MSG_CONTROL_RETRACT_RECOVER " Возврат +mm:" - #define MSG_CONTROL_RETRACT_RECOVERF " Возврат F:" - #define MSG_AUTORETRACT " АвтоОткат:" - #define MSG_FILAMENTCHANGE "Change filament" - #define MSG_INIT_SDCARD "Init. SD-Card" - #define MSG_CNG_SDCARD "Change SD-Card" - #define MSG_ZPROBE_OUT "Z probe out. bed" - #define MSG_POSITION_UNKNOWN "Home X/Y before Z" - #define MSG_ZPROBE_ZOFFSET "Z Offset" - #define MSG_BABYSTEP_X "Babystep X" - #define MSG_BABYSTEP_Y "Babystep Y" - #define MSG_BABYSTEP_Z "Babystep Z" - #define MSG_ENDSTOP_ABORT "Endstop abort" - #define MSG_CONTRAST "Contrast" + #define MSG_USERWAIT "Ожиданиие" + #define MSG_RESUMING "Resuming print" + #define MSG_NO_MOVE "Нет движения." + #define MSG_KILLED "УБИТО." + #define MSG_STOPPED "ОСТАНОВЛЕНО." + #define MSG_CONTROL_RETRACT "Откат mm:" + #define MSG_CONTROL_RETRACTF "Откат F:" + #define MSG_CONTROL_RETRACT_ZLIFT "Прыжок mm:" + #define MSG_CONTROL_RETRACT_RECOVER "Возврат +mm:" + #define MSG_CONTROL_RETRACT_RECOVERF "Возврат F:" + #define MSG_AUTORETRACT "АвтоОткат:" + #define MSG_FILAMENTCHANGE "Change filament" + #define MSG_INIT_SDCARD "Init. SD-Card" + #define MSG_CNG_SDCARD "Change SD-Card" + #define MSG_ZPROBE_OUT "Z probe out. bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_BABYSTEP_X "Babystep X" + #define MSG_BABYSTEP_Y "Babystep Y" + #define MSG_BABYSTEP_Z "Babystep Z" + #define MSG_ENDSTOP_ABORT "Endstop abort" + #define MSG_CONTRAST "Contrast" // Serial Console Messages From 831fc2a95257d58cddd458d19e57065745fd4024 Mon Sep 17 00:00:00 2001 From: Josef Pavlik Date: Fri, 14 Feb 2014 12:15:31 +0100 Subject: [PATCH 153/256] Pt100 and Pt1000 temperature sensors handling --- Marlin/Configuration.h | 5 +++ Marlin/thermistortables.h | 64 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 33a1c3a160..5d235bc459 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -120,6 +120,11 @@ // 51 is 100k thermistor - EPCOS (1k pullup) // 52 is 200k thermistor - ATC Semitec 204GT-2 (1k pullup) // 55 is 100k thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (1k pullup) +// +// 1047 is Pt1000 with 4k7 pullup +// 1010 is Pt1000 with 1k pullup (non standard) +// 147 is Pt100 with 4k7 pullup +// 110 is Pt100 with 1k pullup (non standard) #define TEMP_SENSOR_0 -1 #define TEMP_SENSOR_1 -1 diff --git a/Marlin/thermistortables.h b/Marlin/thermistortables.h index 58a2466fee..1d2b3ca65f 100644 --- a/Marlin/thermistortables.h +++ b/Marlin/thermistortables.h @@ -857,6 +857,70 @@ const short temptable_60[][2] PROGMEM = { }; #endif +// Pt1000 and Pt100 handling +// +// Rt=R0*(1+a*T+b*T*T) [for T>0] +// a=3.9083E-3, b=-5.775E-7 + +#define PtA 3.9083E-3 +#define PtB -5.775E-7 +#define PtRt(T,R0) ((R0)*(1.0+(PtA)*(T)+(PtB)*(T)*(T))) +#define PtAdVal(T,R0,Rup) (short)(1024/(Rup/PtRt(T,R0)+1)) +#define PtLine(T,R0,Rup) { PtAdVal(T,R0,Rup)*OVERSAMPLENR, T }, + +#if (THERMISTORHEATER_0 == 110) || (THERMISTORHEATER_1 == 110) || (THERMISTORHEATER_2 == 110) || (THERMISTORBED == 110) // Pt100 with 1k0 pullup +const short temptable_110[][2] PROGMEM = { +// only few values are needed as the curve is very flat + PtLine(0,100,1000) + PtLine(50,100,1000) + PtLine(100,100,1000) + PtLine(150,100,1000) + PtLine(200,100,1000) + PtLine(250,100,1000) + PtLine(300,100,1000) +}; +#endif +#if (THERMISTORHEATER_0 == 147) || (THERMISTORHEATER_1 == 147) || (THERMISTORHEATER_2 == 147) || (THERMISTORBED == 147) // Pt100 with 4k7 pullup +const short temptable_147[][2] PROGMEM = { +// only few values are needed as the curve is very flat + PtLine(0,100,4700) + PtLine(50,100,4700) + PtLine(100,100,4700) + PtLine(150,100,4700) + PtLine(200,100,4700) + PtLine(250,100,4700) + PtLine(300,100,4700) +}; +#endif +#if (THERMISTORHEATER_0 == 1010) || (THERMISTORHEATER_1 == 1010) || (THERMISTORHEATER_2 == 1010) || (THERMISTORBED == 1010) // Pt1000 with 1k0 pullup +const short temptable_1010[][2] PROGMEM = { + PtLine(0,1000,1000) + PtLine(25,1000,1000) + PtLine(50,1000,1000) + PtLine(75,1000,1000) + PtLine(100,1000,1000) + PtLine(125,1000,1000) + PtLine(150,1000,1000) + PtLine(175,1000,1000) + PtLine(200,1000,1000) + PtLine(225,1000,1000) + PtLine(250,1000,1000) + PtLine(275,1000,1000) + PtLine(300,1000,1000) +}; +#endif +#if (THERMISTORHEATER_0 == 1047) || (THERMISTORHEATER_1 == 1047) || (THERMISTORHEATER_2 == 1047) || (THERMISTORBED == 1047) // Pt1000 with 4k7 pullup +const short temptable_1047[][2] PROGMEM = { +// only few values are needed as the curve is very flat + PtLine(0,1000,4700) + PtLine(50,1000,4700) + PtLine(100,1000,4700) + PtLine(150,1000,4700) + PtLine(200,1000,4700) + PtLine(250,1000,4700) + PtLine(300,1000,4700) +}; +#endif #define _TT_NAME(_N) temptable_ ## _N #define TT_NAME(_N) _TT_NAME(_N) From 477b6fa1df30d1ff6021df103d5bb5efef31ee4a Mon Sep 17 00:00:00 2001 From: Josef Pavlik Date: Mon, 3 Feb 2014 11:30:12 +0100 Subject: [PATCH 154/256] move engaged from lcd console refreshes power off timeout --- Marlin/Marlin.h | 2 ++ Marlin/Marlin_main.cpp | 4 ++++ Marlin/ultralcd.cpp | 3 +++ 3 files changed, 9 insertions(+) diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index af3325be41..4d6b227287 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -189,6 +189,8 @@ void enquecommand_P(const char *cmd); //put an ascii command at the end of the c void prepare_arc_move(char isclockwise); void clamp_to_software_endstops(float target[3]); +void refresh_cmd_timeout(void); + #ifdef FAST_PWM_FAN void setPwmFrequency(uint8_t pin, int val); #endif diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 920aed00c4..bf13f8e620 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1046,6 +1046,10 @@ static void homeaxis(int axis) { } } #define HOMEAXIS(LETTER) homeaxis(LETTER##_AXIS) ++void refresh_cmd_timeout(void) +{ + previous_millis_cmd = millis(); +} void process_commands() { diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 77be8e8e35..acbc8d6e4b 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -460,6 +460,7 @@ static void lcd_move_x() { if (encoderPosition != 0) { + refresh_cmd_timeout(); current_position[X_AXIS] += float((int)encoderPosition) * move_menu_scale; if (min_software_endstops && current_position[X_AXIS] < X_MIN_POS) current_position[X_AXIS] = X_MIN_POS; @@ -489,6 +490,7 @@ static void lcd_move_y() { if (encoderPosition != 0) { + refresh_cmd_timeout(); current_position[Y_AXIS] += float((int)encoderPosition) * move_menu_scale; if (min_software_endstops && current_position[Y_AXIS] < Y_MIN_POS) current_position[Y_AXIS] = Y_MIN_POS; @@ -518,6 +520,7 @@ static void lcd_move_z() { if (encoderPosition != 0) { + refresh_cmd_timeout(); current_position[Z_AXIS] += float((int)encoderPosition) * move_menu_scale; if (min_software_endstops && current_position[Z_AXIS] < Z_MIN_POS) current_position[Z_AXIS] = Z_MIN_POS; From ab0d3c4fb3c408fcb91e97ee5eb2417129cbb5d0 Mon Sep 17 00:00:00 2001 From: Mark Hanford Date: Fri, 14 Feb 2014 11:48:24 +0000 Subject: [PATCH 155/256] Various typo fixes - only in comments, no code changes. --- Marlin/Configuration.h | 44 +++++++++++++++++++------------------- Marlin/Configuration_adv.h | 28 ++++++++++++------------ 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 6a2c43ba3c..752028ec15 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -8,7 +8,7 @@ //=========================================================================== //============================= DELTA Printer =============================== //=========================================================================== -// For a Delta printer rplace the configuration files wilth the files in the +// For a Delta printer replace the configuration files with the files in the // example_configurations/delta directory. // @@ -68,7 +68,7 @@ // 702= Minitronics v1.0 // 90 = Alpha OMCA board // 91 = Final OMCA board -// 301 = Rambo +// 301= Rambo // 21 = Elefu Ra Board (v3) #ifndef MOTHERBOARD @@ -91,7 +91,7 @@ #define POWER_SUPPLY 1 -// Define this to have the electronics keep the powersupply off on startup. If you don't know what this is leave it. +// Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. // #define PS_DEFAULT_OFF //=========================================================================== @@ -106,7 +106,7 @@ // 0 is not used // 1 is 100k thermistor - best choice for EPCOS 100k (4.7k pullup) // 2 is 200k thermistor - ATC Semitec 204GT-2 (4.7k pullup) -// 3 is mendel-parts thermistor (4.7k pullup) +// 3 is Mendel-parts thermistor (4.7k pullup) // 4 is 10k thermistor !! do not use it for a hotend. It gives bad resolution at high temp. !! // 5 is 100K thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (4.7k pullup) // 6 is 100k EPCOS - Not as accurate as table 1 (created using a fluke thermocouple) (4.7k pullup) @@ -116,7 +116,7 @@ // 9 is 100k GE Sensing AL03006-58.2K-97-G1 (4.7k pullup) // 10 is 100k RS thermistor 198-961 (4.7k pullup) // 20 is the PT100 circuit found in the Ultimainboard V2.x -// 60 is 100k Maker's Tool Works Kapton Bed Thermister +// 60 is 100k Maker's Tool Works Kapton Bed Thermistor // // 1k ohm pullup tables - This is not normal, you would have to have changed out your 4.7k for 1k // (but gives greater accuracy and more stable PID) @@ -177,13 +177,13 @@ #define K1 0.95 //smoothing factor within the PID #define PID_dT ((OVERSAMPLENR * 8.0)/(F_CPU / 64.0 / 256.0)) //sampling period of the temperature routine -// If you are using a preconfigured hotend then you can use one of the value sets by uncommenting it +// If you are using a pre-configured hotend then you can use one of the value sets by uncommenting it // Ultimaker #define DEFAULT_Kp 22.2 #define DEFAULT_Ki 1.08 #define DEFAULT_Kd 114 -// Makergear +// MakerGear // #define DEFAULT_Kp 7.0 // #define DEFAULT_Ki 0.1 // #define DEFAULT_Kd 12 @@ -252,7 +252,7 @@ #define ENDSTOPPULLUPS // Comment this out (using // at the start of the line) to disable the endstop pullup resistors #ifndef ENDSTOPPULLUPS - // fine Enstop settings: Individual Pullups. will be ignored if ENDSTOPPULLUPS is defined + // fine endstop settings: Individual pullups. will be ignored if ENDSTOPPULLUPS is defined // #define ENDSTOPPULLUP_XMAX // #define ENDSTOPPULLUP_YMAX // #define ENDSTOPPULLUP_ZMAX @@ -336,7 +336,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #define BACK_PROBE_BED_POSITION 180 #define FRONT_PROBE_BED_POSITION 20 - // these are the offsets to the prob relative to the extruder tip (Hotend - Probe) + // these are the offsets to the probe relative to the extruder tip (Hotend - Probe) #define X_PROBE_OFFSET_FROM_EXTRUDER -25 #define Y_PROBE_OFFSET_FROM_EXTRUDER -29 #define Z_PROBE_OFFSET_FROM_EXTRUDER -12.35 @@ -357,7 +357,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of // #define PROBE_SERVO_DEACTIVATION_DELAY 300 -//If you have enabled the Bed Auto Levelling and are using the same Z Probe for Z Homing, +//If you have enabled the Bed Auto Leveling and are using the same Z Probe for Z Homing, //it is highly recommended you let this Z_SAFE_HOMING enabled!!! #define Z_SAFE_HOMING // This feature is meant to avoid Z homing with probe outside the bed area. @@ -391,7 +391,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of //#define BED_CENTER_AT_0_0 // If defined, the center of the bed is at (X=0, Y=0) //Manual homing switch locations: -// For deltabots this means top and center of the cartesian print volume. +// For deltabots this means top and center of the Cartesian print volume. #define MANUAL_X_HOME_POS 0 #define MANUAL_Y_HOME_POS 0 #define MANUAL_Z_HOME_POS 0 @@ -405,7 +405,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #define DEFAULT_AXIS_STEPS_PER_UNIT {78.7402,78.7402,200.0*8/3,760*1.1} // default steps per unit for Ultimaker #define DEFAULT_MAX_FEEDRATE {500, 500, 5, 25} // (mm/sec) -#define DEFAULT_MAX_ACCELERATION {9000,9000,100,10000} // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. +#define DEFAULT_MAX_ACCELERATION {9000,9000,100,10000} // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for Skeinforge 40+, for older versions raise them a lot. #define DEFAULT_ACCELERATION 3000 // X, Y, Z and E max acceleration in mm/s^2 for printing moves #define DEFAULT_RETRACT_ACCELERATION 3000 // X, Y, Z and E max acceleration in mm/s^2 for retracts @@ -426,11 +426,11 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of //=========================================================================== // EEPROM -// the microcontroller can store settings in the EEPROM, e.g. max velocity... -// M500 - stores paramters in EEPROM +// The microcontroller can store settings in the EEPROM, e.g. max velocity... +// M500 - stores parameters in EEPROM // M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily). // M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to. -//define this to enable eeprom support +//define this to enable EEPROM support //#define EEPROM_SETTINGS //to disable EEPROM Serial responses and decrease program space by ~1700 byte: comment this out: // please keep turned on if you can. @@ -446,14 +446,14 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #define ABS_PREHEAT_FAN_SPEED 255 // Insert Value between 0 and 255 //LCD and SD support -//#define ULTRA_LCD //general lcd support, also 16x2 +//#define ULTRA_LCD //general LCD support, also 16x2 //#define DOGLCD // Support for SPI LCD 128x64 (Controller ST7565R graphic Display Family) //#define SDSUPPORT // Enable SD Card Support in Hardware Console //#define SDSLOW // Use slower SD transfer mode (not normally needed - uncomment if you're getting volume init error) //#define ENCODER_PULSES_PER_STEP 1 // Increase if you have a high resolution encoder //#define ENCODER_STEPS_PER_MENU_ITEM 5 // Set according to ENCODER_PULSES_PER_STEP or your liking -//#define ULTIMAKERCONTROLLER //as available from the ultimaker online store. -//#define ULTIPANEL //the ultipanel as on thingiverse +//#define ULTIMAKERCONTROLLER //as available from the Ultimaker online store. +//#define ULTIPANEL //the UltiPanel as on Thingiverse //#define LCD_FEEDBACK_FREQUENCY_HZ 1000 // this is the tone frequency the buzzer plays when on UI feedback. ie Screen Click //#define LCD_FEEDBACK_FREQUENCY_DURATION_MS 100 // the duration the buzzer plays the UI feedback sound. ie Screen Click @@ -578,7 +578,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of // https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/schematics#!shiftregister-connection //#define SR_LCD #ifdef SR_LCD - #define SR_LCD_2W_NL // Non latching 2 wire shiftregister + #define SR_LCD_2W_NL // Non latching 2 wire shift register //#define NEWPANEL #endif @@ -594,7 +594,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #define LCD_WIDTH 20 #define LCD_HEIGHT 4 #endif -#else //no panel but just lcd +#else //no panel but just LCD #ifdef ULTRA_LCD #ifdef DOGLCD // Change number of lines to match the 128x64 graphics display #define LCD_WIDTH 20 @@ -616,8 +616,8 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of // Increase the FAN pwm frequency. Removes the PWM noise but increases heating in the FET/Arduino //#define FAST_PWM_FAN -// Temperature status leds that display the hotend and bet temperature. -// If alle hotends and bed temperature and temperature setpoint are < 54C then the BLUE led is on. +// Temperature status LEDs that display the hotend and bet temperature. +// If all hotends and bed temperature and temperature setpoint are < 54C then the BLUE led is on. // Otherwise the RED led is on. There is 1C hysteresis. //#define TEMP_STAT_LEDS diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index dc986fae4a..67cbfcc80f 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -11,7 +11,7 @@ #define BED_CHECK_INTERVAL 5000 //ms between checks in bang-bang control //// Heating sanity check: -// This waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature +// This waits for the watch period in milliseconds whenever an M104 or M109 increases the target temperature // If the temperature has not increased at the end of that period, the target temperature is set to zero. // It can be reset with another M104/M109. This check is also only triggered if the target temperature and the current temperature // differ by at least 2x WATCH_TEMP_INCREASE @@ -19,11 +19,11 @@ //#define WATCH_TEMP_INCREASE 10 //Heat up at least 10 degree in 20 seconds #ifdef PIDTEMP - // this adds an experimental additional term to the heatingpower, proportional to the extrusion speed. - // if Kc is choosen well, the additional required power due to increased melting should be compensated. + // this adds an experimental additional term to the heating power, proportional to the extrusion speed. + // if Kc is chosen well, the additional required power due to increased melting should be compensated. #define PID_ADD_EXTRUSION_RATE #ifdef PID_ADD_EXTRUSION_RATE - #define DEFAULT_Kc (1) //heatingpower=Kc*(e_speed) + #define DEFAULT_Kc (1) //heating power=Kc*(e_speed) #endif #endif @@ -34,7 +34,7 @@ // the target temperature is set to mintemp+factor*se[steps/sec] and limited by mintemp and maxtemp // you exit the value by any M109 without F* // Also, if the temperature is set to a value Date: Sun, 16 Feb 2014 00:47:06 +1300 Subject: [PATCH 156/256] Updated gen3+ board pins names to current convention --- Marlin/pins.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Marlin/pins.h b/Marlin/pins.h index 995fa54c5f..9976d431d0 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -1781,8 +1781,8 @@ #define Z_DIR_PIN 28 #define Z_STOP_PIN 30 -#define E_STEP_PIN 17 -#define E_DIR_PIN 21 +#define E0_STEP_PIN 17 +#define E0_DIR_PIN 21 #define LED_PIN -1 @@ -1793,15 +1793,16 @@ #define HEATER_0_PIN 12 // (extruder) -#define HEATER_1_PIN 16 // (bed) +#define HEATER_BED_PIN 16 // (bed) #define X_ENABLE_PIN 19 #define Y_ENABLE_PIN 24 #define Z_ENABLE_PIN 29 -#define E_ENABLE_PIN 13 +#define E0_ENABLE_PIN 13 #define TEMP_0_PIN 0 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! (pin 33 extruder) -#define TEMP_1_PIN 5 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! (pin 34 bed) +#define TEMP_1_PIN -1 #define TEMP_2_PIN -1 +#define TEMP_BED_PIN 5 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! (pin 34 bed) #define SDPOWER -1 #define SDSS 4 #define HEATER_2_PIN -1 From ad2c6488c7720e83febce85c43e711b83a2ca8c6 Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Sun, 16 Feb 2014 10:38:29 -0800 Subject: [PATCH 157/256] Add probe_pt(), useful for auto bed leveling --- Marlin/Marlin_main.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 7c7a0b0442..5152dc9532 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -978,6 +978,27 @@ static void retract_z_probe() { #endif } +/// Probe bed height at position (x,y), returns the measured z value +static float probe_pt(float x, float y, float z_before) { + // move to right place + do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], z_before); + do_blocking_move_to(x - X_PROBE_OFFSET_FROM_EXTRUDER, y - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]); + + engage_z_probe(); // Engage Z Servo endstop if available + run_z_probe(); + float measured_z = current_position[Z_AXIS]; + retract_z_probe(); + + SERIAL_PROTOCOLPGM("Bed x: "); + SERIAL_PROTOCOL(x); + SERIAL_PROTOCOLPGM(" y: "); + SERIAL_PROTOCOL(y); + SERIAL_PROTOCOLPGM(" z: "); + SERIAL_PROTOCOL(measured_z); + SERIAL_PROTOCOLPGM("\n"); + return measured_z; +} + #endif // #ifdef ENABLE_AUTO_BED_LEVELING static void homeaxis(int axis) { From c4fbb44d6d42b84137a89ab7aa5ab7143116184d Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Sun, 16 Feb 2014 10:40:36 -0800 Subject: [PATCH 158/256] Refactor 3-point auto bed leveling to use probe_pt() --- Marlin/Marlin_main.cpp | 49 +++--------------------------------------- 1 file changed, 3 insertions(+), 46 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 5152dc9532..783b6da76c 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1490,56 +1490,13 @@ void process_commands() // prob 1 - do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], Z_RAISE_BEFORE_PROBING); - do_blocking_move_to(LEFT_PROBE_BED_POSITION - X_PROBE_OFFSET_FROM_EXTRUDER, BACK_PROBE_BED_POSITION - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]); - - engage_z_probe(); // Engage Z Servo endstop if available - run_z_probe(); - float z_at_xLeft_yBack = current_position[Z_AXIS]; - retract_z_probe(); - - SERIAL_PROTOCOLPGM("Bed x: "); - SERIAL_PROTOCOL(LEFT_PROBE_BED_POSITION); - SERIAL_PROTOCOLPGM(" y: "); - SERIAL_PROTOCOL(BACK_PROBE_BED_POSITION); - SERIAL_PROTOCOLPGM(" z: "); - SERIAL_PROTOCOL(current_position[Z_AXIS]); - SERIAL_PROTOCOLPGM("\n"); + float z_at_xLeft_yBack = probe_pt(LEFT_PROBE_BED_POSITION, BACK_PROBE_BED_POSITION, Z_RAISE_BEFORE_PROBING); // prob 2 - do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); - do_blocking_move_to(LEFT_PROBE_BED_POSITION - X_PROBE_OFFSET_FROM_EXTRUDER, FRONT_PROBE_BED_POSITION - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]); - - engage_z_probe(); // Engage Z Servo endstop if available - run_z_probe(); - float z_at_xLeft_yFront = current_position[Z_AXIS]; - retract_z_probe(); - - SERIAL_PROTOCOLPGM("Bed x: "); - SERIAL_PROTOCOL(LEFT_PROBE_BED_POSITION); - SERIAL_PROTOCOLPGM(" y: "); - SERIAL_PROTOCOL(FRONT_PROBE_BED_POSITION); - SERIAL_PROTOCOLPGM(" z: "); - SERIAL_PROTOCOL(current_position[Z_AXIS]); - SERIAL_PROTOCOLPGM("\n"); + float z_at_xLeft_yFront = probe_pt(LEFT_PROBE_BED_POSITION, FRONT_PROBE_BED_POSITION, current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); // prob 3 - do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); - // the current position will be updated by the blocking move so the head will not lower on this next call. - do_blocking_move_to(RIGHT_PROBE_BED_POSITION - X_PROBE_OFFSET_FROM_EXTRUDER, FRONT_PROBE_BED_POSITION - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]); - - engage_z_probe(); // Engage Z Servo endstop if available - run_z_probe(); - float z_at_xRight_yFront = current_position[Z_AXIS]; - retract_z_probe(); // Retract Z Servo endstop if available - - SERIAL_PROTOCOLPGM("Bed x: "); - SERIAL_PROTOCOL(RIGHT_PROBE_BED_POSITION); - SERIAL_PROTOCOLPGM(" y: "); - SERIAL_PROTOCOL(FRONT_PROBE_BED_POSITION); - SERIAL_PROTOCOLPGM(" z: "); - SERIAL_PROTOCOL(current_position[Z_AXIS]); - SERIAL_PROTOCOLPGM("\n"); + float z_at_xRight_yFront = probe_pt(RIGHT_PROBE_BED_POSITION, FRONT_PROBE_BED_POSITION, current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); clean_up_after_endstop_move(); From 0f7393a13e44958ed60371936c0bd2f699d1a137 Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Sun, 16 Feb 2014 10:42:29 -0800 Subject: [PATCH 159/256] Refactor 'accurate' auto bed leveling to use probe_pt() --- Marlin/Marlin_main.cpp | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 783b6da76c..9032713750 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1436,31 +1436,20 @@ void process_commands() for (int xCount=0; xCount < ACCURATE_BED_LEVELING_POINTS; xCount++) { + float z_before; if (probePointCounter == 0) { // raise before probing - do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], Z_RAISE_BEFORE_PROBING); + z_before = Z_RAISE_BEFORE_PROBING; } else { // raise extruder - do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); + z_before = current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS; } + float measured_z = probe_pt(xProbe, yProbe, z_before); - do_blocking_move_to(xProbe - X_PROBE_OFFSET_FROM_EXTRUDER, yProbe - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]); - - engage_z_probe(); // Engage Z Servo endstop if available - run_z_probe(); - eqnBVector[probePointCounter] = current_position[Z_AXIS]; - retract_z_probe(); - - SERIAL_PROTOCOLPGM("Bed x: "); - SERIAL_PROTOCOL(xProbe); - SERIAL_PROTOCOLPGM(" y: "); - SERIAL_PROTOCOL(yProbe); - SERIAL_PROTOCOLPGM(" z: "); - SERIAL_PROTOCOL(current_position[Z_AXIS]); - SERIAL_PROTOCOLPGM("\n"); + eqnBVector[probePointCounter] = measured_z; eqnAMatrix[probePointCounter + 0*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = xProbe; eqnAMatrix[probePointCounter + 1*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = yProbe; From 8c5675c29060b5a4f826b2101ca2ff9ed1308d75 Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Sun, 16 Feb 2014 17:16:00 -0800 Subject: [PATCH 160/256] Use language.h instead of English literals for "bed" --- Marlin/Marlin_main.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 9032713750..2b8138f093 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -989,7 +989,8 @@ static float probe_pt(float x, float y, float z_before) { float measured_z = current_position[Z_AXIS]; retract_z_probe(); - SERIAL_PROTOCOLPGM("Bed x: "); + SERIAL_PROTOCOLPGM(MSG_BED); + SERIAL_PROTOCOLPGM(" x: "); SERIAL_PROTOCOL(x); SERIAL_PROTOCOLPGM(" y: "); SERIAL_PROTOCOL(y); @@ -1520,7 +1521,8 @@ void process_commands() feedrate = homing_feedrate[Z_AXIS]; run_z_probe(); - SERIAL_PROTOCOLPGM("Bed Position X: "); + SERIAL_PROTOCOLPGM(MSG_BED); + SERIAL_PROTOCOLPGM(" X: "); SERIAL_PROTOCOL(current_position[X_AXIS]); SERIAL_PROTOCOLPGM(" Y: "); SERIAL_PROTOCOL(current_position[Y_AXIS]); From 2f2459c0db59bb9cf009101c57a0c65550f41b7d Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Sun, 16 Feb 2014 15:53:01 -0800 Subject: [PATCH 161/256] Fix G10/G11 Z-lift --- Marlin/Marlin_main.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 9032713750..1681c88b70 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1134,7 +1134,6 @@ void process_commands() destination[X_AXIS]=current_position[X_AXIS]; destination[Y_AXIS]=current_position[Y_AXIS]; destination[Z_AXIS]=current_position[Z_AXIS]; - current_position[Z_AXIS]-=retract_zlift; destination[E_AXIS]=current_position[E_AXIS]; current_position[E_AXIS]+=retract_length/volumetric_multiplier[active_extruder]; plan_set_e_position(current_position[E_AXIS]); @@ -1142,6 +1141,9 @@ void process_commands() feedrate=retract_feedrate; retracted=true; prepare_move(); + current_position[Z_AXIS]-=retract_zlift; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + prepare_move(); feedrate = oldFeedrate; } @@ -1152,8 +1154,10 @@ void process_commands() destination[X_AXIS]=current_position[X_AXIS]; destination[Y_AXIS]=current_position[Y_AXIS]; destination[Z_AXIS]=current_position[Z_AXIS]; - current_position[Z_AXIS]+=retract_zlift; destination[E_AXIS]=current_position[E_AXIS]; + current_position[Z_AXIS]+=retract_zlift; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + //prepare_move(); current_position[E_AXIS]-=(retract_length+retract_recover_length)/volumetric_multiplier[active_extruder]; plan_set_e_position(current_position[E_AXIS]); float oldFeedrate = feedrate; From 66e386913897d9f45762e227161d53e8323b1c5b Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Sun, 16 Feb 2014 18:59:04 -0800 Subject: [PATCH 162/256] Fix autoretract This takes the (now working) G10/G11 code and moves it to a function, which is called by G10 and G11, and also called by G1 if autoretract is enabled and a retract/recover move is detected. --- Marlin/Marlin_main.cpp | 120 +++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 71 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 1681c88b70..c07cbc4271 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1080,6 +1080,41 @@ static void homeaxis(int axis) { } #define HOMEAXIS(LETTER) homeaxis(LETTER##_AXIS) +#ifdef FWRETRACT + void retract(bool retracting) { + if(retracting && !retracted) { + destination[X_AXIS]=current_position[X_AXIS]; + destination[Y_AXIS]=current_position[Y_AXIS]; + destination[Z_AXIS]=current_position[Z_AXIS]; + destination[E_AXIS]=current_position[E_AXIS]; + current_position[E_AXIS]+=retract_length/volumetric_multiplier[active_extruder]; + plan_set_e_position(current_position[E_AXIS]); + float oldFeedrate = feedrate; + feedrate=retract_feedrate; + retracted=true; + prepare_move(); + current_position[Z_AXIS]-=retract_zlift; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + prepare_move(); + feedrate = oldFeedrate; + } else if(!retracting && retracted) { + destination[X_AXIS]=current_position[X_AXIS]; + destination[Y_AXIS]=current_position[Y_AXIS]; + destination[Z_AXIS]=current_position[Z_AXIS]; + destination[E_AXIS]=current_position[E_AXIS]; + current_position[Z_AXIS]+=retract_zlift; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + //prepare_move(); + current_position[E_AXIS]-=(retract_length+retract_recover_length)/volumetric_multiplier[active_extruder]; + plan_set_e_position(current_position[E_AXIS]); + float oldFeedrate = feedrate; + feedrate=retract_recover_feedrate; + retracted=false; + prepare_move(); + feedrate = oldFeedrate; + } + } //retract +#endif //FWRETRACT void process_commands() { unsigned long codenum; //throw away variable @@ -1095,6 +1130,18 @@ void process_commands() case 1: // G1 if(Stopped == false) { get_coordinates(); // For X Y Z E F + #ifdef FWRETRACT + if(autoretract_enabled) + if( !(code_seen(X_AXIS) || code_seen(Y_AXIS) || code_seen(Z_AXIS)) && code_seen(E_AXIS)) { + float echange=destination[E_AXIS]-current_position[E_AXIS]; + if((echange<-MIN_RETRACT && !retracted) || (echange>MIN_RETRACT && retracted)) { //move appears to be an attempt to attract or recover + current_position[E_AXIS] = destination[E_AXIS]; //hide the slicer-generated retract/recover from calculations + plan_set_e_position(current_position[E_AXIS]); //AND from the planner + retract(!retracted); + return; + } + } + #endif //FWRETRACT prepare_move(); //ClearToSend(); return; @@ -1129,43 +1176,10 @@ void process_commands() break; #ifdef FWRETRACT case 10: // G10 retract - if(!retracted) - { - destination[X_AXIS]=current_position[X_AXIS]; - destination[Y_AXIS]=current_position[Y_AXIS]; - destination[Z_AXIS]=current_position[Z_AXIS]; - destination[E_AXIS]=current_position[E_AXIS]; - current_position[E_AXIS]+=retract_length/volumetric_multiplier[active_extruder]; - plan_set_e_position(current_position[E_AXIS]); - float oldFeedrate = feedrate; - feedrate=retract_feedrate; - retracted=true; - prepare_move(); - current_position[Z_AXIS]-=retract_zlift; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - prepare_move(); - feedrate = oldFeedrate; - } - + retract(true); break; case 11: // G11 retract_recover - if(retracted) - { - destination[X_AXIS]=current_position[X_AXIS]; - destination[Y_AXIS]=current_position[Y_AXIS]; - destination[Z_AXIS]=current_position[Z_AXIS]; - destination[E_AXIS]=current_position[E_AXIS]; - current_position[Z_AXIS]+=retract_zlift; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - //prepare_move(); - current_position[E_AXIS]-=(retract_length+retract_recover_length)/volumetric_multiplier[active_extruder]; - plan_set_e_position(current_position[E_AXIS]); - float oldFeedrate = feedrate; - feedrate=retract_recover_feedrate; - retracted=false; - prepare_move(); - feedrate = oldFeedrate; - } + retract(false); break; #endif //FWRETRACT case 28: //G28 Home all Axis one at a time @@ -3020,42 +3034,6 @@ void get_coordinates() next_feedrate = code_value(); if(next_feedrate > 0.0) feedrate = next_feedrate; } - #ifdef FWRETRACT - if(autoretract_enabled) - if( !(seen[X_AXIS] || seen[Y_AXIS] || seen[Z_AXIS]) && seen[E_AXIS]) - { - float echange=destination[E_AXIS]-current_position[E_AXIS]; - if(echange<-MIN_RETRACT) //retract - { - if(!retracted) - { - - destination[Z_AXIS]+=retract_zlift; //not sure why chaninging current_position negatively does not work. - //if slicer retracted by echange=-1mm and you want to retract 3mm, corrrectede=-2mm additionally - float correctede=-echange-retract_length; - //to generate the additional steps, not the destination is changed, but inversely the current position - current_position[E_AXIS]+=-correctede; - feedrate=retract_feedrate; - retracted=true; - } - - } - else - if(echange>MIN_RETRACT) //retract_recover - { - if(retracted) - { - //current_position[Z_AXIS]+=-retract_zlift; - //if slicer retracted_recovered by echange=+1mm and you want to retract_recover 3mm, corrrectede=2mm additionally - float correctede=-echange+1*retract_length+retract_recover_length; //total unretract=retract_length+retract_recover_length[surplus] - current_position[E_AXIS]+=correctede; //to generate the additional steps, not the destination is changed, but inversely the current position - feedrate=retract_recover_feedrate; - retracted=false; - } - } - - } - #endif //FWRETRACT } void get_arc_coordinates() From 99f0e44864a248e3487a4e3d9aad5a5f07f3d447 Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Sun, 16 Feb 2014 19:00:28 -0800 Subject: [PATCH 163/256] Move FWRETRACT defaults to configuration_adv.h --- Marlin/Configuration_adv.h | 10 ++++++++-- Marlin/Marlin_main.cpp | 8 ++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index dc986fae4a..aed27c0796 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -399,8 +399,14 @@ const unsigned int dropsegments=5; //everything with less than this number of st // the moves are than replaced by the firmware controlled ones. // #define FWRETRACT //ONLY PARTIALLY TESTED -#define MIN_RETRACT 0.1 //minimum extruded mm to accept a automatic gcode retraction attempt - +#ifdef FWRETRACT + #define MIN_RETRACT 0.1 //minimum extruded mm to accept a automatic gcode retraction attempt + #define RETRACT_LENGTH 3 //default retract length (positive mm) + #define RETRACT_FEEDRATE 80*60 //default feedrate for retracting + #define RETRACT_ZLIFT 0 //default retract Z-lift + #define RETRACT_RECOVER_LENGTH 0 //default additional recover length (mm, added to retract length when recovering) + #define RETRACT_RECOVER_FEEDRATE 8*60 //default feedrate for recovering from retraction +#endif //adds support for experimental filament exchange support M600; requires display #ifdef ULTIPANEL diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index c07cbc4271..e860d7d254 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -233,8 +233,11 @@ int EtoPPressure=0; #ifdef FWRETRACT bool autoretract_enabled=true; bool retracted=false; - float retract_length=3, retract_feedrate=17*60, retract_zlift=0.8; - float retract_recover_length=0, retract_recover_feedrate=8*60; + float retract_length = RETRACT_LENGTH; + float retract_feedrate = RETRACT_FEEDRATE; + float retract_zlift = RETRACT_ZLIFT; + float retract_recover_length = RETRACT_RECOVER_LENGTH; + float retract_recover_feedrate = RETRACT_RECOVER_FEEDRATE; #endif #ifdef ULTIPANEL @@ -1115,6 +1118,7 @@ static void homeaxis(int axis) { } } //retract #endif //FWRETRACT + void process_commands() { unsigned long codenum; //throw away variable From c43838bb1ee4f787c637f4fc0b91aa4b78e4f56a Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Sun, 16 Feb 2014 19:04:54 -0800 Subject: [PATCH 164/256] disable auto retract by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should make it safe to enable FWRETRACT by default, with autoretract (which should now be fixed) only enabled by M209. FWRETRACT should probably now default to enabled (to make G10/G11 and M207-209 available, without changing functionality when they are not used), but I’ll save that for another pull request/discussion. --- Marlin/Marlin_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index e860d7d254..4e9fed10ef 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -231,7 +231,7 @@ int EtoPPressure=0; #endif #ifdef FWRETRACT - bool autoretract_enabled=true; + bool autoretract_enabled=false; bool retracted=false; float retract_length = RETRACT_LENGTH; float retract_feedrate = RETRACT_FEEDRATE; From 306588925df929d843bb25fbfb93695e5a1f4afe Mon Sep 17 00:00:00 2001 From: Paul Telford Date: Sun, 16 Feb 2014 21:01:19 -0800 Subject: [PATCH 165/256] Add whitespace to M114 output --- Marlin/Marlin_main.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 9032713750..2ae569828e 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -2122,18 +2122,18 @@ void process_commands() case 114: // M114 SERIAL_PROTOCOLPGM("X:"); SERIAL_PROTOCOL(current_position[X_AXIS]); - SERIAL_PROTOCOLPGM("Y:"); + SERIAL_PROTOCOLPGM(" Y:"); SERIAL_PROTOCOL(current_position[Y_AXIS]); - SERIAL_PROTOCOLPGM("Z:"); + SERIAL_PROTOCOLPGM(" Z:"); SERIAL_PROTOCOL(current_position[Z_AXIS]); - SERIAL_PROTOCOLPGM("E:"); + SERIAL_PROTOCOLPGM(" E:"); SERIAL_PROTOCOL(current_position[E_AXIS]); SERIAL_PROTOCOLPGM(MSG_COUNT_X); SERIAL_PROTOCOL(float(st_get_position(X_AXIS))/axis_steps_per_unit[X_AXIS]); - SERIAL_PROTOCOLPGM("Y:"); + SERIAL_PROTOCOLPGM(" Y:"); SERIAL_PROTOCOL(float(st_get_position(Y_AXIS))/axis_steps_per_unit[Y_AXIS]); - SERIAL_PROTOCOLPGM("Z:"); + SERIAL_PROTOCOLPGM(" Z:"); SERIAL_PROTOCOL(float(st_get_position(Z_AXIS))/axis_steps_per_unit[Z_AXIS]); SERIAL_PROTOCOLLN(""); From b45beeffd6b8b2ca980cf61636ccb7b075d3ebd1 Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Sun, 16 Feb 2014 23:21:53 -0800 Subject: [PATCH 166/256] typo fix in Makefile --- Marlin/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Makefile b/Marlin/Makefile index 9c26c3cc0a..a4de46a64e 100644 --- a/Marlin/Makefile +++ b/Marlin/Makefile @@ -236,7 +236,7 @@ VPATH += $(HARDWARE_DIR)/libraries/Wire VPATH += $(HARDWARE_DIR)/libraries/Wire/utility VPATH += $(HARDWARE_DIR)/libraries/LiquidTWI2 endif -ifeq ($(WIRE, 1) +ifeq ($(WIRE), 1) VPATH += $(HARDWARE_DIR)/libraries/Wire VPATH += $(HARDWARE_DIR)/libraries/Wire/utility endif From 5bd09d26e2d3cf310182c246129dfb7eb2718d17 Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Sun, 16 Feb 2014 23:19:08 -0800 Subject: [PATCH 167/256] Makefile works with auto bed leveling --- Marlin/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Marlin/Makefile b/Marlin/Makefile index a4de46a64e..3bd0ae3bf4 100644 --- a/Marlin/Makefile +++ b/Marlin/Makefile @@ -260,7 +260,8 @@ CXXSRC = WMath.cpp WString.cpp Print.cpp Marlin_main.cpp \ MarlinSerial.cpp Sd2Card.cpp SdBaseFile.cpp SdFatUtil.cpp \ SdFile.cpp SdVolume.cpp motion_control.cpp planner.cpp \ stepper.cpp temperature.cpp cardreader.cpp ConfigurationStore.cpp \ - watchdog.cpp SPI.cpp Servo.cpp Tone.cpp ultralcd.cpp digipot_mcp4451.cpp + watchdog.cpp SPI.cpp Servo.cpp Tone.cpp ultralcd.cpp digipot_mcp4451.cpp \ + vector_3.cpp qr_solve.cpp ifeq ($(LIQUID_TWI2), 0) CXXSRC += LiquidCrystal.cpp else From 8f0cee2a14a9f28e4fd9e8ac7784a7700cd83940 Mon Sep 17 00:00:00 2001 From: Cylindric Date: Mon, 17 Feb 2014 10:58:36 +0000 Subject: [PATCH 168/256] Various typo fixes - only in comments, no code changes. --- Marlin/LiquidCrystalRus.cpp | 10 +++++----- Marlin/MarlinSerial.cpp | 4 ++-- Marlin/cardreader.cpp | 6 +++--- Marlin/ultralcd_st7920_u8glib_rrd.h | 8 ++++---- Marlin/watchdog.h | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Marlin/LiquidCrystalRus.cpp b/Marlin/LiquidCrystalRus.cpp index c193e449db..6ee2c112e9 100644 --- a/Marlin/LiquidCrystalRus.cpp +++ b/Marlin/LiquidCrystalRus.cpp @@ -11,7 +11,7 @@ #include "WProgram.h" #endif -// it is a russian alphabet translation +// it is a Russian alphabet translation // except 0401 --> 0xa2 = ╗, 0451 --> 0xb5 const PROGMEM uint8_t utf_recode[] = { 0x41,0xa0,0x42,0xa1,0xe0,0x45,0xa3,0xa4,0xa5,0xa6,0x4b,0xa7,0x4d,0x48,0x4f, @@ -115,7 +115,7 @@ void LiquidCrystalRus::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! // according to datasheet, we need at least 40ms after power rises above 2.7V - // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50 + // before sending commands. Arduino can turn on way before 4.5V so we'll wait 50 delayMicroseconds(50000); // Now we pull both RS and R/W low to begin commands digitalWrite(_rs_pin, LOW); @@ -126,7 +126,7 @@ void LiquidCrystalRus::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { //put the LCD into 4 bit or 8 bit mode if (! (_displayfunction & LCD_8BITMODE)) { - // this is according to the hitachi HD44780 datasheet + // this is according to the Hitachi HD44780 datasheet // figure 24, pg 46 // we start in 8bit mode, try to set 4 bit mode @@ -144,7 +144,7 @@ void LiquidCrystalRus::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { // finally, set to 8-bit interface writeNbits(0x02,4); } else { - // this is according to the hitachi HD44780 datasheet + // this is according to the Hitachi HD44780 datasheet // page 45 figure 23 // Send function set command sequence @@ -308,7 +308,7 @@ inline void LiquidCrystalRus::command(uint8_t value) { } } else send(out_char, HIGH); #if defined(ARDUINO) && ARDUINO >= 100 - return 1; // assume sucess + return 1; // assume success #endif } diff --git a/Marlin/MarlinSerial.cpp b/Marlin/MarlinSerial.cpp index 0433df2d32..a7251dd6a2 100644 --- a/Marlin/MarlinSerial.cpp +++ b/Marlin/MarlinSerial.cpp @@ -25,7 +25,7 @@ #ifndef AT90USB // this next line disables the entire HardwareSerial.cpp, -// this is so I can support Attiny series and any other chip without a uart +// this is so I can support Attiny series and any other chip without a UART #if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H) #if UART_PRESENT(SERIAL_PORT) @@ -73,7 +73,7 @@ void MarlinSerial::begin(long baud) bool useU2X = true; #if F_CPU == 16000000UL && SERIAL_PORT == 0 - // hardcoded exception for compatibility with the bootloader shipped + // hard coded exception for compatibility with the bootloader shipped // with the Duemilanove and previous boards and the firmware on the 8U2 // on the Uno and Mega 2560. if (baud == 57600) { diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index e5c3108961..5fb8dcc0ff 100644 --- a/Marlin/cardreader.cpp +++ b/Marlin/cardreader.cpp @@ -22,7 +22,7 @@ CardReader::CardReader() file_subcall_ctr=0; memset(workDirParents, 0, sizeof(workDirParents)); - autostart_stilltocheck=true; //the sd start is delayed, because otherwise the serial cannot answer fast enought to make contact with the hostsoftware. + autostart_stilltocheck=true; //the SD start is delayed, because otherwise the serial cannot answer fast enough to make contact with the host software. lastnr=0; //power to SD reader #if SDPOWER > -1 @@ -245,7 +245,7 @@ void CardReader::openFile(char* name,bool read, bool replace_current/*=true*/) { if(!cardOK) return; - if(file.isOpen()) //replaceing current file by new file, or subfile call + if(file.isOpen()) //replacing current file by new file, or subfile call { if(!replace_current) { @@ -544,7 +544,7 @@ void CardReader::closefile(bool store_location) if(store_location) { - //future: store printer state, filename and position for continueing a stoped print + //future: store printer state, filename and position for continuing a stopped print // so one can unplug the printer and continue printing the next day. } diff --git a/Marlin/ultralcd_st7920_u8glib_rrd.h b/Marlin/ultralcd_st7920_u8glib_rrd.h index e198a858ac..386e312e5b 100644 --- a/Marlin/ultralcd_st7920_u8glib_rrd.h +++ b/Marlin/ultralcd_st7920_u8glib_rrd.h @@ -12,8 +12,8 @@ #define ST7920_DAT_PIN LCD_PINS_ENABLE #define ST7920_CS_PIN LCD_PINS_RS -//#define PAGE_HEIGHT 8 //128 byte frambuffer -//#define PAGE_HEIGHT 16 //256 byte frambuffer +//#define PAGE_HEIGHT 8 //128 byte framebuffer +//#define PAGE_HEIGHT 16 //256 byte framebuffer #define PAGE_HEIGHT 32 //512 byte framebuffer #define WIDTH 128 @@ -59,8 +59,8 @@ uint8_t u8g_dev_rrd_st7920_128x64_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, vo ST7920_SET_CMD(); ST7920_WRITE_BYTE(0x08); //display off, cursor+blink off ST7920_WRITE_BYTE(0x01); //clear CGRAM ram - u8g_Delay(10); //delay for cgram clear - ST7920_WRITE_BYTE(0x3E); //extended mode + gdram active + u8g_Delay(10); //delay for CGRAM clear + ST7920_WRITE_BYTE(0x3E); //extended mode + GDRAM active for(y=0;y Date: Mon, 17 Feb 2014 13:04:44 +0000 Subject: [PATCH 169/256] Various typo fixes - only in comments, no code changes. --- Marlin/ultralcd.cpp | 26 +++++++++---------- Marlin/ultralcd.h | 8 +++--- .../ultralcd_implementation_hitachi_HD44780.h | 12 ++++----- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 8961b67e1c..3262f2d245 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -38,7 +38,7 @@ char lcd_status_message[LCD_WIDTH+1] = WELCOME_MSG; #include "ultralcd_implementation_hitachi_HD44780.h" #endif -/** forward declerations **/ +/** forward declarations **/ void copy_and_scalePID_i(); void copy_and_scalePID_d(); @@ -62,9 +62,9 @@ static void lcd_set_contrast(); static void lcd_control_retract_menu(); static void lcd_sdcard_menu(); -static void lcd_quick_feedback();//Cause an LCD refresh, and give the user visual or audiable feedback that something has happend +static void lcd_quick_feedback();//Cause an LCD refresh, and give the user visual or audible feedback that something has happened -/* Different types of actions that can be used in menuitems. */ +/* 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); @@ -145,7 +145,7 @@ static void menu_action_setting_edit_callback_long5(const char* pstr, unsigned l #ifndef REPRAPWORLD_KEYPAD volatile uint8_t buttons;//Contains the bits of the currently pressed buttons. #else -volatile uint8_t buttons_reprapworld_keypad; // to store the reprapworld_keypad shiftregister values +volatile uint8_t buttons_reprapworld_keypad; // to store the reprapworld_keypad shift register values #endif #ifdef LCD_HAS_SLOW_BUTTONS volatile uint8_t slow_buttons;//Contains the bits of the currently pressed buttons. @@ -162,7 +162,7 @@ bool lcd_oldcardstatus; menuFunc_t currentMenu = lcd_status_screen; /* function pointer to the currently active menu */ uint32_t lcd_next_update_millis; uint8_t lcd_status_update_delay; -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 atleast 1 full redraw (first redraw is partial) */ +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; @@ -173,10 +173,10 @@ void* editValue; int32_t minEditValue, maxEditValue; menuFunc_t callbackFunc; -// placeholders for Ki and Kd edits +// place-holders for Ki and Kd edits float raw_Ki, raw_Kd; -/* Main status screen. It's up to the implementation specific part to show what is needed. As this is very display dependend */ +/* Main status screen. It's up to the implementation specific part to show what is needed. As this is very display dependent */ static void lcd_status_screen() { if (lcd_status_update_delay) @@ -708,9 +708,9 @@ static void lcd_control_temperature_preheat_abs_settings_menu() static void lcd_control_motion_menu() { START_MENU(); - MENU_ITEM(back, MSG_CONTROL, lcd_control_menu); + MENU_ITEM(back, MSG_CONTROL, lcd_control_menu); #ifdef ENABLE_AUTO_BED_LEVELING - MENU_ITEM_EDIT(float32, MSG_ZPROBE_ZOFFSET, &zprobe_zoffset, 0.5, 50); + MENU_ITEM_EDIT(float32, MSG_ZPROBE_ZOFFSET, &zprobe_zoffset, 0.5, 50); #endif MENU_ITEM_EDIT(float5, MSG_ACC, &acceleration, 500, 99000); MENU_ITEM_EDIT(float3, MSG_VXY_JERK, &max_xy_jerk, 1, 990); @@ -1008,7 +1008,7 @@ void lcd_init() WRITE(SHIFT_LD,HIGH); #endif #else // Not NEWPANEL - #ifdef SR_LCD_2W_NL // Non latching 2 wire shiftregister + #ifdef SR_LCD_2W_NL // Non latching 2 wire shift register pinMode (SR_DATA_PIN, OUTPUT); pinMode (SR_CLK_PIN, OUTPUT); #elif defined(SHIFT_CLK) @@ -1055,7 +1055,7 @@ void lcd_update() { lcdDrawUpdate = 2; lcd_oldcardstatus = IS_SD_INSERTED; - lcd_implementation_init(); // to maybe revive the lcd if static electricty killed it. + lcd_implementation_init(); // to maybe revive the LCD if static electricity killed it. if(lcd_oldcardstatus) { @@ -1470,7 +1470,7 @@ char *ftostr52(const float &x) } // Callback for after editing PID i value -// grab the pid i value out of the temp variable; scale it; then update the PID driver +// grab the PID i value out of the temp variable; scale it; then update the PID driver void copy_and_scalePID_i() { #ifdef PIDTEMP @@ -1480,7 +1480,7 @@ void copy_and_scalePID_i() } // Callback for after editing PID d value -// grab the pid d value out of the temp variable; scale it; then update the PID driver +// grab the PID d value out of the temp variable; scale it; then update the PID driver void copy_and_scalePID_d() { #ifdef PIDTEMP diff --git a/Marlin/ultralcd.h b/Marlin/ultralcd.h index d6fa0fdcfe..f4570f6a58 100644 --- a/Marlin/ultralcd.h +++ b/Marlin/ultralcd.h @@ -17,7 +17,7 @@ void lcd_setcontrast(uint8_t value); #endif - static unsigned char blink = 0; // Variable for visualisation of fan rotation in GLCD + static unsigned char blink = 0; // Variable for visualization of fan rotation in GLCD #define LCD_MESSAGEPGM(x) lcd_setstatuspgm(PSTR(x)) #define LCD_ALERTMESSAGEPGM(x) lcd_setalertstatuspgm(PSTR(x)) @@ -29,7 +29,7 @@ void lcd_buttons_update(); extern volatile uint8_t buttons; //the last checked buttons in a bit array. #ifdef REPRAPWORLD_KEYPAD - extern volatile uint8_t buttons_reprapworld_keypad; // to store the keypad shiftregister values + extern volatile uint8_t buttons_reprapworld_keypad; // to store the keypad shift register values #endif #else FORCE_INLINE void lcd_buttons_update() {} @@ -72,7 +72,7 @@ #define REPRAPWORLD_KEYPAD_MOVE_HOME (buttons_reprapworld_keypad&EN_REPRAPWORLD_KEYPAD_MIDDLE) #endif //REPRAPWORLD_KEYPAD #else - //atomatic, do not change + //atomic, do not change #define B_LE (1< Date: Mon, 17 Feb 2014 07:53:45 -0800 Subject: [PATCH 170/256] Fix syntax error introduced in 477b6fa1d --- Marlin/Marlin_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 498adfdb95..952ac5847b 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1080,7 +1080,7 @@ static void homeaxis(int axis) { } } #define HOMEAXIS(LETTER) homeaxis(LETTER##_AXIS) -+void refresh_cmd_timeout(void) +void refresh_cmd_timeout(void) { previous_millis_cmd = millis(); } From cf5c3b6610ae747a7f1db1806c221f127827d4af Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 17 Feb 2014 17:00:50 +0100 Subject: [PATCH 171/256] Added dutch to language.h --- Marlin/language.h | 182 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) diff --git a/Marlin/language.h b/Marlin/language.h index 2126f7fb5f..3560412374 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -17,6 +17,7 @@ // 8 Portuguese // 9 Finnish // 10 Aragonese +// 11 Dutch #ifndef LANGUAGE_CHOICE #define LANGUAGE_CHOICE 1 // Pick your language from the list above @@ -1918,4 +1919,185 @@ #endif +#if LANGUAGE_CHOICE == 11 //Dutch + +// LCD Menu Messages +// Please note these are limited to 17 characters! + + #define WELCOME_MSG MACHINE_NAME " gereed." + #define MSG_SD_INSERTED "Kaart ingestoken" + #define MSG_SD_REMOVED "Kaart verwijderd" + #define MSG_MAIN "Main" + #define MSG_AUTOSTART "Autostart" + #define MSG_DISABLE_STEPPERS "Motoren uit" + #define MSG_AUTO_HOME "Auto home" + #define MSG_SET_ORIGIN "Nulpunt instellen" + #define MSG_PREHEAT_PLA "PLA voorverwarmen" + #define MSG_PREHEAT_PLA_SETTINGS "PLA voorverw. conf" + #define MSG_PREHEAT_ABS "ABS voorverwarmen" + #define MSG_PREHEAT_ABS_SETTINGS "ABS voorverw. conf" + #define MSG_COOLDOWN "Afkoelen" + #define MSG_SWITCH_PS_ON "Stroom aan" + #define MSG_SWITCH_PS_OFF "Stroom uit" + #define MSG_EXTRUDE "Extrude" + #define MSG_RETRACT "Retract" + #define MSG_MOVE_AXIS "As verplaatsen" + #define MSG_MOVE_X "Verplaats X" + #define MSG_MOVE_Y "Verplaats Y" + #define MSG_MOVE_Z "Verplaats Z" + #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_01MM "Verplaats 0.1mm" + #define MSG_MOVE_1MM "Verplaats 1mm" + #define MSG_MOVE_10MM "Verplaats 10mm" + #define MSG_SPEED "Snelheid" + #define MSG_NOZZLE "Nozzle" + #define MSG_NOZZLE1 "Nozzle2" + #define MSG_NOZZLE2 "Nozzle3" + #define MSG_BED "Bed" + #define MSG_FAN_SPEED "Fan snelheid" + #define MSG_FLOW "Flow" + #define MSG_CONTROL "Control" + #define MSG_MIN " \002 Min" + #define MSG_MAX " \002 Max" + #define MSG_FACTOR " \002 Fact" + #define MSG_AUTOTEMP "Autotemp" + #define MSG_ON "Aan " + #define MSG_OFF "Uit" + #define MSG_PID_P "PID-P" + #define MSG_PID_I "PID-I" + #define MSG_PID_D "PID-D" + #define MSG_PID_C "PID-C" + #define MSG_ACC "Versn" + #define MSG_VXY_JERK "Vxy-jerk" + #define MSG_VZ_JERK "Vz-jerk" + #define MSG_VE_JERK "Ve-jerk" + #define MSG_VMAX "Vmax " + #define MSG_X "x" + #define MSG_Y "y" + #define MSG_Z "z" + #define MSG_E "e" + #define MSG_VMIN "Vmin" + #define MSG_VTRAV_MIN "VTrav min" + #define MSG_AMAX "Amax " + #define MSG_A_RETRACT "A-retract" + #define MSG_XSTEPS "Xsteps/mm" + #define MSG_YSTEPS "Ysteps/mm" + #define MSG_ZSTEPS "Zsteps/mm" + #define MSG_ESTEPS "Esteps/mm" + #define MSG_RECTRACT "Rectract" + #define MSG_TEMPERATURE "Temperatuur" + #define MSG_MOTION "Beweging" + #define MSG_CONTRAST "LCD contrast" + #define MSG_STORE_EPROM "Geheugen opslaan" + #define MSG_LOAD_EPROM "Geheugen laden" + #define MSG_RESTORE_FAILSAFE "Noodstop reset" + #define MSG_REFRESH "Ververs" + #define MSG_WATCH "Info scherm" + #define MSG_PREPARE "Voorbereiden" + #define MSG_TUNE "Afstellen" + #define MSG_PAUSE_PRINT "Print pauzeren" + #define MSG_RESUME_PRINT "Print hervatten" + #define MSG_STOP_PRINT "Print stoppen" + #define MSG_CARD_MENU "Print van SD" + #define MSG_NO_CARD "Geen SD kaart" + #define MSG_DWELL "Slapen..." + #define MSG_USERWAIT "Wachten..." + #define MSG_RESUMING "Print hervatten" + #define MSG_NO_MOVE "Geen beweging." + #define MSG_KILLED "AFGEBROKEN. " + #define MSG_STOPPED "GESTOPT. " + #define MSG_CONTROL_RETRACT "Retract mm" + #define MSG_CONTROL_RETRACTF "Retract F" + #define MSG_CONTROL_RETRACT_ZLIFT "Hop mm" + #define MSG_CONTROL_RETRACT_RECOVER "UnRet +mm" + #define MSG_CONTROL_RETRACT_RECOVERF "UnRet F" + #define MSG_AUTORETRACT "AutoRetr." + #define MSG_FILAMENTCHANGE "Verv. Filament" + #define MSG_INIT_SDCARD "Init. SD kaart" + #define MSG_CNG_SDCARD "Verv. SD card" + #define MSG_ZPROBE_OUT "Z probe uit. bed" + #define MSG_POSITION_UNKNOWN "Home X/Y voor Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_BABYSTEP_X "Babystap X" + #define MSG_BABYSTEP_Y "Babystap Y" + #define MSG_BABYSTEP_Z "Babystap Z" + #define MSG_ENDSTOP_ABORT "Endstop afbr." + +// Serial Console Messages + + #define MSG_Enqueing "enqueing \"" + #define MSG_POWERUP "Opstarten" + #define MSG_EXTERNAL_RESET " Externe Reset" + #define MSG_BROWNOUT_RESET " Lage voedingsspanning Reset" + #define MSG_WATCHDOG_RESET " Watchdog Reset" + #define MSG_SOFTWARE_RESET " Software Reset" + #define MSG_AUTHOR " | Auteur: " + #define MSG_CONFIGURATION_VER " Laatst bijgewerkt: " + #define MSG_FREE_MEMORY " Vrij Geheugen: " + #define MSG_PLANNER_BUFFER_BYTES " PlannerBufferBytes: " + #define MSG_OK "ok" + #define MSG_FILE_SAVED "Bestand opslaan voltooid." + #define MSG_ERR_LINE_NO "Regelnummer is niet het laatste regelnummer+1, Laatste regel: " + #define MSG_ERR_CHECKSUM_MISMATCH "Checksum fout, Laatste regel: " + #define MSG_ERR_NO_CHECKSUM "Regel zonder checksum, Laatste regel: " + #define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "Geen regelnummer met checksum, Laatste regel: " + #define MSG_FILE_PRINTED "Bestand afdrukken klaar" + #define MSG_BEGIN_FILE_LIST "Begin bestandslijst" + #define MSG_END_FILE_LIST "Einde bestandslijst" + #define MSG_M104_INVALID_EXTRUDER "M104 Ongeldige extruder " + #define MSG_M105_INVALID_EXTRUDER "M105 Ongeldige extruder " + #define MSG_M200_INVALID_EXTRUDER "M200 Ongeldige extruder " + #define MSG_M218_INVALID_EXTRUDER "M218 Ongeldige extruder " + #define MSG_ERR_NO_THERMISTORS "Geen thermistors - geen temperatuur" + #define MSG_M109_INVALID_EXTRUDER "M109 Ongeldige extruder " + #define MSG_HEATING "Opwarmen..." + #define MSG_HEATING_COMPLETE "Opwarmen klaar." + #define MSG_BED_HEATING "Bed opwarmen." + #define MSG_BED_DONE "Bed klaar." + #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup voor gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" + #define MSG_COUNT_X " Aantal X: " + #define MSG_ERR_KILLED "Printer stopgezet. kill() aangeroepen!" + #define MSG_ERR_STOPPED "Printer gestopt vanwege fouten. Los de fout op en gebruik M999 om opnieuw te starten. (Temperatuur is gereset, stel deze opnieuw in na herstart)" + #define MSG_RESEND "Opnieuw sturen: " + #define MSG_UNKNOWN_COMMAND "Onbekend commando: \"" + #define MSG_ACTIVE_EXTRUDER "Actieve Extruder: " + #define MSG_INVALID_EXTRUDER "Ongeldige extruder" + #define MSG_X_MIN "x_min: " + #define MSG_X_MAX "x_max: " + #define MSG_Y_MIN "y_min: " + #define MSG_Y_MAX "y_max: " + #define MSG_Z_MIN "z_min: " + #define MSG_Z_MAX "z_max: " + #define MSG_M119_REPORT "Eindstop statusrapportage:" + #define MSG_ENDSTOP_HIT "GERAAKT" + #define MSG_ENDSTOP_OPEN "open" + #define MSG_HOTEND_OFFSET "Hotend afwijking:" + + #define MSG_SD_CANT_OPEN_SUBDIR "Kan subdirectory niet openen" + #define MSG_SD_INIT_FAIL "SD initialiseren mislukt" + #define MSG_SD_VOL_INIT_FAIL "volume.init mislukt" + #define MSG_SD_OPENROOT_FAIL "openRoot mislukt" + #define MSG_SD_CARD_OK "SD kaart ok" + #define MSG_SD_WORKDIR_FAIL "workDir openen mislukt" + #define MSG_SD_OPEN_FILE_FAIL "Openen mislukt, bestand: " + #define MSG_SD_FILE_OPENED "Bestand geopend: " + #define MSG_SD_SIZE " Grootte: " + #define MSG_SD_FILE_SELECTED "Bestanden geselecteerd:" + #define MSG_SD_WRITE_TO_FILE "Schrijven naar bestand: " + #define MSG_SD_PRINTING_BYTE "SD printen byte: " + #define MSG_SD_NOT_PRINTING "Niet SD printen" + #define MSG_SD_ERR_WRITE_TO_FILE "Fout tijdens het schrijven naar bestand:" + #define MSG_SD_CANT_ENTER_SUBDIR "Kan subdirectory niet in: " + + #define MSG_STEPPER_TOO_HIGH "stapsnelheid te hoog:" + #define MSG_ENDSTOPS_HIT "endstops geraakt: " + #define MSG_ERR_COLD_EXTRUDE_STOP " Koude extrusie voorkomen" + #define MSG_ERR_LONG_EXTRUDE_STOP " te lange extrusie voorkomen" + #define MSG_BABYSTEPPING_X "Babystepping X" + #define MSG_BABYSTEPPING_Y "Babystepping Y" + #define MSG_BABYSTEPPING_Z "Babystepping Z" + #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Fout in menustructuur" + +#endif + #endif // ifndef LANGUAGE_H From af9395ac2ec8d9ede37028720af953e56821120b Mon Sep 17 00:00:00 2001 From: Jim Morris Date: Mon, 17 Feb 2014 20:50:59 -0800 Subject: [PATCH 172/256] Add M605 to dynamically set delta configuration Save above configs in eeprom fix docs in createTemperatureLookupMarlin.py add missing azteegX3pro digipot settings in delta example config --- Marlin/ConfigurationStore.cpp | 25 ++++++-- Marlin/Marlin.h | 4 ++ Marlin/Marlin_main.cpp | 63 +++++++++++++++---- Marlin/createTemperatureLookupMarlin.py | 9 +-- .../delta/Configuration.h | 13 +--- .../delta/Configuration_adv.h | 6 ++ 6 files changed, 87 insertions(+), 33 deletions(-) diff --git a/Marlin/ConfigurationStore.cpp b/Marlin/ConfigurationStore.cpp index 3409ade705..80dce5df06 100644 --- a/Marlin/ConfigurationStore.cpp +++ b/Marlin/ConfigurationStore.cpp @@ -37,7 +37,7 @@ void _EEPROM_readData(int &pos, uint8_t* value, uint8_t size) // the default values are used whenever there is a change to the data, to prevent // wrong data being written to the variables. // ALSO: always make sure the variables in the Store and retrieve sections are in the same order. -#define EEPROM_VERSION "V10" +#define EEPROM_VERSION "V11" #ifdef EEPROM_SETTINGS void Config_StoreSettings() @@ -59,6 +59,9 @@ void Config_StoreSettings() EEPROM_WRITE_VAR(i,add_homeing); #ifdef DELTA EEPROM_WRITE_VAR(i,endstop_adj); + EEPROM_WRITE_VAR(i,delta_radius); + EEPROM_WRITE_VAR(i,delta_diagonal_rod); + EEPROM_WRITE_VAR(i,delta_segments_per_second); #endif #ifndef ULTIPANEL int plaPreheatHotendTemp = PLA_PREHEAT_HOTEND_TEMP, plaPreheatHPBTemp = PLA_PREHEAT_HPB_TEMP, plaPreheatFanSpeed = PLA_PREHEAT_FAN_SPEED; @@ -156,7 +159,14 @@ void Config_PrintSettings() SERIAL_ECHOPAIR(" M666 X",endstop_adj[0] ); SERIAL_ECHOPAIR(" Y" ,endstop_adj[1] ); SERIAL_ECHOPAIR(" Z" ,endstop_adj[2] ); - SERIAL_ECHOLN(""); + SERIAL_ECHOLN(""); + SERIAL_ECHO_START; + SERIAL_ECHOLNPGM("Delta settings: L=delta_diagonal_rod, R=delta_radius, S=delta_segments_per_second"); + SERIAL_ECHO_START; + SERIAL_ECHOPAIR(" M665 L",delta_diagonal_rod ); + SERIAL_ECHOPAIR(" R" ,delta_radius ); + SERIAL_ECHOPAIR(" S" ,delta_segments_per_second ); + SERIAL_ECHOLN(""); #endif #ifdef PIDTEMP SERIAL_ECHO_START; @@ -199,7 +209,10 @@ void Config_RetrieveSettings() EEPROM_READ_VAR(i,max_e_jerk); EEPROM_READ_VAR(i,add_homeing); #ifdef DELTA - EEPROM_READ_VAR(i,endstop_adj); + EEPROM_READ_VAR(i,endstop_adj); + EEPROM_READ_VAR(i,delta_radius); + EEPROM_READ_VAR(i,delta_diagonal_rod); + EEPROM_READ_VAR(i,delta_segments_per_second); #endif #ifndef ULTIPANEL int plaPreheatHotendTemp, plaPreheatHPBTemp, plaPreheatFanSpeed; @@ -264,7 +277,11 @@ void Config_ResetDefault() max_e_jerk=DEFAULT_EJERK; add_homeing[0] = add_homeing[1] = add_homeing[2] = 0; #ifdef DELTA - endstop_adj[0] = endstop_adj[1] = endstop_adj[2] = 0; + endstop_adj[0] = endstop_adj[1] = endstop_adj[2] = 0; + delta_radius= DELTA_RADIUS; + delta_diagonal_rod= DELTA_DIAGONAL_ROD; + delta_segments_per_second= DELTA_SEGMENTS_PER_SECOND; + recalc_delta_settings(delta_radius, delta_diagonal_rod); #endif #ifdef ULTIPANEL plaPreheatHotendTemp = PLA_PREHEAT_HOTEND_TEMP; diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index 7a4b864fde..d79fc019fb 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -209,6 +209,10 @@ extern float current_position[NUM_AXIS] ; extern float add_homeing[3]; #ifdef DELTA extern float endstop_adj[3]; +extern float delta_radius; +extern float delta_diagonal_rod; +extern float delta_segments_per_second; +void recalc_delta_settings(float radius, float diagonal_rod); #endif extern float min_pos[3]; extern float max_pos[3]; diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 0023279d8b..d8a105dc3f 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -161,6 +161,7 @@ // M503 - print the current settings (from memory not from eeprom) // M540 - Use S[0|1] to enable or disable the stop SD card print on endstop hit (requires ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) // M600 - Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal] +// M665 - set delta configurations // M666 - set delta endstop adjustemnt // M605 - Set dual x-carriage movement mode: S [ X R ] // M907 - Set digital trimpot motor current using axis codes. @@ -246,9 +247,21 @@ int EtoPPressure=0; #endif #ifdef DELTA -float delta[3] = {0.0, 0.0, 0.0}; -#endif - + float delta[3] = {0.0, 0.0, 0.0}; + #define SIN_60 0.8660254037844386 + #define COS_60 0.5 + // these are the default values, can be overriden with M665 + float delta_radius= DELTA_RADIUS; + float delta_tower1_x= -SIN_60*delta_radius; // front left tower + float delta_tower1_y= -COS_60*delta_radius; + float delta_tower2_x= SIN_60*delta_radius; // front right tower + float delta_tower2_y= -COS_60*delta_radius; + float delta_tower3_x= 0.0; // back middle tower + float delta_tower3_y= delta_radius; + float delta_diagonal_rod= DELTA_DIAGONAL_ROD; + float delta_diagonal_rod_2= sq(delta_diagonal_rod); + float delta_segments_per_second= DELTA_SEGMENTS_PER_SECOND; +#endif //=========================================================================== //=============================private variables============================= @@ -2267,6 +2280,19 @@ void process_commands() } break; #ifdef DELTA + case 665: // M665 set delta configurations L R S + if(code_seen('L')) { + delta_diagonal_rod= code_value(); + } + if(code_seen('R')) { + delta_radius= code_value(); + } + if(code_seen('S')) { + delta_segments_per_second= code_value(); + } + + recalc_delta_settings(delta_radius, delta_diagonal_rod); + break; case 666: // M666 set delta endstop adjustemnt for(int8_t i=0; i < 3; i++) { @@ -3101,19 +3127,30 @@ void clamp_to_software_endstops(float target[3]) } #ifdef DELTA +void recalc_delta_settings(float radius, float diagonal_rod) +{ + delta_tower1_x= -SIN_60*radius; // front left tower + delta_tower1_y= -COS_60*radius; + delta_tower2_x= SIN_60*radius; // front right tower + delta_tower2_y= -COS_60*radius; + delta_tower3_x= 0.0; // back middle tower + delta_tower3_y= radius; + delta_diagonal_rod_2= sq(diagonal_rod); +} + void calculate_delta(float cartesian[3]) { - delta[X_AXIS] = sqrt(DELTA_DIAGONAL_ROD_2 - - sq(DELTA_TOWER1_X-cartesian[X_AXIS]) - - sq(DELTA_TOWER1_Y-cartesian[Y_AXIS]) + delta[X_AXIS] = sqrt(delta_diagonal_rod_2 + - sq(delta_tower1_x-cartesian[X_AXIS]) + - sq(delta_tower1_y-cartesian[Y_AXIS]) ) + cartesian[Z_AXIS]; - delta[Y_AXIS] = sqrt(DELTA_DIAGONAL_ROD_2 - - sq(DELTA_TOWER2_X-cartesian[X_AXIS]) - - sq(DELTA_TOWER2_Y-cartesian[Y_AXIS]) + delta[Y_AXIS] = sqrt(delta_diagonal_rod_2 + - sq(delta_tower2_x-cartesian[X_AXIS]) + - sq(delta_tower2_y-cartesian[Y_AXIS]) ) + cartesian[Z_AXIS]; - delta[Z_AXIS] = sqrt(DELTA_DIAGONAL_ROD_2 - - sq(DELTA_TOWER3_X-cartesian[X_AXIS]) - - sq(DELTA_TOWER3_Y-cartesian[Y_AXIS]) + delta[Z_AXIS] = sqrt(delta_diagonal_rod_2 + - sq(delta_tower3_x-cartesian[X_AXIS]) + - sq(delta_tower3_y-cartesian[Y_AXIS]) ) + cartesian[Z_AXIS]; /* SERIAL_ECHOPGM("cartesian x="); SERIAL_ECHO(cartesian[X_AXIS]); @@ -3143,7 +3180,7 @@ void prepare_move() if (cartesian_mm < 0.000001) { cartesian_mm = abs(difference[E_AXIS]); } if (cartesian_mm < 0.000001) { return; } float seconds = 6000 * cartesian_mm / feedrate / feedmultiply; - int steps = max(1, int(DELTA_SEGMENTS_PER_SECOND * seconds)); + int steps = max(1, int(delta_segments_per_second * seconds)); // SERIAL_ECHOPGM("mm="); SERIAL_ECHO(cartesian_mm); // SERIAL_ECHOPGM(" seconds="); SERIAL_ECHO(seconds); // SERIAL_ECHOPGM(" steps="); SERIAL_ECHOLN(steps); diff --git a/Marlin/createTemperatureLookupMarlin.py b/Marlin/createTemperatureLookupMarlin.py index 77187b8099..01c602dffa 100755 --- a/Marlin/createTemperatureLookupMarlin.py +++ b/Marlin/createTemperatureLookupMarlin.py @@ -16,9 +16,9 @@ Usage: python createTemperatureLookup.py [options] Options: -h, --help show this help --rp=... pull-up resistor - --t0=ttt:rrr low temperature temperature:resistance point (around 25C) - --t1=ttt:rrr middle temperature temperature:resistance point (around 150C) - --t2=ttt:rrr high temperature temperature:resistance point (around 250C) + --t1=ttt:rrr low temperature temperature:resistance point (around 25C) + --t2=ttt:rrr middle temperature temperature:resistance point (around 150C) + --t3=ttt:rrr high temperature temperature:resistance point (around 250C) --num-temps=... the number of temperature points to calculate (default: 20) """ @@ -98,7 +98,8 @@ def main(argv): try: opts, args = getopt.getopt(argv, "h", ["help", "rp=", "t1=", "t2=", "t3=", "num-temps="]) - except getopt.GetoptError: + except getopt.GetoptError as err: + print str(err) usage() sys.exit(2) diff --git a/Marlin/example_configurations/delta/Configuration.h b/Marlin/example_configurations/delta/Configuration.h index 0d232d372f..c724484bd9 100644 --- a/Marlin/example_configurations/delta/Configuration.h +++ b/Marlin/example_configurations/delta/Configuration.h @@ -51,6 +51,7 @@ // 65 = Azteeg X1 // 66 = Melzi with ATmega1284 (MaKr3d version) // 67 = Azteeg X3 +// 68 = Azteeg X3 Pro // 7 = Ultimaker // 71 = Ultimaker (Older electronics. Pre 1.5.4. This is rare) // 77 = 3Drag Controller @@ -119,18 +120,6 @@ // Effective horizontal distance bridged by diagonal push rods. #define DELTA_RADIUS (DELTA_SMOOTH_ROD_OFFSET-DELTA_EFFECTOR_OFFSET-DELTA_CARRIAGE_OFFSET) -#define DELTA_DIAGONAL_ROD_2 sq(DELTA_DIAGONAL_ROD) - -// Effective X/Y positions of the three vertical towers. -#define SIN_60 0.8660254037844386 -#define COS_60 0.5 -#define DELTA_TOWER1_X -SIN_60*DELTA_RADIUS // front left tower -#define DELTA_TOWER1_Y -COS_60*DELTA_RADIUS -#define DELTA_TOWER2_X SIN_60*DELTA_RADIUS // front right tower -#define DELTA_TOWER2_Y -COS_60*DELTA_RADIUS -#define DELTA_TOWER3_X 0.0 // back middle tower -#define DELTA_TOWER3_Y DELTA_RADIUS - //=========================================================================== //=============================Thermal Settings ============================ //=========================================================================== diff --git a/Marlin/example_configurations/delta/Configuration_adv.h b/Marlin/example_configurations/delta/Configuration_adv.h index fcf6ff570f..4d6e78b4d9 100644 --- a/Marlin/example_configurations/delta/Configuration_adv.h +++ b/Marlin/example_configurations/delta/Configuration_adv.h @@ -270,6 +270,12 @@ // Motor Current setting (Only functional when motor driver current ref pins are connected to a digital trimpot on supported boards) #define DIGIPOT_MOTOR_CURRENT {135,135,135,135,135} // Values 0-255 (RAMBO 135 = ~0.75A, 185 = ~1A) +// uncomment to enable an I2C based DIGIPOT like on the Azteeg X3 Pro +//#define DIGIPOT_I2C +// Number of channels available for I2C digipot, For Azteeg X3 Pro we have 8 +#define DIGIPOT_I2C_NUM_CHANNELS 8 +// actual motor currents in Amps, need as many here as DIGIPOT_I2C_NUM_CHANNELS +#define DIGIPOT_I2C_MOTOR_CURRENTS {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0} //=========================================================================== //=============================Additional Features=========================== From 498d76fd794b803cdfe0293c8defb4294986c848 Mon Sep 17 00:00:00 2001 From: Marco Date: Tue, 18 Feb 2014 09:40:10 +0100 Subject: [PATCH 173/256] Fixed some messages where the text shown on the screen was more than 17 characters --- Marlin/language.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index 3560412374..9ed9095ebf 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -1933,9 +1933,9 @@ #define MSG_AUTO_HOME "Auto home" #define MSG_SET_ORIGIN "Nulpunt instellen" #define MSG_PREHEAT_PLA "PLA voorverwarmen" - #define MSG_PREHEAT_PLA_SETTINGS "PLA voorverw. conf" + #define MSG_PREHEAT_PLA_SETTINGS "PLA verw. conf" #define MSG_PREHEAT_ABS "ABS voorverwarmen" - #define MSG_PREHEAT_ABS_SETTINGS "ABS voorverw. conf" + #define MSG_PREHEAT_ABS_SETTINGS "ABS verw. conf" #define MSG_COOLDOWN "Afkoelen" #define MSG_SWITCH_PS_ON "Stroom aan" #define MSG_SWITCH_PS_OFF "Stroom uit" @@ -1984,7 +1984,7 @@ #define MSG_YSTEPS "Ysteps/mm" #define MSG_ZSTEPS "Zsteps/mm" #define MSG_ESTEPS "Esteps/mm" - #define MSG_RECTRACT "Rectract" + #define MSG_RECTRACT "Terugtrekken" #define MSG_TEMPERATURE "Temperatuur" #define MSG_MOTION "Beweging" #define MSG_CONTRAST "LCD contrast" From 51ae4881ab0fea7f82fcf6d8266a5b53cd17e007 Mon Sep 17 00:00:00 2001 From: Marco Date: Tue, 18 Feb 2014 09:47:36 +0100 Subject: [PATCH 174/256] Fixed small typo that would prevent compiling --- Marlin/Marlin_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 498adfdb95..952ac5847b 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1080,7 +1080,7 @@ static void homeaxis(int axis) { } } #define HOMEAXIS(LETTER) homeaxis(LETTER##_AXIS) -+void refresh_cmd_timeout(void) +void refresh_cmd_timeout(void) { previous_millis_cmd = millis(); } From 8212d8d543d534dde330ed982633418b8a063978 Mon Sep 17 00:00:00 2001 From: Marco Date: Tue, 18 Feb 2014 10:40:25 +0100 Subject: [PATCH 175/256] Revert "Fixed small typo that would prevent compiling" This reverts commit 51ae4881ab0fea7f82fcf6d8266a5b53cd17e007. --- Marlin/Marlin_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 952ac5847b..498adfdb95 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1080,7 +1080,7 @@ static void homeaxis(int axis) { } } #define HOMEAXIS(LETTER) homeaxis(LETTER##_AXIS) -void refresh_cmd_timeout(void) ++void refresh_cmd_timeout(void) { previous_millis_cmd = millis(); } From c00383f286de4b22a48f5cbea4e96938dc55e646 Mon Sep 17 00:00:00 2001 From: Christian Axelsson Date: Tue, 18 Feb 2014 18:50:12 +0100 Subject: [PATCH 176/256] Fixed typo. --- Marlin/temperature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index 66a097d280..060d11f62b 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -250,7 +250,7 @@ void PID_autotune(float temp, int extruder, int ncycles) Kp = 0.6*Ku; Ki = 2*Kp/Tu; Kd = Kp*Tu/8; - SERIAL_PROTOCOLLNPGM(" Clasic PID "); + SERIAL_PROTOCOLLNPGM(" Classic PID "); SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp); SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki); SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd); From 2ccdf4f36d368dd5b5d24aab05dc54c39e8bf458 Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Wed, 19 Feb 2014 00:02:59 -0800 Subject: [PATCH 177/256] Use descriptive constants instead of numeric literals --- Marlin/Marlin_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index f98d530dea..47f81a4d43 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1241,7 +1241,7 @@ void process_commands() #else // NOT DELTA - home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))); + home_all_axis = !((code_seen(axis_codes[X_AXIS])) || (code_seen(axis_codes[Y_AXIS])) || (code_seen(axis_codes[Z_AXIS]))); #if Z_HOME_DIR > 0 // If homing away from BED do Z first if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) { From d2d7d186b5aaa208351d0dda35b26b59b6fbebca Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Wed, 19 Feb 2014 00:10:17 -0800 Subject: [PATCH 178/256] Use descriptive constants, more --- Marlin/Marlin_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 47f81a4d43..a3f0d60489 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -2088,7 +2088,7 @@ void process_commands() } else { - bool all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))|| (code_seen(axis_codes[3]))); + bool all_axis = !((code_seen(axis_codes[X_AXIS])) || (code_seen(axis_codes[Y_AXIS])) || (code_seen(axis_codes[Z_AXIS]))|| (code_seen(axis_codes[E_AXIS]))); if(all_axis) { st_synchronize(); From 357e31270aa97cf9cae6cf8da335666af1fcaec6 Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Wed, 19 Feb 2014 00:51:43 -0800 Subject: [PATCH 179/256] Prevent G29 without first homing in X and Y If position is unknown, then G29 can be dangerous. --- Marlin/Marlin_main.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index f98d530dea..444d698287 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1409,6 +1409,15 @@ void process_commands() #error "You must have a Z_MIN endstop in order to enable Auto Bed Leveling feature!!! Z_MIN_PIN must point to a valid hardware pin." #endif + // Prevent user from running a G29 without first homing in X and Y + if (! (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS]) ) + { + LCD_MESSAGEPGM(MSG_POSITION_UNKNOWN); + SERIAL_ECHO_START; + SERIAL_ECHOLNPGM(MSG_POSITION_UNKNOWN); + break; // abort G29, since we don't know where we are + } + st_synchronize(); // make sure the bed_level_rotation_matrix is identity or the planner will get it incorectly //vector_3 corrected_position = plan_get_position_mm(); From f308a8af91a0f7638a48a5e4f8647d1567992df6 Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Wed, 19 Feb 2014 01:06:24 -0800 Subject: [PATCH 180/256] update comment --- Marlin/Marlin_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 444d698287..bc8327b8b4 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -76,7 +76,7 @@ // G10 - retract filament according to settings of M207 // G11 - retract recover filament according to settings of M208 // G28 - Home all Axis -// G29 - Detailed Z-Probe, probes the bed at 3 points. You must de at the home position for this to work correctly. +// G29 - Detailed Z-Probe, probes the bed at 3 or more points. Will fail if you haven't homed yet. // G30 - Single Z Probe, probes bed at current XY location. // G90 - Use Absolute Coordinates // G91 - Use Relative Coordinates From 34fd59c3704b830985721d2694706e9d903c9b4a Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Sat, 15 Feb 2014 18:06:51 -0800 Subject: [PATCH 181/256] ABL at any points --- Marlin/Configuration.h | 16 ++++++++++++++ Marlin/Marlin_main.cpp | 49 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index c9f3558d41..839bc3482e 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -335,12 +335,28 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #ifdef ENABLE_AUTO_BED_LEVELING +// Enable auto bed leveling at any 3 points that aren't colinear +#define AUTO_BED_LEVELING_ANY_POINTS + +#ifdef AUTO_BED_LEVELING_ANY_POINTS + #define ABL_PROBE_PT_1_X -11 + #define ABL_PROBE_PT_1_Y -15 + #define ABL_PROBE_PT_2_X -11 + #define ABL_PROBE_PT_2_Y 75 + #define ABL_PROBE_PT_3_X 121 + #define ABL_PROBE_PT_3_Y -15 + + +#else // not AUTO_BED_LEVELING_ANY_POINTS + // these are the positions on the bed to do the probing #define LEFT_PROBE_BED_POSITION 15 #define RIGHT_PROBE_BED_POSITION 170 #define BACK_PROBE_BED_POSITION 180 #define FRONT_PROBE_BED_POSITION 20 +#endif + // these are the offsets to the probe relative to the extruder tip (Hotend - Probe) #define X_PROBE_OFFSET_FROM_EXTRUDER -25 #define Y_PROBE_OFFSET_FROM_EXTRUDER -29 diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index d92d1e2ce8..8a6542b1f2 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -846,7 +846,36 @@ static void set_bed_level_equation_lsq(double *plane_equation_coefficients) plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); } -#else +#else // not ACCURATE_BED_LEVELING + + #ifdef AUTO_BED_LEVELING_ANY_POINTS +static void set_bed_level_equation_any_pts(float z_at_pt_1, float z_at_pt_2, float z_at_pt_3) { + + plan_bed_level_matrix.set_to_identity(); + + vector_3 pt1 = vector_3(ABL_PROBE_PT_1_X, ABL_PROBE_PT_1_Y, z_at_pt_1); + vector_3 pt2 = vector_3(ABL_PROBE_PT_2_X, ABL_PROBE_PT_2_Y, z_at_pt_2); + vector_3 pt3 = vector_3(ABL_PROBE_PT_3_X, ABL_PROBE_PT_3_Y, z_at_pt_3); + + vector_3 from_2_to_1 = (pt1 - pt2).get_normal(); + vector_3 from_2_to_3 = (pt3 - pt2).get_normal(); + vector_3 planeNormal = vector_3::cross(from_2_to_1, from_2_to_3).get_normal(); + planeNormal = vector_3(planeNormal.x, planeNormal.y, abs(planeNormal.z)); + + plan_bed_level_matrix = matrix_3x3::create_look_at(planeNormal); + + vector_3 corrected_position = plan_get_position(); + current_position[X_AXIS] = corrected_position.x; + current_position[Y_AXIS] = corrected_position.y; + current_position[Z_AXIS] = corrected_position.z; + + // but the bed at 0 so we don't go below it. + current_position[Z_AXIS] = zprobe_zoffset; + + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + +} + #else // not AUTO_BED_LEVELING_ANY_POINTS static void set_bed_level_equation(float z_at_xLeft_yFront, float z_at_xRight_yFront, float z_at_xLeft_yBack) { plan_bed_level_matrix.set_to_identity(); @@ -881,6 +910,7 @@ static void set_bed_level_equation(float z_at_xLeft_yFront, float z_at_xRight_yF plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); } + #endif // AUTO_BED_LEVELING_ANY_POINTS #endif // ACCURATE_BED_LEVELING static void run_z_probe() { @@ -1514,6 +1544,21 @@ void process_commands() #else // ACCURATE_BED_LEVELING not defined + #ifdef AUTO_BED_LEVELING_ANY_POINTS + // probe 1 + float z_at_pt_1 = probe_pt(ABL_PROBE_PT_1_X, ABL_PROBE_PT_1_Y, Z_RAISE_BEFORE_PROBING); + + // probe 2 + float z_at_pt_2 = probe_pt(ABL_PROBE_PT_2_X, ABL_PROBE_PT_2_Y, current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); + + // probe 3 + float z_at_pt_3 = probe_pt(ABL_PROBE_PT_3_X, ABL_PROBE_PT_3_Y, current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); + + clean_up_after_endstop_move(); + + set_bed_level_equation_any_pts(z_at_pt_1, z_at_pt_2, z_at_pt_3); + #else // not AUTO_BED_LEVELING_ANY_POINTS + // prob 1 float z_at_xLeft_yBack = probe_pt(LEFT_PROBE_BED_POSITION, BACK_PROBE_BED_POSITION, Z_RAISE_BEFORE_PROBING); @@ -1526,7 +1571,7 @@ void process_commands() clean_up_after_endstop_move(); set_bed_level_equation(z_at_xLeft_yFront, z_at_xRight_yFront, z_at_xLeft_yBack); - + #endif #endif // ACCURATE_BED_LEVELING st_synchronize(); From 3b718b816c6d89e1a8d739a92689a8805c76be0d Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Wed, 19 Feb 2014 14:04:37 -0800 Subject: [PATCH 182/256] better documentation --- Marlin/Configuration.h | 48 ++++++++++++++++++++++++++++++++---------- Marlin/Marlin_main.cpp | 12 ++++++----- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 839bc3482e..3261998792 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -335,21 +335,44 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #ifdef ENABLE_AUTO_BED_LEVELING -// Enable auto bed leveling at any 3 points that aren't colinear -#define AUTO_BED_LEVELING_ANY_POINTS +// There are 3 different ways to pick the X and Y locations to probe: +// 1. Basic 3-point probe at left-back, left-front, and right-front corners of a rectangle +// 2. Probe all points of a 2D lattice, defined by a rectangle and ACCURATE_BED_LEVELING_POINTS +// 3. 3-point probe at 3 arbitrary points that don't form a line. -#ifdef AUTO_BED_LEVELING_ANY_POINTS - #define ABL_PROBE_PT_1_X -11 - #define ABL_PROBE_PT_1_Y -15 - #define ABL_PROBE_PT_2_X -11 - #define ABL_PROBE_PT_2_Y 75 - #define ABL_PROBE_PT_3_X 121 - #define ABL_PROBE_PT_3_Y -15 +// To enable mode 1: +// - #define ENABLE_AUTO_BED_LEVELING +// - Set the XXXX_PROBE_BED_POSITION values below +// - Don't define AUTO_BED_LEVELING_ANY_POINTS or ACCURATE_BED_LEVELING + +// To enable mode 2: +// - #define ENABLE_AUTO_BED_LEVELING +// - Set the XXXX_PROBE_BED_POSITION values below +// - #define ACCURATE_BED_LEVELING +// - Set the ACCURATE_BED_LEVELING_POINTS to your desired density + +// To enable mode 3: +// - #define ENABLE_AUTO_BED_LEVELING +// - #define AUTO_BED_LEVELING_ANY_POINTS +// - Set the ABL_PROBE_PT_XXXX values below +// - Comment out (undefine) ACCURATE_BED_LEVELING since that is incompatible + +// Mode 3: Enable auto bed leveling at any 3 points that aren't colinear +// #define AUTO_BED_LEVELING_ANY_POINTS +#ifdef AUTO_BED_LEVELING_ANY_POINTS + #define ABL_PROBE_PT_1_X 15 + #define ABL_PROBE_PT_1_Y 15 + #define ABL_PROBE_PT_2_X 25 + #define ABL_PROBE_PT_2_Y 75 + #define ABL_PROBE_PT_3_X 125 + #define ABL_PROBE_PT_3_Y 25 #else // not AUTO_BED_LEVELING_ANY_POINTS - // these are the positions on the bed to do the probing + // Modes 1 & 2: + // For mode 1, probing happens at left-back, left-front, and right-front corners + // For mode 2, probing happens at lattice points within this rectangle (see ACCURATE_BED_LEVELING_POINTS) #define LEFT_PROBE_BED_POSITION 15 #define RIGHT_PROBE_BED_POSITION 170 #define BACK_PROBE_BED_POSITION 180 @@ -398,8 +421,11 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of // with accurate bed leveling, the bed is sampled in a ACCURATE_BED_LEVELING_POINTSxACCURATE_BED_LEVELING_POINTS grid and least squares solution is calculated // Note: this feature occupies 10'206 byte #define ACCURATE_BED_LEVELING - + // Mode 2 only #ifdef ACCURATE_BED_LEVELING + #ifdef AUTO_BED_LEVELING_ANY_POINTS + #error AUTO_BED_LEVELING_ANY_POINTS is incompatible with ACCURATE_BED_LEVELING + #endif // I wouldn't see a reason to go above 3 (=9 probing points on the bed) #define ACCURATE_BED_LEVELING_POINTS 2 #endif diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 8a6542b1f2..b3f971a105 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1433,7 +1433,7 @@ void process_commands() break; #ifdef ENABLE_AUTO_BED_LEVELING - case 29: // G29 Detailed Z-Probe, probes the bed at 3 points. + case 29: // G29 Detailed Z-Probe, probes the bed at 3 or more points. { #if Z_MIN_PIN == -1 #error "You must have a Z_MIN endstop in order to enable Auto Bed Leveling feature!!! Z_MIN_PIN must point to a valid hardware pin." @@ -1463,6 +1463,7 @@ void process_commands() feedrate = homing_feedrate[Z_AXIS]; #ifdef ACCURATE_BED_LEVELING + // probe at the points of a lattice grid int xGridSpacing = (RIGHT_PROBE_BED_POSITION - LEFT_PROBE_BED_POSITION) / (ACCURATE_BED_LEVELING_POINTS-1); int yGridSpacing = (BACK_PROBE_BED_POSITION - FRONT_PROBE_BED_POSITION) / (ACCURATE_BED_LEVELING_POINTS-1); @@ -1545,6 +1546,7 @@ void process_commands() #ifdef AUTO_BED_LEVELING_ANY_POINTS + // Probe at 3 arbitrary points // probe 1 float z_at_pt_1 = probe_pt(ABL_PROBE_PT_1_X, ABL_PROBE_PT_1_Y, Z_RAISE_BEFORE_PROBING); @@ -1558,14 +1560,14 @@ void process_commands() set_bed_level_equation_any_pts(z_at_pt_1, z_at_pt_2, z_at_pt_3); #else // not AUTO_BED_LEVELING_ANY_POINTS - - // prob 1 + // probe at 3 corners of a rectangle + // probe 1 float z_at_xLeft_yBack = probe_pt(LEFT_PROBE_BED_POSITION, BACK_PROBE_BED_POSITION, Z_RAISE_BEFORE_PROBING); - // prob 2 + // probe 2 float z_at_xLeft_yFront = probe_pt(LEFT_PROBE_BED_POSITION, FRONT_PROBE_BED_POSITION, current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); - // prob 3 + // probe 3 float z_at_xRight_yFront = probe_pt(RIGHT_PROBE_BED_POSITION, FRONT_PROBE_BED_POSITION, current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); clean_up_after_endstop_move(); From 174b8d99d5a6524a2173ff699f7b2acc1c74d5d0 Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Wed, 19 Feb 2014 21:12:39 -0800 Subject: [PATCH 183/256] Simplify 3-point probing using new code only --- Marlin/Configuration.h | 99 ++++++++++++++++++------------------------ Marlin/Marlin_main.cpp | 90 ++++++++------------------------------ Marlin/qr_solve.cpp | 2 +- Marlin/qr_solve.h | 2 +- 4 files changed, 64 insertions(+), 129 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 3261998792..e18c98a437 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -335,50 +335,49 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #ifdef ENABLE_AUTO_BED_LEVELING -// There are 3 different ways to pick the X and Y locations to probe: -// 1. Basic 3-point probe at left-back, left-front, and right-front corners of a rectangle -// 2. Probe all points of a 2D lattice, defined by a rectangle and ACCURATE_BED_LEVELING_POINTS -// 3. 3-point probe at 3 arbitrary points that don't form a line. - -// To enable mode 1: -// - #define ENABLE_AUTO_BED_LEVELING -// - Set the XXXX_PROBE_BED_POSITION values below -// - Don't define AUTO_BED_LEVELING_ANY_POINTS or ACCURATE_BED_LEVELING - -// To enable mode 2: -// - #define ENABLE_AUTO_BED_LEVELING -// - Set the XXXX_PROBE_BED_POSITION values below -// - #define ACCURATE_BED_LEVELING -// - Set the ACCURATE_BED_LEVELING_POINTS to your desired density - -// To enable mode 3: -// - #define ENABLE_AUTO_BED_LEVELING -// - #define AUTO_BED_LEVELING_ANY_POINTS -// - Set the ABL_PROBE_PT_XXXX values below -// - Comment out (undefine) ACCURATE_BED_LEVELING since that is incompatible - - - -// Mode 3: Enable auto bed leveling at any 3 points that aren't colinear -// #define AUTO_BED_LEVELING_ANY_POINTS -#ifdef AUTO_BED_LEVELING_ANY_POINTS - #define ABL_PROBE_PT_1_X 15 - #define ABL_PROBE_PT_1_Y 15 - #define ABL_PROBE_PT_2_X 25 - #define ABL_PROBE_PT_2_Y 75 - #define ABL_PROBE_PT_3_X 125 - #define ABL_PROBE_PT_3_Y 25 -#else // not AUTO_BED_LEVELING_ANY_POINTS - - // Modes 1 & 2: - // For mode 1, probing happens at left-back, left-front, and right-front corners - // For mode 2, probing happens at lattice points within this rectangle (see ACCURATE_BED_LEVELING_POINTS) - #define LEFT_PROBE_BED_POSITION 15 - #define RIGHT_PROBE_BED_POSITION 170 - #define BACK_PROBE_BED_POSITION 180 - #define FRONT_PROBE_BED_POSITION 20 +// There are 2 different ways to pick the X and Y locations to probe: + +// - "grid" mode +// Probe every point in a rectangular grid +// You must specify the rectangle, and the density of sample points +// This mode is preferred because there are more measurements. +// It used to be called ACCURATE_BED_LEVELING but "grid" is more descriptive + +// - "3-point" mode +// Probe 3 arbitrary points on the bed (that aren't colinear) +// You must specify the X & Y coordinates of all 3 points + + #define AUTO_BED_LEVELING_GRID + // with AUTO_BED_LEVELING_GRID, the bed is sampled in a + // AUTO_BED_LEVELING_GRID_POINTSxAUTO_BED_LEVELING_GRID_POINTS grid + // and least squares solution is calculated + // Note: this feature occupies 10'206 byte + #ifdef AUTO_BED_LEVELING_GRID + + // set the rectangle in which to probe + #define LEFT_PROBE_BED_POSITION 15 + #define RIGHT_PROBE_BED_POSITION 170 + #define BACK_PROBE_BED_POSITION 180 + #define FRONT_PROBE_BED_POSITION 20 + + // set the number of grid points per dimension + // I wouldn't see a reason to go above 3 (=9 probing points on the bed) + #define AUTO_BED_LEVELING_GRID_POINTS 2 + + + #else // not AUTO_BED_LEVELING_GRID + // with no grid, just probe 3 arbitrary points. A simple cross-product + // is used to esimate the plane of the print bed + + #define ABL_PROBE_PT_1_X 15 + #define ABL_PROBE_PT_1_Y 180 + #define ABL_PROBE_PT_2_X 15 + #define ABL_PROBE_PT_2_Y 20 + #define ABL_PROBE_PT_3_X 170 + #define ABL_PROBE_PT_3_Y 20 + + #endif // AUTO_BED_LEVELING_GRID -#endif // these are the offsets to the probe relative to the extruder tip (Hotend - Probe) #define X_PROBE_OFFSET_FROM_EXTRUDER -25 @@ -418,19 +417,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #endif - // with accurate bed leveling, the bed is sampled in a ACCURATE_BED_LEVELING_POINTSxACCURATE_BED_LEVELING_POINTS grid and least squares solution is calculated - // Note: this feature occupies 10'206 byte - #define ACCURATE_BED_LEVELING - // Mode 2 only - #ifdef ACCURATE_BED_LEVELING - #ifdef AUTO_BED_LEVELING_ANY_POINTS - #error AUTO_BED_LEVELING_ANY_POINTS is incompatible with ACCURATE_BED_LEVELING - #endif - // I wouldn't see a reason to go above 3 (=9 probing points on the bed) - #define ACCURATE_BED_LEVELING_POINTS 2 - #endif - -#endif +#endif // ENABLE_AUTO_BED_LEVELING // The position of the homing switches diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index b3f971a105..fd5e6b5a7c 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -31,7 +31,7 @@ #ifdef ENABLE_AUTO_BED_LEVELING #include "vector_3.h" - #ifdef ACCURATE_BED_LEVELING + #ifdef AUTO_BED_LEVELING_GRID #include "qr_solve.h" #endif #endif // ENABLE_AUTO_BED_LEVELING @@ -822,7 +822,7 @@ static void axis_is_at_home(int axis) { } #ifdef ENABLE_AUTO_BED_LEVELING -#ifdef ACCURATE_BED_LEVELING +#ifdef AUTO_BED_LEVELING_GRID static void set_bed_level_equation_lsq(double *plane_equation_coefficients) { vector_3 planeNormal = vector_3(-plane_equation_coefficients[0], -plane_equation_coefficients[1], 1); @@ -846,10 +846,9 @@ static void set_bed_level_equation_lsq(double *plane_equation_coefficients) plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); } -#else // not ACCURATE_BED_LEVELING +#else // not AUTO_BED_LEVELING_GRID - #ifdef AUTO_BED_LEVELING_ANY_POINTS -static void set_bed_level_equation_any_pts(float z_at_pt_1, float z_at_pt_2, float z_at_pt_3) { +static void set_bed_level_equation_3pts(float z_at_pt_1, float z_at_pt_2, float z_at_pt_3) { plan_bed_level_matrix.set_to_identity(); @@ -869,49 +868,14 @@ static void set_bed_level_equation_any_pts(float z_at_pt_1, float z_at_pt_2, flo current_position[Y_AXIS] = corrected_position.y; current_position[Z_AXIS] = corrected_position.z; - // but the bed at 0 so we don't go below it. + // put the bed at 0 so we don't go below it. current_position[Z_AXIS] = zprobe_zoffset; plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); } - #else // not AUTO_BED_LEVELING_ANY_POINTS -static void set_bed_level_equation(float z_at_xLeft_yFront, float z_at_xRight_yFront, float z_at_xLeft_yBack) { - plan_bed_level_matrix.set_to_identity(); - - vector_3 xLeftyFront = vector_3(LEFT_PROBE_BED_POSITION, FRONT_PROBE_BED_POSITION, z_at_xLeft_yFront); - vector_3 xLeftyBack = vector_3(LEFT_PROBE_BED_POSITION, BACK_PROBE_BED_POSITION, z_at_xLeft_yBack); - vector_3 xRightyFront = vector_3(RIGHT_PROBE_BED_POSITION, FRONT_PROBE_BED_POSITION, z_at_xRight_yFront); - - vector_3 xPositive = (xRightyFront - xLeftyFront).get_normal(); - vector_3 yPositive = (xLeftyBack - xLeftyFront).get_normal(); - vector_3 planeNormal = vector_3::cross(xPositive, yPositive).get_normal(); - - //planeNormal.debug("planeNormal"); - //yPositive.debug("yPositive"); - plan_bed_level_matrix = matrix_3x3::create_look_at(planeNormal); - //bedLevel.debug("bedLevel"); - - //plan_bed_level_matrix.debug("bed level before"); - //vector_3 uncorrected_position = plan_get_position_mm(); - //uncorrected_position.debug("position before"); - - // and set our bed level equation to do the right thing - //plan_bed_level_matrix.debug("bed level after"); - vector_3 corrected_position = plan_get_position(); - //corrected_position.debug("position after"); - current_position[X_AXIS] = corrected_position.x; - current_position[Y_AXIS] = corrected_position.y; - current_position[Z_AXIS] = corrected_position.z; - - // but the bed at 0 so we don't go below it. - current_position[Z_AXIS] = zprobe_zoffset; - - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); -} - #endif // AUTO_BED_LEVELING_ANY_POINTS -#endif // ACCURATE_BED_LEVELING +#endif // AUTO_BED_LEVELING_GRID static void run_z_probe() { plan_bed_level_matrix.set_to_identity(); @@ -1462,11 +1426,11 @@ void process_commands() setup_for_endstop_move(); feedrate = homing_feedrate[Z_AXIS]; -#ifdef ACCURATE_BED_LEVELING +#ifdef AUTO_BED_LEVELING_GRID // probe at the points of a lattice grid - int xGridSpacing = (RIGHT_PROBE_BED_POSITION - LEFT_PROBE_BED_POSITION) / (ACCURATE_BED_LEVELING_POINTS-1); - int yGridSpacing = (BACK_PROBE_BED_POSITION - FRONT_PROBE_BED_POSITION) / (ACCURATE_BED_LEVELING_POINTS-1); + int xGridSpacing = (RIGHT_PROBE_BED_POSITION - LEFT_PROBE_BED_POSITION) / (AUTO_BED_LEVELING_GRID_POINTS-1); + int yGridSpacing = (BACK_PROBE_BED_POSITION - FRONT_PROBE_BED_POSITION) / (AUTO_BED_LEVELING_GRID_POINTS-1); // solve the plane equation ax + by + d = z @@ -1476,9 +1440,9 @@ void process_commands() // so Vx = -a Vy = -b Vz = 1 (we want the vector facing towards positive Z // "A" matrix of the linear system of equations - double eqnAMatrix[ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS*3]; + double eqnAMatrix[AUTO_BED_LEVELING_GRID_POINTS*AUTO_BED_LEVELING_GRID_POINTS*3]; // "B" vector of Z points - double eqnBVector[ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS]; + double eqnBVector[AUTO_BED_LEVELING_GRID_POINTS*AUTO_BED_LEVELING_GRID_POINTS]; int probePointCounter = 0; @@ -1501,7 +1465,7 @@ void process_commands() zig = true; } - for (int xCount=0; xCount < ACCURATE_BED_LEVELING_POINTS; xCount++) + for (int xCount=0; xCount < AUTO_BED_LEVELING_GRID_POINTS; xCount++) { float z_before; if (probePointCounter == 0) @@ -1518,9 +1482,9 @@ void process_commands() eqnBVector[probePointCounter] = measured_z; - eqnAMatrix[probePointCounter + 0*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = xProbe; - eqnAMatrix[probePointCounter + 1*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = yProbe; - eqnAMatrix[probePointCounter + 2*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = 1; + eqnAMatrix[probePointCounter + 0*AUTO_BED_LEVELING_GRID_POINTS*AUTO_BED_LEVELING_GRID_POINTS] = xProbe; + eqnAMatrix[probePointCounter + 1*AUTO_BED_LEVELING_GRID_POINTS*AUTO_BED_LEVELING_GRID_POINTS] = yProbe; + eqnAMatrix[probePointCounter + 2*AUTO_BED_LEVELING_GRID_POINTS*AUTO_BED_LEVELING_GRID_POINTS] = 1; probePointCounter++; xProbe += xInc; } @@ -1528,7 +1492,7 @@ void process_commands() clean_up_after_endstop_move(); // solve lsq problem - double *plane_equation_coefficients = qr_solve(ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS, 3, eqnAMatrix, eqnBVector); + double *plane_equation_coefficients = qr_solve(AUTO_BED_LEVELING_GRID_POINTS*AUTO_BED_LEVELING_GRID_POINTS, 3, eqnAMatrix, eqnBVector); SERIAL_PROTOCOLPGM("Eqn coefficients: a: "); SERIAL_PROTOCOL(plane_equation_coefficients[0]); @@ -1542,10 +1506,8 @@ void process_commands() free(plane_equation_coefficients); -#else // ACCURATE_BED_LEVELING not defined +#else // AUTO_BED_LEVELING_GRID not defined - - #ifdef AUTO_BED_LEVELING_ANY_POINTS // Probe at 3 arbitrary points // probe 1 float z_at_pt_1 = probe_pt(ABL_PROBE_PT_1_X, ABL_PROBE_PT_1_Y, Z_RAISE_BEFORE_PROBING); @@ -1558,24 +1520,10 @@ void process_commands() clean_up_after_endstop_move(); - set_bed_level_equation_any_pts(z_at_pt_1, z_at_pt_2, z_at_pt_3); - #else // not AUTO_BED_LEVELING_ANY_POINTS - // probe at 3 corners of a rectangle - // probe 1 - float z_at_xLeft_yBack = probe_pt(LEFT_PROBE_BED_POSITION, BACK_PROBE_BED_POSITION, Z_RAISE_BEFORE_PROBING); + set_bed_level_equation_3pts(z_at_pt_1, z_at_pt_2, z_at_pt_3); - // probe 2 - float z_at_xLeft_yFront = probe_pt(LEFT_PROBE_BED_POSITION, FRONT_PROBE_BED_POSITION, current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); - - // probe 3 - float z_at_xRight_yFront = probe_pt(RIGHT_PROBE_BED_POSITION, FRONT_PROBE_BED_POSITION, current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS); - - clean_up_after_endstop_move(); - - set_bed_level_equation(z_at_xLeft_yFront, z_at_xRight_yFront, z_at_xLeft_yBack); - #endif -#endif // ACCURATE_BED_LEVELING +#endif // AUTO_BED_LEVELING_GRID st_synchronize(); // The following code correct the Z height difference from z-probe position and hotend tip position. diff --git a/Marlin/qr_solve.cpp b/Marlin/qr_solve.cpp index 0a491281c5..bfe4fce1ab 100644 --- a/Marlin/qr_solve.cpp +++ b/Marlin/qr_solve.cpp @@ -1,6 +1,6 @@ #include "qr_solve.h" -#ifdef ACCURATE_BED_LEVELING +#ifdef AUTO_BED_LEVELING_GRID #include #include diff --git a/Marlin/qr_solve.h b/Marlin/qr_solve.h index b756d1e1b5..b38086aad0 100644 --- a/Marlin/qr_solve.h +++ b/Marlin/qr_solve.h @@ -1,6 +1,6 @@ #include "Configuration.h" -#ifdef ACCURATE_BED_LEVELING +#ifdef AUTO_BED_LEVELING_GRID void daxpy ( int n, double da, double dx[], int incx, double dy[], int incy ); double ddot ( int n, double dx[], int incx, double dy[], int incy ); From b46a1b6360682d5ecc92cc529fa08dc5bac6c421 Mon Sep 17 00:00:00 2001 From: Cylindric Date: Thu, 20 Feb 2014 14:20:27 +0000 Subject: [PATCH 184/256] Update the menu plan document with the current menu as per ultralcd.cpp. --- Marlin/LCD Menu Tree.pdf | Bin 17373 -> 94148 bytes Marlin/Menu Plans.xlsx | Bin 28860 -> 34782 bytes Marlin/language.h | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/LCD Menu Tree.pdf b/Marlin/LCD Menu Tree.pdf index aa95bbc1dd6b5ac841a9bdd8904d35ab0f4c5236..72b5911dd719830999dc6d9cfedb09ee1061b128 100644 GIT binary patch literal 94148 zcmcG!bzEERnl4Offnue&yK5i>C|=y%T?2&T?zFf=ai_QyhoXhz?heJ>-R-3BJ9}o& z*)wzI`{N5F>yg{9CkyWDx2P3G#hKYyI8c$O>!2@GBsMZuGFxLyR3tt=fU3J47$9Qg zWMpM)4p1~Q2Ro7hq1(y;StA>BIp=I%2brW1)S-hZG$s)Tu#pqQ)<)FG2}~!-17u|bu>${mvT?JqGqSSM zLVuxRa<-=b4+%vFTT^Efumj!m3yd5L1jYo$0mc@_5&AZRae^s_A%hWvaf7acVXXd| z0by8S*kIWI5dt)_|F4Swoamq2|D`}sBpkrd0{snzGT719*}(+t2raa@t&P*43mX~d zpP~W8fn*>43_8yP2QqGU4i*rX9<;JhA5ia(WE_9FkZ`bdw)@9X`D+4D0jN3{**Mz$iPFR! zAff^g1-n2@z{(QBQ0uBj#*R>tzYopdnK+WM{&UiQ4F4l(afp=@*a0AJ1;tSmY+`E) z2FQYK%$+RA*g4ra|7bZnL7}!rMRH58%doZm-GJV+g3#wWHrULVb1F!`YWLZM);dfk zjnl>>N#DSV=%~Bw=fQC~pwa7oL^0?49HW3XkI-kl=7K&_^B}LFSV@g&1N9Z(m)q{M zi#X}WQ<1C9%?6CR`X-D^+lzxvgn4Jq?G*YHE&)Z)ND#$Nd zh)?c_E1)_{2j>uNOUs(X^6Zy{w^?=8B1?Tv#C6-kj)hlB_}@x0l}c!6xTL^!D0+@qCKMb zV!4ULrAyyb!wMQAm!pwiKBTlY(i&feiMg z+u3J(6vg<3mh~%%#VJam#byQJd1l{>oR=$eF;s?SaixZL6~kM`#i&Hw{nza#K(i%5((M zQi{{{$aGIir>T#H<$Z^0otm=%MuE&>#&d*?@d{eTbI+{YSE$cOMuTRn9uNzgQgE%a zy1FI-k!}QL3$)t!`l{tx0vw4+l9G!$1GW83 z-E_C*_frNmc@ruNF~nzC(#+|ZCGIYlF{+Eft=Mbgkn>iIYPL!GqfCgJw!wo)Y?f0- zHlkr$S00A;tmR8yiZq=)<3)>#a6oZO4Pd+hFE<6Feab=j%cMg{&#>q_b$)MqUA5e; z?_Q4^##f)NhI=JSuS%YN82o;Yrm?{16>-KdmqBVr-=G)m-_uA1@6M*qr9M#l0FK6*z>Tj@LQ0 zwFN=h+Uv6aRQTzWq<&5Clu}>XX)Oeh7H63AzzN@Qstx6 zp*c#K%Zg)!MW3-NReXffTBu> z@Dz(EM@N8%Y7qAa5(n|#mk8Eul5sRWmNcLXP~`5$#nYR6@lgn(H)?Kx5hpNRKxib0bWOVcJRkMr#@hlm{p?&7orBC&H)BENW zxkGx{(k(M@t)DzXm6GX5Mh|w~m7^>(r0*$}3xs8*lERVB71Dcc*m+} zt%1hOU?es1R6aB*gwb4G1(8q&O1aD|qe<>?Uett8^{pJQj{2&&`GW{-j!RMkS@ z+@|+iUN_P$FL-Gce8{-~RYtuHP%)!+gEu%Ie!42oZNVVZfQdyXIg6l38Qjoc@*cNB z3MIaPrJKpCcD1i^**g?#;UhR_8coobxi&vyY3MVF-pLHFbS^sW1dUHk4Cyh+BbL%s zi35cT#tJ0!iU>V)l5a{XPI$(^2VGbVu(|>8uMIUwcaqzytS5K5@QL0P?5k|an%u1+PBh#~EG`%NM0rmE0z%+@s=HFb{} zsyhbFX~F$vejO#2LJkU|jAsN-6YdwyuOGAq7`E0hRUO*G`G>z{rrYA$0v5s?>5Rok z?U^QugqN}4Vs5rB;v@j*R9Hp8K5`hcE#3Zl#jFnyK-RVOAuZn1^urZ(gi4VD_*?(U z`}n74A|c@~4E{uq@953Tj)>!FiPz!%gbUN=`T;re?@CngEgg8psq1soqTVs6;BT(F zNQUB)zq7>PR!ADXV7Rsm8ja3u5&r88$BnWv+&$t62@^x@dA*}IIGU-2Z?po;rmdhe zO;Kv6hMsHb_mrERe5e2{mkIuweUnX)U{5nDGBVz!no*`9(}gS+O7LzAvpD4EaQCm^ zi>3L8eaolpCDjA!&A@xrp0q<`cZs-PL=PTxsx@wfvr54*lY;G|548{VvU3UKT!2`a+TR2~}%F)mM+Dp1BDX`x`}q{X2o+ZwPrs zulCWYySh{2$Eyl&nxBZipLToigQSs=v9ZME6Ks})ktqc@4~?$kp#Ho4w1s;2fLnII!)$dm06jjsUU zk}_Tnl?%ak5x$6=eVk=+IU5WC`^Oi>aNuKAi-!wK=ZSft2%q^S2i#I6Ffr`2bdyJKTJl5mP4PW(YX64keG??)!=* z8Lj&MEICzJCupw!5T)sN?cz-gX0Z~vIgoafFO^b4nT&tE#^rI1k}hQu+0MA*{4qz5 znMJ4JN`s6Z`h9~B%#(1el|-Tv55ovO7eS0iH7tD@&mI2mrH@1<6*krA<=F&$cXoJpq6C{N&C_k3l8CT4LB{Nuh>erQywW@zL>vZN4wG1W$9{PH%(9 zGC=wv_)YR=tS?m*aq7OwLSYKNyCb`d{3$fon6bjWjMH(>sHa9jUcEDCw1ypEc9Wcf7cyC%7s zWfDDKIivMOx(R4yq7?En8I&q=R~O;_H<&hwB=z{8`_G4UjMAZtPk$jRhYrUE_Iq}#51mywrsM^VFNVT?&hu|FkDu# z#rj8z3>7Y`d>zYh7N2&ibHgm%ZP>lZ1l*jpN=6MvH{Mo|y%%d(n>c%{_;xQXB9Y^! zNLBkDkV8rdqTZ-7nJOdX6p&!gK3hSubJqxZHFRz~g-MzMhB=5*WC!9ibxd-}^@8U^ zmo1`p(UXpzNBlW3b>+L;ZM|^H@N**k3W307lJN0tO9gUK5QEcNwwuc;phaG&U<11V z-&nRLBO=_Eq(_@iqAh93X*?Lu_Z=`ezq@SpBueF|F)z|L|64fOO4r51U3gEVe-?b^ z?pv#$aayyL;L@c>PX&OOGpfI>@-!fdFW=WjdeWTmwK$(l`4nrm> zLfn*T(~UN9BPb5nx|0IfpwtV{C6PsaMbnsNe@qZ5X{p)OFAyooXmujiDts78{NvC--Zejs#`sKPB6{PcBd0VckEWItp-SQca8pmc*gs)56I)))H-d5tyfv zj`U_;P)~Hrbbb5E*X_zxkhU!zSu5*fie9HzxBjE?8BOMb9{VrW;UCT7KM06FZSp@_ z&A-TwKOHnc#o5^D5A&f4B`p40l{c~mL%V8#u#qG9F9{)G5m7NQMrbeWXlrHU2oSS@ zwx$ppbASfKM##ny^6&FM(xPBT69(F6MuQM8?6v3Z-$}{+_V0v2y?AP~&e& z5GyM{^WU_9P(c+Zu(di=a#>{}+t7 zIR6dc9qlh;eLGFFvDt zr4B85ssyQ(0CsOdX*E3_XK6i#CCwj|QopYoq~?rcn6H_Sy)oMt!Ev=x?QPZ6tqb+4 z`!v>rv0TME2jzd^jHX7YuLg+V*g`xpQIVzN0tes9OD4)AX=;WDH z!%Q||BP4b^QIv^RiV;43Nekl*3kmH~C^S&Pd=@qg4Cu)$-o6D}DXc)8+ zy{_E`N3S<9NpAwtdlKHDh<>ay^{A3vW(+)N42*C_=8R05M>gS1Gl;mPFy+Ee)N7YyQN5QVt`F)O|)Q zi?-bUfp-J@w1gK1gWY~0q?4&5J%c$30jiq!1JPGM$6ag|NC6JTYfE_%J%h3yQZ z){qmGN-sprtn9}_;2x>|#-ZiS{%$0lsWD zb3Is;OaT#JbiRoSR-;o%a(8%Qi{p3EwUa4)#Xva@xWfqmzzQn)eMOt-P$Op~i=k4I z_~IH+OOX$ajG-r%@&OB(b2%q zxJ9B|GMU}zSw@1>yrqCCo~(aU8u9#{h-5M@rio-SH>UsYfNnx7?RkvAE&Ubeedeol z0&hD-)xr~GaHwVhlOjefvI$pQU1P^D>@wPXGY@r1?o}bpZq2?v$WU$`gP|(k7B^|* z-G6#CcQvz>;;@rs_lu`cG@+~r6 zGooUIMYbf$c%jd_@NCXU2*!);MxsnL@J06KHnfNsRgq2&lQ#$tN4<1J6=OG4jX%e3 zGB(trgr&t=Lv`_EXhMm4_LrlTKIrf81XLOLoqC$~*+mFXP&Lx_Sdwq(LgMBydwkYz zL)r8iVx%Ixzb`c$lMw8fSQDx6i`ZvUV^M&PbPnBhrUdo`IObBQ*G z=w!|ecRcju{UV~3`f6q4b$dP+v$wgvzhFb!OVZ??Fx@(EVzpSOi?~Sra_vM7zGY|g zIT%sG+o`j|>hWQ&4YZG%>Z;po-?9@;h5h zF2&qv`MQQ_(nhS*8{T>J7;#(3_`W$$0fTRYDYhs&hPDDTE^jjc@~|GBW==$DHEOH> zyXAK4`gnWmq)pdGpHINc?dkTadGI04-1di;*Ygoh>*M*w=sR?`Rfh9Jg_W1?0df6ZaIr{lV1{`Kmc476mQVtyYz`T;s;K?nOb9PqH z5XffCNH1Jlx4-FR{e&kPVRCL0Cc3f-noi)?+lnanE-7_u+Q-+s+Emrm<2&}jGuw9^ zpOpQ&otj>_+dn=zJ-QoPT)sJ>{~?!2A)#>!LoQa2K5b;qay=T6xRt~P4?eYkYt|_a z$MH%otLN!>hawIacii2+tz* zxPY0hvHB3I)uN``fgZ=G@kdk-I$FXR*q@(1nI7DD4h9ztv&3{!^)s{%tB|SrDp|#D zO3#BF)si64#e{15NhY(6{Vn^KPT;5HZOT5=-hDyAI(om3#m^;cZtvXgJ_LKKTZ`tasgKVbm0dHD;Q1djZWhS@srX%;0BS> zxSYYf=|Ej8J+@u_%%u4&XVU$MfD5W?Dd7~~q64nVys5qo`$OU=8}<`Hc7LjjxA|bB z$Ae`ex8JQMu$U{%Kz8H#Q7RmqDw=DcF+yYAD+b3oA~Pr>vvZ5hl>tsG?ygYoa!=r* zN%E~8o?`Ugvl1t)uP~d(X>Md%)Xl=t&D!RR@j9GC`8mbaEAQZLUXSlleB#6+Lz$HS zbuiu1)upQTZ@C@KfoGh+;V~I+$LD?jU(xP`_7buozhi*>D%@^u>?p77af}yz zM&l}S|AEd@5H{Qit};u(Ey^{>X5sWKzvSlF-~Wf8^HovMUxHf#1y&^G;m+4Bn#50* z&Q{67FFUWZRe^xS0!-dg{AZ5;B@!)N`5PM;$xU|oz@>Q0?5?Y;J;y! znciOcp(#=e-A#3_yK~LA)vwd{u>7vIkdDwCo^N?!W59PZI@nkBpjqwiT6_XZy#E!W zB6uPYWVL-<%AH|S^nh1==aL=my=~49Vg&)d$(*v80)M>mm8X_vqiXMs>97CfZO#U= zF&M5+c)$bV>vUMk@05kMcPp~vdlm!a*{H_#G`Ql-XQ9WX^xuz*%&?6@+k>MuwAYf! zv~JS3y_nxRi5L5YypVbEB*BK$WYAcC=gL$H8h)$ZK5ryBK3?kVShsD`F{epkclro# zLAPxRbPTx4=o#BhN_0ondyLw%VZX{*)Yz7rtlmxikpewcpdfMIs-aIi>$BAlo01(+ zn{`(GP@4tNgA|#~#|pAt!)XgzvMv}2=gyd|?5;3!O)E~imp8GPDhKN~;P#U{=>|OXw>U9(2P&X&wgIp+dlc}^8@7pmug`ursYGmLDsa}X#c8u3_8&f# z2`sb+l}rOG)WZ$RqS^~?#qKn>w=B;Fr`hI++Em>LB-BP>N9;FeOHC@Je3Ztp3k`p= zHV$K2=n&D?XtmyDV6Ll1XcUZ;D*Kc=*G9KWT@XrbIn~z<@s@T2R3si&)0wnmwwyAw zx33^)2b1FhbhP1qRUhE?1B)-pZT1AN=6VnF0LkC7mb?>c)Xv(({RC}Sn>t6-m&{X~ znyNhJOw#siBD^D5nLQ#WTS!_!&ORkPOqx9cn#5j-Qu6E<15VrzAXGAY~%M6Qi0X{F>-)j8B{41U(Y zN$h0VOzXbrrH%9)chy}A_&gaszWMb5K|r1)nzCZ!cH@H`*E^5Bb_)KUoM6!9u0ILW z7^jEz@{GEXwd^#fq;=CI4#3)Q;s?Gp()bL*((0_W)e_%yna~o)WhM%FYh2*Bo5E znj$#{(YaEYpiZ8)>U(VgZMOC(PpCaj&Au(ay+#EMR-SHq!;^0JOCMHj^mX+GmmfDA z9yYetJmm0yKJP3w*SjX+3NB3ux1QDWM%X>vUO(Hk__%pJWa;Py&HBC|`U<)~O)oCG-q;F2xwz(fL4AR{V>Pta>+QAcr`34-iWOhC zmjkrZkmIn6qi7ErJ9=2!uUq0ztq=o&x+$Z+1p6O;JI}yEztM)}MM6T10 zMIPlUqdNQClKg5#g-@4QnVFEu8Z!?+nNf+oJxYG;Jag+yl!#2Z@i-C>SP=#BUGCRM zFSD&)M-H>cjz>tdB%hAFXEIHXPNzq7jzXrNm5&~#Y^0AIrjA99wkAnXMM_S|W-X9H(`5+vLj4gRDInVyIS~8i*&{!q!-GMYo`3!Md;QPnfA{`Zoqw$S z_Zt7$`6Ky{@jqYxH>-ck{J(ttv(^7;{9k+gzclp7{(~6%o7(#aHTFO7Kx`cBod5Q0 z4;vXb2M7fE&$Q5CI-(br*z&XQH2=+J@^3_P(~cOs09GpUkDGm)RDB8lA7Ni%NRsto zqXvI|%R=!UuIqI>vMIU}I!&h$Y*Eo?+U2nF19Ws-EL|{q-{y#`b&haqhtUac7jiMIdPRs zRHWNK1g7a6PbsjAky%m%ivDuHpJXnacU#&-=JG_onygLt!HGcR>#mMtU}N#N%M|8x zQ0Cy_&}2;dT9P(oL(QLZ>3X2@75rWC$~pCWO#gRHR5P*h;;{0Rcy(Mo3$Y(&nKzZj z%^A9)JJ?DHCXG3&?-y^!+0vgP1ybwdcjWUwBI|yE`;9ixj&ch7VSiB&*(#|n_yvQ? z-<>QYYe&Yn%k_}XfP}}uqp~7GYYOLi7A|5CSlQ3@?Dc#5w&zm|z?)YS>H7W=&wwY3 zG0n@pWpy!YZ7~UMU5I2C;m4!AH6{1xOZP?ngVUaGiTsNO?1Jv9$<|A672`|j#yK~| z$i(xqy)UizBlrxLC0yZA!uggTcA;^okcM>eWt{uP3t#mnYorF+@BXl(?|aBNmA#7; zc}ZxI@$GT2d$3*NdI{W!_S;xR*(Z4h4JmGZX(H%3hoOpZI*_wHw$r)OGCW4!OQ6M^NaXLU#C_k zn@2!m#wFJTh1Y_ATj!GlsWqJKOH#?~zZ-irKrD&AUYDUzkH$-H3UIQb!9eO0^QdmW zQ<0F)Qys`{mn0T5DN475yt2;ewZP@5GR==(S9hV0WSeL6Hwo&->cZ-d?}>6 z@4FOMHXq6@>F}OyukAeNC%+5Rn{H@vr{$_Latx?$G1O%_gjY*zm3=3F&6`W?ynPO6 zdavQN;`@}_hH08K(CC$PPUrHHbGXtc5sc0i^Hp}i)j<7xQu#F-vL9Wt@M2VT5gaaQ6)WNm~^&Q`6Tx-$QgZ2cI6w%n&(b#0mYwGiH2d2I>TagT+Mu9N&u zCxRC9C&W`L%Vm7K><<<%f?p59t!MF`xGLBjP)kx-eRS{U*ueSJl;Pn>$l@rZoKDai z-UY(e*0!lRxCsdVZg=G*?6TF{qmbK^%K0Sr{Yw8h8z&IdhqG&2mndUO7)p3yTe*Sc^MFGzsOkIdDzA`5lBgE;F2dpwAbWDRWtvf z@{)IatsA`L4eB+rH8nw!S<~41FmQMrmr7dTuIGnyCPBsW&V0_1@{_}%jk?jO^UiQt z@n~6}kPoW5%n!=uh1jVK0w#4$#`Na!+#g?@@%uozPW?Y~gvjFr0W)PiJL>9<$Vf7d zjyW6a1GS)mnR5ri>Lqbzz=Nv3dDHyz*puNCb0lY~=GR?~t)dbpfOBcWhhqKVvI>La zchXL-&YKO*EVm#GxpEg**Uil)OyWK($?vmd0P zI?G+*O94+4nEOElIo|g6Ei7DIO%@as$JBxO6gGvS<0KB;n1jEi;Z__Kj}aNyJQMr) zaTO};y3Vo(%1)n#%0it0DHaO*QOmPF>u3H?F7>I3Z1&2ivjh7c67o^I^b<{M?+@~8y#ZfRlZu>QWf^NT5?w0QU18S zjRt;G#gLM=UXMh-k)!JqUUxTy+R{ARI*FJWZJU`3`dm%Ebgg!e1Tx|^pB0hTQ&nfs z+C+|*XwChij25WBQ!(u1?Xk~SGzv>E7lD=hbCsHl+>L>C(c4G{v4{Px*heM$M1e^eX1v=-vIS(dJ2Izffa`7M(dp^0N3KP28XW&WQ5G2 z(Z+d8a&Xtm5_P#lU${3J=(emkyvrg_VvKuZI@t0TEFR4I`wY6eo?CHm?$UMod)^Gm zL?oJ&bR$5{!p9#6UCo*%gcVRuC{;eMu@*$aD*TmW*Wi0y<28c-=WN3Clt%m+ zV|WK!)UA=tHlCzSH(TWwdU(P5Zl#Q^A3W7=9`FjI@Au#{ZMwc2uAyXf;^y5WA>hyt z6)1<98IzRo$#|N4I_R5d$Q`F0TxT5}XirwI=SD|v6L^*;;tEmuvMF>-9mn9#Uz8W0 z^(lgsuNcKq-7G`|zInK>{c!M=#3p3tv@s-(#>k5G^TM6XdwT%AV-oebuuNeh#BqMR zz^fM<&*f{Oz!%(2rcyMQJPTZ!^4Btt4lHIH zMA2ZIWQGS$VK6I~RFUjslyESOw`O#u<@e}3G21wznTC)am+{|T6-9F;CWH=rs@iIO zt@vZuS}YR7XC|Q)bBuS6BY751a8OCjXLph>twWr_K{p&6sG&XBAF^cga@(GudDnfX zp7-H?AWqKfOXdCf2P);rmMx!MR}LRjlLL{cJ9|N7sU_makzcelVq8YXDq2rlh{si- zQcH44h4-KOudZlb+PwXC0dX&4TcOvwzkx-ehha^NME&KpTnu3#S%P!?8HPxWR2;~N zjH7&NRvtIwut7dI<#6=GBiXP)-kpBx zVF5^L9wdI-9&#;RBayl^aTwb}Dd!Kefw)LtB!d?7-BnX1^4v93tta@XhSeb?@n+$m zw0!rEsd5um@!JBBqh7%@G5@{4tnIOP?d#O0`VHn80R2++(0pwnCQYRGz z@sNsRkP8F#Ph7_L(91>Z{WiT;vdLip<0rf~8jQ~mSqho^GzWAr=0!ey!w_}*dO{we zL;HjGi{BAy$n1Gp^&4|Q&pg~5%PXY$O6M=y-x$LA)KaJ;2d*-QX69(X*$x?n44kYr z%?`xi&srbFd}hZbK4*CnJ7j)i`snp)9W(yU?qaP~rMx>+r|yW!`qPFEm}MX<_}qGK zA;G(9#zrB0y7rXC54KmrR7+{VtaDMTt+ z_ImM&<0q&p$0~J*(_kl=V%7L}TjgG>#H(s5$AEJ3T;4cF84_M-SqtzckD6_4rnC$mCfzLfi?jY3XuJ9n*$4xGX$j!J}Aw2T-PN@$q z(}H#rAl!=UpxsALzJhqC-X}%A^7c-pU=KG|-D?GayDGkO=oYv{27LvL+@v z(2HtQgq-y4T}{kQ;GeigKQtK@G{PMVhk6*(i55OTX(&_Pr~}x=V39q!umMp zu`#%TEo7VSdexM(I9Pat`5ww<%0{+L8$|Qo=My#aPPZrhYMJ!aa!e zxIpzjJaVwGH2)fP%($>PB0V}#S+XjIf;>lG&ggXKPkPy)^n5ZN}q%+Kk|JMAyX&EAvYtZ zAr~iyC-)%dAuo9^_7+pPT%E2LS^F299ZC9Y!7nwd6{{$>=#MbZu&oG%?ewR_w>ar< zRz6p>Yplwg!rc;i!OMSEXtzH_w16k|kNy?B`uf!TRNxlV4Xp(^>Wk~I#aCigwqLl~ z30Iv@3EZ$-V59t!+GSS7PGQ|h_z!~GaWT5Q)zR8rY4bP2(I%@ zH$(nSJPXFW+tcvXg|PFfpCe!KzMjf>r2t2#0M|lrs`Pmu2`@PzSgMvWeGlJ;1eG!z z6Ehe@pc5X{AO~l%WEIHUnry2VX!1J<+lB$3{YUMWs%bE)Y(L4~yY;rj>GeVNvYhY9 zD2=m2WF$iX>rM#8XCPA2irsCrD<}ZFAuLDelng4 zVvb!o3xvN)i5&l&!tW`+Zq?VV$Lie5n$~OfNy*1f&-nG(%Cz|p1_pg5tY0un*q`9^ z$6!bN9am}Xa2~PKUkUn={xbM=vkLkE*ZO+JFK(6al;al33$Ya@%YXD2;wk-ycLJ}5 zS4~dQZ{K^tJfkcl_`;riacyTiedk8l0=N9e_VaA}r&YC6qz_2?@PIG4?Z~U{r$irM z-}#HIYMr9E5fHsm_(I!`xe7CfcKwBB>@5j`XFEwH;UO%^7|d@&S~nCcglIpBU!8`8 zZf~vN(EOMU+1+5QU7##nDb_zQ^niZBe7wvV1B)>{&(opw*aTwwxBbt5QGbCt0l7-_i zL`p^}5yDP>L*pl{_=@K9nIRD!f{7459b9fZog%EbABEyuq+f4YiBMi^__dRvnSPO7 zg~d07*+rNTG8jX+gok{?m4u@w!@qnZKjvTJlf`%=h&|wQg7oM~9_t%olwN*)mS}LD zAdY_aB9WIlGp_EDmZHhf(-xIDPO~7SFd6O?hOdc2cyH^2oCD_#g2SxyInev<(OOsf z?0JG{+en@>{Y`L&pu~srdN1i~maD@7{)zF4XPKV!sK=mAKWk&%rvv(KF`5*A8*(_x zqwhY|J}EwF&(5`_r86B5FM*b*BBZk4EH69N40)!72O&gj1UbbadXdk`a*hxI=5K+u zA!ZYNyH}S8+R|L(NL>dp6xS>TP%b)M{rT{rgwSpic+^~)=1tF-{i)W(on*cAyMa$! zU7}5INFSi83s<}TB@$43JQ?)}zW>?g{`gdjZt?(QUBHZYW_|g#M=MWH+CBcqq`c+F zdoyM*!p}&-;m!ODr!TF!lgYF=I716YKTr%iD=k%3B4=c_cI#3=!DiWQ`?VfS1=JSg zwu=;HXgHs|dmbdF&VvS9Wtyj6*F&xhqP0&wmZCUM@57s3lw>fE9-I$umk|KRFFHpn zUT4X{SBi=`}eyi9c%=48f+y!N{Xq14(Yeb5>*Q3!~9e zMO=L7A$ZFweAdk#yYtGondhTWskVaAb;6{jEnMsq3O}m)6Zey=>2%>&G19V@36G$k zklXm7AVodR1AKzAr%@#yhHe^|gD`3FuzXVnTMC55RVk#)oi?=kdD)`~g>{z##kV$} zX^fes!ISjQ2i8AWln58_kCoY9AGygbFNxJhfmOr@gPAJ~9f2Q~++(=~Eqn^+UG60n zn`-V(b%y)-wG?$@#4SFrv-0p17UW&+XMZ4q6w?!9C1Q~DO!8hUPI#cII=#XzSC!Fm z8UT6D#Cz!_tflHSqh@S7IAt_t^UN>eWgU_lp}mWWeET*eWLhGNH#=G&t2oW=*=H*} zFLr3;#y~SQK8rvvLHk4g*1?q9ihX=$vb9)#u^$U(OIFSr z*Bt~NKNks3R*3WL;hy?1-L5R6s;2QgG?y4Xn3lW~e2yky$hN$3zl)4U_n_l&$CaVk zK3!9!_1^hgdHmA*gi6v;TX-Zho$FgdCY;wC)y(DJG)1^xinedvL^kbB%sT8}?>hoT z4z8TcJa@{>pwAxj+&{DOWVl-DDyH+(O&K13E76Wd$S*)q70x><%Oq}jEaqO8nA81H zc%NE}c(>FVawzETmTUeiPbdSk8GCB$gul{=SVzFeS`FY`dy`T+)2rk0uFQy84?f@J zR30+hT)7n-?ia~;&7_+*I_bnh0KKF8oBLrzymHMTU`64`mdCsJ^@f@$5S;Bcll>+oegQ3Suqs45eT3OSB zk3GEF%j&S&tt+LVgG3LR6RY{)7QB}i#=1s}{3-ajsF!PPTeFsX&WQ&tcDbz55|UX_ z&a)wQw{83(moE4FkRooN_;&GJL5Vp(^NA;)bc+PN^?X6J4R?Xl*41(p#x;c6X})tv zJp&PYWxrY*bp~_Wia*~ye zSqhA~I{12$)OW+bS-NA8wmT=n!p`O&TYPZ^ykE7bnW-^893;-bQo~qTb)~1F`b~>%Uo~!g)UXmB;qC#f z&7|JbH!zE^vL7=r8@w8F*~*s(4_9;fN|S;DEkExfpJHO0eSsjGKrMJdOO2Skm>k_( zSlJoEyP$=@_p{ReGmCNBft;&HR>6%bt<1`zL*mnEPW@hoM6zYJPW}27u5(tfdY16g z6TLSV`yR7;tJ5mU7j$IMt$7K~v@y_(pche--a-m5^@y`eJNx!QakrSfcWkSm{hDe`iC!fQ99PL71ALZw21P~jqWXP%GQ z+M&d^aNs?RE3jeW2D0}^H}XKSojET!|6V%rVHEpAsc*grwq3qt0G-N7dqs$LKqFmFL}*;Qh=JQf;@3 z=i-_yZN#PErv5t6XNn?(w&koPYzrigbNoZwFcf|x)@0$-;go{G^2qvB@9+YD143;$ z%uV3@%e@FAr>CZMzPY>5q`&LolE+K#{xIB)9@kJ>QMCMbO~IY}G;M)WiTP+l60zJv zx_wa*T{G%1CDn$M%4_0<=@E=iGwQEoyc*78_y~jPASh_jiryTeJ7R68R&LR?5hIlRR*xJy1vIV%AdbS(N|w%~kwuqJ z;#c2BtQSEt{1l0@jxiaK+(--$0mz5aCf7+GB5Dt2fSDQ4f95k)gW(Z3l|zkoAZ54 z1sB_9#$-pQJGK2RS004X6G4pW2p*+Xh@Z`=TgCZjfh^v^54gPHBra8NK8@+F+)^V zYozF8J_c)xmrecGGPm9kte&odr7IHx$u-7EtqR~0qDVoB+^g?E33<|S9C0UG?evjt zz1qcQ$)!Ra51+3#dmhVN>|HYlOnVHt=X!PULNTQ|lOkiZE8QMwpmb^18AX?B$ zR@9wF+9i;YCn2TJ<`-s|5Zm6AY=J3eVqe4*O6$OB9rZvzsetmCe+Pc%2TjShlX92a z>F4i!ztl0(8IP|+_BseElIZuR>0Y12H?1u&r0?vTQRj+rd__kS9WtDuA2L*mgcpA{ z6Pg!`aas}CTT8PSflW&>!@r^aQ&^R5TVAI<0vU!VwZ=Z|%rxnvs zroAH9MB`7~`M*n;gP(%Vh)a-_-j=5F(niqk5&L%kB-X#XVRI zWMdI#0U}l+ZzH9is`ItyU5r|*tMcW`#>*PtS2?HLcba`i7-Y50RR7sGBPHSz9GIfT z^ulQN(l8QvD5mkPv2bN@NS;`$H|ppx&?pk6K6&h0)&jPZU@qf2yR@#xBex1)Dv_mp zFFQ$7Q;n{iXJJ9X)p}AaoAtMWitm+VR}<-hAM<vu5bG-qtH`+E+V##lXzv`PuWv^lG?o(6WK??V^}+cHT4fL&BrB zc8pD}s2{y|kKN9nMEPt$--S{f^=k05@~L2o#<1^l1yM(nzdrJut;kwvDUSV7U!W~0 z+ATqjd~(kaUtQ3B4&MyuBkB{REvGZ`ZrC%c=eVSu_ZkL2GHKM((cL}MCT87Um{^m# zdLwII^4!Wne*SFhxrI+&H93E2*d1U(3&9l*w0?39O}-Qi@|SuSWW3&fl=gI$!5e@_hH+ei z(rqWP9`nZVyAYl|ola*Ef1x-6Z)>*k6*AoSww-|KgQ*;$@1S0K{qEhThbp&XqQ!-= zP~W{fp>uqI8sd9cOY>c|YF+!-^qRG!GiKUD+70f{OhXorO}%3Nz9kDDotcs|s9i#& z-+*o*F=5v9DQipPbK0@#E$SUN7GIs)p=yfvTwG$LCCz@th@QO)`@~39$2-RL9)3f4 zYIJD(l-Pt6#iDd{jUSkO?bzO(b0?$^o|)>`DY0in=JcKs-BbG|@FOjz)fa*WWp+r; zh#PQ)-W=X7F;R`}SIe+;hlwXMv_U<}huS6{Ffc8}%TS2#c~D+q?2Pvqdygevc%NN4 zASNX~EG#}H#;0oetrs3#yH-zO3CS_-Qxd|$5>nd7BqxNSeoMXOY7OcahN+r!fZ|cV zXbQocB}-_xpl${{x|;V`0)H}$3fHRm|G4`S=%}i!-Fxn-Tf?n+o-$Obl2oQjRjM*4 zl~fW4frQKngM=_cm=OhmC=MXn7!d?SQ>#{x@Yfw_WsV^`|f??A|$$u|6t-Iiq-^V zo;oj*sE;XHK@z485UiEg(2DEI*FLpmT3<=>l=_C$8}AfMZ0K5&Kf9dX^VHf>r|po= zVNg79A8vjC{WMN@oDZ1W<6!?@m|LEyKEcS*XGatYhJOux1a2ROi3W!XeHqaqiBi$T z@-i&p+9a`=2IHuV&GehU2MD-8JsCRB#F6p-O~^TX82$3kLMH2o{+Zi;`BC&MAuk@s zz6WDM{C$GXr9L*7Je^DCEN-J_I$`oAPTj<*l8o-Uq}sikTy-{Zq5}NzF?9opHd2b_ zP$RPQrNN5vV#KOe=lZ3iSg96A*rK|`#ix%fq*qTMq0A!l6vn6ToyWOZKb!gJ6VjJ(TeD|M zeS6>~{Mm^W^Zw^s+cw&ZI>XT|MEj3}7jhCtEnwPCFgfVRF=whXl?VA8JEG?cJ+DC2 zkV*nkgS{@*JF3r-xtakpxd{Kb@x-xL2qsZ6kyXrlWw9Ig z@E|-*!uVurMQhgr|B~lhXCCgn^%i5W=Y~n^+XLRY2X85Rpt1GA!m3$CHgn06)>)ey zQjnpby(%|JV=x`GJ0?{+v%OhPQ>b=sBx_M;iCWihGMYSor!yxr)8;6tok=*Y1P}Ec zh_|gw!GKOpEZf4%WOA!kZj3E}l?12%xY&@n_LxPab0TUN*rPX)s1L zy}SBA#LG#fQk6<6<9Vf0A(tS%UWX+ttJUgs21cWnNQ|HrF8(zL`1J6rgF zPNmiJ5}8^pQ^=d7vKAJ#7${XF@}@TcCg%6-SMqxx6$8!O#PfW5aii8ta(yJ>C$d0Z zB-MM~-<_DU^YrfL+6~!zZv8i(whKK4bTIkmuDCUB=@ z-XHMDhsOSQB+27pT^&@dx=seiF6APkrmmqcqaj zIwLCjhKE;AE7E1}&I#T1jXXi|WjMc*j6YtJI*(Ch&@hrUt3tEZLu-j!&g zft*F(@XBk?x+aZ~`Kj=w@bv|>UFiE5$q_y$>_A(EJJ7f2YvDF@r$9narc9VeHOj^` zN7N>xjd2+i;OW{O=Ap6Q9|Moq&;srYj%a!H7z#*`w9{xZ*<$(?sw^ofj^(e4WAkVm z4mm_cLx}2mJcU(+#0g6jo-0^)_rZmZEW0H?G0-+`l1o@~N(hzy73S@>drxgGXW7Rv zmr%KA3en3)53+lK&Zl8LJPmXz7=J{E8JV2r5HEAd@Hbo&3#1-p<=>LYnviT54xS$- z`9CqyU`8qU^yPDGQS=;pG5S8+cq@B;&plDU82{j3g8yb`98B9$8RxWNvb1n|J4Bhs zk%DvTF6l|ZpGEJi)0;-s3friZS7Xen+qt+WL~b8JG^C5?@y^hsK2_UTUf)v?A~}aR zT1p{IO2fZ=QP^^LaPX5q6x>}|eoy(`eQf^aFgqIM+0osb-g#TE-LE%o?!9X54+FEq7QMKO0^D6wlsa@3)OVv{9h_g0KsRHN5K!eQ~ zDIv4xDiZY`giT4Mu6wtgJqz^x>3r4hrWY@NCb`Jr+j{TVP3hbC&f9AJ#a%EfF@KKE z5BPI<+@Is({@g#^hr4Ix5%c%qlAhhRy97{(TkI zx_CrP1LAjeADt3oNZmC-F=ci4UP$AV}F4YHW>{BWwUE!B@3pUqJHPIh8F|7BEPKPOtX4O-``QTU;zp4HHf>LI5n+gE3Z)-3)5!Qv zFe;$is8ASrlUk1XZ&XdpcShYPzLMgJk$EBJd0b5tK7TC@@@ogYBCllfT%i+;A4Lb# z$erzhV-}q*zraOgWzLG|taVuq>$eu;sH0i-ofMDqS2RFJMFzpmsV`57e*4u^9ZQ9Z zUa=WpBTcsNhS^yyt{ADaXJ@r}(&rUS*)%h6?zJ*)o;d3($cG2j@S%4Wd+s{XrzlAQ zILjZP97Qa^k}HLBp=0=K7@@A|I3GX8#Sc^c!&HK_>i~DwgS0(N2{ZLoCLfJKXm0@g z@hBXnsYKSst^UXTFZy5iOZ-XBZynarq-Kam_@fHVC9ZRV$Z2j5#7zXAb`3Joz+-~M zWBH`MWbfivSJC|;R$9H(#JBV_~WvNrp?{Eq;T-2 z-o#0hCncp=?78#zFOx_wYwq14QyW!r-J@1@MfbE?(7o?sy4U`HU-wvH#e(q#A-4=1G?;t?}*yTg6}bK-0omy_7>F;QXN+t#$?T?Nz4t$;++z5uP2s|AonfB zbw-S5b7n8PX^OS1yx8Qbtt!$*R(7{}Nl;rbJAAuOqFJ7eMBgRTqdhI;TxxIG`U&zol-HXy@G$0=jkd)Z+=k+ zq-0nW5~Ybu<@aYYNC__*mm>BTv^Uh}+%UVX+B3U=%xhk7IX%XF-_amHd% zsCbbzudz@VTE5V_SD}o93}W}N=G?k`oLd_Zg$&xhee84gJyZtTZh4jASj@l*iE;*r z){P+lbyhYu+a2~f9KNvIQ%?5fsLYWY_PE6lZcjMZL99rQevRj{>lw`G2O&T_f#jrn z8ZLQSbiMH0=yPl*`t{ReV@S@n!nvcY43Ynzco)N>7l5jxV1pREArHv|eGG3E=;EM} zl?G;SDvOef8m1|n%^&NzVq{-r5IP1uD8;$N!tnW1G!{mzmmuq(?S+J zPUiq4jziYPQ$!r6W4S^Sb64Pkm{Z`5Er_J_MwWuVxcn4qZCh4qaujx!x7|}RZ`vET z&)BuBB%@_Z`v|+`QPkXe%fgwVz>MnjX=Uph=jJcCe^&kNTkmQ4l;i=%KF8;PxerqaLfR*izB!t6uNA5<$ka^; zh)8h&S*bp_pdY{Gci~Ew_)77OSaM76J$-tEXW3)R3)e3SEo{m|eVq@jtK#L4Dpj89xn+gTh0a~cr5%Mm z^Bj%?Dx+HFYrmy_?E#-WP`@N@bCN#L#$<^7nvPpjZ61lqbrPMRMt1^?E(b8h!K5-C zM77LN!lz?bKX3Bb}d zjx7Fv!5GuN2Q1&?Eum&@JK@Dyv$lgUD4f3*SjL&$^q(S=GoR|625hb9e4@7jIK4!0 zC3dpoDqM;2OL64{#g!8jS0*y`uj9&(lK!KV#&Jb*$3MrFCI4+)aR9DdPKn{l1>ir0 zDJHn`bBZe|03&~j=vlW;{Y9cgjv3QZ*7bE9R;>RjtZ3O3eBtsSYG_$pY;qR26}4I%FTNsKgDfk@F zm(Mhd$f69`e74k7n=ghdcD;e1+w-k=-Cr3cHPmkI0 z!)zVZZ8y>F{ZzO2Ly%%0($4q1%yo;Z?Vk_`|FCA`hYPyzX`i-rZbAM$vhOM!Obk|~ zrdQ=9(0z3v;rOCQdJ28>53E?!Pxm*rEGxGrRV}U~`{b&{WJdo8Uf~)x0-7BdAbPzw zV#HD;!_uP?IcTC`N3O?7BaT4&+D_R3XFxd|ohMK_{5&h2`}7YX^Cx#elD z<%MO*6*rXoTc=O+wmw2i?qDY70#$`1OO%8j0?f4ft?B7jKURVkzaBB_mFb?LoS^Lp zXmHMarDllCP4pD4MhERZh5Xmi-FPKx;Z?dDi}}Ud&7$tk4bI;)FR?T~N9SHse#1(W zzp=EnA+I_^uW=P+6t4E!$||dp_V!hmrH6B@*5bJ}X{u(5ezaYGWie5m)ON2k6gagPad_rwv>)bb1Z8 ziZ(%yjKY!i^ql*}BOv83@LYOi7dZm70mMsM;}HmgxP^rXqy@Fm7zrW}zn>N(ljud# zdU?sy_yD*4;uiPEsEV zNesfq7le)I-WSll5QHp42M(Zp!V1s?Jy>!FmjTgRA*`op+n`Ei9zxq9fLu1a1wQDW zmqECPWDCX49Nh@HqeDj-3HnE1nClf1Abp=Ksj#3ZY3Yi`^FjtsdXDpP&Ne$K)6Q?X zRhWYI*H7kcnJ!^6pu#s2GhQQoiS`W5iP&h*kc5*dXxorfq2Lfh!rdWuM?^2@BMNmL z&vOc?RKg*|4YAurxpkV;yF^av!XqrF1N<4uu~4gietn)M;!*P+#4 z?aSG`Sz_L^hwT@pqi*2|2=dddQVAR}7}Q`Ffg{Pu>9!%{k7#A;v_89C zmfk0|^~q$?7#-j^>1nSJ2nRj^RU_jy@1dZ1LZguRN~4gO)Dx6t)~~33^V~m5DiaGb zt@o(iB{}owx{JLQo7ES|oVTc>U2;A!E#zeTpDb)NayD-PLMD%0^OnkyA$(`caH`K2 zlW5)}QR4*Z5R<^t%!HZq`VZxHY^o2<$nbUsgDoY=>sI<_cqIYPvp;RVb9SCyKgVcxSI-S^y~AXH zxVZ=49;;lR4hSfqhdO~;`WeaCfvBb>wx1MVKC_at~ z#!)c-0rJoee?%w8m|^5>A88BflgnjsebCbp$n`**MU5gs9)2RRW91~!yRDc`5y7!Z>p&OuB)f})71kURw` zW*CJe36bzDdiB|7g-Op!yV}|WWm_AJa6gQY40?E?hs3$2vL=|D zFU($!%87WRL-1WSe0L^%*T8f}lxn$3r6m19h#x|^$CP?(FffErJwi$>musa`l~S)) zsgQD9B7S;*EvTor;R)FxVv_(6gnELlVsU_%yck1PYf(`M&s?gJx>rqF>S5K3Qtw#k zv@P2XLOb~Q9AR{9=^4CtRbO)~?nE6b;@nBwubt_V+EQRi7}%$c0$ugNi+ zvL^-nlXJ}6;@Nk0X6DYkt!WnQ{WEUsDDAFI%c$)tDD9q{4tqjf93@E)P~L#lNOV*| zh>WPUS}<+W0|YiMzt#{&L_466NJMc}8&Fxwl+_J4^qeVNRPS3eyJg|*8C~3;GMg(i z{>JuO@*2y+Rl-G5i;TKq^aU_F=>iH5$dibQDPf(^1KLG&7KcM=ae*1~NqtHs=uS*G z;@C`4&mR&g@pxl>KjUsyyzhrXG+wZ2wJISg%@XW6T{EvD(Ue)1o}6t7HcVR3o?4n| zm6+eNCmZF$@7R7vZX_eQC^tpU2QrW>6nsyUkO4a5gL(A8JcgL5Czvc0IA*siQd7xl z65&Bq{v?%&OZ5_9_9P`KR43UTj2sp`0?(r21VMcbB{6l@PnhNFR#{E#{GnA=p6ux> ztIF1<=Pa-8YIf$7C3_nyy~#DprWvw*K4b2TjJD|xUx^EjW=P)2tMgmc$^|-oUcll` zuqw5#obnt`O}-0D<&rsSl|R!;4r^S#N`izLFb@@U?M@$r&%`u&32El#KmqVLgdh?B zD0a~LffQWv!SWASi?k~`#MTka@WZ-Q3|F!;-V=-!`3Ef)6`fU!QfYVvWWvQXJ@h?I zzp4eO*i*BxvUWi@VYx1?EUUSGxkMw};R#g!=T-bYt^0bQJuli$MEI7*Wo6 zBU*AB7|X#s!+_*cb{tI*vEU%Z4>74rt5fjG@9zF;{Q;lww8%+| z4^Qwo22TVhLn5^6OW-r{JI$T~L_ra+7A`IqF5bF7$M>N0C86!}FVOSC%vn)p0tzY^ zU&JT{dt_k&0S{CPCdZ*ZkuT~11t~w2!O&IxJh{S7)EkYWjlzTI@6u%gYOi6rHn40H z`%7HTMVLe;gQ-8kB%<;oY9_-yges026(}R|6?Q9=46dM>QR!4J6;`Pvx_;}cY%i0> z-or@P+v6FZu8~So(>XkHW_Xxr%hmln6T@lJ&LfREIqWc7xU#&cDQLU1Z{NPcLA=mhkh8PP?rYU44>#4=AY z{EPSSEY4}Wd1~oT%C>QVMOAAy-CZ#yYmV2Im*lN2bV=0HH?`-OthnOy8!LhjJu$z> zUn2ZYr7`4n66!P{;aZ^1z<8L*fRZN<8;PhYin^^Ny3ieh&?+y$B|Hz z;tB_o@IM+ix98{(zWmrtTXS00HmvP7q!y$iM#)?9T4U69a~0svdYEYgDuz5EG0`JA zi7H@W^sx6t3|gFwS@Pn?V_1T*&h;9QYXfp+u-8q{h;`Ie@{977%2F&7x@Xd_G|x~$ z<8H(XrMP>3LS?wfl-pbJKOWC&T3cJQvOeQpuCa4!i%jCSW@uVwNO`4njavK6zN+;z zLK#zgf~{?{>&bs7a-!3C4;N;Nm^z5v4xL~$sBF-iHI-#rY4^krxaPq z10W-*#jrb)lBJZB2iGMvq)ytcU(>L)VOIlgAc4>Adc^2;dY8UgFQKJo3TIMXgT6su z)=K9r$P@um7BWF#z6?Gmuy+vV&(N?0V)g8?gvLXTdjeZ_ip z`$~Fx{8bDQLKE9pyrg|aT#$$iahAc9R^3&cRclh~1L+3?9hIr6O}EZ$Uq2-|CnGr_ zJ;CPmPMKF?4XD2sOdTBswVArA>PO5DHRqmGQByG~JgGwRk+~!#&{&+LQR!SptCN+o zmWns-!oG`lN{I(m^fF@P3JDLZ6ezxgbSxkRF-s}vI|jW+@LMT1FCb8vknVTEQ`BD= zZ(P7TUlcyQ>n@~yM);I{7fln6;|0;rkX`tMbjrg>y?|qx%&Y;Mi9Ev7>{6UWWiWIm zDm&f{r|{;?Dg}M&^gRGxy_;98R5aLbvAw_KY z<1Gj2*XuZdpd6!YwaH@FZ?RaECR>tu%W_WVa;IDKBibZ)rZe0El)qh}br)s`_o8=P zi7Hodws0@I^kz?9k|r|Q6?E%o%@QJDi5M(#0dS;cl1cR*z}Zok4(T8q4j+*l`_)5i z@1V0EJkr}^NxTstbsWiJ3M0$E5>gW9Dzj;Q{q6&qjW^Xl@bHe#Hh+~@-`N^~SBb1{ zW2gU#N9s0o_zym|Y?-^XKC_3s5`0DP(p$2&{N&iNZOAQr zv?sYPlRd}FdsZRes^^?`k z-NzLOJqs73ebI-3120H08`gki#!Y;~iepkOW9U~BsU?g{O^hzarS<)e11hs@-?F?% zp7wRzQXg8FnbGabtSfRQ6f^{Ky3*NC^xDTBp1QF;SEJo*Hrhi?1;x_?W}^uxkO432 zrNuCZ#U~gJ^i88=q;fKsDz#E6@7Hjgg6#)!Zirbd2{mXg>dolcQ=+C#XnCXsv~=Ob z>)Xp8AWq!fr%q)|T^5N<=S~P!>g7GtKq6vxN4(RNi~yn z>y^=Ny|QCSWz{j<>tHoT_EtvC-a?L(A%f#gdoeHND&UEEDrVfcIb34T_7|pZ-prM* zs$6~}V9e^tHOd6PN4N`zzvwE>U9k%6I2WA*pWi^MAaVx{isX~%4F~{qgalK9ewUFv zh+n-M;%T~!jeK;PYNda8V*Rcd0qIi;(&EoKB1;r@lZWf%FU;_*2(`=+ev0nPEGDZ$ zW>FF6jQ+f$yV|YOY%rPI+t9mpGGP=K}E3L?1;X8J#9858l_sI6Y<$`RAvdJodAkyLJ~SbZb61!)qq6M{=8ZQ-1& zDvLMV>QKHGFWyJ#*u?-yY(n0PeCCbusC!G zbgVK|31(y)4hDyV;Ftx)D1`_-N7CG|7VjXO4mtG z%6M6i?67=`{DeZG=uteSc$W|HYx!4|2H2)6|6L_fRjAggK2|SPpH%1*0vdwuIa>#Vc)+H0@9_BuzBEx(7ZkDNDhH>hWT zMomhgr7C?(p+_hD5vdlm;L-S_J0F^k4bop3^>E5~zh+wRqOFf* zKi2fv#>aZIK6)3;&5C3#%KG?Sv@%IQd|Z0G>hXWMi{47owa4EcBaRt*7fnbZ?;!n7 z`scqH`sowXp6GmH-xF7}p8!>4FC*HR{mZdWj*X7}+SsodWJ8-_z2W231aH`Pyr$JWO1l zHb#|)vz8&dmG7~|&lJ5ul?A5LyH#0aY3XmPvW7i6jH$Ae(neruG1!QC%=;pB|Tx+AV5RM_V z?f^ETrJZ_ki!HFg+cXmfacreFMvTSn8(BN` zBD-_J$}9)s(Eyu4^0@(hxOLu#>pEy0#WQXtNWOC~nqh>LhBkziE~u7!RHkuuM?50r#0Xfd4$@?0`C)} z^C zkY?AE%nBtV6Zxq4*+MI)ta==>k=8OsQEDMwh%KV=L~6XuE5j zc!syr+VHUxF-c^3VrFeA@o%MLNR4i*s^_^`kJdaQ{Ho%YvbKCb8dd*86xEQL8;LnZ zXg+PUgG1DYds0Pf9fn6r4sjnsw3FM_HC1*Sk6t@jHL9_hmoj!too_g)3)6lIQS@41 zMWO`VwJ00q-;oe16&lB+sCOxWG z*I$WOBB%KN5304L1sG56qSOp-p^$^pp;qs$+Qn*4rdC~_>S42*CuZ0w0zJ4o z5A2N)tyS!<$SA(w?~XB#&f5`_L~A9-qcoRhbq?id(ZKR(%n9mlH?o(guTs7F8bvXe ziJ*l(IjfmW&{iHuiPJ`t@KSuN)MLQ38yt|&FFkzx{0-v1WTSPfM5?l*4peRl6a zPQJIsDw!0enTFN8R%|JEP`(%Loj1R(RHQugnm{#3$=1dPdKG?;<%f^afc1ger_`x9 z`Q30=&42IQo7Jj*uV1OPh0jEpOPt0_Jl$~n%3PIuR+uV6@PRW`;vBpyriopw;J{M| zk1Ef+cJ=-jq9>RJHK!s}bwl(&1Aq4l{jv7Nz@C^$-taxpPBpiX)+)*ty=I&;X>yUV zqPZa!X^YH_8|{%;G!hHOnu;|nbl8sm$jp@p$#-m<{h8eG7AX^vxzd67sX%tV?SLgaH4 zEh6Dy3prQc-qsurwY3==BC%MgEgA_oat{lQUX0V+iiu(JMt^g-F|x2t@v*VFE!q-X zYz(%vL>A&=(AXGiYn~T|NAV^e3IvkJ5jI;Qh@LSXF@__tR*V=AEsA3X!LTtN3pO_M zR?yxPgf?YP_DFlIITYib@R0Mt+Q|Rb2twBoX@wjQ*0(G+#zL@#*+%9XVLudZgdrL! z5;nFq#6lq~X;m~7_98;YxuIaZ9W%wUHMF!hh7i^8Jn9|8xM41Z+gn4iU`yMx#x^W? zQ>d}P*cge&`BV`xbt+3j$ed?M6Kp}y!^j;hPg_$k8dCfWazpi)Km6j6iZuk0EiIuq zUm_*IEs@9qewn;&Kv?Rr!0ln~e`H{t;=#6f$XLJF*b$5^<__{47_eO*j46q>5c$zo z=n2hhZwbbdsajJ)-86eaNYJthqtS{N(89 zp0uT8OI|ZZiHBNwxrsGnRP3y9OC*>&D0~hop7JG*sU;-R9*?$T|AjjERz{nqP)qcl z2|dhO&`L~f49yL;x5NvBZP7)E_fgoLn`{kZ$@eG*egw48gC1pR@4m|(p%(o2D`yGy zc>QmMG>r+ubHZ~>BTN^jLw;U(9&(9L0{I2u1;{gm8IbLQ1M-W)i;!muGa04K&})jAy)}*$ovn@HG)U*K&}yLAbW*c$Ueab*)Ntd zL3E0+BbJGWA%9!^5#+O)Z!$r%Pt(sdnp>J%kZ)^lLw-l|4&*zMp8sK!G?WQax)gx? zavJo6e<1z<_(SoBG{=3w{hIy21DXTCgPMcDLz+Xt!y3dy zb3}6lcvN!~cuaE)cv5o`*rVwIUe;U&UeR0u_VRDM)m+tF1>Vry0N&Kx1omnAfc=Q4 z5=q2Ra|hAWNc_DRS(1TiQX0iG9XMPX4jdtk0A@;=z$_^Xm@Q=kbEF*LlhTvGand;8 zcxgOvf;0j6jPwlf!_tR=6Qzm3$34OzzkgmFiVHI>&7EP1ihq(1-(`e3+M_9 zdi+qHSk(*>)y&Yd6~Y0gX;>UhVFozbXDi3j-Aowm9eoKNrE5CbPZ@K~0nY`u5DQh9t1G6SFH+@Y z;8(yanfUT49C43utpjgV+da&2%X{?V%V%+XRpp)F*HezX%|7**IOo0`RBa@VM^sxE zRDP3KsKQ>W%7lC+sZ;nG_@*k~PSIa@FVDhGnWX~{AFwkkgO19$$H6=vd>$86e@-d> z@IJG~fQ>lk?XQ5ZsYiaU`Y>yJvJZ3JW~@w9=31sxuNNell?|tHgeug^s$A%%sJ^KE z%dqdu#-toEcG>v*=nEdu?%rd;1Fla2+mc6dmQD3}I@kerf!$!AdOlk{uLn0JkK(N9 zitlA%Wqv#^WpVJ556H{!;VzX|sd;lyVSb*+!UNsY65B!9Pp zw}W@7cHT^}jrA_uqpn+GjQwKYOYySZzSF?HzSE`UWe0rcNp5n{0QN3!c)M` z^0P_Jit-D<)#Yyj*Op(Q(Rcg$N;i~W^W7=kTz(UC*<5~`kjvXDL?Gtqmr8e3=xC0I zsn=m{vtl@5#(QLrD=NnDu_}zf-4)}h*D;K>xuO6z_f||H`!=$F#;-@O>1cVN!a){X zgzlu=S>a1+R#eO;%k^ZrNsVwH`i7}ZT#aoH-(aueeB8dkA}za%aW$q-I4$AB}#8uVbZ@@PRUS7GOvDt0^sa624BjPu1}D2O*!Y%q7gbN4`{9hzP8z zG$l2cD~r{+^pyrGOCVpZoQb*Is4NFwCG4;C05L~ocwJ?H`qt5myd*ag&c8>#R2ikQ zIuaTut6Zwarw^J=#DNg{6_5{Cu7<3wTubdY5N;;iM!18INb;r1-DG($=?|!}?Q^DA z9;PS#RE1n}TB_y%r&Y~WbD*cRqpF2k#s<7ikuOy(B2ShjHJ7ViN%%uELj0>%l4bxe zRjna;9r>epwFP*o>Q$0=($&}bI#wayoHMEp`c1qx`iq^VRY#QCMKZ6VomHr-kk2ZW z$6w4VHeE$^byilrsq943TuISb{Ke>dP02}I^;X?fa)#vF+y}Ra_FlJ6S$DL@uHjeR zsIJag?hJLMxCYhLIR~1He0TUuoO9hq>N`F$N6HygMRx&u9dJ(}w4qIl8b36Pq zp+R+ZE&`r|?4~xTw9aMj+0?S0G)?|;v=38zR9ELK?j?Q?WYksXN_Q8vSw-0G4>;Gj zQ6Zh{+?&YeR?=_x*S!>X?;?2*N2+o_f1`7wdq3K5aUbGQavx3H%OLY=S?)efc2FUm zuevY#=R0@0dw{RId;L-8KKFHhhx4Gj&%e}p#C^x#nYj0<_m1vF&2%2GmT-@w`?B*? zwH|o3dW3qn?JHeToyjX_HL9QULUk_ezgeBqC+-^6ytXKJ zQssW9-075Ym3xyi`s!+4d6c`r>gt)v8os)^oJXMAL)K7voNKD1+AtnT!0R_F*z0=WfV zdGM@)yyBQgxSMbioCb9v-*beOhvtvC$W4kdw3;W>fx1e zw)}=LfCu%*HQbYrJwkUM=OhoRqASB=@t<^!@l5lthK5(g z^ZZ`vGI~%Ip|AAyxW;?D$gxSDS#*!X-OyD~)#5(`%^bepJ#+o%m3yCSiih{Ld1C%c zuIb49%WBRi?uK+XQEIqa;b-w`=~+ZFzh9sCEc0D=IXsCwav!d)}@sn{pp)Ou2uhjH}|b0UWsFIMY2_{8tglS1E2g{WpNhUH+iI-^o1t z)Owf)`5<|IgjX}qasLg(>J-q2$lNHc^PHu~TtM_@d)`Fm^Lt7O*~xT{@?60z>OI#e zZZrHlTutgzN-0*BW1cHa_jlaoN#n(80t1ZXz1)X@mOR<(ihFMQdf~}!*jzGT$F;mh zROLLvy;QOH@~X?Tw??Vqi^%>W-ljAfNOyJB3=gD}JW9p$H5vTAQ!|FDlf+#$`}uCFIYb&%RM(!G z6TXY+g(qs){+e_COxK~Bi^$tRO%K*uAk&{~6bbnm(R^HFprbNqj_(e3yA8 zuIJBJuG5u=0|sZhmp?6^_l`(Ke~IgyH#0B}SNT1HV-KxYKgCT&vJc<*v##r+H`jO0 z)#IhT=`BRA_ImMj>bma5y#sQIzuz^+J2Q|^I0;zJ`+7ZOKR{SV_xCMm+2?HxSX8{@ zogbJ+@{BUc8&y^|P>S{))CZ+~f7^uWP;=2;a z*VMb&zpX6OyDi`?%l4x3yT*HW2WGt#_wJ>>2lyI!5v#J?nqL1*Wxi#3-edfE199sq zEA*c9T`V(U6$Y%G3Ct-g_MQ*S#oR9iT7Z`Wv9c2H)xe^%ncf?LWsv&=uawQKWr0Pm z>$O_w%WKmED@za5qUx4;YP0xy)fxh8IPy5x@_Ku*HXjilQ#*ZwJoE}LKb z>cCh$a|q8tvy=3^zDc$F66l&;dyw+*I$b?Nh$oh^!rD_9FgG1ZMCo^-*o{QC0Dc_a$F#`S4^|*5R8HSXZ{x zXX87i_KH8VtkX9=u*jM2Ye*&WL3 zzKtYPKKtB(EmUW?W*^}}!Wo2kRxevobCKj({{FJnJ|EvNwaXG3s<&LORCmX#i9J|* z3c0O3KNC_-ejqZDJw~5>G5XX?`MgV1Kk4G1amn=QmX2s=Knthrx%&7UX=I87=%{9&2%tfC~d8Kq|EDK5#qyTH9PnNz!pD7)sPYJ%S ze^&o2JJ0`@7nAt^G-Xe-JeJGy*~i#8`kmBSYysQK8rU}WW%j?=YwVls3v56854MZ_ zoc)TOWxp15?BB(Yi63LP#Ixd$*=_Mnv4`Ced&OT1g7{zJe+ja9OMFMrYBUC&yCdsF2C!=roPzx(LVuqN3{Cr$|oDCDR#j$L-m@DS85#rP0(`=+TQJly|iIc@5_NZ7a7PCyz zF51~+d}UbHkbfBR5A1Qw?<~7OvmC`gpRgZf_4b4IBlhF=Q}(l<oH|8(c>saIpH|%IOn+N=z*>t7P}n1 zXffMy9di-Vu;W=a)^050|4ZtNYz%hVRyGwo?aQo~eVzRu_AL7bXgWK@4zuUk5zq{F z3}k0NVLxLI?8EMOd96b%37JdtR1Qy%4TUF(LTaHqRrH1vf0`vwYlu0TC>)|KBl#4ZKwqT_WV9t z2@C&p%N_?W0WSx4fmeaM!RuAtL_Ezt8?=OQwtYEamwlDJTRmT|^6VsSBK=nTcKa^y z9{Ya#A^TDL3HxdLIr~MNC#VP9Yrn429^yT8?6LRR@9#;aCD)BaSn%^Tgye;rS_IpWR@e_GjU7@52vjXLz6M4{CqE{vX5#!+rGkv;9Hr z-fQy@ndigK=|O({rSc!@=O3g0e^;#jT;o0{|L&dtgL3l^nOFYrG4DTBTpnci{r1}Z z^5lc=-S?|=_gkljnaBIJdzkTl*PI^I?)_@$!_MJ@_WN`4pTdtn)aL#6(+3^%-t+v2 zX!HBd^^YCHKZT!zJjj0|%wJ_l1}TqTWemQD^4Iqs%2u|0;N1oDI#z04XWnSuVt&=U z6ST$rI&hzPXVH2{2aDq7jhxL#icXsknva{0<9Mp*bWxlWG@Ql8g*n*_E%pSYe+UQdPBqv5qg z-#VbB-ze76t8qR5ZBmegSv|sJHWH(!p=}l$!t9`7^f%4JF{e+k5$qp9BiScGqu4)z z9%Y{bWw1}P)#$T^eTF^8*0RsB$Jzg7hY^pHpd8HoCgLGzC9Qs7ex`b{&s1+}GKEcX z(-PBiQuF|5l807nvK;R~eVcT#V6)%=6*JJ%rKr!>gm@8OR(porYcR<2_{V zNLa*Gg;o*uny#DrfPJPrX35lR)|*F|HUTpsXPa})dFDdXbl$>jf-gtSC1yQZ-$mx7 z)St-gF?X6*V4i(QHTzzIezUm{R0sb+=56L3 z=G_>nj^=Z(k9*C5(3?+!vd!m7cgb9W zSaUmT&6mwr%~x@D$rLx=z_otU9t*Q*vBt%iMYm~_C7p6;m1UGA%VL0h+AX-%k0z%d!kn z*so+8Y@EQ^3BuFd8hE2+CC)B_x67=u0eD zEY~bIEw?8vGxb?TtIj;aa)oERbvS(L!OCu|RIhak$cEKE3wb)oVPRI6 z*<^KFeb(95+2$SAdTWz4jH_{O0Wn>|kJcsD<>pLlmlZqL+D&^j)4JZe$=q-5w{Ep= zx9);(oz^|DxZipRbkusn>Ne-0^=a!l%%dDLIc>dYF1DPq_8=>|ti9Ijrajg^>m8e9 z>bB`^BW#)0Fu!8zv1QwGZITVW(W}q2%7$2*^K2$tv1OlWiLJyolQMsa$!9CKc}T~1 zShg)-tFtxQ=G&qcgRKMe-OqO(GGdQyDX5cb2|Ti`FlX9UqmSOS+!jDCU&k8UvE`z5 zF0JfzzS6d}whgw;rtLfm=3Lu0+YZ}q+g{rN+hN-=+ezCQ+j(d&*)H3z+HTnTr?RQq zsp-~kYxmSqQ?sTTrjE1vrshvgpE`;5uR=@BOX*%zJotR}SNVL_gy#T}{)48-*yLqQ zn7of=OkM(7K6&}X8xwC7bQW|@?wZ`i<;kliuln#fkQam_>AFGdL7PBZLE9B7xKVIp z(ws?ixXk}{NAn}iS^Ar$S6CNvWCdG^XOvZVy3n$2_IWlGPgfi9_y0A%o)ks?y|}k; zZ5X8gABle+@kjry>$jPae$#pmeg97@ee=&g`c3O^(QjH`r0?zd1yzkc`m~V$r}A|1 z5c?`)X&K-#V57?8)nkDwPXXJ&)4>j~3+z_gJj~H|AN_2V>%mPaM}9r59uw!>hq&4= zaa@veTn_F6uL5_g`Y!dj9=r*>RXy_a?J3uHf%mB6><1rGZ6vNA1)oSco(7-0kN)BV z+TDA+_<-v@;NFxY_vbpe4}6C)odnh^=eiNx()r`W~1>E^5JlCU3TUp4p)v*l}` zo8a48QL8i5YsVX!3}Hjuu!MNIq06w!(5)L~SP$N0*s7cxwu5#V_Hfp^&`ilb6BNgpj7#!N@sG;$P9DXs@5R^+~4sq^0_lM)gTY^=SyzCp{|D88#G^ z=?ykka|88hqUMg~U1pXvl8#wXrAD&nq)h2CW|y+1vFt@@f;5x8B$Y~D7Lt6DpT$tU zo?>yTUhC=aM7~IWC$i%&-akPYB`ALrv5!5&*huWek=R`$O)3|wT#_Pl#x5CIuF9Si zz3D!T9WxR;W@KZEo%!mK>!RQe^?a#%>`dVms%|xSt*YC=o*5~P42--y@^bbe&{4ue z*(abmmVG+=MD{s;O`+_IBc<#fv^kO8n|%(__3S>hy)#xCt0x*U^4QqSvDuJv`R@(T z{fdb{!u?9n9M^o0iJDWIGfYc=D>PJdP4gR;CGjtT%9e)UK9(bml18&9r7_YI>?!Fb z=_U5GR4di8JSl+t+XVXVvHU-oU4cLO0p}AIsknjg4Z=#`H&p#+fI6vzqx?U)M*1x2 zzsONLj5M=ILs#W5ljbSHsigVeB-=@r2rEdlmgIFLe}d#?BtJs(tAw8?O$p&p!fz9f zCj1`ZaKe0QUxWPop7dRg@-b*W$7S(zT!v;8$)l+Kd1`-*u#+?`geJndz?TS%$U+hS zUOHekN6o)euQsy(SsIaIB5fr6G%!N*8mi827q#ajMo9h~$v@>Nd|lp7k^CVcS=K6= zpK!#}0dLRkM5s+f`wMPaZT}0>P)oU;G#T7;Wn67J@GFWe|BUcQq_>iXT=NkX-=eF8 zX*%+GGxw0NC=C%4eoH=oN&9!yaxCF5f&1iN@mcV3H5t^VDD5>G<{q_?zRp*Q%UG|U(M;jFaESablDnu4`7HNP z?){ARjuMAYQQrQN#@$SPd1Wf4`DXC-0`jZ9>N@(V*BZh$!jE$lzxn^z`|kLvimmOL z*|X2tIVl8EAR!4MKoUaANg;%Qp@k4aXrZd1g%AlfBmo4G5{gK>h$u*tDiErmAXSP| z6%Y};pa_VdQboKXn3HeKbGC@(zL$IN_kQ0$a(;Pc&YIa%o>{YIW}nSom|tL3u0_sv z=%WY9RQ2{$soE!)S?#5=D(x+5MBY@kf@TfbC2h7oi14yP>4W$+;3eP%$U}hD<>0{>dz9MNBn!mymni~Wos3e zX^^`>z8aD+m0zYn{uA&L@H1x#xHbUsmB7Qu-xl&>;1iIaQ7G;zZI=Q%zsihX1eOBN zDY>#LatvBt3pu|;P9MwP2m>M62)turDNtQ|N#)U;wInJDp_1H#WD4fsc3kzdi5G#T zz;i&dS~3|qVbip~09OI0t9P10o`$$Lu4)NgI;gBA>5NMCLOC0NXE6I#pbalT z;-Y4yOwoy9ZHlr3+MBp4NyVj?vgC3yY_$&EbCwy1mfH}|L^)pre>UT1fU2D{k;kI! zzs!Qxom6d;8IT7ce;E*#Q#%S=u55x#S1X0=f!YtlRvg4tF5tlhy*LOaC!ov;kOv}9 z4`5ppmArzuNocLP_LTYE_bvh|fjpN0tbcN1=p0)S9a` zOWGhgD8E*1LwuDr9_^37_$pocR-tr**4fbJPc75Y=An?NJYOIlrB*kx1{0wJO7bOg zE=QgPsP`X`$EvkYwn01&SXXgHR;WbHR^;Cc{0j3o33;AZ>!WO_))u zVNRVx8)%0nLy^kR3r$J1*|0MLxC%8o)GDm|0K*k(FM^ZHn0MEJw~;>-`6Ccd#vK0y zlHr)Mbs-NiEt0~mz=KY-<^dNeK9O@dEI@z6bAU6^+PTR850qbumV64lkFj2&&&0Z; zv^o@HdL66Pe(Xc0Lhi04GF7eAG)G>-j8O8$Qt9~#wR4cOoU>2uw`ta^xUTjO+8dY) zyHVp5$fseh?ZfPLL94!p+}*TASF!3{#Y|a+HTnyzCaP5@uwF!9jxSaF5N)+{cc*qE zvYXn0kmXS|mZ}|y%t!h8Y9B&+I1%<_x+)E`tRYJN4DkTSR|3l{fxxY5c3aj^YBBOW z0ql=C+ZH)LM4M}<{S3|V&(Y@3VXM{LPgi>$?IWop`XKP?pIv=aq zHxcD8#vK0wwX4)BsP{|YYrvzB*9AtSd?)T#do5~@l6OEk7uCK?+XhKfU~{z>lDSA- zh+41{(`p0HqIYGmrC-3>e*u0i%1uLdVMi2Eunl~G7- z0OYV6Lha&Yb?ESEtRrb?+c@;@CgPPbQdYF{8%P2n@q*+%NID^YMYT!}M;yCT*^|zu zssx4kG7;!Um@UJUhM=54h$4^mz{+~ojc|@b2`QV-PHcv%rAiIti8sRj8W%773b|8yC4Yw zTGZ~{lxI-95c!umI8x^V8S#@1xkI5ApxU6NBA%n-d>%?DLL1^8HGp@}sypf=Vzyi{ z;97?BtOKViw4o2;@s0v@J~CTtpbgYEt-x8Y+3Vgw7a;CSptSZVp#@570XE{xJ=94G z*Pc^X@qOTMpSp@r@zY-+#Zg+>eOy&d*;ps5W#xn)qmSu8Z&i-wU0xli@_edFptw2# zT{l~fyDMcstMNiz?af-ii3Mj>%X>IIVcd0f-=n)wIyP2UyR0lpHddP;l}~^IIZH_( zp9{u@>-ArOwiQ`zKPVo1CIbF0MoTCs$^gmd>3THPIl4A z#%fy--=aJih*aQZcr!?GN|3q~SEU2A(V%oPyHwfNN3vGr)Ke4TP?$ceWE^=JFee&p>=P;>EyMfa-q2GL@6~SGeAJ zl{O2hxbMN^fH#3YSBlS+3AJfG|_VNi&ZDl?BUlEJc}WMs&pp3V8`Sa|v;! zKk1OK1^NP)I>%ZnPaWqG-vbN=w*?qSH^e8X@e->rBI#hbD^k}YH5mLCV2nmOQ_CMH z?PXwIA-@X@fn*ghr=0pOeGs3m-d{tlSMg*O*Yc3RF(fw?YFmIKAqhqN6mTx^4sb0} zr{G!-#CJNBrkzK87%&yM$k_&k5^wLNT*X6H(@K$Qf+1;fHbY13!xYY{;)F zWGBJlag;v^SDi1EZHI8n8MP__SE$m1PHFs9zn7H^D29>zl99+a>NWv1h*Mc^$* zl_Mu()Pf;5Fd_v?B4?phCy<&A9wHDw4|z++ROD}mmFN`oL18zPvjnYLr2O}gUR3~} z3Il*=!R-O3UYWJ1_PmB`XQLM*!NXNYj?y>exeDfwphqcaVNb{%YVOdOl3XS^br09t z(OUGH+NtCnAz6xeq_bYLCF;IJrmCI)!?A<#TjvNmp2Wyj0IHn#(B`#{1z<_F1in(J zJ*sU>opaogt=1IGrhcgLYsfEyLo4FB4s|cIt2xIRM&A$f`WeJ)s4|_}#jik%a@E)= zxj2M2GEeaO1FjG{IraQF-Z62n2L~}&3+EtlSv}T_J;7SCwyYC-n)M<}qI`9aU}KQq!m3ieA#~P? zGQBVP;{9d;R8kFAk%hBpR+svp%2HScYsWgXY?j0N!oTH6HrA}umFX;yuB^!_u^5)f z>a*so5o^WTvo5R~ym>1hozJmxtfY6Z0mYgJ&=(j43@B;7(@H+4g@E*{SSJ;{-8X08Tc*mHt-+7pB3t&sK_3x z8$b`BH_#s#3=AcV(<6Ziz=pt7U?#95VZ5FV%moer76V5CClDs+(}1&pbAgM1%YmhY zb@h$FEx?_?eZWJ&V}yzNDd1V)1>hCnb>JPsdip(}L!m_iZ9q?;FJY1;02l%c2Sx)E zfXPKebBZjDfoZ@@U>2||uzS(af+9;Uuph7hI1D%nSi;nEzv^uTj~{Z=JJ|n(`a{oQ z#{ac%65pJ0uKc_GDY`!<3ezvyzZ-J+loRj}r@nF1f-AH=HhMlbdi?=?P``$dKZ2@V zkIE`M2KxR>6tvn@`L{wpvi*-AaY#%$qPO`J?GP}d>bHQ!A68GmJJc7sZWZsl#@GRwdl=tI> zd?YX7Q}`^WF7k9U%r(QAW;oC3ACE6~`oW{~x`h%r?K=?K;+*MjSrS>zMm(z`Qa(tC^dA@8%^H=XG|)13AAeCC`%K6jn+DyPiw ztQng5tC;D29%krmhK0`S{R^Dm116iH$wL60gjBz(^)tiSPIKBW zQRh2|CEgSxoE}Y?;H`*p!PNayHDX+-y>B#q_oZE32JPfVv$>=N*Qs`c+T-mK%Y;j~ z3tdCC#uG;Tl44NFR)=9>!e9pN-wg3E#fB6&q`0N+ z?n*RULkxeWQGXpqRTUcQNny?UGkp(Kp}`)>8D!?HX66hwb5=KVTFJgufwy)$?baF^ zA;eNFrPoj)<*!L$9DT2)LPI^Lta?%jJ@H0Q1nI5vo68>YODbGKUBXle#I0^iuq9AE z8gUy;3_I5@Ms*6-1*5tPOr;UEx>O z4Sr?a;aAoJeq}4budF9@pdxgj68y?~!LO`0{L1>kudFZp%2tM7*(&fW>j%HG{_rbX z6@Fy{;8!*fer1E;SGF4b$_B%)Y<2jR4S`?T8t^My6MkiD!LMv6{K|&GuWUH{%GQQo z*$DWRtpmTZk?<=U1;4V<@GBbwzp{4tm5qg8**N%>jfY>^1o)M$3%|07@GDyner1#3 zSGGR<$|l3FYyp7>ina2LKEmShE1Z+ST>nH5NgtIb{C=!`NG!;!*xo9q$lfg+B>70uUk->#HAP#U%91@4P6i37nu8R-E2izi# ziDTR8`=%-r`^(S zaewUx?FU{}`%(Lm2WUTOKk-22nVJVFpVYjXR<4!vU`hXYb!m|n9zrT%@EX!xy7QW{ zf~>%6$%?Wf50#Z=WgaH|q#qBLfijTSmccTZN5~Kv!t2OdvKEh&VKR(I$p{(2qh+Lw zv2{K70@wzfuCi6tuP&VZCWQt7TNwTqQ%R+ZjHF4{vYy8Gby=2s6TX2b*rwc}JVoX62o1E;bk5+2(3<Mn=Ff!wn*JKo@D_FXm(BdkWe^ ztnCnHTC*r@NwE$HTUt9J%&>Ms*vi@&VWzb!g&CCZNrWw}Pa({(K8>)IH5*~3wL68a zC|?hREv-EfW>|Y6Y-Pqo(%OYE!`h9o zm9;lv=6}IRKlD7^+TUbmfXU22lbJy#GlNZL3QR_Zn2Z#fj1-%U3^f@UW->C|WaL?s zk&z}N&zX#jG8uW^WMs6-$XJt+aV8@rCL`lbMkbhy0hxX)^PY$;>R1nU_sQW}A$>YBDm%WMr<%$ZIAe z^Grq-n2anm8Chg9^18{$Vv~`HU}P#Z@*o!0!CJXk#*3Nt^Xw>yG=&kH5u7sGP2iXWS_~%dnP0An~WSV898V&a>!)lh{?!N zlaUWhMm{tdIc73)!erzllaZ4qBOjZ(a>``p6O)|*=!H4idrt{%^IJ5E*d;~N2^Za?{!pHEj%*My_3CxYZz$a4)=lD71 zDY8TstLSpv7AJK=J*;lALH*`8@RUSE= z*HHID_)yg!x?VlUpy3YRuQ_Tyl18QRp_H46`C}4Nt64T%-m+}9*09#JRu)sl)IZ}u zydWlv7xB)$UwkD^p>|KBb7lygBxg|%XVWK~y~lEjAC(O zjabVXh>c<+dxFYJVt(Q^F;7er)5Q$&H!)MZBxZ@1#cc7)pUPepbHrTSLs2C&a3hEt zS{+cnJIeP(`BmW8$yH=i{l#La7$$~`XT=CHQandF1zqv9c-kz3gJ1E7ajk`MRW-Ws zReUuG*YWjC7;TJpOd456XJ$2e8@bHQ$TRYphcU&N$|@PtjhW2bc-fdkW&OUyP?Wfg zN_3|ZOHtxF(%X%6f|e*(N4W;dbw{}sjQ++z=4A{vikL6zsERrQjrqnxR^52rSVrtS zcek1JHx@O8q3#Lvmu%J@X66Z}+9$Ia4`qVA!PNa$?}zyW&6`zxjoDv`)>({bBbxf# z+UQEHdy3lPZ49NFqm32DTGmamhx-7`2saX`Rjo;C|0hz8IrN`gVP`&%uggkPpr;Ia zYCunI&{GfSX$9!1mw6&EkYD|;WkILP9fUJb?_?UWOROOqO>9mf*=)LIDO<(Xv$rVk z9(I6zKsNg{S?vq#3cF5r`yO3pa8K^dtMC9G%xm&+9?9c)5>Mf&JcGC69r;tdC+|y^ zPT9G!WZ$OoS$r;E#Fz6@zKL(=`}h%lf}iG}k+pE)HbPgf?zUE=SO^a%mZGV|MEd5& zeF@z;^_P2a(tBQk`w@C_IuG-TyeeTO9zf{D0|~u(5S0^5e{_cCHF#~pnmmHA7Oz7X z$|DKGcofwU!{d293hg|BCs7#7>+U>0J84l8Iea=Bnp|Z zO|a4a!1khT3Z2aTb!v$orPDQfV~VxZGYB(v+9m7l^(>us!FngXvwD_XA3}dc^nI8< zTz{5wy`;|~oTt;?LSLvaB3!PoAY7@hA}rO{5U$f{rPp`qyLDP8^}YH&eLsco>j!jN z|MbK95&bCTx~5-e!s2PENa$tprq;b+n@nR}2Y1gHjr=qk^BMHfpeYh-vQA_CA!*GC zc8YnjtLz)*!;^V3tHPJjZ1&^p`3B}s3&fqSAXt}buz3TW~Rd4cPVR}2g9Sc`)@?o|00y>{YsJHj9I{Hw3D2r6@ z>S0m1&k?QO)x%=+W%@E^SMTa!vFcqtEKa?vhsEnV^_?t1y`_iM)!)McDi**3{Gi8XNE+1KVl>pR2NYep2!`xvZQs;3M+~hc7fDN_NHa4@*A|kFtt8!AM;f({wCIR_jr7LL_5xOxU$kYasVxF+)u1gBdg6|D zSAw4SVDx=4`js*IRWSN~7ip?SmIFBtNOZEosJ=fFja|>Cs-PHaA z)PrNDMLSPB(JQnUy~*yf`^>=w*)_L6ST{YHJ0kQhk600*Kdb(K6Il?h-atUsgR3_VsQ=GIc7v1E;AAm4Sqn~uN~A5Ye%(@w5!@T z+BNNlc1!y~`%(Kzd!UtRPE7$uJoqBW1L-OLYf3Q6|Y` z*-)m)#F`%GJFg_Bh04T ztTq>$D}RDF;!SuOt+koF15f8|czfRLulsy|-RJwwZ)l!0bB}1R+a~D?ER`PX_XPFU z@elOENA4V}-@;csJpcXkliaVTKSMq9{P1LAveuf4>7m&GMwQu?GH-MLjPF7aPaqEf+mtgGF{qSx`zgul-0y)3pm7A|>7 zJ;CMT4)*r;$VVgrOM}J+(B@u!+Oiy0#0IkgtPd-uzZCVcSAV21>782~`rg^yv9->$ zKH8(==i}b{?#{i>7MJ*x*h}Podx^GYu_m|>Uh03Q)TtkrzIW5%^zYH&I(GMmt>rqk zYdD&zb&?h@(WyhMm%XC;VtCoQ^eXC`Kj@j_!GmHw?H)>K^|EI5$sIU&P;P9HJwQop zUOuh!dlwEa8k|=g+-z`R!QjGP#rbqab$d0Hu6b4YHN9j0z&=qOihB(#2yWM`i9M*Y zdu*J&zC9r>Ha0Fk;VJqWPl8{*+Q)7FUul`U-BqQ#ddb#p+hxUu*=sq!1`TSKU(mNt zVQ^}P=E2Q7v`KDePfLi3wRI(E6-z_td2R6JJkX5_EXa&F(F&6E76JI%@Z}9yvWMp&w7JzoSaX zis)JEK5aEQ*?+_Q@#_zDuRm>H+;hIq-l&(9{9Vq2z9pjX^=msCPkGa^Br-9lXF>g* zIUWxVR7o1Van|X^?qlC@e|BnO|4CCqD_1Gsc&+vJ9kso#WT($4NJ|WLB-CA#aPh~p zpJspi+VinnTUYCHZPe*k-1FRmJmM;+M1C@M$+2rc&V5OIwzo%F(%5_T$8^g*QZKtf z`=`52>~Sn8;6cLf9$$rbD(JZ2o$I4mr?jWT=Z1IAy!hRA7r$4>rAOEg{TLrS;A;N< z&8POaIc^WCcWQ3dsns=_Z(5(-q-EQ;a{9h3G@3`tO1KL#qT2(B(m)SdF1%M%iSN+p zm7YtQ`QDmwV8h8e+ZS~`0UZjgA*FVz~dZB60EMH?<3XE`qxtbQk> z-L#uAA-OA7U1{C_mB@e**HY-7a@wy7r?y#6`N@W$Vp zu@V0(#-fJ3x^vR|KboG~C%8lYGlQtqhlVWP9vhbs7Z)ENUtbxr1Ttg4e6^1o|Np{} znc1~}lKo#Armr_-FAa9T7d~pI{@j>#H?Iv_8{VN&^0~&(Z=Mlwg?nYhTHn&=jJm)oR^2W&9PiC*acJWN@p_i*p44eP`y{JV^66?4&ez3d2 z_HEfiU-r#vbtL}%dK!Jb?euylaSXd&z@5+HmX-{ ze7&fIUcKU@dL`1=dWku`?R9AdOz4&S8v}T>;@3w`zUAAMAFdZ2@9VoQbDpi5y|dE* zwzZQ9Tudf#QuBYy0Fo|~CX*8PuqQ>u$4153W9=}3Pd#D++t|qnK4Jn>9?t~+ld_Bd z%-+SG85B{eOZ>P`79P0vQ}U_Q*2bcn-M{Gf^wtr_#e$u~`YxKeWP$7cF-xa?*LwRa z^&hxjxH$iAx0)5IPM_?PJnG!KW19~T*j_)f`SUd^b_}(vfa|;7k zd)^P&SbV2#e*Z$#>w6vW?V|S{C%6U@+B8`2(Jd+g3otqv~2y% z#<595!@JAXX#=nPFmgoWUDZDPy7?#TFLg`#Vd%jtdA)mn@X5RhFHEm#|M6DBiQa*4 zHhm_;qt&~~9=EoB+ota%d$-(a?`*x|L;bN^i~YTs>jCRwbD0(T z;>&j;bGe_dM#RVZ*(?7>=<;w}Vx#PJoOYq+uXZ78@L)0yG*J0@`MrA;_X%z?w7Bo! z!u;Y9FlKgp679s|V(Z7pkui%izs9Mr|3B^Qzp`MP3ZKmOv**4WIIm}LaMRa@br_IR z_4MEmj(+!Tf5#kO&kJ897mxSf8nZa=dinW%P21G?q>!Df+r{?ck@dkX@80gawsouN zD|U@&HDrDZ>)EneUo0Ft`FLqj>XdcMzjo^xK$`8@CQ{eGX<>)D6H6l!BqAJX>o#1e3LiW-tz`|jaE+Y^(IP+l+1 zFq7qcpx5TK{65zt700RYn^sHaJ^Kvz=hvJglt|_$ckWEV8#b5oyL0uwCzu<1M2-PF zIAnl>!JANSfQxi8vU_z11<>{rzBraC&*$hsO1* zBxa6MJq$|G#OsC)Lnz>j4>yTHph9v2AV<(yb~s}SGX4Y0VC57KBfRR>iQVuG2U(>97>0XCGkQEdNzA^D(zZ-7ECLs)N+O8es<2<05xdJ5Pa7;jY89vx+3kU(TL;a z7%l667M0?2$4K>cHE+UdEy*ii&KO5^j0#Emb(Z8Rpw9m>-Li*EOueUt4rkibWPvWYU=#ys}G7+?ym?#}vHeYh2r|M=9h? zl)AG z6Z6Xj*5Rr~jPcdcvMBRMQj zn|2bKkxkr)aAu~ls$WZbN@jcVP!6I(n2@_zR1tUTqL4qTJ|qAno5fg?h1YPj5=6I)LQ;5eh&=&hm-z$t#daQ{EiyMT7O>e*9l8Zt6K z^NZ0&=2&aCy^B;{DMnQ`|CRmq}U$l>n$b0R>D&G|ndQ z?pT3Asf!6+@|`-$@p((Hd}TB?A|}6*otebZY0XNG9m#8EJ^a0Hw|gs1phc_KPpA71 zs{L&4SQ*zlp=PeBS{`S6#6f7BOJm(XH5CYoUp@-ttzCG0wR#G1^}?G+@MXTcj)4v} zW~l{Okd=kcPSrg=rB}!Md19=JRxjPyX(7f>DY!IuB=jBlnyejPEJy?}pSwGvWL|$C zCLu)fEem;@Qq0YVv;|NU)qUc&;PkRDI#GE37S=53B&pyF0Xjun%@66)c;$d zJA14}t|qn+xDM?do~~h>d)gglZv(E<3_jx;C)VPIExCC@IjZ&Kc5)Q-IrL z4~H8uo$GJAT$34<1;>@whb~?2oizZ@Gw-DcaJMC6nTw9%!?w55#wU~ge~fN^k+H<1 z70WgKHBwoTwElWyJTzNVc!ifqYLLR^T?r5%XV%g5bA3^*_OKZ*!a)h@Wrc%GUTN*s zF0@q$8lz4YY?~orHe&_g&%PJ%ys|i0C&|KHj%w9YccVA48qN!vL<~5R5%WMteW*9V z6)Y(r27B~GjQWe=w>~b_D6PrW*tjlx{8Sz(<8-;c^}y?}rkhgXUV9dba`x!*oRjuy z$H)cBQx*juXw>(ZR!^+Xp06D%E)CYJ!?m7K5>*KiG;~NhbIjaStf9KP(#E%~z+^Kz z3=y3#4){!&h`LF)tA8JGzNyWqpektSY`KPGx&w;BiVT!2Z)U^s=+)v z=R*)pIh1Bqr*EqKF$uH~&zc|_{Cd+(i$zi5+eGctciug-Z%a~Y_i46}-m?j7btMeh?4k{=Y2_c(JR%X$4yV6GQ=klh z0xg4p!2o-@eLjEr(`l2BN#w$qA2{yX@A~EELJMurP_tj)V@VJV1Gd+SbDY8V4WVc@ zl)!HNUWX-rN)%iS4_FOqjTAjZJmTMQ zzLR2=|8)kWy>pB&LANzLXZ#!6K4aUqZS#z6+dO02wr$(CZO?b^ecva!Z*u?pQt9;G zRl8QDD&0wCclBC%v!<`1Q}T2`k#-&0`Sv#5da`b%D`GIHAGOWKTS=M9Ns zpiJ(&QxzGVnkg!p$XT1Yt7l26=z(bo%#Ekg*K~I(QM|KD_GF3_2rPiW@;~pW?s6#* z?3>L`l4)zaSowArERi;p-Erd9X(jt&EvfXM2ly843S6yw3%_T9RKo zW^*(b=>iv3&BWh7BSDVheTi7bs6NEK;D(w?egh!4R6qK<6d#d)z3&cnRa74-uNWQx zcrn>JW8X>xW2}OSGUra!soZ~g=_>4wfjN|E1!|GG#as2)$U#}?bx(7K->Y$P#qV0V z4$MOeSw~zh_6_eyj~93JZhI4^wR+`NkO|QL^hTKUD5z9>#Ct1mGqp82naBHlkbKpT zFWn3>4_>F1yblq78hRqwok6RsB;a|E-kY z3VF;^E1lx$vIw1VSmy?8t}if#d6CnQ!~K;RSIZhIz4M@&E^u;{PEy5I#Ne?@y**jj z`Eg1sS0aDaIDS;*8EyMOXWxwTj#@jm_YDhWVq@&+}y6B9cDJ;8sQ zS_CXC^#7dyf91b0{^#}oqW!1kziR)_X#c7CKi>Zv{U7gtkNi*1|6u*c|Iht@89|5O zf6koaKQrg%rV}-{ax!tC6SXpMG7&a0vNblLlQyw2buuGhVrF7s{=W_b0Xs7*Gd(Xa zEYyD%(k=5c6QHlWwDdaTZTl?2DD|&M{0SlCGKhyEBn~pJM@o*vO$duacn%N_Bmf4B zM8xKo+WHISd{v%czyL`^NvonjLEBVCkl)lST9q$CkZ`l<`bRKKvgyb7$7knfLT37- ztE1a-hT~@Yz*wMEXV>dF`h>}AS=opO=Y^Dt;m2b`n;qz z;+LQAhu=egA<@&}S!#7pGQ3MI;rSs|CW}p4=JX8O>k-A|I6(Mm^7S+o;8yPTUwGE} z`+V;wJsf{pnN#rx;}Nv!_iZk7_%@JiMI4+MeXWA2=f)`U#=e=P;t{ceV3a1b$Ok#jb#i992mjXNON@{hB=kp>J%VyHa1y zfl~MF2wZ8=<7nYIn!Ts=tJKTojPA82tI>N>^-$QM*7-ikRsALRA-f*W0WYWPFwr*I zoiouw32&%{3ds-n82g!ffoD}>z0v-YE84AsWiGGC=^lP;Fe=n@OYDcYIUAsAK5%hQ zJbn!L5P+k6%W{B+!<0kO^Ctt7F9WMmq=95qh|2=X+krlLuZvB0t*mrp2Rb=Wm*ONh zg%pIYy&Bo+-7Yy|2*aq?xFhcxLxE=t-`i5PsYiGX5neTG6@gd*G}` zP0*JHP>*avIo>JYjIGcNGj1z@iBDa#3zK{U6~FR@F?9dqf%g;6>~{U5g}ko6)M6f3 zf3MZ3$qd!eXzj&cNzKfPhu zi7(yWgU8`Y;@wT*druoYH{xN6(7TAin%>{J!1eFDpW^NxWaRaMTki{c_B=UYJy+iU z(HS}(BT@bRf{;`nZYF4fAh1Wj55sO(10_3n0FpddvNXiQEV!)}VSP_h9ga)Aco*4a zIB8HOq9Udu+A^wx*(SrtnvcgM*yx8SHKNO+P7RydZ)nwWEms#+vE~e{+V=3V(Fu&u{C{#L{ZK-U6!YlNE7lv??g}n~RK+yGh-2=9dPTz6l-PLYF(UTj&rBDFxGyXaE6mY443!#5nrgriA4GafbY764-5R=VseHXHp_W+vCWBtf}me$No6%(4iog?VVZs!Kv zvx3?8d0XIb!>$1`(&kAUt==`xmI)P2NtX)SM|Y{a!40fTOAXf$?2VS@U1Br`rbXuW z&1x6D#EMibegD7@eFL3>MUvGibd~+U`j8LR#6eqb>UJnf-3^*k|G361NyeJ`=!4FaW@x+JRsIXd)k ze+Gl%p>#>^t4UB>+8jr#m#ow96|qct6a6>&@)r64HW`f~4c z1N!E=b>;jwh};Y=^Y*VRAyvWwZYPFmegonnn~|!a@a4GC)os?SE&YH#F~W z5;<2A(~m{RHu}iRdI-dx4#3X?OnLJ_L29|D(C*6;bI6Y%>QRNt$%4yqbtqR7+i7|0 zsn`kFZ=d@xsgTH;Y;a6*0$)rxXsxU7Ra1m+$ZssJ&h*$iDmE^zEa)sX;zma7WYQOo z$}J~bB+8dqtLt}&9P?S;Gx^z;QKr0kVm z#49Z~FM5M@C{f)g=ngRHi3U7$!*Yvc%-V#rV;T7x8kV z)hS`WgX5Av>4jqMw3F&7VfC0D^pjE~Kk=5@9p!D9OS=>G#C4QSoQ}uaNO!_B1F+c_ zOR*PO6vJT~-0Daf;~8OCY#j|$v?4*OXabu#qZ~EGSy(C4A}{i&?W>8gv}%!F8wWwH zTZc>VqCxiQ_*P<$UkbPd))s}wrP^Toz}>97hs?hF&EGXtp_!Fxc++t~xwaq*0~nN-f! zZ2Ho?zO8)=WJCQQ*3HGq@{F~SDe0Zexy^ZMSvgxX_SN2Hmd<&C#gY}4PVEsd=gVTw z;u^~u-~f^%s4mE=A0r?%PGpqW7-2JL?z>f5n9~4-Fgi|BoRAnf9x^-# zv|l_Rl0IOUm>tqZkee_D;UacQbQO{z$Sfd9pD-0bDu_ZDuTP8t=@AfvAOJ}ggxClQ zDAd@$TUEK=-Ws?fV(}wSxGNzlC3a@5%Jz zL)s$fl68u@CD|q3diEpsQw5~}=n&zMb%{Iq-Lh}F`W=Hz0W%2Mq&P&}B5v`wpnC-W z*m8gM8wGs@c?XFBJOMmGVvwGY9e@r1V{PR6iXg zJQ5zkrd;bkR>VEL{uuxlcqlPK$hoIjp=_;aosk0{Dn42`fn}iL`~( zC0f&K`)$)A)MZ;EYNKWaTI21&^0I0Z?Klho1`K-;K_WrHL0~~|LGD3qK^#G>{Z@h% zJDX8vgp)**#M+{%0~`|5lI$s!;kkAwosAs~tX0QN`h-H1Iz z;y)AO2z5X^f*DUCFH!gozXuyXAuo~V6?#KC!Y9wk^@_Sjl%yLECHED3!ybnq_Z4x+ zKcXYQ$?J@CKsv%rL?*W_z!BpJxknq%QTPtJ7fWPQ`1ZR8AHN{4$?J@8KskCL7n9cw zFRky1x+za+>8Yxiad`f!0BHzBz}>9 z$m5BuMa~D_LyqGmZjpD$yX3zrv=5lBdXvK!a0lIMCGO;YVjZcG_Xxj%jR%s$=WfP2 z;E#8azvO=6m_UrXBz7qHgw)em{r#d%tRi>K-}HCj8n-5I$=?icU>cWGXwLlvJtD2z z@F{R9@@5(*z4GE3WYEdvxh`g(L-(XtJw4+)wT_XQA#WLJHv-eC)eiDjv2wPLGg8fRATUciW**-^Kp*EAf*eTV5%qYL;Z z^B@dZId7;hS_k%)^k|bcT>+@HYqS@&`(#O%Y*c%yzp!V!IU7BUJ0m_r=7r(o$GUOs zy9IU9=TjQ02DvE>K12R8@+e6g!@M@xdU7^5SMo^wYEtqlKbP{p1lJS9<@2yi_m056 zy=r-zAGR5`u{!@FDA6_3%h&YxJ}ZMw$bJ(=52rivCd@K@Un`VM*JnPK3}MAOWWPAZ zL~ZI)JR@BEK+H!U*L-5WHupD8>aCN;dVP#Z-1Co+;Z6(ij*%dIyc!p0EA>E7cJlN* z_~w*RULaZcgqyMaZ)prXb5)=tLk2Q>qtO=nlmU1H=uafPP-N=(Xd~z~@KvCeUS2n( zY=5>r;>QMZ)jrKt=bgKctQz7r*h!!-UubG5r{|JUKG;t5)V$h9szck+9b`GBtWIPi z5Zo_({S3AbC1W~>KaYWiy1tS>WP-F9g1<*q{nJv$(8sureBKo7EqVuQayvhE^Si*V_W=Y~SlhL0CWHk-{=`$=eZXSo`4(s@-=7$4dP;j;?ps2%yO z_yKYn8@PHx!44`n&~VG;hNtU?zDM5)N_UX@QPf^CCp4og-yqd~yzO5RGVJc4Uw9G{ z^#q0EUvP`n31{1jKfB`_#MhUzN5c+2vS-ci|LqI^4eT4-(X=s|$&7Lh@kfjv_aw#vU4QpkH^;Abh9?vx42|wef2*yNG^ug#LuF5zN>L zSnh&|<+}a!XC=$Hfdy8f`6X8!1k?`nn37KyayvV)%e zgqKj|wv9c3n2zbaA(_xN!%tTlwK%bUMw`CXdF5KqL#KIaU%YQM?s=K>z&HHv6xm6l ze&+S^Q-yunZT>>3@{~S*lC4F(;c8tPQS4B<1^Yyv?&W}_*9T76D=z5oP912UDOz8+ zC23}lw0d!e@_lcYhF9$J(}?%W<)57iW-$6a6wJmf)NsHI1v&C1Y#X<#6e(wC@A zm(fqNqV{k?%9z|dJ;33fF#?MZjnn{8nIPBw!KyH5x`cXk=h7OkHq6>_)7yStA~In0 zRAApimxrq~bo<$%mPIJuFTVv$_U2%N(0CEbN2!k3tOucTi1NcdK!wC$YpELYrk4#!sA;*f9Z0Mlh?U<+S>XImJ?{cKyh=WNIi7QQ> zd!3hd$iwr`Q$Y8}WVpSDw>A-L3=4)~!s|}tsNHje{j=n3Z`LP6VcuLu@!pSTtRhVq zrNXiNs7g6~m8kdRgfb>&8$lS9`(MSeA1S;vb>L;e*o|F#&&^=G%ti*+OtRv7wh4XX zwmF+vvSAN)%c&5dQ1!SpOxBtwu9&2>xkHq!d}yO6LQ5*(1JWGB3yt4eJ1>{Et4^e# zz+UI|jorAXLzaQx%mKKH2C!3QT%^wU2S4Zk#GG!H{j}lQ@dWl*$oxo;S;P%g8A!nL ze?}t|W8M9!0?=s>bu(EW>bJFzeNek1pz^4SD1^N;bW2-Cb|)D#W-G?s=1@o+MI^gf z-Rhx05lK9yiH@sH;BokD#!5#gttcg+GS5Ay(skIrm$e=)>S;oU*^V|=s(X}dHe6hf zO&0E9DPI!ZgJ-^EHxuG={?Vl&oKRd(M9)-9S|gLDgB`-7suQR%L}aDv<1RCpDC^ceAFItB;| zFj(PmB}3E=C8nNYArhwM?}PE);oJ>KU0ZK{9#c zgf!Hb&!5>xmv-DVPhx&Q6b{A005%bAyiC z@h6TDV%W}4bfbyx3+u_x3)L8Q(L`Nyrz*ZBQ7ve;;$)rFItk!8%qyuK$DbE^U@r|X zY`N?=5_``OS=c6Z8r)ud_O7{P`M9NQGU~4qcp~vmNBLZ@@LzXSd7|w3EabF{Jw>JK9aJh0EO8K_A>|Hl6cG&OSV;!ujmvmk$)QDB&z9f>t}0z-cO^oazZ{O z);YQPH=!YZEg~p^`mBu~;Cb2Bd&e8OiMHx>Xx{uh>3O;Z%Wm|0njP3m9=)-szccnL zp{5tu?Y9%<10Yz?gmX^?y^NS=)}vIMu16)1&3u)O8Q{KQVyAO@11#`|y6d~`Vmb4V zM2*D zZ_^6`ExSfMy7W$cf$_)SpufAsMa-I2xbZyWZyHVo9)=Xu_8xspv=7ykLRlU4IE5@P zV!IiZ73%B+PmMcq7rpPG?gR&|{>N$#)GHPZEEy$l{rc9XB3`=$79*nJ{mXCoLC1UP z(O??pl`IK~x?1>@RPj-iL?36X{Q_$6_;>j02zpiG=>FU7EKCYlw2Eg2^iskAk@v3q z+4?yxv&pF|PafE8;r*Z&f&Cr^!O@D}ND1`^BC(C_F{(i>ijn4x7}`N7`)%de z@H82|cE_h2jwh`Xrs#vm%&wKEX49CiPv6spA?=c(Miw&Gf(nkh($ht_R9v)E2H3uK zFQ3$wm!|LPN~tU?Gf4`GN!*;a?-B3g)o;j&npx+<>WQ)@k{B1#m^ZTaCvrUzH4rKo zm}us29guqcdWCR#9EN1Kq|M{LJRuo8Fg_OX*m zFmJN>s?Qjbb2tjxCZ<%8ef(l$SWZhfi_u`J8{Z|J>0f4?Pn+xP?oDm8f&OB#3T$CS zR4v7wmhKwoZ-xb?PDf?ue)@1FKq9!Hk^&$%L{co%GNLQb+!pnbhwM5; zW=v@Zdl^A1^vK&65*eQD{&ET@3L|d-$KGEu{`O2St;EeVx(%VEt=h>*_u}?&luM zj8(eD{L8vnRCQOm*L;0Cb5kEq3?e=1?_C-%OI9JI#yOmq0L(4?F&wn(Z#!#7rZh`w z=W56IbM@+b{m{IT)NkjprOlc3NH*Mag-kdb4C(aoRUD8h=|ys!qJ{KfR@?L>m8P>@ z)bOOclJ{iI`A8+`b?5`E`QaIAOn0q#HlFtUhhCKoI9u}h($!<8iq*1rR3#lpT7!=! zM9gSQcc+<)AAWF*EjV%ix4u(2=mwyl6N5Brmb-@4^IQJZ_8m*^8~@$v z*^DPuJNG-RZxJJN5(V6BR-kB7!g`~3XU zmJ}M_Y_@AUhXZNRw0bovshC=aksuTiZ(@Kgm(ZM2ufBfgmQ8^Jt{AS@%0^6`I2*a`a`7e-W#m#iioCt4(703 zmp$ekMj{x|mS;ai1#~qzw=?DBbr!exWTVMKe9#77CR3MfbSIOYo?QQ{al%Rc6N~r4 z9K4qNh};qU9w$Ef`pI*k=Sj%CutAOL{)BRUi;RqciyuxtCyAw*4p_TSEzv`MEvwy^32-eqi75U-YE+i zY(7I_-E@{)^W7kXDWqv@)1iAvQ(a9bC(Z1IG&V|34`p3`&)rQX2sk_Z*-uXU(6aos zDx#`rP3v=Drs*~4G_~#L7h{ZT$T^Jojm=2^y|fd6&HRkm&Z=pdQhVm2**zRFd)R95-RKKhY6) zq_|r&OtItRxNEb8we36yVzfHMmy(k*QI$CxEr*|JZtuxXwh?t@5%@Rl1#}cB4{mxH zd-H@0wn&W~{3g|Vb(bohPfMCf?GgQJsn}jV!vKek^-pw57lTEu5YR7$;4Wj$hgJar zy6j`AcovL%j0e=#=fQ%QzpagG@yW49ZGe0Nv{K|NUnglP)F&RcFixZU#2ci+%hJBB<9$;VeI64wk>IYN-L0NY z!xq*_#eL4#oj$?AUEoGGb_RQdjSqUPc#n@Pql@?QIBDjp_9_|nWT_VLY1y`LU-~k1 zk|Mr?EK%bbDvXL@tB*uGu)w(YvSZk&S+P|WdNCROkNgzYP*FcS<%}THGr&@Tb;#A* zWEibNLG*lP%AXy(wF!c;G!yo&0A%2-~Jjg+uwgoDn?bNSXc`Ck3|9aB|twb`CRUn2t^%L_Wx9|Yv^ zKLPV`11m&Ax9%6>cTaDQ&6ASwUXw7UtHZr2OH2t+4S+?9#FxAq|D=$Kp4A)1*I(e38}8OHx2uc#L0eXpe=G%9u` zx6vGmWk_HUAZ^-JfRvFjuq^569dj0kV#NqSRQhWx`0nZbk4yGVb8z1P=hTtW-#g{l zdJdUU+n&KCz&8-d^j~xR0V}D%O+2rqdZievmhyZoQR_qMb}8W)ofEsW|ELiRx_y2l zJ_LBC0#(d%;Y)ftAxUpS-}Qs~CQ3#I-oz+VCMaopS+bnvYxpupE>j9GX~>{Hik#0F z4x)hP_&UVuxQNs^sld>6M@ZBqi02`D5o5Kxh2s~~VKww{-B#|-kwwYLScwC0VvjfI zt(%cdG`(NCE;kRnnKnfz{aZvE4-8Wj&F8h?~&4|)95r0FSN zlE4;v!qKXR~~cz zV4T?ms=|>xywa=9lMUazsg|u6zzOH`tDlFZwA#+8bSzaS-H(@$j-`x{!`tAw`+8Tn z`yR*fn8n=U!CY6)%z5htycwJ<+$HHx_(c)!u+s&#m&>0H!9Bb44<`fDL^OtatoO@0 zkm4lWGS421%^EfB&(n;>MDGU0C=KEX*8o6#2a8}V!tqj?^qGe!&+AA_ziSK7VuP6QrN5mmY(H?L386<@ ze5$~v9iSI~PN)gIueIW19;5fR2tsVzuppZsCp^yVa@!9dKKfPKz%Rr%? zw}H^%#kp+UZE?ct$xs^@EStfu$h`#2)yGDk==IYd*%&zsqpnom0yk}jzLE}}B4ey` z1meR+{_-@}_)AlR>df&_4BQk(M>)w9nNFV|JH+xgdrTfyCJ3u=riCw#IvGyMwWwr7 zl*G<)D1-u~U~7-nrdYkUAT0_oPOi|XYB`NTU%Q|*Q-c{SDpmb>$GTl}t-UB!zv$?A%g%1DY!twXfw$c_{@W( z>AU(bTLnpXphJ-Ftn(p&Fn_B|6ZIg*xcQsxDykIq)qC~@$x(_Y&XgAa|uSsOp zh1h@1#_6zFRIKEfGfvggg0@5E^YxOI+n%$GpJ<0fHi9kkqR5hx(14E|44eFRoV7+1 zWr>o5{FQ_!)cod*2d%T5xW{vS48`h*kUN5{K@J4*Qt3KnCJ5CqlpFel9&JV5C5w-G za&e&g0gD>VvJsQ%U5^Tk#Auu~u6w_ae9FPo?34O?821d&WzY&^6aen(-K=FkGd1Q+ zt?_PKD_J#`O5^Q}hX0`mkrhL-Q+Ao4S-jAV@dvjj9(qdO?dM_4QWL<1qNlhH3 zr7a%+3@fq)Iwk4GYQ1~;$6DONyz7c1e(H`o^}Ps^CjX4BH|;eiuByxBzfI>*!$!(P z*Hku^toN_)i*Y@YkSsAK*r_?oG;(q1(ln69*iUB6Y_klCTHHYY&^>p9b&efKdUj_J zPt<$$=tt2+^$lZeyb}4hVH$BX6Hg>lPax%?tR>g=CgW%vqe-qN7OkP&x0(w!P)Hz; z59HJ)A_+p~CFYp?lYcj%kkJsN;Nz1~PY!KocBVMm|1_QUiih==sXsIM;kL_m?0#VE?6yFy1? z{75!9h_LEkX%ylIbf1Al56Tk?A|uw_(!OILyO&6pw2Eg-OYXuq7su>ptXaGWo|UiW#eIA)oas3ARE zIj<h}1~&w^Ap6^yVnjlidJhQ{PAh*dJx1 zzb*iByy^S5n)H?TNf*M?>xR59Lre=UD_FiNc8!9lSjEBX>nrHHSY43t)sa<_CQFU7 zsO4F>1T(j1^dl>`iNTkDo4n)A z@XH?$OVUELNes4jdgrw=jRx2vqlgCN!NY|DF?iVf9a(C(LS_h}B4Sk8cfQTDv9=DD z0*6wu!$^eyfjbb!=*g|545?FmWinFPJY*7z-;|UEUX`pW<20u^^e$G3&3YttZ~vYz zWd=MNN9#E`LO{v{`0_xHvK^Rt7Ak>Ni{%BoYeWAm6P>WUGOWF(}r zl+=>bw9|`!l2xa(bkZrZS2o7yjT$Xg>MV*#?VYsKX?ZBDrTZo&+*yt^@(Yph)k;!Saq#+H*$q+@B}$)`9%r+{u!+OrxdZ?gATB`EJTcj9mF{;V zUfICOa=brvBl^O~Zvz23_3;eEv8_9Vn3=AwFezziT`5}1X^2Uw7)cl{3@i;j>Plti zi;(f88ce#s&6p)>&pfhj+sXHe-_URHTA<`G+If;c!FoAlTIbBKA?&J`|c%u z=_9WW0ws1g;SxK?BM0$gkMp^<3a0&!ZeYA-;LL^!eTl91g(JiPjg=#Bwrw*}HM9MS zqz^CkI{WWi*BD9ofrG<>;>3bjii|Y+HM3Wddp+^j-ZS*^@!0eByJ{$>cm8!OrOE!G zX8W`^XuFFzT0Eex^BvZnTm5UwI9had!ky}%zCM2F`z}dgef{nrX>F!hDbg}=W@PXx z7%sQl$xy~{Av1(M^Azex{n=+Y&daq{?cAP^*y;9DzH8hDPlvij$*?x0^Z57bYe4Z)a=A%$efaV9W%-#S6@l(Ilds?^ur5;! zwcBr!Uu0_FR(4soq9P>yMr98)f=ELr4g3d^&Z3gz2P7ZHo)XJ6r_97D#3B9{#DYI;^J#P3`Q?TZ4sY ztTTK59T?2njVU6&h!(nN%{dl}rNHBRMA=zk9FtGZu~e_MGeg4-7rk&f3R+I|FGdwtZuN7J2bBx~gS zOuuB0EyOM@V?DqaHRUfi<`=n5NICoMY<03VIN3~pzWFU$CbT;40#xILhvUa}7!)uU zEtixtS`reL3Km$02d^M5L;{}{KXdMWD=zPej%PBFq#+FT;r)QX8wiHD8 zBv-~KJ`vSHP>6#k-I-X?I{&^?3fneG7DXx9D36q~V5wuNUCBypin9^b$J~qlrJ|&u z6fmU$+=%H{@K$#=ZpOjLv5rZ!Qn{iw9oD$JjKo-Lug@MG8DUAiIbt>OjSkiLnr!w| z_H5(I?C9DT=pUXJwdpt9yXyOR?i?Z`v+#j-hy;dKx!LbPDrfSoI4 zro~C_eTiS?qRjJ2V9v{H>@@lF+?>2gxyAZDSP57&qSRh!I|=P>=I%-KgtM|k`}E~$ ztRxt+r6A4@%_3_tOChj(^hHC|y#smgvAye=nhwckDhW63__gXyn(S~eeeL_U)Dn8_ zC6~^nJcir(;JlvWR%=Bl9LPYN(`|X}riCbFh|FqHa5jmb;FH2~bQhC)yPY8Z%v)RA zSaNt|EkaXqK7odQu|XD-p^{jaOHosm*b|TOb56P-X{zA$Sy8Z{M7n~~#2O`8a=-=Z ztyKtwjP!+_UW#vrTaWFKsYznJIE=g716-^FXY(3lwbZd0%c~0`w?1!7GOcJZ_dJGr zuo=A3B4u5XLLKbRQQ&c2SSIvCJlVOt*nG;+rc=WV$j+JA-d!;3C?;OwiKO_SsgQ#naI!>`E|F4%&2qB*{XMca6^dg8x@}m@}A7D@#rOR z=DL4VsCrhI4|T>-6viyprdOmwqnf3X6`cc^Cd!f#cnPCF|)4as&sj(jz9lm)Pqkp{50Hk z8;3V9;PCHdgjIaN{frLDTp-yy& zf}{^?#Gha1S7C`K;y6C}+;YnE?nvLkeun0;laa(aoU{)}5(%_poxt~@#<~*8RP)BV zBKP5{#|2@sb94_DV|eCN>9ak``kf(%RH%&j13kIa$?h~~5u8|W$=^uMX_Jn^Mb~le z*F=el%-AztM znY#SpZunoDYLIa$2#1WJD8Q<-U&XNj@jz$6ivogiZ0M~7X9AD>a9_pnd=!H>gEzqQ zh+Ky>L|Jw<=zQ*b=R-G3F9D*#Fz@}xl~>+({#8l)-rhB~;3 zxk%D7yanxFj(^*TnFD%vwB1=%8e?pqeh`=#zbbT5tl|| zc#lCStE}~yWFr^)wvTD~s!z%KO=i+MkzD~RY+cm>=}_Jof^29t(p%^LWk zbK?zatT`9?>l(iJlaaSWkqc-4#Ise_jJ>Qbu3rHuF;p318EiGI|-wL`Xz zvaeGPrWM_n<*z)9rv{!Mg_$jqMsn7uE|r|VJr7ss!7w5w^Z(*)1~>eXD15H9-Y~W` zPcpT`pN@SF%klQ&4X*7%NVXk9)QM0q5E%^EW4Gh$(yF^04QrN;!B;+r9XW$qgT9Gr zP;mgYA76hn#;1V5EaHDzPQ@v^+fC)+HtJ*#=LHb(Th29XMuVw$<>!+Sr> z*2opc9vfgK8)x7b!|Q9OE?)S1;s1^Hi$;iYFlq1l8Or2L#NiUAhKPs20PJvnl$$%{ zCK+q`rgsfvPy;XdWSF zt!ryn*3xBX)4PLxdjELt)x{ZGv$0Wq0SW5t-KCo~Q*!|TM+4*8+T#5o%3A4JM2C6p z=<+GOzH7Mv&Xcv3UpaZ;r?c|t+By0c6Y|paqY!Fy}E16WA_b%y1BY*e&h6- zB|e{9J_C5H3vTPzR4+6vR)83^>&msLwM?$yom0;`za_gl`&YZ@n2E%?YRrmBp`Et# zNR`rdBQ(~LBbY%j{L;%ncfR&V`qfhcon(1+@$}Z!)z#k2Pk(xK1$f;k3kl|gXgs(G zi4iz)rs4JV)YqU}sM}iESUA$idvJ0FOYW12t=`(W&^m;O7R*{i(HFN6i(5klx;PX3 zmBoi}8G)wHU)$vT)a2P$ z{w<=;1$p&OadLC<49=s|wcy-EzniuF46NfxfRe8R7CEM)aRxS%7Q>NEOW%&~1rbux zvaoPq;^9%6t9r_JDnf&5_2Ady`(H@YOw+S$2|Dg^@GwE$iM;0{bNXH z`!Z^KQT8rWIl+^^!CF-|fn%e|E`C=qVovp}h*vWd&LCjFcf0+*e}4WpdhBsnCp#MC z;OZGPO?P(o7DodG=J9FPiry!7Z)`U1FZRAH>+*JZQNSf2Qryx5z{tuMGBe* zbn30%h2*}ix85xM`=?>Mx_P-Z(J}$z7xFwrksPww@R|Vk4)a66d#*~V@prYKsc}JW zL#Vl=7#F!%0>55q34C$BD@E3leDT7@lA~NG@09wkI7*Wz7q_=go}irV%>C`ns&}Fk z93ql?D8pxLAd&?Eje^f3qJb?9a~w~sB?&hJ5L=+#rnC(yVyng`^{%O7gMZB-rGL)A z)UWP{3Sb{vHQ3I-Ou%{rOF%!6FOauQ+BCP$+PJr*)1aMcOdz&<)V(W?PrX_kRJX9& zzi(Nm!8@}WKz0UMe%kkM2!<8tnQG{&3xz2Dw6#T_W2c3AB=I z0)IE#W%v|@+CjV$D#(B`XhxA{mLlr(b|mHYIK&`5s;N@^fPTu5EUIiP3hEqL|Cgcg z&xmt?e2q=SN0b%msg{(tr-XCUW%>20%_7I%lp8}Dpjki**`#!4$~>p z1#(F_{(KS+{a7P3gU!_b&G_?nR08q?w-#WfJ(x+-Xg_Do@_nG*MFNIbQOyPL@v=j)FcqUo#HYek*{aWJHFbaa!jscq@XU$4+D=^n6z ztrEv9d!q1Uj__&Me^Lh_W@m;1nPEC%azx#Jtsr;w`)k)ETT-JegBd6shzgOZA*s>o zem9J3H|Zh1=FAZm_k2Vt>%{5nyN-4Y#DRx#z_kxBim-CBaE$oRX+1@|vqK-dskywm0@QrA!8mmO!SUlX%+IL(cBl4+ zJPVnGj~?x@bM;UTDhxq^pa4?@r+P7C{YTQgLZB1sl!3rR_j1L#0C90BKpEso*@(+v zN!Yi^Tp~0-c0W$!9Oe#O2)wN381B_W6d&eJNvy7gEi1$c;ht1ayZ62nC;huRIxaKr zSjYm`{;Kn&0blWycV!x4Qx9M+b2!eY`TL?1Zr($DM$qHe{6t(c|2nuiSs_o{vsm?K z0a|g#Tij+(fdl6q=0e9yVS__E!G*JgEc&(VsnYLx9*0-4E4wbJGa+#{0$4;t#LyZv zmWh@@0Z9WNxsl~~!im7UX5$9?hQqp#WWjIIt6x%T6C%9?y9N{Y$rDW@)D>Fb1g12{ ze9>=TalXCvh>om;Hlkjz_9Ku!Z2P=}fsA~RjIjj1ICm)fn1c^tH@|fSIz!xW?Q(s1 z_8Y?JfZ&#UaK_p+dWwz=am#kVOG|gco7%M_IAy-@Qi^Hwe0(QNdWFIgxd_j)j^FDplG_U+r zg5rl%S(5alg`~r81DB)3r)4ZzldPr+;;Vuu`w7}sHA74&jW^(c^#CT1%UEm2fzC|S zT-s^%Ul5hakZ_t;_v$c;PDlLR&^NUFP6lbu{{Suw7xN$-lY#Y2bdJVrDw=rDD8Xg2 z12UyAm<$Hz3g5XykMxASVxnuL;6JJE$%QVKtK3|<_NyWJ%(k${+RSE8uv*SBz{-RrPjUhi1gCVRI)($*c@efhG zFd6jsbPIJxu*-h>Lu_gQV&MHN!^&EoUsfy-ytBH3@K-Ge!)hFOSKz-jwvb~ro^OZc zDD6Re^BUaubQ252vvVK#w{qtplz;GVg)D`tB1c=B`=Cl~?SOc<=;0-w*{BCKasR#e z2omS4L^o#YG4X0f-zX(hn2Sj^Uuvo{I@q#)Kw9Z|a`MJwBwrWA7 z6y=KD>TL7|cvoQJTo6n|5vq99U2FFs4|F)2eAIGjhY zt2^%dnp@0ef5XpLMpGW9wM>p=5>HBqE!H8ro?XbY1k5aEnNtIC@2C@f^y*(74VS4q zEY~*wb`vvVSt^`E8FTNcW2l6G2EN=m9n>5+HOq|kqB>s)KZS5&4vEtXcU=Lhwl3s# zDYEaXfHE?&-f9{)Jz5oU4=Z(E!6wWH?h%RMZelh((7{r(WxGx^C7N1eB05R0SRQ1% zPVuf^F0|k#{(w1(&4(k?qy>hrTPzH=uPJH(zY!E>Az{&t`w({|s7{|JH1(T?OIa$k z?2K^ci+V)#3K1O|#%8W&g;Qu0i1Ie>fiI0_XJ8qK zuBH-O9+oV`oHExuC|`l)A)=b5+G<=2frrRxnq{+N85iOLSBI(E26574vMolLJ($1L z)m3}IwhH+tG0tyg=n9$|Z4fO@P8*Gr2W-zp*0KXO8Yd6iUO_ojtNFIAuH~jy+jhWC z+b-8?li#-2wbm4}9dJEuT4_7%>JP7d^4j4F$4t{2+cDQhwl162*-iqkx1DCIEyRbL zwsSOc+93Lwp0!;D`7hW8T+8bcu;k0OLDwee=}p(>@Ty@a;gyuFcWk9&?XtCrwO&W; zipW|(?3%DXz$Z`(*wauNL>^PMJqJdu*q+ZU;Ciht$6hS^o*sBTjr?|qIi@Z4D%TFv zHhZmWckKbY6>}V}9d%awJl8(-+k;SkA=V9|e+E%P2d+e`A%~(K@d)B^Y(+*W39-nu z(;fuN=h&B{oQ+Uxz`k1M^@zvO|Bpx3ve&S!*YNHR*D26;Egwr|BwV?+=#; zp6!u#W8K|YcQ=(u+k(5B5I3_m6g5ABeR)k@J!?&S>=5xx`|Z22B$LT@Q>ReoDU^8% zwLRlHk9b_hK|9-VoyS^i$Mrt)$8lUvq0BSLpO?p_7ExcLeQ-wsjHbjS|z$8^+w z9p(sIeNNdSDw<9-@viqx?>4Dio9j+BX~S!!>1-23MaWNY88lsJ(t({%HBG=Z4pu|c zrN*hQE09w_=X+C$>l$18OjnyAHkw+SX1T7LJ_OId&3rz*8p^B5@evW8#@=~NY*p3K zRjJA3BBmQnjci4R_%N@@Nn>Wyd^Zo+3U`N^I$hTztJuO3>+Izb>tOzf7Du*=D6ayl zyH}jLO-+8cs&=3$MD5nJ(yfIS*Ptfr+(~t7o7TzkP!Ifi)cjexiZ#99)`G2Gc5BUI z<5ag6a<-slwzUkJ)lEBHJ8(_0QaP}SZEo7*BIdZJ{nT!j+wOGOv9MhV4`WABZ%(Oa zW1+n=dP1aT@@fbNsmHeF)-CGfqqO;^Kl9#M~Y97@vIzP9NG;t*S5 zvCMpGF^4Fxt+nPd2Sj*tg(Hqic8HKu=}2KKER?6HN2EQicF$t+!>u&3otU3$;>ch- zG34p4+u_JVnT2$fag?#KLmk%1cF>z^92In3c2pwPK*{$V5Hrmdhn@Po!-cp2u|2ZS z-0FZGwb}0IaaY&%JC?evb*CJwu*{QTG`k#6(b?p926G_hm=`!+Y#D%BuzxnUJGQ!V z%!?hXU|+P=u^qq_lO$1$2u_gCgs4NtpG zP=@Z7PdZMIM3>e4q~n~s5$;|@ITvxZ&T=QA4P}J<%TzbI*EK)o7-+d{e#SxfrB=sH z@YUyD}f8w-a$bU>dF4On0H1nsX5IaeZ%fCz)SqE_S!dxV2gD z?gV~@+i%|9T*XG#9fI<;SPNDJ^R8wG^79a37Mu4rcOc&-kJ@YI1IzxMKWjeL{Io06bfLN5{X*@5=8af)6CI;wh{ooV&96bMqxQULKHax7Xugcn2AU7LUp5amA8~In-)uha-UfKez0*RP&$#zk6wT+| z`+&I=1g+GYkJp7_m-QS zI%+-V1mp`wU#98hFz-r`8h>eI&#Q7+pmHL&lvt_`N>4YZ{OO6xbl_lS~67R0T zk`SrP&p07QS&E&{4!703TgJnsXe%vc;iop>D=?>m%~|ky8Z(pV^Pu}e zJjGJu`BgNYTxsx}Dn{5RoF+QqJ>df~Q@AGliJ0(g${}jRF~lQI z6kVhjPnN!mXG%x$l;CIT>FVj^9R2=kB9ifhkX({SvPnMqGReWeS)E6gkS(MQe@*Qr z@;Z5ke245Oza~4$2jn;84EZgmBLA2FGXG_Ai$BA^M{e`)^OwjFf0h3&$MJvQ|G-K7 zE&dLt5ClQNMG5gjA{Qf!5;C|rAzR4il7u`VpGy{sg;Fj}_>S-$E<<#SYq>Gv*TrpI zo%lWRdz?@FzPOuPEdEeD$n}Va#3Nit{E2vsTOl47f6hHF{zAOSeO3Gq@e211@v3-( zdtSUHiQHx>R!ZWwODWPQZkLoH<#2nXT&aNj-%^oO%>76zm&&;xOH-xU+)-(cRLh-| z%#xWqBUzgN7K3Q9rlnzT|{$^B0HJ83QVp|nnV zn!7G-ke=agN&QkkcSriB^pD(-v`N~;OVTUScX@@hRocp{rPrm``Dkgow4K*T-`WerK8eOK216<{X0KOIxGDrKVJHyB9<>#Bq$Pit0GzPHNHV{RB@d@ zq+Y9jn*SYsE9hcC4auZ$@{Q*qy$|UMq-!L-Y&|98`|K*ye&dz05GCU^c4btaZM;se z^c)BLqL2{v6!jFss}0~I0{)`e1?~d)>Id8h;H#Ip{{&wh;0B1u{hs?h`06e07WnEN z?jxe)6}*C|`B*-dMDs~}68PsReiVt}Gx#w?%V+c1B#zJJb4fg3#21kSehObo68Q?g zf~4?s`MD&OjtohQdLrrxG79>4hMdPsv)%P znp)%O8Y`4@K#6%Z3!yKZ5@tNffUz3`^X{wURgw-fZ3~$OGwpwo3i1YdlT0UX0nH+Z z$YC;@9095#$AISIuLV}aJp47OgPHgNG2yTLnaK?xD<^OQY2YMIB8_NGoAgKNPsA?W zl5UY^=_BbQ;)G!mNQ**JNW`s(Rz#C|idaP~c~p_2NFnnTV-?xtONw%Zo_tv`RWTJ} z0S9w_AC82co^DlNgmf9w0Hi@kH(_+3BSwXsG?->o9|O9Kc&vH=aj^QPk+9E31tg7} zk7P{1{4`^xF$Yqc`?S4rDGAw8(vmQT3< zpz`;t|54)V=bxkg-^x~ht#%*efA{wPLB9EU z`nB`F(eJ;MT^=O&ljhp}{N%IF-A{^h_Zz2A(~nOo_i5Vuuln?$a-S4KKW!gAYrVf_ z`b+5Xd1c;jK7H0U@BO^Tp-oEHtRlC=>Z#yeTKO5a1)pK(0cGI-EgeH11IoguS{?Z%JkM5;^FTAmAo&BCN&W~l zn;+nRODe&OZj&luw2(on!Dl9t8j$WH3x+MA-$t_ayndU0Cnn1Ac-=XI_CW5olAxSV z(|$;YAU}M64{ALPv`z-CMf_F*1^z{`3ZKT+^sh;QMCes4kw`qWu7t8_B#O{qERMnd z^Q?tFeU-$KzXysZUjs@Y{{WOoz7CW`HjrnaPCxkuNhQybZ;?^tU&vvw$4Q_p==*iB z2d5Af>f!#C5AZk22g(P_Z|aF&q1WgW^l5O-)aU5)^~HL4;`xfvjifrAg>gwH{o$w0b6++lM1PCF7kidQ!kwJtIA_5{Xh>D025dp(P zL`B4i5P?BtARj=$YGE{2OqifGR>{9LCQHoaT9O3$u zlBiv7IsJS78Aw7poJ@WB@lg^E&`c$Sc6QsrN4Q-$E1XMh?L=>Xu8-ca-W>Q8j$q!5 z_QT!7-C3`M!^6D@$3dn$#;^pXE5e1~4WJsvaXsN7;Su3cbc_j)4~g*PP-b{K)i5(W zn`V+})>?Xa9@QHPFAA53D`*Y|hgZ?(;WSgt!&Tw6-FA~b6^A#3H-)Ri+tD8`&4Hby zhj-CY#S)>!@ZRu&P^fO7VFzphG|S6bN5dyf9pgyyH1%L`81_vgsHHvL~Us zjAWZPYfB)v0v13#k|>P~3Rgsi5q&lB*GEQ2#zrParbg}v&4|p3%%K|Au(d}PP@hWC z>&4XXWs%1`%cq``two-saeSwR)pV?jyku6GcaERdL}e&}X|lQQuspJlztaNig{>z2 zyY&*Tr8Z~4_DaY`hlesFuhH>FWJhE-wYiUu55hAepF}>39E+TcoQ|B1il{G|5KRn~ zMw?@->s9}UrJITOu~_KX&gKK6$SBKxBKql4)f9;%ES zi;g7e;^;Wi;UPN4MN2~aBSq0^(HYUwXc@JTA6*z-5?xMGE24?v>5*7;2H9zGv@%58 z=$hzyvfmk@=FyEbhBeX6G_Hc^*67aY9=3dHdqs3V&36Iykv-Rn=)vfr=#l90@PKed z^lPg9OlW_2UgWb-evBXKyF~2|l|+kU^~3XGNpwzWESY#dvXjzK8MRf)I{wb{!~(H) zu`IGf)d7-^J9}^(_=GZvt#pO zi(=)mir6Y%zurOKU=OZEvGe=0|B?H%F|-fhC+|)9f0J@g2$|PaB;_8X<7Dp1&O18q z$gaw+$~~QXnrVK`L!K|smpwasc3whW0(gmZG^Zn#4yM!d(wX0-x=VHTknAD+ng4gk zde7RA|5+*(v&ly0h%(xv%%k0fPb?A-iFn#wEvKD_q-~2IJ;Jwcxs^iZuBUtrgkMQ1}&*3#r;oHL3`1=S|EuIy^NurcY zDPU4NN?DY0DMcuCr__s5A*BJ7hEN(|WdBh<%GAO6m>+%Se7s4MDNV1F&!jZl$jvkP zB1+|^-tY2?I{7L}Rg~6J+Ftn4?wmuyY0bd{? zkciaW%?YFi(gT@+97>@;K7H;d9~g`@JTNj)?B@8Y1LFcEfoV?fzzogQD3#w+vy$L@S|fB9o2Mf*T({t!Cir3PHrf;H+UfU5uKy? zOy4PAufV~$5x(kR75S&+pY=}{8~>!?pKSOiAN-R8|K!3y#lb)M$usQ}@#LA_7Okw4 zQ0i~L-~Fj2U8EF9!Wh;)YtsG0bH+ydXKJG(%Nag zBb2qr+9!PYU!i#Gxb+v&T=PqyQgj?$$6D(|-9!X+vTiBb>OQ)UXs@r(SBMNfjIM7T z@b0n9|6}z^m25vr*b|s%a3OFJ@I~Mq(*yJ)pyPr3 zmcD_c6~=df@j#DXA2LmV?*KDV1FyVy^b3sk28`kbjA8@$wcwutzZU#6ICneF-2tou zXDYBOu$Yk680Z&(jewT`JK(HIjMm4Xp>w^MunBZ{q0#nQ;2hNEaV9{13E>1_JTT8b z&K$@u1^q`x`JC4`-|vBF%ja?4XQcg+R4;h7L1u#QbFS0Ke+~{LZOprm=cSL=qOXYX z8PocQ!1sWaD7^+fWd4-~52JJw@IQgzIGA_)FTf8l#>cq-z=2-PP9o~08I*s+=vMk} zf&4mPd*By@8|^Q7)aYlP?+RK;N%m>f@Gdxi1vUeI0bGF*9Y+m*=+h7R7tqRNjKZ_| zQo`nDq_+d_L+LEgn0=e9*Basb3nNQfgZNx)Cil&n4!RQk{1&rtCG^~yk>uwAbE*G# z7_EMV`hni8Ih%o}P|7yE(&o2#K4pIny+IqkI9S3O@IA|XoNAtmcCYvGTQ(=Mp5-g1 zl=?5P_FW1)XFVKtu7VX|jvTC9Clxi{3Yu1{{DWhIvx{)1a}(-8i|9i<@EOctp8YaP zrvXXZ@-+DGW3DH7GWt2{RX)>JJ~X_Ndn>Ea=RA8hWYAmtQ>+oT^Z6_(|K!bxzMsx* zf&Ry%&XusnJ}A8hb5Q_HGI$@5>pyDdbS~lJra$nI8Y@)a&8S|+8ia=RYT!Jy!u=V^ zd~1v68}+r+tGT>R=^bOUEDy zKWY5|=LXr&=v>gb=yPY#w;22wSOw&Ez0plzb6d2C5^OYqyH=0AgO2=u(iY0&uw zKL%ET&wV=$&D`!IkEDws69Hymj9b{YwPo-gg&e$Yjz?K9vRL%#>)-Y$fU&u+z9h3)O( z9_m8yQy^ahd}jvjdewSX%??p$ZrAu8LKz~nLGKqsq^`|sVnU}d7Yv(9{4aUc^R~K5jg!Y z`{O|00s1biuMi}=06SxK90xrflGAt(Mm=P@A@|ezy^(w$tM7fRsrS)3T~&2ElnV6U zVve;KentT+(PAxMm+dBu)|XtfodJ3-baDu*?+f5@oYf9zWrB`jrT-qBTd{JxfuCml z661@&Z5}$szzWtUBv-)?+yr_Qa3T6!4*9Q9e-(PNA9xybJ)d{}bR}Y|ZihKNiYwRa z*q_`Fem&;sUVJsDHSz#f1oI!$Z084fFQFHCtIzI_wa>JTeZ`Yl3$LNYGVteNtsTJ{ zk3$a|fnU#fq{Fxl9>z+k#2Wt)R~GKoZd^MuvBp>MF2#D<+Zpm+MPJ3c6!JfORu%73 z^oWOWj@!2Rfc_q^#SM<@Sg(K_*wy9*(C_#yPa z6ngVR1ClxV8gMS)eUyghBp=JO(-5@hb8>8cOLu=rwg+|wwxoM~UVZnX{>QM!KSb+X z+8piv3HT83ZScDR8=}wIXv+usb>5Xx-?;R0)b=s&(5#oiNeBLtcSm|OO5cMed<6Ot zv^xdZ0eAr8t$}y_5LbZ@Sz|ih*de!g0_S$Xd(dygNGC!wHvmTgTiE<=^1IQ`QJ|Z$ z4eL%QZI3>D2`_ZaCT-{-EPNlXHNDa2yD|1-XzMG?qXYVLl(qt=F*t94a|P&6xmWsD zaOwj`(p|XJ&44%R5U>T|2u*h@I)GNbfMl3=zxoQ^Vd^g6Gy@j#y`&xj%x3%7rD*Fv zfiD7IF*d{d=Rbq<8P5F$PyjWouAaF{vSt+Ya2h(P4~z%rZQ!@y4B=faT>%FWy%nDA zI@Di-I-8=NyCLZS>+wjfXTAON+4(@+zn@(Xd=`i&17~snd-fUNgTOt&-vM)h4*{P8 z;u(Ty2pUf+&SD3C_K(1g!2f_u3g6e9JqixrpH2YA1M_MVsPs#Zt~me>-`%|6N!H#4 zOyGUKkyk*z&w9pi?&3R8rscreSHZ#EYpsv(1q`2`Gn7DnWvxVMIZ%*(Mu1<-Xr*u; ztX`l;p+DcEhGoD>=t*8}8{i4_?F8SWnf~)#c6<%)xN9#(Dfi@h(0R2J`CiQQ*+oyN zht@=|bu;$sfR~{*+-KF|X-v&aK(2WpYU_iV`#?W^O#Op^d>45db-rKA_o3C$a5dLM z$lAM!QC55P*WgaP_76Zj38^{8cW|g-zBdasXZd~&Iw=4qaX$&aVT8p z$WNjkH<~%avy46r*7V;cQ zR{%EycX;grM_3#9EZ`u-inFSnrNK> zy#X}KuK?}^4g!ua9G2f<&SES8jsTV;`a~&eTW#d|Sy=^I&r=Z~)&jpFpAcR`ehGR3 z=+{6`2L2kzPeN9*q`Vrq#yiV`jD=^I3Que#{DwRRtO1fO$&)Gu8S*ybW6e)&`YV2x zxLDGCy)04fz^NuW4f1Ogo;9fq)bKUvEMlmZT8_X@?gwI>YCOO4QJr)bwu;di z$NrXS@?ezB`5DM;i&w`m%&F3!z!E+IO_H*Qu{5@ju9{<{l!9{*xEk0MGuRzi z01N<2t%Fo^CG=ka%@4!8uQoC~%Lyng29|p=XL()B6qpxAem@am7C4o_QD;dTx(VpT z{4ODN0CbFLYdYkw2Im-~wE=WH(4PUzfhT~QQCbGvRJ)f)2YRa47O(=6s~I(-C#YfI zl!6`yIsv!z_Ecn%sExHvy~SAAD_RTS8^1U!XC+50pDI*%RBAWs9_>% z&h#Wboxpc(!dZzptJv$m;28?yrcMBy{mR8G|zk&dRxsL{f6NWg}t#(`eRNDfCtgrQMJ4( z+p&zg1vRWhe=2}8!Fe3Ly1{FgV=0lnHNcFM9`tfE>ISf=2C#Fqh4F3$CPHQ_`g{nS zhfv#MjH?v7It-b^o^4~K-I=3jfIo~mdI+rXYRC@*eFS(1MpOIP z0dyN4k^GcBm9fdum=WHqY)6Y@fP-=FZdg=6ErM0>Smt|{xv^EeXEc^5GjXhpz%l@nn0cX{#@= zDWiQBH1_8XzEkrx2VDvb0j~kR4*7YI`3iU?_}2mh;NS}Dpk3SRVGa=cG2d9w_`b|{ zA87CDc?avk8Oi7-Lnj_51o{@x9YNm)IuCdpH2{717RKoYei9JZS?{|coSWyve!#~u z%HH88c=8=+X(_%TTFNx>OTeE5ehK(^^6$eQz`@;$b2UcCn(u>I%X7v9TLLjI8{@LQ zT>;;-G=csv^uAxH!7S7q!WzUbqNWUp?^0{=-Ae5SaBv?~gMDeu79g}&^9t}&AimG4 zL5nr`wytI)-}}_Ueku9oMCa7s#i*K&7*(skk5LstG^r%SC2A&8MS^H6I*1(6L&QXH zQ6vW8f7wTiv0|c_D(*1S4%OaVv=;RQf4|&C{6btH`iM)#<>Hs(8gae2N!%iC6?c9g z>naKVquxRUM19d-bfk6FQ{;;R(O(RvbvRNKi*cevOcOJ{kB8M8@vw#=9#$FZXd*c7 zeX?jQg5)!@M4kwXi^YYaueeNHA+8kHl3(KZ?6--#Any|`sogZXW9(!iYBj|>>r$wu zHlmTp5ZR&|jlY-ZE(*l}F+_|Iqr@0QFP$!Cnl|HwEn3l;=^{~d79kN8mxzl*KQT}Y z6;~mGJ4ax>UED2ZU3cxc$yR+}Q(!8v9WWah;xLp}cVI7IA#eb22yn!8*WEnP8U>sP zoB^B%Tn4NJZWul8#v80^;CA3H;NH>WC){iu0Dc7g6nGSP0(c5oTU>JOby@=xfJwj< zU^*}h*mc~5>&EGPU{7EnaKQK}H<#!kz!AVvz%jt_z{$Yr6DZR&fwO`0fQx|TzzX21 z2_>V)>nh+{;D$-0J-rE74cr0T4crGjIO)dm#rhEN2=F-YYv371TTPmj)5Ugy^?^yi zWMBZ;jxg8G0(J%F1A76BfP)G1>=D4xz;VFIz&n7Ygk9}Q4*)*`ehNGaJV6+?PXTKgeH!QoHUu^$jQCQ3X}}C%Hn1x&HfhSJ zNxmMy-oPT@AmA|I)sv=7oa7q~91ENXoC>@HI19h!<~LBBdoE4HxBng5-$#RU|Jy!k zeDY|?G5dZN>zyMi6Kn2Y%_ZUlDn$L`PttgBM*lfu!*j;QKfxww-$E|yAor^-ufaKB z(|?MJt~Sm8rM!hm{ugpd-v6It$~j=GbHLPdz}Dx0=c3#C{{%DWnmwGZWMk=yI$g}7 ztLGxIOso)9Vx8D1s>KemM;s7`#0ha)D(RPrGFhg{OqnZVvZpMRgE*S394kxYbU90w z$wi(m$^w&*Hu*x6FY{s^%E!FehIHTWqXJ3$4&?q^uRLLpC*SBbFHekl@`)xUV&YW8 zUuN=6Ufy_?$qztICF!IgpmfrPr0q!ul8$-hP3C#+H2J_=K}}A2{N{U2e!%2LzPTxH zQQzcACNJ^MPoC&~PMKqJqlc8`G*-%6k2U#XkKek&-q%UQo6K%bJh1Hev~Ajq<-C!xQ?hT3$=BsTU%T}||Gu3^l8BKcVI+#|mSZ7{IEFv4U;H3icsZu!C5^E@B18Ay%*-v4Z0fD>wnMg6knxaDBuI zZh%<94PgU~U;~MW72FuHf|C#{xCvqfH$|-AW{4Hs9I=91AXacPVg#f;!4bp?jv`iY46%YQ zK&;?=#0tI;v4XoJR`5lL72E@{f`5Ve>xuch7_owTAy)7uh!xx$v4Z;`R&W7g1@}d) z;6lU-?uS^xMTixADPjfpN37t>5G!~9epfpXv4RI7R`BJB6+9TRg0H}@r-zU=@cj?( zgi7hSOU$NYrkF#=-Q<(YsD$6Ob&psh){1+@X0e4zcF|EL-W7Yr{o+$PekHyV$HhYY zK70{=AO0YIAHEpB5C1iOAHD>?4_}JkhnM5`;Sb^W;mh#*@Q3mH@a1x$Tq_=t>*Vv| zHTi;kL2Q;U$`{2J`Ld*If_zoJD&CNrEXRZnqNU7{`_hf|;mq*R5fP%5=mZIzbVuC`09cBmcFRy);B=~KJZF6pS< zYPWRN9<@itsl95i^s9YppNzL&v0jl0)~nX5vYz!@>$kGLwZ+;Z8(6Pfugiwko7S7M zk+sd*CKIiuu|8nPk0dy(^nohpof1sr9+_xol>AVSOQ+TVGmV$`;mF)>ksw z`m6O<+0y!(^*5PfePewiTXD2;naXj-WozrKbyfy6{mG#AX`f6ZlW=7lT~F7O>AHb# zAlvFjx{++Bo9Sk6jf$PC>|w~`%nKnG-|PSa_!qi(C)$}HVpx0juCrp}bvI!kBC z&N^FX%N$LI?4omZuFTb4byu0ELpmh8>WGfWZaSu8GNki$z6|T`y1R_%9=eB&>Ylo% zjOkvwm%Kpt*1cuEF4TqcLS3YbWOvyx0eXP!p$F+f@)vrr9xQw6p?avin4_Z0 zUK|fyUc!;kWp9pwF8jEaYsmuFc5T_$bzDalx^Zrt?B~Y2@v_LR=hl;#x((b0vcKEN zZ6q&q8@r9=0Jn+TL=JRYxGm%$x4qk5UhcR3wjAtt{EocBALoygL;UgncsbPUT=|`F zUEvXfc=rpxS5Anx=#W;jl`NF~ko}Ob@Me5{-e;conRR^T4;GXR3rfR%(L8(Nc{@38 zCw1&Z+GEMHG?ZzotJPZ%qdT>j=t;ZVbGh^RL>$4rkB~l@;9N@k#sa6W(;s=Ea~bk} z&H&^^&LGPB5_LK9zRqCeh0Ybo`#D397dgWyFC@8NBJb-AM_%Y$iM*dP0(p^hHRb(C z?i%EMosq~3ookWzb4DRAaz;~LL~_?7@9PvJFLZ7|-p?6>yvP|y``5nCP{KmzD#Cuw zb%aI#hDOF>!Id8oAYIWSY^) zbfb~mjYjS;8oASGWQNhmOrw#zjYeh}jof22Qff4EBaOennFNj8294bHZ)#+=(a3#9 zBXf*K<{FKZ8I8;{8kuiwWr5MmuZ(6E8qGXlG_%NP=0T&8#YQ7bj7F9kjg%XWJY+Po z%xGk}(a0l4BNav?j~b0UW;AjyG;%*I<=4>2!~dp6Rv3+}G#XiDH1dSe$dg7Rl|~~^ z8;w*MjXYyCvf5~5jnT+&j7HWPTY1iCW}VT@^F}l4jb>gjn%Q79@{-ZW%SIy`jYeKE z8rftt@;Ef|6g2WIEak<2QzNe#jr`VVWV6x87Ne1Bqmeg^M&2|U*=jVh&1hu1(Z~*? zk++RTb{dWR&S+$p(a3J2k#~(o_85))hq0BtMl-)Rn%QSG^PbVnexsRJp^?|2k+-0c zci2++-5lI+JXy;Ujpa3Rl)PR}kQ3!3IayAV)8!0#x11&Km9ynsStdVFm&fhKe==Up zzXOriO8!rn(Q>p<@@7fCL*61wge`BCw+ctzCT|n2yi?vO;^bX&rtr&qWT{Ay_sKa_ z!~61m(NGOigG8gacjDfmeSxBVfnVLJW~jT=Om(-KrS4Is>RvUQpPZ=c)%DcPF^Zqu z(A~LcUgz$-4L=K!Q+PadKEI97!V|t9B+~1YQEhSxNelI`dIEb8ZueoeTs@*H)T8P# z^|)H0R;pD$X;+cGbhjR}9=BFlE3H-56V{W~Q&y$*v{hw2W39HHwbod_vDRA8S?jFl zt@YLm)&}cE>m}=D-=n^jzEi$cz9)QVd`~+mPO9%2-)idu-x}XKr?u~S-+JGRP8%oP zX{O55{XeGzb)TA}=Hfky-^ITwqkhk$`^+@DlUzh2TueuXSRx)09mK<8x#$F~cUHHk zTSON%S=}LW)iY|fxInE{YsH0BS46Z>52-~s9&jt>H)P#J*XC|U;iv`iCU`4 z@eGA)7SN3%-O$wm_18oFO;LYy#OjJyBdGn!YKoewZdKFNZECu@og@{VaizM_)FGi? z^^9#_j}nl4y!HTB40s z?!)dQBIrKqt|aYyyW1j4Gtp9ev|UOmX4-CVWHPArIby;0JSCnK{Jb^kdpSkxrcyp* z#;eggpPTJw(|9j+hf(i_Q(uzYDb#Yd`-Hn%T*cbMa{%FHxFPD*rNqto2V99Y^j|q6 zM>IKiTV_jvoeJ2g3p@40PV2)?8^BH*n>zv*^8BCZitZ|3AzXlV=g^FOBJ#xy(qmPcrppYOC39s&c9*?m zp&TFw%i(gQ97CRt{oG9QZ}a3LSuQK&Dp@7h$&IpF?vT6XKKTK8i#X{gjF(8 z@2+l8#e|boiBSGhKkX0vbNyv>XP#_RPwY-Mon!YPs;^y0SY*>K*&b*QvS}A=Uttg7 zU(MUMP?|)ar`osL(@5$8dlBI>oAws=BX$MhD*Fk-r|e3?D*GA2XKlLD+ppTM*>s(> zx7gM8>y*D~Z?)GSllE~%vFNr*Rlf6lF*=c%%X& zl}7U6x{~sFvf8(>epwF!dXUhAGV;s6mk*Htiz5r}OqSJ!X8#JB=?7@;w$OaNh3_rB z+29$F(6@qCY-q&?O*qhmi&4g5lzxmd9-~a4T84{E>8Ev*Mk^(OR!DtX84YPgB+^Pq zBFj%Fi*HAko=4W*O%E-vaZVjCpT~IZeTww!)mIVoqCQP6L?J zAV!;p(YC>8(=pn%nA3Kc)ApFt49sZ?r|oij`(e`Brhb%14;5e@;lE% zK1Gs8k^CQL#+yj;C6YXevM(n;qU@n{yoj==@&9@8+bH-Q668H3zafJEuZ#SK_Nsl>E7q&lZ>=rX>(-mr zHtQ|xZR=g@u=Tn1h4rQNmGxKaZ`L=~w^ogHR%`9kuCAvW=tjDkZlPQ0fKJnGb$gwu zvvju3(fkBEq$4_}^L2OKL-*9ZbZ=d#i*$cIKo8P`^-$+qr^Y$!O4o92*KyU6&EeE;kE{^$B%*XO>>%zZ!a`@GLQ&;9(K`+nY;L35(H(L88A zG!89@UW1mypfKzh4h$!t1Ly+!fHAbzZUrcSDPRTI0tWxx=lkzI-#7Qrc%hlwjJSY_ zL!D>i|4a81SidCy07YB1bIiIIp1+d+{dp$$HT#3k07_Oe3zk;Ck`=VVJfY|}1vs-D z3+4iaXac1FP|!}_3Ut=Da^{bMrhhBYRemg4-wBho`hO#Ze-w1yxAMQrBVfx}2;83Tn>2 z<<=p#A=z;7Z4@F7rSJFP`&7q22@%QmF7zKh0c%yC0OMMobcCjd*1+00)_4x5F}}1pbv@*aT7@(5!57+ zNNQ@DJ0O(|s;;PDbmf1fW!xYqtDF;uw6wOdBg%p6Kda(_2EIW)o-|2Aijkxd#Y$_7 zhLHh*4C<>A)QPI9#Py)`=XWIf!*@jSq=osqdx8vL-Rd3&P%s1o;DJGQ44eS~u!rt< z=W?!^{5r3hLMic2EQrvMnrREv5!Arfg(#g%Tr8Jswwk^8>emBWM_|3 zD)xs?oA3xJdMkO1?HMsY*%!a-o`bKtmIBg62xzP=zW%uBQtnSh(Jyrg*PjmF3x`E$ zwk$Sy3`p~bXK{tenI)!|VCgT}wrw+O9M3)&WaN7IN-$o$zfS)~dpqfsoy_z`8)R1x zRom&ssEMw`q}+LaBr>?r9IFfRyB ziTbcuAr0<%b!1NoRz`e@Z)zlen_KF{g~%-V&W9G5up^TO$X+%x$tlVX!wTE|ns5X( zeR3H92h<}dPz>r)F)Xx72s~U<;%b@Vt@vAcN~lx!gZL-`Y1Q|? z+8GC7#`PA$7Ah4h?y6PtfcC5dB#@S%1!%@JVH(95_|WM=S}H2;w7tp!U&cw^Y)XG25t5rtw00OVHC95nr+gYY=*-!HIl z-@YGRz?1e*YNmrYR(sbYxj@X9DiP@KCM1I8CAOlSy&J`zN8N%K{&KDt-G3yh+WaE?D&0< z&Efrr$rGzkyW`@zXZ#YC^#s^x6S_f8$u6$7g!sSl`d9;48<(w{E)7 zvrONL?=cqfAAyB5DD`>Li>xm9@RX$ZdIv(au7HdT5=p8g5}8b12AL|Tx}t*7NB%EB z_WR+8KRNtgf@!qeIY*NF{f2|LPzNGQC&t1`Hc)i6y7dlKo+1xB>gL-Ds@mtbRK*wT z7OD3WY{u2_R&Oo$cjLm2RVYn5ITw%hcgcqiu8oz;n0`;l(%-1askd-v)6E;sp{Mb7 z7R}^(^@{1S!$q_Dg3f49F)8&)rJL(Gc`x&3?pqfdbI|(6+N6rv+)wc{T&dwpi_Xieu)2MF*DAt&zz8>1F4B`Z14ww|ncA70NP&C9vYxelC}( z!rI(=A$r=`tRUj*weCmrK?gPfG1Ut4Ew#lcRDT~&u;pT@v-A=9v4(o{#!71Mt7zpET(E;|`7Dh+YAHti&e3@qNq-8oWfk)wAztJe zgNEOa59A>%6@^nE6V)`;6ji-ky+Aj0BEi*ztWHpMbtMyAH$tlVMmKj*jYL*eb@liL zfcN=Eo7=1K+kqx^WilRrV{1A_0(AHcKx+^}AQM7hoYB7pK**ONPllX$H>g1%6A7&K zco~5^Rw2*|gdn&Ift&vt0{^6L`j2==>t0oc6tufPG#}VJIBm7Kl-*YY$8B&9LciB zPfsa%0Bi6FsN;!iK%sAp94q5OB!G&axghhE3wBg01P5rKe7$_#UFn{Z`k{0mD$SQ3 zu?#a1)F2Z{B%&sn1i_5-yGmlIe4oTqbEYGwD-eX_1hBJHjG3!-W0W z;`-jq&|@tZLkuIkqPwSWPi@R=ayEKiUaHf#!RM?OHXOqU-BQ?c(60G-~qC%7%%Z`y54w7DUN8`J|^X!5)p z)-|YG=`cw;Ne{C%*kYZn92grEP^9Y?UDoa+?F6@XMmi%UXxMMY*;#EnPs&n8_g^%h zGHy}V*2t>b=bSH;m2jUg(LuYegkv}2@fU*af_h{J$ipH74gi*rC=dZXt)kZtNy37a z7!MK&d0-sK&&Kh4Mj{9xQOgxW;qQtK&Z=dxjcD~)_C#ub+MZ2CL~4Qdt)~QV&B{Rn za3q&F21bE}LRpLfO#d5}VM`c$^c>{Q4z0(1ROrW0Qk@3#K%37jGXqUPBc=gUKTh|r zvuvf92Dvs1LCX}gUqvxf5Q6e5ifQ~ifgEeX7<{hvkNkoIFelB;k+R0+V^qD%q^o{o zSe3vcv$?U|q2pUO5xNXYIX~ThMIh!%KR9TU7A56UqNB3)W=@gA`IkX8)m85!uA0&2 zHow-7Z0_e0^1YvbUXt*E)8?MTL&8h*_FF+CMcg@ve22d36BdqBsawv!n|?d-GEPEO zyV@ark|G_ekjD@`J&?jKHZ@@N{$zIZC@%jetH!nMiL_LO;D8K~_o9=OPVWcnmYl^N z=A67OcO}Bz!7#`6;ry%I?G8N|a3e#N-80Y1IvAwDk9n!M!7<;F;vA(rjf%Wj&r|2R zXLCOA%W`;Xq`ccNVP4bL?=adLen!~2Ne#cd=d_sFDZ-snRYTDUUO^Fw&}gib#H=l9g`gor6e%dnj&`0wd8tZ==mGR2`WO3!!&jN z8R}(iZ^pdcl>{>0QyhDuhxdiY4E2$5$77*a5%-W)j~A4BB~E0OU>0z4#oc*0l>7h3 z@#E-}M6xBMrmvKgWu0KmV9{yKnC2J??o7AJ-*3E$ZFp8@q4vTGrW^b~iaM z@>%Q2bJHH)p^ih zJM&~r)ra2Y^PQ7^Q=M!+V_u@UO^eMR8hu56J^ECzE2l?u|FA`m4;Lzx{Sm1b!mL^s zoSCttM}F_#1^Z4p3@v}>^7g)vDRQ~)k|v32%|9hiD=NmUFZ_JXFF&@K7FzZXT_4rF zKu1~CWv9~lNISIvXM?Cooo#cw`!x&L%i9WGRQVpr^ndvC+IjtNHtp+d^hxubGrCj3 z<#xMGwq~xcaavSdglCIwi^EU%?aL(AljjBv6dx|`ou%?(eNa;JilNaq2Tl8?)tfoL zUitcI%*7LrOXc-Tue-%Mz49uzb~vDJHX_GAyVc0=bVcO7{p^Z$&#!ow1bNP}bp7+; zKu__dIN_hZA+AvhX+IUFj^(sBWveHCsPk{EyknPfVQbCBhV)0}6XZe`Sy^k@xW69f z77-}@qq`M@MqjWz*m$p0&}gm z&h4K@Eq^aD2{ftFT)!yh)7#QZF%yeY)(r2O`|iXQ^SOcRk9HfJn5EdSU9ds=2S+pg zs-L~zGKs@6dBa4c#1}Pf9^D|Qn)+L(dFvsi>TUKBxgw@8*!xzOc1Y6s#(v%A{}Z+ful`s!Ch`;y}2B+quWe{zfy z9t@iLsdL~+?>iTdM|VZb1sL$^96C<>@#WOzL)FNMn**L~vfi;QwlnQz@$LbI~sHJ_2zJw7H`3dr4dW= zQ(J$yqOht@?vZKCiImw5J`sAU7c`=aJNse+rt&Hm8FRffM?0TQ&zpELq@`@k1LHv^ zhTM$7S(nDWc(QgpYqM%muDSZ`gU_zk(uvcTt%;moXIkZGT<1tL9&;*@|tU z@f!}tk2!lM*Y^5p>shALBFXK_BMYB+ED&+~Uq5`dZ>?o;&gxSim#tb~$(iqaCBAq{ zjPd}VWo>L38wMt?gXInl|E) zwy-ztxwSVg-SaYTezQ_!qFZB;xX^cC%KQg?&&B4+4VCU^7Hz7`i+mnEF248a4fWK5 z#b%w)`G@vM-d;|g5VEI6{>)6n&^ei-_UK$*@~Fj4Qxex^3}g$r++svEua zerxC2WTI)WYVzx)cP~FKd0mz0mGOWC{F(lK@P(_QqWJKncMDSd8vJYjymldW+uOMn zACn*08kc*Se?AhIb}C=Ft!DGxrDN%@YgzKQH_QK^Fz;d^+pVu7_jY-Kr`LOSrvIDJ z{#Vn6U2^oZnW@}!GC=KIZL|G!M^4Wxi?OPaj|)7P)n8`Db^D)w#@6-F@!0yhNdHLr zNr${`RnrHh+wb}Dp4#gnL0ca!d-|%tmpwvn+~6Bq7v56K?rlTbpx4GF>fUFStNPmx#oZk)pO6sL zdQPI1w&qExXh+rIDJq8Mm!E$Qa9l#o>}k1%B$=D(>}WYQNp580yp~k;t?OE9)+ueR z^0qWkj30G;-^m;U@8uc!d7tX{HEm%fXD5#BdQkFa{+_^utMxi1A7g*NDpo!FP|c^T zPx@rMeeb<~*GC!A*5}(=4~w3jcwu(SFSn4X@JTXHT|Lx$_Au49yOUF0%VYm_s%&ug zIuT*gmW1~C1mCt;W#xOv-PLe$W6sS{bE1vxi`-`TjJ6Gp5SNIf(y}8hBs1Nngx795 zMTgFhWlVQ#Klk-Jb*5RP*C;dRH;GZ-f*`*9WI0;vUARk4ceh+)q)n5!Fy?br{YF2D zWoDq2)`GAccHsJg_#da0yH1#{x^{19)$B}j-uVN~yUg>Bxmbh+|DrTCdP;xYjI!)s zD$)&JUT&LqKT!3ebBITEURHeg({n#>xEoAVdS|)csrb~eeessM^=&%>!zb&fts4+O zVA8leTcufpR7Xw}xcj-c6|AvUZka0m#~2+s3Qt~+Yw&uTP^nTP2z8GNx~#*`K9Jrn z{fBP0E336DeXPUe-dk2#pKLaNFh%EKO?O9!XMV(%!%O!iiwyjyr?d)tgV!Z5DvgiO z&8W1$|ESZdXNqM+d9Lq)OYb}`{&dJ!zu?wyX=TwJH-8nrZ_V20elxkiVeXxmmO&2& zOA5P=D{~IJ+kQG+HaC4})eHNBEDmH_`M3v* zEySLF%f)OPv1CQ?N)}&8%*>P(|33JzBwktQ`^7;cOFKTz(cb>?^Blw7h7 zUTwd2vF42pO4oYgVkTuUnW>NB;!YBSXC-rWLNj{LDlJ?wz9nX9mVQW4mqEWu@R=CF zA5NbZO^Py6Xg)SdXPIbHv}Ts6qs1@Wn|GWB?|eAy*@3z$)#a#sZgE+~&?=9` zPtTlF&&wi7#Ud- zFk)A+YSXS1|FPk+U3Z=GH;`P<$s1VSV4_r_oTn#f7^hTf zoTq%TesWBaUY@#sfVq{YMr-l!c`DuY?xq__n1V_@i79b1-7%|O<4{qg&2;Dt-;d`O%^6s@0{z5!+PSCzutN zCT`bGjB@T#y3irITD-64$DbP}_HMk?GrXo@%DocX9@WBnt=^aqJ$i+8w!NDQ&kY;W zt~LDVz~~N@y|p!QD_u3%Ilc=^PPl8ZcWCiqZd&#q+wdsQQ2dm$L+eJgj+Ji8hDU`f zUEi}mYJHBbx9m6;W>;e9rolGS*%{p@-8jrH|J%NrJHPI0mv89yZQmVM9mh7<@U(W(K_E!UDx!%8DH6)kUQ5 z{(2)E7N5ssc&slU`gOG)!j+lvd7|%UT!tsT{QtQx zmq%r10>11_Bt6>i_T_L00UZ>~7%=0484t|(U?u=FA()9|XVPAob5B7B1sxQ0P|zWL z++@E7=%Ap3f({Bg7|_9h4hD2Epo0M&(#Kq;g8>~3=wLtx13IK6$$Ski=-`45F6iKb z4ld~6f(|a|;DQb==#XApG95h7!2=yU(7^*8JkY@d9X!y%10B-m2$^G+Ui-2$(7^{C ze9*xM9emKi2OWIS!3Q0D&>;XF0?;7<9RkoH038C*Apji$&>;XF0?;7@9Z~~i9wQ;> z5P}XN=n#SqA?Of-4k73ef({Yr5P=R6=n#Pp5$F(s4iV@OfesPq5Xp8Bsl4Bxd%}_J zARO5a!jbJD9N7-Sk?kNH*$%>y?I0Z44#EK);57&Vo)ZE(2=LC38fae5wPJrhGcus)l z1b9w>=LC38fae5wPJrhGcus)l1b9w>=LC38fae5wPJrhGcus)l1b9w>=LC38fae5w zPJrix51y}p=LC38fae5wPJrhGcus)l1b9w>=LC38fae5wPJrhGcus)l1b9w>=LC38 zfae5wPJrhGcus)l1b9w>=LC38fae5wPJrhGcus)l1b9w>=LC38fae5wPJrhGcus-m z6nIX7=M;EOf#(!>PJ!nXcus-m6nIX7=M;EOf#(!>PJ!nXcus-m6nIX7=M;EOf#(!> zPJ!nXcus-m6nIX7=M;EOf#(!>PJ!nXcus-m6nIX7=M;EOf#(!>PJ!nXcus-m6nIX7 z=M;EOf#(!>PJ!nXcus-m6nIX7=M;EOf#(!>PJ!nXcus-m6nIX7=M;EOf#(!>PJ!nX zcus-m6nIX7=M;EOf#(!>PJ!nXcus-m6nIX7=M;EOf#(!>PJ!nXcus-m6nIX7=M;EO zf#(!>PJ!nXcus-m6nIX7=M;EOf#(!>PJ!nXcus-m6nIX7=M;F(0M8lVIRiXrfaeVG zoB^IQz;gz8&H&FD;5h?4XMpDn@SFjjGr)5Oc+LRN8Q?hsJZFIC4Dg%*o-@F626)Z@ z&l%u313YJd=M3MkJJ;mw(Q9 z(jSwl%uFEtzW?WTLjITE8U1$_9O%BvM;xfEC|x1`Yh9T9UoQrKTkdra4F0xSCgh7m z($z8p14~;gWyQZ&&^XG9{~yQ3UJxh_VSPQMuZ!gl!M@Ua(o^=`L5mm>U-Z{O{|BO{ B)VKfu delta 9651 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 Gl>ZN+BRjtU diff --git a/Marlin/Menu Plans.xlsx b/Marlin/Menu Plans.xlsx index 240b2a210136d97fa9bd23834416466c29ddbb74..8c7e2c17ba9cfcf4559c10c5272f3a1d3f1c8632 100644 GIT binary patch delta 29022 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 delta 23030 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 w{)Yhqf-*-)B2!pHO(U3S{$2S Date: Thu, 20 Feb 2014 14:28:29 +0000 Subject: [PATCH 185/256] Fix some extra and some missing tabs, to make the file consistent. --- Marlin/language.h | 86 +++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index 769b6025db..025f9cf0b6 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -41,7 +41,7 @@ #define MACHINE_NAME "Mendel" #endif -// Default firmware set to Mendel +// Default firmware set to Mendel #define FIRMWARE_URL "https://github.com/ErikZalm/Marlin/" #endif @@ -159,9 +159,9 @@ #define MSG_FILAMENTCHANGE "Change filament" #define MSG_INIT_SDCARD "Init. SD card" #define MSG_CNG_SDCARD "Change SD card" - #define MSG_ZPROBE_OUT "Z probe out. bed" - #define MSG_POSITION_UNKNOWN "Home X/Y before Z" - #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_ZPROBE_OUT "Z probe out. bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" #define MSG_BABYSTEP_X "Babystep X" #define MSG_BABYSTEP_Y "Babystep Y" #define MSG_BABYSTEP_Z "Babystep Z" @@ -344,9 +344,9 @@ #define MSG_FILAMENTCHANGE "Zmien filament" #define MSG_INIT_SDCARD "Inicjal. karty SD" #define MSG_CNG_SDCARD "Zmiana karty SD" - #define MSG_ZPROBE_OUT "Sonda Z za lozem" - #define MSG_POSITION_UNKNOWN "Wroc w XY przed Z" - #define MSG_ZPROBE_ZOFFSET "Offset Z" + #define MSG_ZPROBE_OUT "Sonda Z za lozem" + #define MSG_POSITION_UNKNOWN "Wroc w XY przed Z" + #define MSG_ZPROBE_ZOFFSET "Offset Z" #define MSG_BABYSTEP_X "Babystep X" #define MSG_BABYSTEP_Y "Babystep Y" #define MSG_BABYSTEP_Z "Babystep Z" @@ -527,11 +527,11 @@ #define MSG_CONTROL_RETRACT_RECOVERF "UnRet F" #define MSG_AUTORETRACT "Retract. Auto." #define MSG_FILAMENTCHANGE "Changer filament" - #define MSG_INIT_SDCARD "Init. la carte SD" + #define MSG_INIT_SDCARD "Init. la carte SD" #define MSG_CNG_SDCARD "Changer de carte" - #define MSG_ZPROBE_OUT "Z sonde exte. lit" - #define MSG_POSITION_UNKNOWN "Rev. dans XY av.Z" - #define MSG_ZPROBE_ZOFFSET "Offset Z" + #define MSG_ZPROBE_OUT "Z sonde exte. lit" + #define MSG_POSITION_UNKNOWN "Rev. dans XY av.Z" + #define MSG_ZPROBE_ZOFFSET "Offset Z" #define MSG_BABYSTEP_X "Babystep X" #define MSG_BABYSTEP_Y "Babystep Y" #define MSG_BABYSTEP_Z "Babystep Z" @@ -612,7 +612,7 @@ #define MSG_BABYSTEPPING_Y "Babystepping Y" #define MSG_BABYSTEPPING_Z "Babystepping Z" #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Error in menu structure" - + #endif @@ -699,7 +699,7 @@ #define MSG_STOP_PRINT "Druck stoppen" #define MSG_CARD_MENU "SDKarten Menü" #define MSG_NO_CARD "Keine SDKarte" - #define MSG_DWELL "Warten..." + #define MSG_DWELL "Warten..." #define MSG_USERWAIT "Warte auf Nutzer" #define MSG_RESUMING "Druck fortsetzung" #define MSG_NO_MOVE "Kein Zug." @@ -713,17 +713,17 @@ #define MSG_CONTROL_RETRACT_RECOVERF "UnRet F" #define MSG_AUTORETRACT "AutoRetr." #define MSG_FILAMENTCHANGE "Filament wechseln" - #define MSG_INIT_SDCARD "Init. SD-Card" + #define MSG_INIT_SDCARD "Init. SD-Card" #define MSG_CNG_SDCARD "Change SD-Card" - #define MSG_ZPROBE_OUT "Z probe out. bed" - #define MSG_POSITION_UNKNOWN "Home X/Y before Z" - #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_ZPROBE_OUT "Z probe out. bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" #define MSG_BABYSTEP_X "Babystep X" #define MSG_BABYSTEP_Y "Babystep Y" #define MSG_BABYSTEP_Z "Babystep Z" #define MSG_ENDSTOP_ABORT "Endstop abort" #define MSG_CONTRAST "Contrast" - + // Serial Console Messages #define MSG_Enqueing "enqueing \"" @@ -906,9 +906,9 @@ #define MSG_CONTROL_ARROW "Control" #define MSG_RETRACT_ARROW "Retraer" #define MSG_STEPPER_RELEASED "Desacoplada." - #define MSG_ZPROBE_OUT "Z probe out. bed" - #define MSG_POSITION_UNKNOWN "Home X/Y before Z" - #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_ZPROBE_OUT "Z probe out. bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" #define MSG_BABYSTEP_X "Babystep X" #define MSG_BABYSTEP_Y "Babystep Y" #define MSG_BABYSTEP_Z "Babystep Z" @@ -1086,11 +1086,11 @@ #define MSG_CONTROL_RETRACT_RECOVERF "Возврат F:" #define MSG_AUTORETRACT "АвтоОткат:" #define MSG_FILAMENTCHANGE "Change filament" - #define MSG_INIT_SDCARD "Init. SD-Card" + #define MSG_INIT_SDCARD "Init. SD-Card" #define MSG_CNG_SDCARD "Change SD-Card" - #define MSG_ZPROBE_OUT "Z probe out. bed" - #define MSG_POSITION_UNKNOWN "Home X/Y before Z" - #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_ZPROBE_OUT "Z probe out. bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" #define MSG_BABYSTEP_X "Babystep X" #define MSG_BABYSTEP_Y "Babystep Y" #define MSG_BABYSTEP_Z "Babystep Z" @@ -1269,9 +1269,9 @@ #define MSG_FILAMENTCHANGE "Cambia filamento" #define MSG_INIT_SDCARD "Iniz. SD-Card" #define MSG_CNG_SDCARD "Cambia SD-Card" - #define MSG_ZPROBE_OUT "Z probe out. bed" - #define MSG_POSITION_UNKNOWN "Home X/Y before Z" - #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_ZPROBE_OUT "Z probe out. bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" #define MSG_BABYSTEP_X "Babystep X" #define MSG_BABYSTEP_Y "Babystep Y" #define MSG_BABYSTEP_Z "Babystep Z" @@ -1456,11 +1456,11 @@ #define MSG_CONTROL_RETRACT_RECOVERF " DesRet F:" #define MSG_AUTORETRACT " AutoRetr.:" #define MSG_FILAMENTCHANGE "Change filament" - #define MSG_INIT_SDCARD "Init. SD-Card" + #define MSG_INIT_SDCARD "Init. SD-Card" #define MSG_CNG_SDCARD "Change SD-Card" - #define MSG_ZPROBE_OUT "Son. fora da mesa" - #define MSG_POSITION_UNKNOWN "XY antes de Z" - #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_ZPROBE_OUT "Son. fora da mesa" + #define MSG_POSITION_UNKNOWN "XY antes de Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" #define MSG_BABYSTEP_X "Babystep X" #define MSG_BABYSTEP_Y "Babystep Y" #define MSG_BABYSTEP_Z "Babystep Z" @@ -1640,11 +1640,11 @@ #define MSG_CONTROL_RETRACT_RECOVERF "UnRet F" #define MSG_AUTORETRACT "AutoVeto." #define MSG_FILAMENTCHANGE "Change filament" - #define MSG_INIT_SDCARD "Init. SD-Card" + #define MSG_INIT_SDCARD "Init. SD-Card" #define MSG_CNG_SDCARD "Change SD-Card" - #define MSG_ZPROBE_OUT "Z probe out. bed" - #define MSG_POSITION_UNKNOWN "Home X/Y before Z" - #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_ZPROBE_OUT "Z probe out. bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" #define MSG_BABYSTEP_X "Babystep X" #define MSG_BABYSTEP_Y "Babystep Y" #define MSG_BABYSTEP_Z "Babystep Z" @@ -1834,9 +1834,9 @@ #define MSG_CONTROL_ARROW "Control" #define MSG_RETRACT_ARROW "Retraer" #define MSG_STEPPER_RELEASED "Desacoplada." - #define MSG_ZPROBE_OUT "Z probe out. bed" - #define MSG_POSITION_UNKNOWN "Home X/Y before Z" - #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_ZPROBE_OUT "Z probe out. bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" #define MSG_BABYSTEP_X "Babystep X" #define MSG_BABYSTEP_Y "Babystep Y" #define MSG_BABYSTEP_Z "Babystep Z" @@ -2013,11 +2013,11 @@ #define MSG_CONTROL_RETRACT_RECOVERF "UnRet F" #define MSG_AUTORETRACT "AutoRetr." #define MSG_FILAMENTCHANGE "Verv. Filament" - #define MSG_INIT_SDCARD "Init. SD kaart" + #define MSG_INIT_SDCARD "Init. SD kaart" #define MSG_CNG_SDCARD "Verv. SD card" - #define MSG_ZPROBE_OUT "Z probe uit. bed" - #define MSG_POSITION_UNKNOWN "Home X/Y voor Z" - #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_ZPROBE_OUT "Z probe uit. bed" + #define MSG_POSITION_UNKNOWN "Home X/Y voor Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" #define MSG_BABYSTEP_X "Babystap X" #define MSG_BABYSTEP_Y "Babystap Y" #define MSG_BABYSTEP_Z "Babystap Z" From 99f632654451335711baf7c1a900e2cb789a8b4e Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Thu, 20 Feb 2014 16:43:37 -0800 Subject: [PATCH 186/256] Remove unnecessary dependency on time.h from qr_solve.cpp Fixed compiler errors on Ubuntu using arduino-core --- Marlin/qr_solve.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Marlin/qr_solve.cpp b/Marlin/qr_solve.cpp index bfe4fce1ab..55dcf64093 100644 --- a/Marlin/qr_solve.cpp +++ b/Marlin/qr_solve.cpp @@ -4,8 +4,6 @@ #include #include -#include - //# include "r8lib.h" From aee63afccd7585a75fecffd8790db1bb00ac0047 Mon Sep 17 00:00:00 2001 From: RoyOnWheels Date: Sun, 23 Feb 2014 14:36:50 -0800 Subject: [PATCH 187/256] Clarify which PID values to enter Users can be confused as to which values to enter after a PID tune. Updating the message to help clarity it. New message: "PID Autotune finished! Put the last Kp, Ki and Kd constants from above into Configuration.h" Old message: "PID Autotune finished! Put the Kp, Ki and Kd constants into Configuration.h" --- Marlin/temperature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index decab104d5..b86e7588d2 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -304,7 +304,7 @@ void PID_autotune(float temp, int extruder, int ncycles) return; } if(cycles > ncycles) { - SERIAL_PROTOCOLLNPGM("PID Autotune finished! Put the Kp, Ki and Kd constants into Configuration.h"); + SERIAL_PROTOCOLLNPGM("PID Autotune finished! Put the last Kp, Ki and Kd constants from above into Configuration.h"); return; } lcd_update(); From 77df0d689a86ac985baa9e35117ad26d2c4ec6ea Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Mon, 24 Feb 2014 13:15:36 -0800 Subject: [PATCH 188/256] autretract fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I made these changes previously, but I can’t find the commit now. This reapplies the changes to get auto retract working again. Conflicts: Marlin/Configuration_adv.h Marlin/Marlin_main.cpp --- Marlin/Marlin_main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index fd5e6b5a7c..9fe64119ff 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1135,9 +1135,9 @@ void process_commands() get_coordinates(); // For X Y Z E F #ifdef FWRETRACT if(autoretract_enabled) - if( !(code_seen(X_AXIS) || code_seen(Y_AXIS) || code_seen(Z_AXIS)) && code_seen(E_AXIS)) { + if( !(code_seen('X') || code_seen('Y') || code_seen('Z')) && code_seen('E')) { float echange=destination[E_AXIS]-current_position[E_AXIS]; - if((echange<-MIN_RETRACT && !retracted) || (echange>MIN_RETRACT && retracted)) { //move appears to be an attempt to attract or recover + if((echange<-MIN_RETRACT && !retracted) || (echange>MIN_RETRACT && retracted)) { //move appears to be an attempt to retract or recover current_position[E_AXIS] = destination[E_AXIS]; //hide the slicer-generated retract/recover from calculations plan_set_e_position(current_position[E_AXIS]); //AND from the planner retract(!retracted); From d819c55395e8bd1c2fb61aa0415c9a292b5662dd Mon Sep 17 00:00:00 2001 From: Cylindric Date: Tue, 25 Feb 2014 09:52:58 +0000 Subject: [PATCH 189/256] Various typo fixes - only in comments, no code changes. --- Marlin/Servo.h | 12 ++++++------ Marlin/fastio.h | 2 +- Marlin/stepper.h | 4 ++-- Marlin/temperature.h | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Marlin/Servo.h b/Marlin/Servo.h index 35e040c657..204497a4ad 100644 --- a/Marlin/Servo.h +++ b/Marlin/Servo.h @@ -24,7 +24,7 @@ Note that analogWrite of PWM on pins associated with the timer are disabled when the first servo is attached. Timers are seized as needed in groups of 12 servos - 24 servos use two timers, 48 servos will use four. - The sequence used to sieze timers is defined in timers.h + The sequence used to seize timers is defined in timers.h The methods are: @@ -50,7 +50,7 @@ /* * Defines for 16 bit timers used with Servo library * - * If _useTimerX is defined then TimerX is a 16 bit timer on the curent board + * If _useTimerX is defined then TimerX is a 16 bit timer on the current board * timer16_Sequence_t enumerates the sequence that the timers should be allocated * _Nbr_16timers indicates how many 16 bit timers are available. * @@ -89,12 +89,12 @@ typedef enum { _timer3, _Nbr_16timers } timer16_Sequence_t ; typedef enum { _Nbr_16timers } timer16_Sequence_t ; #endif -#define Servo_VERSION 2 // software version of this library +#define Servo_VERSION 2 // software version of this library #define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo #define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo #define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached -#define REFRESH_INTERVAL 20000 // minumim time to refresh servos in microseconds +#define REFRESH_INTERVAL 20000 // minimum time to refresh servos in microseconds #define SERVOS_PER_TIMER 12 // the maximum number of servos controlled by one timer #define MAX_SERVOS (_Nbr_16timers * SERVOS_PER_TIMER) @@ -118,13 +118,13 @@ public: uint8_t attach(int pin); // attach the given pin to the next free channel, sets pinMode, returns channel number or 0 if failure uint8_t attach(int pin, int min, int max); // as above but also sets min and max values for writes. void detach(); - void write(int value); // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds + void write(int value); // if value is < 200 it is treated as an angle, otherwise as pulse width in microseconds void writeMicroseconds(int value); // Write pulse width in microseconds int read(); // returns current pulse width as an angle between 0 and 180 degrees int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release) bool attached(); // return true if this servo is attached, otherwise false #if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0) - int pin; // store the hw pin of the servo + int pin; // store the hardware pin of the servo #endif private: uint8_t servoIndex; // index into the channel data for this servo diff --git a/Marlin/fastio.h b/Marlin/fastio.h index a969d56ab9..53f8221dff 100644 --- a/Marlin/fastio.h +++ b/Marlin/fastio.h @@ -1,5 +1,5 @@ /* - This code contibuted by Triffid_Hunter and modified by Kliment + This code contributed by Triffid_Hunter and modified by Kliment why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html */ diff --git a/Marlin/stepper.h b/Marlin/stepper.h index 3a1cb0b5d9..1477a6e03e 100644 --- a/Marlin/stepper.h +++ b/Marlin/stepper.h @@ -71,8 +71,8 @@ float st_get_position_mm(uint8_t axis); void st_wake_up(); -void checkHitEndstops(); //call from somwhere to create an serial error message with the locations the endstops where hit, in case they were triggered -void endstops_hit_on_purpose(); //avoid creation of the message, i.e. after homeing and before a routine call of checkHitEndstops(); +void checkHitEndstops(); //call from somewhere to create an serial error message with the locations the endstops where hit, in case they were triggered +void endstops_hit_on_purpose(); //avoid creation of the message, i.e. after homing and before a routine call of checkHitEndstops(); void enable_endstops(bool check); // Enable/disable endstop checking diff --git a/Marlin/temperature.h b/Marlin/temperature.h index 82de2402f0..a8580def56 100644 --- a/Marlin/temperature.h +++ b/Marlin/temperature.h @@ -28,7 +28,7 @@ #endif // public functions -void tp_init(); //initialise the heating +void tp_init(); //initialize the heating void manage_heater(); //it is critical that this is called periodically. // low level conversion routines From fdce91192eeea86b9e46aef7141c336836ceb047 Mon Sep 17 00:00:00 2001 From: Cylindric Date: Tue, 25 Feb 2014 10:01:15 +0000 Subject: [PATCH 190/256] Various typo fixes - only in comments, no code changes. --- Marlin/Marlin.h | 10 +++++----- Marlin/Marlin_main.cpp | 38 +++++++++++++++++++------------------- Marlin/qr_solve.cpp | 6 +++--- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index 7a4b864fde..5998cef386 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -1,5 +1,5 @@ // Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware. -// Licence: GPL +// License: GPL #ifndef MARLIN_H #define MARLIN_H @@ -30,7 +30,7 @@ # include "Arduino.h" #else # include "WProgram.h" - //Arduino < 1.0.0 does not define this, so we need to do it ourselfs + //Arduino < 1.0.0 does not define this, so we need to do it ourselves # define analogInputToDigitalPin(p) ((p) + A0) #endif @@ -87,7 +87,7 @@ void serial_echopair_P(const char *s_P, double v); void serial_echopair_P(const char *s_P, unsigned long v); -//things to write to serial from Programmemory. saves 400 to 2k of RAM. +//Things to write to serial from Program memory. Saves 400 to 2k of RAM. FORCE_INLINE void serialprintPGM(const char *str) { char ch=pgm_read_byte(str); @@ -184,8 +184,8 @@ void Stop(); bool IsStopped(); -void enquecommand(const char *cmd); //put an ascii command at the end of the current buffer. -void enquecommand_P(const char *cmd); //put an ascii command at the end of the current buffer, read from flash +void enquecommand(const char *cmd); //put an ASCII command at the end of the current buffer. +void enquecommand_P(const char *cmd); //put an ASCII command at the end of the current buffer, read from flash void prepare_arc_move(char isclockwise); void clamp_to_software_endstops(float target[3]); diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 9fe64119ff..13f86159fa 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -63,7 +63,7 @@ #define VERSION_STRING "1.0.0" -// look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html +// look here for descriptions of G-codes: http://linuxcnc.org/handbook/gcode/g-code.html // http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes //Implemented Codes @@ -80,7 +80,7 @@ // G30 - Single Z Probe, probes bed at current XY location. // G90 - Use Absolute Coordinates // G91 - Use Relative Coordinates -// G92 - Set current position to cordinates given +// G92 - Set current position to coordinates given // M Codes // M0 - Unconditional stop - Wait for user to press a button on the LCD (Only if ULTRA_LCD is enabled) @@ -101,7 +101,7 @@ // M31 - Output time since last M109 or SD card start to serial // M32 - Select file and start SD print (Can be used _while_ printing from SD card files): // syntax "M32 /path/filename#", or "M32 S !filename#" -// Call gcode file : "M32 P !filename#" and return to caller file after finishing (simiarl to #include). +// Call gcode file : "M32 P !filename#" and return to caller file after finishing (similar to #include). // The '#' is necessary when calling from within sd files, as it stops buffer prereading // M42 - Change pin status via gcode Use M42 Px Sy to set pin x to value y, when omitting Px the onboard led will be used. // M80 - Turn on Power Supply @@ -127,18 +127,18 @@ // M128 - EtoP Open (BariCUDA EtoP = electricity to air pressure transducer by jmil) // M129 - EtoP Closed (BariCUDA EtoP = electricity to air pressure transducer by jmil) // M140 - Set bed target temp -// M150 - Set BlinkM Colour Output R: Red<0-255> U(!): Green<0-255> B: Blue<0-255> over i2c, G for green does not work. +// M150 - Set BlinkM Color Output R: Red<0-255> U(!): Green<0-255> B: Blue<0-255> over i2c, G for green does not work. // M190 - Sxxx Wait for bed current temp to reach target temp. Waits only when heating // Rxxx Wait for bed current temp to reach target temp. Waits when heating and cooling // M200 D- set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters). // M201 - Set max acceleration in units/s^2 for print moves (M201 X1000 Y1000) // M202 - Set max acceleration in units/s^2 for travel moves (M202 X1000 Y1000) Unused in Marlin!! // M203 - Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in mm/sec -// M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) im mm/sec^2 also sets minimum segment time in ms (B20000) to prevent buffer underruns and M20 minimum feedrate +// M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) in mm/sec^2 also sets minimum segment time in ms (B20000) to prevent buffer under-runs and M20 minimum feedrate // M205 - advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk, E=maximum E jerk -// M206 - set additional homeing offset +// M206 - set additional homing offset // M207 - set retract length S[positive mm] F[feedrate mm/min] Z[additional zlift/hop], stays in mm regardless of M200 setting -// M208 - set recover=unretract length S[positive mm surplus to the M207 S*] F[feedrate mm/min] +// M208 - set recover=unretract length S[positive mm surplus to the M207 S*] F[feedrate mm/sec] // M209 - S<1=true/0=false> enable automatic retract detect if the slicer did not support G10/11: every normal extrude-only move will be classified as retract depending on the direction. // M218 - set hotend offset (in mm): T X Y // M220 S- set speed factor override percentage @@ -147,7 +147,7 @@ // M240 - Trigger a camera to take a photograph // M250 - Set LCD contrast C (value 0..63) // M280 - set servo position absolute. P: servo index, S: angle or microseconds -// M300 - Play beepsound S P +// M300 - Play beep sound S P // M301 - Set PID parameters P I and D // M302 - Allow cold extrudes, or set the minimum extrude S. // M303 - PID relay autotune S sets the target temperature. (default target temperature = 150C) @@ -155,13 +155,13 @@ // M400 - Finish all moves // M401 - Lower z-probe if present // M402 - Raise z-probe if present -// M500 - stores paramters in EEPROM +// M500 - stores parameters in EEPROM // M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily). // M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to. -// M503 - print the current settings (from memory not from eeprom) +// M503 - print the current settings (from memory not from EEPROM) // M540 - Use S[0|1] to enable or disable the stop SD card print on endstop hit (requires ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) // M600 - Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal] -// M666 - set delta endstop adjustemnt +// M666 - set delta endstop adjustment // M605 - Set dual x-carriage movement mode: S [ X R ] // M907 - Set digital trimpot motor current using axis codes. // M908 - Control digital trimpot directly. @@ -254,7 +254,7 @@ float delta[3] = {0.0, 0.0, 0.0}; //=========================================================================== -//=============================private variables============================= +//=============================Private Variables============================= //=========================================================================== const char axis_codes[NUM_AXIS] = {'X', 'Y', 'Z', 'E'}; static float destination[NUM_AXIS] = { 0.0, 0.0, 0.0, 0.0}; @@ -274,7 +274,7 @@ static int buflen = 0; static char serial_char; static int serial_count = 0; static boolean comment_mode = false; -static char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc +static char *strchr_pointer; // just a pointer to find chars in the command string like X, Y, Z, E, etc const int sensitive_pins[] = SENSITIVE_PINS; // Sensitive pin list for M42 @@ -302,7 +302,7 @@ bool CooldownNoWait = true; bool target_direction; //=========================================================================== -//=============================ROUTINES============================= +//=============================Routines====================================== //=========================================================================== void get_arc_coordinates(); @@ -339,7 +339,7 @@ void enquecommand(const char *cmd) { if(buflen < BUFSIZE) { - //this is dangerous if a mixing of serial and this happsens + //this is dangerous if a mixing of serial and this happens strcpy(&(cmdbuffer[bufindw][0]),cmd); SERIAL_ECHO_START; SERIAL_ECHOPGM("enqueing \""); @@ -354,7 +354,7 @@ void enquecommand_P(const char *cmd) { if(buflen < BUFSIZE) { - //this is dangerous if a mixing of serial and this happsens + //this is dangerous if a mixing of serial and this happens strcpy_P(&(cmdbuffer[bufindw][0]),cmd); SERIAL_ECHO_START; SERIAL_ECHOPGM("enqueing \""); @@ -661,9 +661,9 @@ void get_command() return; } - //'#' stops reading from sd to the buffer prematurely, so procedural macro calls are possible - // if it occures, stop_buffering is triggered and the buffer is ran dry. - // this character _can_ occure in serial com, due to checksums. however, no checksums are used in sd printing + //'#' stops reading from SD to the buffer prematurely, so procedural macro calls are possible + // if it occurs, stop_buffering is triggered and the buffer is ran dry. + // this character _can_ occur in serial com, due to checksums. however, no checksums are used in SD printing static bool stop_buffering=false; if(buflen==0) stop_buffering=false; diff --git a/Marlin/qr_solve.cpp b/Marlin/qr_solve.cpp index 55dcf64093..f19d989d41 100644 --- a/Marlin/qr_solve.cpp +++ b/Marlin/qr_solve.cpp @@ -1171,7 +1171,7 @@ void dqrlss ( double a[], int lda, int m, int n, int kr, double b[], double x[], Discussion: - DQRLSS must be preceeded by a call to DQRANK. + DQRLSS must be preceded by a call to DQRANK. The system is to be solved is A * X = B @@ -1223,7 +1223,7 @@ void dqrlss ( double a[], int lda, int m, int n, int kr, double b[], double x[], linear system. Output, double RSD[M], the residual, B - A*X. RSD may - overwite B. + overwrite B. Input, int JPVT[N], the pivot information from DQRANK. Columns JPVT[0], ..., JPVT[KR-1] of the original matrix are linearly @@ -1312,7 +1312,7 @@ int dqrsl ( double a[], int lda, int n, int k, double qraux[], double y[], can be replaced by dummy variables in the calling program. To save storage, the user may in some cases use the same array for different parameters in the calling sequence. A - frequently occuring example is when one wishes to compute + frequently occurring example is when one wishes to compute any of B, RSD, or AB and does not need Y or QTY. In this case one may identify Y, QTY, and one of B, RSD, or AB, while providing separate arrays for anything else that is to be From 661e378ce9de8165d64fbff6f28b086f26b7b773 Mon Sep 17 00:00:00 2001 From: anfroholic Date: Tue, 25 Feb 2014 17:46:23 -0600 Subject: [PATCH 191/256] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e85be7c3eb..236c312776 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ AutoTemp: If your gcode contains a wide spread of extruder velocities, or you realtime change the building speed, the temperature should be changed accordingly. Usually, higher speed requires higher temperature. This can now be performed by the AutoTemp function -By calling M109 S T F you enter the autotemp mode. +By calling M109 S B F you enter the autotemp mode. You can leave it by calling M109 without any F. If active, the maximal extruder stepper rate of all buffered moves will be calculated, and named "maxerate" [steps/sec]. From 8c4377dd63568291fdb62b7b2aeecb14a5982467 Mon Sep 17 00:00:00 2001 From: David Forrest Date: Wed, 26 Feb 2014 00:44:22 -0500 Subject: [PATCH 192/256] temperature.cpp: Fix PID_DEBUG compile error. --- Marlin/temperature.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index 4ce5cb16f1..6be3177a18 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -449,7 +449,8 @@ void manage_heater() pid_output = constrain(target_temperature[e], 0, PID_MAX); #endif //PID_OPENLOOP #ifdef PID_DEBUG - SERIAL_ECHO_START(" PIDDEBUG "); + SERIAL_ECHO_START; + SERIAL_ECHO(" PID_DEBUG "); SERIAL_ECHO(e); SERIAL_ECHO(": Input "); SERIAL_ECHO(pid_input); From fcd8524b6ee36dce954b72067510adf4bf5ec130 Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Wed, 26 Feb 2014 17:29:27 +0100 Subject: [PATCH 193/256] Only increase EEPROM version for DELTA printers. --- Marlin/ConfigurationStore.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Marlin/ConfigurationStore.cpp b/Marlin/ConfigurationStore.cpp index 80dce5df06..074ef6ae37 100644 --- a/Marlin/ConfigurationStore.cpp +++ b/Marlin/ConfigurationStore.cpp @@ -37,7 +37,11 @@ void _EEPROM_readData(int &pos, uint8_t* value, uint8_t size) // the default values are used whenever there is a change to the data, to prevent // wrong data being written to the variables. // ALSO: always make sure the variables in the Store and retrieve sections are in the same order. +#ifdef DELTA #define EEPROM_VERSION "V11" +#else +#define EEPROM_VERSION "V10" +#endif #ifdef EEPROM_SETTINGS void Config_StoreSettings() From 15d1b8d71985ba1770588bb6e05df3d5c0931c96 Mon Sep 17 00:00:00 2001 From: Tommi Lamberg Date: Wed, 5 Mar 2014 14:02:52 +0200 Subject: [PATCH 194/256] Fixed finnish translation - Fixed Few finnish transalations - Removed duplicate contrast define --- Marlin/language.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index 025f9cf0b6..0782763702 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -1564,8 +1564,8 @@ #define MSG_PREHEAT_ABS "Esilammita ABS" #define MSG_PREHEAT_ABS_SETTINGS "Esilamm. ABS konf" #define MSG_COOLDOWN "Jaahdyta" - #define MSG_SWITCH_PS_ON "Switch Power On" - #define MSG_SWITCH_PS_OFF "Switch Power Off" + #define MSG_SWITCH_PS_ON "Virta paalle" + #define MSG_SWITCH_PS_OFF "Virta pois" #define MSG_EXTRUDE "Pursota" #define MSG_RETRACT "Veda takaisin" #define MSG_MOVE_AXIS "Liikuta akseleita" @@ -1649,7 +1649,6 @@ #define MSG_BABYSTEP_Y "Babystep Y" #define MSG_BABYSTEP_Z "Babystep Z" #define MSG_ENDSTOP_ABORT "Endstop abort" - #define MSG_CONTRAST "Contrast" // Serial Console Messages @@ -1725,8 +1724,8 @@ #define MSG_BABYSTEPPING_Y "Babystepping Y" #define MSG_BABYSTEPPING_Z "Babystepping Z" #define MSG_ENDSTOP_ABORT "Endstop abort" - #define MSG_CONTRAST "Contrast" - #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Error in menu structure" + #define MSG_CONTRAST "Kontrasti" + #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Virhe valikon rakenteessa" #endif From 881e348eed2a52eb3ad50f27a12763bf012d1605 Mon Sep 17 00:00:00 2001 From: paciotti Date: Sat, 8 Mar 2014 22:35:05 +0100 Subject: [PATCH 195/256] Update Configuration_adv.h Increase Z_HOME_RETRACT_MM to 2mm default to avoid end stop not switching during retract. --- Marlin/Configuration_adv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index bca056f9b0..923badb117 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -215,7 +215,7 @@ //homing hits the endstop, then retracts by this distance, before it tries to slowly bump again: #define X_HOME_RETRACT_MM 5 #define Y_HOME_RETRACT_MM 5 -#define Z_HOME_RETRACT_MM 1 +#define Z_HOME_RETRACT_MM 2 //#define QUICK_HOME //if this is defined, if both x and y are to be homed, a diagonal move will be performed initially. #define AXIS_RELATIVE_MODES {false, false, false, false} From 765b2da3d431245e6f8b6e5c9bcfbf706b9e066e Mon Sep 17 00:00:00 2001 From: blddk Date: Mon, 10 Mar 2014 21:52:33 +0100 Subject: [PATCH 196/256] Added CHDK support Added so M240 can be used to trigger CHDK instead of sending an IR signal, see more about CHDK here http://captain-slow.dk/2014/03/09/3d-printing-timelapses/ --- Marlin/Configuration_adv.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index bca056f9b0..316d7dae1a 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -279,6 +279,9 @@ //=============================Additional Features=========================== //=========================================================================== +//#define CHDK 4 //Pin for triggering CHDK to take a picture see how to use it here http://captain-slow.dk/2014/03/09/3d-printing-timelapses/ +#define CHDK_DELAY 50 //How long in ms the pin should stay HIGH before going LOW again + #define SD_FINISHED_STEPPERRELEASE true //if sd support and the file is finished: disable steppers? #define SD_FINISHED_RELEASECOMMAND "M84 X Y Z E" // You might want to keep the z enabled so your bed stays in place. From 09af1b90b8b55eafcc3539aa1e8d08c48cee54f7 Mon Sep 17 00:00:00 2001 From: blddk Date: Mon, 10 Mar 2014 21:57:08 +0100 Subject: [PATCH 197/256] Added CHDK support Added CHDK support to take pictures instead of doing an IR command, see more about how to use it here http://captain-slow.dk/2014/03/09/3d-printing-timelapses/ --- Marlin/Marlin_main.cpp | 52 +++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index d62447071e..bb8b30356f 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -314,6 +314,12 @@ bool Stopped=false; bool CooldownNoWait = true; bool target_direction; +//Insert variables if CHDK is defined +#ifdef CHDK +unsigned long chdkHigh = 0; +boolean chdkActive = false; +#endif + //=========================================================================== //=============================Routines====================================== //=========================================================================== @@ -2588,23 +2594,33 @@ void process_commands() #endif //PIDTEMP case 240: // M240 Triggers a camera by emulating a Canon RC-1 : http://www.doc-diy.net/photo/rc-1_hacked/ { - #if defined(PHOTOGRAPH_PIN) && PHOTOGRAPH_PIN > -1 - const uint8_t NUM_PULSES=16; - const float PULSE_LENGTH=0.01524; - for(int i=0; i < NUM_PULSES; i++) { - WRITE(PHOTOGRAPH_PIN, HIGH); - _delay_ms(PULSE_LENGTH); - WRITE(PHOTOGRAPH_PIN, LOW); - _delay_ms(PULSE_LENGTH); + #ifdef CHDK + + SET_OUTPUT(CHDK); + WRITE(CHDK, HIGH); + chdkHigh = millis(); + chdkActive = true; + + #else + + #if defined(PHOTOGRAPH_PIN) && PHOTOGRAPH_PIN > -1 + const uint8_t NUM_PULSES=16; + const float PULSE_LENGTH=0.01524; + for(int i=0; i < NUM_PULSES; i++) { + WRITE(PHOTOGRAPH_PIN, HIGH); + _delay_ms(PULSE_LENGTH); + WRITE(PHOTOGRAPH_PIN, LOW); + _delay_ms(PULSE_LENGTH); } delay(7.33); for(int i=0; i < NUM_PULSES; i++) { - WRITE(PHOTOGRAPH_PIN, HIGH); - _delay_ms(PULSE_LENGTH); - WRITE(PHOTOGRAPH_PIN, LOW); - _delay_ms(PULSE_LENGTH); + WRITE(PHOTOGRAPH_PIN, HIGH); + _delay_ms(PULSE_LENGTH); + WRITE(PHOTOGRAPH_PIN, LOW); + _delay_ms(PULSE_LENGTH); } - #endif + #endif + #endif //chdk end if } break; #ifdef DOGLCD @@ -3353,6 +3369,16 @@ void manage_inactivity() } } } + + #ifdef CHDK //Check if pin should be set to LOW after M240 set it to HIGH + if (chdkActive) + { + chdkActive = false; + if (millis()-chdkHigh < CHDK_DELAY) return; + WRITE(CHDK, LOW); + } + #endif + #if defined(KILL_PIN) && KILL_PIN > -1 if( 0 == READ(KILL_PIN) ) kill(); From 6cd85e6008a5b697a161026b722e7e83c0c78c64 Mon Sep 17 00:00:00 2001 From: Matthew Schick Date: Wed, 12 Mar 2014 18:13:50 -0400 Subject: [PATCH 198/256] Add support for disabling encoder control for feedrate multiplier Signed-off-by: Matthew Schick --- Marlin/Configuration_adv.h | 5 +++++ Marlin/ultralcd.cpp | 2 ++ 2 files changed, 7 insertions(+) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index bca056f9b0..b0cb833d14 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -239,6 +239,11 @@ #define MANUAL_FEEDRATE {50*60, 50*60, 4*60, 60} // set the speeds for manual moves (mm/min) #endif +//Comment to disable setting feedrate multiplier via encoder +#ifdef ULTIPANEL + #define ULTIPANEL_FEEDMULTIPLY +#endif + // minimum time in microseconds that a movement needs to take if the buffer is emptied. #define DEFAULT_MINSEGMENTTIME 20000 diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 3262f2d245..f9f65a2081 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -196,6 +196,7 @@ static void lcd_status_screen() lcd_quick_feedback(); } +#ifdef ULTIPANEL_FEEDMULTIPLY // Dead zone at 100% feedrate if ((feedmultiply < 100 && (feedmultiply + int(encoderPosition)) > 100) || (feedmultiply > 100 && (feedmultiply + int(encoderPosition)) < 100)) @@ -219,6 +220,7 @@ static void lcd_status_screen() feedmultiply += int(encoderPosition); encoderPosition = 0; } +#endif//ULTIPANEL_FEEDMULTIPLY if (feedmultiply < 10) feedmultiply = 10; From aab61e63c3ab3ff9db143009c8faf9a624abf650 Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Fri, 14 Mar 2014 14:52:48 -0700 Subject: [PATCH 199/256] FWRETRACT in mm/s MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Firmware retraction now stores the retract and recover speeds in mm/s instead of mm/min. This makes it match the units of the maximum feedrate, and fixes problems with modifying the value via LCD control panel. From gcode, the values are still taken in mm/min to match the units of G1 and similar, and they are converted to mm/s before they are stored. I also lowered the default retract feedrate to make it less likely to cause problems for geared extruders when the user hasn’t bothered to set a reasonable maximum feedrate, though users should be setting both of these values to suit their hardware. --- Marlin/Configuration_adv.h | 4 ++-- Marlin/Marlin_main.cpp | 12 ++++++------ Marlin/language.h | 36 ++++++++++++++++++------------------ 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index aed27c0796..044bd90582 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -402,10 +402,10 @@ const unsigned int dropsegments=5; //everything with less than this number of st #ifdef FWRETRACT #define MIN_RETRACT 0.1 //minimum extruded mm to accept a automatic gcode retraction attempt #define RETRACT_LENGTH 3 //default retract length (positive mm) - #define RETRACT_FEEDRATE 80*60 //default feedrate for retracting + #define RETRACT_FEEDRATE 45 //default feedrate for retracting (mm/s) #define RETRACT_ZLIFT 0 //default retract Z-lift #define RETRACT_RECOVER_LENGTH 0 //default additional recover length (mm, added to retract length when recovering) - #define RETRACT_RECOVER_FEEDRATE 8*60 //default feedrate for recovering from retraction + #define RETRACT_RECOVER_FEEDRATE 8 //default feedrate for recovering from retraction (mm/s) #endif //adds support for experimental filament exchange support M600; requires display diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 4e9fed10ef..cc664b839e 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1093,7 +1093,7 @@ static void homeaxis(int axis) { current_position[E_AXIS]+=retract_length/volumetric_multiplier[active_extruder]; plan_set_e_position(current_position[E_AXIS]); float oldFeedrate = feedrate; - feedrate=retract_feedrate; + feedrate=retract_feedrate*60; retracted=true; prepare_move(); current_position[Z_AXIS]-=retract_zlift; @@ -1111,7 +1111,7 @@ static void homeaxis(int axis) { current_position[E_AXIS]-=(retract_length+retract_recover_length)/volumetric_multiplier[active_extruder]; plan_set_e_position(current_position[E_AXIS]); float oldFeedrate = feedrate; - feedrate=retract_recover_feedrate; + feedrate=retract_recover_feedrate*60; retracted=false; prepare_move(); feedrate = oldFeedrate; @@ -2291,7 +2291,7 @@ void process_commands() break; #endif #ifdef FWRETRACT - case 207: //M207 - set retract length S[positive mm] F[feedrate mm/sec] Z[additional zlift/hop] + case 207: //M207 - set retract length S[positive mm] F[feedrate mm/min] Z[additional zlift/hop] { if(code_seen('S')) { @@ -2299,14 +2299,14 @@ void process_commands() } if(code_seen('F')) { - retract_feedrate = code_value() ; + retract_feedrate = code_value()/60 ; } if(code_seen('Z')) { retract_zlift = code_value() ; } }break; - case 208: // M208 - set retract recover length S[positive mm surplus to the M207 S*] F[feedrate mm/sec] + case 208: // M208 - set retract recover length S[positive mm surplus to the M207 S*] F[feedrate mm/min] { if(code_seen('S')) { @@ -2314,7 +2314,7 @@ void process_commands() } if(code_seen('F')) { - retract_recover_feedrate = code_value() ; + retract_recover_feedrate = code_value()/60 ; } }break; case 209: // M209 - S<1=true/0=false> enable automatic retract detect if the slicer did not support G10/11: every normal extrude-only move will be classified as retract depending on the direction. diff --git a/Marlin/language.h b/Marlin/language.h index 2126f7fb5f..3593bdeed3 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -150,10 +150,10 @@ #define MSG_KILLED "KILLED. " #define MSG_STOPPED "STOPPED. " #define MSG_CONTROL_RETRACT "Retract mm" - #define MSG_CONTROL_RETRACTF "Retract F" + #define MSG_CONTROL_RETRACTF "Retract V" #define MSG_CONTROL_RETRACT_ZLIFT "Hop mm" #define MSG_CONTROL_RETRACT_RECOVER "UnRet +mm" - #define MSG_CONTROL_RETRACT_RECOVERF "UnRet F" + #define MSG_CONTROL_RETRACT_RECOVERF "UnRet V" #define MSG_AUTORETRACT "AutoRetr." #define MSG_FILAMENTCHANGE "Change filament" #define MSG_INIT_SDCARD "Init. SD card" @@ -335,10 +335,10 @@ #define MSG_STOPPED "Zatrzymany. " #define MSG_STEPPER_RELEASED "Zwolniony." #define MSG_CONTROL_RETRACT "Wycofaj mm" - #define MSG_CONTROL_RETRACTF "Wycofaj F" + #define MSG_CONTROL_RETRACTF "Wycofaj V" #define MSG_CONTROL_RETRACT_ZLIFT "Skok Z mm:" #define MSG_CONTROL_RETRACT_RECOVER "Cof. wycof. +mm" - #define MSG_CONTROL_RETRACT_RECOVERF "Cof. wycof. F" + #define MSG_CONTROL_RETRACT_RECOVERF "Cof. wycof. V" #define MSG_AUTORETRACT "Auto. wycofanie" #define MSG_FILAMENTCHANGE "Zmien filament" #define MSG_INIT_SDCARD "Inicjal. karty SD" @@ -520,10 +520,10 @@ #define MSG_STOPPED "STOPPE." #define MSG_STEPPER_RELEASED "RELACHE." #define MSG_CONTROL_RETRACT "Retraction mm" - #define MSG_CONTROL_RETRACTF "Retraction F" + #define MSG_CONTROL_RETRACTF "Retraction V" #define MSG_CONTROL_RETRACT_ZLIFT "Hop mm" #define MSG_CONTROL_RETRACT_RECOVER "UnRet +mm" - #define MSG_CONTROL_RETRACT_RECOVERF "UnRet F" + #define MSG_CONTROL_RETRACT_RECOVERF "UnRet V" #define MSG_AUTORETRACT "Retract. Auto." #define MSG_FILAMENTCHANGE "Changer filament" #define MSG_INIT_SDCARD "Init. la carte SD" @@ -706,10 +706,10 @@ #define MSG_STOPPED "GESTOPPT" #define MSG_STEPPER_RELEASED "Stepper frei" #define MSG_CONTROL_RETRACT "Retract mm" - #define MSG_CONTROL_RETRACTF "Retract F" + #define MSG_CONTROL_RETRACTF "Retract V" #define MSG_CONTROL_RETRACT_ZLIFT "Hop mm" #define MSG_CONTROL_RETRACT_RECOVER "UnRet +mm" - #define MSG_CONTROL_RETRACT_RECOVERF "UnRet F" + #define MSG_CONTROL_RETRACT_RECOVERF "UnRet V" #define MSG_AUTORETRACT "AutoRetr." #define MSG_FILAMENTCHANGE "Filament wechseln" #define MSG_INIT_SDCARD "Init. SD-Card" @@ -888,10 +888,10 @@ #define MSG_KILLED "PARADA DE EMERG." #define MSG_STOPPED "PARADA" #define MSG_CONTROL_RETRACT "Retraer mm" - #define MSG_CONTROL_RETRACTF "Retraer F" + #define MSG_CONTROL_RETRACTF "Retraer V" #define MSG_CONTROL_RETRACT_ZLIFT "Levantar mm" #define MSG_CONTROL_RETRACT_RECOVER "DesRet +mm" - #define MSG_CONTROL_RETRACT_RECOVERF "DesRet F" + #define MSG_CONTROL_RETRACT_RECOVERF "DesRet V" #define MSG_AUTORETRACT "AutoRetr." #define MSG_FILAMENTCHANGE "Change filament" #define MSG_INIT_SDCARD "Iniciando tarjeta" @@ -1079,10 +1079,10 @@ #define MSG_KILLED "УБИТО." #define MSG_STOPPED "ОСТАНОВЛЕНО." #define MSG_CONTROL_RETRACT "Откат mm:" - #define MSG_CONTROL_RETRACTF "Откат F:" + #define MSG_CONTROL_RETRACTF "Откат V:" #define MSG_CONTROL_RETRACT_ZLIFT "Прыжок mm:" #define MSG_CONTROL_RETRACT_RECOVER "Возврат +mm:" - #define MSG_CONTROL_RETRACT_RECOVERF "Возврат F:" + #define MSG_CONTROL_RETRACT_RECOVERF "Возврат V:" #define MSG_AUTORETRACT "АвтоОткат:" #define MSG_FILAMENTCHANGE "Change filament" #define MSG_INIT_SDCARD "Init. SD-Card" @@ -1260,10 +1260,10 @@ #define MSG_KILLED "UCCISO. " #define MSG_STOPPED "ARRESTATO. " #define MSG_CONTROL_RETRACT "Ritrai mm" - #define MSG_CONTROL_RETRACTF "Ritrai F" + #define MSG_CONTROL_RETRACTF "Ritrai V" #define MSG_CONTROL_RETRACT_ZLIFT "Salta mm" #define MSG_CONTROL_RETRACT_RECOVER "UnRet +mm" - #define MSG_CONTROL_RETRACT_RECOVERF "UnRet F" + #define MSG_CONTROL_RETRACT_RECOVERF "UnRet V" #define MSG_AUTORETRACT "AutoArretramento" #define MSG_FILAMENTCHANGE "Cambia filamento" #define MSG_INIT_SDCARD "Iniz. SD-Card" @@ -1449,10 +1449,10 @@ #define MSG_STOPPED "PARADA. " #define MSG_STEPPER_RELEASED "Lancado." #define MSG_CONTROL_RETRACT " Retrair mm:" - #define MSG_CONTROL_RETRACTF " Retrair F:" + #define MSG_CONTROL_RETRACTF " Retrair V:" #define MSG_CONTROL_RETRACT_ZLIFT " Levantar mm:" #define MSG_CONTROL_RETRACT_RECOVER " DesRet +mm:" - #define MSG_CONTROL_RETRACT_RECOVERF " DesRet F:" + #define MSG_CONTROL_RETRACT_RECOVERF " DesRet V:" #define MSG_AUTORETRACT " AutoRetr.:" #define MSG_FILAMENTCHANGE "Change filament" #define MSG_INIT_SDCARD "Init. SD-Card" @@ -1633,10 +1633,10 @@ #define MSG_KILLED "KILLED. " #define MSG_STOPPED "STOPPED. " #define MSG_CONTROL_RETRACT "Veda mm" - #define MSG_CONTROL_RETRACTF "Veda F" + #define MSG_CONTROL_RETRACTF "Veda V" #define MSG_CONTROL_RETRACT_ZLIFT "Z mm" #define MSG_CONTROL_RETRACT_RECOVER "UnRet +mm" - #define MSG_CONTROL_RETRACT_RECOVERF "UnRet F" + #define MSG_CONTROL_RETRACT_RECOVERF "UnRet V" #define MSG_AUTORETRACT "AutoVeto." #define MSG_FILAMENTCHANGE "Change filament" #define MSG_INIT_SDCARD "Init. SD-Card" From 272072fa208e6da3ad6ac80f36073b645be6da9e Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Fri, 14 Mar 2014 23:19:43 +0000 Subject: [PATCH 200/256] Added M112 --- Marlin/Marlin_main.cpp | 3 +++ README.md | 1 + 2 files changed, 4 insertions(+) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index d62447071e..f9bb1c6e15 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1808,6 +1808,9 @@ void process_commands() #endif setWatch(); break; + case 112: // M112 -Emergency Stop + kill(); + break; case 140: // M140 set bed temp if (code_seen('S')) setTargetBed(code_value()); break; diff --git a/README.md b/README.md index 236c312776..443799e0c6 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,7 @@ M Codes * M107 - Fan off * M109 - Sxxx Wait for extruder current temp to reach target temp. Waits only when heating * Rxxx Wait for extruder current temp to reach target temp. Waits when heating and cooling +* M112 - Emergency stop * M114 - Output current position to serial port * M115 - Capabilities string * M117 - display message From a38c90ee84a1045320759708742942e10f873f64 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Sat, 15 Mar 2014 15:56:15 +0000 Subject: [PATCH 201/256] Added estop handling --- Marlin/Marlin_main.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index f9bb1c6e15..f27add1576 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -658,6 +658,12 @@ void get_command() } } + + if(strcmp(cmdbuffer[bufindw], "M112") == 0) + { + kill(); + } + bufindw = (bufindw + 1)%BUFSIZE; buflen += 1; } @@ -3340,6 +3346,9 @@ void handle_status_leds(void) { void manage_inactivity() { + if(buflen < (BUFSIZE-1)) + get_command(); + if( (millis() - previous_millis_cmd) > max_inactive_time ) if(max_inactive_time) kill(); From 3906f27c460d6752549fbd11826dee34c6f3f3ff Mon Sep 17 00:00:00 2001 From: Dim3nsioneer Date: Sat, 15 Mar 2014 18:09:46 +0100 Subject: [PATCH 202/256] Individual extruder flow rate Extension of M221, Tune menu --- Marlin/Marlin.h | 3 ++- Marlin/Marlin_main.cpp | 24 +++++++++++++++++++++++- Marlin/language.h | 40 ++++++++++++++++++++++++++++++++++++++++ Marlin/ultralcd.cpp | 7 +++++++ 4 files changed, 72 insertions(+), 2 deletions(-) diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index 97866c8165..e7282092e5 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -203,7 +203,8 @@ void setPwmFrequency(uint8_t pin, int val); extern float homing_feedrate[]; extern bool axis_relative_modes[]; extern int feedmultiply; -extern int extrudemultiply; // Sets extrude multiply factor (in percent) +extern int extrudemultiply; // Sets extrude multiply factor (in percent) for all extruders +extern int extruder_multiply[EXTRUDERS]; // sets extrude multiply factor (in percent) for each extruder individually extern float volumetric_multiplier[EXTRUDERS]; // reciprocal of cross-sectional area of filament (in square millimeters), stored this way to reduce computational burden in planner extern float current_position[NUM_AXIS] ; extern float add_homeing[3]; diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index bb8b30356f..d7397ac0c7 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -189,6 +189,14 @@ bool axis_relative_modes[] = AXIS_RELATIVE_MODES; int feedmultiply=100; //100->1 200->2 int saved_feedmultiply; int extrudemultiply=100; //100->1 200->2 +int extruder_multiply[EXTRUDERS] = {100 + #if EXTRUDERS > 1 + , 100 + #if EXTRUDERS > 2 + , 100 + #endif + #endif +}; float volumetric_multiplier[EXTRUDERS] = {1.0 #if EXTRUDERS > 1 , 1.0 @@ -2426,7 +2434,18 @@ void process_commands() { if(code_seen('S')) { - extrudemultiply = code_value() ; + int tmp_code = code_value(); + if (code_seen('T')) + { + if(setTargetedHotend(221)){ + break; + } + extruder_multiply[tmp_extruder] = tmp_code; + } + else + { + extrudemultiply = tmp_code ; + } } } break; @@ -3546,6 +3565,9 @@ bool setTargetedHotend(int code){ case 218: SERIAL_ECHO(MSG_M218_INVALID_EXTRUDER); break; + case 221: + SERIAL_ECHO(MSG_M221_INVALID_EXTRUDER); + break; } SERIAL_ECHOLN(tmp_extruder); return true; diff --git a/Marlin/language.h b/Marlin/language.h index 0782763702..9e70814fb4 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -100,6 +100,9 @@ #define MSG_BED "Bed" #define MSG_FAN_SPEED "Fan speed" #define MSG_FLOW "Flow" + #define MSG_FLOW0 "Flow 0" + #define MSG_FLOW1 "Flow 1" + #define MSG_FLOW2 "Flow 2" #define MSG_CONTROL "Control" #define MSG_MIN " \002 Min" #define MSG_MAX " \002 Max" @@ -192,6 +195,7 @@ #define MSG_M105_INVALID_EXTRUDER "M105 Invalid extruder " #define MSG_M200_INVALID_EXTRUDER "M200 Invalid extruder " #define MSG_M218_INVALID_EXTRUDER "M218 Invalid extruder " + #define MSG_M221_INVALID_EXTRUDER "M221 Invalid extruder " #define MSG_ERR_NO_THERMISTORS "No thermistors - no temperature" #define MSG_M109_INVALID_EXTRUDER "M109 Invalid extruder " #define MSG_HEATING "Heating..." @@ -283,6 +287,9 @@ #define MSG_BED "Loze" #define MSG_FAN_SPEED "Obroty wiatraka" #define MSG_FLOW "Przeplyw" + #define MSG_FLOW0 "Przeplyw 0" + #define MSG_FLOW1 "Przeplyw 1" + #define MSG_FLOW2 "Przeplyw 2" #define MSG_CONTROL "Kontrola" #define MSG_MIN " \002 Min" #define MSG_MAX " \002 Max" @@ -378,6 +385,7 @@ #define MSG_M105_INVALID_EXTRUDER "M105 Niepoprawny ekstruder " #define MSG_M200_INVALID_EXTRUDER "M200 Niepoprawny ekstruder " #define MSG_M218_INVALID_EXTRUDER "M218 Niepoprawny ekstruder " + #define MSG_M221_INVALID_EXTRUDER "M221 Niepoprawny ekstruder " #define MSG_ERR_NO_THERMISTORS "Brak termistorow - brak temperatury :(" #define MSG_M109_INVALID_EXTRUDER "M109 Niepoprawny ekstruder " #define MSG_HEATING "Nagrzewanie ekstrudera..." @@ -470,6 +478,9 @@ #define MSG_BED "Plateau" #define MSG_FAN_SPEED "Vite. ventilateur" #define MSG_FLOW "Flux" + #define MSG_FLOW0 "Flux 0" + #define MSG_FLOW1 "Flux 1" + #define MSG_FLOW2 "Flux 2" #define MSG_CONTROL "Controler" #define MSG_MIN " \002 Min" #define MSG_MAX " \002 Max" @@ -563,6 +574,7 @@ #define MSG_M105_INVALID_EXTRUDER "M105 Extruder invalide" #define MSG_M200_INVALID_EXTRUDER "M200 Extruder invalide" #define MSG_M218_INVALID_EXTRUDER "M218 Extruder invalide" + #define MSG_M221_INVALID_EXTRUDER "M221 Extruder invalide" #define MSG_ERR_NO_THERMISTORS "Pas de thermistor, pas de temperature" #define MSG_M109_INVALID_EXTRUDER "M109 Extruder invalide " #define MSG_HEATING "En chauffe..." @@ -654,6 +666,9 @@ #define MSG_BED "Bett" #define MSG_FAN_SPEED "Lüftergeschw." #define MSG_FLOW "Fluss" + #define MSG_FLOW0 "Fluss 0" + #define MSG_FLOW1 "Fluss 1" + #define MSG_FLOW2 "Fluss 2" #define MSG_CONTROL "Einstellungen" #define MSG_MIN "\002 Min" #define MSG_MAX "\002 Max" @@ -749,6 +764,7 @@ #define MSG_M105_INVALID_EXTRUDER "M105 Invalid extruder " #define MSG_M200_INVALID_EXTRUDER "M200 Invalid extruder " #define MSG_M218_INVALID_EXTRUDER "M218 Invalid extruder " + #define MSG_M221_INVALID_EXTRUDER "M221 Invalid extruder " #define MSG_ERR_NO_THERMISTORS "No thermistors - no temp" #define MSG_M109_INVALID_EXTRUDER "M109 Invalid extruder " #define MSG_HEATING "Heating..." @@ -839,6 +855,9 @@ #define MSG_BED "Base" #define MSG_FAN_SPEED "Ventilador" #define MSG_FLOW "Flujo" + #define MSG_FLOW0 "Flujo 0" + #define MSG_FLOW1 "Flujo 1" + #define MSG_FLOW2 "Flujo 2" #define MSG_CONTROL "Control" #define MSG_MIN "\002 Min" #define MSG_MAX "\002 Max" @@ -940,6 +959,7 @@ #define MSG_M105_INVALID_EXTRUDER "M105 Extrusor Invalido " #define MSG_M200_INVALID_EXTRUDER "M200 Extrusor Invalido " #define MSG_M218_INVALID_EXTRUDER "M218 Extrusor Invalido " + #define MSG_M221_INVALID_EXTRUDER "M221 Extrusor Invalido " #define MSG_ERR_NO_THERMISTORS "No hay termistores - no temp" #define MSG_M109_INVALID_EXTRUDER "M109 Extrusor Invalido " #define MSG_HEATING "Calentando..." @@ -1029,6 +1049,9 @@ #define MSG_BED "\002 Кровать:" #define MSG_FAN_SPEED "Куллер:" #define MSG_FLOW "Поток:" + #define MSG_FLOW0 " Поток0:" + #define MSG_FLOW1 " Поток1:" + #define MSG_FLOW2 " Поток2:" #define MSG_CONTROL "Настройки \003" #define MSG_MIN "\002 Минимум:" #define MSG_MAX "\002 Максимум:" @@ -1122,6 +1145,7 @@ #define MSG_M105_INVALID_EXTRUDER "M105 ошибка экструдера " #define MSG_M200_INVALID_EXTRUDER "M200 ошибка экструдера " #define MSG_M218_INVALID_EXTRUDER "M218 ошибка экструдера " + #define MSG_M221_INVALID_EXTRUDER "M221 ошибка экструдера " #define MSG_ERR_NO_THERMISTORS "Нет термистра - нет температуры" #define MSG_M109_INVALID_EXTRUDER "M109 ошибка экструдера " #define MSG_HEATING "Нагрев... " @@ -1210,6 +1234,9 @@ #define MSG_BED "Piatto" #define MSG_FAN_SPEED "Ventola" #define MSG_FLOW "Flusso" + #define MSG_FLOW0 "Flusso 0" + #define MSG_FLOW1 "Flusso 1" + #define MSG_FLOW2 "Flusso 2" #define MSG_CONTROL "Controllo" #define MSG_MIN " \002 Min:" #define MSG_MAX " \002 Max:" @@ -1303,6 +1330,7 @@ #define MSG_M105_INVALID_EXTRUDER "M105 Estrusore non valido " #define MSG_M200_INVALID_EXTRUDER "M200 Estrusore non valido " #define MSG_M218_INVALID_EXTRUDER "M218 Estrusore non valido " + #define MSG_M221_INVALID_EXTRUDER "M221 Estrusore non valido " #define MSG_ERR_NO_THERMISTORS "Nessun Termistore - nessuna temperatura" #define MSG_M109_INVALID_EXTRUDER "M109 Estrusore non valido " #define MSG_HEATING "Riscaldamento..." @@ -1395,6 +1423,9 @@ #define MSG_BED "\002Base:" #define MSG_FAN_SPEED "Velocidade vento." #define MSG_FLOW "Fluxo:" + #define MSG_FLOW0 "Fluxo0:" + #define MSG_FLOW1 "Fluxo1:" + #define MSG_FLOW2 "Fluxo2:" #define MSG_CONTROL "Controle \003" #define MSG_MIN "\002 Min:" #define MSG_MAX "\002 Max:" @@ -1492,6 +1523,7 @@ #define MSG_M105_INVALID_EXTRUDER "M105 Extrusor inválido " #define MSG_M200_INVALID_EXTRUDER "M200 Extrusor inválido " #define MSG_M218_INVALID_EXTRUDER "M218 Extrusor inválido " + #define MSG_M221_INVALID_EXTRUDER "M221 Extrusor inválido " #define MSG_ERR_NO_THERMISTORS "Nao ha termistor - no temp" #define MSG_M109_INVALID_EXTRUDER "M109 Extrusor inválido " #define MSG_HEATING "Aquecendo..." @@ -1583,6 +1615,9 @@ #define MSG_BED "Alusta" #define MSG_FAN_SPEED "Tuul. nopeus" #define MSG_FLOW "Virtaus" + #define MSG_FLOW0 "Virtaus 0" + #define MSG_FLOW1 "Virtaus 1" + #define MSG_FLOW2 "Virtaus 2" #define MSG_CONTROL "Kontrolli" #define MSG_MIN " \002 Min" #define MSG_MAX " \002 Max" @@ -1675,6 +1710,7 @@ #define MSG_M105_INVALID_EXTRUDER "M105 Virheellinen suutin " #define MSG_M200_INVALID_EXTRUDER "M200 Virheellinen suutin " #define MSG_M218_INVALID_EXTRUDER "M218 Virheellinen suutin " + #define MSG_M221_INVALID_EXTRUDER "M221 Virheellinen suutin " #define MSG_ERR_NO_THERMISTORS "Ei termistoreja - ei lampotiloja" #define MSG_M109_INVALID_EXTRUDER "M109 Virheellinen suutin " #define MSG_HEATING "Lammitan..." @@ -1766,6 +1802,9 @@ #define MSG_BED "Base" #define MSG_FAN_SPEED "Ixoriador" #define MSG_FLOW "Fluxo" + #define MSG_FLOW0 "Fluxo 0" + #define MSG_FLOW1 "Fluxo 1" + #define MSG_FLOW2 "Fluxo 2" #define MSG_CONTROL "Control" #define MSG_MIN "\002 Min" #define MSG_MAX "\002 Max" @@ -1867,6 +1906,7 @@ #define MSG_M105_INVALID_EXTRUDER "M105 Extrusor Invalido " #define MSG_M200_INVALID_EXTRUDER "M200 Extrusor Invalido " #define MSG_M218_INVALID_EXTRUDER "M218 Extrusor Invalido " + #define MSG_M221_INVALID_EXTRUDER "M221 Extrusor Invalido " #define MSG_ERR_NO_THERMISTORS "No i hai termistores - no temp" #define MSG_M109_INVALID_EXTRUDER "M109 Extrusor Invalido " #define MSG_HEATING "Calentando..." diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index f9f65a2081..4c8df66deb 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -414,6 +414,13 @@ static void lcd_tune_menu() #endif MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &fanSpeed, 0, 255); MENU_ITEM_EDIT(int3, MSG_FLOW, &extrudemultiply, 10, 999); + MENU_ITEM_EDIT(int3, MSG_FLOW0, &extruder_multiply[0], 10, 999); +#if TEMP_SENSOR_1 != 0 + MENU_ITEM_EDIT(int3, MSG_FLOW1, &extruder_multiply[1], 10, 999); +#endif +#if TEMP_SENSOR_2 != 0 + MENU_ITEM_EDIT(int3, MSG_FLOW2, &extruder_multiply[2], 10, 999); +#endif #ifdef BABYSTEPPING #ifdef BABYSTEP_XY From 06709ad60e09b53c2b01a1c87a5d87e47d1c4d70 Mon Sep 17 00:00:00 2001 From: Ralf Schultz Date: Mon, 17 Mar 2014 15:45:13 +0100 Subject: [PATCH 203/256] Added servo pin assignments to Sanguinololu --- Marlin/pins.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Marlin/pins.h b/Marlin/pins.h index 9976d431d0..56d55e985f 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -1054,6 +1054,22 @@ #define FAN_PIN 4 #endif +#ifdef NUM_SERVOS + #define SERVO0_PIN 11 + + #if NUM_SERVOS > 1 + #define SERVO1_PIN 27 + #endif + + #if NUM_SERVOS > 2 + #define SERVO2_PIN 28 + #endif + + #if NUM_SERVOS > 3 + #define SERVO3_PIN 29 + #endif +#endif + #define PS_ON_PIN -1 #define KILL_PIN -1 From 944ced87c551d9be7761e099dd59e56adb703ac9 Mon Sep 17 00:00:00 2001 From: Dim3nsioneer Date: Mon, 17 Mar 2014 18:37:46 +0100 Subject: [PATCH 204/256] Extended Preheat options Preheat LCD menus base on code by D-Base --- Marlin/language.h | 126 +++++++++++++++++++++++++++-- Marlin/ultralcd.cpp | 190 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 275 insertions(+), 41 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index 9e70814fb4..c8b7de8ef8 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -77,9 +77,19 @@ #define MSG_AUTO_HOME "Auto home" #define MSG_SET_ORIGIN "Set origin" #define MSG_PREHEAT_PLA "Preheat PLA" - #define MSG_PREHEAT_PLA_SETTINGS "Preheat PLA conf" + #define MSG_PREHEAT_PLA0 "Preheat PLA 1" + #define MSG_PREHEAT_PLA1 "Preheat PLA 2" + #define MSG_PREHEAT_PLA2 "Preheat PLA 3" + #define MSG_PREHEAT_PLA012 "Preheat PLA All" + #define MSG_PREHEAT_PLA_BEDONLY "Preheat PLA Bed" + #define MSG_PREHEAT_PLA_SETTINGS "Preheat PLA Conf" #define MSG_PREHEAT_ABS "Preheat ABS" - #define MSG_PREHEAT_ABS_SETTINGS "Preheat ABS conf" + #define MSG_PREHEAT_ABS0 "Preheat ABS 1" + #define MSG_PREHEAT_ABS1 "Preheat ABS 2" + #define MSG_PREHEAT_ABS2 "Preheat ABS 3" + #define MSG_PREHEAT_ABS012 "Preheat ABS All" + #define MSG_PREHEAT_ABS_BEDONLY "Preheat ABS Bed" + #define MSG_PREHEAT_ABS_SETTINGS "Preheat ABS Conf" #define MSG_COOLDOWN "Cooldown" #define MSG_SWITCH_PS_ON "Switch power on" #define MSG_SWITCH_PS_OFF "Switch power off" @@ -264,9 +274,19 @@ #define MSG_AUTO_HOME "Auto. poz. zerowa" #define MSG_SET_ORIGIN "Ustaw punkt zero" #define MSG_PREHEAT_PLA "Rozgrzej PLA" - #define MSG_PREHEAT_PLA_SETTINGS "Ustaw. rozg. PLA" + #define MSG_PREHEAT_PLA0 "Rozgrzej PLA 1" + #define MSG_PREHEAT_PLA1 "Rozgrzej PLA 2" + #define MSG_PREHEAT_PLA2 "Rozgrzej PLA 3" + #define MSG_PREHEAT_PLA012 "Rozgrzej PLA Wszystko" + #define MSG_PREHEAT_PLA_BEDONLY "Rozgrzej PLA Loze" + #define MSG_PREHEAT_PLA_SETTINGS "Ustawienia roz. PLA" #define MSG_PREHEAT_ABS "Rozgrzej ABS" - #define MSG_PREHEAT_ABS_SETTINGS "Ustaw. rozg. ABS" + #define MSG_PREHEAT_ABS0 "Rozgrzej ABS 1" + #define MSG_PREHEAT_ABS1 "Rozgrzej ABS 2" + #define MSG_PREHEAT_ABS2 "Rozgrzej ABS 3" + #define MSG_PREHEAT_ABS012 "Rozgrzej ABS Wszystko" + #define MSG_PREHEAT_ABS_BEDONLY "Rozgrzej ABS Loze" + #define MSG_PREHEAT_ABS_SETTINGS "Ustawienia roz. ABS" #define MSG_COOLDOWN "Chlodzenie" #define MSG_SWITCH_PS_ON "Wlacz zasilacz" #define MSG_SWITCH_PS_OFF "Wylacz zasilacz" @@ -453,9 +473,19 @@ #define MSG_AUTO_HOME "Home auto." #define MSG_SET_ORIGIN "Regler origine" #define MSG_PREHEAT_PLA " Prechauffage PLA" - #define MSG_PREHEAT_PLA_SETTINGS " Regl. prech. PLA" + #define MSG_PREHEAT_PLA0 "Prechauffage PLA 1" + #define MSG_PREHEAT_PLA1 "Prechauffage PLA 2" + #define MSG_PREHEAT_PLA2 "Prechauffage PLA 3" + #define MSG_PREHEAT_PLA012 "Prechauffage PLA Tout" + #define MSG_PREHEAT_PLA_BEDONLY "Prechauffage PLA Plateau" + #define MSG_PREHEAT_PLA_SETTINGS " Regl. prechauffe PLA" #define MSG_PREHEAT_ABS "Prechauffage ABS" - #define MSG_PREHEAT_ABS_SETTINGS "Regl. prech. ABS" + #define MSG_PREHEAT_ABS0 "Prechauffage ABS 1" + #define MSG_PREHEAT_ABS1 "Prechauffage ABS 2" + #define MSG_PREHEAT_ABS2 "Prechauffage ABS 3" + #define MSG_PREHEAT_ABS012 "Prechauffage ABS Tout" + #define MSG_PREHEAT_ABS_BEDONLY "Prechauffage ABS Plateau" + #define MSG_PREHEAT_ABS_SETTINGS "Regl. prechauffe ABS" #define MSG_COOLDOWN "Refroidir" #define MSG_SWITCH_PS_ON "Allumer alim." #define MSG_SWITCH_PS_OFF "Eteindre alim." @@ -643,9 +673,19 @@ #define MSG_AUTO_HOME "Auto Nullpunkt" #define MSG_SET_ORIGIN "Setze Nullpunkt" #define MSG_PREHEAT_PLA "Vorwärmen PLA" - #define MSG_PREHEAT_PLA_SETTINGS "Vorwärm. PLA Ein." + #define MSG_PREHEAT_PLA0 "Vorwärmen PLA 1" + #define MSG_PREHEAT_PLA1 "Vorwärmen PLA 2" + #define MSG_PREHEAT_PLA2 "Vorwärmen PLA 3" + #define MSG_PREHEAT_PLA012 "Vorwärmen PLA Alle" + #define MSG_PREHEAT_PLA_BEDONLY "Vorwärmen PLA Bett" + #define MSG_PREHEAT_PLA_SETTINGS "Vorwärmen PLA Einstellungen" #define MSG_PREHEAT_ABS "Vorwärmen ABS" - #define MSG_PREHEAT_ABS_SETTINGS "Vorwärm. ABS Ein." + #define MSG_PREHEAT_ABS0 "Vorwärmen ABS 1" + #define MSG_PREHEAT_ABS1 "Vorwärmen ABS 2" + #define MSG_PREHEAT_ABS2 "Vorwärmen ABS 3" + #define MSG_PREHEAT_ABS012 "Vorwärmen ABS Alle" + #define MSG_PREHEAT_ABS_BEDONLY "Vorwärmen ABS Bett" + #define MSG_PREHEAT_ABS_SETTINGS "Vorwärmen ABS Einstellungen" #define MSG_COOLDOWN "Abkühlen" #define MSG_SWITCH_PS_ON "Switch Power On" #define MSG_SWITCH_PS_OFF "Switch Power Off" @@ -832,8 +872,18 @@ #define MSG_AUTO_HOME "Llevar al origen" #define MSG_SET_ORIGIN "Establecer cero" #define MSG_PREHEAT_PLA "Precalentar PLA" + #define MSG_PREHEAT_PLA0 "Precalentar PLA 1" + #define MSG_PREHEAT_PLA1 "Precalentar PLA 2" + #define MSG_PREHEAT_PLA2 "Precalentar PLA 3" + #define MSG_PREHEAT_PLA012 "Precalentar PLA Todo" + #define MSG_PREHEAT_PLA_BEDONLY "Precalentar PLA Base" #define MSG_PREHEAT_PLA_SETTINGS "Ajustar temp. PLA" #define MSG_PREHEAT_ABS "Precalentar ABS" + #define MSG_PREHEAT_ABS0 "Precalentar ABS 1" + #define MSG_PREHEAT_ABS1 "Precalentar ABS 2" + #define MSG_PREHEAT_ABS2 "Precalentar ABS 3" + #define MSG_PREHEAT_ABS012 "Precalentar ABS Todo" + #define MSG_PREHEAT_ABS_BEDONLY "Precalentar ABS Base" #define MSG_PREHEAT_ABS_SETTINGS "Ajustar temp. ABS" #define MSG_COOLDOWN "Enfriar" #define MSG_SWITCH_PS_ON "Switch Power On" @@ -1026,8 +1076,18 @@ #define MSG_AUTO_HOME "Парковка" #define MSG_SET_ORIGIN "Запомнить ноль" #define MSG_PREHEAT_PLA "Преднагрев PLA" + #define MSG_PREHEAT_PLA0 "Преднагрев PLA0" + #define MSG_PREHEAT_PLA1 "Преднагрев PLA1" + #define MSG_PREHEAT_PLA2 "Преднагрев PLA2" + #define MSG_PREHEAT_PLA012 "Преднагрев PLA все " + #define MSG_PREHEAT_PLA_BEDONLY "Преднагрев PLA \002 Кровать" #define MSG_PREHEAT_PLA_SETTINGS "Настройки PLA" #define MSG_PREHEAT_ABS "Преднагрев ABS" + #define MSG_PREHEAT_ABS0 "Преднагрев ABS0" + #define MSG_PREHEAT_ABS1 "Преднагрев ABS1" + #define MSG_PREHEAT_ABS2 "Преднагрев ABS2" + #define MSG_PREHEAT_ABS012 "Преднагрев ABS все " + #define MSG_PREHEAT_ABS_BEDONLY "Преднагрев ABS \002 Кровать" #define MSG_PREHEAT_ABS_SETTINGS "Настройки ABS" #define MSG_COOLDOWN "Охлаждение" #define MSG_SWITCH_PS_ON "Switch Power On" @@ -1211,8 +1271,18 @@ #define MSG_AUTO_HOME "Auto Home" #define MSG_SET_ORIGIN "Imposta Origine" #define MSG_PREHEAT_PLA "Preriscalda PLA" + #define MSG_PREHEAT_PLA0 "Preriscalda PLA 1" + #define MSG_PREHEAT_PLA1 "Preriscalda PLA 2" + #define MSG_PREHEAT_PLA2 "Preriscalda PLA 3" + #define MSG_PREHEAT_PLA012 "Preriscalda PLA Tutto" + #define MSG_PREHEAT_PLA_BEDONLY "Preriscalda PLA Piatto" #define MSG_PREHEAT_PLA_SETTINGS "Preris. PLA Conf" #define MSG_PREHEAT_ABS "Preriscalda ABS" + #define MSG_PREHEAT_ABS0 "Preriscalda ABS 1" + #define MSG_PREHEAT_ABS1 "Preriscalda ABS 2" + #define MSG_PREHEAT_ABS2 "Preriscalda ABS 3" + #define MSG_PREHEAT_ABS012 "Preriscalda ABS Tutto" + #define MSG_PREHEAT_ABS_BEDONLY "Preriscalda ABS Piatto" #define MSG_PREHEAT_ABS_SETTINGS "Preris. ABS Conf" #define MSG_COOLDOWN "Raffredda" #define MSG_SWITCH_PS_ON "Switch Power On" @@ -1398,8 +1468,18 @@ #define MSG_AUTO_HOME "Ir para origen" #define MSG_SET_ORIGIN "Estabelecer orig." #define MSG_PREHEAT_PLA "Pre-aquecer PLA" + #define MSG_PREHEAT_PLA0 " pre-aquecer PLA 1" + #define MSG_PREHEAT_PLA1 " pre-aquecer PLA 2" + #define MSG_PREHEAT_PLA2 " pre-aquecer PLA 3" + #define MSG_PREHEAT_PLA012 " pre-aquecer PLA Tudo" + #define MSG_PREHEAT_PLA_BEDONLY " pre-aquecer PLA \002Base" #define MSG_PREHEAT_PLA_SETTINGS "PLA setting" #define MSG_PREHEAT_ABS "Pre-aquecer ABS" + #define MSG_PREHEAT_ABS0 " pre-aquecer ABS 1" + #define MSG_PREHEAT_ABS1 " pre-aquecer ABS 2" + #define MSG_PREHEAT_ABS2 " pre-aquecer ABS 3" + #define MSG_PREHEAT_ABS012 " pre-aquecer ABS Tudo" + #define MSG_PREHEAT_ABS_BEDONLY " pre-aquecer ABS \002Base" #define MSG_PREHEAT_ABS_SETTINGS "ABS setting" #define MSG_COOLDOWN "Esfriar" #define MSG_SWITCH_PS_ON "Switch Power On" @@ -1592,8 +1672,18 @@ #define MSG_AUTO_HOME "Aja referenssiin" #define MSG_SET_ORIGIN "Aseta origo" #define MSG_PREHEAT_PLA "Esilammita PLA" + #define MSG_PREHEAT_PLA0 "Esilammita PLA 1" + #define MSG_PREHEAT_PLA1 "Esilammita PLA 2" + #define MSG_PREHEAT_PLA2 "Esilammita PLA 3" + #define MSG_PREHEAT_PLA012 "Esilammita PLA Kaikki" + #define MSG_PREHEAT_PLA_BEDONLY "Esilammita PLA Alusta" #define MSG_PREHEAT_PLA_SETTINGS "Esilamm. PLA konf" #define MSG_PREHEAT_ABS "Esilammita ABS" + #define MSG_PREHEAT_ABS0 "Esilammita ABS 1" + #define MSG_PREHEAT_ABS1 "Esilammita ABS 2" + #define MSG_PREHEAT_ABS2 "Esilammita ABS 3" + #define MSG_PREHEAT_ABS012 "Esilammita ABS Kaikki" + #define MSG_PREHEAT_ABS_BEDONLY "Esilammita ABS Alusta" #define MSG_PREHEAT_ABS_SETTINGS "Esilamm. ABS konf" #define MSG_COOLDOWN "Jaahdyta" #define MSG_SWITCH_PS_ON "Virta paalle" @@ -1779,8 +1869,18 @@ #define MSG_AUTO_HOME "Levar a l'orichen" #define MSG_SET_ORIGIN "Establir zero" #define MSG_PREHEAT_PLA "Precalentar PLA" + #define MSG_PREHEAT_PLA0 "Precalentar PLA0" + #define MSG_PREHEAT_PLA1 "Precalentar PLA1" + #define MSG_PREHEAT_PLA2 "Precalentar PLA2" + #define MSG_PREHEAT_PLA012 "Precalentar PLA a" + #define MSG_PREHEAT_PLA_BEDONLY "Prec. PLA Base" #define MSG_PREHEAT_PLA_SETTINGS "Achustar tem. PLA" #define MSG_PREHEAT_ABS "Precalentar ABS" + #define MSG_PREHEAT_ABS0 "Precalentar ABS0" + #define MSG_PREHEAT_ABS1 "Precalentar ABS1" + #define MSG_PREHEAT_ABS2 "Precalentar ABS2" + #define MSG_PREHEAT_ABS012 "Precalentar ABS a" + #define MSG_PREHEAT_ABS_BEDONLY "Prec. ABS Base" #define MSG_PREHEAT_ABS_SETTINGS "Achustar tem. ABS" #define MSG_COOLDOWN "Enfriar" #define MSG_SWITCH_PS_ON "Enchegar Fuent" @@ -1972,8 +2072,18 @@ #define MSG_AUTO_HOME "Auto home" #define MSG_SET_ORIGIN "Nulpunt instellen" #define MSG_PREHEAT_PLA "PLA voorverwarmen" + #define MSG_PREHEAT_PLA0 "PLA voorverw. 0" + #define MSG_PREHEAT_PLA1 "PLA voorverw. 1" + #define MSG_PREHEAT_PLA2 "PLA voorverw. 2" + #define MSG_PREHEAT_PLA012 "PLA voorverw. aan" + #define MSG_PREHEAT_PLA_BEDONLY "PLA voorverw. Bed" #define MSG_PREHEAT_PLA_SETTINGS "PLA verw. conf" #define MSG_PREHEAT_ABS "ABS voorverwarmen" + #define MSG_PREHEAT_ABS0 "ABS voorverw. 0" + #define MSG_PREHEAT_ABS1 "ABS voorverw. 1" + #define MSG_PREHEAT_ABS2 "ABS voorverw. 2" + #define MSG_PREHEAT_ABS012 "ABS voorverw. aan" + #define MSG_PREHEAT_ABS_BEDONLY "ABS voorverw. Bed" #define MSG_PREHEAT_ABS_SETTINGS "ABS verw. conf" #define MSG_COOLDOWN "Afkoelen" #define MSG_SWITCH_PS_ON "Stroom aan" diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 4c8df66deb..8ae977d211 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -304,37 +304,6 @@ static void lcd_autostart_sd() } #endif -void lcd_preheat_pla() -{ - setTargetHotend0(plaPreheatHotendTemp); - setTargetHotend1(plaPreheatHotendTemp); - setTargetHotend2(plaPreheatHotendTemp); - setTargetBed(plaPreheatHPBTemp); - fanSpeed = plaPreheatFanSpeed; - lcd_return_to_status(); - setWatch(); // heater sanity check timer -} - -void lcd_preheat_abs() -{ - setTargetHotend0(absPreheatHotendTemp); - setTargetHotend1(absPreheatHotendTemp); - setTargetHotend2(absPreheatHotendTemp); - setTargetBed(absPreheatHPBTemp); - fanSpeed = absPreheatFanSpeed; - lcd_return_to_status(); - setWatch(); // heater sanity check timer -} - -static void lcd_cooldown() -{ - setTargetHotend0(0); - setTargetHotend1(0); - setTargetHotend2(0); - setTargetBed(0); - lcd_return_to_status(); -} - #ifdef BABYSTEPPING static void lcd_babystep_x() { @@ -435,6 +404,154 @@ static void lcd_tune_menu() END_MENU(); } +void lcd_preheat_pla0() +{ + setTargetHotend0(plaPreheatHotendTemp); + setTargetBed(plaPreheatHPBTemp); + fanSpeed = plaPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} + +void lcd_preheat_abs0() +{ + setTargetHotend0(absPreheatHotendTemp); + setTargetBed(absPreheatHPBTemp); + fanSpeed = absPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} + +#if TEMP_SENSOR_1 != 0 //2nd extruder preheat +void lcd_preheat_pla1() +{ + setTargetHotend1(plaPreheatHotendTemp); + setTargetBed(plaPreheatHPBTemp); + fanSpeed = plaPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} + +void lcd_preheat_abs1() +{ + setTargetHotend1(absPreheatHotendTemp); + setTargetBed(absPreheatHPBTemp); + fanSpeed = absPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} +#endif //2nd extruder preheat + +#if TEMP_SENSOR_2 != 0 //3 extruder preheat +void lcd_preheat_pla2() +{ + setTargetHotend2(plaPreheatHotendTemp); + setTargetBed(plaPreheatHPBTemp); + fanSpeed = plaPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} + +void lcd_preheat_abs2() +{ + setTargetHotend2(absPreheatHotendTemp); + setTargetBed(absPreheatHPBTemp); + fanSpeed = absPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} +#endif //3 extruder preheat + +#if TEMP_SENSOR_1 != 0 || TEMP_SENSOR_2 != 0 //more than one extruder present +void lcd_preheat_pla012() +{ + setTargetHotend0(plaPreheatHotendTemp); + setTargetHotend1(plaPreheatHotendTemp); + setTargetHotend2(plaPreheatHotendTemp); + setTargetBed(plaPreheatHPBTemp); + fanSpeed = plaPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} + +void lcd_preheat_abs012() +{ + setTargetHotend0(absPreheatHotendTemp); + setTargetHotend1(absPreheatHotendTemp); + setTargetHotend2(absPreheatHotendTemp); + setTargetBed(absPreheatHPBTemp); + fanSpeed = absPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} +#endif //more than one extruder present + +void lcd_preheat_pla_bedonly() +{ + setTargetBed(plaPreheatHPBTemp); + fanSpeed = plaPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} + +void lcd_preheat_abs_bedonly() +{ + setTargetBed(absPreheatHPBTemp); + fanSpeed = absPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} + +static void lcd_preheat_pla_menu() +{ + START_MENU(); + MENU_ITEM(back, MSG_PREPARE, lcd_prepare_menu); + MENU_ITEM(function, MSG_PREHEAT_PLA0, lcd_preheat_pla0); +#if TEMP_SENSOR_1 != 0 //2 extruder preheat + MENU_ITEM(function, MSG_PREHEAT_PLA1, lcd_preheat_pla1); +#endif //2 extruder preheat +#if TEMP_SENSOR_2 != 0 //3 extruder preheat + MENU_ITEM(function, MSG_PREHEAT_PLA2, lcd_preheat_pla2); +#endif //3 extruder preheat +#if TEMP_SENSOR_1 != 0 || TEMP_SENSOR_2 != 0 //all extruder preheat + MENU_ITEM(function, MSG_PREHEAT_PLA012, lcd_preheat_pla012); +#endif //2 extruder preheat +#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(); + MENU_ITEM(back, MSG_PREPARE, lcd_prepare_menu); + MENU_ITEM(function, MSG_PREHEAT_ABS0, lcd_preheat_abs0); +#if TEMP_SENSOR_1 != 0 //2 extruder preheat + MENU_ITEM(function, MSG_PREHEAT_ABS1, lcd_preheat_abs1); +#endif //2 extruder preheat +#if TEMP_SENSOR_2 != 0 //3 extruder preheat + MENU_ITEM(function, MSG_PREHEAT_ABS2, lcd_preheat_abs2); +#endif //3 extruder preheat +#if TEMP_SENSOR_1 != 0 || TEMP_SENSOR_2 != 0 //all extruder preheat + MENU_ITEM(function, MSG_PREHEAT_ABS012, lcd_preheat_abs012); +#endif //2 extruder preheat +#if TEMP_SENSOR_BED != 0 + MENU_ITEM(function, MSG_PREHEAT_ABS_BEDONLY, lcd_preheat_abs_bedonly); +#endif + END_MENU(); +} + +void lcd_cooldown() +{ + setTargetHotend0(0); + setTargetHotend1(0); + setTargetHotend2(0); + setTargetBed(0); + fanSpeed = 0; + lcd_return_to_status(); +} + static void lcd_prepare_menu() { START_MENU(); @@ -447,8 +564,15 @@ static void lcd_prepare_menu() MENU_ITEM(gcode, MSG_DISABLE_STEPPERS, PSTR("M84")); MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28")); //MENU_ITEM(gcode, MSG_SET_ORIGIN, PSTR("G92 X0 Y0 Z0")); - MENU_ITEM(function, MSG_PREHEAT_PLA, lcd_preheat_pla); - MENU_ITEM(function, MSG_PREHEAT_ABS, lcd_preheat_abs); +#if TEMP_SENSOR_0 != 0 + #if TEMP_SENSOR_1 != 0 || TEMP_SENSOR_2 != 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); + #else + MENU_ITEM(function, MSG_PREHEAT_PLA, lcd_preheat_pla0); + MENU_ITEM(function, MSG_PREHEAT_ABS, lcd_preheat_abs0); + #endif +#endif MENU_ITEM(function, MSG_COOLDOWN, lcd_cooldown); #if PS_ON_PIN > -1 if (powersupply) From eecda434fb46ebb858cc467da28ed2e346439dba Mon Sep 17 00:00:00 2001 From: Ralf Schultz Date: Tue, 18 Mar 2014 08:25:20 +0100 Subject: [PATCH 205/256] Sanguinololu servo pins set default disabled --- Marlin/pins.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/pins.h b/Marlin/pins.h index 56d55e985f..76d5e37bc5 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -1055,18 +1055,18 @@ #endif #ifdef NUM_SERVOS - #define SERVO0_PIN 11 + #define SERVO0_PIN -1 #if NUM_SERVOS > 1 - #define SERVO1_PIN 27 + #define SERVO1_PIN -1 #endif #if NUM_SERVOS > 2 - #define SERVO2_PIN 28 + #define SERVO2_PIN -1 #endif #if NUM_SERVOS > 3 - #define SERVO3_PIN 29 + #define SERVO3_PIN -1 #endif #endif From fad2a60ce6ad364b7da84623cd9a94966ee3e412 Mon Sep 17 00:00:00 2001 From: Dim3nsioneer Date: Wed, 19 Mar 2014 12:23:35 +0100 Subject: [PATCH 206/256] Corrections for preheat extension in language.h --- Marlin/language.h | 89 ++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index c8b7de8ef8..4082221cad 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -261,7 +261,6 @@ #if LANGUAGE_CHOICE == 2 - // LCD Menu Messages // Please note these are limited to 17 characters! @@ -277,16 +276,16 @@ #define MSG_PREHEAT_PLA0 "Rozgrzej PLA 1" #define MSG_PREHEAT_PLA1 "Rozgrzej PLA 2" #define MSG_PREHEAT_PLA2 "Rozgrzej PLA 3" - #define MSG_PREHEAT_PLA012 "Rozgrzej PLA Wszystko" + #define MSG_PREHEAT_PLA012 "Roz. PLA Wszystko" #define MSG_PREHEAT_PLA_BEDONLY "Rozgrzej PLA Loze" - #define MSG_PREHEAT_PLA_SETTINGS "Ustawienia roz. PLA" + #define MSG_PREHEAT_PLA_SETTINGS "Ustaw. rozg. PLA" #define MSG_PREHEAT_ABS "Rozgrzej ABS" #define MSG_PREHEAT_ABS0 "Rozgrzej ABS 1" #define MSG_PREHEAT_ABS1 "Rozgrzej ABS 2" #define MSG_PREHEAT_ABS2 "Rozgrzej ABS 3" - #define MSG_PREHEAT_ABS012 "Rozgrzej ABS Wszystko" + #define MSG_PREHEAT_ABS012 "Roz. ABS Wszystko" #define MSG_PREHEAT_ABS_BEDONLY "Rozgrzej ABS Loze" - #define MSG_PREHEAT_ABS_SETTINGS "Ustawienia roz. ABS" + #define MSG_PREHEAT_ABS_SETTINGS "Ustaw. rozg. ABS" #define MSG_COOLDOWN "Chlodzenie" #define MSG_SWITCH_PS_ON "Wlacz zasilacz" #define MSG_SWITCH_PS_OFF "Wylacz zasilacz" @@ -473,19 +472,19 @@ #define MSG_AUTO_HOME "Home auto." #define MSG_SET_ORIGIN "Regler origine" #define MSG_PREHEAT_PLA " Prechauffage PLA" - #define MSG_PREHEAT_PLA0 "Prechauffage PLA 1" - #define MSG_PREHEAT_PLA1 "Prechauffage PLA 2" - #define MSG_PREHEAT_PLA2 "Prechauffage PLA 3" - #define MSG_PREHEAT_PLA012 "Prechauffage PLA Tout" - #define MSG_PREHEAT_PLA_BEDONLY "Prechauffage PLA Plateau" - #define MSG_PREHEAT_PLA_SETTINGS " Regl. prechauffe PLA" + #define MSG_PREHEAT_PLA0 "Prechauff. PLA 1" + #define MSG_PREHEAT_PLA1 "Prechauff. PLA 2" + #define MSG_PREHEAT_PLA2 "Prechauff. PLA 3" + #define MSG_PREHEAT_PLA012 "Prech. PLA Tout" + #define MSG_PREHEAT_PLA_BEDONLY "Prech. PLA Plateau" + #define MSG_PREHEAT_PLA_SETTINGS "Regl. prech. PLA" #define MSG_PREHEAT_ABS "Prechauffage ABS" - #define MSG_PREHEAT_ABS0 "Prechauffage ABS 1" - #define MSG_PREHEAT_ABS1 "Prechauffage ABS 2" - #define MSG_PREHEAT_ABS2 "Prechauffage ABS 3" - #define MSG_PREHEAT_ABS012 "Prechauffage ABS Tout" - #define MSG_PREHEAT_ABS_BEDONLY "Prechauffage ABS Plateau" - #define MSG_PREHEAT_ABS_SETTINGS "Regl. prechauffe ABS" + #define MSG_PREHEAT_ABS0 "Prechauff. ABS 1" + #define MSG_PREHEAT_ABS1 "Prechauff. ABS 2" + #define MSG_PREHEAT_ABS2 "Prechauff. ABS 3" + #define MSG_PREHEAT_ABS012 "Prech. ABS Tout" + #define MSG_PREHEAT_ABS_BEDONLY "Prech. ABS Plateau" + #define MSG_PREHEAT_ABS_SETTINGS "Regl. prech. ABS" #define MSG_COOLDOWN "Refroidir" #define MSG_SWITCH_PS_ON "Allumer alim." #define MSG_SWITCH_PS_OFF "Eteindre alim." @@ -676,16 +675,16 @@ #define MSG_PREHEAT_PLA0 "Vorwärmen PLA 1" #define MSG_PREHEAT_PLA1 "Vorwärmen PLA 2" #define MSG_PREHEAT_PLA2 "Vorwärmen PLA 3" - #define MSG_PREHEAT_PLA012 "Vorwärmen PLA Alle" - #define MSG_PREHEAT_PLA_BEDONLY "Vorwärmen PLA Bett" - #define MSG_PREHEAT_PLA_SETTINGS "Vorwärmen PLA Einstellungen" + #define MSG_PREHEAT_PLA012 "Vorw. PLA Alle" + #define MSG_PREHEAT_PLA_BEDONLY "Vorw. PLA Bett" + #define MSG_PREHEAT_PLA_SETTINGS "Vorwärm. PLA Ein." #define MSG_PREHEAT_ABS "Vorwärmen ABS" #define MSG_PREHEAT_ABS0 "Vorwärmen ABS 1" #define MSG_PREHEAT_ABS1 "Vorwärmen ABS 2" #define MSG_PREHEAT_ABS2 "Vorwärmen ABS 3" - #define MSG_PREHEAT_ABS012 "Vorwärmen ABS Alle" - #define MSG_PREHEAT_ABS_BEDONLY "Vorwärmen ABS Bett" - #define MSG_PREHEAT_ABS_SETTINGS "Vorwärmen ABS Einstellungen" + #define MSG_PREHEAT_ABS012 "Vorw. ABS Alle" + #define MSG_PREHEAT_ABS_BEDONLY "Vorw. ABS Bett" + #define MSG_PREHEAT_ABS_SETTINGS "Vorwärm. ABS Ein." #define MSG_COOLDOWN "Abkühlen" #define MSG_SWITCH_PS_ON "Switch Power On" #define MSG_SWITCH_PS_OFF "Switch Power Off" @@ -875,15 +874,15 @@ #define MSG_PREHEAT_PLA0 "Precalentar PLA 1" #define MSG_PREHEAT_PLA1 "Precalentar PLA 2" #define MSG_PREHEAT_PLA2 "Precalentar PLA 3" - #define MSG_PREHEAT_PLA012 "Precalentar PLA Todo" - #define MSG_PREHEAT_PLA_BEDONLY "Precalentar PLA Base" + #define MSG_PREHEAT_PLA012 "Precal. PLA Todo" + #define MSG_PREHEAT_PLA_BEDONLY "Precal. PLA Base" #define MSG_PREHEAT_PLA_SETTINGS "Ajustar temp. PLA" #define MSG_PREHEAT_ABS "Precalentar ABS" #define MSG_PREHEAT_ABS0 "Precalentar ABS 1" #define MSG_PREHEAT_ABS1 "Precalentar ABS 2" #define MSG_PREHEAT_ABS2 "Precalentar ABS 3" - #define MSG_PREHEAT_ABS012 "Precalentar ABS Todo" - #define MSG_PREHEAT_ABS_BEDONLY "Precalentar ABS Base" + #define MSG_PREHEAT_ABS012 "Precal. ABS Todo" + #define MSG_PREHEAT_ABS_BEDONLY "Precal. ABS Base" #define MSG_PREHEAT_ABS_SETTINGS "Ajustar temp. ABS" #define MSG_COOLDOWN "Enfriar" #define MSG_SWITCH_PS_ON "Switch Power On" @@ -1079,15 +1078,15 @@ #define MSG_PREHEAT_PLA0 "Преднагрев PLA0" #define MSG_PREHEAT_PLA1 "Преднагрев PLA1" #define MSG_PREHEAT_PLA2 "Преднагрев PLA2" - #define MSG_PREHEAT_PLA012 "Преднагрев PLA все " - #define MSG_PREHEAT_PLA_BEDONLY "Преднагрев PLA \002 Кровать" + #define MSG_PREHEAT_PLA012 "Преднаг. PLA все" + #define MSG_PREHEAT_PLA_BEDONLY "Пред. PLA Кровать" #define MSG_PREHEAT_PLA_SETTINGS "Настройки PLA" #define MSG_PREHEAT_ABS "Преднагрев ABS" #define MSG_PREHEAT_ABS0 "Преднагрев ABS0" #define MSG_PREHEAT_ABS1 "Преднагрев ABS1" #define MSG_PREHEAT_ABS2 "Преднагрев ABS2" - #define MSG_PREHEAT_ABS012 "Преднагрев ABS все " - #define MSG_PREHEAT_ABS_BEDONLY "Преднагрев ABS \002 Кровать" + #define MSG_PREHEAT_ABS012 "Преднаг. ABS все " + #define MSG_PREHEAT_ABS_BEDONLY "Пред. ABS Кровать" #define MSG_PREHEAT_ABS_SETTINGS "Настройки ABS" #define MSG_COOLDOWN "Охлаждение" #define MSG_SWITCH_PS_ON "Switch Power On" @@ -1274,15 +1273,15 @@ #define MSG_PREHEAT_PLA0 "Preriscalda PLA 1" #define MSG_PREHEAT_PLA1 "Preriscalda PLA 2" #define MSG_PREHEAT_PLA2 "Preriscalda PLA 3" - #define MSG_PREHEAT_PLA012 "Preriscalda PLA Tutto" - #define MSG_PREHEAT_PLA_BEDONLY "Preriscalda PLA Piatto" + #define MSG_PREHEAT_PLA012 "Preris. PLA Tutto" + #define MSG_PREHEAT_PLA_BEDONLY "Preri. PLA Piatto" #define MSG_PREHEAT_PLA_SETTINGS "Preris. PLA Conf" #define MSG_PREHEAT_ABS "Preriscalda ABS" #define MSG_PREHEAT_ABS0 "Preriscalda ABS 1" #define MSG_PREHEAT_ABS1 "Preriscalda ABS 2" #define MSG_PREHEAT_ABS2 "Preriscalda ABS 3" - #define MSG_PREHEAT_ABS012 "Preriscalda ABS Tutto" - #define MSG_PREHEAT_ABS_BEDONLY "Preriscalda ABS Piatto" + #define MSG_PREHEAT_ABS012 "Preris. ABS Tutto" + #define MSG_PREHEAT_ABS_BEDONLY "Preri. ABS Piatto" #define MSG_PREHEAT_ABS_SETTINGS "Preris. ABS Conf" #define MSG_COOLDOWN "Raffredda" #define MSG_SWITCH_PS_ON "Switch Power On" @@ -1471,15 +1470,15 @@ #define MSG_PREHEAT_PLA0 " pre-aquecer PLA 1" #define MSG_PREHEAT_PLA1 " pre-aquecer PLA 2" #define MSG_PREHEAT_PLA2 " pre-aquecer PLA 3" - #define MSG_PREHEAT_PLA012 " pre-aquecer PLA Tudo" - #define MSG_PREHEAT_PLA_BEDONLY " pre-aquecer PLA \002Base" + #define MSG_PREHEAT_PLA012 " pre-aq. PLA Tudo" + #define MSG_PREHEAT_PLA_BEDONLY " pre-aq. PLA \002Base" #define MSG_PREHEAT_PLA_SETTINGS "PLA setting" #define MSG_PREHEAT_ABS "Pre-aquecer ABS" #define MSG_PREHEAT_ABS0 " pre-aquecer ABS 1" #define MSG_PREHEAT_ABS1 " pre-aquecer ABS 2" #define MSG_PREHEAT_ABS2 " pre-aquecer ABS 3" - #define MSG_PREHEAT_ABS012 " pre-aquecer ABS Tudo" - #define MSG_PREHEAT_ABS_BEDONLY " pre-aquecer ABS \002Base" + #define MSG_PREHEAT_ABS012 " pre-aq. ABS Tudo" + #define MSG_PREHEAT_ABS_BEDONLY " pre-aq. ABS \002Base" #define MSG_PREHEAT_ABS_SETTINGS "ABS setting" #define MSG_COOLDOWN "Esfriar" #define MSG_SWITCH_PS_ON "Switch Power On" @@ -1675,15 +1674,15 @@ #define MSG_PREHEAT_PLA0 "Esilammita PLA 1" #define MSG_PREHEAT_PLA1 "Esilammita PLA 2" #define MSG_PREHEAT_PLA2 "Esilammita PLA 3" - #define MSG_PREHEAT_PLA012 "Esilammita PLA Kaikki" - #define MSG_PREHEAT_PLA_BEDONLY "Esilammita PLA Alusta" + #define MSG_PREHEAT_PLA012 "Esila. PLA Kaikki" + #define MSG_PREHEAT_PLA_BEDONLY "Esila. PLA Alusta" #define MSG_PREHEAT_PLA_SETTINGS "Esilamm. PLA konf" #define MSG_PREHEAT_ABS "Esilammita ABS" #define MSG_PREHEAT_ABS0 "Esilammita ABS 1" #define MSG_PREHEAT_ABS1 "Esilammita ABS 2" #define MSG_PREHEAT_ABS2 "Esilammita ABS 3" - #define MSG_PREHEAT_ABS012 "Esilammita ABS Kaikki" - #define MSG_PREHEAT_ABS_BEDONLY "Esilammita ABS Alusta" + #define MSG_PREHEAT_ABS012 "Esila. ABS Kaikki" + #define MSG_PREHEAT_ABS_BEDONLY "Esila. ABS Alusta" #define MSG_PREHEAT_ABS_SETTINGS "Esilamm. ABS konf" #define MSG_COOLDOWN "Jaahdyta" #define MSG_SWITCH_PS_ON "Virta paalle" @@ -2105,6 +2104,9 @@ #define MSG_BED "Bed" #define MSG_FAN_SPEED "Fan snelheid" #define MSG_FLOW "Flow" + #define MSG_FLOW0 "Flow 0" + #define MSG_FLOW1 "Flow 1" + #define MSG_FLOW2 "Flow 2" #define MSG_CONTROL "Control" #define MSG_MIN " \002 Min" #define MSG_MAX " \002 Max" @@ -2197,6 +2199,7 @@ #define MSG_M105_INVALID_EXTRUDER "M105 Ongeldige extruder " #define MSG_M200_INVALID_EXTRUDER "M200 Ongeldige extruder " #define MSG_M218_INVALID_EXTRUDER "M218 Ongeldige extruder " + #define MSG_M221_INVALID_EXTRUDER "M221 Ongeldige extruder " #define MSG_ERR_NO_THERMISTORS "Geen thermistors - geen temperatuur" #define MSG_M109_INVALID_EXTRUDER "M109 Ongeldige extruder " #define MSG_HEATING "Opwarmen..." From 7395dafc1e7c3f84dc4b66384e0726ef0d916a94 Mon Sep 17 00:00:00 2001 From: Dim3nsioneer Date: Wed, 19 Mar 2014 12:30:50 +0100 Subject: [PATCH 207/256] semantic changes in language.h --- Marlin/language.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index 4082221cad..d55d0f8b55 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -82,14 +82,14 @@ #define MSG_PREHEAT_PLA2 "Preheat PLA 3" #define MSG_PREHEAT_PLA012 "Preheat PLA All" #define MSG_PREHEAT_PLA_BEDONLY "Preheat PLA Bed" - #define MSG_PREHEAT_PLA_SETTINGS "Preheat PLA Conf" + #define MSG_PREHEAT_PLA_SETTINGS "Preheat PLA conf" #define MSG_PREHEAT_ABS "Preheat ABS" #define MSG_PREHEAT_ABS0 "Preheat ABS 1" #define MSG_PREHEAT_ABS1 "Preheat ABS 2" #define MSG_PREHEAT_ABS2 "Preheat ABS 3" #define MSG_PREHEAT_ABS012 "Preheat ABS All" #define MSG_PREHEAT_ABS_BEDONLY "Preheat ABS Bed" - #define MSG_PREHEAT_ABS_SETTINGS "Preheat ABS Conf" + #define MSG_PREHEAT_ABS_SETTINGS "Preheat ABS conf" #define MSG_COOLDOWN "Cooldown" #define MSG_SWITCH_PS_ON "Switch power on" #define MSG_SWITCH_PS_OFF "Switch power off" From c8cdd1fc6f01505f3a3cd5e584f8d221610232b8 Mon Sep 17 00:00:00 2001 From: Dim3nsioneer Date: Wed, 19 Mar 2014 14:27:38 +0100 Subject: [PATCH 208/256] Bugfixes for language option 6 (russian) --- Marlin/language.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index d55d0f8b55..ed94cc36ed 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -1066,10 +1066,10 @@ // LCD Menu Messages // Please note these are limited to 17 characters! - #define WELCOME_MSG MACHINE_NAME " Готов." + #define WELCOME_MSG MACHINE_NAME "Готов." #define MSG_SD_INSERTED "Карта вставлена" #define MSG_SD_REMOVED "Карта извлечена" - #define MSG_MAIN "Меню \003" + #define MSG_MAIN "Меню \003" #define MSG_AUTOSTART "Автостарт" #define MSG_DISABLE_STEPPERS "Выкл. двигатели" #define MSG_AUTO_HOME "Парковка" @@ -1150,8 +1150,8 @@ #define MSG_WATCH "Обзор \003" #define MSG_PREPARE "Действия \x7E" #define MSG_TUNE "Настройки \x7E" - #define MSG_RESUME_PRINT "Продолжить печать" - #define MSG_RESUME_PRINT "Продолжить печать" + #define MSG_PAUSE_PRINT "Продолжить печать" + #define MSG_RESUME_PRINT "возобн. печать" #define MSG_STOP_PRINT "Остановить печать" #define MSG_CARD_MENU "Меню карты \x7E" #define MSG_NO_CARD "Нет карты" From f643f4d67487e0d4ae190e579e9051e90985516f Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Fri, 21 Mar 2014 20:42:00 +0000 Subject: [PATCH 209/256] Test and refactor --- Marlin/Marlin_main.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index f27add1576..669c7b81b1 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -659,10 +659,9 @@ void get_command() } + //If command was e-stop process now if(strcmp(cmdbuffer[bufindw], "M112") == 0) - { kill(); - } bufindw = (bufindw + 1)%BUFSIZE; buflen += 1; From 990e770e15c38903288db760549521c12e4ffa43 Mon Sep 17 00:00:00 2001 From: pixatintes Date: Sun, 23 Mar 2014 10:30:08 +0100 Subject: [PATCH 210/256] Update language.h Added catalan language --- Marlin/language.h | 192 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) diff --git a/Marlin/language.h b/Marlin/language.h index ed94cc36ed..343fc24ecc 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -18,6 +18,7 @@ // 9 Finnish // 10 Aragonese // 11 Dutch +// 12 Catalan #ifndef LANGUAGE_CHOICE #define LANGUAGE_CHOICE 1 // Pick your language from the list above @@ -2252,4 +2253,195 @@ #endif + +#if LANGUAGE_CHOICE == 12 + +// LCD Menu Messages + +// Please note these are limited to 17 characters! + + #define WELCOME_MSG MACHINE_NAME " a punt!" + #define MSG_SD_INSERTED "SD detectada." + #define MSG_SD_REMOVED "SD expulsada." + #define MSG_MAIN "Menu principal" + #define MSG_AUTOSTART "Inici automatic" + #define MSG_DISABLE_STEPPERS " Apagar motors" + #define MSG_AUTO_HOME " Home global" + #define MSG_SET_ORIGIN "Establir origen" + #define MSG_PREHEAT_PLA " Preescalfar PLA" + #define MSG_PREHEAT_PLA_SETTINGS "Config. temp. PLA" + #define MSG_PREHEAT_ABS " Preescalfar ABS" + #define MSG_PREHEAT_ABS_SETTINGS "Config. temp. ABS" + #define MSG_COOLDOWN " Refredar" + #define MSG_SWITCH_PS_ON " Switch Power On" + #define MSG_SWITCH_PS_OFF " Switch Power Off" + #define MSG_EXTRUDE "Extruir" + #define MSG_RETRACT "Retreure" + #define MSG_MOVE_AXIS " Moure eixos" + #define MSG_MOVE_X " Moure X" + #define MSG_MOVE_Y " Moure Y" + #define MSG_MOVE_Z " Moure Z" + #define MSG_MOVE_E "Extrusor" + #define MSG_MOVE_01MM " Moure 0.1mm" + #define MSG_MOVE_1MM " Moure 1mm" + #define MSG_MOVE_10MM " Moure 10mm" + #define MSG_SPEED "Velocitat" + #define MSG_NOZZLE "Nozzle" + #define MSG_NOZZLE1 "Nozzle2" + #define MSG_NOZZLE2 "Nozzle3" + #define MSG_BED "Llit" + #define MSG_FAN_SPEED "Vel. Ventilador" + #define MSG_FLOW "Fluxe" + #define MSG_CONTROL " Control" + #define MSG_MIN "\002 Min" + #define MSG_MAX "\002 Max" + #define MSG_FACTOR "\002 Fact" + #define MSG_AUTOTEMP "Autotemp" + #define MSG_ON "On" + #define MSG_OFF "Off" + #define MSG_PID_P "PID-P" + #define MSG_PID_I "PID-I" + #define MSG_PID_D "PID-D" + #define MSG_PID_C "PID-C" + #define MSG_ACC "Acel" + #define MSG_VXY_JERK "Vxy-jerk" + #define MSG_VZ_JERK "Vz-jerk" + #define MSG_VE_JERK "Ve-jerk" + #define MSG_VMAX "Vmax" + #define MSG_X "x" + #define MSG_Y "y" + #define MSG_Z "z" + #define MSG_E "e" + #define MSG_VMIN "Vmin" + #define MSG_VTRAV_MIN "VTrav min" + #define MSG_AMAX "Amax" + #define MSG_A_RETRACT "A-retrac." + #define MSG_XSTEPS "X passos/mm" + #define MSG_YSTEPS "Y passos/mm" + #define MSG_ZSTEPS "Z passos/mm" + #define MSG_ESTEPS "E passos/mm" + #define MSG_RECTRACT "Retreure" + #define MSG_TEMPERATURE " Temperatura" + #define MSG_MOTION " Moviment" + #define MSG_STORE_EPROM "Desar memoria" + #define MSG_LOAD_EPROM "Llegir memoria" + #define MSG_RESTORE_FAILSAFE " Rest. emergencia" + #define MSG_REFRESH "Tornar a carregar" + #define MSG_WATCH "Pantalla Info." + #define MSG_PREPARE " Preparar" + #define MSG_TUNE " Ajustar" + #define MSG_PAUSE_PRINT " Pausa Imp." + #define MSG_RESUME_PRINT " Reprendre Imp." + #define MSG_STOP_PRINT " Aturar Imp." + #define MSG_CARD_MENU " Explorar SD" + #define MSG_NO_CARD " -Sense SD" + #define MSG_DWELL "Repos..." + #define MSG_USERWAIT "Esperant ordres" + #define MSG_RESUMING "Reprendre Imp." + #define MSG_NO_MOVE "Sense moviment" + #define MSG_KILLED "PARADA DE EMERG." + #define MSG_STOPPED "PARADA" + #define MSG_CONTROL_RETRACT "Retreure mm" + #define MSG_CONTROL_RETRACTF "Retreure F" + #define MSG_CONTROL_RETRACT_ZLIFT "Aixecar mm" + #define MSG_CONTROL_RETRACT_RECOVER "DesRet +mm" + #define MSG_CONTROL_RETRACT_RECOVERF "DesRet F" + #define MSG_AUTORETRACT "AutoRetr." + #define MSG_FILAMENTCHANGE "Canviar filament" + #define MSG_INIT_SDCARD "Iniciant SD" + #define MSG_CNG_SDCARD "Canviar SD" + #define MSG_RECTRACT_WIDE " Retreure " + #define MSG_TEMPERATURE_WIDE "Temperatura" + #define MSG_TEMPERATURE_RTN "Temperatura" + #define MSG_MAIN_WIDE "Menu principal" + #define MSG_MOTION_WIDE "Moviment" + #define MSG_PREPARE_ALT "Preparar" + #define MSG_CONTROL_ARROW "Control" + #define MSG_RETRACT_ARROW "Retreure" + #define MSG_STEPPER_RELEASED "Desacoblada." + #define MSG_ZPROBE_OUT "Z probe out. bed" + #define MSG_POSITION_UNKNOWN "Home X/Y before Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_BABYSTEP_X "Babystep X" + #define MSG_BABYSTEP_Y "Babystep Y" + #define MSG_BABYSTEP_Z "Babystep Z" + #define MSG_ENDSTOP_ABORT "Endstop abort" + #define MSG_CONTRAST "Contrast" + +// Serial Console Messages + + #define MSG_Enqueing "en cua \"" + #define MSG_POWERUP "PowerUp" + #define MSG_EXTERNAL_RESET " Reset Extern" + #define MSG_BROWNOUT_RESET " Reset per Voltatge Incorrecte" + #define MSG_WATCHDOG_RESET " Reset per Bloqueig" + #define MSG_SOFTWARE_RESET " Reset per Software" + #define MSG_AUTHOR " | Autor: " + #define MSG_CONFIGURATION_VER " Ultima actualitzacio: " + #define MSG_FREE_MEMORY " Memoria lliure: " + #define MSG_PLANNER_BUFFER_BYTES " PlannerBufferBytes: " + #define MSG_OK "Ok" + #define MSG_FILE_SAVED "Desat." + #define MSG_ERR_LINE_NO "El Numero de la Linia no es igual al Ultimo Numero de Linia+1, Ultima Linia:" + #define MSG_ERR_CHECKSUM_MISMATCH "el checksum no coincideix, Ultima Linia:" + #define MSG_ERR_NO_CHECKSUM "No s'ha trobat el Checksum amb el numero de linia, Ultima Linia:" + #define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No s'ha trobat Numero de Linia amb el Checksum, Ultima Linia:" + #define MSG_FILE_PRINTED "Treball acabat!" + #define MSG_BEGIN_FILE_LIST "Inici de la llista d'arxius" + #define MSG_END_FILE_LIST "Fi de la llista d'arxius" + #define MSG_M104_INVALID_EXTRUDER "M104 Extrusor Invalid " + #define MSG_M105_INVALID_EXTRUDER "M105 Extrusor Invalid " + #define MSG_M200_INVALID_EXTRUDER "M200 Extrusor Invalid " + #define MSG_M218_INVALID_EXTRUDER "M218 Extrusor Invalid " + #define MSG_ERR_NO_THERMISTORS "No hi ha termistors - no temp" + #define MSG_M109_INVALID_EXTRUDER "M109 Extrusor Invalid " + #define MSG_HEATING "Escalfant Nozzle..." + #define MSG_HEATING_COMPLETE "Nozzle calent." + #define MSG_BED_HEATING "Escalfant llit..." + #define MSG_BED_DONE "Llit calent." + #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" + #define MSG_COUNT_X " Compta X:" + #define MSG_ERR_KILLED "¡¡Impressora Parada per kill()!!" + #define MSG_ERR_STOPPED "¡Impressora parada per errors. Repara l'error i utilitza M999 per reiniciar!. (Hi ha un reset de temperatura, cal ajustar-la abans de continuar)" + #define MSG_RESEND "Reenviar:" + #define MSG_UNKNOWN_COMMAND "Comanda Desconeguda:\"" + #define MSG_ACTIVE_EXTRUDER "Extrusor Actiu: " + #define MSG_INVALID_EXTRUDER "Extrusor Invalid" + #define MSG_X_MIN "x_min: " + #define MSG_X_MAX "x_max: " + #define MSG_Y_MIN "y_min: " + #define MSG_Y_MAX "y_max: " + #define MSG_Z_MIN "z_min: " + #define MSG_Z_MAX "z_max: " + #define MSG_M119_REPORT "Comprovant finals de carrera." + #define MSG_ENDSTOP_HIT "Activat!" + #define MSG_ENDSTOP_OPEN "obert" + #define MSG_HOTEND_OFFSET "Hotend offsets:" + #define MSG_SD_CANT_OPEN_SUBDIR "No s'ha pogut obrir la subcarpeta." + #define MSG_SD_INIT_FAIL "Error en iniciar la SD" + #define MSG_SD_VOL_INIT_FAIL "Error al muntar el volum" + #define MSG_SD_OPENROOT_FAIL "Error en obrir la carpeta arrel" + #define MSG_SD_CARD_OK "Tarjeta SD OK" + #define MSG_SD_WORKDIR_FAIL "Error en obrir la carpeta de treball" + #define MSG_SD_OPEN_FILE_FAIL "Error en obrir, Fitxer: " + #define MSG_SD_FILE_OPENED "Fitxer obert:" + #define MSG_SD_SIZE " Mida:" + #define MSG_SD_FILE_SELECTED "Fitxer Seleccionat" + #define MSG_SD_WRITE_TO_FILE "Desant al fitxer: " + #define MSG_SD_PRINTING_BYTE "SD imprimint el byte " + #define MSG_SD_NOT_PRINTING "No s'esta imprimint amb SD" + #define MSG_SD_ERR_WRITE_TO_FILE "Error al escriure al fitxer" + #define MSG_SD_CANT_ENTER_SUBDIR "No es pot obrir la carpeta:" + #define MSG_STEPPER_TOO_HIGH "Steprate massa alt : " + #define MSG_ENDSTOPS_HIT "S'ha tocat el final de carrera: " + #define MSG_ERR_COLD_EXTRUDE_STOP " extrusio freda evitada" + #define MSG_ERR_LONG_EXTRUDE_STOP " extrusio massa llarga evitada" + #define MSG_BABYSTEPPING_X "Babystepping X" + #define MSG_BABYSTEPPING_Y "Babystepping Y" + #define MSG_BABYSTEPPING_Z "Babystepping Z" + #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Error a l'estructura dels menus" + +#endif + + #endif // ifndef LANGUAGE_H From a3530d1141a44a0c4baff675aa327d8949d79e2a Mon Sep 17 00:00:00 2001 From: pixatintes Date: Sun, 23 Mar 2014 18:06:48 +0100 Subject: [PATCH 211/256] Update language.h Updated to latest version. --- Marlin/language.h | 365 +++++++++++++++++++++++----------------------- 1 file changed, 186 insertions(+), 179 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index 343fc24ecc..d90cf15558 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -2260,186 +2260,193 @@ // Please note these are limited to 17 characters! - #define WELCOME_MSG MACHINE_NAME " a punt!" - #define MSG_SD_INSERTED "SD detectada." - #define MSG_SD_REMOVED "SD expulsada." - #define MSG_MAIN "Menu principal" - #define MSG_AUTOSTART "Inici automatic" - #define MSG_DISABLE_STEPPERS " Apagar motors" - #define MSG_AUTO_HOME " Home global" - #define MSG_SET_ORIGIN "Establir origen" - #define MSG_PREHEAT_PLA " Preescalfar PLA" - #define MSG_PREHEAT_PLA_SETTINGS "Config. temp. PLA" - #define MSG_PREHEAT_ABS " Preescalfar ABS" - #define MSG_PREHEAT_ABS_SETTINGS "Config. temp. ABS" - #define MSG_COOLDOWN " Refredar" - #define MSG_SWITCH_PS_ON " Switch Power On" - #define MSG_SWITCH_PS_OFF " Switch Power Off" - #define MSG_EXTRUDE "Extruir" - #define MSG_RETRACT "Retreure" - #define MSG_MOVE_AXIS " Moure eixos" - #define MSG_MOVE_X " Moure X" - #define MSG_MOVE_Y " Moure Y" - #define MSG_MOVE_Z " Moure Z" - #define MSG_MOVE_E "Extrusor" - #define MSG_MOVE_01MM " Moure 0.1mm" - #define MSG_MOVE_1MM " Moure 1mm" - #define MSG_MOVE_10MM " Moure 10mm" - #define MSG_SPEED "Velocitat" - #define MSG_NOZZLE "Nozzle" - #define MSG_NOZZLE1 "Nozzle2" - #define MSG_NOZZLE2 "Nozzle3" - #define MSG_BED "Llit" - #define MSG_FAN_SPEED "Vel. Ventilador" - #define MSG_FLOW "Fluxe" - #define MSG_CONTROL " Control" - #define MSG_MIN "\002 Min" - #define MSG_MAX "\002 Max" - #define MSG_FACTOR "\002 Fact" - #define MSG_AUTOTEMP "Autotemp" - #define MSG_ON "On" - #define MSG_OFF "Off" - #define MSG_PID_P "PID-P" - #define MSG_PID_I "PID-I" - #define MSG_PID_D "PID-D" - #define MSG_PID_C "PID-C" - #define MSG_ACC "Acel" - #define MSG_VXY_JERK "Vxy-jerk" - #define MSG_VZ_JERK "Vz-jerk" - #define MSG_VE_JERK "Ve-jerk" - #define MSG_VMAX "Vmax" - #define MSG_X "x" - #define MSG_Y "y" - #define MSG_Z "z" - #define MSG_E "e" - #define MSG_VMIN "Vmin" - #define MSG_VTRAV_MIN "VTrav min" - #define MSG_AMAX "Amax" - #define MSG_A_RETRACT "A-retrac." - #define MSG_XSTEPS "X passos/mm" - #define MSG_YSTEPS "Y passos/mm" - #define MSG_ZSTEPS "Z passos/mm" - #define MSG_ESTEPS "E passos/mm" - #define MSG_RECTRACT "Retreure" - #define MSG_TEMPERATURE " Temperatura" - #define MSG_MOTION " Moviment" - #define MSG_STORE_EPROM "Desar memoria" - #define MSG_LOAD_EPROM "Llegir memoria" - #define MSG_RESTORE_FAILSAFE " Rest. emergencia" - #define MSG_REFRESH "Tornar a carregar" - #define MSG_WATCH "Pantalla Info." - #define MSG_PREPARE " Preparar" - #define MSG_TUNE " Ajustar" - #define MSG_PAUSE_PRINT " Pausa Imp." - #define MSG_RESUME_PRINT " Reprendre Imp." - #define MSG_STOP_PRINT " Aturar Imp." - #define MSG_CARD_MENU " Explorar SD" - #define MSG_NO_CARD " -Sense SD" - #define MSG_DWELL "Repos..." - #define MSG_USERWAIT "Esperant ordres" - #define MSG_RESUMING "Reprendre Imp." - #define MSG_NO_MOVE "Sense moviment" - #define MSG_KILLED "PARADA DE EMERG." - #define MSG_STOPPED "PARADA" - #define MSG_CONTROL_RETRACT "Retreure mm" - #define MSG_CONTROL_RETRACTF "Retreure F" - #define MSG_CONTROL_RETRACT_ZLIFT "Aixecar mm" - #define MSG_CONTROL_RETRACT_RECOVER "DesRet +mm" - #define MSG_CONTROL_RETRACT_RECOVERF "DesRet F" - #define MSG_AUTORETRACT "AutoRetr." - #define MSG_FILAMENTCHANGE "Canviar filament" - #define MSG_INIT_SDCARD "Iniciant SD" - #define MSG_CNG_SDCARD "Canviar SD" - #define MSG_RECTRACT_WIDE " Retreure " - #define MSG_TEMPERATURE_WIDE "Temperatura" - #define MSG_TEMPERATURE_RTN "Temperatura" - #define MSG_MAIN_WIDE "Menu principal" - #define MSG_MOTION_WIDE "Moviment" - #define MSG_PREPARE_ALT "Preparar" - #define MSG_CONTROL_ARROW "Control" - #define MSG_RETRACT_ARROW "Retreure" - #define MSG_STEPPER_RELEASED "Desacoblada." - #define MSG_ZPROBE_OUT "Z probe out. bed" - #define MSG_POSITION_UNKNOWN "Home X/Y before Z" - #define MSG_ZPROBE_ZOFFSET "Z Offset" - #define MSG_BABYSTEP_X "Babystep X" - #define MSG_BABYSTEP_Y "Babystep Y" - #define MSG_BABYSTEP_Z "Babystep Z" - #define MSG_ENDSTOP_ABORT "Endstop abort" - #define MSG_CONTRAST "Contrast" - + #define WELCOME_MSG MACHINE_NAME " preparada." + #define MSG_SD_INSERTED "SD detectada." + #define MSG_SD_REMOVED "SD expulsada." + #define MSG_MAIN "Menu principal" + #define MSG_AUTOSTART "Inici automatic" + #define MSG_DISABLE_STEPPERS "Apagar motors" + #define MSG_AUTO_HOME "Home global" + #define MSG_SET_ORIGIN "Establir origen" + #define MSG_PREHEAT_PLA "Preescalfar PLA" + #define MSG_PREHEAT_PLA0 "Preescalfar PLA 1" + #define MSG_PREHEAT_PLA1 "Preescalfar PLA 2" + #define MSG_PREHEAT_PLA2 "Preescalfar PLA 3" + #define MSG_PREHEAT_PLA012 "Preesc. tot PLA" + #define MSG_PREHEAT_PLA_BEDONLY "Preesc. llit PLA" + #define MSG_PREHEAT_PLA_SETTINGS "Configuració PLA" + #define MSG_PREHEAT_ABS "Preescalfar ABS" + #define MSG_PREHEAT_ABS0 "Preescalfar ABS 1" + #define MSG_PREHEAT_ABS1 "Preescalfar ABS 2" + #define MSG_PREHEAT_ABS2 "Preescalfar ABS 3" + #define MSG_PREHEAT_ABS012 "Preesc. tot ABS" + #define MSG_PREHEAT_ABS_BEDONLY "Preesc. llit ABS" + #define MSG_PREHEAT_ABS_SETTINGS "Configuració ABS" + #define MSG_COOLDOWN "Refredar" + #define MSG_SWITCH_PS_ON "Switch power on" + #define MSG_SWITCH_PS_OFF "Switch power off" + #define MSG_EXTRUDE "Extruir" + #define MSG_RETRACT "Refredar" + #define MSG_MOVE_AXIS "Moure eixos" + #define MSG_MOVE_X "Moure X" + #define MSG_MOVE_Y "Moure Y" + #define MSG_MOVE_Z "Moure Z" + #define MSG_MOVE_E "Extrusor" + #define MSG_MOVE_01MM "Moure 0.1mm" + #define MSG_MOVE_1MM "Moure 1mm" + #define MSG_MOVE_10MM "Moure 10mm" + #define MSG_SPEED "Velocitat" + #define MSG_NOZZLE "Nozzle" + #define MSG_NOZZLE1 "Nozzle2" + #define MSG_NOZZLE2 "Nozzle3" + #define MSG_BED "Llit" + #define MSG_FAN_SPEED "Vel. Ventilador" + #define MSG_FLOW "Fluxe" + #define MSG_FLOW0 "Fluxe 0" + #define MSG_FLOW1 "Fluxe 1" + #define MSG_FLOW2 "Fluxe 2" + #define MSG_CONTROL "Control" + #define MSG_MIN " \002 Min" + #define MSG_MAX " \002 Max" + #define MSG_FACTOR " \002 Fact" + #define MSG_AUTOTEMP "Autotemp" + #define MSG_ON "On " + #define MSG_OFF "Off" + #define MSG_PID_P "PID-P" + #define MSG_PID_I "PID-I" + #define MSG_PID_D "PID-D" + #define MSG_PID_C "PID-C" + #define MSG_ACC "Accel" + #define MSG_VXY_JERK "Vxy-jerk" + #define MSG_VZ_JERK "Vz-jerk" + #define MSG_VE_JERK "Ve-jerk" + #define MSG_VMAX "Vmax " + #define MSG_X "x" + #define MSG_Y "y" + #define MSG_Z "z" + #define MSG_E "e" + #define MSG_VMIN "Vmin" + #define MSG_VTRAV_MIN "VTrav min" + #define MSG_AMAX "Amax " + #define MSG_A_RETRACT "A-retract" + #define MSG_XSTEPS "Xpassos/mm" + #define MSG_YSTEPS "Ypassos/mm" + #define MSG_ZSTEPS "Zpassos/mm" + #define MSG_ESTEPS "Epassos/mm" + #define MSG_RECTRACT "Retreure" + #define MSG_TEMPERATURE "Temperatura" + #define MSG_MOTION "Moviment" + #define MSG_CONTRAST "Contrast de LCD" + #define MSG_STORE_EPROM "Desar a memoria" + #define MSG_LOAD_EPROM "Carregar de mem." + #define MSG_RESTORE_FAILSAFE "Rest. emergencia" + #define MSG_REFRESH "Refrescar" + #define MSG_WATCH "Pantalla Info." + #define MSG_PREPARE "Preparar" + #define MSG_TUNE "Calibrar" + #define MSG_PAUSE_PRINT "Pausa imp." + #define MSG_RESUME_PRINT "Reprendre imp." + #define MSG_STOP_PRINT "Parar inp." + #define MSG_CARD_MENU "Imprimir de SD" + #define MSG_NO_CARD "-Sense targeta SD" + #define MSG_DWELL "Repos..." + #define MSG_USERWAIT "Esperant usuari.." + #define MSG_RESUMING "Reprenent imp." + #define MSG_NO_MOVE "Sense moviment." + #define MSG_KILLED "PARADA DE EMERG. " + #define MSG_STOPPED "ATURAT. " + #define MSG_CONTROL_RETRACT "Retreure mm" + #define MSG_CONTROL_RETRACTF "Retreure F" + #define MSG_CONTROL_RETRACT_ZLIFT "Aixecar mm" + #define MSG_CONTROL_RETRACT_RECOVER "DesRet +mm" + #define MSG_CONTROL_RETRACT_RECOVERF "DesRet F" + #define MSG_AUTORETRACT "AutoRetr." + #define MSG_FILAMENTCHANGE "Canviar filament" + #define MSG_INIT_SDCARD "Iniciant SD" + #define MSG_CNG_SDCARD "Canviar SD" + #define MSG_ZPROBE_OUT "Z probe out. bed" + #define MSG_POSITION_UNKNOWN "Home X/Y abans Z" + #define MSG_ZPROBE_ZOFFSET "Z Offset" + #define MSG_BABYSTEP_X "Babystep X" + #define MSG_BABYSTEP_Y "Babystep Y" + #define MSG_BABYSTEP_Z "Babystep Z" + #define MSG_ENDSTOP_ABORT "Endstop abort" + // Serial Console Messages - - #define MSG_Enqueing "en cua \"" - #define MSG_POWERUP "PowerUp" - #define MSG_EXTERNAL_RESET " Reset Extern" - #define MSG_BROWNOUT_RESET " Reset per Voltatge Incorrecte" - #define MSG_WATCHDOG_RESET " Reset per Bloqueig" - #define MSG_SOFTWARE_RESET " Reset per Software" - #define MSG_AUTHOR " | Autor: " - #define MSG_CONFIGURATION_VER " Ultima actualitzacio: " - #define MSG_FREE_MEMORY " Memoria lliure: " - #define MSG_PLANNER_BUFFER_BYTES " PlannerBufferBytes: " - #define MSG_OK "Ok" - #define MSG_FILE_SAVED "Desat." - #define MSG_ERR_LINE_NO "El Numero de la Linia no es igual al Ultimo Numero de Linia+1, Ultima Linia:" - #define MSG_ERR_CHECKSUM_MISMATCH "el checksum no coincideix, Ultima Linia:" - #define MSG_ERR_NO_CHECKSUM "No s'ha trobat el Checksum amb el numero de linia, Ultima Linia:" - #define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No s'ha trobat Numero de Linia amb el Checksum, Ultima Linia:" - #define MSG_FILE_PRINTED "Treball acabat!" - #define MSG_BEGIN_FILE_LIST "Inici de la llista d'arxius" - #define MSG_END_FILE_LIST "Fi de la llista d'arxius" - #define MSG_M104_INVALID_EXTRUDER "M104 Extrusor Invalid " - #define MSG_M105_INVALID_EXTRUDER "M105 Extrusor Invalid " - #define MSG_M200_INVALID_EXTRUDER "M200 Extrusor Invalid " - #define MSG_M218_INVALID_EXTRUDER "M218 Extrusor Invalid " - #define MSG_ERR_NO_THERMISTORS "No hi ha termistors - no temp" - #define MSG_M109_INVALID_EXTRUDER "M109 Extrusor Invalid " - #define MSG_HEATING "Escalfant Nozzle..." - #define MSG_HEATING_COMPLETE "Nozzle calent." - #define MSG_BED_HEATING "Escalfant llit..." - #define MSG_BED_DONE "Llit calent." - #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" - #define MSG_COUNT_X " Compta X:" - #define MSG_ERR_KILLED "¡¡Impressora Parada per kill()!!" - #define MSG_ERR_STOPPED "¡Impressora parada per errors. Repara l'error i utilitza M999 per reiniciar!. (Hi ha un reset de temperatura, cal ajustar-la abans de continuar)" - #define MSG_RESEND "Reenviar:" - #define MSG_UNKNOWN_COMMAND "Comanda Desconeguda:\"" - #define MSG_ACTIVE_EXTRUDER "Extrusor Actiu: " - #define MSG_INVALID_EXTRUDER "Extrusor Invalid" - #define MSG_X_MIN "x_min: " - #define MSG_X_MAX "x_max: " - #define MSG_Y_MIN "y_min: " - #define MSG_Y_MAX "y_max: " - #define MSG_Z_MIN "z_min: " - #define MSG_Z_MAX "z_max: " - #define MSG_M119_REPORT "Comprovant finals de carrera." - #define MSG_ENDSTOP_HIT "Activat!" - #define MSG_ENDSTOP_OPEN "obert" - #define MSG_HOTEND_OFFSET "Hotend offsets:" - #define MSG_SD_CANT_OPEN_SUBDIR "No s'ha pogut obrir la subcarpeta." - #define MSG_SD_INIT_FAIL "Error en iniciar la SD" - #define MSG_SD_VOL_INIT_FAIL "Error al muntar el volum" - #define MSG_SD_OPENROOT_FAIL "Error en obrir la carpeta arrel" - #define MSG_SD_CARD_OK "Tarjeta SD OK" - #define MSG_SD_WORKDIR_FAIL "Error en obrir la carpeta de treball" - #define MSG_SD_OPEN_FILE_FAIL "Error en obrir, Fitxer: " - #define MSG_SD_FILE_OPENED "Fitxer obert:" - #define MSG_SD_SIZE " Mida:" - #define MSG_SD_FILE_SELECTED "Fitxer Seleccionat" - #define MSG_SD_WRITE_TO_FILE "Desant al fitxer: " - #define MSG_SD_PRINTING_BYTE "SD imprimint el byte " - #define MSG_SD_NOT_PRINTING "No s'esta imprimint amb SD" - #define MSG_SD_ERR_WRITE_TO_FILE "Error al escriure al fitxer" - #define MSG_SD_CANT_ENTER_SUBDIR "No es pot obrir la carpeta:" - #define MSG_STEPPER_TOO_HIGH "Steprate massa alt : " - #define MSG_ENDSTOPS_HIT "S'ha tocat el final de carrera: " - #define MSG_ERR_COLD_EXTRUDE_STOP " extrusio freda evitada" - #define MSG_ERR_LONG_EXTRUDE_STOP " extrusio massa llarga evitada" - #define MSG_BABYSTEPPING_X "Babystepping X" - #define MSG_BABYSTEPPING_Y "Babystepping Y" - #define MSG_BABYSTEPPING_Z "Babystepping Z" - #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Error a l'estructura dels menus" + + #define MSG_Enqueing "en cua \"" + #define MSG_POWERUP "PowerUp" + #define MSG_EXTERNAL_RESET " Reset Extern" + #define MSG_BROWNOUT_RESET " Reset per Voltatge Incorrecte" + #define MSG_WATCHDOG_RESET " Reset per Bloqueix" + #define MSG_SOFTWARE_RESET " Reset per Software" + #define MSG_AUTHOR " | Author: " + #define MSG_CONFIGURATION_VER "Ultima actualitzacio: " + #define MSG_FREE_MEMORY " Memoria lliure: " + #define MSG_PLANNER_BUFFER_BYTES " PlannerBufferBytes: " + #define MSG_OK "ok" + #define MSG_FILE_SAVED "Fitxer desat." + #define MSG_ERR_LINE_NO "El Numero de la Linia no es igual al Ultimo Numero de Linia+1, Ultima Linia:" + #define MSG_ERR_CHECKSUM_MISMATCH "el checksum no coincideix, Ultima Linia:" + #define MSG_ERR_NO_CHECKSUM "No s'ha trobat el Checksum amb el numero de linea, Ultima Linea:" + #define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No s'ha trobat Numero de Linea amb el Checksum, Ultima Linea:" + #define MSG_FILE_PRINTED "Impresio acabada" + #define MSG_BEGIN_FILE_LIST "Inici de la llista d'arxius" + #define MSG_END_FILE_LIST "Fi de la llista d'arxius" + #define MSG_M104_INVALID_EXTRUDER "M104 Extrusor Invalid " + #define MSG_M105_INVALID_EXTRUDER "M105 Extrusor Invalid " + #define MSG_M200_INVALID_EXTRUDER "M200 Extrusor Invalid " + #define MSG_M218_INVALID_EXTRUDER "M218 Extrusor Invalid " + #define MSG_M221_INVALID_EXTRUDER "M221 Extrusor Invalid " + #define MSG_ERR_NO_THERMISTORS "No hi ha termistors - sense temperatura" + #define MSG_M109_INVALID_EXTRUDER "M109 Extrusor Invalid " + #define MSG_HEATING "Escalfant..." + #define MSG_HEATING_COMPLETE "Escalfament acabat." + #define MSG_BED_HEATING "Escalfant llit." + #define MSG_BED_DONE "Llit Calent." + #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" + #define MSG_COUNT_X " Count X: " + #define MSG_ERR_KILLED "Impressora Parada per kill()!" + #define MSG_ERR_STOPPED "Impressora Parada per errors. Repara l'error i utilitza M999 per reiniciar!. (Hi ha un reset de temperatura, cal ajustarla abans de continuuar)" + #define MSG_RESEND "Reenviar: " + #define MSG_UNKNOWN_COMMAND "Comanda Desconeguda: \"" + #define MSG_ACTIVE_EXTRUDER "Extrusor Actiu: " + #define MSG_INVALID_EXTRUDER "Extrusor Invalid" + #define MSG_X_MIN "x_min: " + #define MSG_X_MAX "x_max: " + #define MSG_Y_MIN "y_min: " + #define MSG_Y_MAX "y_max: " + #define MSG_Z_MIN "z_min: " + #define MSG_Z_MAX "z_max: " + #define MSG_M119_REPORT "Comprobant finals de carrera." + #define MSG_ENDSTOP_HIT "Activat" + #define MSG_ENDSTOP_OPEN "obert" + #define MSG_HOTEND_OFFSET "Hotend offsets:" + + #define MSG_SD_CANT_OPEN_SUBDIR "No s'ha pogut obrir la carpeta" + #define MSG_SD_INIT_FAIL "Error al iniciar la SD" + #define MSG_SD_VOL_INIT_FAIL "Error al montar el volum" + #define MSG_SD_OPENROOT_FAIL "Error al obrir la carpeta arrel" + #define MSG_SD_CARD_OK "Targeta SD OK" + #define MSG_SD_WORKDIR_FAIL "Error al obrir la carpeta de treball" + #define MSG_SD_OPEN_FILE_FAIL "Error al obrir, Fitxer: " + #define MSG_SD_FILE_OPENED "Fitxer obert:" + #define MSG_SD_SIZE " Mida: " + #define MSG_SD_FILE_SELECTED "Fitxer Seleccionat" + #define MSG_SD_WRITE_TO_FILE "Desant al fitxer: " + #define MSG_SD_PRINTING_BYTE "SD imprimint el byte " + #define MSG_SD_NOT_PRINTING "No s'està imprimint amb SD" + #define MSG_SD_ERR_WRITE_TO_FILE "Error al esciure al fitxer" + #define MSG_SD_CANT_ENTER_SUBDIR "No es pot obrir la carpeta: " + + #define MSG_STEPPER_TOO_HIGH "Steprate massa alt: " + #define MSG_ENDSTOPS_HIT "S'ha tocat el final de carrera: " + #define MSG_ERR_COLD_EXTRUDE_STOP " extrusio freda evitada" + #define MSG_ERR_LONG_EXTRUDE_STOP " extrusio massa llarga evitada" + #define MSG_BABYSTEPPING_X "Babystepping X" + #define MSG_BABYSTEPPING_Y "Babystepping Y" + #define MSG_BABYSTEPPING_Z "Babystepping Z" + #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Error a l'estructura dels menus" #endif From b0093a15134c1fd28a862d7489a1fb759cf4e670 Mon Sep 17 00:00:00 2001 From: David Forrest Date: Wed, 26 Mar 2014 23:41:10 -0400 Subject: [PATCH 212/256] thermistortables.h: Add comments that table 60 uses beta=3950. --- Marlin/Configuration.h | 2 +- Marlin/thermistortables.h | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index e18c98a437..714bb3e634 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -116,7 +116,7 @@ // 9 is 100k GE Sensing AL03006-58.2K-97-G1 (4.7k pullup) // 10 is 100k RS thermistor 198-961 (4.7k pullup) // 20 is the PT100 circuit found in the Ultimainboard V2.x -// 60 is 100k Maker's Tool Works Kapton Bed Thermistor +// 60 is 100k Maker's Tool Works Kapton Bed Thermistor beta=3950 // // 1k ohm pullup tables - This is not normal, you would have to have changed out your 4.7k for 1k // (but gives greater accuracy and more stable PID) diff --git a/Marlin/thermistortables.h b/Marlin/thermistortables.h index 1d2b3ca65f..6120923f10 100644 --- a/Marlin/thermistortables.h +++ b/Marlin/thermistortables.h @@ -781,6 +781,14 @@ const short temptable_55[][2] PROGMEM = { #endif #if (THERMISTORHEATER_0 == 60) || (THERMISTORHEATER_1 == 60) || (THERMISTORHEATER_2 == 60) || (THERMISTORBED == 60) // Maker's Tool Works Kapton Bed Thermister +// ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=3950 +// r0: 100000 +// t0: 25 +// r1: 0 (parallel with rTherm) +// r2: 4700 (series with rTherm) +// beta: 3950 +// min adc: 1 at 0.0048828125 V +// max adc: 1023 at 4.9951171875 V const short temptable_60[][2] PROGMEM = { {51*OVERSAMPLENR, 272}, {61*OVERSAMPLENR, 258}, From aeaf9b9312fb1eff68ed0ecbf42aca07cb9360f1 Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Sun, 30 Mar 2014 11:34:36 -0700 Subject: [PATCH 213/256] fix bug in M200 with multiple extruders --- Marlin/Marlin_main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 9fe64119ff..d3a7862065 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -2241,8 +2241,6 @@ void process_commands() SERIAL_ECHO_START; SERIAL_ECHO(MSG_M200_INVALID_EXTRUDER); } - SERIAL_ECHOLN(tmp_extruder); - break; } volumetric_multiplier[tmp_extruder] = 1 / area; } From a65564eef6fdcefcb95470f8332e732b598ff2bd Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Sun, 30 Mar 2014 11:34:36 -0700 Subject: [PATCH 214/256] fix bug in M200 with multiple extruders --- Marlin/Marlin_main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index cc664b839e..67d7093962 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -2231,8 +2231,6 @@ void process_commands() SERIAL_ECHO_START; SERIAL_ECHO(MSG_M200_INVALID_EXTRUDER); } - SERIAL_ECHOLN(tmp_extruder); - break; } volumetric_multiplier[tmp_extruder] = 1 / area; } From 875950831991f17f8d3ad0fb96ef63d77d5f03f9 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 1 Apr 2014 09:26:19 +0800 Subject: [PATCH 215/256] fix bug for dual extruders not working some guy find that marlin not working good for dual extruders delta . when type T0 or T1 to active extruder and E0 or E1 move causing XYZ motion . so i locales the bugs and fix it , I have dry run the fix. --- Marlin/Marlin_main.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index d7397ac0c7..66ce22410b 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -3051,7 +3051,16 @@ void process_commands() // Set the new active extruder and position active_extruder = tmp_extruder; #endif //else DUAL_X_CARRIAGE +#ifdef DELTA + + calculate_delta(current_position); // change cartesian kinematic to delta kinematic; + //sent position to plan_set_position(); + plan_set_position(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS],current_position[E_AXIS]); + +#else plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + +#endif // Move to the old position if 'F' was in the parameters if(make_move && Stopped == false) { prepare_move(); From dfb98101e4c6481c4a7f82d7ebf58d54882fa84a Mon Sep 17 00:00:00 2001 From: nothinman Date: Thu, 3 Apr 2014 18:05:48 +0100 Subject: [PATCH 216/256] Change CONTROLLERFAN_PIN for board 35 to -1, as it would conflict with board's 33 extruder pin, causing burnout (it's the same board, just different number of fans/extruders, therefore should be pin-compatible) --- Marlin/pins.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/pins.h b/Marlin/pins.h index 9976d431d0..0811179858 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -502,7 +502,7 @@ #endif #if MOTHERBOARD == 35 - #define CONTROLLERFAN_PIN 10 //Pin used for the fan to cool controller + #define CONTROLLERFAN_PIN -1 //Pin used for the fan to cool controller #endif #define PS_ON_PIN 12 From dca9790f421143790c84b91133aab4c695498e25 Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Fri, 4 Apr 2014 10:13:44 -0700 Subject: [PATCH 217/256] Update Readme descriptions for M200, M207 and M208 --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e85be7c3eb..551c53075c 100644 --- a/README.md +++ b/README.md @@ -204,15 +204,15 @@ M Codes * M140 - Set bed target temp * M190 - Sxxx Wait for bed current temp to reach target temp. Waits only when heating * Rxxx Wait for bed current temp to reach target temp. Waits when heating and cooling -* M200 - Set filament diameter +* M200 D- set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters). * M201 - Set max acceleration in units/s^2 for print moves (M201 X1000 Y1000) * M202 - Set max acceleration in units/s^2 for travel moves (M202 X1000 Y1000) Unused in Marlin!! * M203 - Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in mm/sec * M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) im mm/sec^2 also sets minimum segment time in ms (B20000) to prevent buffer underruns and M20 minimum feedrate * M205 - advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk, E=maximum E jerk * M206 - set additional homeing offset -* M207 - set retract length S[positive mm] F[feedrate mm/sec] Z[additional zlift/hop] -* M208 - set recover=unretract length S[positive mm surplus to the M207 S*] F[feedrate mm/sec] +* M207 - set retract length S[positive mm] F[feedrate mm/min] Z[additional zlift/hop], stays in mm regardless of M200 setting +* M208 - set recover=unretract length S[positive mm surplus to the M207 S*] F[feedrate mm/min] * M209 - S<1=true/0=false> enable automatic retract detect if the slicer did not support G10/11: every normal extrude-only move will be classified as retract depending on the direction. * M218 - set hotend offset (in mm): T X Y * M220 S- set speed factor override percentage From b0aeac117f301223903bc90c391000f43c690e96 Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Wed, 19 Feb 2014 14:59:10 -0800 Subject: [PATCH 218/256] Adjustable Z probe offset, via custom M-code --- Marlin/Configuration.h | 9 +++++++++ Marlin/Marlin_main.cpp | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 714bb3e634..a98e2d9fc1 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -459,6 +459,15 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of //=============================Additional Features=========================== //=========================================================================== +// Custom M code points +#define CUSTOM_M_CODES +#ifdef CUSTOM_M_CODES + #define CUSTOM_M_CODE_SET_Z_PROBE_OFFSET 851 + #define Z_PROBE_OFFSET_RANGE_MIN -2 + #define Z_PROBE_OFFSET_RANGE_MAX 0 +#endif + + // EEPROM // The microcontroller can store settings in the EEPROM, e.g. max velocity... // M500 - stores parameters in EEPROM diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index b45ca1a90d..f3cb293001 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -2719,6 +2719,42 @@ void process_commands() } break; #endif + + #ifdef CUSTOM_M_CODE_SET_Z_PROBE_OFFSET + case CUSTOM_M_CODE_SET_Z_PROBE_OFFSET: + { + float value; + if (code_seen('Z')) + { + value = code_value(); + if ((Z_PROBE_OFFSET_RANGE_MIN <= value) && (value <= Z_PROBE_OFFSET_RANGE_MAX)) + { + zprobe_zoffset = -value; // compare w/ line 278 of ConfigurationStore.cpp + SERIAL_ECHO_START; + SERIAL_ECHOLNPGM("Z probe offset has been set"); + SERIAL_PROTOCOLLN(""); + } + else + { + SERIAL_ECHO_START; + SERIAL_ECHOPGM("Invalid z-probe value. Must be between "); + SERIAL_ECHO(Z_PROBE_OFFSET_RANGE_MIN); + SERIAL_ECHOPGM(" and "); + SERIAL_ECHO(Z_PROBE_OFFSET_RANGE_MAX); + SERIAL_PROTOCOLLN(""); + } + } + else + { + SERIAL_ECHO_START; + SERIAL_ECHOLNPGM("Z probe offset is currently "); + SERIAL_ECHO(-zprobe_zoffset); + SERIAL_PROTOCOLLN(""); + } + break; + } + #endif // CUSTOM_M_CODE_SET_Z_PROBE_OFFSET + #ifdef FILAMENTCHANGEENABLE case 600: //Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal] { From d3f305332a37fc830cbfd9d8bb9a09c793b526e0 Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Mon, 24 Feb 2014 10:06:12 -0800 Subject: [PATCH 219/256] Allowable range now includes default value --- Marlin/Configuration.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index a98e2d9fc1..32ce5b7dbb 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -463,8 +463,8 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #define CUSTOM_M_CODES #ifdef CUSTOM_M_CODES #define CUSTOM_M_CODE_SET_Z_PROBE_OFFSET 851 - #define Z_PROBE_OFFSET_RANGE_MIN -2 - #define Z_PROBE_OFFSET_RANGE_MAX 0 + #define Z_PROBE_OFFSET_RANGE_MIN -15 + #define Z_PROBE_OFFSET_RANGE_MAX -5 #endif From 27a7cf9fcff436f1d30451c26db1fe4f8c442c36 Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Sun, 6 Apr 2014 19:43:46 -0500 Subject: [PATCH 220/256] use existing strings --- Marlin/Marlin_main.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index f3cb293001..618e906b88 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -2731,15 +2731,16 @@ void process_commands() { zprobe_zoffset = -value; // compare w/ line 278 of ConfigurationStore.cpp SERIAL_ECHO_START; - SERIAL_ECHOLNPGM("Z probe offset has been set"); + SERIAL_ECHOLNPGM(MSG_ZPROBE_ZOFFSET " " MSG_OK); SERIAL_PROTOCOLLN(""); } else { SERIAL_ECHO_START; - SERIAL_ECHOPGM("Invalid z-probe value. Must be between "); + SERIAL_ECHOPGM(MSG_ZPROBE_ZOFFSET); + SERIAL_ECHOPGM(MSG_Z_MIN); SERIAL_ECHO(Z_PROBE_OFFSET_RANGE_MIN); - SERIAL_ECHOPGM(" and "); + SERIAL_ECHOPGM(MSG_Z_MAX); SERIAL_ECHO(Z_PROBE_OFFSET_RANGE_MAX); SERIAL_PROTOCOLLN(""); } @@ -2747,7 +2748,7 @@ void process_commands() else { SERIAL_ECHO_START; - SERIAL_ECHOLNPGM("Z probe offset is currently "); + SERIAL_ECHOLNPGM(MSG_ZPROBE_ZOFFSET " : "); SERIAL_ECHO(-zprobe_zoffset); SERIAL_PROTOCOLLN(""); } From 3161740df9b952f627fd9ad1e132e7eaf723fc0e Mon Sep 17 00:00:00 2001 From: Nutz95 Date: Sun, 13 Apr 2014 17:03:20 +0200 Subject: [PATCH 221/256] This table is made for thermistor 3950 (can be found on ebay for cheap) it's caracteristics are : MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit R25℃ ;100KΩ±1% B Value(R25/50℃):3990K 1% Dissipation Factor(mW/℃):1.1~1.6 In still Air Thermal Time Constant(S):10~17 In Still Air Operating temperature range: (-50~+260°C) Dimension: 1.8mm Dia X4.1mm Lead Length :30mm This table was found on the following blogs: http://cae2100.wordpress.com/2014/03/08/beta3950-thermistor-table-for-marlin/ and http://microfabricator.com/articles/view/id/531ad7e59aad9d3131000000/beta-3950-thermistor-table-for-marlin --- Marlin/Configuration.h | 1 + Marlin/thermistortables.h | 198 ++++++++++++++++++++++++-------------- 2 files changed, 127 insertions(+), 72 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 32ce5b7dbb..f169f8e419 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -115,6 +115,7 @@ // 8 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup) // 9 is 100k GE Sensing AL03006-58.2K-97-G1 (4.7k pullup) // 10 is 100k RS thermistor 198-961 (4.7k pullup) +// 11 is 100k beta 3950 1% thermistor (4.7k pullup) // 20 is the PT100 circuit found in the Ultimainboard V2.x // 60 is 100k Maker's Tool Works Kapton Bed Thermistor beta=3950 // diff --git a/Marlin/thermistortables.h b/Marlin/thermistortables.h index 6120923f10..db8359ef79 100644 --- a/Marlin/thermistortables.h +++ b/Marlin/thermistortables.h @@ -563,78 +563,132 @@ const short temptable_10[][2] PROGMEM = { {1016*OVERSAMPLENR, 0} }; #endif - -#if (THERMISTORHEATER_0 == 20) || (THERMISTORHEATER_1 == 20) || (THERMISTORHEATER_2 == 20) || (THERMISTORBED == 20) // PT100 with INA826 amp on Ultimaker v2.0 electronics -/* The PT100 in the Ultimaker v2.0 electronics has a high sample value for a high temperature. -This does not match the normal thermistor behaviour so we need to set the following defines */ -#if (THERMISTORHEATER_0 == 20) -# define HEATER_0_RAW_HI_TEMP 16383 -# define HEATER_0_RAW_LO_TEMP 0 -#endif -#if (THERMISTORHEATER_1 == 20) -# define HEATER_1_RAW_HI_TEMP 16383 -# define HEATER_1_RAW_LO_TEMP 0 -#endif -#if (THERMISTORHEATER_2 == 20) -# define HEATER_2_RAW_HI_TEMP 16383 -# define HEATER_2_RAW_LO_TEMP 0 -#endif -#if (THERMISTORBED == 20) -# define HEATER_BED_RAW_HI_TEMP 16383 -# define HEATER_BED_RAW_LO_TEMP 0 -#endif -const short temptable_20[][2] PROGMEM = { -{ 0*OVERSAMPLENR , 0 }, -{ 227*OVERSAMPLENR , 1 }, -{ 236*OVERSAMPLENR , 10 }, -{ 245*OVERSAMPLENR , 20 }, -{ 253*OVERSAMPLENR , 30 }, -{ 262*OVERSAMPLENR , 40 }, -{ 270*OVERSAMPLENR , 50 }, -{ 279*OVERSAMPLENR , 60 }, -{ 287*OVERSAMPLENR , 70 }, -{ 295*OVERSAMPLENR , 80 }, -{ 304*OVERSAMPLENR , 90 }, -{ 312*OVERSAMPLENR , 100 }, -{ 320*OVERSAMPLENR , 110 }, -{ 329*OVERSAMPLENR , 120 }, -{ 337*OVERSAMPLENR , 130 }, -{ 345*OVERSAMPLENR , 140 }, -{ 353*OVERSAMPLENR , 150 }, -{ 361*OVERSAMPLENR , 160 }, -{ 369*OVERSAMPLENR , 170 }, -{ 377*OVERSAMPLENR , 180 }, -{ 385*OVERSAMPLENR , 190 }, -{ 393*OVERSAMPLENR , 200 }, -{ 401*OVERSAMPLENR , 210 }, -{ 409*OVERSAMPLENR , 220 }, -{ 417*OVERSAMPLENR , 230 }, -{ 424*OVERSAMPLENR , 240 }, -{ 432*OVERSAMPLENR , 250 }, -{ 440*OVERSAMPLENR , 260 }, -{ 447*OVERSAMPLENR , 270 }, -{ 455*OVERSAMPLENR , 280 }, -{ 463*OVERSAMPLENR , 290 }, -{ 470*OVERSAMPLENR , 300 }, -{ 478*OVERSAMPLENR , 310 }, -{ 485*OVERSAMPLENR , 320 }, -{ 493*OVERSAMPLENR , 330 }, -{ 500*OVERSAMPLENR , 340 }, -{ 507*OVERSAMPLENR , 350 }, -{ 515*OVERSAMPLENR , 360 }, -{ 522*OVERSAMPLENR , 370 }, -{ 529*OVERSAMPLENR , 380 }, -{ 537*OVERSAMPLENR , 390 }, -{ 544*OVERSAMPLENR , 400 }, -{ 614*OVERSAMPLENR , 500 }, -{ 681*OVERSAMPLENR , 600 }, -{ 744*OVERSAMPLENR , 700 }, -{ 805*OVERSAMPLENR , 800 }, -{ 862*OVERSAMPLENR , 900 }, -{ 917*OVERSAMPLENR , 1000 }, -{ 968*OVERSAMPLENR , 1100 } -}; -#endif +#if (THERMISTORHEATER_0 == 11) || (THERMISTORHEATER_1 == 11) || (THERMISTORHEATER_2 == 11) || (THERMISTORBED == 11) // QU-BD silicone bed QWG-104F-3950 thermistor +const short temptable_8[][2] PROGMEM = { + {1*OVERSAMPLENR, 938}, + {31*OVERSAMPLENR, 314}, + {41*OVERSAMPLENR, 290}, + {51*OVERSAMPLENR, 272}, + {61*OVERSAMPLENR, 258}, + {71*OVERSAMPLENR, 247}, + {81*OVERSAMPLENR, 237}, + {91*OVERSAMPLENR, 229}, + {101*OVERSAMPLENR, 221}, + {111*OVERSAMPLENR, 215}, + {121*OVERSAMPLENR, 209}, + {131*OVERSAMPLENR, 204}, + {141*OVERSAMPLENR, 199}, + {151*OVERSAMPLENR, 195}, + {161*OVERSAMPLENR, 190}, + {171*OVERSAMPLENR, 187}, + {181*OVERSAMPLENR, 183}, + {191*OVERSAMPLENR, 179}, + {201*OVERSAMPLENR, 176}, + {221*OVERSAMPLENR, 170}, + {241*OVERSAMPLENR, 165}, + {261*OVERSAMPLENR, 160}, + {281*OVERSAMPLENR, 155}, + {301*OVERSAMPLENR, 150}, + {331*OVERSAMPLENR, 144}, + {361*OVERSAMPLENR, 139}, + {391*OVERSAMPLENR, 133}, + {421*OVERSAMPLENR, 128}, + {451*OVERSAMPLENR, 123}, + {491*OVERSAMPLENR, 117}, + {531*OVERSAMPLENR, 111}, + {571*OVERSAMPLENR, 105}, + {611*OVERSAMPLENR, 100}, + {641*OVERSAMPLENR, 95}, + {681*OVERSAMPLENR, 90}, + {711*OVERSAMPLENR, 85}, + {751*OVERSAMPLENR, 79}, + {791*OVERSAMPLENR, 72}, + {811*OVERSAMPLENR, 69}, + {831*OVERSAMPLENR, 65}, + {871*OVERSAMPLENR, 57}, + {881*OVERSAMPLENR, 55}, + {901*OVERSAMPLENR, 51}, + {921*OVERSAMPLENR, 45}, + {941*OVERSAMPLENR, 39}, + {971*OVERSAMPLENR, 28}, + {981*OVERSAMPLENR, 23}, + {991*OVERSAMPLENR, 17}, + {1001*OVERSAMPLENR, 9}, + {1021*OVERSAMPLENR, -27} +}; +#endif + +#if (THERMISTORHEATER_0 == 20) || (THERMISTORHEATER_1 == 20) || (THERMISTORHEATER_2 == 20) || (THERMISTORBED == 20) // PT100 with INA826 amp on Ultimaker v2.0 electronics +/* The PT100 in the Ultimaker v2.0 electronics has a high sample value for a high temperature. +This does not match the normal thermistor behaviour so we need to set the following defines */ +#if (THERMISTORHEATER_0 == 20) +# define HEATER_0_RAW_HI_TEMP 16383 +# define HEATER_0_RAW_LO_TEMP 0 +#endif +#if (THERMISTORHEATER_1 == 20) +# define HEATER_1_RAW_HI_TEMP 16383 +# define HEATER_1_RAW_LO_TEMP 0 +#endif +#if (THERMISTORHEATER_2 == 20) +# define HEATER_2_RAW_HI_TEMP 16383 +# define HEATER_2_RAW_LO_TEMP 0 +#endif +#if (THERMISTORBED == 20) +# define HEATER_BED_RAW_HI_TEMP 16383 +# define HEATER_BED_RAW_LO_TEMP 0 +#endif +const short temptable_20[][2] PROGMEM = { +{ 0*OVERSAMPLENR , 0 }, +{ 227*OVERSAMPLENR , 1 }, +{ 236*OVERSAMPLENR , 10 }, +{ 245*OVERSAMPLENR , 20 }, +{ 253*OVERSAMPLENR , 30 }, +{ 262*OVERSAMPLENR , 40 }, +{ 270*OVERSAMPLENR , 50 }, +{ 279*OVERSAMPLENR , 60 }, +{ 287*OVERSAMPLENR , 70 }, +{ 295*OVERSAMPLENR , 80 }, +{ 304*OVERSAMPLENR , 90 }, +{ 312*OVERSAMPLENR , 100 }, +{ 320*OVERSAMPLENR , 110 }, +{ 329*OVERSAMPLENR , 120 }, +{ 337*OVERSAMPLENR , 130 }, +{ 345*OVERSAMPLENR , 140 }, +{ 353*OVERSAMPLENR , 150 }, +{ 361*OVERSAMPLENR , 160 }, +{ 369*OVERSAMPLENR , 170 }, +{ 377*OVERSAMPLENR , 180 }, +{ 385*OVERSAMPLENR , 190 }, +{ 393*OVERSAMPLENR , 200 }, +{ 401*OVERSAMPLENR , 210 }, +{ 409*OVERSAMPLENR , 220 }, +{ 417*OVERSAMPLENR , 230 }, +{ 424*OVERSAMPLENR , 240 }, +{ 432*OVERSAMPLENR , 250 }, +{ 440*OVERSAMPLENR , 260 }, +{ 447*OVERSAMPLENR , 270 }, +{ 455*OVERSAMPLENR , 280 }, +{ 463*OVERSAMPLENR , 290 }, +{ 470*OVERSAMPLENR , 300 }, +{ 478*OVERSAMPLENR , 310 }, +{ 485*OVERSAMPLENR , 320 }, +{ 493*OVERSAMPLENR , 330 }, +{ 500*OVERSAMPLENR , 340 }, +{ 507*OVERSAMPLENR , 350 }, +{ 515*OVERSAMPLENR , 360 }, +{ 522*OVERSAMPLENR , 370 }, +{ 529*OVERSAMPLENR , 380 }, +{ 537*OVERSAMPLENR , 390 }, +{ 544*OVERSAMPLENR , 400 }, +{ 614*OVERSAMPLENR , 500 }, +{ 681*OVERSAMPLENR , 600 }, +{ 744*OVERSAMPLENR , 700 }, +{ 805*OVERSAMPLENR , 800 }, +{ 862*OVERSAMPLENR , 900 }, +{ 917*OVERSAMPLENR , 1000 }, +{ 968*OVERSAMPLENR , 1100 } +}; +#endif #if (THERMISTORHEATER_0 == 51) || (THERMISTORHEATER_1 == 51) || (THERMISTORHEATER_2 == 51) || (THERMISTORBED == 51) // 100k EPCOS (WITH 1kohm RESISTOR FOR PULLUP, R9 ON SANGUINOLOLU! NOT FOR 4.7kohm PULLUP! THIS IS NOT NORMAL!) From ed6f4a71c5fc26dbcee7da77ae75fa357a2b71c5 Mon Sep 17 00:00:00 2001 From: Nutz95 Date: Sun, 13 Apr 2014 18:00:55 +0200 Subject: [PATCH 222/256] fix wrong temptable index --- Marlin/thermistortables.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Marlin/thermistortables.h b/Marlin/thermistortables.h index db8359ef79..0a80e77b6a 100644 --- a/Marlin/thermistortables.h +++ b/Marlin/thermistortables.h @@ -563,8 +563,11 @@ const short temptable_10[][2] PROGMEM = { {1016*OVERSAMPLENR, 0} }; #endif -#if (THERMISTORHEATER_0 == 11) || (THERMISTORHEATER_1 == 11) || (THERMISTORHEATER_2 == 11) || (THERMISTORBED == 11) // QU-BD silicone bed QWG-104F-3950 thermistor -const short temptable_8[][2] PROGMEM = { + +#if (THERMISTORHEATER_0 == 11) || (THERMISTORHEATER_1 == 11) || (THERMISTORHEATER_2 == 11) || (THERMISTORBED == 11) +// QU-BD silicone bed QWG-104F-3950 thermistor + +const short temptable_11[][2] PROGMEM = { {1*OVERSAMPLENR, 938}, {31*OVERSAMPLENR, 314}, {41*OVERSAMPLENR, 290}, From e5b70237c7777429db95f49071855dda095e284f Mon Sep 17 00:00:00 2001 From: koldo artola Date: Sun, 13 Apr 2014 22:19:38 +0200 Subject: [PATCH 223/256] Added new language (Basque-Euskera) Added: * new language (Basque-Euskera) * some minor corrections for Spanish * added 2 new constants for every language (required for a minor change I am preparing to ultralcd.cpp) --- Marlin/language.h | 240 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 231 insertions(+), 9 deletions(-) diff --git a/Marlin/language.h b/Marlin/language.h index 3439335aef..6c408551a2 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -19,6 +19,7 @@ // 10 Aragonese // 11 Dutch // 12 Catalan +// 13 Basque-Euskera #ifndef LANGUAGE_CHOICE #define LANGUAGE_CHOICE 1 // Pick your language from the list above @@ -101,6 +102,8 @@ #define MSG_MOVE_Y "Move Y" #define MSG_MOVE_Z "Move Z" #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_E1 "Extruder2" + #define MSG_MOVE_E2 "Extruder3" #define MSG_MOVE_01MM "Move 0.1mm" #define MSG_MOVE_1MM "Move 1mm" #define MSG_MOVE_10MM "Move 10mm" @@ -297,6 +300,8 @@ #define MSG_MOVE_Y "Przesun w Y" #define MSG_MOVE_Z "Przesun w Z" #define MSG_MOVE_E "Ekstruzja (os E)" + #define MSG_MOVE_E1 "Extruder2" + #define MSG_MOVE_E2 "Extruder3" #define MSG_MOVE_01MM "Przesuwaj co .1mm" #define MSG_MOVE_1MM "Przesuwaj co 1mm" #define MSG_MOVE_10MM "Przesuwaj co 10mm" @@ -498,6 +503,8 @@ #define MSG_MOVE_Y "Move Y" #define MSG_MOVE_Z "Move Z" #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_E1 "Extruder2" + #define MSG_MOVE_E2 "Extruder3" #define MSG_MOVE_01MM "Move 0.1mm" #define MSG_MOVE_1MM "Move 1mm" #define MSG_MOVE_10MM "Move 10mm" @@ -696,6 +703,8 @@ #define MSG_MOVE_Y "Y bewegen" #define MSG_MOVE_Z "Z bewegen" #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_E1 "Extruder2" + #define MSG_MOVE_E2 "Extruder3" #define MSG_MOVE_01MM "0.1mm bewegen" #define MSG_MOVE_1MM "1mm bewegen" #define MSG_MOVE_10MM "10mm bewegen" @@ -891,13 +900,15 @@ #define MSG_EXTRUDE "Extruir" #define MSG_RETRACT "Retraer" #define MSG_MOVE_AXIS "Mover ejes" - #define MSG_MOVE_X "Move X" - #define MSG_MOVE_Y "Move Y" - #define MSG_MOVE_Z "Move Z" - #define MSG_MOVE_E "Extruder" - #define MSG_MOVE_01MM "Move 0.1mm" - #define MSG_MOVE_1MM "Move 1mm" - #define MSG_MOVE_10MM "Move 10mm" + #define MSG_MOVE_X "Mover X" + #define MSG_MOVE_Y "Mover Y" + #define MSG_MOVE_Z "Mover Z" + #define MSG_MOVE_E "Extrusor" + #define MSG_MOVE_E1 "Extrusor2" + #define MSG_MOVE_E2 "Extrusor3" + #define MSG_MOVE_01MM "Mover 0.1mm" + #define MSG_MOVE_1MM "Mover 1mm" + #define MSG_MOVE_10MM "Mover 10mm" #define MSG_SPEED "Velocidad" #define MSG_NOZZLE "Nozzle" #define MSG_NOZZLE1 "Nozzle2" @@ -963,7 +974,7 @@ #define MSG_CONTROL_RETRACT_RECOVER "DesRet +mm" #define MSG_CONTROL_RETRACT_RECOVERF "DesRet V" #define MSG_AUTORETRACT "AutoRetr." - #define MSG_FILAMENTCHANGE "Change filament" + #define MSG_FILAMENTCHANGE "Cambiar filamento" #define MSG_INIT_SDCARD "Iniciando tarjeta" #define MSG_CNG_SDCARD "Cambiar tarjeta" #define MSG_RECTRACT_WIDE "Retraer" @@ -1019,7 +1030,7 @@ #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" #define MSG_COUNT_X " Cuenta X:" #define MSG_ERR_KILLED "¡¡Impresora Parada con kill()!!" - #define MSG_ERR_STOPPED "¡Impresora parada por errores. Arregle el error y use M999 Para reiniciar!. (La temperatura se reestablece. Ajustela antes de continuar)" + #define MSG_ERR_STOPPED "¡Impresora parada por errores. Arregle el error y use M999 Para reiniciar!. (La temperatura se reestablece. Ajustela despues de continuar)" #define MSG_RESEND "Reenviar:" #define MSG_UNKNOWN_COMMAND "Comando Desconocido:\"" #define MSG_ACTIVE_EXTRUDER "Extrusor Activo: " @@ -1099,6 +1110,8 @@ #define MSG_MOVE_Y "Move Y" #define MSG_MOVE_Z "Move Z" #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_E1 "Extruder2" + #define MSG_MOVE_E2 "Extruder3" #define MSG_MOVE_01MM "Move 0.1mm" #define MSG_MOVE_1MM "Move 1mm" #define MSG_MOVE_10MM "Move 10mm" @@ -1294,6 +1307,8 @@ #define MSG_MOVE_Y "Move Y" #define MSG_MOVE_Z "Move Z" #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_E1 "Extruder2" + #define MSG_MOVE_E2 "Extruder3" #define MSG_MOVE_01MM "Move 0.1mm" #define MSG_MOVE_1MM "Move 1mm" #define MSG_MOVE_10MM "Move 10mm" @@ -1493,6 +1508,8 @@ #define MSG_MOVE_Y "Move Y" #define MSG_MOVE_Z "Move Z" #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_E1 "Extruder2" + #define MSG_MOVE_E2 "Extruder3" #define MSG_MOVE_01MM "Move 0.1mm" #define MSG_MOVE_1MM "Move 1mm" #define MSG_MOVE_10MM "Move 10mm" @@ -1695,6 +1712,8 @@ #define MSG_MOVE_Y "Move Y" #define MSG_MOVE_Z "Move Z" #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_E1 "Extruder2" + #define MSG_MOVE_E2 "Extruder3" #define MSG_MOVE_01MM "Move 0.1mm" #define MSG_MOVE_1MM "Move 1mm" #define MSG_MOVE_10MM "Move 10mm" @@ -1892,6 +1911,8 @@ #define MSG_MOVE_Y "Move Y" #define MSG_MOVE_Z "Move Z" #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_E1 "Extruder2" + #define MSG_MOVE_E2 "Extruder3" #define MSG_MOVE_01MM "Move 0.1mm" #define MSG_MOVE_1MM "Move 1mm" #define MSG_MOVE_10MM "Move 10mm" @@ -2095,6 +2116,8 @@ #define MSG_MOVE_Y "Verplaats Y" #define MSG_MOVE_Z "Verplaats Z" #define MSG_MOVE_E "Extruder" + #define MSG_MOVE_E1 "Extruder2" + #define MSG_MOVE_E2 "Extruder3" #define MSG_MOVE_01MM "Verplaats 0.1mm" #define MSG_MOVE_1MM "Verplaats 1mm" #define MSG_MOVE_10MM "Verplaats 10mm" @@ -2292,6 +2315,8 @@ #define MSG_MOVE_Y "Moure Y" #define MSG_MOVE_Z "Moure Z" #define MSG_MOVE_E "Extrusor" + #define MSG_MOVE_E1 "Extruder2" + #define MSG_MOVE_E2 "Extruder3" #define MSG_MOVE_01MM "Moure 0.1mm" #define MSG_MOVE_1MM "Moure 1mm" #define MSG_MOVE_10MM "Moure 10mm" @@ -2450,5 +2475,202 @@ #endif +//Basque-Euskera +#if LANGUAGE_CHOICE == 13 + +// LCD Menu Messages +// Please note these are limited to 17 characters! + + #define WELCOME_MSG MACHINE_NAME " prest." + #define MSG_SD_INSERTED "Txartela sartuta" + #define MSG_SD_REMOVED "Txartela kenduta" + #define MSG_MAIN "Menu nagusia" + #define MSG_AUTOSTART "Auto hasiera" + #define MSG_DISABLE_STEPPERS "Itzali motoreak" + #define MSG_AUTO_HOME "Hasierara joan" + #define MSG_SET_ORIGIN "Hasiera ipini" + #define MSG_PREHEAT_PLA "Aurreberotu PLA" + #define MSG_PREHEAT_PLA0 "Aurreberotu PLA1" + #define MSG_PREHEAT_PLA1 "Aurreberotu PLA2" + #define MSG_PREHEAT_PLA2 "Aurreberotu PLA3" + #define MSG_PREHEAT_PLA012 "Berotu PLA Guztia" + #define MSG_PREHEAT_PLA_BEDONLY "Berotu PLA Ohea" + #define MSG_PREHEAT_PLA_SETTINGS "Berotu PLA Konfig" + #define MSG_PREHEAT_ABS "Aurreberotu ABS" + #define MSG_PREHEAT_ABS0 "Aurreberotu ABS 1" + #define MSG_PREHEAT_ABS1 "Aurreberotu ABS 2" + #define MSG_PREHEAT_ABS2 "Aurreberotu ABS 3" + #define MSG_PREHEAT_ABS012 "Berotu ABS Guztia" + #define MSG_PREHEAT_ABS_BEDONLY "Berotu ABS Ohea" + #define MSG_PREHEAT_ABS_SETTINGS "Berotu ABS Konfig" + #define MSG_COOLDOWN "Hoztu" + #define MSG_SWITCH_PS_ON "Energia piztu" + #define MSG_SWITCH_PS_OFF "Energia itzali" + #define MSG_EXTRUDE "Estruitu" + #define MSG_RETRACT "Atzera eragin" + #define MSG_MOVE_AXIS "Ardatzak mugitu" + #define MSG_MOVE_X "Mugitu X" + #define MSG_MOVE_Y "Mugitu Y" + #define MSG_MOVE_Z "Mugitu Z" + #define MSG_MOVE_E "Estrusorea" + #define MSG_MOVE_E1 "Estrusorea2" + #define MSG_MOVE_E2 "Estrusorea3" + #define MSG_MOVE_01MM "Mugitu 0.1mm" + #define MSG_MOVE_1MM "Mugitu 1mm" + #define MSG_MOVE_10MM "Mugitu 10mm" + #define MSG_SPEED "Abiadura" + #define MSG_NOZZLE "Pita" + #define MSG_NOZZLE1 "Pita2" + #define MSG_NOZZLE2 "Pita3" + #define MSG_BED "Ohea" + #define MSG_FAN_SPEED "Haizagailua" + #define MSG_FLOW "Fluxua" + #define MSG_FLOW0 "Fluxua 0" + #define MSG_FLOW1 "Fluxua 1" + #define MSG_FLOW2 "Fluxua 2" + #define MSG_CONTROL "Kontrola" + #define MSG_MIN " \002 Min" + #define MSG_MAX " \002 Max" + #define MSG_FACTOR " \002 Faktorea" + #define MSG_AUTOTEMP "Auto tenperatura" + #define MSG_ON "On " + #define MSG_OFF "Off" + #define MSG_PID_P "PID-P" + #define MSG_PID_I "PID-I" + #define MSG_PID_D "PID-D" + #define MSG_PID_C "PID-C" + #define MSG_ACC "Azelerazioa" + #define MSG_VXY_JERK "Vxy-astindua" + #define MSG_VZ_JERK "Vz-astindua" + #define MSG_VE_JERK "Ve-astindua" + #define MSG_VMAX "Vmax " + #define MSG_X "x" + #define MSG_Y "y" + #define MSG_Z "z" + #define MSG_E "e" + #define MSG_VMIN "Vmin" + #define MSG_VTRAV_MIN "VTrav min" + #define MSG_AMAX "Amax " + #define MSG_A_RETRACT "A-retrakt" + #define MSG_XSTEPS "X pausoak/mm" + #define MSG_YSTEPS "Y pausoak/mm" + #define MSG_ZSTEPS "Z pausoak/mm" + #define MSG_ESTEPS "E pausoak/mm" + #define MSG_RECTRACT "Atzera eragin" + #define MSG_TEMPERATURE "Tenperatura" + #define MSG_MOTION "Mugimendua" + #define MSG_CONTRAST "LCD kontrastea" + #define MSG_STORE_EPROM "Gorde memoria" + #define MSG_LOAD_EPROM "Kargatu memoria" + #define MSG_RESTORE_FAILSAFE "Larri. berriz." + #define MSG_REFRESH "Berriz kargatu" + #define MSG_WATCH "Pantaila info" + #define MSG_PREPARE "Prestatu" + #define MSG_TUNE "Doitu" + #define MSG_PAUSE_PRINT "Pausatu inprimak." + #define MSG_RESUME_PRINT "Jarraitu inprima." + #define MSG_STOP_PRINT "Gelditu inprima." + #define MSG_CARD_MENU "SD-tik inprimatu" + #define MSG_NO_CARD "Ez dago txartelik" + #define MSG_DWELL "Lo egin..." + #define MSG_USERWAIT "Aginduak zain..." + #define MSG_RESUMING "Jarraitzen inpri." + #define MSG_NO_MOVE "Mugimendu gabe" + #define MSG_KILLED "LARRIALDI GELDIA" + #define MSG_STOPPED "GELDITUTA. " + #define MSG_CONTROL_RETRACT "Atzera egin mm" + #define MSG_CONTROL_RETRACTF "Atzera egin V" + #define MSG_CONTROL_RETRACT_ZLIFT "Igo mm" + #define MSG_CONTROL_RETRACT_RECOVER "Atzera egin +mm" + #define MSG_CONTROL_RETRACT_RECOVERF "Atzera egin V" + #define MSG_AUTORETRACT "Atzera egin" + #define MSG_FILAMENTCHANGE "Aldatu filament." + #define MSG_INIT_SDCARD "Hasieratu txartela" + #define MSG_CNG_SDCARD "Aldatu txartela" + #define MSG_ZPROBE_OUT "Z ohe hasiera" + #define MSG_POSITION_UNKNOWN "Posizio ezezaguna" + #define MSG_ZPROBE_ZOFFSET "Z konpentsatu" + #define MSG_BABYSTEP_X "Babystep X" + #define MSG_BABYSTEP_Y "Babystep Y" + #define MSG_BABYSTEP_Z "Babystep Z" + #define MSG_ENDSTOP_ABORT "Endstop deuseztat" + +// Serial Console Messages + + #define MSG_Enqueing "Zerrendan \"" + #define MSG_POWERUP "Pizketa" + #define MSG_EXTERNAL_RESET " Kanpoko Reset" + #define MSG_BROWNOUT_RESET " Tentsio Okerra Reset" + #define MSG_WATCHDOG_RESET " Reset Blokeoa" + #define MSG_SOFTWARE_RESET " Software Reset" + #define MSG_AUTHOR " | Egilea: " + #define MSG_CONFIGURATION_VER " Azken Aktualizazio: " + #define MSG_FREE_MEMORY " Aske Memoria: " + #define MSG_PLANNER_BUFFER_BYTES " PlannerBufferBytes: " + #define MSG_OK "ok" + #define MSG_FILE_SAVED "Gordetuta." + #define MSG_ERR_LINE_NO "Lerro zenbakia ez da azken zenbakia+1 berdina, Azken Lerroa: " + #define MSG_ERR_CHECKSUM_MISMATCH "checksum-ak ez du aldiberekotasuna, Azken Lerroa: " + #define MSG_ERR_NO_CHECKSUM "Ez da checksum-ik aurkitu lerro zenbakian, Azken Lerroa: " + #define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "Ez da lerro zenbakia aurkitu checksum-arekin, Azken Lerroa: " + #define MSG_FILE_PRINTED "Inprimaketa bukatua" + #define MSG_BEGIN_FILE_LIST "Hasi artxibo zerrenda" + #define MSG_END_FILE_LIST "Amaitu artxibo zerrenda" + #define MSG_M104_INVALID_EXTRUDER "M104 Balio gabeko Estrusorea " + #define MSG_M105_INVALID_EXTRUDER "M105 Balio gabeko Estrusorea " + #define MSG_M200_INVALID_EXTRUDER "M200 Balio gabeko Estrusorea " + #define MSG_M218_INVALID_EXTRUDER "M218 Balio gabeko Estrusorea " + #define MSG_M221_INVALID_EXTRUDER "M221 Balio gabeko Estrusorea " + #define MSG_ERR_NO_THERMISTORS "Termistorerik ez dago - Tenperaturarik gabe" + #define MSG_M109_INVALID_EXTRUDER "M109 Balio gabeko Estrusorea " + #define MSG_HEATING "Berotzen..." + #define MSG_HEATING_COMPLETE "berotuta." + #define MSG_BED_HEATING "Ohea berotzen." + #define MSG_BED_DONE "Ohea berotuta." + #define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID "\n" + #define MSG_COUNT_X " X Kontu: " + #define MSG_ERR_KILLED "Inprimagailua geldituta. kill() called!" + #define MSG_ERR_STOPPED "Akatsen eraginez inprimagailua geldituta. Errorea konpondu eta M999 erabili berrabiarazteko. (Tenperatura galdu egin da. Berriro ipini)" + #define MSG_RESEND "Bidali berriro: " + #define MSG_UNKNOWN_COMMAND "Agindu ezezaguna: \"" + #define MSG_ACTIVE_EXTRUDER "Estrusore Aktiboa: " + #define MSG_INVALID_EXTRUDER "Balio gabeko Estrusorea" + #define MSG_X_MIN "x_min: " + #define MSG_X_MAX "x_max: " + #define MSG_Y_MIN "y_min: " + #define MSG_Y_MAX "y_max: " + #define MSG_Z_MIN "z_min: " + #define MSG_Z_MAX "z_max: " + #define MSG_M119_REPORT "Bide amaiera egiaztatzen" + #define MSG_ENDSTOP_HIT "Sakatuta" + #define MSG_ENDSTOP_OPEN "irekia" + #define MSG_HOTEND_OFFSET "Hotend offsets:" + + #define MSG_SD_CANT_OPEN_SUBDIR "Azpidirektorio ezin da ireki" + #define MSG_SD_INIT_FAIL "Akatsa txartela hasterakoan" + #define MSG_SD_VOL_INIT_FAIL "Akatsa partizioa hasterakoan" + #define MSG_SD_OPENROOT_FAIL "Akatsa direktorio nagusian" + #define MSG_SD_CARD_OK "SD card ok" + #define MSG_SD_WORKDIR_FAIL "Akatsa lan direktorioan" + #define MSG_SD_OPEN_FILE_FAIL "Akatsa irekitzean, File: " + #define MSG_SD_FILE_OPENED "Artxiboa irekita: " + #define MSG_SD_SIZE " Tamaina: " + #define MSG_SD_FILE_SELECTED "Artxiboa aukeratuta" + #define MSG_SD_WRITE_TO_FILE "Artxiboa idazten: " + #define MSG_SD_PRINTING_BYTE "SD byte idazten " + #define MSG_SD_NOT_PRINTING "Ez dago SD-tik inprimatzen" + #define MSG_SD_ERR_WRITE_TO_FILE "Akatsak artxiboa idazten" + #define MSG_SD_CANT_ENTER_SUBDIR "Azpidirektorio ezin da ireki: " + + #define MSG_STEPPER_TOO_HIGH "Motorra oso goi dago: " + #define MSG_ENDSTOPS_HIT "Bide amaiera ukitu da: " + #define MSG_ERR_COLD_EXTRUDE_STOP " estrusio hotza saihestua" + #define MSG_ERR_LONG_EXTRUDE_STOP " estrusio oso luzea saihestua" + #define MSG_BABYSTEPPING_X "Babystepping X" + #define MSG_BABYSTEPPING_Y "Babystepping Y" + #define MSG_BABYSTEPPING_Z "Babystepping Z" + #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Akatsak menu-an" + +#endif #endif // ifndef LANGUAGE_H From 27d544ac25d73013f1ba39e7905368e84e038694 Mon Sep 17 00:00:00 2001 From: whosawhatsis Date: Sat, 19 Apr 2014 17:26:43 -0700 Subject: [PATCH 224/256] Speed up QUICK_HOME feedrate for diagonal move Speed up the diagonal move while still keeping each individual axis at or below its homing feedrate. --- Marlin/Marlin_main.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 618e906b88..5e7cdf8e57 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1286,7 +1286,12 @@ void process_commands() destination[X_AXIS] = 1.5 * max_length(X_AXIS) * x_axis_home_dir;destination[Y_AXIS] = 1.5 * max_length(Y_AXIS) * home_dir(Y_AXIS); feedrate = homing_feedrate[X_AXIS]; if(homing_feedrate[Y_AXIS] max_length(Y_AXIS)) { + feedrate *= sqrt(pow(max_length(Y_AXIS) / max_length(X_AXIS), 2) + 1); + } else { + feedrate *= sqrt(pow(max_length(X_AXIS) / max_length(Y_AXIS), 2) + 1); + } plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); st_synchronize(); From e4dc80d3d36168c0f15fd31d6856d6635237d2ec Mon Sep 17 00:00:00 2001 From: MyMakibox Date: Wed, 23 Apr 2014 17:30:07 +0800 Subject: [PATCH 225/256] Update Configuration_adv.h Corrected error in AUTOTEMP instructions --- Marlin/Configuration_adv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 5fa3847c1a..245f65c9ef 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -30,7 +30,7 @@ //automatic temperature: The hot end target temperature is calculated by all the buffered lines of gcode. //The maximum buffered steps/sec of the extruder motor are called "se". -//You enter the autotemp mode by a M109 S T F +//You enter the autotemp mode by a M109 S B F // the target temperature is set to mintemp+factor*se[steps/sec] and limited by mintemp and maxtemp // you exit the value by any M109 without F* // Also, if the temperature is set to a value Date: Wed, 23 Apr 2014 17:33:26 +0800 Subject: [PATCH 226/256] Update Marlin_main.cpp Added description of autotemp flags to M109 --- Marlin/Marlin_main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 5e7cdf8e57..420bd00abb 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -118,6 +118,7 @@ // M107 - Fan off // M109 - Sxxx Wait for extruder current temp to reach target temp. Waits only when heating // Rxxx Wait for extruder current temp to reach target temp. Waits when heating and cooling +// IF AUTOTEMP is enabled, S B F. Exit autotemp by any M109 without F // M114 - Output current position to serial port // M115 - Capabilities string // M117 - display message From 2fa514e88a0da8b470c5a01e210cd4732974fadf Mon Sep 17 00:00:00 2001 From: Cameron Lai Date: Thu, 24 Apr 2014 12:55:00 +0800 Subject: [PATCH 227/256] Add port for 5DPrint D8 Driver board --- Marlin/pins.h | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/Marlin/pins.h b/Marlin/pins.h index 7fa0ee47b9..3e5fa79c64 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -1,6 +1,7 @@ #ifndef PINS_H #define PINS_H +#if MOTHERBOARD != 88 #define X_MS1_PIN -1 #define X_MS2_PIN -1 #define Y_MS1_PIN -1 @@ -12,6 +13,87 @@ #define E1_MS1_PIN -1 #define E1_MS2_PIN -1 #define DIGIPOTSS_PIN -1 +#endif + +/**************************************************************************************** +* 5DPrint D8 Driver board +* https://bitbucket.org/makible/5dprint-d8-controller-board +****************************************************************************************/ + +#if MOTHERBOARD == 88 + +#define KNOWN_BOARD 1 +#define AT90USB 1286 // Disable MarlinSerial etc. + +#ifndef __AVR_AT90USB1286__ +#error Oops! Make sure you have 'Teensy++ 2.0' selected from the 'Tools -> Boards' menu. +#endif + +#define LARGE_FLASH true + +#define X_STEP_PIN 0 +#define X_DIR_PIN 1 +#define X_ENABLE_PIN 23 +#define X_STOP_PIN 37 + +#define Y_STEP_PIN 2 +#define Y_DIR_PIN 3 +#define Y_ENABLE_PIN 19 +#define Y_STOP_PIN 36 + +#define Z_STEP_PIN 4 +#define Z_DIR_PIN 5 +#define Z_ENABLE_PIN 18 +#define Z_STOP_PIN 39 + +#define E0_STEP_PIN 6 +#define E0_DIR_PIN 7 +#define E0_ENABLE_PIN 17 + +#define HEATER_0_PIN 21 // Extruder +#define HEATER_1_PIN -1 +#define HEATER_2_PIN -1 +#define HEATER_BED_PIN 20 // Bed +#define FAN_PIN 22 // Fan +// You may need to change FAN_PIN to 16 because Marlin isn't using fastio.h +// for the fan and Teensyduino uses a different pin mapping. + +#define TEMP_0_PIN 1 // Extruder / Analog pin numbering +#define TEMP_BED_PIN 0 // Bed / Analog pin numbering + +#define TEMP_1_PIN -1 +#define TEMP_2_PIN -1 + +#define SDPOWER -1 +#define SDSS 8 +#define LED_PIN -1 +#define PS_ON_PIN -1 +#define KILL_PIN -1 +#define ALARM_PIN -1 + +#ifndef SDSUPPORT +// these pins are defined in the SD library if building with SD support + #define SCK_PIN 9 + #define MISO_PIN 11 + #define MOSI_PIN 10 +#endif + +// Microstepping pins +#define X_MS1_PIN 13 +#define X_MS2_PIN 14 +#define Y_MS1_PIN 33 +#define Y_MS2_PIN 32 +#define Z_MS1_PIN 31 +#define Z_MS2_PIN 30 +#define E0_MS1_PIN 29 +#define E0_MS2_PIN 28 + +#endif /* 88 */ + +/**************************************************************************************** +* +* +****************************************************************************************/ #if MOTHERBOARD == 99 #define KNOWN_BOARD 1 From 1cbcbb0971a88aa211e256f2abaaada7bac78e9d Mon Sep 17 00:00:00 2001 From: Cameron Lai Date: Thu, 24 Apr 2014 12:55:21 +0800 Subject: [PATCH 228/256] Add makibox machine information --- Marlin/language.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Marlin/language.h b/Marlin/language.h index 6c408551a2..c032aca89e 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -36,6 +36,9 @@ #elif MOTHERBOARD == 77 #define MACHINE_NAME "3Drag" #define FIRMWARE_URL "http://3dprint.elettronicain.it/" +#elif MOTHERBOARD == 88 + #define MACHINE_NAME "Makibox" + #define FIRMWARE_URL "https://github.com/ErikZalm/Marlin/" #else #ifdef CUSTOM_MENDEL_NAME #define MACHINE_NAME CUSTOM_MENDEL_NAME From eea3ba5588580b4460b3f27da549bcf52db5aad6 Mon Sep 17 00:00:00 2001 From: Cameron Lai Date: Thu, 24 Apr 2014 12:56:06 +0800 Subject: [PATCH 229/256] Fix for stepper microstepping --- Marlin/stepper.cpp | 55 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index eaba4362dc..8f8be8c824 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -1228,34 +1228,55 @@ void digipot_current(uint8_t driver, int current) void microstep_init() { + #if defined(Y_MS1_PIN) && Y_MS1_PIN > -1 + SET_OUTPUT(Y_MS1_PIN); + SET_OUTPUT(Y_MS2_PIN); + #endif + #if defined(Z_MS1_PIN) && Z_MS1_PIN > -1 + SET_OUTPUT(Z_MS1_PIN); + SET_OUTPUT(Z_MS2_PIN); + #endif + + #if defined(E0_MS1_PIN) && E0_MS1_PIN > -1 + SET_OUTPUT(E0_MS1_PIN); + SET_OUTPUT(E0_MS2_PIN); + #endif + + #if defined(E1_MS1_PIN) && E1_MS1_PIN > -1 + SET_OUTPUT(E1_MS1_PIN); + SET_OUTPUT(E1_MS2_PIN); + #endif + #if defined(X_MS1_PIN) && X_MS1_PIN > -1 + SET_OUTPUT(X_MS1_PIN); + SET_OUTPUT(X_MS2_PIN); + const uint8_t microstep_modes[] = MICROSTEP_MODES; - pinMode(X_MS2_PIN,OUTPUT); - pinMode(Y_MS2_PIN,OUTPUT); - pinMode(Z_MS2_PIN,OUTPUT); - pinMode(E0_MS2_PIN,OUTPUT); - pinMode(E1_MS2_PIN,OUTPUT); for(int i=0;i<=4;i++) microstep_mode(i,microstep_modes[i]); - #endif + #endif } void microstep_ms(uint8_t driver, int8_t ms1, int8_t ms2) { if(ms1 > -1) switch(driver) { - case 0: digitalWrite( X_MS1_PIN,ms1); break; - case 1: digitalWrite( Y_MS1_PIN,ms1); break; - case 2: digitalWrite( Z_MS1_PIN,ms1); break; - case 3: digitalWrite(E0_MS1_PIN,ms1); break; - case 4: digitalWrite(E1_MS1_PIN,ms1); break; + case 0: WRITE( X_MS1_PIN,ms1); break; + case 1: WRITE( Y_MS1_PIN,ms1); break; + case 2: WRITE( Z_MS1_PIN,ms1); break; + case 3: WRITE(E0_MS1_PIN,ms1); break; + #if defined(E1_MS1_PIN) && E1_MS1_PIN > -1 + case 4: WRITE(E1_MS1_PIN,ms1); break; + #endif } if(ms2 > -1) switch(driver) { - case 0: digitalWrite( X_MS2_PIN,ms2); break; - case 1: digitalWrite( Y_MS2_PIN,ms2); break; - case 2: digitalWrite( Z_MS2_PIN,ms2); break; - case 3: digitalWrite(E0_MS2_PIN,ms2); break; - case 4: digitalWrite(E1_MS2_PIN,ms2); break; + case 0: WRITE( X_MS2_PIN,ms2); break; + case 1: WRITE( Y_MS2_PIN,ms2); break; + case 2: WRITE( Z_MS2_PIN,ms2); break; + case 3: WRITE(E0_MS2_PIN,ms2); break; + #if defined(E1_MS1_PIN) && E1_MS1_PIN > -1 + case 4: WRITE(E1_MS2_PIN,ms2); break; + #endif } } @@ -1286,8 +1307,10 @@ void microstep_readings() SERIAL_PROTOCOLPGM("E0: "); SERIAL_PROTOCOL( digitalRead(E0_MS1_PIN)); SERIAL_PROTOCOLLN( digitalRead(E0_MS2_PIN)); + #if defined(E1_MS1_PIN) && E1_MS1_PIN > -1 SERIAL_PROTOCOLPGM("E1: "); SERIAL_PROTOCOL( digitalRead(E1_MS1_PIN)); SERIAL_PROTOCOLLN( digitalRead(E1_MS2_PIN)); + #endif } From 3a8e36f19ea2852c9d1ee99daf097ed781ac2f38 Mon Sep 17 00:00:00 2001 From: Cameron Lai Date: Thu, 24 Apr 2014 12:56:46 +0800 Subject: [PATCH 230/256] Add Digipot config for 5DPrint D8 Driver Board --- Marlin/digipot_mcp4451.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Marlin/digipot_mcp4451.cpp b/Marlin/digipot_mcp4451.cpp index 11ee684223..7c150558bc 100644 --- a/Marlin/digipot_mcp4451.cpp +++ b/Marlin/digipot_mcp4451.cpp @@ -6,8 +6,13 @@ #include "Wire.h" // Settings for the I2C based DIGIPOT (MCP4451) on Azteeg X3 Pro +#if MOTHERBOARD == 88 +#define DIGIPOT_I2C_FACTOR 117.96 +#define DIGIPOT_I2C_MAX_CURRENT 1.736 +#else #define DIGIPOT_I2C_FACTOR 106.7 #define DIGIPOT_I2C_MAX_CURRENT 2.5 +#endif static byte current_to_wiper( float current ){ return byte(ceil(float((DIGIPOT_I2C_FACTOR*current)))); From da6b536182dc31632cff09e54468e6bfbbdef858 Mon Sep 17 00:00:00 2001 From: Cameron Lai Date: Thu, 24 Apr 2014 16:49:42 +0800 Subject: [PATCH 231/256] Add 5DPrint D8 Driver Board info and temperature table for Makibox hot bed --- Marlin/Configuration.h | 2 ++ Marlin/thermistortables.h | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index f169f8e419..b293284d89 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -70,6 +70,7 @@ // 91 = Final OMCA board // 301= Rambo // 21 = Elefu Ra Board (v3) +// 88 = 5DPrint D8 Driver Board #ifndef MOTHERBOARD #define MOTHERBOARD 7 @@ -116,6 +117,7 @@ // 9 is 100k GE Sensing AL03006-58.2K-97-G1 (4.7k pullup) // 10 is 100k RS thermistor 198-961 (4.7k pullup) // 11 is 100k beta 3950 1% thermistor (4.7k pullup) +// 12 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup) (calibrated for Makibox hot bed) // 20 is the PT100 circuit found in the Ultimainboard V2.x // 60 is 100k Maker's Tool Works Kapton Bed Thermistor beta=3950 // diff --git a/Marlin/thermistortables.h b/Marlin/thermistortables.h index 0a80e77b6a..07b385e119 100644 --- a/Marlin/thermistortables.h +++ b/Marlin/thermistortables.h @@ -921,6 +921,41 @@ const short temptable_60[][2] PROGMEM = { {1008*OVERSAMPLENR, 0}, }; #endif +#if (THERMISTORBED == 12) +//100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup) (calibrated for Makibox hot bed) +const short temptable_12[][2] PROGMEM = { + {35*OVERSAMPLENR, 180}, //top rating 180C + {211*OVERSAMPLENR, 140}, + {233*OVERSAMPLENR, 135}, + {261*OVERSAMPLENR, 130}, + {290*OVERSAMPLENR, 125}, + {328*OVERSAMPLENR, 120}, + {362*OVERSAMPLENR, 115}, + {406*OVERSAMPLENR, 110}, + {446*OVERSAMPLENR, 105}, + {496*OVERSAMPLENR, 100}, + {539*OVERSAMPLENR, 95}, + {585*OVERSAMPLENR, 90}, + {629*OVERSAMPLENR, 85}, + {675*OVERSAMPLENR, 80}, + {718*OVERSAMPLENR, 75}, + {758*OVERSAMPLENR, 70}, + {793*OVERSAMPLENR, 65}, + {822*OVERSAMPLENR, 60}, + {841*OVERSAMPLENR, 55}, + {875*OVERSAMPLENR, 50}, + {899*OVERSAMPLENR, 45}, + {926*OVERSAMPLENR, 40}, + {946*OVERSAMPLENR, 35}, + {962*OVERSAMPLENR, 30}, + {977*OVERSAMPLENR, 25}, + {987*OVERSAMPLENR, 20}, + {995*OVERSAMPLENR, 15}, + {1001*OVERSAMPLENR, 10}, + {1010*OVERSAMPLENR, 0}, + {1023*OVERSAMPLENR, -40}, +}; +#endif // Pt1000 and Pt100 handling // From 39e9b133f3246124798c642ea90585b84c929e2a Mon Sep 17 00:00:00 2001 From: Cameron Lai Date: Thu, 24 Apr 2014 17:06:07 +0800 Subject: [PATCH 232/256] Add example configuration for Makibox printer, which uses the 5DPrint D8 Driver Board --- .../makibox/Configuration.h | 722 ++++++++++++++++++ .../makibox/Configuration_adv.h | 498 ++++++++++++ 2 files changed, 1220 insertions(+) create mode 100644 Marlin/example_configurations/makibox/Configuration.h create mode 100644 Marlin/example_configurations/makibox/Configuration_adv.h diff --git a/Marlin/example_configurations/makibox/Configuration.h b/Marlin/example_configurations/makibox/Configuration.h new file mode 100644 index 0000000000..83a9c75872 --- /dev/null +++ b/Marlin/example_configurations/makibox/Configuration.h @@ -0,0 +1,722 @@ +#ifndef CONFIGURATION_H +#define CONFIGURATION_H + +// This configuration file contains the basic settings. +// Advanced settings can be found in Configuration_adv.h +// BASIC SETTINGS: select your board type, temperature sensor type, axis scaling, and endstop configuration + +//=========================================================================== +//============================= DELTA Printer =============================== +//=========================================================================== +// For a Delta printer replace the configuration files with the files in the +// example_configurations/delta directory. +// + +// User-specified version info of this build to display in [Pronterface, etc] terminal window during +// startup. Implementation of an idea by Prof Braino to inform user that any changes made to this +// build by the user have been successfully uploaded into firmware. +#define STRING_VERSION_CONFIG_H __DATE__ " " __TIME__ // build date and time +#define STRING_CONFIG_H_AUTHOR "(none, default config)" // Who made the changes. + +// SERIAL_PORT selects which serial port should be used for communication with the host. +// This allows the connection of wireless adapters (for instance) to non-default port pins. +// Serial port 0 is still used by the Arduino bootloader regardless of this setting. +#define SERIAL_PORT 0 + +// This determines the communication speed of the printer +// This determines the communication speed of the printer +#define BAUDRATE 250000 + +// This enables the serial port associated to the Bluetooth interface +//#define BTENABLED // Enable BT interface on AT90USB devices + + +//// The following define selects which electronics board you have. Please choose the one that matches your setup +// 10 = Gen7 custom (Alfons3 Version) "https://github.com/Alfons3/Generation_7_Electronics" +// 11 = Gen7 v1.1, v1.2 = 11 +// 12 = Gen7 v1.3 +// 13 = Gen7 v1.4 +// 2 = Cheaptronic v1.0 +// 20 = Sethi 3D_1 +// 3 = MEGA/RAMPS up to 1.2 = 3 +// 33 = RAMPS 1.3 / 1.4 (Power outputs: Extruder, Fan, Bed) +// 34 = RAMPS 1.3 / 1.4 (Power outputs: Extruder0, Extruder1, Bed) +// 35 = RAMPS 1.3 / 1.4 (Power outputs: Extruder, Fan, Fan) +// 4 = Duemilanove w/ ATMega328P pin assignment +// 5 = Gen6 +// 51 = Gen6 deluxe +// 6 = Sanguinololu < 1.2 +// 62 = Sanguinololu 1.2 and above +// 63 = Melzi +// 64 = STB V1.1 +// 65 = Azteeg X1 +// 66 = Melzi with ATmega1284 (MaKr3d version) +// 67 = Azteeg X3 +// 68 = Azteeg X3 Pro +// 7 = Ultimaker +// 71 = Ultimaker (Older electronics. Pre 1.5.4. This is rare) +// 72 = Ultimainboard 2.x (Uses TEMP_SENSOR 20) +// 77 = 3Drag Controller +// 8 = Teensylu +// 80 = Rumba +// 81 = Printrboard (AT90USB1286) +// 82 = Brainwave (AT90USB646) +// 83 = SAV Mk-I (AT90USB1286) +// 9 = Gen3+ +// 70 = Megatronics +// 701= Megatronics v2.0 +// 702= Minitronics v1.0 +// 90 = Alpha OMCA board +// 91 = Final OMCA board +// 301= Rambo +// 21 = Elefu Ra Board (v3) +// 88 = 5DPrint D8 Driver Board + +#ifndef MOTHERBOARD +#define MOTHERBOARD 88 +#endif + +// Define this to set a custom name for your generic Mendel, +// #define CUSTOM_MENDEL_NAME "This Mendel" + +// Define this to set a unique identifier for this printer, (Used by some programs to differentiate between machines) +// You can use an online service to generate a random UUID. (eg http://www.uuidgenerator.net/version4) +// #define MACHINE_UUID "00000000-0000-0000-0000-000000000000" + +// This defines the number of extruders +#define EXTRUDERS 1 + +//// The following define selects which power supply you have. Please choose the one that matches your setup +// 1 = ATX +// 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC) + +#define POWER_SUPPLY 1 + +// Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it. +// #define PS_DEFAULT_OFF + +//=========================================================================== +//=============================Thermal Settings ============================ +//=========================================================================== +// +//--NORMAL IS 4.7kohm PULLUP!-- 1kohm pullup can be used on hotend sensor, using correct resistor and table +// +//// Temperature sensor settings: +// -2 is thermocouple with MAX6675 (only for sensor 0) +// -1 is thermocouple with AD595 +// 0 is not used +// 1 is 100k thermistor - best choice for EPCOS 100k (4.7k pullup) +// 2 is 200k thermistor - ATC Semitec 204GT-2 (4.7k pullup) +// 3 is Mendel-parts thermistor (4.7k pullup) +// 4 is 10k thermistor !! do not use it for a hotend. It gives bad resolution at high temp. !! +// 5 is 100K thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (4.7k pullup) +// 6 is 100k EPCOS - Not as accurate as table 1 (created using a fluke thermocouple) (4.7k pullup) +// 7 is 100k Honeywell thermistor 135-104LAG-J01 (4.7k pullup) +// 71 is 100k Honeywell thermistor 135-104LAF-J01 (4.7k pullup) +// 8 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup) +// 9 is 100k GE Sensing AL03006-58.2K-97-G1 (4.7k pullup) +// 10 is 100k RS thermistor 198-961 (4.7k pullup) +// 11 is 100k beta 3950 1% thermistor (4.7k pullup) +// 12 is 100k 0603 SMD Vishay NTCS0603E3104FXT (4.7k pullup) (calibrated for Makibox hot bed) +// 20 is the PT100 circuit found in the Ultimainboard V2.x +// 60 is 100k Maker's Tool Works Kapton Bed Thermistor beta=3950 +// +// 1k ohm pullup tables - This is not normal, you would have to have changed out your 4.7k for 1k +// (but gives greater accuracy and more stable PID) +// 51 is 100k thermistor - EPCOS (1k pullup) +// 52 is 200k thermistor - ATC Semitec 204GT-2 (1k pullup) +// 55 is 100k thermistor - ATC Semitec 104GT-2 (Used in ParCan & J-Head) (1k pullup) +// +// 1047 is Pt1000 with 4k7 pullup +// 1010 is Pt1000 with 1k pullup (non standard) +// 147 is Pt100 with 4k7 pullup +// 110 is Pt100 with 1k pullup (non standard) + +#define TEMP_SENSOR_0 1 +#define TEMP_SENSOR_1 0 +#define TEMP_SENSOR_2 0 +#define TEMP_SENSOR_BED 12 + +// This makes temp sensor 1 a redundant sensor for sensor 0. If the temperatures difference between these sensors is to high the print will be aborted. +//#define TEMP_SENSOR_1_AS_REDUNDANT +#define MAX_REDUNDANT_TEMP_SENSOR_DIFF 10 + +// Actual temperature must be close to target for this long before M109 returns success +#define TEMP_RESIDENCY_TIME 10 // (seconds) +#define TEMP_HYSTERESIS 3 // (degC) range of +/- temperatures considered "close" to the target one +#define TEMP_WINDOW 1 // (degC) Window around target to start the residency timer x degC early. + +// The minimal temperature defines the temperature below which the heater will not be enabled It is used +// to check that the wiring to the thermistor is not broken. +// Otherwise this would lead to the heater being powered on all the time. +#define HEATER_0_MINTEMP 5 +#define HEATER_1_MINTEMP 5 +#define HEATER_2_MINTEMP 5 +#define BED_MINTEMP 5 + +// When temperature exceeds max temp, your heater will be switched off. +// This feature exists to protect your hotend from overheating accidentally, but *NOT* from thermistor short/failure! +// You should use MINTEMP for thermistor short/failure protection. +#define HEATER_0_MAXTEMP 275 +#define HEATER_1_MAXTEMP 275 +#define HEATER_2_MAXTEMP 275 +#define BED_MAXTEMP 150 + +// If your bed has low resistance e.g. .6 ohm and throws the fuse you can duty cycle it to reduce the +// average current. The value should be an integer and the heat bed will be turned on for 1 interval of +// HEATER_BED_DUTY_CYCLE_DIVIDER intervals. +//#define HEATER_BED_DUTY_CYCLE_DIVIDER 4 + +// If you want the M105 heater power reported in watts, define the BED_WATTS, and (shared for all extruders) EXTRUDER_WATTS +//#define EXTRUDER_WATTS (12.0*12.0/6.7) // P=I^2/R +//#define BED_WATTS (12.0*12.0/1.1) // P=I^2/R + +// PID settings: +// Comment the following line to disable PID and enable bang-bang. +#define PIDTEMP +#define BANG_MAX 255 // limits current to nozzle while in bang-bang mode; 255=full current +#define PID_MAX 255 // limits current to nozzle while PID is active (see PID_FUNCTIONAL_RANGE below); 255=full current +#ifdef PIDTEMP + //#define PID_DEBUG // Sends debug data to the serial port. + //#define PID_OPENLOOP 1 // Puts PID in open loop. M104/M140 sets the output power from 0 to PID_MAX + #define PID_FUNCTIONAL_RANGE 10 // If the temperature difference between the target temperature and the actual temperature + // is more then PID_FUNCTIONAL_RANGE then the PID will be shut off and the heater will be set to min/max. + #define PID_INTEGRAL_DRIVE_MAX 255 //limit for the integral term + #define K1 0.95 //smoothing factor within the PID + #define PID_dT ((OVERSAMPLENR * 8.0)/(F_CPU / 64.0 / 256.0)) //sampling period of the temperature routine + +// If you are using a pre-configured hotend then you can use one of the value sets by uncommenting it +// Ultimaker + #define DEFAULT_Kp 22.2 + #define DEFAULT_Ki 1.08 + #define DEFAULT_Kd 114 + +// MakerGear +// #define DEFAULT_Kp 7.0 +// #define DEFAULT_Ki 0.1 +// #define DEFAULT_Kd 12 + +// Mendel Parts V9 on 12V +// #define DEFAULT_Kp 63.0 +// #define DEFAULT_Ki 2.25 +// #define DEFAULT_Kd 440 +#endif // PIDTEMP + +// Bed Temperature Control +// Select PID or bang-bang with PIDTEMPBED. If bang-bang, BED_LIMIT_SWITCHING will enable hysteresis +// +// Uncomment this to enable PID on the bed. It uses the same frequency PWM as the extruder. +// If your PID_dT above is the default, and correct for your hardware/configuration, that means 7.689Hz, +// which is fine for driving a square wave into a resistive load and does not significantly impact you FET heating. +// This also works fine on a Fotek SSR-10DA Solid State Relay into a 250W heater. +// If your configuration is significantly different than this and you don't understand the issues involved, you probably +// shouldn't use bed PID until someone else verifies your hardware works. +// If this is enabled, find your own PID constants below. +//#define PIDTEMPBED +// +//#define BED_LIMIT_SWITCHING + +// This sets the max power delivered to the bed, and replaces the HEATER_BED_DUTY_CYCLE_DIVIDER option. +// all forms of bed control obey this (PID, bang-bang, bang-bang with hysteresis) +// setting this to anything other than 255 enables a form of PWM to the bed just like HEATER_BED_DUTY_CYCLE_DIVIDER did, +// so you shouldn't use it unless you are OK with PWM on your bed. (see the comment on enabling PIDTEMPBED) +#define MAX_BED_POWER 255 // limits duty cycle to bed; 255=full current + +#ifdef PIDTEMPBED +//120v 250W silicone heater into 4mm borosilicate (MendelMax 1.5+) +//from FOPDT model - kp=.39 Tp=405 Tdead=66, Tc set to 79.2, aggressive factor of .15 (vs .1, 1, 10) + #define DEFAULT_bedKp 10.00 + #define DEFAULT_bedKi .023 + #define DEFAULT_bedKd 305.4 + +//120v 250W silicone heater into 4mm borosilicate (MendelMax 1.5+) +//from pidautotune +// #define DEFAULT_bedKp 97.1 +// #define DEFAULT_bedKi 1.41 +// #define DEFAULT_bedKd 1675.16 + +// FIND YOUR OWN: "M303 E-1 C8 S90" to run autotune on the bed at 90 degreesC for 8 cycles. +#endif // PIDTEMPBED + + + +//this prevents dangerous Extruder moves, i.e. if the temperature is under the limit +//can be software-disabled for whatever purposes by +#define PREVENT_DANGEROUS_EXTRUDE +//if PREVENT_DANGEROUS_EXTRUDE is on, you can still disable (uncomment) very long bits of extrusion separately. +#define PREVENT_LENGTHY_EXTRUDE + +#define EXTRUDE_MINTEMP 170 +#define EXTRUDE_MAXLENGTH (X_MAX_LENGTH+Y_MAX_LENGTH) //prevent extrusion of very large distances. + +//=========================================================================== +//=============================Mechanical Settings=========================== +//=========================================================================== + +// Uncomment the following line to enable CoreXY kinematics +// #define COREXY + +// coarse Endstop Settings +#define ENDSTOPPULLUPS // Comment this out (using // at the start of the line) to disable the endstop pullup resistors + +#ifndef ENDSTOPPULLUPS + // fine endstop settings: Individual pullups. will be ignored if ENDSTOPPULLUPS is defined + // #define ENDSTOPPULLUP_XMAX + // #define ENDSTOPPULLUP_YMAX + // #define ENDSTOPPULLUP_ZMAX + // #define ENDSTOPPULLUP_XMIN + // #define ENDSTOPPULLUP_YMIN + // #define ENDSTOPPULLUP_ZMIN +#endif + +#ifdef ENDSTOPPULLUPS + #define ENDSTOPPULLUP_XMAX + #define ENDSTOPPULLUP_YMAX + #define ENDSTOPPULLUP_ZMAX + #define ENDSTOPPULLUP_XMIN + #define ENDSTOPPULLUP_YMIN + #define ENDSTOPPULLUP_ZMIN +#endif + +// The pullups are needed if you directly connect a mechanical endswitch between the signal and ground pins. +const bool X_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop. +const bool Y_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop. +const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic of the endstop. +const bool X_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop. +const bool Y_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop. +const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of the endstop. +//#define DISABLE_MAX_ENDSTOPS +//#define DISABLE_MIN_ENDSTOPS + +// Disable max endstops for compatibility with endstop checking routine +#if defined(COREXY) && !defined(DISABLE_MAX_ENDSTOPS) + #define DISABLE_MAX_ENDSTOPS +#endif + +// For Inverting Stepper Enable Pins (Active Low) use 0, Non Inverting (Active High) use 1 +#define X_ENABLE_ON 0 +#define Y_ENABLE_ON 0 +#define Z_ENABLE_ON 0 +#define E_ENABLE_ON 0 // For all extruders + +// Disables axis when it's not being used. +#define DISABLE_X false +#define DISABLE_Y false +#define DISABLE_Z false +#define DISABLE_E false // For all extruders + +#define INVERT_X_DIR false // for Mendel set to false, for Orca set to true +#define INVERT_Y_DIR false // for Mendel set to true, for Orca set to false +#define INVERT_Z_DIR false // for Mendel set to false, for Orca set to true +#define INVERT_E0_DIR true // for direct drive extruder v9 set to true, for geared extruder set to false +#define INVERT_E1_DIR false // for direct drive extruder v9 set to true, for geared extruder set to false +#define INVERT_E2_DIR false // for direct drive extruder v9 set to true, for geared extruder set to false + +// ENDSTOP SETTINGS: +// Sets direction of endstops when homing; 1=MAX, -1=MIN +#define X_HOME_DIR -1 +#define Y_HOME_DIR -1 +#define Z_HOME_DIR -1 + +#define min_software_endstops true // If true, axis won't move to coordinates less than HOME_POS. +#define max_software_endstops true // If true, axis won't move to coordinates greater than the defined lengths below. + +// Travel limits after homing +#define X_MAX_POS 110 +#define X_MIN_POS 0 +#define Y_MAX_POS 150 +#define Y_MIN_POS 0 +#define Z_MAX_POS 86 +#define Z_MIN_POS 0 + +#define X_MAX_LENGTH (X_MAX_POS - X_MIN_POS) +#define Y_MAX_LENGTH (Y_MAX_POS - Y_MIN_POS) +#define Z_MAX_LENGTH (Z_MAX_POS - Z_MIN_POS) +//============================= Bed Auto Leveling =========================== + +//#define ENABLE_AUTO_BED_LEVELING // Delete the comment to enable (remove // at the start of the line) + +#ifdef ENABLE_AUTO_BED_LEVELING + +// There are 2 different ways to pick the X and Y locations to probe: + +// - "grid" mode +// Probe every point in a rectangular grid +// You must specify the rectangle, and the density of sample points +// This mode is preferred because there are more measurements. +// It used to be called ACCURATE_BED_LEVELING but "grid" is more descriptive + +// - "3-point" mode +// Probe 3 arbitrary points on the bed (that aren't colinear) +// You must specify the X & Y coordinates of all 3 points + + #define AUTO_BED_LEVELING_GRID + // with AUTO_BED_LEVELING_GRID, the bed is sampled in a + // AUTO_BED_LEVELING_GRID_POINTSxAUTO_BED_LEVELING_GRID_POINTS grid + // and least squares solution is calculated + // Note: this feature occupies 10'206 byte + #ifdef AUTO_BED_LEVELING_GRID + + // set the rectangle in which to probe + #define LEFT_PROBE_BED_POSITION 15 + #define RIGHT_PROBE_BED_POSITION 170 + #define BACK_PROBE_BED_POSITION 180 + #define FRONT_PROBE_BED_POSITION 20 + + // set the number of grid points per dimension + // I wouldn't see a reason to go above 3 (=9 probing points on the bed) + #define AUTO_BED_LEVELING_GRID_POINTS 2 + + + #else // not AUTO_BED_LEVELING_GRID + // with no grid, just probe 3 arbitrary points. A simple cross-product + // is used to esimate the plane of the print bed + + #define ABL_PROBE_PT_1_X 15 + #define ABL_PROBE_PT_1_Y 180 + #define ABL_PROBE_PT_2_X 15 + #define ABL_PROBE_PT_2_Y 20 + #define ABL_PROBE_PT_3_X 170 + #define ABL_PROBE_PT_3_Y 20 + + #endif // AUTO_BED_LEVELING_GRID + + + // these are the offsets to the probe relative to the extruder tip (Hotend - Probe) + #define X_PROBE_OFFSET_FROM_EXTRUDER -25 + #define Y_PROBE_OFFSET_FROM_EXTRUDER -29 + #define Z_PROBE_OFFSET_FROM_EXTRUDER -12.35 + + #define Z_RAISE_BEFORE_HOMING 4 // (in mm) Raise Z before homing (G28) for Probe Clearance. + // Be sure you have this distance over your Z_MAX_POS in case + + #define XY_TRAVEL_SPEED 8000 // X and Y axis travel speed between probes, in mm/min + + #define Z_RAISE_BEFORE_PROBING 15 //How much the extruder will be raised before traveling to the first probing point. + #define Z_RAISE_BETWEEN_PROBINGS 5 //How much the extruder will be raised when traveling from between next probing points + + + //If defined, the Probe servo will be turned on only during movement and then turned off to avoid jerk + //The value is the delay to turn the servo off after powered on - depends on the servo speed; 300ms is good value, but you can try lower it. + // You MUST HAVE the SERVO_ENDSTOPS defined to use here a value higher than zero otherwise your code will not compile. + +// #define PROBE_SERVO_DEACTIVATION_DELAY 300 + + +//If you have enabled the Bed Auto Leveling and are using the same Z Probe for Z Homing, +//it is highly recommended you let this Z_SAFE_HOMING enabled!!! + + #define Z_SAFE_HOMING // This feature is meant to avoid Z homing with probe outside the bed area. + // When defined, it will: + // - Allow Z homing only after X and Y homing AND stepper drivers still enabled + // - If stepper drivers timeout, it will need X and Y homing again before Z homing + // - Position the probe in a defined XY point before Z Homing when homing all axis (G28) + // - Block Z homing only when the probe is outside bed area. + + #ifdef Z_SAFE_HOMING + + #define Z_SAFE_HOMING_X_POINT (X_MAX_LENGTH/2) // X point for Z homing when homing all axis (G28) + #define Z_SAFE_HOMING_Y_POINT (Y_MAX_LENGTH/2) // Y point for Z homing when homing all axis (G28) + + #endif + +#endif // ENABLE_AUTO_BED_LEVELING + + +// The position of the homing switches +//#define MANUAL_HOME_POSITIONS // If defined, MANUAL_*_HOME_POS below will be used +//#define BED_CENTER_AT_0_0 // If defined, the center of the bed is at (X=0, Y=0) + +//Manual homing switch locations: +// For deltabots this means top and center of the Cartesian print volume. +#define MANUAL_X_HOME_POS 0 +#define MANUAL_Y_HOME_POS 0 +#define MANUAL_Z_HOME_POS 0 +//#define MANUAL_Z_HOME_POS 402 // For delta: Distance between nozzle and print surface after homing. + +//// MOVEMENT SETTINGS +#define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E +#define HOMING_FEEDRATE {1500, 1500, 120, 0} // set the homing speeds (mm/min) ***** MakiBox A6 ***** + +// default settings + +#define DEFAULT_AXIS_STEPS_PER_UNIT {400, 400, 400, 163} // default steps per unit for ***** MakiBox A6 ***** +#define DEFAULT_MAX_FEEDRATE {60, 60, 20, 45} // (mm/sec) +#define DEFAULT_MAX_ACCELERATION {2000,2000,30,10000} // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot. + +#define DEFAULT_ACCELERATION 3000 // X, Y, Z and E max acceleration in mm/s^2 for printing moves +#define DEFAULT_RETRACT_ACCELERATION 3000 // X, Y, Z and E max acceleration in mm/s^2 for retracts + +// Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing). +// The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder). +// For the other hotends it is their distance from the extruder 0 hotend. +// #define EXTRUDER_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis +// #define EXTRUDER_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis + +// The speed change that does not require acceleration (i.e. the software might assume it can be done instantaneously) +#define DEFAULT_XYJERK 20.0 // (mm/sec) +#define DEFAULT_ZJERK 0.4 // (mm/sec) +#define DEFAULT_EJERK 5.0 // (mm/sec) + +//=========================================================================== +//=============================Additional Features=========================== +//=========================================================================== + +// Custom M code points +#define CUSTOM_M_CODES +#ifdef CUSTOM_M_CODES + #define CUSTOM_M_CODE_SET_Z_PROBE_OFFSET 851 + #define Z_PROBE_OFFSET_RANGE_MIN -15 + #define Z_PROBE_OFFSET_RANGE_MAX -5 +#endif + + +// EEPROM +// The microcontroller can store settings in the EEPROM, e.g. max velocity... +// M500 - stores parameters in EEPROM +// M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily). +// M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to. +//define this to enable EEPROM support +//#define EEPROM_SETTINGS +//to disable EEPROM Serial responses and decrease program space by ~1700 byte: comment this out: +// please keep turned on if you can. +//#define EEPROM_CHITCHAT + +// Preheat Constants +#define PLA_PREHEAT_HOTEND_TEMP 180 +#define PLA_PREHEAT_HPB_TEMP 70 +#define PLA_PREHEAT_FAN_SPEED 255 // Insert Value between 0 and 255 + +#define ABS_PREHEAT_HOTEND_TEMP 240 +#define ABS_PREHEAT_HPB_TEMP 100 +#define ABS_PREHEAT_FAN_SPEED 255 // Insert Value between 0 and 255 + +//LCD and SD support +//#define ULTRA_LCD //general LCD support, also 16x2 +//#define DOGLCD // Support for SPI LCD 128x64 (Controller ST7565R graphic Display Family) +#define SDSUPPORT // Enable SD Card Support in Hardware Console +#define SDSLOW // Use slower SD transfer mode (not normally needed - uncomment if you're getting volume init error) +//#define ENCODER_PULSES_PER_STEP 1 // Increase if you have a high resolution encoder +//#define ENCODER_STEPS_PER_MENU_ITEM 5 // Set according to ENCODER_PULSES_PER_STEP or your liking +//#define ULTIMAKERCONTROLLER //as available from the Ultimaker online store. +//#define ULTIPANEL //the UltiPanel as on Thingiverse +//#define LCD_FEEDBACK_FREQUENCY_HZ 1000 // this is the tone frequency the buzzer plays when on UI feedback. ie Screen Click +//#define LCD_FEEDBACK_FREQUENCY_DURATION_MS 100 // the duration the buzzer plays the UI feedback sound. ie Screen Click + +// The MaKr3d Makr-Panel with graphic controller and SD support +// http://reprap.org/wiki/MaKr3d_MaKrPanel +//#define MAKRPANEL + +// The RepRapDiscount Smart Controller (white PCB) +// http://reprap.org/wiki/RepRapDiscount_Smart_Controller +//#define REPRAP_DISCOUNT_SMART_CONTROLLER + +// The GADGETS3D G3D LCD/SD Controller (blue PCB) +// http://reprap.org/wiki/RAMPS_1.3/1.4_GADGETS3D_Shield_with_Panel +//#define G3D_PANEL + +// The RepRapDiscount FULL GRAPHIC Smart Controller (quadratic white PCB) +// http://reprap.org/wiki/RepRapDiscount_Full_Graphic_Smart_Controller +// +// ==> REMEMBER TO INSTALL U8glib to your ARDUINO library folder: http://code.google.com/p/u8glib/wiki/u8glib +//#define REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER + +// The RepRapWorld REPRAPWORLD_KEYPAD v1.1 +// http://reprapworld.com/?products_details&products_id=202&cPath=1591_1626 +//#define REPRAPWORLD_KEYPAD +//#define REPRAPWORLD_KEYPAD_MOVE_STEP 10.0 // how much should be moved when a key is pressed, eg 10.0 means 10mm per click + +// The Elefu RA Board Control Panel +// http://www.elefu.com/index.php?route=product/product&product_id=53 +// REMEMBER TO INSTALL LiquidCrystal_I2C.h in your ARUDINO library folder: https://github.com/kiyoshigawa/LiquidCrystal_I2C +//#define RA_CONTROL_PANEL + +//automatic expansion +#if defined (MAKRPANEL) + #define DOGLCD + #define SDSUPPORT + #define ULTIPANEL + #define NEWPANEL + #define DEFAULT_LCD_CONTRAST 17 +#endif + +#if defined (REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER) + #define DOGLCD + #define U8GLIB_ST7920 + #define REPRAP_DISCOUNT_SMART_CONTROLLER +#endif + +#if defined(ULTIMAKERCONTROLLER) || defined(REPRAP_DISCOUNT_SMART_CONTROLLER) || defined(G3D_PANEL) + #define ULTIPANEL + #define NEWPANEL +#endif + +#if defined(REPRAPWORLD_KEYPAD) + #define NEWPANEL + #define ULTIPANEL +#endif +#if defined(RA_CONTROL_PANEL) + #define ULTIPANEL + #define NEWPANEL + #define LCD_I2C_TYPE_PCA8574 + #define LCD_I2C_ADDRESS 0x27 // I2C Address of the port expander +#endif + +//I2C PANELS + +//#define LCD_I2C_SAINSMART_YWROBOT +#ifdef LCD_I2C_SAINSMART_YWROBOT + // This uses the LiquidCrystal_I2C library ( https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home ) + // Make sure it is placed in the Arduino libraries directory. + #define LCD_I2C_TYPE_PCF8575 + #define LCD_I2C_ADDRESS 0x27 // I2C Address of the port expander + #define NEWPANEL + #define ULTIPANEL +#endif + +// PANELOLU2 LCD with status LEDs, separate encoder and click inputs +//#define LCD_I2C_PANELOLU2 +#ifdef LCD_I2C_PANELOLU2 + // This uses the LiquidTWI2 library v1.2.3 or later ( https://github.com/lincomatic/LiquidTWI2 ) + // Make sure the LiquidTWI2 directory is placed in the Arduino or Sketchbook libraries subdirectory. + // (v1.2.3 no longer requires you to define PANELOLU in the LiquidTWI2.h library header file) + // Note: The PANELOLU2 encoder click input can either be directly connected to a pin + // (if BTN_ENC defined to != -1) or read through I2C (when BTN_ENC == -1). + #define LCD_I2C_TYPE_MCP23017 + #define LCD_I2C_ADDRESS 0x20 // I2C Address of the port expander + #define LCD_USE_I2C_BUZZER //comment out to disable buzzer on LCD + #define NEWPANEL + #define ULTIPANEL + + #ifndef ENCODER_PULSES_PER_STEP + #define ENCODER_PULSES_PER_STEP 4 + #endif + + #ifndef ENCODER_STEPS_PER_MENU_ITEM + #define ENCODER_STEPS_PER_MENU_ITEM 1 + #endif + + + #ifdef LCD_USE_I2C_BUZZER + #define LCD_FEEDBACK_FREQUENCY_HZ 1000 + #define LCD_FEEDBACK_FREQUENCY_DURATION_MS 100 + #endif + +#endif + +// Panucatt VIKI LCD with status LEDs, integrated click & L/R/U/P buttons, separate encoder inputs +//#define LCD_I2C_VIKI +#ifdef LCD_I2C_VIKI + // This uses the LiquidTWI2 library v1.2.3 or later ( https://github.com/lincomatic/LiquidTWI2 ) + // Make sure the LiquidTWI2 directory is placed in the Arduino or Sketchbook libraries subdirectory. + // Note: The pause/stop/resume LCD button pin should be connected to the Arduino + // BTN_ENC pin (or set BTN_ENC to -1 if not used) + #define LCD_I2C_TYPE_MCP23017 + #define LCD_I2C_ADDRESS 0x20 // I2C Address of the port expander + #define LCD_USE_I2C_BUZZER //comment out to disable buzzer on LCD (requires LiquidTWI2 v1.2.3 or later) + #define NEWPANEL + #define ULTIPANEL +#endif + +// Shift register panels +// --------------------- +// 2 wire Non-latching LCD SR from: +// https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/schematics#!shiftregister-connection +//#define SR_LCD +#ifdef SR_LCD + #define SR_LCD_2W_NL // Non latching 2 wire shift register + //#define NEWPANEL +#endif + + +#ifdef ULTIPANEL +// #define NEWPANEL //enable this if you have a click-encoder panel + #define SDSUPPORT + #define ULTRA_LCD + #ifdef DOGLCD // Change number of lines to match the DOG graphic display + #define LCD_WIDTH 20 + #define LCD_HEIGHT 5 + #else + #define LCD_WIDTH 20 + #define LCD_HEIGHT 4 + #endif +#else //no panel but just LCD + #ifdef ULTRA_LCD + #ifdef DOGLCD // Change number of lines to match the 128x64 graphics display + #define LCD_WIDTH 20 + #define LCD_HEIGHT 5 + #else + #define LCD_WIDTH 16 + #define LCD_HEIGHT 2 + #endif + #endif +#endif + +// default LCD contrast for dogm-like LCD displays +#ifdef DOGLCD +# ifndef DEFAULT_LCD_CONTRAST +# define DEFAULT_LCD_CONTRAST 32 +# endif +#endif + +// Increase the FAN pwm frequency. Removes the PWM noise but increases heating in the FET/Arduino +//#define FAST_PWM_FAN + +// Temperature status LEDs that display the hotend and bet temperature. +// If all hotends and bed temperature and temperature setpoint are < 54C then the BLUE led is on. +// Otherwise the RED led is on. There is 1C hysteresis. +//#define TEMP_STAT_LEDS + +// Use software PWM to drive the fan, as for the heaters. This uses a very low frequency +// which is not ass annoying as with the hardware PWM. On the other hand, if this frequency +// is too low, you should also increment SOFT_PWM_SCALE. +//#define FAN_SOFT_PWM + +// Incrementing this by 1 will double the software PWM frequency, +// affecting heaters, and the fan if FAN_SOFT_PWM is enabled. +// However, control resolution will be halved for each increment; +// at zero value, there are 128 effective control positions. +#define SOFT_PWM_SCALE 0 + +// M240 Triggers a camera by emulating a Canon RC-1 Remote +// Data from: http://www.doc-diy.net/photo/rc-1_hacked/ +// #define PHOTOGRAPH_PIN 23 + +// SF send wrong arc g-codes when using Arc Point as fillet procedure +//#define SF_ARC_FIX + +// Support for the BariCUDA Paste Extruder. +//#define BARICUDA + +//define BlinkM/CyzRgb Support +//#define BLINKM + +/*********************************************************************\ +* R/C SERVO support +* Sponsored by TrinityLabs, Reworked by codexmas +**********************************************************************/ + +// Number of servos +// +// If you select a configuration below, this will receive a default value and does not need to be set manually +// set it manually if you have more servos than extruders and wish to manually control some +// leaving it undefined or defining as 0 will disable the servo subsystem +// If unsure, leave commented / disabled +// +//#define NUM_SERVOS 3 // Servo index starts with 0 for M280 command + +// Servo Endstops +// +// This allows for servo actuated endstops, primary usage is for the Z Axis to eliminate calibration or bed height changes. +// Use M206 command to correct for switch height offset to actual nozzle height. Store that setting with M500. +// + +#define DIGIPOT_I2C + +//#define SERVO_ENDSTOPS {-1, -1, 0} // Servo index for X, Y, Z. Disable with -1 +//#define SERVO_ENDSTOP_ANGLES {0,0, 0,0, 70,0} // X,Y,Z Axis Extend and Retract angles + +#include "Configuration_adv.h" +#include "thermistortables.h" + +#endif //__CONFIGURATION_H diff --git a/Marlin/example_configurations/makibox/Configuration_adv.h b/Marlin/example_configurations/makibox/Configuration_adv.h new file mode 100644 index 0000000000..7883c79996 --- /dev/null +++ b/Marlin/example_configurations/makibox/Configuration_adv.h @@ -0,0 +1,498 @@ +#ifndef CONFIGURATION_ADV_H +#define CONFIGURATION_ADV_H + +//=========================================================================== +//=============================Thermal Settings ============================ +//=========================================================================== + +#ifdef BED_LIMIT_SWITCHING + #define BED_HYSTERESIS 2 //only disable heating if T>target+BED_HYSTERESIS and enable heating if T>target-BED_HYSTERESIS +#endif +#define BED_CHECK_INTERVAL 5000 //ms between checks in bang-bang control + +//// Heating sanity check: +// This waits for the watch period in milliseconds whenever an M104 or M109 increases the target temperature +// If the temperature has not increased at the end of that period, the target temperature is set to zero. +// It can be reset with another M104/M109. This check is also only triggered if the target temperature and the current temperature +// differ by at least 2x WATCH_TEMP_INCREASE +//#define WATCH_TEMP_PERIOD 40000 //40 seconds +//#define WATCH_TEMP_INCREASE 10 //Heat up at least 10 degree in 20 seconds + +#ifdef PIDTEMP + // this adds an experimental additional term to the heating power, proportional to the extrusion speed. + // if Kc is chosen well, the additional required power due to increased melting should be compensated. + #define PID_ADD_EXTRUSION_RATE + #ifdef PID_ADD_EXTRUSION_RATE + #define DEFAULT_Kc (1) //heating power=Kc*(e_speed) + #endif +#endif + + +//automatic temperature: The hot end target temperature is calculated by all the buffered lines of gcode. +//The maximum buffered steps/sec of the extruder motor are called "se". +//You enter the autotemp mode by a M109 S T F +// the target temperature is set to mintemp+factor*se[steps/sec] and limited by mintemp and maxtemp +// you exit the value by any M109 without F* +// Also, if the temperature is set to a value +// Mode 0: Full control. The slicer has full control over both x-carriages and can achieve optimal travel results +// as long as it supports dual x-carriages. (M605 S0) +// Mode 1: Auto-park mode. The firmware will automatically park and unpark the x-carriages on tool changes so +// that additional slicer support is not required. (M605 S1) +// Mode 2: Duplication mode. The firmware will transparently make the second x-carriage and extruder copy all +// actions of the first x-carriage. This allows the printer to print 2 arbitrary items at +// once. (2nd extruder x offset and temp offset are set using: M605 S2 [Xnnn] [Rmmm]) + +// This is the default power-up mode which can be later using M605. +#define DEFAULT_DUAL_X_CARRIAGE_MODE 0 + +// As the x-carriages are independent we can now account for any relative Z offset +#define EXTRUDER1_Z_OFFSET 0.0 // z offset relative to extruder 0 + +// Default settings in "Auto-park Mode" +#define TOOLCHANGE_PARK_ZLIFT 0.2 // the distance to raise Z axis when parking an extruder +#define TOOLCHANGE_UNPARK_ZLIFT 1 // the distance to raise Z axis when unparking an extruder + +// Default x offset in duplication mode (typically set to half print bed width) +#define DEFAULT_DUPLICATION_X_OFFSET 100 + +#endif //DUAL_X_CARRIAGE + +//homing hits the endstop, then retracts by this distance, before it tries to slowly bump again: +#define X_HOME_RETRACT_MM 5 +#define Y_HOME_RETRACT_MM 5 +#define Z_HOME_RETRACT_MM 2 +//#define QUICK_HOME //if this is defined, if both x and y are to be homed, a diagonal move will be performed initially. + +#define AXIS_RELATIVE_MODES {false, false, false, false} + +#define MAX_STEP_FREQUENCY 40000 // Max step frequency for Ultimaker (5000 pps / half step) + +//By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step. +#define INVERT_X_STEP_PIN false +#define INVERT_Y_STEP_PIN false +#define INVERT_Z_STEP_PIN false +#define INVERT_E_STEP_PIN false + +//default stepper release if idle +#define DEFAULT_STEPPER_DEACTIVE_TIME 60 + +#define DEFAULT_MINIMUMFEEDRATE 0.0 // minimum feedrate +#define DEFAULT_MINTRAVELFEEDRATE 0.0 + +// Feedrates for manual moves along X, Y, Z, E from panel +#ifdef ULTIPANEL +#define MANUAL_FEEDRATE {50*60, 50*60, 4*60, 60} // set the speeds for manual moves (mm/min) +#endif + +//Comment to disable setting feedrate multiplier via encoder +#ifdef ULTIPANEL + #define ULTIPANEL_FEEDMULTIPLY +#endif + +// minimum time in microseconds that a movement needs to take if the buffer is emptied. +#define DEFAULT_MINSEGMENTTIME 20000 + +// If defined the movements slow down when the look ahead buffer is only half full +#define SLOWDOWN + +// Frequency limit +// See nophead's blog for more info +// Not working O +//#define XY_FREQUENCY_LIMIT 15 + +// Minimum planner junction speed. Sets the default minimum speed the planner plans for at the end +// of the buffer and all stops. This should not be much greater than zero and should only be changed +// if unwanted behavior is observed on a user's machine when running at very slow speeds. +#define MINIMUM_PLANNER_SPEED 0.05// (mm/sec) + +// MS1 MS2 Stepper Driver Microstepping mode table +#define MICROSTEP1 LOW,LOW +#define MICROSTEP2 HIGH,LOW +#define MICROSTEP4 LOW,HIGH +#define MICROSTEP8 HIGH,HIGH +#define MICROSTEP16 HIGH,HIGH + +// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU. +#define MICROSTEP_MODES {16,16,16,16,16} // [1,2,4,8,16] + +// Motor Current setting (Only functional when motor driver current ref pins are connected to a digital trimpot on supported boards) +#define DIGIPOT_MOTOR_CURRENT {135,135,135,135,135} // Values 0-255 (RAMBO 135 = ~0.75A, 185 = ~1A) + +// uncomment to enable an I2C based DIGIPOT like on the Azteeg X3 Pro +//#define DIGIPOT_I2C +// Number of channels available for I2C digipot, For Azteeg X3 Pro we have 8 +#define DIGIPOT_I2C_NUM_CHANNELS 4 +// actual motor currents in Amps, need as many here as DIGIPOT_I2C_NUM_CHANNELS +//#define DIGIPOT_I2C_MOTOR_CURRENTS {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0} +#define DIGIPOT_I2C_MOTOR_CURRENTS {1.7, 1.7, 1.7, 1.7} + +//=========================================================================== +//=============================Additional Features=========================== +//=========================================================================== + +//#define CHDK 4 //Pin for triggering CHDK to take a picture see how to use it here http://captain-slow.dk/2014/03/09/3d-printing-timelapses/ +#define CHDK_DELAY 50 //How long in ms the pin should stay HIGH before going LOW again + +#define SD_FINISHED_STEPPERRELEASE true //if sd support and the file is finished: disable steppers? +#define SD_FINISHED_RELEASECOMMAND "M84 X Y Z E" // You might want to keep the z enabled so your bed stays in place. + +#define SDCARD_RATHERRECENTFIRST //reverse file order of sd card menu display. Its sorted practically after the file system block order. +// if a file is deleted, it frees a block. hence, the order is not purely chronological. To still have auto0.g accessible, there is again the option to do that. +// using: +//#define MENU_ADDAUTOSTART + +// The hardware watchdog should reset the microcontroller disabling all outputs, in case the firmware gets stuck and doesn't do temperature regulation. +//#define USE_WATCHDOG + +#ifdef USE_WATCHDOG +// If you have a watchdog reboot in an ArduinoMega2560 then the device will hang forever, as a watchdog reset will leave the watchdog on. +// The "WATCHDOG_RESET_MANUAL" goes around this by not using the hardware reset. +// However, THIS FEATURE IS UNSAFE!, as it will only work if interrupts are disabled. And the code could hang in an interrupt routine with interrupts disabled. +//#define WATCHDOG_RESET_MANUAL +#endif + +// Enable the option to stop SD printing when hitting and endstops, needs to be enabled from the LCD menu when this option is enabled. +//#define ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED + +// Babystepping enables the user to control the axis in tiny amounts, independently from the normal printing process +// it can e.g. be used to change z-positions in the print startup phase in real-time +// does not respect endstops! +//#define BABYSTEPPING +#ifdef BABYSTEPPING + #define BABYSTEP_XY //not only z, but also XY in the menu. more clutter, more functions + #define BABYSTEP_INVERT_Z false //true for inverse movements in Z + #define BABYSTEP_Z_MULTIPLICATOR 2 //faster z movements + + #ifdef COREXY + #error BABYSTEPPING not implemented for COREXY yet. + #endif + + #ifdef DELTA + #ifdef BABYSTEP_XY + #error BABYSTEPPING only implemented for Z axis on deltabots. + #endif + #endif +#endif + +// extruder advance constant (s2/mm3) +// +// advance (steps) = STEPS_PER_CUBIC_MM_E * EXTUDER_ADVANCE_K * cubic mm per second ^ 2 +// +// Hooke's law says: force = k * distance +// Bernoulli's principle says: v ^ 2 / 2 + g . h + pressure / density = constant +// so: v ^ 2 is proportional to number of steps we advance the extruder +//#define ADVANCE + +#ifdef ADVANCE + #define EXTRUDER_ADVANCE_K .0 + + #define D_FILAMENT 2.85 + #define STEPS_MM_E 836 + #define EXTRUTION_AREA (0.25 * D_FILAMENT * D_FILAMENT * 3.14159) + #define STEPS_PER_CUBIC_MM_E (axis_steps_per_unit[E_AXIS]/ EXTRUTION_AREA) + +#endif // ADVANCE + +// Arc interpretation settings: +#define MM_PER_ARC_SEGMENT 1 +#define N_ARC_CORRECTION 25 + +const unsigned int dropsegments=5; //everything with less than this number of steps will be ignored as move and joined with the next movement + +// If you are using a RAMPS board or cheap E-bay purchased boards that do not detect when an SD card is inserted +// You can get round this by connecting a push button or single throw switch to the pin defined as SDCARDCARDDETECT +// in the pins.h file. When using a push button pulling the pin to ground this will need inverted. This setting should +// be commented out otherwise +//#define SDCARDDETECTINVERTED + +#ifdef ULTIPANEL + #undef SDCARDDETECTINVERTED +#endif + +// Power Signal Control Definitions +// By default use ATX definition +#ifndef POWER_SUPPLY + #define POWER_SUPPLY 1 +#endif +// 1 = ATX +#if (POWER_SUPPLY == 1) + #define PS_ON_AWAKE LOW + #define PS_ON_ASLEEP HIGH +#endif +// 2 = X-Box 360 203W +#if (POWER_SUPPLY == 2) + #define PS_ON_AWAKE HIGH + #define PS_ON_ASLEEP LOW +#endif + +// Control heater 0 and heater 1 in parallel. +//#define HEATERS_PARALLEL + +//=========================================================================== +//=============================Buffers ============================ +//=========================================================================== + +// The number of linear motions that can be in the plan at any give time. +// THE BLOCK_BUFFER_SIZE NEEDS TO BE A POWER OF 2, i.g. 8,16,32 because shifts and ors are used to do the ring-buffering. +#if defined SDSUPPORT + #define BLOCK_BUFFER_SIZE 16 // SD,LCD,Buttons take more memory, block buffer needs to be smaller +#else + #define BLOCK_BUFFER_SIZE 16 // maximize block buffer +#endif + + +//The ASCII buffer for receiving from the serial: +#define MAX_CMD_SIZE 96 +#define BUFSIZE 4 + + +// Firmware based and LCD controlled retract +// M207 and M208 can be used to define parameters for the retraction. +// The retraction can be called by the slicer using G10 and G11 +// until then, intended retractions can be detected by moves that only extrude and the direction. +// the moves are than replaced by the firmware controlled ones. + +// #define FWRETRACT //ONLY PARTIALLY TESTED +#ifdef FWRETRACT + #define MIN_RETRACT 0.1 //minimum extruded mm to accept a automatic gcode retraction attempt + #define RETRACT_LENGTH 3 //default retract length (positive mm) + #define RETRACT_FEEDRATE 45 //default feedrate for retracting (mm/s) + #define RETRACT_ZLIFT 0 //default retract Z-lift + #define RETRACT_RECOVER_LENGTH 0 //default additional recover length (mm, added to retract length when recovering) + #define RETRACT_RECOVER_FEEDRATE 8 //default feedrate for recovering from retraction (mm/s) +#endif + +//adds support for experimental filament exchange support M600; requires display +#ifdef ULTIPANEL + #define FILAMENTCHANGEENABLE + #ifdef FILAMENTCHANGEENABLE + #define FILAMENTCHANGE_XPOS 3 + #define FILAMENTCHANGE_YPOS 3 + #define FILAMENTCHANGE_ZADD 10 + #define FILAMENTCHANGE_FIRSTRETRACT -2 + #define FILAMENTCHANGE_FINALRETRACT -100 + #endif +#endif + +#ifdef FILAMENTCHANGEENABLE + #ifdef EXTRUDER_RUNOUT_PREVENT + #error EXTRUDER_RUNOUT_PREVENT currently incompatible with FILAMENTCHANGE + #endif +#endif + +//=========================================================================== +//============================= Define Defines ============================ +//=========================================================================== +#if EXTRUDERS > 1 && defined TEMP_SENSOR_1_AS_REDUNDANT + #error "You cannot use TEMP_SENSOR_1_AS_REDUNDANT if EXTRUDERS > 1" +#endif + +#if EXTRUDERS > 1 && defined HEATERS_PARALLEL + #error "You cannot use HEATERS_PARALLEL if EXTRUDERS > 1" +#endif + +#if TEMP_SENSOR_0 > 0 + #define THERMISTORHEATER_0 TEMP_SENSOR_0 + #define HEATER_0_USES_THERMISTOR +#endif +#if TEMP_SENSOR_1 > 0 + #define THERMISTORHEATER_1 TEMP_SENSOR_1 + #define HEATER_1_USES_THERMISTOR +#endif +#if TEMP_SENSOR_2 > 0 + #define THERMISTORHEATER_2 TEMP_SENSOR_2 + #define HEATER_2_USES_THERMISTOR +#endif +#if TEMP_SENSOR_BED > 0 + #define THERMISTORBED TEMP_SENSOR_BED + #define BED_USES_THERMISTOR +#endif +#if TEMP_SENSOR_0 == -1 + #define HEATER_0_USES_AD595 +#endif +#if TEMP_SENSOR_1 == -1 + #define HEATER_1_USES_AD595 +#endif +#if TEMP_SENSOR_2 == -1 + #define HEATER_2_USES_AD595 +#endif +#if TEMP_SENSOR_BED == -1 + #define BED_USES_AD595 +#endif +#if TEMP_SENSOR_0 == -2 + #define HEATER_0_USES_MAX6675 +#endif +#if TEMP_SENSOR_0 == 0 + #undef HEATER_0_MINTEMP + #undef HEATER_0_MAXTEMP +#endif +#if TEMP_SENSOR_1 == 0 + #undef HEATER_1_MINTEMP + #undef HEATER_1_MAXTEMP +#endif +#if TEMP_SENSOR_2 == 0 + #undef HEATER_2_MINTEMP + #undef HEATER_2_MAXTEMP +#endif +#if TEMP_SENSOR_BED == 0 + #undef BED_MINTEMP + #undef BED_MAXTEMP +#endif + + +#endif //__CONFIGURATION_ADV_H From 2715f6ddbf84397a6a89c4d2d1754ba32a15a899 Mon Sep 17 00:00:00 2001 From: Cameron Lai Date: Thu, 24 Apr 2014 17:48:33 +0800 Subject: [PATCH 233/256] Fix for reading microstepping resolution --- Marlin/stepper.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index 8f8be8c824..bef63ce2db 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -1296,21 +1296,21 @@ void microstep_readings() { SERIAL_PROTOCOLPGM("MS1,MS2 Pins\n"); SERIAL_PROTOCOLPGM("X: "); - SERIAL_PROTOCOL( digitalRead(X_MS1_PIN)); - SERIAL_PROTOCOLLN( digitalRead(X_MS2_PIN)); + SERIAL_PROTOCOL( READ(X_MS1_PIN)); + SERIAL_PROTOCOLLN( READ(X_MS2_PIN)); SERIAL_PROTOCOLPGM("Y: "); - SERIAL_PROTOCOL( digitalRead(Y_MS1_PIN)); - SERIAL_PROTOCOLLN( digitalRead(Y_MS2_PIN)); + SERIAL_PROTOCOL( READ(Y_MS1_PIN)); + SERIAL_PROTOCOLLN( READ(Y_MS2_PIN)); SERIAL_PROTOCOLPGM("Z: "); - SERIAL_PROTOCOL( digitalRead(Z_MS1_PIN)); - SERIAL_PROTOCOLLN( digitalRead(Z_MS2_PIN)); + SERIAL_PROTOCOL( READ(Z_MS1_PIN)); + SERIAL_PROTOCOLLN( READ(Z_MS2_PIN)); SERIAL_PROTOCOLPGM("E0: "); - SERIAL_PROTOCOL( digitalRead(E0_MS1_PIN)); - SERIAL_PROTOCOLLN( digitalRead(E0_MS2_PIN)); + SERIAL_PROTOCOL( READ(E0_MS1_PIN)); + SERIAL_PROTOCOLLN( READ(E0_MS2_PIN)); #if defined(E1_MS1_PIN) && E1_MS1_PIN > -1 SERIAL_PROTOCOLPGM("E1: "); - SERIAL_PROTOCOL( digitalRead(E1_MS1_PIN)); - SERIAL_PROTOCOLLN( digitalRead(E1_MS2_PIN)); + SERIAL_PROTOCOL( READ(E1_MS1_PIN)); + SERIAL_PROTOCOLLN( READ(E1_MS2_PIN)); #endif } From e2d703377a6dfecd2bdd8865da438f70e89759c2 Mon Sep 17 00:00:00 2001 From: Cameron Lai Date: Thu, 24 Apr 2014 19:15:35 +0800 Subject: [PATCH 234/256] Enable EEPROM by default for 5DPrint D8 Controller Board in example configuration --- Marlin/example_configurations/makibox/Configuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/example_configurations/makibox/Configuration.h b/Marlin/example_configurations/makibox/Configuration.h index 83a9c75872..37033ffb6e 100644 --- a/Marlin/example_configurations/makibox/Configuration.h +++ b/Marlin/example_configurations/makibox/Configuration.h @@ -477,7 +477,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of // M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily). // M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to. //define this to enable EEPROM support -//#define EEPROM_SETTINGS +#define EEPROM_SETTINGS //to disable EEPROM Serial responses and decrease program space by ~1700 byte: comment this out: // please keep turned on if you can. //#define EEPROM_CHITCHAT From 7c7f2d094ef1b7e0ee503c7fa579735f2be251b2 Mon Sep 17 00:00:00 2001 From: Cameron Lai Date: Fri, 25 Apr 2014 12:41:48 +0800 Subject: [PATCH 235/256] Revert "Fix for reading microstepping resolution" This reverts commit 2715f6ddbf84397a6a89c4d2d1754ba32a15a899. --- Marlin/stepper.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index bef63ce2db..8f8be8c824 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -1296,21 +1296,21 @@ void microstep_readings() { SERIAL_PROTOCOLPGM("MS1,MS2 Pins\n"); SERIAL_PROTOCOLPGM("X: "); - SERIAL_PROTOCOL( READ(X_MS1_PIN)); - SERIAL_PROTOCOLLN( READ(X_MS2_PIN)); + SERIAL_PROTOCOL( digitalRead(X_MS1_PIN)); + SERIAL_PROTOCOLLN( digitalRead(X_MS2_PIN)); SERIAL_PROTOCOLPGM("Y: "); - SERIAL_PROTOCOL( READ(Y_MS1_PIN)); - SERIAL_PROTOCOLLN( READ(Y_MS2_PIN)); + SERIAL_PROTOCOL( digitalRead(Y_MS1_PIN)); + SERIAL_PROTOCOLLN( digitalRead(Y_MS2_PIN)); SERIAL_PROTOCOLPGM("Z: "); - SERIAL_PROTOCOL( READ(Z_MS1_PIN)); - SERIAL_PROTOCOLLN( READ(Z_MS2_PIN)); + SERIAL_PROTOCOL( digitalRead(Z_MS1_PIN)); + SERIAL_PROTOCOLLN( digitalRead(Z_MS2_PIN)); SERIAL_PROTOCOLPGM("E0: "); - SERIAL_PROTOCOL( READ(E0_MS1_PIN)); - SERIAL_PROTOCOLLN( READ(E0_MS2_PIN)); + SERIAL_PROTOCOL( digitalRead(E0_MS1_PIN)); + SERIAL_PROTOCOLLN( digitalRead(E0_MS2_PIN)); #if defined(E1_MS1_PIN) && E1_MS1_PIN > -1 SERIAL_PROTOCOLPGM("E1: "); - SERIAL_PROTOCOL( READ(E1_MS1_PIN)); - SERIAL_PROTOCOLLN( READ(E1_MS2_PIN)); + SERIAL_PROTOCOL( digitalRead(E1_MS1_PIN)); + SERIAL_PROTOCOLLN( digitalRead(E1_MS2_PIN)); #endif } From d85411f13afe66be65ad78caf754a968ca56ca92 Mon Sep 17 00:00:00 2001 From: Cameron Lai Date: Fri, 25 Apr 2014 12:41:56 +0800 Subject: [PATCH 236/256] Revert "Fix for stepper microstepping" This reverts commit eea3ba5588580b4460b3f27da549bcf52db5aad6. --- Marlin/stepper.cpp | 55 ++++++++++++++-------------------------------- 1 file changed, 16 insertions(+), 39 deletions(-) diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index 8f8be8c824..eaba4362dc 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -1228,55 +1228,34 @@ void digipot_current(uint8_t driver, int current) void microstep_init() { - #if defined(Y_MS1_PIN) && Y_MS1_PIN > -1 - SET_OUTPUT(Y_MS1_PIN); - SET_OUTPUT(Y_MS2_PIN); - #endif - #if defined(Z_MS1_PIN) && Z_MS1_PIN > -1 - SET_OUTPUT(Z_MS1_PIN); - SET_OUTPUT(Z_MS2_PIN); - #endif - - #if defined(E0_MS1_PIN) && E0_MS1_PIN > -1 - SET_OUTPUT(E0_MS1_PIN); - SET_OUTPUT(E0_MS2_PIN); - #endif - - #if defined(E1_MS1_PIN) && E1_MS1_PIN > -1 - SET_OUTPUT(E1_MS1_PIN); - SET_OUTPUT(E1_MS2_PIN); - #endif - #if defined(X_MS1_PIN) && X_MS1_PIN > -1 - SET_OUTPUT(X_MS1_PIN); - SET_OUTPUT(X_MS2_PIN); - const uint8_t microstep_modes[] = MICROSTEP_MODES; + pinMode(X_MS2_PIN,OUTPUT); + pinMode(Y_MS2_PIN,OUTPUT); + pinMode(Z_MS2_PIN,OUTPUT); + pinMode(E0_MS2_PIN,OUTPUT); + pinMode(E1_MS2_PIN,OUTPUT); for(int i=0;i<=4;i++) microstep_mode(i,microstep_modes[i]); - #endif + #endif } void microstep_ms(uint8_t driver, int8_t ms1, int8_t ms2) { if(ms1 > -1) switch(driver) { - case 0: WRITE( X_MS1_PIN,ms1); break; - case 1: WRITE( Y_MS1_PIN,ms1); break; - case 2: WRITE( Z_MS1_PIN,ms1); break; - case 3: WRITE(E0_MS1_PIN,ms1); break; - #if defined(E1_MS1_PIN) && E1_MS1_PIN > -1 - case 4: WRITE(E1_MS1_PIN,ms1); break; - #endif + case 0: digitalWrite( X_MS1_PIN,ms1); break; + case 1: digitalWrite( Y_MS1_PIN,ms1); break; + case 2: digitalWrite( Z_MS1_PIN,ms1); break; + case 3: digitalWrite(E0_MS1_PIN,ms1); break; + case 4: digitalWrite(E1_MS1_PIN,ms1); break; } if(ms2 > -1) switch(driver) { - case 0: WRITE( X_MS2_PIN,ms2); break; - case 1: WRITE( Y_MS2_PIN,ms2); break; - case 2: WRITE( Z_MS2_PIN,ms2); break; - case 3: WRITE(E0_MS2_PIN,ms2); break; - #if defined(E1_MS1_PIN) && E1_MS1_PIN > -1 - case 4: WRITE(E1_MS2_PIN,ms2); break; - #endif + case 0: digitalWrite( X_MS2_PIN,ms2); break; + case 1: digitalWrite( Y_MS2_PIN,ms2); break; + case 2: digitalWrite( Z_MS2_PIN,ms2); break; + case 3: digitalWrite(E0_MS2_PIN,ms2); break; + case 4: digitalWrite(E1_MS2_PIN,ms2); break; } } @@ -1307,10 +1286,8 @@ void microstep_readings() SERIAL_PROTOCOLPGM("E0: "); SERIAL_PROTOCOL( digitalRead(E0_MS1_PIN)); SERIAL_PROTOCOLLN( digitalRead(E0_MS2_PIN)); - #if defined(E1_MS1_PIN) && E1_MS1_PIN > -1 SERIAL_PROTOCOLPGM("E1: "); SERIAL_PROTOCOL( digitalRead(E1_MS1_PIN)); SERIAL_PROTOCOLLN( digitalRead(E1_MS2_PIN)); - #endif } From 97ead2eccb98fa00a67b9b3975956e36eed4e3cc Mon Sep 17 00:00:00 2001 From: Cameron Lai Date: Fri, 25 Apr 2014 12:57:11 +0800 Subject: [PATCH 237/256] Fix for microstepping pin mapping, not using Teensy pin mapping, but Arduino's default pin mapping so Arduino library can be used --- Marlin/pins.h | 18 ++++++++++-------- Marlin/stepper.cpp | 23 +++++++++++++++++++---- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/Marlin/pins.h b/Marlin/pins.h index 3e5fa79c64..02a568a620 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -79,14 +79,16 @@ #endif // Microstepping pins -#define X_MS1_PIN 13 -#define X_MS2_PIN 14 -#define Y_MS1_PIN 33 -#define Y_MS2_PIN 32 -#define Z_MS1_PIN 31 -#define Z_MS2_PIN 30 -#define E0_MS1_PIN 29 -#define E0_MS2_PIN 28 +// Note that the pin mapping is not from fastio.h +// See Sd2PinMap.h for the pin configurations +#define X_MS1_PIN 25 +#define X_MS2_PIN 26 +#define Y_MS1_PIN 9 +#define Y_MS2_PIN 8 +#define Z_MS1_PIN 7 +#define Z_MS2_PIN 6 +#define E0_MS1_PIN 5 +#define E0_MS2_PIN 4 #endif /* 88 */ diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index eaba4362dc..20bedcade8 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -1228,13 +1228,22 @@ void digipot_current(uint8_t driver, int current) void microstep_init() { - #if defined(X_MS1_PIN) && X_MS1_PIN > -1 const uint8_t microstep_modes[] = MICROSTEP_MODES; - pinMode(X_MS2_PIN,OUTPUT); + + #if defined(E1_MS1_PIN) && E1_MS1_PIN > -1 + pinMode(E1_MS1_PIN,OUTPUT); + pinMode(E1_MS2_PIN,OUTPUT); + #endif + + #if defined(X_MS1_PIN) && X_MS1_PIN > -1 + pinMode(X_MS1_PIN,OUTPUT); + pinMode(X_MS2_PIN,OUTPUT); + pinMode(Y_MS1_PIN,OUTPUT); pinMode(Y_MS2_PIN,OUTPUT); - pinMode(Z_MS2_PIN,OUTPUT); + pinMode(Z_MS1_PIN,OUTPUT); + pinMode(Z_MS2_PIN,OUTPUT); + pinMode(E0_MS1_PIN,OUTPUT); pinMode(E0_MS2_PIN,OUTPUT); - pinMode(E1_MS2_PIN,OUTPUT); for(int i=0;i<=4;i++) microstep_mode(i,microstep_modes[i]); #endif } @@ -1247,7 +1256,9 @@ void microstep_ms(uint8_t driver, int8_t ms1, int8_t ms2) case 1: digitalWrite( Y_MS1_PIN,ms1); break; case 2: digitalWrite( Z_MS1_PIN,ms1); break; case 3: digitalWrite(E0_MS1_PIN,ms1); break; + #if defined(E1_MS1_PIN) && E1_MS1_PIN > -1 case 4: digitalWrite(E1_MS1_PIN,ms1); break; + #endif } if(ms2 > -1) switch(driver) { @@ -1255,7 +1266,9 @@ void microstep_ms(uint8_t driver, int8_t ms1, int8_t ms2) case 1: digitalWrite( Y_MS2_PIN,ms2); break; case 2: digitalWrite( Z_MS2_PIN,ms2); break; case 3: digitalWrite(E0_MS2_PIN,ms2); break; + #if defined(E1_MS2_PIN) && E1_MS2_PIN > -1 case 4: digitalWrite(E1_MS2_PIN,ms2); break; + #endif } } @@ -1286,8 +1299,10 @@ void microstep_readings() SERIAL_PROTOCOLPGM("E0: "); SERIAL_PROTOCOL( digitalRead(E0_MS1_PIN)); SERIAL_PROTOCOLLN( digitalRead(E0_MS2_PIN)); + #if defined(E1_MS1_PIN) && E1_MS1_PIN > -1 SERIAL_PROTOCOLPGM("E1: "); SERIAL_PROTOCOL( digitalRead(E1_MS1_PIN)); SERIAL_PROTOCOLLN( digitalRead(E1_MS2_PIN)); + #endif } From 105bebb466af0bbd9e32d818b5f19db7a9ad1a02 Mon Sep 17 00:00:00 2001 From: Cameron Lai Date: Fri, 25 Apr 2014 12:57:47 +0800 Subject: [PATCH 238/256] Fix for pin mapping for SDSS pin and Fan pin, so Arduino library can be used --- Marlin/pins.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Marlin/pins.h b/Marlin/pins.h index 02a568a620..14eff02ccb 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -54,9 +54,9 @@ #define HEATER_1_PIN -1 #define HEATER_2_PIN -1 #define HEATER_BED_PIN 20 // Bed -#define FAN_PIN 22 // Fan // You may need to change FAN_PIN to 16 because Marlin isn't using fastio.h // for the fan and Teensyduino uses a different pin mapping. +#define FAN_PIN 16 // Fan #define TEMP_0_PIN 1 // Extruder / Analog pin numbering #define TEMP_BED_PIN 0 // Bed / Analog pin numbering @@ -65,12 +65,14 @@ #define TEMP_2_PIN -1 #define SDPOWER -1 -#define SDSS 8 #define LED_PIN -1 #define PS_ON_PIN -1 #define KILL_PIN -1 #define ALARM_PIN -1 +// The SDSS pin uses a different pin mapping from file Sd2PinMap.h +#define SDSS 20 + #ifndef SDSUPPORT // these pins are defined in the SD library if building with SD support #define SCK_PIN 9 From 6460709d92ea8ae48ac8d21999a21814fc8eb8e6 Mon Sep 17 00:00:00 2001 From: Cameron Lai Date: Fri, 25 Apr 2014 16:05:05 +0800 Subject: [PATCH 239/256] Fix bug in PID Autotune report --- Marlin/temperature.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index 6be3177a18..737d075754 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -258,14 +258,14 @@ void PID_autotune(float temp, int extruder, int ncycles) Kp = 0.33*Ku; Ki = Kp/Tu; Kd = Kp*Tu/3; - SERIAL_PROTOCOLLNPGM(" Some overshoot ") + SERIAL_PROTOCOLLNPGM(" Some overshoot "); SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp); SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki); SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd); Kp = 0.2*Ku; Ki = 2*Kp/Tu; Kd = Kp*Tu/3; - SERIAL_PROTOCOLLNPGM(" No overshoot ") + SERIAL_PROTOCOLLNPGM(" No overshoot "); SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp); SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki); SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd); From ad5c8cbba9f8b61fd4bc6327c7d9d39dc011b611 Mon Sep 17 00:00:00 2001 From: Cameron Lai Date: Fri, 25 Apr 2014 17:04:24 +0800 Subject: [PATCH 240/256] Add safety limit for hot bed power in example configuration --- Marlin/example_configurations/makibox/Configuration.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Marlin/example_configurations/makibox/Configuration.h b/Marlin/example_configurations/makibox/Configuration.h index 37033ffb6e..6ebd08f43e 100644 --- a/Marlin/example_configurations/makibox/Configuration.h +++ b/Marlin/example_configurations/makibox/Configuration.h @@ -220,7 +220,10 @@ // all forms of bed control obey this (PID, bang-bang, bang-bang with hysteresis) // setting this to anything other than 255 enables a form of PWM to the bed just like HEATER_BED_DUTY_CYCLE_DIVIDER did, // so you shouldn't use it unless you are OK with PWM on your bed. (see the comment on enabling PIDTEMPBED) -#define MAX_BED_POWER 255 // limits duty cycle to bed; 255=full current +#define MAX_BED_POWER 175 // limits duty cycle to bed; 255=full current +// This limit is set to 175 by default in the Makibox configuration and it can adjusted +// to increase the heat up rate. However, if changed, user must be aware of the safety concerns +// of drawing too much current from the power supply. #ifdef PIDTEMPBED //120v 250W silicone heater into 4mm borosilicate (MendelMax 1.5+) From 8b4c4aa5c3b37da0c28e3edd9bf618febb980f0b Mon Sep 17 00:00:00 2001 From: daid Date: Thu, 1 May 2014 12:03:41 +0200 Subject: [PATCH 241/256] Add feature to check&retry CRC read errors on SD. --- Marlin/Configuration.h | 1 + Marlin/Sd2Card.cpp | 84 +++++++++++++++++++++++++++++++++++++++++- Marlin/Sd2Card.h | 2 + Marlin/stepper.cpp | 2 +- Marlin/ultralcd.cpp | 1 + 5 files changed, 88 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index e18c98a437..ea083945ee 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -484,6 +484,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of //#define DOGLCD // Support for SPI LCD 128x64 (Controller ST7565R graphic Display Family) //#define SDSUPPORT // Enable SD Card Support in Hardware Console //#define SDSLOW // Use slower SD transfer mode (not normally needed - uncomment if you're getting volume init error) +//#define SD_CHECK_AND_RETRY // Use CRC checks and retries on the SD communication //#define ENCODER_PULSES_PER_STEP 1 // Increase if you have a high resolution encoder //#define ENCODER_STEPS_PER_MENU_ITEM 5 // Set according to ENCODER_PULSES_PER_STEP or your liking //#define ULTIMAKERCONTROLLER //as available from the Ultimaker online store. diff --git a/Marlin/Sd2Card.cpp b/Marlin/Sd2Card.cpp index 72f5661d86..69ae777358 100644 --- a/Marlin/Sd2Card.cpp +++ b/Marlin/Sd2Card.cpp @@ -373,6 +373,29 @@ bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { * the value zero, false, is returned for failure. */ bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) { +#ifdef SD_CHECK_AND_RETRY + uint8_t retryCnt = 3; + // use address if not SDHC card + if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9; + retry2: + retryCnt --; + if (cardCommand(CMD17, blockNumber)) { + error(SD_CARD_ERROR_CMD17); + if (retryCnt > 0) goto retry; + goto fail; + } + if (!readData(dst, 512)) + { + if (retryCnt > 0) goto retry; + goto fail; + } + return true; + retry: + chipSelectHigh(); + cardCommand(CMD12, 0);//Try sending a stop command, but ignore the result. + errorCode_ = 0; + goto retry2; +#else // use address if not SDHC card if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9; if (cardCommand(CMD17, blockNumber)) { @@ -380,6 +403,7 @@ bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) { goto fail; } return readData(dst, 512); +#endif fail: chipSelectHigh(); @@ -397,6 +421,51 @@ bool Sd2Card::readData(uint8_t *dst) { chipSelectLow(); return readData(dst, 512); } + +#ifdef SD_CHECK_AND_RETRY +static const uint16_t crctab[] PROGMEM = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 +}; +static uint16_t CRC_CCITT(const uint8_t* data, size_t n) { + uint16_t crc = 0; + for (size_t i = 0; i < n; i++) { + crc = pgm_read_word(&crctab[(crc >> 8 ^ data[i]) & 0XFF]) ^ (crc << 8); + } + return crc; +} +#endif + //------------------------------------------------------------------------------ bool Sd2Card::readData(uint8_t* dst, uint16_t count) { // wait for start block token @@ -414,9 +483,22 @@ bool Sd2Card::readData(uint8_t* dst, uint16_t count) { // transfer data spiRead(dst, count); +#ifdef SD_CHECK_AND_RETRY + { + uint16_t calcCrc = CRC_CCITT(dst, count); + uint16_t recvCrc = spiRec() << 8; + recvCrc |= spiRec(); + if (calcCrc != recvCrc) + { + error(SD_CARD_ERROR_CRC); + goto fail; + } + } +#else // discard CRC spiRec(); spiRec(); +#endif chipSelectHigh(); return true; @@ -638,4 +720,4 @@ bool Sd2Card::writeStop() { return false; } -#endif +#endif diff --git a/Marlin/Sd2Card.h b/Marlin/Sd2Card.h index 7de5f11bcc..d6b302bfed 100644 --- a/Marlin/Sd2Card.h +++ b/Marlin/Sd2Card.h @@ -103,6 +103,8 @@ uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X17; uint8_t const SD_CARD_ERROR_SCK_RATE = 0X18; /** init() not called */ uint8_t const SD_CARD_ERROR_INIT_NOT_CALLED = 0X19; +/** crc check error */ +uint8_t const SD_CARD_ERROR_CRC = 0X20; //------------------------------------------------------------------------------ // card types /** Standard capacity V1 SD card */ diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index eaba4362dc..875400be18 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -191,7 +191,7 @@ void checkHitEndstops() endstop_x_hit=false; endstop_y_hit=false; endstop_z_hit=false; -#ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED +#if defined(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) && defined(SDSUPPORT) if (abort_on_endstop_hit) { card.sdprinting = false; diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 4c8df66deb..b3bf9816f6 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -194,6 +194,7 @@ static void lcd_status_screen() currentMenu = lcd_main_menu; encoderPosition = 0; lcd_quick_feedback(); + lcd_implementation_init(); // to maybe revive the LCD if static electricity killed it. } #ifdef ULTIPANEL_FEEDMULTIPLY From 9db9842aeabe76f78bfda67fac89b75a531bb0b7 Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Wed, 14 May 2014 21:59:48 +0200 Subject: [PATCH 242/256] Fixed error found by the free coverity tool (https://scan.coverity.com/) =================================================== Hi, Please find the latest report on new defect(s) introduced to ErikZalm/Marlin found with Coverity Scan. Defect(s) Reported-by: Coverity Scan Showing 15 of 15 defect(s) ** CID 59629: Unchecked return value (CHECKED_RETURN) /Marlin_main.cpp: 2154 in process_commands()() ** CID 59630: Operands don't affect result (CONSTANT_EXPRESSION_RESULT) /Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino/Tone.cpp: 319 in tone(unsigned char, unsigned int, unsigned long)() ** CID 59631: Missing break in switch (MISSING_BREAK) /Marlin_main.cpp: 1187 in process_commands()() ** CID 59632: Missing break in switch (MISSING_BREAK) /Marlin_main.cpp: 1193 in process_commands()() ** CID 59633: Out-of-bounds write (OVERRUN) /temperature.cpp: 914 in disable_heater()() ** CID 59634: Out-of-bounds write (OVERRUN) /temperature.cpp: 913 in disable_heater()() ** CID 59635: Out-of-bounds read (OVERRUN) /temperature.cpp: 626 in analog2temp(int, unsigned char)() ** CID 59636: Out-of-bounds read (OVERRUN) /temperature.cpp: 620 in analog2temp(int, unsigned char)() ** CID 59637: Out-of-bounds write (OVERRUN) /temperature.cpp: 202 in PID_autotune(float, int, int)() ** CID 59638: Out-of-bounds read (OVERRUN) /temperature.cpp: 214 in PID_autotune(float, int, int)() ** CID 59639: Out-of-bounds write (OVERRUN) /Marlin_main.cpp: 2278 in process_commands()() ** CID 59640: Out-of-bounds read (OVERRUN) /Marlin_main.cpp: 1802 in process_commands()() ** CID 59641: Uninitialized scalar field (UNINIT_CTOR) /Applications/Arduino.app/Contents/Resources/Java/libraries/LiquidCrystal/LiquidCrystal.cpp: 51 in LiquidCrystal::LiquidCrystal(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char)() ** CID 59642: Uninitialized scalar field (UNINIT_CTOR) /Applications/Arduino.app/Contents/Resources/Java/libraries/LiquidCrystal/LiquidCrystal.cpp: 45 in LiquidCrystal::LiquidCrystal(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char)() ** CID 59643: Uninitialized scalar field (UNINIT_CTOR) /Applications/Arduino.app/Contents/Resources/Java/libraries/LiquidCrystal/LiquidCrystal.cpp: 32 in LiquidCrystal::LiquidCrystal(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char)() ________________________________________________________________________________________________________ *** CID 59629: Unchecked return value (CHECKED_RETURN) /Marlin_main.cpp: 2154 in process_commands()() 2148 } 2149 #endif 2150 } 2151 } 2152 break; 2153 case 85: // M85 CID 59629: Unchecked return value (CHECKED_RETURN) Calling "code_seen" without checking return value (as is done elsewhere 66 out of 67 times). 2154 code_seen('S'); 2155 max_inactive_time = code_value() * 1000; 2156 break; 2157 case 92: // M92 2158 for(int8_t i=0; i < NUM_AXIS; i++) 2159 { ________________________________________________________________________________________________________ *** CID 59630: Operands don't affect result (CONSTANT_EXPRESSION_RESULT) /Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino/Tone.cpp: 319 in tone(unsigned char, unsigned int, unsigned long)() 313 else 314 { 315 // two choices for the 16 bit timers: ck/1 or ck/64 316 ocr = F_CPU / frequency / 2 - 1; 317 318 prescalarbits = 0b001; CID 59630: Operands don't affect result (CONSTANT_EXPRESSION_RESULT) "ocr > 65535U" is always false regardless of the values of its operands. This occurs as the logical operand of if. 319 if (ocr > 0xffff) 320 { 321 ocr = F_CPU / frequency / 2 / 64 - 1; 322 prescalarbits = 0b011; 323 } 324 ________________________________________________________________________________________________________ *** CID 59631: Missing break in switch (MISSING_BREAK) /Marlin_main.cpp: 1187 in process_commands()() 1181 case 2: // G2 - CW ARC 1182 if(Stopped == false) { 1183 get_arc_coordinates(); 1184 prepare_arc_move(true); 1185 return; 1186 } CID 59631: Missing break in switch (MISSING_BREAK) The above case falls through to this one. 1187 case 3: // G3 - CCW ARC 1188 if(Stopped == false) { 1189 get_arc_coordinates(); 1190 prepare_arc_move(false); 1191 return; 1192 } ________________________________________________________________________________________________________ *** CID 59632: Missing break in switch (MISSING_BREAK) /Marlin_main.cpp: 1193 in process_commands()() 1187 case 3: // G3 - CCW ARC 1188 if(Stopped == false) { 1189 get_arc_coordinates(); 1190 prepare_arc_move(false); 1191 return; 1192 } CID 59632: Missing break in switch (MISSING_BREAK) The above case falls through to this one. 1193 case 4: // G4 dwell 1194 LCD_MESSAGEPGM(MSG_DWELL); 1195 codenum = 0; 1196 if(code_seen('P')) codenum = code_value(); // milliseconds to wait 1197 if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait 1198 ________________________________________________________________________________________________________ *** CID 59633: Out-of-bounds write (OVERRUN) /temperature.cpp: 914 in disable_heater()() 908 WRITE(HEATER_0_PIN,LOW); 909 #endif 910 #endif 911 912 #if defined(TEMP_1_PIN) && TEMP_1_PIN > -1 913 target_temperature[1]=0; CID 59633: Out-of-bounds write (OVERRUN) Overrunning array "soft_pwm" of 1 bytes at byte offset 1 using index "1". 914 soft_pwm[1]=0; 915 #if defined(HEATER_1_PIN) && HEATER_1_PIN > -1 916 WRITE(HEATER_1_PIN,LOW); 917 #endif 918 #endif 919 ________________________________________________________________________________________________________ *** CID 59634: Out-of-bounds write (OVERRUN) /temperature.cpp: 913 in disable_heater()() 907 #if defined(HEATER_0_PIN) && HEATER_0_PIN > -1 908 WRITE(HEATER_0_PIN,LOW); 909 #endif 910 #endif 911 912 #if defined(TEMP_1_PIN) && TEMP_1_PIN > -1 CID 59634: Out-of-bounds write (OVERRUN) Overrunning array "target_temperature" of 1 2-byte elements at element index 1 (byte offset 2) using index "1". 913 target_temperature[1]=0; 914 soft_pwm[1]=0; 915 #if defined(HEATER_1_PIN) && HEATER_1_PIN > -1 916 WRITE(HEATER_1_PIN,LOW); 917 #endif 918 #endif ________________________________________________________________________________________________________ *** CID 59635: Out-of-bounds read (OVERRUN) /temperature.cpp: 626 in analog2temp(int, unsigned char)() 620 if(heater_ttbl_map[e] != NULL) 621 { 622 float celsius = 0; 623 uint8_t i; 624 short (*tt)[][2] = (short (*)[][2])(heater_ttbl_map[e]); 625 CID 59635: Out-of-bounds read (OVERRUN) Overrunning array "heater_ttbllen_map" of 1 bytes at byte offset 1 using index "e" (which evaluates to 1). 626 for (i=1; i raw) 629 { 630 celsius = PGM_RD_W((*tt)[i-1][1]) + 631 (raw - PGM_RD_W((*tt)[i-1][0])) * ________________________________________________________________________________________________________ *** CID 59636: Out-of-bounds read (OVERRUN) /temperature.cpp: 620 in analog2temp(int, unsigned char)() 614 if (e == 0) 615 { 616 return 0.25 * raw; 617 } 618 #endif 619 CID 59636: Out-of-bounds read (OVERRUN) Overrunning array "heater_ttbl_map" of 1 2-byte elements at element index 1 (byte offset 2) using index "e" (which evaluates to 1). 620 if(heater_ttbl_map[e] != NULL) 621 { 622 float celsius = 0; 623 uint8_t i; 624 short (*tt)[][2] = (short (*)[][2])(heater_ttbl_map[e]); 625 ________________________________________________________________________________________________________ *** CID 59637: Out-of-bounds write (OVERRUN) /temperature.cpp: 202 in PID_autotune(float, int, int)() 196 { 197 soft_pwm_bed = (MAX_BED_POWER)/2; 198 bias = d = (MAX_BED_POWER)/2; 199 } 200 else 201 { CID 59637: Out-of-bounds write (OVERRUN) Overrunning array "soft_pwm" of 1 bytes at byte offset 1 using index "extruder" (which evaluates to 1). 202 soft_pwm[extruder] = (PID_MAX)/2; 203 bias = d = (PID_MAX)/2; 204 } 205 206 207 ________________________________________________________________________________________________________ *** CID 59638: Out-of-bounds read (OVERRUN) /temperature.cpp: 214 in PID_autotune(float, int, int)() 208 209 for(;;) { 210 211 if(temp_meas_ready == true) { // temp sample ready 212 updateTemperaturesFromRawValues(); 213 CID 59638: Out-of-bounds read (OVERRUN) Overrunning array "current_temperature" of 1 4-byte elements at element index 1 (byte offset 4) using index "extruder" (which evaluates to 1). 214 input = (extruder<0)?current_temperature_bed:current_temperature[extruder]; 215 216 max=max(max,input); 217 min=min(min,input); 218 if(heating == true && input > temp) { 219 if(millis() - t2 > 5000) { ________________________________________________________________________________________________________ *** CID 59639: Out-of-bounds write (OVERRUN) /Marlin_main.cpp: 2278 in process_commands()() 2272 tmp_extruder = code_value(); 2273 if(tmp_extruder >= EXTRUDERS) { 2274 SERIAL_ECHO_START; 2275 SERIAL_ECHO(MSG_M200_INVALID_EXTRUDER); 2276 } 2277 } CID 59639: Out-of-bounds write (OVERRUN) Overrunning array "volumetric_multiplier" of 1 4-byte elements at element index 1 (byte offset 4) using index "tmp_extruder" (which evaluates to 1). 2278 volumetric_multiplier[tmp_extruder] = 1 / area; 2279 } 2280 break; 2281 case 201: // M201 2282 for(int8_t i=0; i < NUM_AXIS; i++) 2283 { ________________________________________________________________________________________________________ *** CID 59640: Out-of-bounds read (OVERRUN) /Marlin_main.cpp: 1802 in process_commands()() 1796 int pin_status = code_value(); 1797 int pin_number = LED_PIN; 1798 if (code_seen('P') && pin_status >= 0 && pin_status <= 255) 1799 pin_number = code_value(); 1800 for(int8_t i = 0; i < (int8_t)sizeof(sensitive_pins); i++) 1801 { CID 59640: Out-of-bounds read (OVERRUN) Overrunning array "sensitive_pins" of 28 2-byte elements at element index 55 (byte offset 110) using index "i" (which evaluates to 55). 1802 if (sensitive_pins[i] == pin_number) 1803 { 1804 pin_number = -1; 1805 break; 1806 } 1807 } ________________________________________________________________________________________________________ *** CID 59641: Uninitialized scalar field (UNINIT_CTOR) /Applications/Arduino.app/Contents/Resources/Java/libraries/LiquidCrystal/LiquidCrystal.cpp: 51 in LiquidCrystal::LiquidCrystal(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char)() 45 } 46 47 LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable, 48 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) 49 { 50 init(1, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0); CID 59641: Uninitialized scalar field (UNINIT_CTOR) Non-static class member "_initialized" is not initialized in this constructor nor in any functions that it calls. 51 } 52 53 void LiquidCrystal::init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable, 54 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3, 55 uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7) 56 { ________________________________________________________________________________________________________ *** CID 59642: Uninitialized scalar field (UNINIT_CTOR) /Applications/Arduino.app/Contents/Resources/Java/libraries/LiquidCrystal/LiquidCrystal.cpp: 45 in LiquidCrystal::LiquidCrystal(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char)() 39 } 40 41 LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable, 42 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) 43 { 44 init(1, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0); CID 59642: Uninitialized scalar field (UNINIT_CTOR) Non-static class member "_initialized" is not initialized in this constructor nor in any functions that it calls. 45 } 46 47 LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable, 48 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) 49 { 50 init(1, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0); ________________________________________________________________________________________________________ *** CID 59643: Uninitialized scalar field (UNINIT_CTOR) /Applications/Arduino.app/Contents/Resources/Java/libraries/LiquidCrystal/LiquidCrystal.cpp: 32 in LiquidCrystal::LiquidCrystal(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char)() 26 27 LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable, 28 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3, 29 uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7) 30 { 31 init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7); CID 59643: Uninitialized scalar field (UNINIT_CTOR) Non-static class member "_initialized" is not initialized in this constructor nor in any functions that it calls. 32 } 33 34 LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable, 35 uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3, 36 uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7) 37 { ________________________________________________________________________________________________________ To view the defects in Coverity Scan visit, http://scan.coverity.com/projects/2224?tab=overview --- Marlin/Marlin_main.cpp | 12 ++++++++---- Marlin/temperature.cpp | 6 +++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 420bd00abb..ebc36bc1af 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1177,19 +1177,21 @@ void process_commands() //ClearToSend(); return; } - //break; + break; case 2: // G2 - CW ARC if(Stopped == false) { get_arc_coordinates(); prepare_arc_move(true); return; } + break; case 3: // G3 - CCW ARC if(Stopped == false) { get_arc_coordinates(); prepare_arc_move(false); return; } + break; case 4: // G4 dwell LCD_MESSAGEPGM(MSG_DWELL); codenum = 0; @@ -1797,7 +1799,7 @@ void process_commands() int pin_number = LED_PIN; if (code_seen('P') && pin_status >= 0 && pin_status <= 255) pin_number = code_value(); - for(int8_t i = 0; i < (int8_t)sizeof(sensitive_pins); i++) + for(int8_t i = 0; i < (int8_t)(sizeof(sensitive_pins)/sizeof(int)); i++) { if (sensitive_pins[i] == pin_number) { @@ -2151,8 +2153,9 @@ void process_commands() } break; case 85: // M85 - code_seen('S'); - max_inactive_time = code_value() * 1000; + if(code_seen('S')) { + max_inactive_time = code_value() * 1000; + } break; case 92: // M92 for(int8_t i=0; i < NUM_AXIS; i++) @@ -2273,6 +2276,7 @@ void process_commands() if(tmp_extruder >= EXTRUDERS) { SERIAL_ECHO_START; SERIAL_ECHO(MSG_M200_INVALID_EXTRUDER); + break; } } volumetric_multiplier[tmp_extruder] = 1 / area; diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index 737d075754..a199f4e742 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -179,7 +179,7 @@ void PID_autotune(float temp, int extruder, int ncycles) float Kp, Ki, Kd; float max = 0, min = 10000; - if ((extruder > EXTRUDERS) + if ((extruder >= EXTRUDERS) #if (TEMP_BED_PIN <= -1) ||(extruder < 0) #endif @@ -909,7 +909,7 @@ void disable_heater() #endif #endif - #if defined(TEMP_1_PIN) && TEMP_1_PIN > -1 + #if defined(TEMP_1_PIN) && TEMP_1_PIN > -1 && EXTRUDERS > 1 target_temperature[1]=0; soft_pwm[1]=0; #if defined(HEATER_1_PIN) && HEATER_1_PIN > -1 @@ -917,7 +917,7 @@ void disable_heater() #endif #endif - #if defined(TEMP_2_PIN) && TEMP_2_PIN > -1 + #if defined(TEMP_2_PIN) && TEMP_2_PIN > -1 && EXTRUDERS > 2 target_temperature[2]=0; soft_pwm[2]=0; #if defined(HEATER_2_PIN) && HEATER_2_PIN > -1 From 92e14298b008bf591e1f0317a5b53ab812988073 Mon Sep 17 00:00:00 2001 From: zaubara Date: Thu, 15 May 2014 01:37:23 +0200 Subject: [PATCH 243/256] Fixes typo for lcd backlighting on I2C PCF8575 When using LCD_I2C_TYPE_PCF8575T (like Sainsmart I2C), the backlight won't come on; the incorrect ifdef blocks the evocation of the backlight functions. --- Marlin/ultralcd_implementation_hitachi_HD44780.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/ultralcd_implementation_hitachi_HD44780.h b/Marlin/ultralcd_implementation_hitachi_HD44780.h index 932895b9bb..11e0a95196 100644 --- a/Marlin/ultralcd_implementation_hitachi_HD44780.h +++ b/Marlin/ultralcd_implementation_hitachi_HD44780.h @@ -297,7 +297,7 @@ static void lcd_implementation_init() B00000 }; //thanks Sonny Mounicou -#if defined(LCDI2C_TYPE_PCF8575) +#if defined(LCD_I2C_TYPE_PCF8575) lcd.begin(LCD_WIDTH, LCD_HEIGHT); #ifdef LCD_I2C_PIN_BL lcd.setBacklightPin(LCD_I2C_PIN_BL,POSITIVE); From cfb98ef682be2ffb75e7d3d741afc721e054e391 Mon Sep 17 00:00:00 2001 From: Erik van der Zalm Date: Thu, 15 May 2014 22:09:50 +0200 Subject: [PATCH 244/256] More coverity fixes --- Marlin/Marlin_main.cpp | 2 +- Marlin/temperature.cpp | 1 + README.md | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index ebc36bc1af..53d829acf0 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -2468,7 +2468,7 @@ void process_commands() if(pin_state >= -1 && pin_state <= 1){ - for(int8_t i = 0; i < (int8_t)sizeof(sensitive_pins); i++) + for(int8_t i = 0; i < (int8_t)(sizeof(sensitive_pins)/sizeof(int)); i++) { if (sensitive_pins[i] == pin_number) { diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index a199f4e742..aac6ca66f5 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -609,6 +609,7 @@ static float analog2temp(int raw, uint8_t e) { SERIAL_ERROR((int)e); SERIAL_ERRORLNPGM(" - Invalid extruder number !"); kill(); + return 0.0; } #ifdef HEATER_0_USES_MAX6675 if (e == 0) diff --git a/README.md b/README.md index 94552684ea..0b955540ff 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ ========================== Marlin 3D Printer Firmware ========================== +[![Coverity Scan Build Status](https://scan.coverity.com/projects/2224/badge.svg)](https://scan.coverity.com/projects/2224) + Marlin has a GPL license because I believe in open development. Please do not use this code in products (3D printers, CNC etc) that are closed source or are crippled by a patent. From 38192cb5f3e5f55ee7805faef90cf374ba335495 Mon Sep 17 00:00:00 2001 From: nothinman Date: Tue, 20 May 2014 15:20:19 +0100 Subject: [PATCH 245/256] Add M112 description to Marlin_main --- Marlin/Marlin_main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 916f0c8c4d..c4afca7f68 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -119,6 +119,7 @@ // M109 - Sxxx Wait for extruder current temp to reach target temp. Waits only when heating // Rxxx Wait for extruder current temp to reach target temp. Waits when heating and cooling // IF AUTOTEMP is enabled, S B F. Exit autotemp by any M109 without F +// M112 - Emergency stop // M114 - Output current position to serial port // M115 - Capabilities string // M117 - display message From 09b84faa00485a2299e09146825af137743635de Mon Sep 17 00:00:00 2001 From: David Forrest Date: Fri, 10 Jan 2014 15:23:30 -0500 Subject: [PATCH 246/256] Configuration.h, pins.h: Add MOTHERBOARD 84 for Teensy++2.0 --- Marlin/Configuration.h | 1 + Marlin/pins.h | 125 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 4570e34e2c..537ff7a295 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -62,6 +62,7 @@ // 81 = Printrboard (AT90USB1286) // 82 = Brainwave (AT90USB646) // 83 = SAV Mk-I (AT90USB1286) +// 84 = Teensy++2.0 (AT90USB1286) // CLI compile: DEFINES=AT90USBxx_TEENSYPP_ASSIGNMENTS HARDWARE_MOTHERBOARD=84 make // 9 = Gen3+ // 70 = Megatronics // 701= Megatronics v2.0 diff --git a/Marlin/pins.h b/Marlin/pins.h index 14eff02ccb..c3644a086a 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -1650,6 +1650,10 @@ #error Oops! Make sure you have 'Teensy++ 2.0' selected from the 'Tools -> Boards' menu. #endif +#ifdef AT90USBxx_TEENSYPP_ASSIGNMENTS // use Teensyduino Teensy++2.0 pin assignments instead of Marlin traditional. +#error These Teensylu/Printrboard assignments depend on traditional Marlin assignments, not AT90USBxx_TEENSYPP_ASSIGNMENTS in fastio.h +#endif + #define LARGE_FLASH true #define X_STEP_PIN 0 @@ -1857,6 +1861,127 @@ #endif // MOTHERBOARD == 83 +/**************************************************************************************** +* Teensy++ 2.0 Breadboard pin assignments (AT90USB1286) +* Requires the Teensyduino software with Teensy++ 2.0 selected in Arduino IDE! + http://www.pjrc.com/teensy/teensyduino.html +* See http://reprap.org/wiki/Printrboard for more info +* CLI build: DEFINES=AT90USBxx_TEENSYPP_ASSIGNMENTS HARDWARE_MOTHERBOARD=84 make +* +****************************************************************************************/ +#if MOTHERBOARD == 84 +#define KNOWN_BOARD 1 +#define AT90USB 1286 // Disable MarlinSerial etc. + +#ifndef __AVR_AT90USB1286__ +#error Oops! Make sure you have 'Teensy++ 2.0' selected from the 'Tools -> Boards' menu. +#endif + +#define LARGE_FLASH true + +/* +DaveX plan for Teensylu/printrboard-type pinouts (ref teensylu & sprinter) for a TeensyBreadboard: + + USB + GND GND |-----#####-----| +5V ATX +5SB + ATX PS_ON PWM 27 |b7 ##### b6| 26 PWM* Stepper Enable + PWM 0 |d0 b5| 25 PWM* + PWM 1 |d1 b4| 24 PWM + X_MIN 2 |d2 b3| 23 MISO_PIN + Y_MIN 3 |d3 b2| 22 MOSI_PIN + Z_MIN 4 |d4 * * b1| 21 SCK_PIN + 5 |d5 e e b0| 20 SDSS + LED 6 |d6 5 4 e7| 19 + 7 |d7 e6| 18 + LCD RS 8 |e0 | GND + LCD EN 9 |e1 a4 a0 R| AREF + LCD D4 10 |c0 a5 a1 f0| 38 A0 ENC_1 + LCD D5 11 |c1 a6 a2 f1| 39 A1 ENC_2 + LCD D6 12 |c2 a7 a3 f2| 40 A2 ENC_CLK + LCD D6 13 |c3 f3| 41 A3 + Bed Heat PWM 14 |c4 V G R f4| 42 A4 + Extruder Heat PWM 15 |c5 c n S f5| 43 A5 + Fan PWM 16 |c6 c d T f6| 44 A6 Bed TC + 17 |c7 * * * f7| 45 A7 Extruder TC * 4.7k * +5 + ----------------- + + Interior E4: 36, INT4 + Interior E5: 37, INT5 + Interior PA0-7: 28-35 -- Printrboard and Teensylu use these pins for step & direction: + T++ PA Signal Marlin + + Z STEP 32 a4 a0 28 X STEP + Z DIR 33 a5 a1 29 X DIR + E STEP 34 a6 a2 30 Y STEP + E DIR 35 a7 a3 31 Y DIR + +*/ + +#ifndef AT90USBxx_TEENSYPP_ASSIGNMENTS // use Teensyduino Teensy++2.0 pin assignments instead of Marlin alphabetical. + #error Uncomment #define AT90USBxx_TEENSYPP_ASSIGNMENTS in fastio.h for this config + // or build from command line with: DEFINES=AT90USBxx_TEENSYPP_ASSIGNMENTS HARDWARE_MOTHERBOARD=84 make +#endif + +#define X_STEP_PIN 28 // 0 Marlin +#define X_DIR_PIN 29 // 1 Marlin +#define X_ENABLE_PIN 26 + +#define Y_STEP_PIN 30 // 2 Marlin +#define Y_DIR_PIN 31 // 3 +#define Y_ENABLE_PIN 26 // Shared w/x + +#define Z_STEP_PIN 32 // 4 +#define Z_DIR_PIN 33 // 5 +#define Z_ENABLE_PIN 26 // Shared w/x + +#define E0_STEP_PIN 34 // 6 +#define E0_DIR_PIN 35 // 7 +#define E0_ENABLE_PIN 26 // Shared w/x + +#define HEATER_0_PIN 15 // 21 // Extruder +#define HEATER_1_PIN -1 +#define HEATER_2_PIN -1 +#define HEATER_BED_PIN 14 // 20 // Bed +#define FAN_PIN 16 // 22 // Fan + +#define X_STOP_PIN 2 +#define Y_STOP_PIN 3 +#define Z_STOP_PIN 4 + +#define TEMP_0_PIN 7 // Extruder / Analog pin numbering +#define TEMP_BED_PIN 6 // Bed / Analog pin numbering +#define TEMP_1_PIN -1 +#define TEMP_2_PIN -1 + +#define SDPOWER -1 +#define SDCARDDETECT -1 +#define SDSS 20 // 8 +#define LED_PIN 6 +#define PS_ON_PIN 27 +#define KILL_PIN -1 +#define ALARM_PIN -1 + +#ifndef SDSUPPORT +// these pins are defined in the SD library if building with SD support + #define SCK_PIN 21 // 9 + #define MISO_PIN 23 // 11 + #define MOSI_PIN 22 // 10 +#endif + +#ifdef ULTIPANEL +#define LCD_PINS_RS 8 +#define LCD_PINS_ENABLE 9 +#define LCD_PINS_D4 10 +#define LCD_PINS_D5 11 +#define LCD_PINS_D6 12 +#define LCD_PINS_D7 13 +#define BTN_EN1 38 +#define BTN_EN2 39 +#define BTN_ENC 40 +#endif + +#endif // MOTHERBOARD == 84 (Teensy++2.0 Breadboard) + /**************************************************************************************** * Gen3+ pin assignment From 07c0eeee99d5d464f33e5d7f0920dc28719ffeeb Mon Sep 17 00:00:00 2001 From: Justin Nesselrotte Date: Sun, 1 Jun 2014 19:04:41 -0500 Subject: [PATCH 247/256] Fixed a comment in the planner --- Marlin/planner.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/planner.h b/Marlin/planner.h index 9df0174602..837199eb7a 100644 --- a/Marlin/planner.h +++ b/Marlin/planner.h @@ -151,7 +151,7 @@ FORCE_INLINE block_t *plan_get_current_block() return(block); } -// Gets the current block. Returns NULL if buffer empty +// Returns true if the buffer has a queued block, false otherwise FORCE_INLINE bool blocks_queued() { if (block_buffer_head == block_buffer_tail) { From 29e7639933e29feaf58bc657e80c47e88716b02b Mon Sep 17 00:00:00 2001 From: Dim3nsioneer Date: Mon, 2 Jun 2014 08:13:09 +0200 Subject: [PATCH 248/256] Add switch unused feeder(s) off Having the non-active feeder motors powered on all the time is not necessary. A feature to deactivate the unused feeder motors has been implemented. The feature is enabled on default but can be switched off in the configuration. --- Marlin/Configuration.h | 1 + Marlin/planner.cpp | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 537ff7a295..5ee06d7108 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -305,6 +305,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #define DISABLE_Y false #define DISABLE_Z false #define DISABLE_E false // For all extruders +#define DISABLE_UNSELECTED_E true //disable only not selected extruders and keep selected extruder active #define INVERT_X_DIR true // for Mendel set to false, for Orca set to true #define INVERT_Y_DIR false // for Mendel set to true, for Orca set to false diff --git a/Marlin/planner.cpp b/Marlin/planner.cpp index bfc71323fe..db53a02cb2 100644 --- a/Marlin/planner.cpp +++ b/Marlin/planner.cpp @@ -657,12 +657,24 @@ block->steps_y = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-positi if(block->steps_z != 0) enable_z(); #endif - // Enable all + // Enable extruder(s) if(block->steps_e != 0) { - enable_e0(); - enable_e1(); - enable_e2(); + if (DISABLE_UNSELECTED_E) //enable only selected extruder + { + switch(extruder) + { + case 0: enable_e0(); disable_e1(); disable_e2(); break; + case 1: disable_e0(); enable_e1(); disable_e2(); break; + case 2: disable_e0(); disable_e1(); enable_e2(); break; + } + } + else //enable all + { + enable_e0(); + enable_e1(); + enable_e2(); + } } if (block->steps_e == 0) From 8a32c5395bb51e06819716d02d3e57c44655f917 Mon Sep 17 00:00:00 2001 From: Dim3nsioneer Date: Mon, 2 Jun 2014 14:07:02 +0200 Subject: [PATCH 249/256] renaming the disable inactive extruder feature --- Marlin/Configuration.h | 2 +- Marlin/planner.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 5ee06d7108..1355a7ab9f 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -305,7 +305,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of #define DISABLE_Y false #define DISABLE_Z false #define DISABLE_E false // For all extruders -#define DISABLE_UNSELECTED_E true //disable only not selected extruders and keep selected extruder active +#define DISABLE_INACTIVE_EXTRUDER true //disable only inactive extruders and keep active extruder enabled #define INVERT_X_DIR true // for Mendel set to false, for Orca set to true #define INVERT_Y_DIR false // for Mendel set to true, for Orca set to false diff --git a/Marlin/planner.cpp b/Marlin/planner.cpp index db53a02cb2..5b20f86f99 100644 --- a/Marlin/planner.cpp +++ b/Marlin/planner.cpp @@ -660,7 +660,7 @@ block->steps_y = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-positi // Enable extruder(s) if(block->steps_e != 0) { - if (DISABLE_UNSELECTED_E) //enable only selected extruder + if (DISABLE_INACTIVE_EXTRUDER) //enable only selected extruder { switch(extruder) { From 0de826160ef590fbf2576d69299c8c4640fc9d94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 2 Jun 2014 17:11:32 +0200 Subject: [PATCH 250/256] M30 response is missing linefeed, "ok" therefore not on own line This leads to the command not being acknowledged properly by the firmware, leading to consecutive issues in host software waiting for an acknowledgement. --- Marlin/cardreader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index 5fb8dcc0ff..d2fb418fba 100644 --- a/Marlin/cardreader.cpp +++ b/Marlin/cardreader.cpp @@ -437,7 +437,7 @@ void CardReader::removeFile(char* name) if (file.remove(curDir, fname)) { SERIAL_PROTOCOLPGM("File deleted:"); - SERIAL_PROTOCOL(fname); + SERIAL_PROTOCOLLN(fname); sdpos = 0; } else From 6e6e4e214323c42f949ed86a67551f136fe41365 Mon Sep 17 00:00:00 2001 From: Greg Tan Date: Sun, 8 Jun 2014 09:35:04 +0800 Subject: [PATCH 251/256] Added thermistor table for the 500C thermistor shipped with the Pico hot end. --- Marlin/Configuration.h | 1 + Marlin/thermistortables.h | 75 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 1355a7ab9f..66bf69052d 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -132,6 +132,7 @@ // 1010 is Pt1000 with 1k pullup (non standard) // 147 is Pt100 with 4k7 pullup // 110 is Pt100 with 1k pullup (non standard) +// 70 is 500C thermistor for Pico hot end #define TEMP_SENSOR_0 -1 #define TEMP_SENSOR_1 -1 diff --git a/Marlin/thermistortables.h b/Marlin/thermistortables.h index 07b385e119..86bf5c2d4e 100644 --- a/Marlin/thermistortables.h +++ b/Marlin/thermistortables.h @@ -1021,6 +1021,81 @@ const short temptable_1047[][2] PROGMEM = { PtLine(300,1000,4700) }; #endif +#if (THERMISTORHEATER_0 == 70) || (THERMISTORHEATER_1 == 70) || (THERMISTORHEATER_2 == 70) || (THERMISTORBED == 70) // 500C thermistor for Pico hot end +const short temptable_70[][2] PROGMEM = { + { 110.774119598719*OVERSAMPLENR , 350 }, + { 118.214386957249*OVERSAMPLENR , 345 }, + { 126.211418543166*OVERSAMPLENR , 340 }, + { 134.789559066223*OVERSAMPLENR , 335 }, + { 144.004513869701*OVERSAMPLENR , 330 }, + { 153.884483790827*OVERSAMPLENR , 325 }, + { 164.484880793637*OVERSAMPLENR , 320 }, + { 175.848885102724*OVERSAMPLENR , 315 }, + { 188.006799079015*OVERSAMPLENR , 310 }, + { 201.008072969044*OVERSAMPLENR , 305 }, + { 214.83716032276*OVERSAMPLENR , 300 }, + { 229.784739779664*OVERSAMPLENR , 295 }, + { 245.499466045473*OVERSAMPLENR , 290 }, + { 262.2766342096*OVERSAMPLENR , 285 }, + { 280.073883176433*OVERSAMPLENR , 280 }, + { 298.952693467726*OVERSAMPLENR , 275 }, + { 318.808251051674*OVERSAMPLENR , 270 }, + { 337.490932563222*OVERSAMPLENR , 265 }, + { 361.683649122745*OVERSAMPLENR , 260 }, + { 384.717024083981*OVERSAMPLENR , 255 }, + { 408.659301759076*OVERSAMPLENR , 250 }, + { 433.471659455884*OVERSAMPLENR , 245 }, + { 459.199039926034*OVERSAMPLENR , 240 }, + { 485.566500982316*OVERSAMPLENR , 235 }, + { 512.538918631075*OVERSAMPLENR , 230 }, + { 539.980999544838*OVERSAMPLENR , 225 }, + { 567.783095549935*OVERSAMPLENR , 220 }, + { 595.698041673552*OVERSAMPLENR , 215 }, + { 623.633922319597*OVERSAMPLENR , 210 }, + { 651.356162750829*OVERSAMPLENR , 205 }, + { 678.700901620956*OVERSAMPLENR , 200 }, + { 705.528145361264*OVERSAMPLENR , 195 }, + { 731.61267976339*OVERSAMPLENR , 190 }, + { 756.786212184365*OVERSAMPLENR , 185 }, + { 780.950223357761*OVERSAMPLENR , 180 }, + { 804.012961595082*OVERSAMPLENR , 175 }, + { 825.904975939166*OVERSAMPLENR , 170 }, + { 846.403941639008*OVERSAMPLENR , 165 }, + { 865.52326974895*OVERSAMPLENR , 160 }, + { 883.246145367727*OVERSAMPLENR , 155 }, + { 899.5821946515*OVERSAMPLENR , 150 }, + { 914.544289228582*OVERSAMPLENR , 145 }, + { 928.145628221761*OVERSAMPLENR , 140 }, + { 940.422208546562*OVERSAMPLENR , 135 }, + { 951.456922916497*OVERSAMPLENR , 130 }, + { 961.303500633788*OVERSAMPLENR , 125 }, + { 970.044756889055*OVERSAMPLENR , 120 }, + { 977.761456230051*OVERSAMPLENR , 115 }, + { 984.540978083453*OVERSAMPLENR , 110 }, + { 990.440780765757*OVERSAMPLENR , 105 }, + { 995.589621465301*OVERSAMPLENR , 100 }, + { 1000.02514280144*OVERSAMPLENR , 95 }, + { 1003.84429789876*OVERSAMPLENR , 90 }, + { 1007.10199009318*OVERSAMPLENR , 85 }, + { 1009.87151698323*OVERSAMPLENR , 80 }, + { 1012.21633594237*OVERSAMPLENR , 75 }, + { 1014.18959892949*OVERSAMPLENR , 70 }, + { 1015.84079162998*OVERSAMPLENR , 65 }, + { 1017.21555915335*OVERSAMPLENR , 60 }, + { 1018.35284662863*OVERSAMPLENR , 55 }, + { 1019.28926921888*OVERSAMPLENR , 50 }, + { 1020.05398015669*OVERSAMPLENR , 45 }, + { 1020.67737496272*OVERSAMPLENR , 40 }, + { 1021.1802909627*OVERSAMPLENR , 35 }, + { 1021.58459281248*OVERSAMPLENR , 30 }, + { 1021.90701441192*OVERSAMPLENR , 25 }, + { 1022.16215103698*OVERSAMPLENR , 20 }, + { 1022.36275529549*OVERSAMPLENR , 15 }, + { 1022.51930392497*OVERSAMPLENR , 10 }, + { 1022.64051573734*OVERSAMPLENR , 5 }, + { 1022.73355805611*OVERSAMPLENR , 0 } +}; +#endif #define _TT_NAME(_N) temptable_ ## _N #define TT_NAME(_N) _TT_NAME(_N) From 86b4b805d25c004e71733dea7d40099f218ef6b4 Mon Sep 17 00:00:00 2001 From: Pablo Clemente Date: Thu, 12 Jun 2014 18:43:16 +0200 Subject: [PATCH 252/256] Fixed stop print LCD function on M104 --- Marlin/Marlin_main.cpp | 6 ++++-- Marlin/ultralcd.cpp | 3 +++ Marlin/ultralcd.h | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index c4afca7f68..a9a29dde60 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1945,14 +1945,16 @@ void process_commands() /* See if we are heating up or cooling down */ target_direction = isHeatingHotend(tmp_extruder); // true if heating, false if cooling + + forced_heating_stop = true; #ifdef TEMP_RESIDENCY_TIME long residencyStart; residencyStart = -1; /* continue to loop until we have reached the target temp _and_ until TEMP_RESIDENCY_TIME hasn't passed since we reached it */ - while((residencyStart == -1) || - (residencyStart >= 0 && (((unsigned int) (millis() - residencyStart)) < (TEMP_RESIDENCY_TIME * 1000UL))) ) { + while((forced_heating_stop == true)&&((residencyStart == -1) || + (residencyStart >= 0 && (((unsigned int) (millis() - residencyStart)) < (TEMP_RESIDENCY_TIME * 1000UL)))) ) { #else while ( target_direction ? (isHeatingHotend(tmp_extruder)) : (isCoolingHotend(tmp_extruder)&&(CooldownNoWait==false)) ) { #endif //TEMP_RESIDENCY_TIME diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index f09dd410d6..4f5aaac998 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -19,6 +19,7 @@ int absPreheatHotendTemp; int absPreheatHPBTemp; int absPreheatFanSpeed; +boolean forced_heating_stop = true ; #ifdef ULTIPANEL static float manual_feedrate[] = MANUAL_FEEDRATE; @@ -256,6 +257,8 @@ static void lcd_sdcard_stop() enquecommand_P(PSTR(SD_FINISHED_RELEASECOMMAND)); } autotempShutdown(); + + forced_heating_stop = false; } /* Menu implementation */ diff --git a/Marlin/ultralcd.h b/Marlin/ultralcd.h index f4570f6a58..b4195f3975 100644 --- a/Marlin/ultralcd.h +++ b/Marlin/ultralcd.h @@ -42,6 +42,8 @@ extern int absPreheatHotendTemp; extern int absPreheatHPBTemp; extern int absPreheatFanSpeed; + + extern boolean forced_heating_stop; void lcd_buzz(long duration,uint16_t freq); bool lcd_clicked(); From cd3220d055cee14f9feb6f483d992cce80d03a87 Mon Sep 17 00:00:00 2001 From: Pablo Clemente Date: Fri, 13 Jun 2014 08:39:58 +0200 Subject: [PATCH 253/256] Inverted state logic for forced_heating_stop variable --- Marlin/Marlin_main.cpp | 4 ++-- Marlin/ultralcd.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index a9a29dde60..315a9bb481 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1946,14 +1946,14 @@ void process_commands() /* See if we are heating up or cooling down */ target_direction = isHeatingHotend(tmp_extruder); // true if heating, false if cooling - forced_heating_stop = true; + forced_heating_stop = false; #ifdef TEMP_RESIDENCY_TIME long residencyStart; residencyStart = -1; /* continue to loop until we have reached the target temp _and_ until TEMP_RESIDENCY_TIME hasn't passed since we reached it */ - while((forced_heating_stop == true)&&((residencyStart == -1) || + while((forced_heating_stop == false)&&((residencyStart == -1) || (residencyStart >= 0 && (((unsigned int) (millis() - residencyStart)) < (TEMP_RESIDENCY_TIME * 1000UL)))) ) { #else while ( target_direction ? (isHeatingHotend(tmp_extruder)) : (isCoolingHotend(tmp_extruder)&&(CooldownNoWait==false)) ) { diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 4f5aaac998..289b84e969 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -19,7 +19,7 @@ int absPreheatHotendTemp; int absPreheatHPBTemp; int absPreheatFanSpeed; -boolean forced_heating_stop = true ; +boolean forced_heating_stop = false ; #ifdef ULTIPANEL static float manual_feedrate[] = MANUAL_FEEDRATE; @@ -258,7 +258,7 @@ static void lcd_sdcard_stop() } autotempShutdown(); - forced_heating_stop = false; + forced_heating_stop = true; } /* Menu implementation */ From d86c3cf43c6ee542d2f47db091b04f633c1fcf46 Mon Sep 17 00:00:00 2001 From: Pablo Clemente Date: Mon, 30 Jun 2014 15:12:13 +0200 Subject: [PATCH 254/256] Changed the type of variable to bool, the name to "cancel_heatup", flags implementation and added this fix to M190 gcode too. --- Marlin/Marlin_main.cpp | 9 +++++---- Marlin/ultralcd.cpp | 6 +++--- Marlin/ultralcd.h | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 315a9bb481..3e44168208 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1946,14 +1946,14 @@ void process_commands() /* See if we are heating up or cooling down */ target_direction = isHeatingHotend(tmp_extruder); // true if heating, false if cooling - forced_heating_stop = false; + cancel_heatup = false; #ifdef TEMP_RESIDENCY_TIME long residencyStart; residencyStart = -1; /* continue to loop until we have reached the target temp _and_ until TEMP_RESIDENCY_TIME hasn't passed since we reached it */ - while((forced_heating_stop == false)&&((residencyStart == -1) || + while((!cancel_heatup)&&((residencyStart == -1) || (residencyStart >= 0 && (((unsigned int) (millis() - residencyStart)) < (TEMP_RESIDENCY_TIME * 1000UL)))) ) { #else while ( target_direction ? (isHeatingHotend(tmp_extruder)) : (isCoolingHotend(tmp_extruder)&&(CooldownNoWait==false)) ) { @@ -2010,10 +2010,11 @@ void process_commands() CooldownNoWait = false; } codenum = millis(); - + + cancel_heatup = false; target_direction = isHeatingBed(); // true if heating, false if cooling - while ( target_direction ? (isHeatingBed()) : (isCoolingBed()&&(CooldownNoWait==false)) ) + while ( (target_direction)&&(!cancel_heatup) ? (isHeatingBed()) : (isCoolingBed()&&(CooldownNoWait==false)) ) { if(( millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. { diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 289b84e969..bb7dd0faa8 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -19,7 +19,7 @@ int absPreheatHotendTemp; int absPreheatHPBTemp; int absPreheatFanSpeed; -boolean forced_heating_stop = false ; +bool cancel_heatup = false ; #ifdef ULTIPANEL static float manual_feedrate[] = MANUAL_FEEDRATE; @@ -195,7 +195,7 @@ static void lcd_status_screen() currentMenu = lcd_main_menu; encoderPosition = 0; lcd_quick_feedback(); - lcd_implementation_init(); // to maybe revive the LCD if static electricity killed it. + lcd_implementation_init(); // to maybe revive the LCD if static electricity killed it. } #ifdef ULTIPANEL_FEEDMULTIPLY @@ -258,7 +258,7 @@ static void lcd_sdcard_stop() } autotempShutdown(); - forced_heating_stop = true; + cancel_heatup = true; } /* Menu implementation */ diff --git a/Marlin/ultralcd.h b/Marlin/ultralcd.h index b4195f3975..9bf685805d 100644 --- a/Marlin/ultralcd.h +++ b/Marlin/ultralcd.h @@ -43,7 +43,7 @@ extern int absPreheatHPBTemp; extern int absPreheatFanSpeed; - extern boolean forced_heating_stop; + extern bool cancel_heatup; void lcd_buzz(long duration,uint16_t freq); bool lcd_clicked(); From 43c298a7a9674bade1395a75fe54667cdb22fce4 Mon Sep 17 00:00:00 2001 From: alexborro Date: Mon, 30 Jun 2014 15:22:37 -0300 Subject: [PATCH 255/256] Add "Thermal Runaway Protection" feature This is a feature to protect your printer from burn up in flames if it has a thermistor coming off place (this happened to a friend of mine recently and motivated me writing this feature). The issue: If a thermistor come off, it will read a lower temperature than actual. The system will turn the heater on forever, burning up the filament and anything else around. After the temperature reaches the target for the first time, this feature will start measuring for how long the current temperature stays below the target minus _HYSTERESIS (set_temperature - THERMAL_RUNAWAY_PROTECTION_HYSTERESIS). If it stays longer than _PERIOD, it means the thermistor temperature cannot catch up with the target, so something *may be* wrong. Then, to be on the safe side, the system will he halt. Bear in mind the count down will just start AFTER the first time the thermistor temperature is over the target, so you will have no problem if your extruder heater takes 2 minutes to hit the target on heating. --- Marlin/Configuration.h | 38 +++++++++++++++++++++++ Marlin/temperature.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++ Marlin/temperature.h | 11 +++++++ 3 files changed, 117 insertions(+) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 66bf69052d..46d6b96dd1 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -251,6 +251,44 @@ #define EXTRUDE_MINTEMP 170 #define EXTRUDE_MAXLENGTH (X_MAX_LENGTH+Y_MAX_LENGTH) //prevent extrusion of very large distances. +/*================== Thermal Runaway Protection ============================== +This is a feature to protect your printer from burn up in flames if it has +a thermistor coming off place (this happened to a friend of mine recently and +motivated me writing this feature). + +The issue: If a thermistor come off, it will read a lower temperature than actual. +The system will turn the heater on forever, burning up the filament and anything +else around. + +After the temperature reaches the target for the first time, this feature will +start measuring for how long the current temperature stays below the target +minus _HYSTERESIS (set_temperature - THERMAL_RUNAWAY_PROTECTION_HYSTERESIS). + +If it stays longer than _PERIOD, it means the thermistor temperature +cannot catch up with the target, so something *may be* wrong. Then, to be on the +safe side, the system will he halt. + +Bear in mind the count down will just start AFTER the first time the +thermistor temperature is over the target, so you will have no problem if +your extruder heater takes 2 minutes to hit the target on heating. + +*/ +// If you want to enable this feature for all your extruder heaters, +// uncomment the 2 defines below: + +// Parameters for all extruder heaters +//#define THERMAL_RUNAWAY_PROTECTION_PERIOD 40 //in seconds +//#define THERMAL_RUNAWAY_PROTECTION_HYSTERESIS 4 // in degree Celsius + +// If you want to enable this feature for your bed heater, +// uncomment the 2 defines below: + +// Parameters for the bed heater +//#define THERMAL_RUNAWAY_PROTECTION_BED_PERIOD 20 //in seconds +//#define THERMAL_RUNAWAY_PROTECTION_BED_HYSTERESIS 2 // in degree Celsius +//=========================================================================== + + //=========================================================================== //=============================Mechanical Settings=========================== //=========================================================================== diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index aac6ca66f5..a10c255af9 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -416,6 +416,10 @@ void manage_heater() for(int e = 0; e < EXTRUDERS; e++) { + #ifdef THERMAL_RUNAWAY_PROTECTION_PERIOD && THERMAL_RUNAWAY_PROTECTION_PERIOD > 0 + thermal_runaway_protection(&thermal_runaway_state_machine[e], &thermal_runaway_timer[e], current_temperature[e], target_temperature[e], e, THERMAL_RUNAWAY_PROTECTION_PERIOD, THERMAL_RUNAWAY_PROTECTION_HYSTERESIS); + #endif + #ifdef PIDTEMP pid_input = current_temperature[e]; @@ -526,6 +530,10 @@ void manage_heater() #if TEMP_SENSOR_BED != 0 + #ifdef THERMAL_RUNAWAY_PROTECTION_PERIOD && THERMAL_RUNAWAY_PROTECTION_PERIOD > 0 + thermal_runaway_protection(&thermal_runaway_bed_state_machine, &thermal_runaway_bed_timer, current_temperature_bed, target_temperature_bed, 9, THERMAL_RUNAWAY_PROTECTION_BED_PERIOD, THERMAL_RUNAWAY_PROTECTION_BED_HYSTERESIS); + #endif + #ifdef PIDTEMPBED pid_input = current_temperature_bed; @@ -896,6 +904,66 @@ void setWatch() #endif } +#ifdef THERMAL_RUNAWAY_PROTECTION_PERIOD && THERMAL_RUNAWAY_PROTECTION_PERIOD > 0 +void thermal_runaway_protection(int *state, unsigned long *timer, float temperature, float target_temperature, int heater_id, int period_seconds, int hysteresis_degc) +{ +/* + SERIAL_ECHO_START; + SERIAL_ECHO("Thermal Thermal Runaway Running. Heater ID:"); + SERIAL_ECHO(heater_id); + SERIAL_ECHO(" ; State:"); + SERIAL_ECHO(*state); + SERIAL_ECHO(" ; Timer:"); + SERIAL_ECHO(*timer); + SERIAL_ECHO(" ; Temperature:"); + SERIAL_ECHO(temperature); + SERIAL_ECHO(" ; Target Temp:"); + SERIAL_ECHO(target_temperature); + SERIAL_ECHOLN(""); +*/ + if ((target_temperature == 0) || thermal_runaway) + { + *state = 0; + *timer = 0; + return; + } + switch (*state) + { + case 0: // "Heater Inactive" state + if (target_temperature > 0) *state = 1; + break; + case 1: // "First Heating" state + if (temperature >= target_temperature) *state = 2; + break; + case 2: // "Temperature Stable" state + if (temperature >= (target_temperature - hysteresis_degc)) + { + *timer = millis(); + } + else if ( (millis() - *timer) > period_seconds*1000) + { + SERIAL_ERROR_START; + SERIAL_ERRORLNPGM("Thermal Runaway, system stopped! Heater_ID: "); + SERIAL_ERRORLN((int)heater_id); + LCD_ALERTMESSAGEPGM("THERMAL RUNAWAY"); + thermal_runaway = true; + while(1) + { + disable_heater(); + disable_x(); + disable_y(); + disable_z(); + disable_e0(); + disable_e1(); + disable_e2(); + manage_heater(); + lcd_update(); + } + } + break; + } +} +#endif void disable_heater() { diff --git a/Marlin/temperature.h b/Marlin/temperature.h index a8580def56..df2b5deacf 100644 --- a/Marlin/temperature.h +++ b/Marlin/temperature.h @@ -154,6 +154,17 @@ void disable_heater(); void setWatch(); void updatePID(); +#ifdef THERMAL_RUNAWAY_PROTECTION_PERIOD && THERMAL_RUNAWAY_PROTECTION_PERIOD > 0 +void thermal_runaway_protection(int *state, unsigned long *timer, float temperature, float target_temperature, int heater_id, int period_seconds, int hysteresis_degc); +static int thermal_runaway_state_machine[3]; // = {0,0,0}; +static unsigned long thermal_runaway_timer[3]; // = {0,0,0}; +static bool thermal_runaway = false; + #if TEMP_SENSOR_BED != 0 + static int thermal_runaway_bed_state_machine; + static unsigned long thermal_runaway_bed_timer; + #endif +#endif + FORCE_INLINE void autotempShutdown(){ #ifdef AUTOTEMP if(autotemp_enabled) From 2242a842189f8d65b86b63bcec7a84044b07c8e1 Mon Sep 17 00:00:00 2001 From: Pablo Clemente Date: Tue, 1 Jul 2014 16:45:03 +0200 Subject: [PATCH 256/256] Changed the declaration of the variable to Marlin_main.cpp to fix issue on commit #965 --- Marlin/Marlin_main.cpp | 2 ++ Marlin/ultralcd.cpp | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 3e44168208..0367eb46c1 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -276,6 +276,8 @@ int EtoPPressure=0; float delta_segments_per_second= DELTA_SEGMENTS_PER_SECOND; #endif +bool cancel_heatup = false ; + //=========================================================================== //=============================Private Variables============================= //=========================================================================== diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index bb7dd0faa8..18c85887ac 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -19,8 +19,6 @@ int absPreheatHotendTemp; int absPreheatHPBTemp; int absPreheatFanSpeed; -bool cancel_heatup = false ; - #ifdef ULTIPANEL static float manual_feedrate[] = MANUAL_FEEDRATE; #endif // ULTIPANEL