Browse Source

Merge branch 'Development' into pr-felix

pull/1/head
chrono 10 years ago
parent
commit
c13d81ce15
  1. 9
      Marlin/BlinkM.cpp
  2. 7
      Marlin/BlinkM.h
  3. 101
      Marlin/Configuration.h
  4. 6
      Marlin/ConfigurationStore.h
  5. 4
      Marlin/Marlin.h
  6. 20
      Marlin/Marlin_main.cpp
  7. 630
      Marlin/cardreader.cpp
  8. 64
      Marlin/cardreader.h
  9. 77
      Marlin/digipot_mcp4451.cpp
  10. 37
      Marlin/language.h
  11. 50
      Marlin/language_en.h
  12. 4
      Marlin/pins_RUMBA.h
  13. 147
      Marlin/stepper.cpp
  14. 111
      Marlin/temperature.h
  15. 14
      README.md

9
Marlin/BlinkM.cpp

@ -5,16 +5,9 @@
#include "Marlin.h"
#ifdef BLINKM
#if (ARDUINO >= 100)
# include "Arduino.h"
#else
# include "WProgram.h"
#endif
#include "BlinkM.h"
void SendColors(byte red, byte grn, byte blu)
{
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

7
Marlin/BlinkM.h

@ -2,13 +2,12 @@
BlinkM.h
Library header file for BlinkM library
*/
#if (ARDUINO >= 100)
# include "Arduino.h"
#if ARDUINO >= 100
#include "Arduino.h"
#else
# include "WProgram.h"
#include "WProgram.h"
#endif
#include "Wire.h"
void SendColors(byte red, byte grn, byte blu);

101
Marlin/Configuration.h

@ -8,7 +8,7 @@
//===========================================================================
/*
Here are some standard links for getting your machine calibrated:
* http://reprap.org/wiki/Calibration
* http://reprap.org/wiki/Calibration
* http://youtu.be/wAL9d7FgInk
* http://calculator.josefprusa.cz
* http://reprap.org/wiki/Triffid_Hunter%27s_Calibration_Guide
@ -59,7 +59,7 @@ Here are some standard links for getting your machine calibrated:
// The following define selects which electronics board you have.
// Please choose the name from boards.h that matches your setup
#ifndef MOTHERBOARD
#define MOTHERBOARD BOARD_ULTIMAKER
#define MOTHERBOARD BOARD_FELIX2
#endif
// Define this to set a custom name for your generic Mendel,
@ -70,7 +70,7 @@ Here are some standard links for getting your machine calibrated:
// #define MACHINE_UUID "00000000-0000-0000-0000-000000000000"
// This defines the number of extruders
#define EXTRUDERS 1
#define EXTRUDERS 2
//// The following define selects which power supply you have. Please choose the one that matches your setup
// 1 = ATX
@ -79,7 +79,7 @@ Here are some standard links for getting your machine calibrated:
#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
#define PS_DEFAULT_OFF
//===========================================================================
//============================= Thermal Settings ============================
@ -104,7 +104,7 @@ Here are some standard links for getting your machine calibrated:
// 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)
// 13 is 100k Hisens 3950 1% up to 300°C for hotend "Simple ONE " & "Hotend "All In ONE"
// 13 is 100k Hisens 3950 1% up to 300°C for hotend "Simple ONE " & "Hotend "All In ONE"
// 20 is the PT100 circuit found in the Ultimainboard V2.x
// 60 is 100k Maker's Tool Works Kapton Bed Thermistor beta=3950
//
@ -118,23 +118,23 @@ Here are some standard links for getting your machine calibrated:
// 1010 is Pt1000 with 1k pullup (non standard)
// 147 is Pt100 with 4k7 pullup
// 110 is Pt100 with 1k pullup (non standard)
// 998 and 999 are Dummy Tables. They will ALWAYS read 25°C or the temperature defined below.
// 998 and 999 are Dummy Tables. They will ALWAYS read 25°C or the temperature defined below.
// Use it for Testing or Development purposes. NEVER for production machine.
// #define DUMMY_THERMISTOR_998_VALUE 25
// #define DUMMY_THERMISTOR_999_VALUE 100
#define TEMP_SENSOR_0 -1
#define TEMP_SENSOR_1 -1
#define TEMP_SENSOR_0 1
#define TEMP_SENSOR_1 1
#define TEMP_SENSOR_2 0
#define TEMP_SENSOR_3 0
#define TEMP_SENSOR_BED 0
#define TEMP_SENSOR_BED 1
// 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_RESIDENCY_TIME 15 // (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.
@ -186,21 +186,11 @@ Here are some standard links for getting your machine calibrated:
#define K1 0.95 //smoothing factor within the PID
#define PID_dT ((OVERSAMPLENR * 10.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
// Felix 2.0+ electronics with v4 Hotend
#define DEFAULT_Kp 12
#define DEFAULT_Ki 0.84
#define DEFAULT_Kd 85
#endif // PIDTEMP
//===========================================================================
@ -263,15 +253,15 @@ The issue: If a thermistor come off, it will read a lower temperature than actua
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
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
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.
@ -321,13 +311,13 @@ your extruder heater takes 2 minutes to hit the target on heating.
#endif
// The pullups are needed if you directly connect a mechanical endswitch between the signal and ground pins.
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_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_MAX_ENDSTOPS
//#define DISABLE_MIN_ENDSTOPS
// For Inverting Stepper Enable Pins (Active Low) use 0, Non Inverting (Active High) use 1
@ -344,7 +334,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
#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
#define INVERT_Y_DIR true // for Mendel set to true, for Orca set to false
#define INVERT_Z_DIR true // for Mendel set to false, for Orca set to true
#define INVERT_E0_DIR false // 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
@ -361,11 +351,11 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
#define max_software_endstops true // If true, axis won't move to coordinates greater than the defined lengths below.
// Travel limits after homing (units are in mm)
#define X_MAX_POS 205
#define X_MAX_POS 245
#define X_MIN_POS 0
#define Y_MAX_POS 205
#define Y_MIN_POS 0
#define Z_MAX_POS 200
#define Z_MAX_POS 235
#define Z_MIN_POS 0
#define X_MAX_LENGTH (X_MAX_POS - X_MIN_POS)
@ -378,7 +368,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
//===========================================================================
//#define ENABLE_AUTO_BED_LEVELING // Delete the comment to enable (remove // at the start of the line)
#define Z_PROBE_REPEATABILITY_TEST // If not commented out, Z-Probe Repeatability test will be included if Auto Bed Leveling is Enabled.
//#define Z_PROBE_REPEATABILITY_TEST // If not commented out, Z-Probe Repeatability test will be included if Auto Bed Leveling is Enabled.
#ifdef ENABLE_AUTO_BED_LEVELING
@ -487,9 +477,9 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
#endif
#endif
#endif
#endif // ENABLE_AUTO_BED_LEVELING
@ -510,12 +500,13 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
// default settings
#define DEFAULT_AXIS_STEPS_PER_UNIT {78.7402,78.7402,200.0*8/3,760*1.1} // default steps per unit for Ultimaker
// default steps per unit for Felix 2.0/3.0: 0.00249mm x/y rounding error with 3mm pitch HTD belt and 14 tooth pulleys. 0 z error.
#define DEFAULT_AXIS_STEPS_PER_UNIT {76.190476, 76.190476, 1600, 164}
#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 {5000,5000,100,80000} // 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
#define DEFAULT_ACCELERATION 1750 //1500 // X, Y, Z and E max acceleration in mm/s^2 for printing moves
#define DEFAULT_RETRACT_ACCELERATION 5000 // X, Y, Z and E max acceleration in mm/s^2 for r 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).
@ -524,8 +515,8 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
// #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_XYJERK 10 // (mm/sec)
#define DEFAULT_ZJERK 0.3 //0.4 // (mm/sec)
#define DEFAULT_EJERK 5.0 // (mm/sec)
@ -570,7 +561,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
//#define LANGUAGE_INCLUDE GENERATE_LANGUAGE_INCLUDE(en)
// Character based displays can have different extended charsets.
#define DISPLAY_CHARSET_HD44780_JAPAN // "ääööüüß23°"
//#define DISPLAY_CHARSET_HD44780_JAPAN // "ääööüüß23°"
//#define DISPLAY_CHARSET_HD44780_WESTERN // "ÄäÖöÜüß²³°" if you see a '~' instead of a 'arrow_right' at the right of submenuitems - this is the right one.
//#define ULTRA_LCD //general LCD support, also 16x2
@ -636,13 +627,13 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
#define ULTRA_LCD //general LCD support, also 16x2
#define DOGLCD // Support for SPI LCD 128x64 (Controller ST7565R graphic Display Family)
#define ULTIMAKERCONTROLLER //as available from the Ultimaker online store.
#ifdef miniVIKI
#define DEFAULT_LCD_CONTRAST 95
#else
#define DEFAULT_LCD_CONTRAST 40
#endif
#define ENCODER_PULSES_PER_STEP 4
#define ENCODER_STEPS_PER_MENU_ITEM 1
#endif
@ -733,7 +724,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 SAV_3DLCD
#ifdef SAV_3DLCD
@ -774,7 +765,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
#endif
// Increase the FAN pwm frequency. Removes the PWM noise but increases heating in the FET/Arduino
//#define FAST_PWM_FAN
#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.
@ -782,7 +773,7 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
//#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
// which is not as 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
@ -831,9 +822,9 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
* Support for a filament diameter sensor
* Also allows adjustment of diameter at print time (vs at slicing)
* Single extruder only at this point (extruder 0)
*
*
* Motherboards
* 34 - RAMPS1.4 - uses Analog input 5 on the AUX2 connector
* 34 - RAMPS1.4 - uses Analog input 5 on the AUX2 connector
* 81 - Printrboard - Uses Analog input 2 on the Exp1 connector (version B,C,D,E)
* 301 - Rambo - uses Analog input 3
* Note may require analog pins to be defined for different motherboards
@ -850,16 +841,12 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
#define MAX_MEASUREMENT_DELAY 20 //delay buffer size in bytes (1 byte = 1cm)- limits maximum measurement delay allowable (must be larger than MEASUREMENT_DELAY_CM and lower number saves RAM)
//defines used in the code
#define DEFAULT_MEASURED_FILAMENT_DIA DEFAULT_NOMINAL_FILAMENT_DIA //set measured to nominal initially
#define DEFAULT_MEASURED_FILAMENT_DIA DEFAULT_NOMINAL_FILAMENT_DIA //set measured to nominal initially
//When using an LCD, uncomment the line below to display the Filament sensor data on the last line instead of status. Status will appear for 5 sec.
//#define FILAMENT_LCD_DISPLAY
#include "Configuration_adv.h"
#include "thermistortables.h"

6
Marlin/ConfigurationStore.h

@ -1,5 +1,5 @@
#ifndef CONFIG_STORE_H
#define CONFIG_STORE_H
#ifndef CONFIGURATIONSTORE_H
#define CONFIGURATIONSTORE_H
#include "Configuration.h"
@ -19,4 +19,4 @@ void Config_ResetDefault();
FORCE_INLINE void Config_RetrieveSettings() { Config_ResetDefault(); Config_PrintSettings(); }
#endif
#endif // __CONFIG_STORE_H
#endif //CONFIGURATIONSTORE_H

4
Marlin/Marlin.h

@ -180,8 +180,8 @@ void manage_inactivity(bool ignore_stepper_queue=false);
#define disable_e3() /* nothing */
#endif
enum AxisEnum {X_AXIS=0, Y_AXIS=1, Z_AXIS=2, E_AXIS=3, X_HEAD=4, Y_HEAD=5};
enum AxisEnum {X_AXIS=0, Y_AXIS=1, Z_AXIS=2, E_AXIS=3, X_HEAD=4, Y_HEAD=5};
//X_HEAD and Y_HEAD is used for systems that don't have a 1:1 relationship between X_AXIS and X Head movement, like CoreXY bots.
void FlushSerialRequestResend();
void ClearToSend();

20
Marlin/Marlin_main.cpp

@ -1734,16 +1734,6 @@ void process_commands()
SERIAL_ECHOLNPGM(MSG_POSITION_UNKNOWN);
break; // abort G29, since we don't know where we are
}
int left_probe_bed_position=LEFT_PROBE_BED_POSITION;
int right_probe_bed_position=RIGHT_PROBE_BED_POSITION;
int back_probe_bed_position=BACK_PROBE_BED_POSITION;
int front_probe_bed_position=FRONT_PROBE_BED_POSITION;
int auto_bed_leveling_grid_points=AUTO_BED_LEVELING_GRID_POINTS;
if (code_seen('L')) left_probe_bed_position=(int)code_value();
if (code_seen('R')) right_probe_bed_position=(int)code_value();
if (code_seen('B')) back_probe_bed_position=(int)code_value();
if (code_seen('F')) front_probe_bed_position=(int)code_value();
if (code_seen('P')) auto_bed_leveling_grid_points=(int)code_value();
#ifdef Z_PROBE_SLED
dock_sled(false);
@ -1764,6 +1754,16 @@ void process_commands()
feedrate = homing_feedrate[Z_AXIS];
#ifdef AUTO_BED_LEVELING_GRID
// probe at the points of a lattice grid
int left_probe_bed_position=LEFT_PROBE_BED_POSITION;
int right_probe_bed_position=RIGHT_PROBE_BED_POSITION;
int back_probe_bed_position=BACK_PROBE_BED_POSITION;
int front_probe_bed_position=FRONT_PROBE_BED_POSITION;
int auto_bed_leveling_grid_points=AUTO_BED_LEVELING_GRID_POINTS;
if (code_seen('L')) left_probe_bed_position=(int)code_value();
if (code_seen('R')) right_probe_bed_position=(int)code_value();
if (code_seen('B')) back_probe_bed_position=(int)code_value();
if (code_seen('F')) front_probe_bed_position=(int)code_value();
if (code_seen('P')) auto_bed_leveling_grid_points=(int)code_value();
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);

630
Marlin/cardreader.cpp

@ -7,476 +7,383 @@
#ifdef SDSUPPORT
CardReader::CardReader() {
filesize = 0;
sdpos = 0;
sdprinting = false;
cardOK = false;
saving = false;
logging = false;
workDirDepth = 0;
file_subcall_ctr = 0;
memset(workDirParents, 0, sizeof(workDirParents));
CardReader::CardReader()
{
filesize = 0;
sdpos = 0;
sdprinting = false;
cardOK = false;
saving = false;
logging = false;
autostart_atmillis=0;
workDirDepth = 0;
file_subcall_ctr=0;
memset(workDirParents, 0, sizeof(workDirParents));
autostart_stilltocheck=true; //the SD start is delayed, because otherwise the serial cannot answer fast enough to make contact with the host software.
autostart_index=0;
autostart_stilltocheck = true; //the SD start is delayed, because otherwise the serial cannot answer fast enough to make contact with the host software.
autostart_index = 0;
//power to SD reader
#if SDPOWER > -1
SET_OUTPUT(SDPOWER);
WRITE(SDPOWER,HIGH);
SET_OUTPUT(SDPOWER);
WRITE(SDPOWER, HIGH);
#endif //SDPOWER
autostart_atmillis=millis()+5000;
autostart_atmillis = millis() + 5000;
}
char *createFilename(char *buffer,const dir_t &p) //buffer>12characters
{
char *pos=buffer;
for (uint8_t i = 0; i < 11; i++)
{
if (p.name[i] == ' ')continue;
if (i == 8)
{
*pos++='.';
}
*pos++=p.name[i];
char *createFilename(char *buffer, const dir_t &p) { //buffer > 12characters
char *pos = buffer;
for (uint8_t i = 0; i < 11; i++) {
if (p.name[i] == ' ') continue;
if (i == 8) *pos++ = '.';
*pos++ = p.name[i];
}
*pos++=0;
*pos++ = 0;
return buffer;
}
void CardReader::lsDive(const char *prepend, SdFile parent, const char * const match/*=NULL*/)
{
void CardReader::lsDive(const char *prepend, SdFile parent, const char * const match/*=NULL*/) {
dir_t p;
uint8_t cnt=0;
while (parent.readDir(p, longFilename) > 0)
{
if( DIR_IS_SUBDIR(&p) && lsAction!=LS_Count && lsAction!=LS_GetFilename) // hence LS_SerialPrint
{
uint8_t cnt = 0;
while (parent.readDir(p, longFilename) > 0) {
if (DIR_IS_SUBDIR(&p) && lsAction != LS_Count && lsAction != LS_GetFilename) { // hence LS_SerialPrint
char path[FILENAME_LENGTH*2];
char lfilename[FILENAME_LENGTH];
createFilename(lfilename,p);
path[0]=0;
if(prepend[0]==0) //avoid leading / if already in prepend
{
strcat(path,"/");
}
strcat(path,prepend);
strcat(path,lfilename);
strcat(path,"/");
createFilename(lfilename, p);
path[0] = 0;
if (prepend[0] == 0) strcat(path, "/"); //avoid leading / if already in prepend
strcat(path, prepend);
strcat(path, lfilename);
strcat(path, "/");
//Serial.print(path);
SdFile dir;
if(!dir.open(parent,lfilename, O_READ))
{
if(lsAction==LS_SerialPrint)
{
if (!dir.open(parent, lfilename, O_READ)) {
if (lsAction == LS_SerialPrint) {
SERIAL_ECHO_START;
SERIAL_ECHOLN(MSG_SD_CANT_OPEN_SUBDIR);
SERIAL_ECHOLN(lfilename);
}
}
lsDive(path,dir);
lsDive(path, dir);
//close done automatically by destructor of SdFile
}
else
{
else {
char pn0 = p.name[0];
if (pn0 == DIR_NAME_FREE) break;
if (pn0 == DIR_NAME_DELETED || pn0 == '.' || pn0 == '_') continue;
if (pn0 == DIR_NAME_DELETED || pn0 == '.') continue;
char lf0 = longFilename[0];
if (lf0 == '.' || lf0 == '_') continue;
if (lf0 == '.') continue;
if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;
filenameIsDir=DIR_IS_SUBDIR(&p);
if(!filenameIsDir)
{
if(p.name[8]!='G') continue;
if(p.name[9]=='~') continue;
}
//if(cnt++!=nr) continue;
createFilename(filename,p);
if(lsAction==LS_SerialPrint)
{
filenameIsDir = DIR_IS_SUBDIR(&p);
if (!filenameIsDir && (p.name[8] != 'G' || p.name[9] == '~')) continue;
//if (cnt++ != nr) continue;
createFilename(filename, p);
if (lsAction == LS_SerialPrint) {
SERIAL_PROTOCOL(prepend);
SERIAL_PROTOCOLLN(filename);
}
else if(lsAction==LS_Count)
{
else if (lsAction == LS_Count) {
nrFiles++;
}
else if(lsAction==LS_GetFilename)
{
}
else if (lsAction == LS_GetFilename) {
if (match != NULL) {
if (strcasecmp(match, filename) == 0) return;
}
else if (cnt == nrFiles) return;
cnt++;
}
}
}
}
void CardReader::ls()
{
lsAction=LS_SerialPrint;
if(lsAction==LS_Count)
nrFiles=0;
void CardReader::ls() {
lsAction = LS_SerialPrint;
root.rewind();
lsDive("",root);
lsDive("", root);
}
void CardReader::initsd()
{
void CardReader::initsd() {
cardOK = false;
if(root.isOpen())
root.close();
#ifdef SDSLOW
if (!card.init(SPI_HALF_SPEED,SDSS)
#if defined(LCD_SDSS) && (LCD_SDSS != SDSS)
&& !card.init(SPI_HALF_SPEED,LCD_SDSS)
#endif
)
#else
if (!card.init(SPI_FULL_SPEED,SDSS)
#if defined(LCD_SDSS) && (LCD_SDSS != SDSS)
&& !card.init(SPI_FULL_SPEED,LCD_SDSS)
if (root.isOpen()) root.close();
#ifdef SDSLOW
#define SPI_SPEED SPI_HALF_SPEED
#else
#define SPI_SPEED SPI_FULL_SPEED
#endif
)
#endif
{
if (!card.init(SPI_SPEED,SDSS)
#if defined(LCD_SDSS) && (LCD_SDSS != SDSS)
&& !card.init(SPI_SPEED, LCD_SDSS)
#endif
) {
//if (!card.init(SPI_HALF_SPEED,SDSS))
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM(MSG_SD_INIT_FAIL);
}
else if (!volume.init(&card))
{
else if (!volume.init(&card)) {
SERIAL_ERROR_START;
SERIAL_ERRORLNPGM(MSG_SD_VOL_INIT_FAIL);
}
else if (!root.openRoot(&volume))
{
else if (!root.openRoot(&volume)) {
SERIAL_ERROR_START;
SERIAL_ERRORLNPGM(MSG_SD_OPENROOT_FAIL);
}
else
{
else {
cardOK = true;
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM(MSG_SD_CARD_OK);
}
workDir=root;
curDir=&root;
workDir = root;
curDir = &root;
/*
if(!workDir.openRoot(&volume))
{
if (!workDir.openRoot(&volume)) {
SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
}
*/
}
void CardReader::setroot()
{
/*if(!workDir.openRoot(&volume))
{
void CardReader::setroot() {
/*if (!workDir.openRoot(&volume)) {
SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
}*/
workDir=root;
curDir=&workDir;
workDir = root;
curDir = &workDir;
}
void CardReader::release()
{
void CardReader::release() {
sdprinting = false;
cardOK = false;
}
void CardReader::startFileprint()
{
if(cardOK)
{
void CardReader::startFileprint() {
if (cardOK) {
sdprinting = true;
}
}
void CardReader::pauseSDPrint()
{
if(sdprinting)
{
sdprinting = false;
}
void CardReader::pauseSDPrint() {
if (sdprinting) sdprinting = false;
}
void CardReader::openLogFile(char* name)
{
void CardReader::openLogFile(char* name) {
logging = true;
openFile(name, false);
}
void CardReader::getAbsFilename(char *t)
{
uint8_t cnt=0;
*t='/';t++;cnt++;
for(uint8_t i=0;i<workDirDepth;i++)
{
void CardReader::getAbsFilename(char *t) {
uint8_t cnt = 0;
*t = '/'; t++; cnt++;
for (uint8_t i = 0; i < workDirDepth; i++) {
workDirParents[i].getFilename(t); //SDBaseFile.getfilename!
while(*t!=0 && cnt< MAXPATHNAMELENGTH)
{t++;cnt++;} //crawl counter forward.
while(*t && cnt < MAXPATHNAMELENGTH) { t++; cnt++; } //crawl counter forward.
}
if(cnt<MAXPATHNAMELENGTH-FILENAME_LENGTH)
if (cnt < MAXPATHNAMELENGTH - FILENAME_LENGTH)
file.getFilename(t);
else
t[0]=0;
t[0] = 0;
}
void CardReader::openFile(char* name,bool read, bool replace_current/*=true*/)
{
if(!cardOK)
return;
if(file.isOpen()) //replacing current file by new file, or subfile call
{
if(!replace_current)
{
if((int)file_subcall_ctr>(int)SD_PROCEDURE_DEPTH-1)
{
void CardReader::openFile(char* name, bool read, bool replace_current/*=true*/) {
if (!cardOK) return;
if (file.isOpen()) { //replacing current file by new file, or subfile call
if (!replace_current) {
if (file_subcall_ctr > 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;
filespos[file_subcall_ctr] = sdpos;
file_subcall_ctr++;
}
else
{
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
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;
char *dirname_start,*dirname_end;
if(name[0]=='/')
{
dirname_start=strchr(name,'/')+1;
while(dirname_start>0)
{
dirname_end=strchr(dirname_start,'/');
//SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start-name));
//SERIAL_ECHO("end :");SERIAL_ECHOLN((int)(dirname_end-name));
if(dirname_end>0 && dirname_end>dirname_start)
{
curDir = &root;
char *fname = name;
char *dirname_start, *dirname_end;
if (name[0] == '/') {
dirname_start = &name[1];
while(dirname_start > 0) {
dirname_end = strchr(dirname_start, '/');
//SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start - name));
//SERIAL_ECHO("end :");SERIAL_ECHOLN((int)(dirname_end - name));
if (dirname_end > 0 && dirname_end > dirname_start) {
char subdirname[FILENAME_LENGTH];
strncpy(subdirname, dirname_start, dirname_end-dirname_start);
subdirname[dirname_end-dirname_start]=0;
strncpy(subdirname, dirname_start, dirname_end - dirname_start);
subdirname[dirname_end - dirname_start] = 0;
SERIAL_ECHOLN(subdirname);
if(!myDir.open(curDir,subdirname,O_READ))
{
if (!myDir.open(curDir, subdirname, O_READ)) {
SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
SERIAL_PROTOCOL(subdirname);
SERIAL_PROTOCOLLNPGM(".");
return;
}
else
{
else {
//SERIAL_ECHOLN("dive ok");
}
curDir=&myDir;
dirname_start=dirname_end+1;
curDir = &myDir;
dirname_start = dirname_end + 1;
}
else // the reminder after all /fsa/fdsa/ is the filename
{
fname=dirname_start;
//SERIAL_ECHOLN("remaider");
else { // the remainder after all /fsa/fdsa/ is the filename
fname = dirname_start;
//SERIAL_ECHOLN("remainder");
//SERIAL_ECHOLN(fname);
break;
}
}
}
else //relative path
{
curDir=&workDir;
else { //relative path
curDir = &workDir;
}
if(read)
{
if (file.open(curDir, fname, O_READ))
{
if (read) {
if (file.open(curDir, fname, O_READ)) {
filesize = file.fileSize();
SERIAL_PROTOCOLPGM(MSG_SD_FILE_OPENED);
SERIAL_PROTOCOL(fname);
SERIAL_PROTOCOLPGM(MSG_SD_SIZE);
SERIAL_PROTOCOLLN(filesize);
sdpos = 0;
SERIAL_PROTOCOLLNPGM(MSG_SD_FILE_SELECTED);
getfilename(0, fname);
lcd_setstatus(longFilename[0] ? longFilename : fname);
}
else
{
else {
SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
SERIAL_PROTOCOL(fname);
SERIAL_PROTOCOLLNPGM(".");
}
}
else
{ //write
if (!file.open(curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC))
{
else { //write
if (!file.open(curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) {
SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
SERIAL_PROTOCOL(fname);
SERIAL_PROTOCOLLNPGM(".");
}
else
{
else {
saving = true;
SERIAL_PROTOCOLPGM(MSG_SD_WRITE_TO_FILE);
SERIAL_PROTOCOLLN(name);
lcd_setstatus(fname);
}
}
}
void CardReader::removeFile(char* name)
{
if(!cardOK)
return;
void CardReader::removeFile(char* name) {
if (!cardOK) return;
file.close();
sdprinting = false;
SdFile myDir;
curDir=&root;
char *fname=name;
char *dirname_start,*dirname_end;
if(name[0]=='/')
{
dirname_start=strchr(name,'/')+1;
while(dirname_start>0)
{
dirname_end=strchr(dirname_start,'/');
//SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start-name));
//SERIAL_ECHO("end :");SERIAL_ECHOLN((int)(dirname_end-name));
if(dirname_end>0 && dirname_end>dirname_start)
{
curDir = &root;
char *fname = name;
char *dirname_start, *dirname_end;
if (name[0] == '/') {
dirname_start = strchr(name, '/') + 1;
while (dirname_start > 0) {
dirname_end = strchr(dirname_start, '/');
//SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start - name));
//SERIAL_ECHO("end :");SERIAL_ECHOLN((int)(dirname_end - name));
if (dirname_end > 0 && dirname_end > dirname_start) {
char subdirname[FILENAME_LENGTH];
strncpy(subdirname, dirname_start, dirname_end-dirname_start);
subdirname[dirname_end-dirname_start]=0;
strncpy(subdirname, dirname_start, dirname_end - dirname_start);
subdirname[dirname_end - dirname_start] = 0;
SERIAL_ECHOLN(subdirname);
if(!myDir.open(curDir,subdirname,O_READ))
{
if (!myDir.open(curDir, subdirname, O_READ)) {
SERIAL_PROTOCOLPGM("open failed, File: ");
SERIAL_PROTOCOL(subdirname);
SERIAL_PROTOCOLLNPGM(".");
return;
}
else
{
else {
//SERIAL_ECHOLN("dive ok");
}
curDir=&myDir;
dirname_start=dirname_end+1;
curDir = &myDir;
dirname_start = dirname_end + 1;
}
else // the reminder after all /fsa/fdsa/ is the filename
{
fname=dirname_start;
//SERIAL_ECHOLN("remaider");
else { // the remainder after all /fsa/fdsa/ is the filename
fname = dirname_start;
//SERIAL_ECHOLN("remainder");
//SERIAL_ECHOLN(fname);
break;
}
}
}
else //relative path
{
curDir=&workDir;
else { // relative path
curDir = &workDir;
}
if (file.remove(curDir, fname)) {
SERIAL_PROTOCOLPGM("File deleted:");
SERIAL_PROTOCOLLN(fname);
sdpos = 0;
}
else {
SERIAL_PROTOCOLPGM("Deletion failed, File: ");
SERIAL_PROTOCOL(fname);
SERIAL_PROTOCOLLNPGM(".");
}
if (file.remove(curDir, fname))
{
SERIAL_PROTOCOLPGM("File deleted:");
SERIAL_PROTOCOLLN(fname);
sdpos = 0;
}
else
{
SERIAL_PROTOCOLPGM("Deletion failed, File: ");
SERIAL_PROTOCOL(fname);
SERIAL_PROTOCOLLNPGM(".");
}
}
void CardReader::getStatus()
{
if(cardOK){
void CardReader::getStatus() {
if (cardOK) {
SERIAL_PROTOCOLPGM(MSG_SD_PRINTING_BYTE);
SERIAL_PROTOCOL(sdpos);
SERIAL_PROTOCOLPGM("/");
SERIAL_PROTOCOLLN(filesize);
}
else{
else {
SERIAL_PROTOCOLLNPGM(MSG_SD_NOT_PRINTING);
}
}
void CardReader::write_command(char *buf)
{
void CardReader::write_command(char *buf) {
char* begin = buf;
char* npos = 0;
char* end = buf + strlen(buf) - 1;
file.writeError = false;
if((npos = strchr(buf, 'N')) != NULL)
{
if ((npos = strchr(buf, 'N')) != NULL) {
begin = strchr(npos, ' ') + 1;
end = strchr(npos, '*') - 1;
}
@ -484,162 +391,129 @@ void CardReader::write_command(char *buf)
end[2] = '\n';
end[3] = '\0';
file.write(begin);
if (file.writeError)
{
if (file.writeError) {
SERIAL_ERROR_START;
SERIAL_ERRORLNPGM(MSG_SD_ERR_WRITE_TO_FILE);
}
}
void CardReader::checkautostart(bool force) {
if (!force && (!autostart_stilltocheck || autostart_atmillis < millis()))
return;
void CardReader::checkautostart(bool force)
{
if(!force)
{
if(!autostart_stilltocheck)
return;
if(autostart_atmillis<millis())
return;
}
autostart_stilltocheck=false;
if(!cardOK)
{
autostart_stilltocheck = false;
if (!cardOK) {
initsd();
if(!cardOK) //fail
return;
if (!cardOK) return; // fail
}
char autoname[30];
sprintf_P(autoname, PSTR("auto%i.g"), autostart_index);
for(int8_t i=0;i<(int8_t)strlen(autoname);i++)
autoname[i]=tolower(autoname[i]);
for (int8_t i = 0; i < (int8_t)strlen(autoname); i++) autoname[i] = tolower(autoname[i]);
dir_t p;
root.rewind();
bool found=false;
while (root.readDir(p, NULL) > 0)
{
for(int8_t i=0;i<(int8_t)strlen((char*)p.name);i++)
p.name[i]=tolower(p.name[i]);
//Serial.print((char*)p.name);
//Serial.print(" ");
//Serial.println(autoname);
if(p.name[9]!='~') //skip safety copies
if(strncmp((char*)p.name,autoname,5)==0)
{
char cmd[30];
bool found = false;
while (root.readDir(p, NULL) > 0) {
for (int8_t i = 0; i < (int8_t)strlen((char*)p.name); i++) p.name[i] = tolower(p.name[i]);
if (p.name[9] != '~' && strncmp((char*)p.name, autoname, 5) == 0) {
char cmd[30];
sprintf_P(cmd, PSTR("M23 %s"), autoname);
enquecommand(cmd);
enquecommands_P(PSTR("M24"));
found=true;
found = true;
}
}
if(!found)
autostart_index=-1;
if (!found)
autostart_index = -1;
else
autostart_index++;
}
void CardReader::closefile(bool store_location)
{
void CardReader::closefile(bool store_location) {
file.sync();
file.close();
saving = false;
logging = false;
if(store_location)
{
saving = logging = false;
if (store_location) {
//future: store printer state, filename and position for continuing a stopped print
// so one can unplug the printer and continue printing the next day.
}
}
void CardReader::getfilename(uint16_t nr, const char * const match/*=NULL*/)
{
curDir=&workDir;
lsAction=LS_GetFilename;
nrFiles=nr;
/**
* Get the name of a file in the current directory by index
*/
void CardReader::getfilename(uint16_t nr, const char * const match/*=NULL*/) {
curDir = &workDir;
lsAction = LS_GetFilename;
nrFiles = nr;
curDir->rewind();
lsDive("",*curDir,match);
lsDive("", *curDir, match);
}
uint16_t CardReader::getnrfilenames()
{
curDir=&workDir;
lsAction=LS_Count;
nrFiles=0;
uint16_t CardReader::getnrfilenames() {
curDir = &workDir;
lsAction = LS_Count;
nrFiles = 0;
curDir->rewind();
lsDive("",*curDir);
lsDive("", *curDir);
//SERIAL_ECHOLN(nrFiles);
return nrFiles;
}
void CardReader::chdir(const char * relpath)
{
void CardReader::chdir(const char * relpath) {
SdFile newfile;
SdFile *parent=&root;
if(workDir.isOpen())
parent=&workDir;
if(!newfile.open(*parent,relpath, O_READ))
{
SERIAL_ECHO_START;
SERIAL_ECHOPGM(MSG_SD_CANT_ENTER_SUBDIR);
SERIAL_ECHOLN(relpath);
SdFile *parent = &root;
if (workDir.isOpen()) parent = &workDir;
if (!newfile.open(*parent, relpath, O_READ)) {
SERIAL_ECHO_START;
SERIAL_ECHOPGM(MSG_SD_CANT_ENTER_SUBDIR);
SERIAL_ECHOLN(relpath);
}
else
{
else {
if (workDirDepth < MAX_DIR_DEPTH) {
for (int d = ++workDirDepth; d--;)
workDirParents[d+1] = workDirParents[d];
workDirParents[0]=*parent;
++workDirDepth;
for (int d = workDirDepth; d--;) workDirParents[d + 1] = workDirParents[d];
workDirParents[0] = *parent;
}
workDir=newfile;
workDir = newfile;
}
}
void CardReader::updir()
{
if(workDirDepth > 0)
{
void CardReader::updir() {
if (workDirDepth > 0) {
--workDirDepth;
workDir = workDirParents[0];
int d;
for (int d = 0; d < workDirDepth; d++)
workDirParents[d] = workDirParents[d+1];
}
}
void CardReader::printingHasFinished()
{
st_synchronize();
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
{
quickStop();
file.close();
sdprinting = false;
if(SD_FINISHED_STEPPERRELEASE)
{
//finishAndDisableSteppers();
enquecommands_P(PSTR(SD_FINISHED_RELEASECOMMAND));
}
autotempShutdown();
void CardReader::printingHasFinished() {
st_synchronize();
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 {
quickStop();
file.close();
sdprinting = false;
if (SD_FINISHED_STEPPERRELEASE) {
//finishAndDisableSteppers();
enquecommands_P(PSTR(SD_FINISHED_RELEASECOMMAND));
}
autotempShutdown();
}
}
#endif //SDSUPPORT

64
Marlin/cardreader.h

@ -3,21 +3,21 @@
#ifdef SDSUPPORT
#define MAX_DIR_DEPTH 10
#define MAX_DIR_DEPTH 10 // Maximum folder depth
#include "SdFile.h"
enum LsAction {LS_SerialPrint,LS_Count,LS_GetFilename};
class CardReader
{
enum LsAction { LS_SerialPrint, LS_Count, LS_GetFilename };
class CardReader {
public:
CardReader();
void initsd();
void write_command(char *buf);
//files auto[0-9].g on the sd card are performed in a row
//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 checkautostart(bool x);
void openFile(char* name,bool read,bool replace_current=true);
void openLogFile(char* name);
void removeFile(char* name);
@ -30,9 +30,8 @@ public:
void getfilename(uint16_t nr, const char* const match=NULL);
uint16_t getnrfilenames();
void getAbsFilename(char *t);
void ls();
void chdir(const char * relpath);
@ -41,56 +40,52 @@ public:
FORCE_INLINE bool isFileOpen() { return file.isOpen(); }
FORCE_INLINE bool eof() { return sdpos>=filesize ;};
FORCE_INLINE int16_t get() { sdpos = file.curPosition();return (int16_t)file.read();};
FORCE_INLINE void setIndex(long index) {sdpos = index;file.seekSet(index);};
FORCE_INLINE uint8_t percentDone(){if(!isFileOpen()) return 0; if(filesize) return sdpos/((filesize+99)/100); else return 0;};
FORCE_INLINE char* getWorkDirName(){workDir.getFilename(filename);return filename;};
FORCE_INLINE bool eof() { return sdpos >= filesize; }
FORCE_INLINE int16_t get() { sdpos = file.curPosition(); return (int16_t)file.read(); }
FORCE_INLINE void setIndex(long index) { sdpos = index; file.seekSet(index); }
FORCE_INLINE uint8_t percentDone() { return (isFileOpen() && filesize) ? sdpos / ((filesize + 99) / 100) : 0; }
FORCE_INLINE char* getWorkDirName() { workDir.getFilename(filename); return filename; }
public:
bool saving;
bool logging;
bool sdprinting;
bool cardOK;
char filename[FILENAME_LENGTH];
char longFilename[LONG_FILENAME_LENGTH];
bool filenameIsDir;
bool saving, logging, sdprinting, cardOK, filenameIsDir;
char filename[FILENAME_LENGTH], longFilename[LONG_FILENAME_LENGTH];
int autostart_index;
private:
SdFile root,*curDir,workDir,workDirParents[MAX_DIR_DEPTH];
SdFile root, *curDir, workDir, workDirParents[MAX_DIR_DEPTH];
uint16_t workDirDepth;
Sd2Card card;
SdVolume volume;
SdFile file;
#define SD_PROCEDURE_DEPTH 1
#define MAXPATHNAMELENGTH (FILENAME_LENGTH*MAX_DIR_DEPTH+MAX_DIR_DEPTH+1)
#define MAXPATHNAMELENGTH (FILENAME_LENGTH*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;
uint32_t sdpos ;
uint32_t sdpos;
bool autostart_stilltocheck; //the sd start is delayed, because otherwise the serial cannot answer fast enought to make contact with the hostsoftware.
LsAction lsAction; //stored for recursion.
int16_t nrFiles; //counter for the files in the current directory and recycled as position counter for getting the nrFiles'th name in the directory.
uint16_t nrFiles; //counter for the files in the current directory and recycled as position counter for getting the nrFiles'th name in the directory.
char* diveDirName;
void lsDive(const char *prepend, SdFile parent, const char * const match=NULL);
};
extern CardReader card;
#define IS_SD_PRINTING (card.sdprinting)
#if (SDCARDDETECT > -1)
# ifdef SDCARDDETECTINVERTED
# define IS_SD_INSERTED (READ(SDCARDDETECT)!=0)
# else
# define IS_SD_INSERTED (READ(SDCARDDETECT)==0)
# endif //SDCARDTETECTINVERTED
#ifdef SDCARDDETECTINVERTED
#define IS_SD_INSERTED (READ(SDCARDDETECT) != 0)
#else
#define IS_SD_INSERTED (READ(SDCARDDETECT) == 0)
#endif
#else
//If we don't have a card detect line, aways asume the card is inserted
# define IS_SD_INSERTED true
//No card detect line? Assume the card is inserted.
#define IS_SD_INSERTED true
#endif
#else
@ -98,4 +93,5 @@ extern CardReader card;
#define IS_SD_PRINTING (false)
#endif //SDSUPPORT
#endif
#endif //__CARDREADER_H

77
Marlin/digipot_mcp4451.cpp

@ -1,59 +1,58 @@
#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
#if MB(5DPRINT)
#define DIGIPOT_I2C_FACTOR 117.96
#define DIGIPOT_I2C_MAX_CURRENT 1.736
#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
#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))));
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();
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_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]);
}
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
#endif //DIGIPOT_I2C

37
Marlin/language.h

@ -159,6 +159,43 @@
#define MSG_ERR_EEPROM_WRITE "Error writing to EEPROM!"
// temperature.cpp strings
#define MSG_PID_AUTOTUNE "PID Autotune"
#define MSG_PID_AUTOTUNE_START MSG_PID_AUTOTUNE " start"
#define MSG_PID_AUTOTUNE_FAILED MSG_PID_AUTOTUNE " failed!"
#define MSG_PID_BAD_EXTRUDER_NUM MSG_PID_AUTOTUNE_FAILED " Bad extruder number"
#define MSG_PID_TEMP_TOO_HIGH MSG_PID_AUTOTUNE_FAILED " Temperature too high"
#define MSG_PID_TIMEOUT MSG_PID_AUTOTUNE_FAILED " timeout"
#define MSG_BIAS " bias: "
#define MSG_D " d: "
#define MSG_MIN " min: "
#define MSG_MAX " max: "
#define MSG_KU " Ku: "
#define MSG_TU " Tu: "
#define MSG_CLASSIC_PID " Classic PID "
#define MSG_KP " Kp: "
#define MSG_KI " Ki: "
#define MSG_KD " Kd: "
#define MSG_OK_B "ok B:"
#define MSG_OK_T "ok T:"
#define MSG_AT " @:"
#define MSG_PID_AUTOTUNE_FINISHED MSG_PID_AUTOTUNE " finished! Put the last Kp, Ki and Kd constants from above into Configuration.h"
#define MSG_PID_DEBUG " PID_DEBUG "
#define MSG_PID_DEBUG_INPUT ": Input "
#define MSG_PID_DEBUG_OUTPUT " Output "
#define MSG_PID_DEBUG_PTERM " pTerm "
#define MSG_PID_DEBUG_ITERM " iTerm "
#define MSG_PID_DEBUG_DTERM " dTerm "
#define MSG_HEATING_FAILED "Heating failed"
#define MSG_EXTRUDER_SWITCHED_OFF "Extruder switched off. Temperature difference between temp sensors is too high !"
#define MSG_INVALID_EXTRUDER_NUM " - Invalid extruder number !"
#define MSG_THERMAL_RUNAWAY_STOP "Thermal Runaway, system stopped! Heater_ID: "
#define MSG_SWITCHED_OFF_MAX " switched off. MAXTEMP triggered !!"
#define MSG_MINTEMP_EXTRUDER_OFF ": Extruder switched off. MINTEMP triggered !"
#define MSG_MAXTEMP_EXTRUDER_OFF ": Extruder" MSG_SWITCHED_OFF_MAX
#define MSG_MAXTEMP_BED_OFF "Heated bed" MSG_SWITCHED_OFF_MAX
// LCD Menu Messages
// Add your own character. Reference: https://github.com/MarlinFirmware/Marlin/pull/1434 photos

50
Marlin/language_en.h

@ -255,7 +255,7 @@
#define MSG_VOLUMETRIC "Filament"
#endif
#ifndef MSG_VOLUMETRIC_ENABLED
#define MSG_VOLUMETRIC_ENABLED "E in mm" STR_h3
#define MSG_VOLUMETRIC_ENABLED "E in mm" STR_h3
#endif
#ifndef MSG_FILAMENT_SIZE_EXTRUDER_0
#define MSG_FILAMENT_SIZE_EXTRUDER_0 "Fil. Dia. 1"
@ -383,23 +383,41 @@
#ifndef MSG_ENDSTOP_ABORT
#define MSG_ENDSTOP_ABORT "Endstop abort"
#endif
#ifndef MSG_HEATING_FAILED_LCD
#define MSG_HEATING_FAILED_LCD "Heating failed"
#endif
#ifndef MSG_ERR_REDUNDANT_TEMP
#define MSG_ERR_REDUNDANT_TEMP "Err: REDUNDANT TEMP ERROR"
#endif
#ifndef MSG_THERMAL_RUNAWAY
#define MSG_THERMAL_RUNAWAY "THERMAL RUNAWAY"
#endif
#ifndef MSG_ERR_MAXTEMP
#define MSG_ERR_MAXTEMP "Err: MAXTEMP"
#endif
#ifndef MSG_ERR_MINTEMP
#define MSG_ERR_MINTEMP "Err: MINTEMP"
#endif
#ifndef MSG_ERR_MAXTEMP_BED
#define MSG_ERR_MAXTEMP_BED "Err: MAXTEMP BED"
#endif
#ifdef DELTA_CALIBRATION_MENU
#ifndef MSG_DELTA_CALIBRATE
#define MSG_DELTA_CALIBRATE "Delta Calibration"
#endif
#ifndef MSG_DELTA_CALIBRATE_X
#define MSG_DELTA_CALIBRATE_X "Calibrate X"
#endif
#ifndef MSG_DELTA_CALIBRATE_Y
#define MSG_DELTA_CALIBRATE_Y "Calibrate Y"
#endif
#ifndef MSG_DELTA_CALIBRATE_Z
#define MSG_DELTA_CALIBRATE_Z "Calibrate Z"
#endif
#ifndef MSG_DELTA_CALIBRATE_CENTER
#define MSG_DELTA_CALIBRATE_CENTER "Calibrate Center"
#endif
#ifndef MSG_DELTA_CALIBRATE
#define MSG_DELTA_CALIBRATE "Delta Calibration"
#endif
#ifndef MSG_DELTA_CALIBRATE_X
#define MSG_DELTA_CALIBRATE_X "Calibrate X"
#endif
#ifndef MSG_DELTA_CALIBRATE_Y
#define MSG_DELTA_CALIBRATE_Y "Calibrate Y"
#endif
#ifndef MSG_DELTA_CALIBRATE_Z
#define MSG_DELTA_CALIBRATE_Z "Calibrate Z"
#endif
#ifndef MSG_DELTA_CALIBRATE_CENTER
#define MSG_DELTA_CALIBRATE_CENTER "Calibrate Center"
#endif
#endif // DELTA_CALIBRATION_MENU
#endif // LANGUAGE_EN_H

4
Marlin/pins_RUMBA.h

@ -6,6 +6,10 @@
#error Oops! Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu.
#endif
#if EXTRUDERS > 3
#error RUMBA supports up to 3 extruders. Comment this line to keep going.
#endif
#define X_STEP_PIN 17
#define X_DIR_PIN 16
#define X_ENABLE_PIN 48

147
Marlin/stepper.cpp

@ -399,89 +399,84 @@ ISR(TIMER1_COMPA_vect)
count_direction[Y_AXIS]=1;
}
// Set direction en check limit switches
#ifndef COREXY
if ((out_bits & (1<<X_AXIS)) != 0) // stepping along -X axis
#else
if ((out_bits & (1<<X_HEAD)) != 0) //AlexBorro: Head direction in -X axis for CoreXY bots.
#endif
if(check_endstops) // check X and Y 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_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;
#ifndef COREXY
if ((out_bits & (1<<X_AXIS)) != 0) // stepping along -X axis (regular cartesians bot)
#else
if (!((current_block->steps_x == current_block->steps_y) && ((out_bits & (1<<X_AXIS))>>X_AXIS != (out_bits & (1<<Y_AXIS))>>Y_AXIS))) // AlexBorro: If DeltaX == -DeltaY, the movement is only in Y axis
if ((out_bits & (1<<X_HEAD)) != 0) //AlexBorro: Head direction in -X axis for CoreXY bots.
#endif
{ // -direction
#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
}
old_x_min_endstop = x_min_endstop;
#endif
}
}
}
else
{ // +direction
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;
else
{ // +direction
#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
}
old_x_max_endstop = x_max_endstop;
#endif
}
}
}
#ifndef COREXY
if ((out_bits & (1<<Y_AXIS)) != 0) // -direction
#else
if ((out_bits & (1<<Y_HEAD)) != 0) //AlexBorro: Head direction in -Y axis for CoreXY bots.
#endif
{
CHECK_ENDSTOPS
{
#if defined(Y_MIN_PIN) && Y_MIN_PIN > -1
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;
step_events_completed = current_block->step_event_count;
}
old_y_min_endstop = y_min_endstop;
#endif
}
}
else
{ // +direction
CHECK_ENDSTOPS
{
#if defined(Y_MAX_PIN) && Y_MAX_PIN > -1
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;
step_events_completed = current_block->step_event_count;
}
old_y_max_endstop = y_max_endstop;
#ifndef COREXY
if ((out_bits & (1<<Y_AXIS)) != 0) // -direction
#else
if (!((current_block->steps_x == current_block->steps_y) && ((out_bits & (1<<X_AXIS))>>X_AXIS == (out_bits & (1<<Y_AXIS))>>Y_AXIS))) // AlexBorro: If DeltaX == DeltaY, the movement is only in X axis
if ((out_bits & (1<<Y_HEAD)) != 0) //AlexBorro: Head direction in -Y axis for CoreXY bots.
#endif
}
{ // -direction
#if defined(Y_MIN_PIN) && Y_MIN_PIN > -1
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;
step_events_completed = current_block->step_event_count;
}
old_y_min_endstop = y_min_endstop;
#endif
}
else
{ // +direction
#if defined(Y_MAX_PIN) && Y_MAX_PIN > -1
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;
step_events_completed = current_block->step_event_count;
}
old_y_max_endstop = y_max_endstop;
#endif
}
}
if ((out_bits & (1<<Z_AXIS)) != 0) { // -direction

111
Marlin/temperature.h

@ -85,55 +85,25 @@ extern float current_temperature_bed;
//inline so that there is no performance decrease.
//deg=degreeCelsius
FORCE_INLINE float degHotend(uint8_t extruder) {
return current_temperature[extruder];
};
FORCE_INLINE float degHotend(uint8_t extruder) { return current_temperature[extruder]; }
FORCE_INLINE float degBed() { return current_temperature_bed; }
#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;
};
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;
};
FORCE_INLINE float degTargetHotend(uint8_t extruder) {
return target_temperature[extruder];
};
FORCE_INLINE float degTargetBed() {
return target_temperature_bed;
};
FORCE_INLINE void setTargetHotend(const float &celsius, uint8_t extruder) {
target_temperature[extruder] = celsius;
};
FORCE_INLINE void setTargetBed(const float &celsius) {
target_temperature_bed = celsius;
};
FORCE_INLINE float degTargetHotend(uint8_t extruder) { return target_temperature[extruder]; }
FORCE_INLINE float degTargetBed() { return target_temperature_bed; }
FORCE_INLINE bool isHeatingHotend(uint8_t extruder){
return target_temperature[extruder] > current_temperature[extruder];
};
FORCE_INLINE void setTargetHotend(const float &celsius, uint8_t extruder) { target_temperature[extruder] = celsius; }
FORCE_INLINE void setTargetBed(const float &celsius) { target_temperature_bed = celsius; }
FORCE_INLINE bool isHeatingBed() {
return target_temperature_bed > current_temperature_bed;
};
FORCE_INLINE bool isHeatingHotend(uint8_t extruder) { return target_temperature[extruder] > current_temperature[extruder]; }
FORCE_INLINE bool isHeatingBed() { return target_temperature_bed > current_temperature_bed; }
FORCE_INLINE bool isCoolingHotend(uint8_t extruder) {
return target_temperature[extruder] < current_temperature[extruder];
};
FORCE_INLINE bool isCoolingBed() {
return target_temperature_bed < current_temperature_bed;
};
FORCE_INLINE bool isCoolingHotend(uint8_t extruder) { return target_temperature[extruder] < current_temperature[extruder]; }
FORCE_INLINE bool isCoolingBed() { return target_temperature_bed < current_temperature_bed; }
#define degHotend0() degHotend(0)
#define degTargetHotend0() degTargetHotend(0)
@ -141,38 +111,36 @@ FORCE_INLINE bool isCoolingBed() {
#define isHeatingHotend0() isHeatingHotend(0)
#define isCoolingHotend0() isCoolingHotend(0)
#if EXTRUDERS > 1
#define degHotend1() degHotend(1)
#define degTargetHotend1() degTargetHotend(1)
#define setTargetHotend1(_celsius) setTargetHotend((_celsius), 1)
#define isHeatingHotend1() isHeatingHotend(1)
#define isCoolingHotend1() isCoolingHotend(1)
#define degHotend1() degHotend(1)
#define degTargetHotend1() degTargetHotend(1)
#define setTargetHotend1(_celsius) setTargetHotend((_celsius), 1)
#define isHeatingHotend1() isHeatingHotend(1)
#define isCoolingHotend1() isCoolingHotend(1)
#else
#define setTargetHotend1(_celsius) do{}while(0)
#define setTargetHotend1(_celsius) do{}while(0)
#endif
#if EXTRUDERS > 2
#define degHotend2() degHotend(2)
#define degTargetHotend2() degTargetHotend(2)
#define setTargetHotend2(_celsius) setTargetHotend((_celsius), 2)
#define isHeatingHotend2() isHeatingHotend(2)
#define isCoolingHotend2() isCoolingHotend(2)
#define degHotend2() degHotend(2)
#define degTargetHotend2() degTargetHotend(2)
#define setTargetHotend2(_celsius) setTargetHotend((_celsius), 2)
#define isHeatingHotend2() isHeatingHotend(2)
#define isCoolingHotend2() isCoolingHotend(2)
#else
#define setTargetHotend2(_celsius) do{}while(0)
#define setTargetHotend2(_celsius) do{}while(0)
#endif
#if EXTRUDERS > 3
#define degHotend3() degHotend(3)
#define degTargetHotend3() degTargetHotend(3)
#define setTargetHotend3(_celsius) setTargetHotend((_celsius), 3)
#define isHeatingHotend3() isHeatingHotend(3)
#define isCoolingHotend3() isCoolingHotend(3)
#define degHotend3() degHotend(3)
#define degTargetHotend3() degTargetHotend(3)
#define setTargetHotend3(_celsius) setTargetHotend((_celsius), 3)
#define isHeatingHotend3() isHeatingHotend(3)
#define isCoolingHotend3() isCoolingHotend(3)
#else
#define setTargetHotend3(_celsius) do{}while(0)
#define setTargetHotend3(_celsius) do{}while(0)
#endif
#if EXTRUDERS > 4
#error Invalid number of extruders
#error Invalid number of extruders
#endif
int getHeaterPower(int heater);
void disable_heater();
void setWatch();
@ -189,15 +157,14 @@ static bool thermal_runaway = false;
#endif
#endif
FORCE_INLINE void autotempShutdown(){
#ifdef AUTOTEMP
if(autotemp_enabled)
{
autotemp_enabled=false;
if(degTargetHotend(active_extruder)>autotemp_min)
setTargetHotend(0,active_extruder);
}
#endif
FORCE_INLINE void autotempShutdown() {
#ifdef AUTOTEMP
if (autotemp_enabled) {
autotemp_enabled = false;
if (degTargetHotend(active_extruder) > autotemp_min)
setTargetHotend(0, active_extruder);
}
#endif
}
void PID_autotune(float temp, int extruder, int ncycles);

14
README.md

@ -1,4 +1,14 @@
# Marlin 3D Printer Firmware
# Marlin 3D Printer Firmware Package for Felix 2.0/3.0
## Felix Modifications
This is a snapshot of upstream Marlin from 20150301 modified to be
used directly with Felix Electronic Boards and Printers. Dual-Head
has been activated but is not tested. Neither are LCD and SDCARD
since Ocotprint is in use here. A pull-request to have direct
upstream hardware support has already been submitted.
<img align="right" src="Documentation/Logo/Marlin%20Logo%20GitHub.png" />
* [Configuration & Compilation](/Documentation/Compilation.md)
@ -41,7 +51,7 @@ The current Marlin dev team consists of:
- Erik van der Zalm ([@ErikZalm](https://github.com/ErikZalm))
- [@daid](https://github.com/daid)
Sprinters lead developers are Kliment and caru.
Grbls lead developer is Simen Svale Skogsrud.
Sonney Jeon (Chamnit) improved some parts of grbl

Loading…
Cancel
Save